#include "common.h" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * 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 bool check_argument(lua_State* L, honey_lua_type type, int index); static void get_argument(lua_State* L, void* destination, honey_lua_type type, int index); /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * String wrangling helpers * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ honey_result honey_format_string(char** string, char* format_string, ...) { honey_result res; va_list args, args_; va_start(args, format_string); va_copy(args_, args); int string_size = vsnprintf(NULL, 0, format_string, args_); va_end(args_); *string = malloc((string_size+1) * sizeof(char)); if (*string == NULL) res = HONEY_MEMORY_ALLOCATION_ERROR; else { vsnprintf(*string, string_size+1, format_string, args); res = HONEY_OK; } va_end(args); return res; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void honey_lua_throw_error(lua_State* L, char* format_string, ...) { honey_result result; va_list args, args_; va_start(args, format_string); va_copy(args_, args); int string_size = vsnprintf(NULL, 0, format_string, args_); va_end(args_); char* string = malloc((string_size + 1) * sizeof(char)); if (string == NULL) lua_pushstring(L, "there was an error allocating memory for an error message"); else { vsnprintf(string, string_size + 1, format_string, args); lua_pushstring(L, string); free(string); } lua_error(L); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Argument parsing functions * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ static void honey_lua_arg_error(lua_State* L, honey_lua_type type, int position) { char expected_type[16]; type_to_string(expected_type, type); char* error_message; honey_result result; char* got_type = (char*) lua_typename(L, lua_type(L, position)); result = honey_format_string(&error_message, "bad argument in position %d: " "expected %s, but got %s instead.", position, expected_type, got_type); if (result != HONEY_OK) { lua_pushstring(L, "error allocating memory for error message :("); } else { lua_pushstring(L, error_message); free(error_message); } lua_error(L); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int honey_lua_parse_arguments(lua_State* L, int n, ...) { va_list args; va_start(args, n); 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); get_argument(L, destination, type, i); } va_end(args); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Table creation functions * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ void honey_lua_create_table(lua_State* L, honey_lua_element* elements, unsigned int n_elements) { lua_createtable(L, 0, n_elements); for (int i=0; iwindow, true); return 0; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Lua binding helper functions * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* string must be able to hold at least 16 characters. */ static void type_to_string(char* string, honey_lua_type type) { switch(type) { case HONEY_BOOLEAN: memcpy(string, "boolean", 8); break; case HONEY_INTEGER: memcpy(string, "integer", 8); break; case HONEY_NUMBER: memcpy(string, "number", 7); break; case HONEY_STRING: memcpy(string, "string", 7); break; case HONEY_FUNCTION: memcpy(string, "function", 9); break; case HONEY_TABLE: memcpy(string, "table", 6); break; case HONEY_NIL: memcpy(string, "nil", 4); break; case HONEY_USERDATA: memcpy(string, "userdata", 9); break; case HONEY_LIGHTUSERDATA: memcpy(string, "light userdata", 16); break; case HONEY_ANY: memcpy(string, "any", 4); break; default: break; } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ static bool check_argument(lua_State* L, honey_lua_type type, int index) { switch(type) { case HONEY_BOOLEAN: if (!lua_isboolean(L, index)) return false; break; case HONEY_INTEGER: case HONEY_NUMBER: if (!lua_isnumber(L, index)) return false; break; case HONEY_STRING: if (!lua_isstring(L, index)) return false; break; case HONEY_FUNCTION: if (!lua_isfunction(L, index)) return false; break; case HONEY_TABLE: if (!lua_istable(L, index)) return false; break; case HONEY_NIL: if (!lua_isnil(L, index)) return false; break; case HONEY_USERDATA: if (!lua_isuserdata(L, index)) return false; break; case HONEY_LIGHTUSERDATA: if (!lua_islightuserdata(L, index)) return false; break; default: break; } return true; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ static void get_argument(lua_State* L, void* destination, honey_lua_type type, int index) { switch (type) { case HONEY_BOOLEAN: { bool* result = destination; *result = lua_toboolean(L, index); } break; case HONEY_INTEGER: { int* result = destination; *result = lua_tointeger(L, index); } break; case HONEY_NUMBER: { float* result = destination; *result = lua_tonumber(L, index); } break; case HONEY_STRING: { char** result = destination; *result = (char*) lua_tostring(L, index); } break; case HONEY_TABLE: break; case HONEY_FUNCTION: break; case HONEY_NIL: break; case HONEY_USERDATA: { void** result = destination; *result = lua_touserdata(L, index); } break; case HONEY_LIGHTUSERDATA: { void** result = destination; *result = lua_touserdata(L, index); } break; case HONEY_ANY: break; default: /* should never get here! */ break; } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */