diff --git a/examples/c-embedded/bind_module.c b/examples/c-embedded/bind_module.c index 79c50da3a..0c4ad725a 100644 --- a/examples/c-embedded/bind_module.c +++ b/examples/c-embedded/bind_module.c @@ -18,25 +18,15 @@ CLValue add(CLVM* vm, const CLValue* args, uint8_t nargs) { } // Forward declaration. -CLValue myCollectionNew(CLVM* vm, const CLValue* args, uint8_t nargs); -CLValue myCollectionAsList(CLVM* vm, const CLValue* args, uint8_t nargs); +CLValue myNodeNew(CLVM* vm, const CLValue* args, uint8_t nargs); +CLValue myNodeAsList(CLVM* vm, const CLValue* args, uint8_t nargs); -struct { char* n; CLFuncFn fn; } funcs[] = { - {"add", add}, - {"asList", myCollectionAsList}, - {"MyCollection.new", myCollectionNew}, +CLHostFuncEntry funcs[] = { + CL_FUNC("add", add), + CL_FUNC("MyNode.asList", myNodeAsList), + CL_FUNC("MyNode.new", myNodeNew), }; -bool funcLoader(CLVM* vm, CLFuncInfo info, CLFuncResult* out) { - // Check that the name matches before setting the function pointer. - if (strncmp(funcs[info.idx].n, info.name.ptr, info.name.len) == 0) { - out->ptr = funcs[info.idx].fn; - return true; - } else { - return false; - } -} - // C has limited static initializers (and objects need a vm instance) so initialize them in `main`. typedef struct { char* n; CLValue v; } NameValue; NameValue vars[2]; @@ -54,20 +44,20 @@ bool varLoader(CLVM* vm, CLVarInfo info, CLValue* out) { // Binding a C struct with it's own children and finalizer. // This struct retains 2 VM values and has 2 arbitrary data values unrelated to the VM. -typedef struct MyCollection { +typedef struct MyNode { CLValue val1; CLValue val2; int a; double b; -} MyCollection; +} MyNode; -CLTypeId myCollectionId; +CLTypeId myNodeId; -// Implement the `new` function in MyCollection. -CLValue myCollectionNew(CLVM* vm, const CLValue* args, uint8_t nargs) { +// Implement the `new` function in MyNode. +CLValue myNodeNew(CLVM* vm, const CLValue* args, uint8_t nargs) { // Instantiate our object. - CLValue new = clNewHostObject(vm, myCollectionId, sizeof(MyCollection)); - MyCollection* my = (MyCollection*)clAsHostObject(new); + CLValue new = clNewHostObject(vm, myNodeId, sizeof(MyNode)); + MyNode* my = (MyNode*)clAsHostObject(new); // Assign the constructor args passed in and retain them since the new object now references them. clRetain(vm, args[0]); @@ -81,35 +71,27 @@ CLValue myCollectionNew(CLVM* vm, const CLValue* args, uint8_t nargs) { return new; } -// Implement the `asList` method in MyCollection. -CLValue myCollectionAsList(CLVM* vm, const CLValue* args, uint8_t nargs) { +// Implement the `asList` method in MyNode. +CLValue myNodeAsList(CLVM* vm, const CLValue* args, uint8_t nargs) { // First argument is `self`. - MyCollection* my = (MyCollection*)clAsHostObject(args[0]); + MyNode* my = (MyNode*)clAsHostObject(args[0]); CLValue vals[4] = {my->val1, my->val2, clInteger(my->a), clFloat(my->b)}; - return clNewList(vm, &vals[0], 4); + return clNewListDyn(vm, &vals[0], 4); } -CLValueSlice myCollectionGetChildren(CLVM* vm, void* obj) { - MyCollection* my = (MyCollection*)obj; +CLValueSlice myNodeGetChildren(CLVM* vm, void* obj) { + MyNode* my = (MyNode*)obj; return (CLValueSlice){ .ptr = &my->val1, .len = 2 }; } -void myCollectionFinalizer(CLVM* vm, void* obj) { - printf("MyCollection finalizer was called.\n"); +void myNodeFinalizer(CLVM* vm, void* obj) { + printf("MyNode finalizer was called.\n"); } -bool typeLoader(CLVM* vm, CLTypeInfo info, CLTypeResult* out) { - if (strncmp("MyCollection", info.name.ptr, info.name.len) == 0) { - out->type = CL_BIND_TYPE_CUSTOM; - out->data.custom.out_type_id = &myCollectionId; - out->data.custom.get_children = myCollectionGetChildren; - out->data.custom.finalizer = myCollectionFinalizer; - return true; - } else { - return false; - } -} +CLHostTypeEntry types[] = { + CL_CUSTOM_TYPE("MyNode", &myNodeId, myNodeGetChildren, myNodeFinalizer), +}; // This module loader provides the source code and callbacks to load @host funcs, vars, and types. bool modLoader(CLVM* vm, CLStr spec, CLModuleLoaderResult* out) { @@ -117,17 +99,17 @@ bool modLoader(CLVM* vm, CLStr spec, CLModuleLoaderResult* out) { out->src = "@host func add(a float, b float) float\n" "@host var .MyConstant float\n" - "@host var .MyList List\n" + "@host var .MyList List[dyn]\n" "\n" "@host\n" - "type MyCollection:\n" + "type MyNode _:\n" " @host func asList() any" "\n" - "@host func MyCollection.new(a any, b any) MyCollection\n"; + "@host func MyNode.new(a any, b any) MyNode\n"; out->srcLen = strlen(out->src); - out->funcLoader = funcLoader; + out->funcs = (CLSlice){ .ptr = funcs, .len = 3 }; + out->types = (CLSlice){ .ptr = types, .len = 1 }; out->varLoader = varLoader; - out->typeLoader = typeLoader; return true; } else { // Fallback to the default module loader to load `builtins`. @@ -152,21 +134,21 @@ int main() { // Initialize var array for loader. vars[0] = (NameValue){"MyConstant", clFloat(1.23)}; CLValue myInt = clInteger(123); - vars[1] = (NameValue){"MyList", clNewList(vm, &myInt, 1)}; + vars[1] = (NameValue){"MyList", clNewListDyn(vm, &myInt, 1)}; CLStr main = STR( - "use mod 'my_mod'\n" + "use m 'my_mod'\n" "\n" "var a = 1.0\n" - "print mod.add(a, 2)\n" - "print(-mod.MyConstant)\n" + "print m.add(a, 2)\n" + "print(-m.MyConstant)\n" "\n" - "mod.MyList.append(3)\n" - "print mod.MyList.len()\n" + "m.MyList.append(3)\n" + "print m.MyList.len()\n" "\n" - "-- Instantiate a new MyCollection.\n" - "var myc = mod.MyCollection.new(1, 2)\n" - "dump myc.asList()" + "-- Instantiate a new MyNode.\n" + "var n = m.MyNode.new(1, 2)\n" + "dump n.asList()" ); CLValue resv; CLResultCode res = clEval(vm, main, &resv); diff --git a/src/include/cyber.h b/src/include/cyber.h index d9e5bcfa9..1375b3535 100644 --- a/src/include/cyber.h +++ b/src/include/cyber.h @@ -2,6 +2,7 @@ #include #include #include +#include #ifndef CYBER_H #define CYBER_H @@ -234,10 +235,12 @@ typedef struct CLHostType { uint8_t type; } CLHostType; -#define CL_CORE_TYPE(t) ((CLHostType){ .data = { .core_custom = { .type_id = t, .get_children = NULL, .finalizer = NULL }}, .type = CL_BIND_TYPE_CORE_CUSTOM }) -#define CL_CORE_TYPE_EXT(t, gc, f) ((CLHostType){ .data = { .core_custom = { .type_id = t, .get_children = gc, .finalizer = f }}, .type = CL_BIND_TYPE_CORE_CUSTOM }) -#define CL_CORE_TYPE_DECL(t) ((CLHostType){ .data = { .core_decl = { .type_id = t }}, .type = CL_BIND_TYPE_CORE_DECL }) -#define CL_CUSTOM_TYPE(ot, gc, f) ((CLHostType){ .data = { .custom = { .out_type_id = ot, .get_children = gc, .finalizer = f }}, .type = CL_BIND_TYPE_CUSTOM }) +#define CL_STR(str) ((CLStr){ .ptr = str, .len = strlen(str) }) +#define CL_FUNC(name, fn) ((CLHostFuncEntry){ CL_STR(name), fn }) +// #define CL_CORE_TYPE(t) ((CLHostType){ .data = { .core_custom = { .type_id = t, .get_children = NULL, .finalizer = NULL }}, .type = CL_BIND_TYPE_CORE_CUSTOM }) +// #define CL_CORE_TYPE_EXT(t, gc, f) ((CLHostType){ .data = { .core_custom = { .type_id = t, .get_children = gc, .finalizer = f }}, .type = CL_BIND_TYPE_CORE_CUSTOM }) +// #define CL_CORE_TYPE_DECL(t) ((CLHostType){ .data = { .core_decl = { .type_id = t }}, .type = CL_BIND_TYPE_CORE_DECL }) +#define CL_CUSTOM_TYPE(name, ot, gc, f) ((CLHostTypeEntry){ CL_STR(name), (CLHostType){ .data = { .custom = { .out_type_id = ot, .get_children = gc, .finalizer = f }}, .type = CL_BIND_TYPE_CUSTOM }}) // A mapping from a matching symbol string to a CLHostType. typedef struct CLHostTypeEntry {