embedding.md 5.0 KB

Embedding

Gravity can be easily embedded into any C/C++ code. Suppose to have the following Gravity code:

func sum (a, b) {
    return a + b
}

func mul (a, b) {
    return a * b
}

func main () {
    var a = 10
    var b = 20
    return sum(a, b) + mul(a, b)
}

To keep the code as simple as possible I skipped any error check condition that would be required. The bare minimum C code to embed the above Gravity code would be:

#include "gravity_compiler.h"
#include "gravity_macros.h"
#include "gravity_core.h"
#include "gravity_vm.h"

const char *source_code = " \
func sum (a, b) {   \
    return a + b    \
}   \
    \
func mul (a, b) {   \
    return a * b    \
}   \
    \
func main () {   \
    var a = 10   \
    var b = 20   \
    return sum(a, b) + mul(a, b)   \
}   \
";

// a very simple report error callback function
void report_error (gravity_vm *vm, error_type_t error_type, const char *message,
                   error_desc_t error_desc, void *xdata) {
    printf("%s\n", message);
    exit(0);
}

int main (void) {
    // setup a delegate struct (much more options are available)
    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 a closure (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 the memory has been transferred, you can get rid of the front-end
    gravity_compiler_free(compiler);
    
    // 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;
}

To load and execute a myfile Gravity source code from disk the required changes would be minimum:

int main (void) {
    size_t size = 0;
    const char *source_code = file_read("myfile.gravity", &size);
    
    ...
    
    // compile Gravity source code into bytecode (embedded into a closure)
    // notice the change of the is_static bool parameter to false
    gravity_closure_t *closure = gravity_compiler_run(compiler, source_code, size, 0, false, true);
    
    ...
}

To directly execute the mul Gravity function and pass some parameter from C to Gravity some minor changes need to be performed:

#include "gravity_compiler.h"
#include "gravity_macros.h"
#include "gravity_core.h"
#include "gravity_vm.h"

const char *source_code = " \
func sum (a, b) {   \
    return a + b    \
}   \
    \
func mul (a, b) {   \
    return a * b    \
}   \
";

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 the memory has been transferred, you can get rid of the front-end
    gravity_compiler_free(compiler);
    
    // load closure into VM
    gravity_vm_loadclosure(vm, closure);
    
    // lookup a reference to the mul closure into the Gravity VM
    gravity_value_t mul_function = gravity_vm_getvalue(vm, "mul", (uint32_t)strlen("mul"));
    if (!VALUE_ISA_CLOSURE(mul_function)) {
        printf("Unable to find mul function into Gravity VM.\n");
        return -1;
    }
    
    // convert function to closure
    gravity_closure_t *mul_closure = VALUE_AS_CLOSURE(mul_function);
    
    // prepare parameters
    gravity_value_t p1 = VALUE_FROM_INT(30);
    gravity_value_t p2 = VALUE_FROM_INT(40);
    gravity_value_t params[] = {p1, p2};
    
    // execute mul closure
    if (gravity_vm_runclosure (vm, mul_closure, VALUE_FROM_NULL, params, 2)) {
        // 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;
}