Move scope functions/structs out of context.[ch]
This commit is contained in:
parent
6add5e47b9
commit
b3322c93e9
6 changed files with 179 additions and 155 deletions
|
|
@ -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
|
||||
|
|
|
|||
142
src/context.c
142
src/context.c
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
1
src/gc.c
1
src/gc.c
|
|
@ -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
144
src/scope.c
Normal 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
30
src/scope.h
Normal 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
|
||||
Loading…
Reference in a new issue