mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-19 07:20:50 +00:00
[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:
parent
049968b38e
commit
44102f2639
3 changed files with 35 additions and 9 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 { \
|
||||
|
|
Loading…
Reference in a new issue