Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start work on a C API #380

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

Start work on a C API #380

wants to merge 1 commit into from

Conversation

udoprog
Copy link
Collaborator

@udoprog udoprog commented Jan 1, 2022

This introduces a basic C API which allows for setting up and running Rune in C.

There's still a bunch of important things missing:

  • Full interaction with the stack.
  • Defining modules and external types.
  • Interact with all kinds of values, especially the ones that use Shared<T> and AnyObj.

Full example with a custom function named test

#include <assert.h>
#include <stdio.h>

#include <rune.h>

/** 
 * A custom C function that interacts with Rune. This is registered below with
 * rune_module_function.
 */
void custom_function(rune_stack *stack, uintptr_t count, rune_vm_error *e) {
    rune_value value = rune_value_unit();

    if (count != 1) {
        rune_vm_error_bad_argument_count(e, count, 1);
        return;
    }

    // Note: Error will be automatically propagated since it's used as an output
    // argument.
    if (!rune_stack_pop_value(stack, &value, e)) {
        return;
    }

    int64_t integer = 0;

    if (!rune_value_as_integer(&value, &integer)) {
        rune_vm_error_bad_argument_at(e, 0, &value, RUNE_INTEGER_TYPE);
        return;
    }

    rune_stack_push_unit(stack);
    rune_stack_push_integer(stack, integer * 10);
    rune_stack_push_tuple(stack, 2, e);
}

int main() {
    rune_context context = rune_context_new();
    rune_module module = rune_module_new();
    rune_runtime_context runtime = rune_runtime_context_new();
    rune_sources sources = rune_sources_new();
    rune_standard_stream out = rune_standard_stream_stderr(RUNE_COLOR_CHOICE_ALWAYS);
    rune_unit unit = rune_unit_new();
    rune_vm vm = rune_vm_new();
    rune_vm_error error = rune_vm_error_new();
    rune_context_error context_error = rune_context_error_new();

    if (!rune_module_function(&module, "test", custom_function, &context_error)) {
        rune_context_error_emit(&context_error, &out);
        goto EXIT;
    }

    if (!rune_context_install(&context, &module, &context_error)) {
        rune_context_error_emit(&context_error, &out);
        goto EXIT;
    }

    rune_module_free(&module);

    rune_source source = rune_source_new("<in>", "pub fn main(n) { test(n) }");
    assert(rune_sources_insert(&sources, &source));
    rune_source_free(&source);

    rune_diagnostics diag = rune_diagnostics_new();

    rune_build build = rune_build_prepare(&sources);
    rune_build_with_diagnostics(&build, &diag);
    rune_build_with_context(&build, &context);

    bool ok = rune_build_build(&build, &unit);

    if (!rune_diagnostics_is_empty(&diag)) {
        assert(rune_diagnostics_emit(&diag, &out, &sources));
    }

    rune_diagnostics_free(&diag);

    if (!ok) {
        goto EXIT;
    }

    assert(rune_context_runtime(&context, &runtime));
    assert(rune_vm_setup(&vm, &runtime, &unit));

    rune_hash entry = rune_hash_name("main");

    if (!rune_vm_set_entrypoint(&vm, entry, 1, &error)) {
        assert(rune_vm_error_emit(&error, &out, &sources));
        goto EXIT;
    }

    rune_stack_push_integer(rune_vm_stack_mut(&vm), 42);
    rune_value ret = rune_value_unit();

    if (!rune_vm_complete(&vm, &ret, &error)) {
        assert(rune_vm_error_emit(&error, &out, &sources));
    }

    int64_t output = 0;

    if (rune_value_as_integer(&ret, &output)) {
        printf("output = %lld\n", output);
    } else {
        rune_hash type_hash = rune_hash_empty();

        if (rune_value_type_hash(&ret, &type_hash, &error)) {
            printf("output = %lld\n", type_hash);
        } else {
            printf("output = ?\n");
        }
    }

    rune_value_free(&ret);

EXIT:
    rune_context_free(&context);
    rune_module_free(&module);
    rune_runtime_context_free(&runtime);
    rune_sources_free(&sources);
    rune_standard_stream_free(&out);
    rune_unit_free(&unit);
    rune_vm_error_free(&error);
    rune_vm_free(&vm);
    return 0;
}

@udoprog udoprog added the enhancement New feature or request label Jan 1, 2022
@udoprog udoprog force-pushed the c-api branch 13 times, most recently from 53de2ca to af685f4 Compare January 2, 2022 09:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant