Move scope functions/structs out of context.[ch]

This commit is contained in:
Laria 2022-04-15 14:41:22 +02:00
parent 6add5e47b9
commit b3322c93e9
6 changed files with 179 additions and 155 deletions

View file

@ -17,6 +17,7 @@ libapfl_a_SOURCES += parser.c
libapfl_a_SOURCES += position.c
libapfl_a_SOURCES += resizable.c
libapfl_a_SOURCES += source_readers.c
libapfl_a_SOURCES += scope.c
libapfl_a_SOURCES += strings.c
libapfl_a_SOURCES += token.c
libapfl_a_SOURCES += tokenizer.c
@ -31,6 +32,7 @@ apfl_internal_headers += gc.h
apfl_internal_headers += hashmap.h
apfl_internal_headers += internal.h
apfl_internal_headers += resizable.h
apfl_internal_headers += scope.h
apfl_internal_headers += value.h
EXTRA_DIST = $(apfl_internal_headers) apfl.h

View file

@ -10,8 +10,6 @@
#include "resizable.h"
#include "value.h"
typedef struct apfl_value *variable;
static struct stack *
stack_new(struct gc *gc)
{
@ -169,144 +167,6 @@ apfl_stack_drop(apfl_ctx ctx, apfl_stackidx index)
return apfl_stack_pop(ctx, &value, index);
}
static bool
scope_keys_eq(void *opaque, const void *_a, const void *_b)
{
(void)opaque;
const struct apfl_string * const *a = _a;
const struct apfl_string * const *b = _b;
return apfl_string_eq(**a, **b);
}
static apfl_hash
scope_calc_hash(void *opaque, const void *_key)
{
(void)opaque;
const struct apfl_string *const*key = _key;
struct apfl_string_view sv = apfl_string_view_from(**key);
return apfl_hash_fnv1a(sv.bytes, sv.len);
}
static struct scope *
scope_new(struct gc *gc)
{
struct apfl_hashmap map;
if (!apfl_hashmap_init(
&map,
gc->allocator,
(struct apfl_hashmap_callbacks) {
.opaque = NULL,
.keys_eq = scope_keys_eq,
.calc_hash = scope_calc_hash,
},
sizeof(struct apfl_string *),
sizeof(variable)
)) {
return NULL;
}
struct scope *scope = apfl_gc_new_scope(gc);
if (scope == NULL) {
apfl_hashmap_deinit(&map);
return NULL;
}
*scope = (struct scope) {
.map = map,
};
return scope;
}
void
apfl_scope_deinit(struct apfl_allocator allocator, struct scope *scope)
{
(void)allocator;
apfl_hashmap_deinit(&scope->map);
}
void
apfl_gc_var_traverse(struct apfl_value *var, gc_visitor cb, void *opaque)
{
struct gc_object *child = apfl_value_get_gc_object(*var);
if (child != NULL) {
cb(opaque, child);
}
}
void
apfl_gc_scope_traverse(struct scope *scope, gc_visitor cb, void *opaque)
{
HASHMAP_EACH(&scope->map, cur) {
struct apfl_string **k = apfl_hashmap_cursor_peek_key(cur);
assert(k != NULL);
cb(opaque, GC_OBJECT_FROM(*k, GC_TYPE_STRING));
variable *v = apfl_hashmap_cursor_peek_value(cur);
assert(v != NULL);
cb(opaque, GC_OBJECT_FROM(*v, GC_TYPE_VAR));
}
}
bool
apfl_scope_get(struct scope *scope, struct apfl_string *name, struct apfl_value *out)
{
variable var;
if (!apfl_hashmap_get(&scope->map, &name, &var)) {
return false;
}
// The value is now in the variable and outside of it (presumably to be
// saved onto the stack). We need to set the COW flag so a mutation of one
// copy doesn't affect the other one.
*out = apfl_value_set_cow_flag(*var);
return true;
}
static variable
get_or_create_variable(struct gc *gc, struct scope *scope, struct apfl_string *name)
{
variable var;
if (apfl_hashmap_get(&scope->map, &name, &var)) {
return var;
}
struct apfl_hashmap_prepared_set prepared_set;
if (!apfl_hashmap_prepare_set(&scope->map, &prepared_set, &name)) {
return NULL;
}
var = apfl_gc_new_var(gc);
if (var == NULL) {
return NULL;
}
*var = (struct apfl_value) { .type = VALUE_NIL };
apfl_hashmap_set_prepared(prepared_set, &var);
return var;
}
bool
apfl_scope_set(struct gc *gc, struct scope *scope, struct apfl_string *name, struct apfl_value value)
{
variable var = get_or_create_variable(gc, scope, name);
if (var == NULL) {
return false;
}
*var = value;
return true;
}
bool
apfl_scope_create_var(struct gc *gc, struct scope *scope, struct apfl_string *name)
{
return get_or_create_variable(gc, scope, name) != NULL;
}
apfl_ctx
apfl_ctx_new(struct apfl_allocator base_allocator)
{
@ -320,7 +180,7 @@ apfl_ctx_new(struct apfl_allocator base_allocator)
return NULL;
}
if ((ctx->scope = scope_new(&ctx->gc)) == NULL) {
if ((ctx->scope = apfl_scope_new(&ctx->gc)) == NULL) {
goto error;
}

View file

@ -11,6 +11,7 @@ extern "C" {
#include "hashmap.h"
#include "gc.h"
#include "value.h"
#include "scope.h"
struct stack {
struct apfl_value *items;
@ -18,10 +19,6 @@ struct stack {
size_t cap;
};
struct scope {
struct apfl_hashmap map;
};
struct apfl_ctx_data {
struct gc gc;
@ -34,16 +31,6 @@ struct apfl_ctx_data {
void apfl_stack_deinit(struct apfl_allocator, struct stack *);
void apfl_gc_stack_traverse(struct stack *, gc_visitor, void *);
void apfl_scope_deinit(struct apfl_allocator, struct scope *);
bool apfl_scope_get(struct scope *, struct apfl_string *name, struct apfl_value *out);
bool apfl_scope_set(struct gc *, struct scope *, struct apfl_string *name, struct apfl_value value);
bool apfl_scope_create_var(struct gc *, struct scope *, struct apfl_string *name);
void apfl_gc_var_traverse(struct apfl_value *, gc_visitor, void *);
void apfl_gc_scope_traverse(struct scope *, gc_visitor, void *);
bool apfl_stack_push(apfl_ctx, struct apfl_value);
bool apfl_stack_check_index(apfl_ctx, apfl_stackidx *);
bool apfl_stack_pop(apfl_ctx, struct apfl_value *value, apfl_stackidx);

View file

@ -7,6 +7,7 @@
#include "gc.h"
#include "hashmap.h"
#include "resizable.h"
#include "scope.h"
#include "value.h"
#define DEBUG_GC 1

144
src/scope.c Normal file
View file

@ -0,0 +1,144 @@
#include <assert.h>
#include "hashmap.h"
#include "scope.h"
typedef struct apfl_value *variable;
void
apfl_scope_deinit(struct apfl_allocator allocator, struct scope *scope)
{
(void)allocator;
apfl_hashmap_deinit(&scope->map);
}
static bool
scope_keys_eq(void *opaque, const void *_a, const void *_b)
{
(void)opaque;
const struct apfl_string * const *a = _a;
const struct apfl_string * const *b = _b;
return apfl_string_eq(**a, **b);
}
static apfl_hash
scope_calc_hash(void *opaque, const void *_key)
{
(void)opaque;
const struct apfl_string *const*key = _key;
struct apfl_string_view sv = apfl_string_view_from(**key);
return apfl_hash_fnv1a(sv.bytes, sv.len);
}
struct scope *
apfl_scope_new(struct gc *gc)
{
struct apfl_hashmap map;
if (!apfl_hashmap_init(
&map,
gc->allocator,
(struct apfl_hashmap_callbacks) {
.opaque = NULL,
.keys_eq = scope_keys_eq,
.calc_hash = scope_calc_hash,
},
sizeof(struct apfl_string *),
sizeof(variable)
)) {
return NULL;
}
struct scope *scope = apfl_gc_new_scope(gc);
if (scope == NULL) {
apfl_hashmap_deinit(&map);
return NULL;
}
*scope = (struct scope) {
.map = map,
};
return scope;
}
void
apfl_gc_var_traverse(struct apfl_value *var, gc_visitor cb, void *opaque)
{
struct gc_object *child = apfl_value_get_gc_object(*var);
if (child != NULL) {
cb(opaque, child);
}
}
void
apfl_gc_scope_traverse(struct scope *scope, gc_visitor cb, void *opaque)
{
HASHMAP_EACH(&scope->map, cur) {
struct apfl_string **k = apfl_hashmap_cursor_peek_key(cur);
assert(k != NULL);
cb(opaque, GC_OBJECT_FROM(*k, GC_TYPE_STRING));
variable *v = apfl_hashmap_cursor_peek_value(cur);
assert(v != NULL);
cb(opaque, GC_OBJECT_FROM(*v, GC_TYPE_VAR));
}
}
bool
apfl_scope_get(struct scope *scope, struct apfl_string *name, struct apfl_value *out)
{
variable var;
if (!apfl_hashmap_get(&scope->map, &name, &var)) {
return false;
}
// The value is now in the variable and outside of it (presumably to be
// saved onto the stack). We need to set the COW flag so a mutation of one
// copy doesn't affect the other one.
*out = apfl_value_set_cow_flag(*var);
return true;
}
static variable
get_or_create_variable(struct gc *gc, struct scope *scope, struct apfl_string *name)
{
variable var;
if (apfl_hashmap_get(&scope->map, &name, &var)) {
return var;
}
struct apfl_hashmap_prepared_set prepared_set;
if (!apfl_hashmap_prepare_set(&scope->map, &prepared_set, &name)) {
return NULL;
}
var = apfl_gc_new_var(gc);
if (var == NULL) {
return NULL;
}
*var = (struct apfl_value) { .type = VALUE_NIL };
apfl_hashmap_set_prepared(prepared_set, &var);
return var;
}
bool
apfl_scope_set(struct gc *gc, struct scope *scope, struct apfl_string *name, struct apfl_value value)
{
variable var = get_or_create_variable(gc, scope, name);
if (var == NULL) {
return false;
}
*var = value;
return true;
}
bool
apfl_scope_create_var(struct gc *gc, struct scope *scope, struct apfl_string *name)
{
return get_or_create_variable(gc, scope, name) != NULL;
}

30
src/scope.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef APFL_SCOPE_H
#define APFL_SCOPE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "gc.h"
#include "hashmap.h"
#include "value.h"
struct scope {
struct apfl_hashmap map;
};
struct scope *apfl_scope_new(struct gc *);
void apfl_scope_deinit(struct apfl_allocator, struct scope *);
bool apfl_scope_get(struct scope *, struct apfl_string *name, struct apfl_value *out);
bool apfl_scope_set(struct gc *, struct scope *, struct apfl_string *name, struct apfl_value value);
bool apfl_scope_create_var(struct gc *, struct scope *, struct apfl_string *name);
void apfl_gc_var_traverse(struct apfl_value *, gc_visitor, void *);
void apfl_gc_scope_traverse(struct scope *, gc_visitor, void *);
#ifdef __cplusplus
}
#endif
#endif