[cexpr] Support chained contexts for scoping

cexpr's symbol tables currently aren't readily extended, and dynamic
scoping is usually a good thing anyway. The chain of contexts is walked
when a symbol is not found in the current context's symtab, but minor
efforts are made to avoid checking the same symtab twice (usually cased
by cloning a context but not updating the symtab).
This commit is contained in:
Bill Currie 2021-12-04 12:28:46 +09:00
parent 049968b38e
commit 44102f2639
3 changed files with 35 additions and 9 deletions

View file

@ -93,6 +93,7 @@ typedef struct exprarray_s {
} exprarray_t;
typedef struct exprctx_s {
struct exprctx_s *parent; // for nested symol scopes
exprval_t *result;
exprtab_t *symtab; // directly accessible symbols
exprtab_t *external_variables; // accessible via $id

View file

@ -286,12 +286,23 @@ static exprval_t *parse_double (const char *str, exprctx_t *context)
static exprsym_t *
parse_name (const char *name, exprctx_t *context)
{
exprtab_t *symtab = context->symtab;
exprsym_t *sym = 0;
exprtab_t *prev_tab = 0;
if (!symtab) {
return 0;
for (exprctx_t *ctx = context; ctx && !sym; ctx = ctx->parent) {
exprtab_t *symtab = ctx->symtab;
if (!symtab) {
// scope barrier
break;
}
if (symtab == prev_tab) {
// already checked this symtab
continue;
}
prev_tab = symtab;
sym = Hash_Find (symtab->tab, name);
}
__auto_type sym = (exprsym_t *) Hash_Find (symtab->tab, name);
return sym;
}
@ -302,8 +313,20 @@ parse_variable (const char *name, exprctx_t *context)
if (strcmp (name, "cvars") == 0) {
val = cexpr_cvar_struct (context);
} else {
exprtab_t *symtab = context->external_variables;
__auto_type sym = (exprsym_t *) Hash_Find (symtab->tab, name);
exprsym_t *sym = 0;
exprtab_t *prev_tab = 0;
for (exprctx_t *ctx = context; ctx && !sym; ctx = ctx->parent) {
exprtab_t *symtab = ctx->external_variables;
if (!symtab) {
// scope barrier
break;
}
if (symtab == prev_tab) {
// already checked this symtab
continue;
}
sym = Hash_Find (symtab->tab, name);
}
if (sym) {
val = cexpr_value_reference (sym->type, sym->value, context);
}

View file

@ -153,11 +153,13 @@ exprval_t dist_result = { &cexpr_float, (float *)&plane + 3 };
exprval_t intercept_result = { &cexpr_vector, &intercept };
exprtab_t symtab = {
symbols,
0
.symbols = symbols,
};
exprctx_t context = { &test_result, &symtab };
exprctx_t context = {
.result = &test_result,
.symtab = &symtab
};
#define TEST_BINOP(op) \
do { \