lang: codegen: redesign variable definition/resolution system to support capturing
the codegen scope system has been removed. instead, each generator state in the stack, from the current state backwards, is informed when a variable is defined, resolved, or captured. when a variable is defined, the state stack is traversed back-to-front (current generator first). each state has a chance to record the variable definition. once one state has signalled that it has recorded the variable definition, the traversal ends. when a variable is resolved, the state stack is traversed back-to-front (current generator first). each state is asked whether or not it recognises the variable identifier being resolved. if a state has the variable in question defined, it returns information about the variable definition, and the traversal stops. once a variable has been resolved, the state stack is traversed front-to-back (current generator last), starting from the generator /after/ the one that provided the variable definition. each generator in the iteration is given the chance to adjust the variable information, or generate IR in response to the variable being accessed. this is used to implement variable capture, where the state of a variable in the enclosing context is captured for later use.
This commit is contained in:
@@ -81,73 +81,6 @@ enum ivy_status codegen_pop_generator(
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
static struct codegen_var *code_generator_scope_get_variable(
|
||||
struct code_generator_scope *scope, const char *ident)
|
||||
{
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &scope->s_vars) {
|
||||
struct codegen_var *var
|
||||
= b_unbox(struct codegen_var, it.entry, v_entry);
|
||||
|
||||
if (!strcmp(var->v_ident->n_content->t_str, ident)) {
|
||||
return var;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool code_generator_scope_is_top_level(struct code_generator_scope *scope)
|
||||
{
|
||||
switch (scope->s_type) {
|
||||
case CODE_GENERATOR_SCOPE_FUNC:
|
||||
case CODE_GENERATOR_SCOPE_UNIT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void code_generator_scope_destroy(struct code_generator_scope *scope)
|
||||
{
|
||||
/* TODO clean up variables */
|
||||
free(scope);
|
||||
}
|
||||
|
||||
struct code_generator_scope *codegen_push_scope(struct ivy_codegen *gen)
|
||||
{
|
||||
struct code_generator_scope *scope = malloc(sizeof *scope);
|
||||
if (!scope) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(scope, 0x0, sizeof *scope);
|
||||
b_queue_push_back(&gen->c_scope, &scope->s_entry);
|
||||
|
||||
return scope;
|
||||
}
|
||||
|
||||
void codegen_pop_scope(struct ivy_codegen *gen)
|
||||
{
|
||||
b_queue_entry *entry = b_queue_pop_back(&gen->c_scope);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct code_generator_scope *scope
|
||||
= b_unbox(struct code_generator_scope, entry, s_entry);
|
||||
code_generator_scope_destroy(scope);
|
||||
}
|
||||
|
||||
struct code_generator_scope *codegen_get_current_scope(struct ivy_codegen *gen)
|
||||
{
|
||||
b_queue_entry *entry = b_queue_last(&gen->c_scope);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return b_unbox(struct code_generator_scope, entry, s_entry);
|
||||
}
|
||||
|
||||
struct codegen_value *codegen_value_create(
|
||||
struct ivy_ast_node *node, struct mie_value *val)
|
||||
{
|
||||
@@ -184,49 +117,112 @@ struct codegen_value *codegen_pop_value(struct ivy_codegen *gen)
|
||||
return b_unbox(struct codegen_value, entry, v_entry);
|
||||
}
|
||||
|
||||
struct codegen_var *codegen_resolve_variable(
|
||||
struct ivy_codegen *gen, const char *ident)
|
||||
enum ivy_status codegen_define_variable(
|
||||
struct ivy_codegen *gen, const char *ident, const struct codegen_var *var)
|
||||
{
|
||||
b_queue_entry *cur = b_queue_last(&gen->c_scope);
|
||||
while (cur) {
|
||||
struct code_generator_scope *scope
|
||||
= b_unbox(struct code_generator_scope, cur, s_entry);
|
||||
struct codegen_var *var
|
||||
= code_generator_scope_get_variable(scope, ident);
|
||||
b_queue_entry *entry = b_queue_last(&gen->c_state);
|
||||
if (!entry) {
|
||||
return IVY_ERR_NO_ENTRY;
|
||||
}
|
||||
|
||||
if (var) {
|
||||
return var;
|
||||
bool resolved = false;
|
||||
|
||||
while (entry) {
|
||||
struct code_generator_state *state
|
||||
= b_unbox(struct code_generator_state, entry, s_entry);
|
||||
const struct code_generator *generator = state->s_gen;
|
||||
enum ivy_status status = IVY_ERR_NO_ENTRY;
|
||||
|
||||
if (generator->g_define_var) {
|
||||
status = generator->g_define_var(gen, state, ident, var);
|
||||
}
|
||||
|
||||
if (code_generator_scope_is_top_level(scope)) {
|
||||
if (status == IVY_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
cur = b_queue_prev(cur);
|
||||
entry = b_queue_prev(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return IVY_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
enum ivy_status code_generator_scope_put_variable(
|
||||
struct code_generator_scope *scope, struct ivy_ast_ident_node *ident,
|
||||
struct mie_value *ptr)
|
||||
enum ivy_status resolve_global_variable(
|
||||
struct ivy_codegen *gen, const char *ident, struct codegen_var *out)
|
||||
{
|
||||
struct codegen_var *var = malloc(sizeof *var);
|
||||
if (!var) {
|
||||
return IVY_ERR_NO_MEMORY;
|
||||
}
|
||||
struct mie_value *var_ptr
|
||||
= mie_builder_get_data_ptr(gen->c_builder, ident);
|
||||
|
||||
memset(var, 0x0, sizeof *var);
|
||||
|
||||
var->v_ident = ident;
|
||||
var->v_ptr = ptr;
|
||||
|
||||
b_queue_push_back(&scope->s_vars, &var->v_entry);
|
||||
out->v_type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID);
|
||||
out->v_node = NULL;
|
||||
out->v_flags = CODEGEN_VAR_F_PTR;
|
||||
out->v_value = var_ptr;
|
||||
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
enum ivy_status codegen_resolve_variable(
|
||||
struct ivy_codegen *gen, const char *ident, struct codegen_var *out)
|
||||
{
|
||||
b_queue_entry *entry = b_queue_last(&gen->c_state);
|
||||
if (!entry) {
|
||||
return IVY_ERR_NO_ENTRY;
|
||||
}
|
||||
|
||||
bool resolved = false;
|
||||
|
||||
while (entry) {
|
||||
struct code_generator_state *state
|
||||
= b_unbox(struct code_generator_state, entry, s_entry);
|
||||
const struct code_generator *generator = state->s_gen;
|
||||
enum ivy_status status = IVY_ERR_NO_ENTRY;
|
||||
|
||||
if (generator->g_resolve_var) {
|
||||
status = generator->g_resolve_var(gen, state, ident, out);
|
||||
}
|
||||
|
||||
if (status == IVY_OK) {
|
||||
resolved = true;
|
||||
break;
|
||||
}
|
||||
|
||||
entry = b_queue_prev(entry);
|
||||
}
|
||||
|
||||
if (!resolved) {
|
||||
return resolve_global_variable(gen, ident, out);
|
||||
}
|
||||
|
||||
if (entry) {
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
while (entry) {
|
||||
struct code_generator_state *state
|
||||
= b_unbox(struct code_generator_state, entry, s_entry);
|
||||
const struct code_generator *generator = state->s_gen;
|
||||
enum ivy_status status = IVY_OK;
|
||||
|
||||
if (generator->g_capture_var) {
|
||||
status = generator->g_capture_var(gen, state, ident, out);
|
||||
}
|
||||
|
||||
if (status != IVY_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
struct mie_value *codegen_load_variable(
|
||||
struct ivy_codegen *gen, struct codegen_var *var)
|
||||
{
|
||||
return mie_builder_load(gen->c_builder, var->v_type, var->v_value, NULL);
|
||||
}
|
||||
|
||||
static struct code_generator_state *get_current_generator_state(
|
||||
struct ivy_codegen *gen)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user