Browse Source

add examples and README

Sunxin 7 năm trước cách đây
mục cha
commit
cf39ff1e06
3 tập tin đã thay đổi với 565 bổ sung0 xóa
  1. 375 0
      README.md
  2. 65 0
      examples/jerry_example_addModule.cpp
  3. 125 0
      examples/jerry_expmple_addCplusplus.cpp

+ 375 - 0
README.md

@@ -1,3 +1,378 @@
 # jerryscript on RT-Thread
 
 JerryScript is a lightweight JavaScript engine for resource-constrained devices such as microcontrollers. It can run on devices with less than 64 KB of RAM and less than 200 KB of flash memory.
+
+API Reference :http://jerryscript.net/api-reference/
+
+首先,不得不说明下JerryScript的基础类型:`jerry_value_t`。一个对象可以设定任意个属性,属性可以是`string`,`function`等,也可以是对象。但每个对象中,都有一个指针:`native_pointer`,这个指针就可用来存放或传递数据。
+
+    jerry_value_t obj
+        ├── 属性1
+        ├── 属性2
+        │   ...
+        │   ...
+        └── native_pointer    
+
+
+JerryScript中则提供了获取、设定native_pointer的API。
+```C
+bool
+jerry_get_object_native_pointer (const jerry_value_t obj_val,
+                                 void **out_native_pointer_p,
+                                 const jerry_object_native_info_t **out_native_info_p)
+
+bool
+jerry_set_object_native_pointer (const jerry_value_t obj_val,
+                                 void *native_p,
+                                 const jerry_object_native_info_t *info_p)
+```
+
+## 如何导入C++的API
+
+此Package中,我们一般使用以下的宏在JerryScript中创建一些接口,来使用C++的API:
+
+```C
+#define REGISTER_HANDLER(NAME)      \
+    jerryx_handler_register_global ( (jerry_char_t *)# NAME, NAME ## _handler)
+#define REGISTER_HANDLER_ALIAS(NAME, HANDLER) \
+    jerryx_handler_register_global ( (jerry_char_t *)# NAME, HANDLER)
+#define REGISTER_METHOD(OBJ, NAME)  \
+    js_add_function (OBJ, # NAME, NAME ## _handler)
+#define REGISTER_METHOD_ALIAS(OBJ, NAME, HANDLER) \
+    js_add_function (OBJ, # NAME, HANDLER)
+#define REGISTER_METHOD_NAME(OBJ, NAME, HANDLER)  \
+    js_add_function (OBJ, NAME, HANDLER ## _handler)
+
+```
+
+可以看到,前两个宏指向函数`jerryx_handler_register_global`,具体内容如下:
+
+```C
+jerry_value_t
+jerryx_handler_register_global (const jerry_char_t *name_p, /**< name of the function */
+                                jerry_external_handler_t handler_p) /**< function callback */
+{
+  jerry_value_t global_obj_val = jerry_get_global_object ();
+  jerry_value_t function_name_val = jerry_create_string (name_p);
+  jerry_value_t function_val = jerry_create_external_function (handler_p);
+
+  jerry_value_t result_val = jerry_set_property (global_obj_val, function_name_val, function_val);
+
+  jerry_release_value (function_val);
+  jerry_release_value (function_name_val);
+  jerry_release_value (global_obj_val);
+
+  return result_val;
+} 
+```
+后三个宏定义都指向了函数`js_add_function`,具体内容如下:
+```C
+void js_add_function(const jerry_value_t obj, const char *name,
+                     jerry_external_handler_t func)
+{
+    jerry_value_t str = jerry_create_string((const jerry_char_t *)name);
+    jerry_value_t jfunc = jerry_create_external_function(func);
+
+    jerry_set_property(obj, str, jfunc);
+
+    jerry_release_value(str);
+    jerry_release_value(jfunc);
+}
+```
+
+从上述代码中可以看到`jerryx_handler_register_global`和`js_add_function`的实质操作就是在指定对象中加入一个名为`name`的`func`,这个`obj`可以指定为全局obj。而我们就只需要在这个func中添加C++的代码并使用API,并且可以把所需要的数据作为属性加入到指定JerryScript对象中或返回出来。如果想要在JS中传递C++对象,我们就可以利用文章开头所说的native_pointer
+
+此func类型为`jerry_external_handler_t`,具体定义如下。
+```C
+typedef jerry_value_t (*jerry_external_handler_t) (const jerry_value_t function_obj,
+                                                   const jerry_value_t this_val,
+                                                   const jerry_value_t args_p[],
+                                                   const jerry_length_t args_count);
+```
+为了方便书写代码,Package中添加了对应的宏定义。
+```C
+#define DECLARE_HANDLER(NAME)       \
+    static jerry_value_t            \
+    NAME ## _handler (const jerry_value_t func_value,   \
+                        const jerry_value_t this_value, \
+                        const jerry_value_t args[],     \
+                        const jerry_length_t args_cnt )
+```
+
+### 示例代码
+
+以添加`request`接口为例
+1. 创建一个初始化API:`js_request_init`,并设定入参变量`obj`。创建好初始化API后,我们就只要在API中执行`REGISTER_METHOD(obj, request)`,但此时函数`request`还未创建,那我们只需要创建它即可。而函数`request`内部,我们就可以添加C++的API,执行我们需要操作或把相关数据转换成JerryScript的数据类型返回出来。
+
+    ```C
+    DECLARE_HANDLER(request)
+    {
+        //此处就能添加对应的C++的API,并执行具体内容。
+    }
+
+    extern "C"
+    {
+        int js_request_init(jerry_value_t obj)
+        {
+            REGISTER_METHOD(obj, request);
+            return 0;
+        }
+    }
+    ```
+
+2. 譬如在此Package中,JerryScript的执行函数为`jerry_main`,那我们就还需要在`jerry_main`中执行下`js_request_init`。
+
+    ```C
+    extern int js_request_init(jerry_value_t obj);
+    int jerry_main(int argc, char** argv)
+    {
+        //...
+        jerry_value_t global_object = jerry_get_global_object();
+        js_request_init(global_object);
+        //...
+    }
+    ```
+
+## 如何添加builtin module
+
+由于JerryScript是一款轻量级的JavaScript的引擎,因此它没有直接提供常见的module。但是开发者可以根据自身需求,去添加相应module。
+
+那如何添加builtin module呢?当相应module的入口建立好后,只需要使用以下finsh命令即可
+```
+//NAME : module的名称
+//MODULE_INIT : module的入口函数
+JS_MODULE(NAME, MODULE_INIT)
+```
+
+示例代码:
+```C
+jerry_value_t myModule_init(void)
+{
+
+    jerry_value_t obj = jerry_create_object();
+    // ...
+    // do something
+    // ...
+    return obj;
+}
+
+JS_MODULE(myModule,myModule_init);
+```
+以上代码就在JerryScript中创建里一个名为`myModule`的module,其返回值为`obj`。
+在JS脚本中,我们都是通过以下方式调用module的。
+```C
+var mqtt = require('myModule')
+```
+
+## Sample
+
+### C++ 导入示例
+
+```C++
+#include <rtthread.h>
+#include <jerry_util.h>
+
+/*自定义C++类*/
+class Rectangle
+{
+   private:
+        int length;
+        int width;
+   
+   public:
+        Rectangle(int length,int width);
+        int getSize();
+        int getLength();
+        int getWidth();
+};
+
+Rectangle::Rectangle(int length,int width)
+{
+    this->length = length;
+    this->width = width;
+}
+
+int Rectangle::getSize()
+{
+    return (this->length * this->width);
+}
+
+int Rectangle::getLength()
+{
+    return this->length;
+}
+
+int Rectangle::getWidth()
+{
+    return this->width;
+}
+/**********/
+
+void rectangle_free_callback(void *native_p)
+{
+    Rectangle* rect = (Rectangle*)native_p;
+    delete(rect);
+}
+
+const static jerry_object_native_info_t rectangle_info =
+{
+    rectangle_free_callback //当js_rect对象释放后,调用该回调
+};
+
+DECLARE_HANDLER(getSize)
+{
+    void *native_pointer = RT_NULL;
+    jerry_get_object_native_pointer(this_value,&native_pointer,RT_NULL);    //获取当前对象中的native_pointer
+    
+    if(native_pointer)
+    {
+        /*调用C++对象的API,并将其返回值转换成JS对象*/
+        Rectangle* rectangle = (Rectangle*)native_pointer;
+        jerry_value_t js_size = jerry_create_number(rectangle->getSize());
+        return js_size;
+    }
+    return jerry_create_undefined();
+}
+
+DECLARE_HANDLER(getLength)
+{
+    void *native_pointer = RT_NULL;
+    jerry_get_object_native_pointer(this_value,&native_pointer,RT_NULL);
+    
+    if(native_pointer)
+    {
+        Rectangle* rectangle = (Rectangle*)native_pointer;
+        jerry_value_t js_length = jerry_create_number(rectangle->getLength());
+        return js_length;
+    }
+    return jerry_create_undefined();
+}
+
+DECLARE_HANDLER(getWidth)
+{
+    void *native_pointer = RT_NULL;
+    jerry_get_object_native_pointer(this_value,&native_pointer,RT_NULL);
+    
+    if(native_pointer)
+    {
+        Rectangle* rectangle = (Rectangle*)native_pointer;
+        jerry_value_t js_width = jerry_create_number(rectangle->getWidth());
+        return js_width;
+    }
+    return jerry_create_undefined();
+}
+
+DECLARE_HANDLER(rectangle_init)
+{
+    /*入参判断*/
+    if(args_cnt !=2 || !jerry_value_is_number(args[0]) || !jerry_value_is_number(args[1]))
+        return jerry_create_undefined();
+    
+    jerry_value_t js_rect = jerry_create_object(); //创建JS对象 js_rect
+    
+    Rectangle* rectangle = new Rectangle(jerry_get_number_value(args[0]),jerry_get_number_value(args[1]));      /创建C++对象 rectangle
+
+    jerry_set_object_native_pointer(js_rect, rectangle,&rectangle_info);    //把js_rect的native_pointer指向rectangle
+    
+    /*调用rectangle的API,并把其返回值转换成JS对象*/
+    jerry_value_t js_length = jerry_create_number(rectangle->getLength());      
+    jerry_value_t js_width = jerry_create_number(rectangle->getWidth());
+    
+    /*把js_length 和 js_width设置成js_rect的属性,类Rectangle中lenght与width为私有变量,如要JS对象与C++对象保持对应,此处代码可注释掉*/
+    js_set_property(js_rect,"length",js_length);
+    js_set_property(js_rect,"width",js_width);
+    
+    jerry_release_value(js_length);
+    jerry_release_value(js_width);
+    
+    REGISTER_METHOD(js_rect,getSize);       //为js_retc注册一个方法getSize
+    REGISTER_METHOD(js_rect,getLength);     //为js_retc注册一个方法getLength
+    REGISTER_METHOD(js_rect,getWidth);      //为js_retc注册一个方法getWidth
+    return js_rect;
+}
+
+extern "C"
+{
+    int js_example_rect_init(jerry_value_t obj)
+    {
+        REGISTER_METHOD(obj, rectangle_init); //为指定对象obj注册一个方法rectangle_init,这个对象可以是global_obj
+        return 0;
+    }
+}
+
+```
+
+### builtin module示例
+
+```C++
+
+#include <rtthread.h>
+#include <jerry_util.h>
+
+/*自定义的C++类*/
+class Circle 
+{
+    private:
+        int radius ;
+    public:
+        Circle(int radius);
+        int getRadius();
+        float getCircumference();
+};
+
+Circle::Circle(int radius)
+{
+    this->radius = radius;
+}
+
+int Circle::getRadius()
+{
+    return this->radius;
+}
+
+float Circle::getCircumference()
+{
+    return (2 * 3.1415 *this->radius);
+}
+
+void circle_free_callback(void *native_p)
+{
+    Circle* rect = (Circle*)native_p;
+    delete(rect);
+}
+/**********/
+
+const static jerry_object_native_info_t circle_info =
+{
+    circle_free_callback //当js_circle对象释放后,调用该回调
+};
+
+DECLARE_HANDLER(getCircumference)
+{
+    /*函数内部具体实现*/
+    void* native_pointer = RT_NULL;
+    jerry_get_object_native_pointer(this_value,&native_pointer,RT_NULL);    //获取当前对象中的native_pointer
+    if(native_pointer)
+    {
+        /*调用C++对象的API,并将其返回值转换成JS对象*/
+        Circle* circle = (Circle*)native_pointer;
+        jerry_value_t js_circumference = jerry_create_number(circle->getCircumference());
+        return js_circumference;
+    }
+    return jerry_create_undefined();
+};
+
+jerry_value_t Circle_init()
+{
+    jerry_value_t js_circle = jerry_create_object();   // 创建JerryScript对象js_circle
+    Circle* circle = new Circle(5);     //创建C++对象 Circle
+    jerry_set_object_native_pointer(js_circle,circle,&circle_info);     //把js_circle的native_pointer指向circle
+    jerry_value_t js_radius = jerry_create_number(circle->getRadius());     //调用Circle的API,并把它转换成JS对象。
+    js_set_property(js_circle,strdup("radius"),js_radius);  //把js_radius设置成js_circle的一个属性
+    jerry_release_value(js_radius);
+    REGISTER_METHOD(js_circle,getCircumference);    //为js_circle注册一个方法 getCircumference
+    return js_circle;
+}
+
+JS_MODULE(Circle,Circle_init); //注册builtin module,名称:Circle,入口函数:Circle_init
+```

