🐛 closure capture and local variables collisions.

main
bog 2024-04-05 21:51:19 +02:00
parent 726b87cad5
commit 603dc6f53a
5 changed files with 110 additions and 25 deletions

View File

@ -66,3 +66,17 @@ assert i() eq 2
assert h() eq 8
assert i() eq 3
var j = fun (count)
return fun ()
count = count + 1
count - 1
end
end
var k = j(37)
assert k() eq 37
assert k() eq 38
assert k() eq 39
assert k() eq 40
assert k() eq 41

View File

@ -149,6 +149,7 @@ void compiler_compile(struct compiler* self,
}
compiler_compile(self, expr, prog, sym);
if (symbol->closure_id != SK_NO_CLOSURE)
{
prog_add_instr(prog, OP_CLOSURE_STORE, symbol->id);
@ -167,7 +168,27 @@ void compiler_compile(struct compiler* self,
break;
}
if (symbol->closure_id != SK_NO_CLOSURE)
struct env* itr = sym->env->parent;
struct symbol* context = NULL;
while (itr)
{
struct symbol* s = env_try_get(itr, symbol->name);
if (s)
{
context = s;
break;
}
itr = itr->parent;
}
if (0 && context)
{
prog_add_instr(prog, OP_LOCAL_LOAD, context->id);
}
else if (symbol->closure_id != SK_NO_CLOSURE)
{
prog_add_instr(prog, OP_CLOSURE_LOAD, symbol->id);
}
@ -189,14 +210,7 @@ void compiler_compile(struct compiler* self,
prog_init(p);
fun_init(fun, p);
for (size_t i=0; i<sym->env->symbols.size; i++)
{
struct symbol* s = sym->env->symbols.data[i];
sym_decl_closure(fun->sym, s->id, s->name);
}
struct node* args = node->children.data[0];
struct node* params = node->children.data[0];
struct node* body = node->children.data[1];
char* var_name =
@ -204,9 +218,9 @@ void compiler_compile(struct compiler* self,
self->var_names.data[self->var_names.size - 1]
: NULL;
for (size_t i=0; i<args->children.size; i++)
for (size_t i=0; i<params->children.size; i++)
{
struct node* child = args->children.data[i];
struct node* child = params->children.data[i];
char* name = child->token->value;
sym_decl_var(fun->sym, name);
}
@ -215,6 +229,30 @@ void compiler_compile(struct compiler* self,
{
sym_decl_var(fun->sym, var_name);
}
// Closure
{
for (size_t i=0; i<sym->env->symbols.size; i++)
{
struct symbol* s = sym->env->symbols.data[i];
sym_decl_closure(fun->sym, s->id, s->name);
}
if (sym->env->parent)
{
for (
size_t i=0;
i<sym->env->parent->symbols.size;
i++
)
{
struct symbol* s =
sym->env->parent->symbols.data[i];
sym_decl_closure(fun->sym, s->id, s->name);
}
}
}
compiler_compile(self, body, p, fun->sym);
union val val;

View File

@ -308,24 +308,55 @@ void exec_capture_env(struct exec* self,
struct env* env)
{
(void) self;
for (size_t i=0; i<env->symbols.size; i++)
if (env->parent)
{
struct symbol* symbol = env->symbols.data[i];
if (symbol->closure_id != SK_NO_CLOSURE)
for (size_t i=0; i<env->parent->symbols.size; i++)
{
struct local* loc =
state_try_get_local_by_id(
state,
symbol->closure_id
);
struct symbol* symbol = env->parent->symbols.data[i];
if (symbol->closure_id != SK_NO_CLOSURE)
{
struct local* loc =
state_try_get_local_by_id(
state,
symbol->closure_id
);
struct value* val =
state_try_get_value(
state,
loc->addr
);
if(!loc) { continue; }
fun_capture(fun, symbol->id, val);
struct value* val =
state_try_get_value(
state,
loc->addr
);
fun_capture(fun, symbol->id, val);
}
}
}
if (env)
{
for (size_t i=0; i<env->symbols.size; i++)
{
struct symbol* symbol = env->symbols.data[i];
if (symbol->closure_id != SK_NO_CLOSURE)
{
struct local* loc =
state_try_get_local_by_id(
state,
symbol->closure_id
);
if(!loc) { continue; }
struct value* val =
state_try_get_value(
state,
loc->addr
);
fun_capture(fun, symbol->id, val);
}
}
}
}

View File

@ -314,6 +314,7 @@ void state_closure_load(struct state* self,
int id)
{
assert(self);
struct frame* frame = state_frame(self);
assert(frame->fun);

View File

@ -142,6 +142,7 @@ int sym_decl_closure(struct sym* self, int id, char const* name)
{
assert(self);
assert(name);
struct symbol* symbol = malloc(sizeof(struct symbol));
symbol_init(symbol, self->closure_counter, name, self->env);
symbol->is_const = false;