Gravity can be extended at runtime using the C API (please read the Embedding section before proceeding).
Three steps are required:
In this simple example we'll create a "Foo" class with a "sum" method in C and then we'll execute it from Gravity.
#include "gravity_compiler.h"
#include "gravity_macros.h"
#include "gravity_core.h"
#include "gravity_vm.h"
#include "gravity_vmmacros.h"
// notice the usage of the extern clause to tell compiler (the front-end) that the Foo object will be registered later by the back-end (the VM)
const char *source_code = " \
extern var Foo; \
func main () { \
var c = Foo(); \
return c.sum(30, 40); \
} \
";
static bool sum (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
// SKIPPED: check nargs (must be 3 because arg[0] is self)
gravity_value_t v1 = GET_VALUE(1);
gravity_value_t v2 = GET_VALUE(2);
// SKIPPED: check that both v1 and v2 are int numbers
RETURN_VALUE(VALUE_FROM_INT(v1.n + v2.n), rindex);
}
void setup_foo (gravity_vm *vm) {
// create a new Foo class
gravity_class_t *c = gravity_class_new_pair (vm, "Foo", NULL, 0, 0);
// allocate and bind bar closure to the newly created class
gravity_class_bind(c, "sum", NEW_CLOSURE_VALUE(sum));
// register class c inside VM
gravity_vm_setvalue(vm, "Foo", VALUE_FROM_OBJECT(c));
}
int main (void) {
// setup a delegate struct
gravity_delegate_t delegate = {.error_callback = report_error};
// allocate a new compiler
gravity_compiler_t *compiler = gravity_compiler_create(&delegate);
// compile Gravity source code into bytecode
gravity_closure_t *closure = gravity_compiler_run(compiler, source_code, strlen(source_code), 0, true, true);
// allocate a new Gravity VM
gravity_vm *vm = gravity_vm_new(&delegate);
// transfer memory from the compiler (front-end) to the VM (back-end)
gravity_compiler_transfer(compiler, vm);
// once memory has been trasferred, you can get rid of the front-end
gravity_compiler_free(compiler);
// register my Foo class inside Gravity VM
setup_foo(vm);
// execute main closure
if (gravity_vm_runmain(vm, closure)) {
// retrieve returned result
gravity_value_t result = gravity_vm_result(vm);
// dump result to a C string and print it to stdout
char buffer[512];
gravity_value_dump(vm, result, buffer, sizeof(buffer));
printf("RESULT: %s\n", buffer);
}
// free VM and core libraries (implicitly allocated by the VM)
gravity_vm_free(vm);
gravity_core_free();
return 0;
}
For more examples see the file gravity_core.c in the src/runtime/ directory. Most of the Gravity classes are built using these same APIs.