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:
parent
370fb89367
commit
c07caa9aa2
9 changed files with 200 additions and 2 deletions
|
|
@ -31,6 +31,7 @@ add_library(apfl
|
|||
builtins.c
|
||||
context.c
|
||||
eval.c
|
||||
registry.c
|
||||
scope.c
|
||||
symbols.c
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 *);
|
||||
|
|
|
|||
|
|
@ -256,5 +256,6 @@
|
|||
'has-key -> has-key
|
||||
'symbol -> symbol
|
||||
'Some -> Some
|
||||
'get-argv -> builtins.get-argv
|
||||
]
|
||||
}
|
||||
|
|
|
|||
10
src/main.c
10
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);
|
||||
|
|
|
|||
133
src/registry.c
Normal file
133
src/registry.c
Normal 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
21
src/registry.h
Normal 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
|
||||
Loading…
Reference in a new issue