Files
ivy/lang/codegen/var.c
Max Wash 7483b32c25 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.
2025-04-22 15:23:42 +01:00

163 lines
4.5 KiB
C

#include "../debug.h"
#include "codegen.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct var_codegen_state {
struct code_generator_state s_base;
unsigned int s_prev_node;
/* TODO support multiple idents (for tuples) */
struct ivy_ast_ident_node *s_var_ident;
struct mie_value *s_var_ptr;
struct mie_value *s_value;
};
static struct code_generator_result gen_var(
struct ivy_codegen *gen, struct code_generator_state *state,
struct ivy_ast_node *node, size_t depth)
{
struct var_codegen_state *var = (struct var_codegen_state *)state;
if (var->s_prev_node != 0) {
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
}
var->s_prev_node = IVY_AST_VAR;
return CODEGEN_RESULT_OK(0);
}
static struct code_generator_result gen_value_expr(
struct ivy_codegen *gen, struct code_generator_state *state,
struct ivy_ast_node *node, size_t depth)
{
struct var_codegen_state *var = (struct var_codegen_state *)state;
if (var->s_prev_node != IVY_AST_IDENT && var->s_prev_node != IVY_AST_TUPLE) {
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
}
codegen_push_generator(gen, CODE_GENERATOR_EXPR, 0, NULL);
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
}
static struct code_generator_result gen_ident(
struct ivy_codegen *gen, struct code_generator_state *state,
struct ivy_ast_node *node, size_t depth)
{
struct var_codegen_state *var = (struct var_codegen_state *)state;
if (var->s_prev_node != IVY_AST_VAR) {
return gen_value_expr(gen, state, node, depth);
}
struct ivy_ast_ident_node *ident = (struct ivy_ast_ident_node *)node;
const char *var_name = ident->n_content->t_str;
/* TODO get type from expression */
struct mie_type *id = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID);
struct mie_value *var_ptr
= mie_builder_alloca(gen->c_builder, id, var_name);
var->s_var_ident = (struct ivy_ast_ident_node *)node;
var->s_var_ptr = var_ptr;
var->s_prev_node = IVY_AST_IDENT;
return CODEGEN_RESULT_OK(0);
}
#if 0
static struct code_generator_result gen_var_ref(
struct ivy_codegen *gen, struct code_generator_state *state,
struct ivy_ast_node *node)
{
struct ivy_ast_ident_node *ident = (struct ivy_ast_ident_node *)node;
struct codegen_var *var
= codegen_resolve_variable(gen, ident->n_content->t_str);
if (var) {
/* this variable has been defined previously, and we have a
* mie_value representing its location on the stack */
struct codegen_value *var_value
= codegen_value_create(node, var->v_ptr);
codegen_push_value(gen, var_value);
return CODEGEN_RESULT_OK(0);
}
/* this variable either doesn't exist, or is a global variable */
struct codegen_value *var_value = codegen_value_create(node, NULL);
codegen_push_value(gen, var_value);
return CODEGEN_RESULT_OK(0);
}
#endif
static enum ivy_status state_init(
struct ivy_codegen *gen, struct code_generator_state *state,
uintptr_t argv, void *argp)
{
debug_printf("codegen: start of var decl\n");
return IVY_OK;
}
static enum ivy_status state_fini(
struct ivy_codegen *gen, struct code_generator_state *state,
struct mie_value **result)
{
debug_printf("codegen: end of var decl\n");
struct var_codegen_state *var = (struct var_codegen_state *)state;
const char *ident = var->s_var_ident->n_content->t_str;
struct mie_type *type = NULL;
if (var->s_value) {
type = mie_value_get_type(var->s_value);
} else {
type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID);
}
struct codegen_var var_info = {
.v_node = (struct ivy_ast_node *)var->s_var_ident,
.v_type = type,
.v_value = var->s_var_ptr,
};
codegen_define_variable(gen, ident, &var_info);
// struct code_generator_scope *scope = codegen_get_current_scope(gen);
// code_generator_scope_put_variable(scope, var->s_var_ident, var->s_var_ptr);
if (var->s_value) {
mie_builder_store(gen->c_builder, var->s_value, var->s_var_ptr);
}
return IVY_OK;
}
static struct code_generator_result value_received(
struct ivy_codegen *gen, struct code_generator_state *state,
struct mie_value *value)
{
debug_printf("codegen: var decl value received\n");
struct var_codegen_state *var = (struct var_codegen_state *)state;
if (!var->s_var_ptr) {
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
}
var->s_value = value;
return CODEGEN_RESULT_OK(CODEGEN_R_POP_GENERATOR);
}
struct code_generator var_generator = {
.g_type = CODE_GENERATOR_VAR,
.g_state_size = sizeof(struct var_codegen_state),
.g_state_init = state_init,
.g_state_fini = state_fini,
.g_value_received = value_received,
.g_expr_generator = gen_value_expr,
.g_node_generators = {
[IVY_AST_VAR] = gen_var,
[IVY_AST_IDENT] = gen_ident,
},
};