diff options
-rw-r--r-- | examples/oop_example.c | 135 | ||||
-rw-r--r-- | examples/oop_example.lua | 22 | ||||
-rw-r--r-- | nerv.c | 4 |
3 files changed, 104 insertions, 57 deletions
diff --git a/examples/oop_example.c b/examples/oop_example.c index 89f5994..859bd03 100644 --- a/examples/oop_example.c +++ b/examples/oop_example.c @@ -3,16 +3,18 @@ #include <stdlib.h> #include "../common.h" +#define SQR(x) ((x) * (x)) + const char *point_tname = "nerv.Point"; +const char *better_point_tname = "nerv.BetterPoint"; typedef struct { double x, y; - int arr[100]; } Point; -static int point_get_sinx (lua_State *L) { +static int point_norm (lua_State *L) { Point *p = luaT_checkudata(L, 1, point_tname); - lua_pushnumber(L, sin(p->x)); + lua_pushnumber(L, sqrt(SQR(p->x) + SQR(p->y))); return 1; } @@ -22,67 +24,104 @@ static int point_set_x (lua_State *L) { return 0; } - -static int point_get_y(lua_State *L) { +static int point_set_y (lua_State *L) { Point *p = luaT_checkudata(L, 1, point_tname); - lua_pushnumber(L, sin(p->x)); - return 1; + p->y = luaL_checknumber(L, 2); + return 0; } -static int point_newindex(lua_State *L) { - Point *p = luaT_checkudata(L, 1, point_tname); - if (lua_isnumber(L, 2)) - { - int d = luaL_checkinteger(L, 2); - double v = luaL_checknumber(L, 3); - if (0 <= d && d < 100) - p->arr[d] = v; - lua_pushboolean(L, 1); - return 1; - } - else - { - lua_pushboolean(L, 0); - return 1; - } +/* generic constructor */ +void point_new_(Point *self, double x, double y) { + self->x = x; + self->y = y; } -static int point_index(lua_State *L) { - Point *p = luaT_checkudata(L, 1, point_tname); - if (lua_isnumber(L, 2)) - { - int d = luaL_checkinteger(L, 2); - if (0 <= d && d < 100) - lua_pushnumber(L, p->arr[d]); - lua_pushboolean(L, 1); - return 2; - } - else - { - lua_pushboolean(L, 0); - return 1; - } +int point_new(lua_State *L) { + /* `_new` function should create the object itself */ + Point *self = (Point *)malloc(sizeof(Point)); + point_new_(self, luaL_checknumber(L, 1), luaL_checknumber(L, 2)); + luaT_pushudata(L, self, point_tname); + fprintf(stderr, "[example] %s constructor is invoked\n", + point_tname); + return 1; } -int point_new(lua_State *L) { +int point___init(lua_State *L) { + /* The difference between this function and `_new` function is that this + * one is called by subclass of Point implemented in Lua, although it + * basically does the same thing as `_new`. Also, it can read the empty + * object (table) from the stack. (In this example, the table is ignored.) */ Point *self = (Point *)malloc(sizeof(Point)); - self->x = 0; - self->y = 0; + point_new_(self, luaL_checknumber(L, 2), luaL_checknumber(L, 3)); luaT_pushudata(L, self, point_tname); + fprintf(stderr, "[example] A subclass has invoked `__init`\n"); return 1; } -static const luaL_Reg point[] = { - {"get_sinx", point_get_sinx}, +static const luaL_Reg point_methods[] = { {"set_x", point_set_x}, - {"get_y", point_get_y}, - {"__index__", point_index}, - {"__newindex__", point_newindex}, + {"set_y", point_set_y}, + {"__init", point___init}, + {"norm", point_norm}, + {NULL, NULL} +}; + + +/* the subclass method overrides the one from baseclass */ +static int better_point_norm (lua_State *L) { + Point *p = luaT_checkudata(L, 1, point_tname); + lua_pushnumber(L, fabs(p->x) + fabs(p->y)); + return 1; +} + +int better_point_new(lua_State *L) { + /* `_new` function should create the object itself */ + Point *self = (Point *)malloc(sizeof(Point)); + point_new_(self, luaL_checknumber(L, 1), luaL_checknumber(L, 2)); + luaT_pushudata(L, self, better_point_tname); + fprintf(stderr, "[example] %s constructor is invoked\n", + better_point_tname); + return 1; +} + +int better_point___init(lua_State *L) { + /* The difference between this function and `_new` function is that this + * one is called by subclass of Point implemented in Lua, although it + * basically does the same thing as `_new`. Also, it can read the empty + * object (table) from the stack. (In this example, the table is ignored.) */ + Point *self = (Point *)malloc(sizeof(Point)); + point_new_(self, luaL_checknumber(L, 2), luaL_checknumber(L, 3)); + luaT_pushudata(L, self, better_point_tname); + fprintf(stderr, "[example] A subclass has invoked `__init`\n"); + return 1; +} + +static const luaL_Reg better_point_methods[] = { + {"norm", better_point_norm}, + {"__init", better_point___init}, {NULL, NULL} }; void nerv_point_init(lua_State *L) { - luaT_newmetatable(L, "nerv.Point", NULL, point_new, NULL, NULL); - luaL_register(L, NULL, point); + /* create a class and let luaT know */ + luaT_newmetatable(L, point_tname, NULL, point_new, NULL, NULL); + /* register member functions */ + luaL_register(L, NULL, point_methods); + /* keep the stack balanced, see `nerv.c` */ + lua_pop(L, 1); +} + +void nerv_better_point_init(lua_State *L) { + /* create a class and let luaT know */ + luaT_newmetatable(L, better_point_tname, point_tname, + better_point_new, NULL, NULL); + /* register member functions */ + luaL_register(L, NULL, better_point_methods); + /* keep the stack balanced, see `nerv.c` */ lua_pop(L, 1); } + +void nerv_example_init(lua_State *L) { + nerv_point_init(L); + nerv_better_point_init(L); +} diff --git a/examples/oop_example.lua b/examples/oop_example.lua index 45da36e..712387b 100644 --- a/examples/oop_example.lua +++ b/examples/oop_example.lua @@ -1,7 +1,15 @@ -a = nerv.Point() -print(a:get_sinx()) -a:set_x(3.14) -print(a:get_sinx()) -print(a[2]) -a[2] = 3 -print(a[2]) +p = nerv.Point(0, 0) -- create a Point instance +print(p) +print(p:norm()) -- get 2-norm of the Point +p:set_x(1.0) +p:set_y(2.0) +print(p:norm()) -- get 2-norm of the Point + +p = nerv.BetterPoint(1, 2) +print(p) +print(p:norm()) --get 1-norm of the Point + +-- create a subclass using lua +local EvenBetterPoint = nerv.class('nerv.EvenBetterPoint', 'nerv.BetterPoint') +bp = nerv.EvenBetterPoint(1, 2) +print(p:norm()) @@ -1,6 +1,6 @@ #include "common.h" -extern void nerv_point_init(lua_State *L); +extern void nerv_example_init(lua_State *L); extern void nerv_matrix_init(lua_State *L); extern void nerv_param_init(lua_State *L); @@ -30,7 +30,7 @@ int luaopen_libnerv(lua_State *L) { * Also note that they can make use of the value at top of the stack which * references to the `nerv` global table. */ nerv_utils_init(L); - nerv_point_init(L); + nerv_example_init(L); nerv_matrix_init(L); nerv_param_init(L); return 1; |