diff --git a/lang/codegen/block.c b/lang/codegen/block.c index 4668702..4825e1c 100644 --- a/lang/codegen/block.c +++ b/lang/codegen/block.c @@ -45,8 +45,6 @@ static enum ivy_status state_init( uintptr_t argv, void *argp) { struct block_codegen_state *block = (struct block_codegen_state *)state; - block->s_scope = codegen_push_scope(gen); - return IVY_OK; } @@ -54,8 +52,6 @@ static enum ivy_status state_fini( struct ivy_codegen *gen, struct code_generator_state *state, struct mie_value **result) { - codegen_pop_scope(gen); - return IVY_OK; } diff --git a/lang/codegen/codegen.c b/lang/codegen/codegen.c index 05b4c0d..7e9687b 100644 --- a/lang/codegen/codegen.c +++ b/lang/codegen/codegen.c @@ -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) { diff --git a/lang/codegen/codegen.h b/lang/codegen/codegen.h index 774315a..279c9c4 100644 --- a/lang/codegen/codegen.h +++ b/lang/codegen/codegen.h @@ -1,6 +1,8 @@ #ifndef _LANG_CODEGEN_H_ #define _LANG_CODEGEN_H_ +#include "var-map.h" + #include #include #include @@ -13,6 +15,8 @@ struct ivy_ast_node; struct mie_value; struct mie_func; +struct codegen_var; + #define CODEGEN_RESULT_OK(flags) \ (struct code_generator_result) \ { \ @@ -27,18 +31,6 @@ struct mie_func; #define __AST_INDEX(type) IVY_AST_##type #define NODE_CODEGEN(type, func) [__AST_INDEX(type)] = func -struct codegen_value { - b_queue_entry v_entry; - struct ivy_ast_node *v_node; - struct mie_value *v_value; -}; - -struct codegen_var { - b_queue_entry v_entry; - struct ivy_ast_ident_node *v_ident; - struct mie_value *v_ptr; -}; - enum code_generator_flags { CODEGEN_F_IGNORE_RESULT = 0x01u, }; @@ -70,6 +62,12 @@ struct code_generator_result { } r_flags; }; +struct codegen_value { + b_queue_entry v_entry; + struct ivy_ast_node *v_node; + struct mie_value *v_value; +}; + struct code_generator_state; typedef enum ivy_status (*code_generator_state_init_callback)( @@ -83,6 +81,15 @@ typedef struct code_generator_result (*code_generator_node_callback)( struct ivy_ast_node *, size_t); typedef struct code_generator_result (*code_generator_value_received_callback)( struct ivy_codegen *, struct code_generator_state *, struct mie_value *); +typedef enum ivy_status (*code_generator_define_variable_callback)( + struct ivy_codegen *, struct code_generator_state *, const char *, + const struct codegen_var *); +typedef enum ivy_status (*code_generator_resolve_variable_callback)( + struct ivy_codegen *, struct code_generator_state *, const char *, + struct codegen_var *); +typedef enum ivy_status (*code_generator_capture_variable_callback)( + struct ivy_codegen *, struct code_generator_state *, const char *, + struct codegen_var *); struct code_generator { enum code_generator_type g_type; @@ -93,6 +100,9 @@ struct code_generator { code_generator_node_callback g_node_generators[IVY_AST_TYPE_COUNT]; code_generator_node_callback g_expr_generator; code_generator_value_received_callback g_value_received; + code_generator_define_variable_callback g_define_var; + code_generator_resolve_variable_callback g_resolve_var; + code_generator_capture_variable_callback g_capture_var; }; struct code_generator_state { @@ -104,13 +114,6 @@ struct code_generator_state { size_t s_depth; }; -struct code_generator_scope { - enum code_generator_scope_type s_type; - b_queue_entry s_entry; - /* TODO turn this into a bst */ - b_queue s_vars; -}; - struct ivy_codegen { b_queue c_values; b_queue c_state; @@ -131,11 +134,6 @@ extern enum ivy_status codegen_push_generator( extern enum ivy_status codegen_pop_generator( struct ivy_codegen *gen, struct mie_value **result); -extern struct code_generator_scope *codegen_push_scope(struct ivy_codegen *gen); -extern void codegen_pop_scope(struct ivy_codegen *gen); -extern struct code_generator_scope *codegen_get_current_scope( - struct ivy_codegen *gen); - extern struct codegen_value *codegen_value_create( struct ivy_ast_node *node, struct mie_value *val); extern void codegen_value_destroy(struct codegen_value *val); @@ -143,11 +141,11 @@ extern void codegen_value_destroy(struct codegen_value *val); extern void codegen_push_value(struct ivy_codegen *gen, struct codegen_value *val); extern struct codegen_value *codegen_pop_value(struct ivy_codegen *gen); -extern struct codegen_var *codegen_resolve_variable( - struct ivy_codegen *gen, const char *ident); - -extern enum ivy_status code_generator_scope_put_variable( - struct code_generator_scope *scope, struct ivy_ast_ident_node *ident, - struct mie_value *ptr); +extern enum ivy_status codegen_define_variable( + struct ivy_codegen *gen, const char *ident, const struct codegen_var *var); +extern enum ivy_status codegen_resolve_variable( + struct ivy_codegen *gen, const char *ident, struct codegen_var *out); +extern struct mie_value *codegen_load_variable( + struct ivy_codegen *gen, struct codegen_var *var); #endif diff --git a/lang/codegen/expr.c b/lang/codegen/expr.c index e175a37..df1e5a3 100644 --- a/lang/codegen/expr.c +++ b/lang/codegen/expr.c @@ -178,8 +178,14 @@ static struct code_generator_result gen_var_reference( struct mie_value *var_ptr = NULL; 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); + struct codegen_var var = {}; + enum ivy_status status + = codegen_resolve_variable(gen, ident->n_content->t_str, &var); + if (status != IVY_OK) { + return CODEGEN_RESULT_ERR(status); + } + +#if 0 if (var) { /* this is a local variable */ var_ptr = var->v_ptr; @@ -192,8 +198,13 @@ static struct code_generator_result gen_var_reference( struct mie_type *id = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID); struct mie_value *var_value = mie_builder_load(gen->c_builder, id, var_ptr, NULL); +#endif + struct mie_value *var_value = codegen_load_variable(gen, &var); + if (!var_value) { + return CODEGEN_RESULT_ERR(IVY_ERR_INTERNAL_FAILURE); + } - enum ivy_status status = push_operand(expr, node, var_value); + status = push_operand(expr, node, var_value); if (status != IVY_OK) { return CODEGEN_RESULT_ERR(status); diff --git a/lang/codegen/unit.c b/lang/codegen/unit.c index 639d2e7..f207066 100644 --- a/lang/codegen/unit.c +++ b/lang/codegen/unit.c @@ -1,4 +1,5 @@ #include "codegen.h" +#include "var-map.h" #include #include @@ -10,6 +11,7 @@ struct unit_codegen_state { /* function for top-level statements */ // struct mie_block *s_immediate_alloca; struct mie_func *s_immediate; + struct codegen_var_map s_vars; }; static enum ivy_status switch_to_immediate_func( @@ -151,7 +153,7 @@ static enum ivy_status state_init( uintptr_t argv, void *argp) { struct unit_codegen_state *unit = (struct unit_codegen_state *)state; - unit->s_scope = codegen_push_scope(gen); + codegen_var_map_init(&unit->s_vars); return IVY_OK; } @@ -160,11 +162,37 @@ static enum ivy_status state_fini( struct ivy_codegen *gen, struct code_generator_state *state, struct mie_value **result) { - codegen_pop_scope(gen); + struct unit_codegen_state *unit = (struct unit_codegen_state *)state; + codegen_var_map_fini(&unit->s_vars); return IVY_OK; } +static enum ivy_status define_var( + struct ivy_codegen *gen, struct code_generator_state *state, + const char *ident, const struct codegen_var *var) +{ + struct unit_codegen_state *unit = (struct unit_codegen_state *)state; + return codegen_var_map_put(&unit->s_vars, ident, var); +} + +static enum ivy_status resolve_var( + struct ivy_codegen *gen, struct code_generator_state *state, + const char *ident, struct codegen_var *var) +{ + struct unit_codegen_state *unit = (struct unit_codegen_state *)state; + struct codegen_var *result = NULL; + enum ivy_status status + = codegen_var_map_get(&unit->s_vars, ident, &result); + + if (status != IVY_OK) { + return status; + } + + memcpy(var, result, sizeof *var); + return IVY_OK; +} + struct code_generator unit_generator = { .g_type = CODE_GENERATOR_UNIT, .g_state_size = sizeof(struct unit_codegen_state), @@ -174,4 +202,6 @@ struct code_generator unit_generator = { NODE_CODEGEN(VAR, gen_var_declaration), }, .g_expr_generator = gen_expr, + .g_define_var = define_var, + .g_resolve_var = resolve_var, }; diff --git a/lang/codegen/var-map.c b/lang/codegen/var-map.c new file mode 100644 index 0000000..0ad0bd0 --- /dev/null +++ b/lang/codegen/var-map.c @@ -0,0 +1,73 @@ +#include "var-map.h" + +#include +#include +#include +#include + +enum ivy_status codegen_var_map_init(struct codegen_var_map *map) +{ + memset(map, 0x0, sizeof *map); + map->m_map = b_hashmap_create(free, free); + + return IVY_OK; +} + +enum ivy_status codegen_var_map_fini(struct codegen_var_map *map) +{ + b_hashmap_release(map->m_map); + return IVY_OK; +} + +enum ivy_status codegen_var_map_get( + struct codegen_var_map *map, const char *ident, struct codegen_var **out) +{ + b_hashmap_key key = { + .key_data = ident, + .key_size = strlen(ident), + }; + + const b_hashmap_value *value = b_hashmap_get(map->m_map, &key); + + if (!value) { + return IVY_ERR_NO_ENTRY; + } + + *out = value->value_data; + + return IVY_OK; +} + +enum ivy_status codegen_var_map_put( + struct codegen_var_map *map, const char *ident, + const struct codegen_var *var) +{ + b_hashmap_key key = { + .key_data = b_strdup(ident), + .key_size = strlen(ident), + }; + + if (!key.key_data) { + return IVY_ERR_NO_MEMORY; + } + + b_hashmap_value value = { + .value_data = malloc(sizeof *var), + .value_size = sizeof *var, + }; + + if (!value.value_data) { + free((void *)key.key_data); + return IVY_ERR_NO_MEMORY; + } + + memcpy(value.value_data, var, sizeof *var); + + b_status status = b_hashmap_put(map->m_map, &key, &value); + if (!B_OK(status)) { + free((void *)key.key_data); + free(value.value_data); + } + + return ivy_status_from_b_status(status); +} diff --git a/lang/codegen/var-map.h b/lang/codegen/var-map.h new file mode 100644 index 0000000..1fdfd62 --- /dev/null +++ b/lang/codegen/var-map.h @@ -0,0 +1,35 @@ +#ifndef CODEGEN_VAR_MAP_H_ +#define CODEGEN_VAR_MAP_H_ + +#include + +struct b_hashmap; +struct mie_value; +struct ivy_ast_node; + +enum codegen_var_flags { + CODEGEN_VAR_F_PTR = 0x01u, + CODEGEN_VAR_F_CAPTURE = 0x02u, +}; + +struct codegen_var { + enum codegen_var_flags v_flags; + struct mie_type *v_type; + struct ivy_ast_node *v_node; + struct mie_value *v_value; +}; + +struct codegen_var_map { + struct b_hashmap *m_map; +}; + +extern enum ivy_status codegen_var_map_init(struct codegen_var_map *map); +extern enum ivy_status codegen_var_map_fini(struct codegen_var_map *map); + +extern enum ivy_status codegen_var_map_get( + struct codegen_var_map *map, const char *ident, struct codegen_var **out); +extern enum ivy_status codegen_var_map_put( + struct codegen_var_map *map, const char *ident, + const struct codegen_var *var); + +#endif diff --git a/lang/codegen/var.c b/lang/codegen/var.c index 24afe16..eca700e 100644 --- a/lang/codegen/var.c +++ b/lang/codegen/var.c @@ -106,8 +106,24 @@ static enum ivy_status state_fini( debug_printf("codegen: end of var decl\n"); struct var_codegen_state *var = (struct var_codegen_state *)state; - struct code_generator_scope *scope = codegen_get_current_scope(gen); - code_generator_scope_put_variable(scope, var->s_var_ident, var->s_var_ptr); + 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);