+ 65 - 0
examples/jerry_example_addModule.cpp

@@ -0,0 +1,65 @@
+#include <rtthread.h>
+#include <jerry_util.h>
+
+class Circle
+{
+    private:
+        int radius ;
+    public:
+        Circle(int radius);
+        int getRadius();
+        float getCircumference();
+};
+
+Circle::Circle(int radius)
+{
+    this->radius = radius;
+}
+
+int Circle::getRadius()
+{
+    return this->radius;
+}
+
+float Circle::getCircumference()
+{
+    return (2 * 3.1415 *this->radius);
+}
+
+void circle_free_callback(void *native_p)
+{
+    Circle* rect = (Circle*)native_p;
+    delete(rect);
+}
+
+const static jerry_object_native_info_t circle_info =
+{
+    circle_free_callback
+};
+
+DECLARE_HANDLER(getCircumference)
+{
+    void* native_pointer = RT_NULL;
+    jerry_get_object_native_pointer(this_value,&native_pointer,RT_NULL);
+    if(native_pointer)
+    {
+        Circle* circle = (Circle*)native_pointer;
+        jerry_value_t js_circumference = jerry_create_number(circle->getCircumference());
+        return js_circumference;
+    }
+    return jerry_create_undefined();
+};
+
+jerry_value_t Circle_init()
+{
+    jerry_value_t js_circle = jerry_create_object();
+    Circle* circle = new Circle(5);
+    jerry_set_object_native_pointer(js_circle,circle,&circle_info);
+    jerry_value_t js_radius = jerry_create_number(circle->getRadius());
+    js_set_property(js_circle,strdup("radius"),js_radius);
+    jerry_release_value(js_radius);
+    REGISTER_METHOD(js_circle,getCircumference);
+    return js_circle;
+}
+
+JS_MODULE(Circle,Circle_init);

