Implement the registry and a agrv getter to test it

The registry is a global dictionary accessible from C that stores arbitrary
apfl values.
This commit is contained in:
Laria 2023-03-30 22:11:44 +02:00
parent 370fb89367
commit c07caa9aa2
9 changed files with 200 additions and 2 deletions

View file

@ -31,6 +31,7 @@ add_library(apfl
builtins.c
context.c
eval.c
registry.c
scope.c
symbols.c

View file

@ -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.

View file

@ -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);
}

View file

@ -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);

View file

@ -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 *);

View file

@ -256,5 +256,6 @@
'has-key -> has-key
'symbol -> symbol
'Some -> Some
'get-argv -> builtins.get-argv
]
}

View file

@ -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);

133
src/registry.c Normal file
View file

@ -0,0 +1,133 @@
#include <assert.h>
#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);
}
}

21
src/registry.h Normal file
View file

@ -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