From c07caa9aa2c299a39f7c571ab1ca18c3101ea634 Mon Sep 17 00:00:00 2001 From: Laria Carolin Chabowski Date: Thu, 30 Mar 2023 22:11:44 +0200 Subject: [PATCH] Implement the registry and a agrv getter to test it The registry is a global dictionary accessible from C that stores arbitrary apfl values. --- src/CMakeLists.txt | 1 + src/apfl.h | 6 ++ src/builtins.c | 17 ++++++ src/context.c | 11 ++++ src/context.h | 2 + src/globals.apfl | 1 + src/main.c | 10 +++- src/registry.c | 133 +++++++++++++++++++++++++++++++++++++++++++++ src/registry.h | 21 +++++++ 9 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 src/registry.c create mode 100644 src/registry.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c955f6..c27df5b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,7 @@ add_library(apfl builtins.c context.c eval.c + registry.c scope.c symbols.c diff --git a/src/apfl.h b/src/apfl.h index c0fa84f..0ac3f60 100644 --- a/src/apfl.h +++ b/src/apfl.h @@ -831,6 +831,10 @@ void apfl_error_decorate_with_backtrace(apfl_ctx ctx, void *ignored); void apfl_load(apfl_ctx, struct apfl_source_reader, apfl_stackidx name); +void apfl_registry_set(apfl_ctx, void *key_major, size_t key_minor, apfl_stackidx); +void apfl_registry_delete(apfl_ctx, void *key_major, size_t key_minor); +bool apfl_registry_try_get(apfl_ctx, void *key_major, size_t key_minor); + enum apfl_call_stack_entry_type { APFL_CSE_FUNCTION, APFL_CSE_CFUNCTION, @@ -856,6 +860,8 @@ bool apfl_call_stack_entry_info_format(struct apfl_io_writer, struct apfl_call_s bool apfl_debug_print_val(apfl_ctx, apfl_stackidx, struct apfl_io_writer); +void apfl_argv_set(apfl_ctx ctx, apfl_stackidx args); + // Raise an error with a value from the stack as the message. noreturn void apfl_raise_error(apfl_ctx, apfl_stackidx); // Raise an error with a constant string as the message. diff --git a/src/builtins.c b/src/builtins.c index d187506..d1a9224 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -629,6 +629,22 @@ iterate_dict(apfl_ctx ctx) apfl_push_nil(ctx); } +static int argv_registry_key; + +void +apfl_argv_set(apfl_ctx ctx, apfl_stackidx args) +{ + apfl_registry_set(ctx, &argv_registry_key, 0, args); +} + +static void +get_argv(apfl_ctx ctx) +{ + if (!apfl_registry_try_get(ctx, &argv_registry_key, 0)) { + apfl_push_nil(ctx); + } +} + static void get_optional(apfl_ctx ctx) { @@ -727,4 +743,5 @@ apfl_builtins(apfl_ctx ctx) add_builtin(ctx, "get-optional", get_optional); add_builtin(ctx, "raise", impl_raise); add_builtin(ctx, "getsym-Some", apfl_sym_some); + add_builtin(ctx, "get-argv", get_argv); } diff --git a/src/context.c b/src/context.c index f3b2ba6..e81a805 100644 --- a/src/context.c +++ b/src/context.c @@ -12,6 +12,7 @@ #include "gc.h" #include "hashmap.h" #include "modules.h" +#include "registry.h" #include "resizable.h" #include "strings.h" #include "value.h" @@ -737,6 +738,8 @@ get_roots(void *own_opaque, gc_visitor visitor, void *visitor_opaque) for (size_t i = 0; i < ctx->iterative_runners.len; i++) { apfl_iterative_runner_visit_gc_objects(ctx->iterative_runners.items[i], visitor, visitor_opaque); } + + apfl_registry_visit_gc_objects(ctx->registry, visitor, visitor_opaque); } static struct call_stack @@ -867,6 +870,7 @@ apfl_ctx_new(struct apfl_config config) ctx->call_stack = call_stack_new(); ctx->globals = NULL; ctx->iterative_runners = iterative_runners_list_new(); + ctx->registry = NULL; apfl_gc_init(&ctx->gc, config.allocator, get_roots, ctx); @@ -876,6 +880,10 @@ apfl_ctx_new(struct apfl_config config) ctx->output_writer = config.output_writer; + if ((ctx->registry = apfl_registry_new(ctx->gc.allocator)) == NULL) { + goto error; + } + if (!init_globals(ctx)) { goto error; } @@ -910,6 +918,9 @@ apfl_ctx_destroy(apfl_ctx ctx) FREE_LIST(ctx->gc.allocator, ctx->iterative_runners.items, ctx->iterative_runners.cap); ctx->iterative_runners = iterative_runners_list_new(); + apfl_registry_destroy(ctx->registry); + ctx->registry = NULL; + struct apfl_allocator base_allocator = ctx->gc.base_allocator; apfl_gc_full(&ctx->gc); diff --git a/src/context.h b/src/context.h index 78b9fac..a2666ba 100644 --- a/src/context.h +++ b/src/context.h @@ -155,6 +155,8 @@ struct apfl_ctx_data { struct iterative_runners_list iterative_runners; struct apfl_io_writer output_writer; + + struct apfl_hashmap *registry; }; void apfl_matcher_call_stack_entry_deinit(struct apfl_allocator, struct matcher_call_stack_entry *); diff --git a/src/globals.apfl b/src/globals.apfl index bc63a43..83a74e3 100644 --- a/src/globals.apfl +++ b/src/globals.apfl @@ -256,5 +256,6 @@ 'has-key -> has-key 'symbol -> symbol 'Some -> Some + 'get-argv -> builtins.get-argv ] } diff --git a/src/main.c b/src/main.c index e6c5509..c427042 100644 --- a/src/main.c +++ b/src/main.c @@ -173,8 +173,6 @@ eval( bool run_as_repl, const char **argv ) { - (void)argv; - struct apfl_io_writer w_out = apfl_io_file_writer(stdout); struct apfl_io_writer w_err = apfl_io_file_writer(stderr); @@ -187,6 +185,14 @@ eval( return 1; } + apfl_list_create(ctx, 0); + while (*argv != NULL) { + apfl_push_const_string(ctx, *argv); + apfl_list_append(ctx, -2, -1); + argv++; + } + apfl_argv_set(ctx, -1); + int rv = 0; if (run_as_repl) { apfl_iterative_runner runner = apfl_iterative_runner_new(ctx, source_reader); diff --git a/src/registry.c b/src/registry.c new file mode 100644 index 0000000..e3bba69 --- /dev/null +++ b/src/registry.c @@ -0,0 +1,133 @@ +#include + +#include "apfl.h" + +#include "alloc.h" +#include "context.h" +#include "hashmap.h" + +struct registry_key { + void *major; + size_t minor; +}; + +bool +keys_eq(void *opaque, const void *_a, const void *_b) +{ + (void)opaque; + + const struct registry_key *a = _a; + const struct registry_key *b = _b; + + return a->major == b->major && a->minor == b->minor; +} + +apfl_hash +calc_hash(void *opaque, const void *_key) +{ + (void)opaque; + + const struct registry_key *key = _key; + apfl_hash h = apfl_hash_fnv1a(&key->major, sizeof(void *)); + h = apfl_hash_fnv1a_add(&key->minor, sizeof(size_t), h); + return h; +} + +struct apfl_hashmap * +apfl_registry_new(struct apfl_allocator allocator) +{ + struct apfl_hashmap *registry = ALLOC_OBJ(allocator, struct apfl_hashmap); + if (registry == NULL) { + return NULL; + } + + if (!apfl_hashmap_init( + registry, + allocator, + (struct apfl_hashmap_callbacks) { + .opaque = NULL, + .keys_eq = keys_eq, + .calc_hash = calc_hash, + }, + sizeof(struct registry_key), + sizeof(struct apfl_value) + )) { + FREE_OBJ(allocator, registry); + return NULL; + } + + return registry; +} + +void +apfl_registry_set(apfl_ctx ctx, void *key_major, size_t key_minor, apfl_stackidx value_stackidx) +{ + assert(ctx->registry != NULL); + + struct apfl_value value = apfl_stack_must_get(ctx, value_stackidx); + + struct registry_key key = { + .major = key_major, + .minor = key_minor, + }; + if (!apfl_hashmap_set(ctx->registry, &key, &value)) { + apfl_raise_alloc_error(ctx); + } + + apfl_drop(ctx, value_stackidx); +} + +void +apfl_registry_delete(apfl_ctx ctx, void *key_major, size_t key_minor) +{ + assert(ctx->registry != NULL); + struct registry_key key = { + .major = key_major, + .minor = key_minor, + }; + + apfl_hashmap_delete(ctx->registry, &key); +} + +bool +apfl_registry_try_get(apfl_ctx ctx, void *key_major, size_t key_minor) +{ + assert(ctx->registry != NULL); + struct registry_key key = { + .major = key_major, + .minor = key_minor, + }; + + struct apfl_value value; + if (!apfl_hashmap_get(ctx->registry, &key, &value)) { + return false; + } + + apfl_stack_must_push(ctx, apfl_value_set_cow_flag(value)); + return true; +} + +void +apfl_registry_destroy(struct apfl_hashmap *registry) +{ + if (registry == NULL) { + return; + } + + struct apfl_allocator allocator = registry->allocator; + apfl_hashmap_deinit(registry); + FREE_OBJ(allocator, registry); +} + +void +apfl_registry_visit_gc_objects(struct apfl_hashmap *registry, gc_visitor visitor, void *opaque) +{ + if (registry == NULL) { + return; + } + + HASHMAP_EACH(registry, cur) { + struct apfl_value *v = apfl_hashmap_cursor_peek_value(cur); + apfl_value_visit_gc_object(*v, visitor, opaque); + } +} diff --git a/src/registry.h b/src/registry.h new file mode 100644 index 0000000..cce3077 --- /dev/null +++ b/src/registry.h @@ -0,0 +1,21 @@ +#ifndef APFL_REGISTRY_H +#define APFL_REGISTRY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "apfl.h" + +#include "gc.h" +#include "hashmap.h" + +struct apfl_hashmap *apfl_registry_new(struct apfl_allocator allocator); +void apfl_registry_destroy(struct apfl_hashmap *); +void apfl_registry_visit_gc_objects(struct apfl_hashmap *, gc_visitor visitor, void *opaque); + +#ifdef __cplusplus +} +#endif + +#endif