diff options
Diffstat (limited to 'README.md')
-rw-r--r-- | README.md | 223 |
1 files changed, 111 insertions, 112 deletions
@@ -6,9 +6,9 @@ title: honeysuckle README honeysuckle =========== -A pure C library to make writing Lua bindings simple. honeysuckle provides -functions to make argument parsing, table operations, error creation and -handling, string wrangling, and registry operations easy and straightforward +A pure C library to make writing Lua bindings simple. honeysuckle provides +functions to make argument parsing, table operations, error creation and +handling, string wrangling, and registry operations easy and straightforward from within your C code. Table of contents @@ -35,7 +35,8 @@ sudo make install To make the tests as well, do the above and then do `make test`. -You should now be able to include `<honeysuckle.h>` into your C files for use. +You should now be able to include `<honeysuckle.h>` into your C +files for use. Usage ----- @@ -56,7 +57,8 @@ Usage [(Back to top)](#table-of-contents) -These constants are used when honeysuckle needs to know a type to expect. +These constants are used when honeysuckle needs to know a type to +expect. - `HS_BOOL` - booleans - `HS_INT` - integers @@ -70,21 +72,29 @@ These constants are used when honeysuckle needs to know a type to expect. - `HS_NIL` - lua's nil - `HS_ANY` - any type -`hs_type_to_string()` takes as argument a single type constant and returns a -const string representing the type. +`hs_type_to_string()` takes as argument a single type constant and +returns a const string representing the type. ### Argument parsing [(Back to top)](#table-of-contents) -`hs_parse_args()` is the primary argument-parsing function. It accepts as -arguments a lua_State pointer, any number of alternating type constant and -pointer pairs, and finally `HS_END` to close the arguments. This function -performs typechecking and in case of an error throws with helpful error -messages. +`hs_parse_args()` is the primary argument-parsing function. It +accepts as arguments a lua_State pointer, any number of +`struct hs_arg`s. These can either be constructed by hand or with +function-like macros identified by the lowercase version of the type +names from the section above. Use of the macros is recommended as +they will likely reduce type mismatch errors (e.g. giving HS_BOOL as +type but providing a pointer to a string). -`HS_TBL`, `HS_FUNC`, `HS_NIL`, and `HS_ANY` take a pointer to an integer -that will be filled with the stack index of the argument. +This function performs typechecking and in case of an error throws +with helpful error messages. + +`HS_TBL`, `HS_FUNC`, `HS_NIL`, and `HS_ANY` take a pointer to an +integer that will be filled with the stack index of the argument. + +Please note that, due to technical limitations, this function can +only parse up to 255 arguments. ```c int some_lua_binding(lua_State *L) @@ -96,13 +106,15 @@ int some_lua_binding(lua_State *L) char *str; void* user; hs_parse_args(L, - HS_BOOL, &b, - HS_INT, &i, - HS_TBL, &tbl_index, - HS_NUM, &n, - HS_STR, &str, - HS_USER, &user, - HS_END); + // explicit initializer for struct + { HS_BOOL, ptr.bool = &b }, + // macro initialization (recommended) + hs_int(i), + hs_tbl(tbl_index), + hs_num(n), + hs_str(str), + hs_user(user) + ); // do something... return 1; } @@ -110,27 +122,32 @@ int some_lua_binding(lua_State *L) #### Overloading -There is another function, `hs_parse_overloaded()`, that permits overloaded -argument parsing. Its syntax is exactly as `hs_parse_args()` except that after -each `HS_END` you may provide another argument list, and after the final -argument list you must provide another `HS_END`. This function throws an error -only if none of the argument lists match the provided arguments. +There is another function, `hs_parse_overloaded()`, that permits +overloaded argument parsing. Its syntax is exactly as +`hs_parse_args()` except that each overload option must be wrapped +in the macro `hs_overload()`. This function returns an integer +containing the zero-indexed index of the overload option that was +actually used. + +If none of the argument lists match the provided arguments, this +function throws an error. ```c int overloaded_lua_binding(lua_State *L) { int i; + float f; char *str; int choice = hs_parse_overloaded(L, - HS_INT, &i, HS_END, - HS_STR, &str, HS_END, - HS_END); + hs_overload( hs_int(i) ), + hs_overload( hs_str(str), hs_num(f) ) + ); if (choice == 0) { // do something with i - // str remains unassigned!! + // str and f remain unassigned!! } else { - // choice == 1, do something with str + // choice == 1, do something with str and f // i remains unassigned!! } return 0; @@ -141,69 +158,58 @@ int overloaded_lua_binding(lua_State *L) [(Back to top)](#table-of-contents) -`hs_create_table()` takes a lua_State pointer, some number of string key/type -constant/value triplets, and finally `HS_END`. It returns the stack index of -the newly created table. Most of the type constants expect their associated -type (e.g. `HS_INT` expects an `int`, `HS_CFUNC` expects `lua_CFunction`, -etc.) but `HS_FUNC` and `HS_TBL` expect an integer stack index. You cannot -use `HS_NIL` or `HS_ANY` with this function. `hs_create_table()` -automatically pops any stack indices provided to it. +`hs_create_table()` takes a lua_State pointer and then up to 255 ` +struct hs_tbl_entry`s. These can either be constructed by hand, or +via function-like macros identified by lowercase versions of the +typenames shown above (e.g. `hs_str_int` would create a string key +with integer value). Most of the type constants expect their +associated type (e.g. `HS_INT` expects an `int`, `HS_CFUNC` expects ` +lua_CFunction`, etc.) but `HS_FUNC`, `HS_USER`, and `HS_TBL` expect +an integer stack index. You cannot use `HS_NIL` or `HS_ANY` with +this function. + +This function returns the stack index of the newly created table, +and automatically pops any stack indices provided to it. ```c int *ptr; // some pointer hs_create_table(L, - "intVal", HS_INT, 4, - "numVal", HS_NUM, 6.0f, - "tableVal", HS_TBL, hs_create_table(L, - "subTableCFunc", HS_CFUNC, some_lua_binding, - "subTableString", HS_STR, "i'm a string!", - HS_END), + // manual struct initialization + { HS_STR, key.string="intVal", HS_INT, value.integer=4 }, + // macro initialization (recommended) + hs_str_num("numVal", 6.0f), + hs_int_tbl(12, hs_create_table(L, + hs_str_cfunc("subTableCFunc", some_lua_binding), + hs_int_bool(15, true), + ), "lightUserdataVal", HS_LIGHT, (void *)ptr, HS_END); ``` -#### Enums - -`hs_create_enum()` takes a lua_State pointer, some number of string/integer -pairs, and finally `HS_END`. It creates a table in which, for each string/int -pair `tbl[string] = int` and `tbl[int] = string` and returns the stack index -of said table. `hs_string_to_enum()` uses such a table to convert a string -literal to enum value and `hs_enum_to_string()` converts enums to strings. In -case the value does not exist, converting to a string results in NULL and -converting to an enum results in a negative value. - -```c -enum { VALUE_1, VALUE_2, VALUE_3 } example_t; - -int index = hs_create_enum(L, - "one", VALUE_1, - "two", VALUE_2, - "three", VALUE_3, - HS_END); - -example_t e = hs_string_to_enum(L, index, "one"); // VALUE_1 -char *str = hs_enum_to_string(L, index, VALUE_3); // "three" -``` - ### Table processing [(Back to top)](#table-of-contents) -`hs_process_table()` is intended for creating lua bindings that can be called -like `set_config{ debug=true, verbosity=2, logfile='run.log' }`. It operates -only on values with string keys and boolean, number, or string types. -`hs_process_table()` accepts a lua_State pointer, a stack index for the table to -operate on, and then a series of string key/data type/function/user data void -pointer quadruplets, finished off by `HS_END`. This function does not pop the -table from the stack. +`hs_process_table()` is intended for creating lua bindings that can +be called like `set_config{ debug=true, verbosity=2, +logfile='run.log' }`. It operates only on values with string keys +and boolean, number, or string types. `hs_process_table()` accepts a +lua_State pointer, a stack index for the table to operate on, and +then a series of `struct hs_table_processor`s. These can either be +constructed manually, or via function-like macros. This function +does not pop the table from the stack. + +honeysuckle provides the functions `hs_pt_set_bool`, +`hs_pt_set_int`, `hs_pt_set_num`, and `hs_pt_set_string` for the +very common operations of "set a variable to the provided value". +These can also be set via the function-like macros `hs_set_bool()`, +`hs_set_int()`, `hs_set_num()`, and `hs_set_str()`. -honeysuckle provides the functions `hs_pt_set_bool`, `hs_pt_set_int`, -`hs_pt_set_num`, and `hs_pt_set_string` for the very common operations of "set -a variable to the provided value". User-defined functions should have signature -`void (function)([type], void *)`, where [type] is either `lua_Boolean`, -`lua_Integer`, `lua_Number`, or `const char *`, depending on the expected -value type. +User-defined functions should have signature +`void (function)([type], void *)`, where [type] is either +`lua_Boolean`, `lua_Integer`, `lua_Number`, or `const char *`, +depending on the expected value type. ```c @@ -220,27 +226,31 @@ struct settings { }; struct settings s; - + hs_process_table(L, tbl_index, - "verbosity", HS_INT, hs_pt_set_int, &(s.verbosity), - "debug", HS_BOOL, hs_pt_set_bool, &(s.debug), - "logfile", HS_STR, set_logfile, &s - "epsilon", HS_NUM, hs_pt_set_num, &(s.epsilon), - HS_END); + // manual struct initialization + { "verbosity", HS_INT, func.integer=hs_pt_set_int, &(s.verbosity) }, + // macro initialization (recommended) + hs_process_bool("debug", hs_pt_set_bool, s.debug), + hs_process_str("logfile", set_logfile, s), + // alternative to explicitly specifying hs_pt_set_bool + hs_set_num("epsilon", s.epsilon) +); ``` ### Errors and error handling [(Back to top)](#table-of-contents) -`hs_throw_error()` constructs and throws error messages like printf. +`hs_throw_error()` constructs and throws error messages like +printf. ```c hs_throw_error(L, "ERROR: %d is not within range", 10); ``` -`hs_traceback()` can be supplied to `lua_pcall()` to get a helpful stack -trace error message: +`hs_traceback()` can be supplied to `lua_pcall()` to get a helpful +stack trace error message: ```c lua_pushcfunction(L, hs_traceback); @@ -251,28 +261,15 @@ int tr_pos = lua_gettop(); int result = lua_pcall(L, nargs, nret, tr_pos); ``` -`hs_call()` performs the above, accepting simply a lua_State pointer, int -nargs, and int nret as arguments. Alternatively, you can use `hs_call_args()` -which provides the same helpful, contained error messages as `hs_call()` but -takes arguments explicitly in the call for both function arguments and -returns: +`hs_call()` performs the above, accepting simply a lua_State +pointer, int nargs, and int nret as arguments. -```c -// some_function accepts int, str and returns number, boolean -lua_pushcfunction(L, some_function); - -lua_Number n; -bool b; -hs_call_args(L, - HS_INT, 4, HS_STR, "hello", HS_END, - HS_NUM, &n, HS_BOOL, &b, HS_END); -``` ### String wrangling [(Back to top)](#table-of-contents) -`hs_pushstring()` allows you to push string values using printf format +`hs_pushstring()` allows you to push string values using printf format strings. ```c @@ -284,8 +281,8 @@ hs_pushstring(L, "hello there, %s. I hear the current time is %d:%02d", "dylan", [(Back to top)](#table-of-contents) honeysuckle provides three macros, `hs_rstore()`, `hs_rload()`, and `hs_ -rdel()` to make registry access easier. These are mostly just thin wrappers -around `luaL_ref()`, `luaL_unref()` and `lua_rawgeti()` but they come up +rdel()` to make registry access easier. These are mostly just thin wrappers +around `luaL_ref()`, `luaL_unref()` and `lua_rawgeti()` but they come up frequently enough that I think these are helpful. ```c @@ -300,10 +297,12 @@ Development ----------- [(Back to top)](#table-of-contents) -honeysuckle is still very early in development. As the specifics of the build -process and testing become clearer I'll update this section. +honeysuckle is still very early in development. As the specifics of +the build process and testing become clearer I'll update this +section. -If you're interested in helping out, send me an email! The to-dos at the time of writing are: +If you're interested in helping out, send me an email! The to-dos at +the time of writing are: * Write initial tests for errors, tracebacks, and function calling * Implement everything @@ -315,8 +314,8 @@ License [(Back to top)](#table-of-contents) -honeysuckle is licensed under the [Anti-Capitalist Software License]. -Basically: if you're a single person, a co-op, or a nonprofit, feel free to +honeysuckle is licensed under the [Anti-Capitalist Software License]. +Basically: if you're a single person, a co-op, or a nonprofit, feel free to use this. Otherwise, send me an email. c: [Anti-Capitalist Software License]: https://anticapitalist.software |