8

I have developed a small scripting language and I've just started writing the very first native library bindings. This is practically the first time I'm writing a native extension to a script language, so I've run into a conceptual issue.

I'd like to write glue code for popular libraries so that they can be used from this language, and because of the design of the engine I've written, this is achieved using an array of C structs describing the function name visible by the virtual machine, along with a function pointer.

Thus, a native binding is really just a global array variable, and now I must obviously give it a (preferably good) name. In C, it's idiomatic to put one's own functions in a "namespace" by prepending a custom prefix to function names, as in myscript_parse_source() or myscript_run_bytecode(). The custom name shall ideally describe the name of the library which it is part of. Here arises the confusion.

Let's say I'm writing a binding for libcURL. In this case, it seems reasonable to call my extension library curl_myscript_binding, like this:

MYSCRIPT_API const MyScriptExtFunc curl_myscript_lib[10];

But now this collides with the curl namespace. (I have even thought about calling it curlmyscript_lib but unfortunately, libcURL does not exclusively use the curl_ prefix -- the public APIs contain macros like CURLCODE_* and CURLOPT_*, so I assume this would clutter the namespace as well.)

Another option would be to declare it as myscript_curl_lib, but that's good only as long as I'm the only one who writes bindings (since I know what I am doing with my namespace). As soon as other contributors start to add their own native bindings, they now clutter the myscript namespace. (I've done some research, and it seems that for example the Perl cURL binding follows this pattern. Not sure what I should think about that...)

So how do you suggest I name my variables? Are there any general guidelines that should be followed?

  • 3
    There is no necessity for globals. You could also provide a function in your API to register a new extension, e.g. SomeLang_register_extension("curl", "H2CO3", "000.001.000", the_extension) where the_extension points to some extension structure but isn't visible globally. Your language would then keep an internal data structure to sort through the extensions by name, version and author. – amon Oct 7 '13 at 18:39
  • @amon Sure, that's possible too. – H2CO3 Oct 7 '13 at 18:54
  • This answer might be of interest, it deals with a different subject but it explains how the naming conventions are derived for HTML; there are similar rules for different languages, it might be useful to choose a convention matching your needs and follow it. – Rob Sep 22 '18 at 1:41
2

Well realistically, it's not necessary to contain a global array of exported functions just to make them visible to your runtime environment.

A good question to ask is whether your runtime environment saves the function pointer and the name associated to it?

Your notion of using a global array to export functions only makes sense if your runtime environment does not save that information but I assume you must save it for the VM's execution environment to properly execute.

A common feature that's added to scripting language like yours is the idea of registering your functions.

Essentially, you need a medium to store the exported function ptr and the exported function pointer's name that will be used in the script code.

I know of two options you could implement for this:

  1. A hashmap that will use the script-side function name as the string key and the function ptr as the value associated to that key.

    exported_funcs["do_thing"] = &native_do_thing;

  2. Commonly used in embedded systems scripting languages such as Pawn, you could use the script data itself to store the function pointer. When you "register" the function, you iterate the script's exported functions table and search for the name that the exported function will register as; once you found that name, overrwrite that script data (not the script file itself but the loaded script memory data) and you've essentially stored the native function pointer.

FuncPtrType **table_entry = get_script_entry_ptr(func_name); *table_entry = func_ptr;

I highly advise that, for the 2nd option, you give the table entry enough size to accommodate pointers sizes of all architectures, notably the entry should be 8 bytes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.