+ 125 - 0
examples/jerry_expmple_addCplusplus.cpp

@@ -0,0 +1,125 @@
+#include <rtthread.h>
+#include <jerry_util.h>
+
+class Rectangle
+{
+   private:
+        int length;
+        int width;
+   
+   public:
+        Rectangle(int length,int width);
+        int getSize();
+        int getLength();
+        int getWidth();
+};
+
+Rectangle::Rectangle(int length,int width)
+{
+    this->length = length;
+    this->width = width;
+}
+
+int Rectangle::getSize()
+{
+    return (this->length * this->width);
+}
+
+int Rectangle::getLength()
+{
+    return this->length;
+}
+
+int Rectangle::getWidth()
+{
+    return this->width;
+}
+
+void rectangle_free_callback(void *native_p)
+{
+    Rectangle* rect = (Rectangle*)native_p;
+    delete(rect);
+}
+
+const static jerry_object_native_info_t rectangle_info =
+{
+    rectangle_free_callback
+};
+
+DECLARE_HANDLER(getSize)
+{
+    void *native_pointer = RT_NULL;
+    jerry_get_object_native_pointer(this_value,&native_pointer,RT_NULL);
+    
+    if(native_pointer)
+    {
+        Rectangle* rectangle = (Rectangle*)native_pointer;
+        jerry_value_t js_size = jerry_create_number(rectangle->getSize());
+        return js_size;
+    }
+    return jerry_create_undefined();
+}
+
+DECLARE_HANDLER(getLength)
+{
+    void *native_pointer = RT_NULL;
+    jerry_get_object_native_pointer(this_value,&native_pointer,RT_NULL);
+    
+    if(native_pointer)
+    {
+        Rectangle* rectangle = (Rectangle*)native_pointer;
+        jerry_value_t js_length = jerry_create_number(rectangle->getLength());
+        return js_length;
+    }
+    return jerry_create_undefined();
+}
+
+DECLARE_HANDLER(getWidth)
+{
+    void *native_pointer = RT_NULL;
+    jerry_get_object_native_pointer(this_value,&native_pointer,RT_NULL);
+    
+    if(native_pointer)
+    {
+        Rectangle* rectangle = (Rectangle*)native_pointer;
+        jerry_value_t js_width = jerry_create_number(rectangle->getWidth());
+        return js_width;
+    }
+    return jerry_create_undefined();
+    
+}
+
+DECLARE_HANDLER(rectangle_addCpp)
+{   
+    if(args_cnt !=2 || !jerry_value_is_number(args[0]) || !jerry_value_is_number(args[1]))
+        return jerry_create_undefined();
+    
+    jerry_value_t js_rect = jerry_create_object();
+    
+    Rectangle* rectangle = new Rectangle(jerry_get_number_value(args[0]),jerry_get_number_value(args[1]));
+    jerry_set_object_native_pointer(js_rect, rectangle,&rectangle_info);
+    
+    jerry_value_t js_length = jerry_create_number(rectangle->getLength());
+    jerry_value_t js_width = jerry_create_number(rectangle->getWidth());
+    
+    js_set_property(js_rect,"length",js_length);
+    js_set_property(js_rect,"width",js_width);
+    
+    jerry_release_value(js_length);
+    jerry_release_value(js_width);
+    
+    REGISTER_METHOD(js_rect,getSize);
+    REGISTER_METHOD(js_rect,getLength);
+    REGISTER_METHOD(js_rect,getWidth);
+    
+    return js_rect;
+}
+
+extern "C"
+{
+    int js_example_rect_init(jerry_value_t obj)
+    {
+        REGISTER_METHOD(obj, rectangle_addCpp);
+        return 0;
+    }
+}