diff options
Diffstat (limited to 'src/honey_lua.c')
-rw-r--r-- | src/honey_lua.c | 273 |
1 files changed, 199 insertions, 74 deletions
diff --git a/src/honey_lua.c b/src/honey_lua.c index 7730809..2469d37 100644 --- a/src/honey_lua.c +++ b/src/honey_lua.c @@ -2,14 +2,31 @@ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * - * Lua binding helper function definitions + * Helper structs + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +struct argument_pair { + honey_lua_type type; + void* ptr; +}; + +struct argument_list { + unsigned int length; + struct argument_pair* args; +}; + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Lua binding helper function declarations * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* string must be able to hold at least 16 characters. */ -static void type_to_string(char* string, - honey_lua_type type); +static int type_to_string(char* string, + honey_lua_type type); static bool check_argument(lua_State* L, honey_lua_type type, @@ -111,90 +128,198 @@ static void honey_lua_arg_error(lua_State* L, /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -int honey_lua_parse_arguments(lua_State* L, int n, ...) +static bool check_arg_list(lua_State* L, + struct argument_list arg_list) { - va_list args; - va_start(args, n); + struct argument_pair* args = arg_list.args; + for (int i=0; i<arg_list.length; i++) { + if (!check_argument(L, args[i].type, i+1)) + return false; + } + return true; +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +static int arg_list_to_string(char* string, + int start_index, + struct argument_list arg_list) +{ + struct argument_pair* args = arg_list.args; - for (int i=1; i<=n; i++) { - honey_lua_type type = va_arg(args, honey_lua_type); - void* destination = va_arg(args, void*); - if (!check_argument(L, type, i)) - honey_lua_arg_error(L, type, i); + string[start_index] = '('; - get_argument(L, destination, type, i); + int index = start_index + 1; + + for (int i=0; i<arg_list.length; i++) { + index += type_to_string(string + index, args[i].type); + if (i != arg_list.length - 1) { + string[index + 1] = ','; + string[index + 2] = ' '; + index += 2; + } } - - va_end(args); + + string[index] = ')'; + + return index+1; } -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Table creation functions - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -void honey_lua_create_table(lua_State* L, - honey_lua_element* elements, - unsigned int n_elements) +static void arg_lists_to_string(char** string, + int n, + struct argument_list* arg_lists) { - lua_createtable(L, 0, n_elements); + unsigned int size = 0; + for (int i=0; i<n; i++) + size += 18*arg_lists[i].length + 5; + + *string = calloc(size, sizeof(char)); + int index = 0; + + for (int i=0; i<n; i++) { + index = arg_list_to_string(*string, index, arg_lists[i]); + if (i != n) { + *string[index] = '\n'; + index++; + } + } +} - for (int i=0; i<n_elements; i++) { - honey_lua_push_element(L, elements[i]); - lua_setfield(L, -2, elements[i].name); +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +static void get_arg_list(lua_State* L, + struct argument_list arg_list) +{ + struct argument_pair* args = arg_list.args; + for (int i=0; i<arg_list.length; i++) { + get_argument(L, args[i].ptr, args[i].type, i+1); } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -void honey_lua_push_element(lua_State* L, honey_lua_element element) + +int honey_lua_parse_arguments(lua_State* L, unsigned int n, ...) { - switch(element.type) { - case HONEY_INTEGER: - lua_pushinteger(L, element.data.integer); - break; + struct argument_list* arg_lists = malloc(n * sizeof(struct argument_list)); + if (arg_lists == NULL) + honey_lua_throw_error(L, "failed to allocate memory for argument parsing!"); - case HONEY_NUMBER: - lua_pushnumber(L, element.data.number); - break; + va_list args; + va_start(args, n); - case HONEY_STRING: - lua_pushstring(L, element.data.string); - break; + for (int i=0; i<n; i++) { + arg_lists[i].length = va_arg(args, int); + arg_lists[i].args = malloc(arg_lists[i].length * sizeof(struct argument_pair)); + if (arg_lists[i].args == NULL) + honey_lua_throw_error(L, "failed to allocate memory for argument parsing!"); - case HONEY_FUNCTION: - lua_pushcfunction(L, element.data.function); - break; + for (int j=0; j<arg_lists[i].length; j++) { + honey_lua_type type = va_arg(args, honey_lua_type); + void* destination = va_arg(args, void*); + } + } + + va_end(args); - case HONEY_TABLE: - honey_lua_create_table(L, - element.data.table.elements, - element.data.table.n_elements); - break; + int index = 0; + + for (; index<n; index++) { + if (check_arg_list(L, arg_lists[index])) { + get_arg_list(L, arg_lists[index]); + break; + } + } - case HONEY_NIL: - lua_pushnil(L); - break; + if (index == n) { + /* no arguments match, throw error */ + } + + + for (int i=0; i<n; i++) + free(arg_lists[i].args); + free(arg_lists); - case HONEY_USERDATA: - /* cannot push userdata, push nil */ - lua_pushnil(L); - break; + return index; +} - case HONEY_LIGHTUSERDATA: - lua_pushlightuserdata(L, element.data.pointer); - break; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Table creation functions + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ - default: - // this should never happen - break; +static void build_table_recursively(lua_State* L, + unsigned int n, + va_list args) +{ + lua_createtable(L, 0, n); + + for (int i=0; i<n; i++) { + honey_lua_type type = va_arg(args, honey_lua_type); + char* name = va_arg(args, char*); + switch(type) { + case HONEY_INTEGER: + lua_pushinteger(L, va_arg(args, int)); + break; + + case HONEY_NUMBER: + lua_pushnumber(L, va_arg(args, double)); + break; + + case HONEY_STRING: + lua_pushstring(L, va_arg(args, char*)); + break; + + case HONEY_FUNCTION: + lua_pushcfunction(L, va_arg(args, int (*)(lua_State* L))); + break; + + case HONEY_TABLE: + build_table_recursively(L, va_arg(args, int), args); + break; + + case HONEY_NIL: + lua_pushnil(L); + break; + + case HONEY_USERDATA: + /* cannot push userdata from C, skip */ + continue; + + case HONEY_LIGHTUSERDATA: + lua_pushlightuserdata(L, va_arg(args, void*)); + break; + + default: + // this should never happen + break; + } + lua_setfield(L, -2, name); } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +void honey_lua_create_table(lua_State* L, + unsigned int n_elements, + ...) +{ + va_list args; + va_start(args, n_elements); + build_table_recursively(L, n_elements, args); + va_end(args); +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Lua pcall wrapping + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + int honey_lua_traceback(lua_State* L) { if (!lua_isstring(L, 1)) @@ -252,58 +377,58 @@ int honey_exit(lua_State* L) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * - * Lua binding helper functions + * Lua binding helper function definitions * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* string must be able to hold at least 16 characters. */ -static void type_to_string(char* string, - honey_lua_type type) +static int type_to_string(char* string, + honey_lua_type type) { switch(type) { case HONEY_BOOLEAN: memcpy(string, "boolean", 8); - break; + return 7; case HONEY_INTEGER: memcpy(string, "integer", 8); - break; + return 7; case HONEY_NUMBER: memcpy(string, "number", 7); - break; + return 6; case HONEY_STRING: memcpy(string, "string", 7); - break; + return 6; case HONEY_FUNCTION: memcpy(string, "function", 9); - break; + return 8; case HONEY_TABLE: memcpy(string, "table", 6); - break; + return 5; case HONEY_NIL: memcpy(string, "nil", 4); - break; + return 3; case HONEY_USERDATA: memcpy(string, "userdata", 9); - break; + return 8; case HONEY_LIGHTUSERDATA: memcpy(string, "light userdata", 16); - break; + return 15; case HONEY_ANY: memcpy(string, "any", 4); - break; + return 3; default: - break; + return 0; } } |