diff --git a/lang/ast/node.c b/lang/ast/node.c index ea273a1..e97efa4 100644 --- a/lang/ast/node.c +++ b/lang/ast/node.c @@ -212,6 +212,11 @@ token_parse_function get_token_parser( return NULL; } +struct ivy_ast_node *ivy_ast_node_create(enum ivy_ast_node_type type) +{ + return ast_node_create(type); +} + struct ivy_ast_node *ast_node_create(enum ivy_ast_node_type type) { const struct ast_node_type *type_info = get_ast_node_type(type); @@ -296,3 +301,18 @@ const char *ivy_ast_node_type_to_string(enum ivy_ast_node_type v) return ""; } } + +void ivy_ast_unit_add_node(struct ivy_ast_unit_node *unit, struct ivy_ast_node *child) +{ + b_queue_push_back(&unit->n_children, &child->n_entry); +} + +struct ivy_ast_node *ivy_ast_unit_dequeue_node(struct ivy_ast_unit_node *unit) +{ + b_queue_entry *entry = b_queue_pop_front(&unit->n_children); + if (!entry) { + return NULL; + } + + return b_unbox(struct ivy_ast_node, entry, n_entry); +} diff --git a/lang/codegen/codegen.c b/lang/codegen/codegen.c index 23bbcaa..28c3e70 100644 --- a/lang/codegen/codegen.c +++ b/lang/codegen/codegen.c @@ -7,6 +7,17 @@ #include #include +/* new codegen layout: + * - traverse the AST in pre-order (i.e. in the order it's displayed by debug) + * - each node type (var, msg, expr) gets its own code generator type + * - expr code generator is limited to simple operator arithmetic. + * - when a code generator encounters a node of an equal or lower depth than + * the node that started it, it has reached the end of its subtree. + * - depth is supplied by the ast iterator. + * - need to devise a way for expression code generator to "return" a + * mie_value for its parent generator to use. + */ + enum ivy_status codegen_push_generator( struct ivy_codegen *gen, enum code_generator_type gen_type, void *arg) { @@ -45,7 +56,8 @@ enum ivy_status codegen_push_generator( return IVY_OK; } -enum ivy_status codegen_pop_generator(struct ivy_codegen *gen) +enum ivy_status codegen_pop_generator( + struct ivy_codegen *gen, struct mie_value **result) { b_queue_entry *entry = b_queue_pop_back(&gen->c_state); if (!entry) { @@ -58,7 +70,7 @@ enum ivy_status codegen_pop_generator(struct ivy_codegen *gen) enum ivy_status status = IVY_OK; if (state->s_gen->g_state_fini) { - status = state->s_gen->g_state_fini(gen, state); + status = state->s_gen->g_state_fini(gen, state, result); } if (status != IVY_OK) { @@ -69,19 +81,148 @@ enum ivy_status codegen_pop_generator(struct ivy_codegen *gen) return IVY_OK; } -void codegen_push_value(struct ivy_codegen *gen, struct mie_value *value) +static struct codegen_var *code_generator_scope_get_variable( + struct code_generator_scope *scope, const char *ident) { - b_queue_push_back(&gen->c_ir_values, &value->v_entry); + 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; } -struct mie_value *codegen_pop_value(struct ivy_codegen *gen) +static bool code_generator_scope_is_top_level(struct code_generator_scope *scope) { - b_queue_entry *entry = b_queue_pop_back(&gen->c_ir_values); + 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 mie_value, entry, v_entry); + 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) +{ + struct codegen_value *out = malloc(sizeof *out); + if (!out) { + return NULL; + } + + memset(out, 0x0, sizeof *out); + + out->v_node = node; + out->v_value = val; + + return out; +} + +void codegen_value_destroy(struct codegen_value *val) +{ + free(val); +} + +void codegen_push_value(struct ivy_codegen *gen, struct codegen_value *value) +{ + b_queue_push_back(&gen->c_values, &value->v_entry); +} + +struct codegen_value *codegen_pop_value(struct ivy_codegen *gen) +{ + b_queue_entry *entry = b_queue_pop_back(&gen->c_values); + if (!entry) { + return NULL; + } + + return b_unbox(struct codegen_value, entry, v_entry); +} + +struct codegen_var *codegen_resolve_variable( + struct ivy_codegen *gen, const char *ident) +{ + 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); + + if (var) { + return var; + } + + if (code_generator_scope_is_top_level(scope)) { + break; + } + } + + return NULL; +} + +enum ivy_status code_generator_scope_put_variable( + struct code_generator_scope *scope, struct ivy_ast_ident_node *ident, + struct mie_value *ptr) +{ + struct codegen_var *var = malloc(sizeof *var); + if (!var) { + return IVY_ERR_NO_MEMORY; + } + + memset(var, 0x0, sizeof *var); + + var->v_ident = ident; + var->v_ptr = ptr; + + b_queue_push_back(&scope->s_vars, &var->v_entry); + + return IVY_OK; } static struct code_generator_state *get_current_generator_state( @@ -106,8 +247,6 @@ enum ivy_status ivy_codegen_create(struct ivy_codegen **out) gen->c_ctx = mie_ctx_create(); - codegen_push_generator(gen, CODE_GENERATOR_UNIT, NULL); - *out = gen; return IVY_OK; } @@ -164,14 +303,46 @@ struct mie_module *ivy_codegen_get_current_module(struct ivy_codegen *gen) return gen->c_module; } +static enum ivy_status pop_generator_recurse(struct ivy_codegen *gen) +{ + while (1) { + struct mie_value *value = NULL; + codegen_pop_generator(gen, &value); + struct code_generator_state *state + = get_current_generator_state(gen); + + if (!state || !state->s_gen->g_value_received) { + return IVY_OK; + } + + struct code_generator_result result + = state->s_gen->g_value_received(gen, state, value); + + if (!(result.r_flags & CODEGEN_POP_GENERATOR)) { + return result.r_status; + } + } + + return IVY_OK; +} + enum ivy_status ivy_codegen_push_node( - struct ivy_codegen *gen, struct ivy_ast_node *node, - enum ivy_ast_iteration_type node_type) + struct ivy_codegen *gen, struct ivy_ast_node *node, size_t node_depth) { if (!gen->c_builder) { return IVY_ERR_BAD_STATE; } + if (b_queue_empty(&gen->c_state)) { + const struct code_generator *generator + = get_root_code_generator(node->n_type); + if (!generator) { + return IVY_ERR_BAD_SYNTAX; + } + + codegen_push_generator(gen, generator->g_type, 0); + } + while (true) { struct code_generator_state *state = get_current_generator_state(gen); @@ -180,25 +351,32 @@ enum ivy_status ivy_codegen_push_node( return IVY_ERR_BAD_STATE; } + enum ivy_status status = IVY_OK; + struct code_generator_result result = {}; + + if (!state->s_root) { + state->s_root = node; + state->s_depth = node_depth; + } else if (node_depth <= state->s_depth) { + status = pop_generator_recurse(gen); + } + + if (status != IVY_OK) { + return status; + } + + state = get_current_generator_state(gen); const struct code_generator *generator = state->s_gen; - code_generator_node_callback func; - switch (node_type) { - case IVY_AST_ITERATION_PRE: - func = generator->g_node_generators_pre[node->n_type]; - break; - case IVY_AST_ITERATION_POST: - func = generator->g_node_generators_post[node->n_type]; - break; - default: - return IVY_ERR_INVALID_VALUE; - } + code_generator_node_callback func + = generator->g_node_generators[node->n_type]; if (!func) { - return IVY_ERR_INVALID_VALUE; + return IVY_OK; } - struct code_generator_result result = func(gen, state, node); + result = func(gen, state, node, node_depth); + if (result.r_flags & CODEGEN_REPEAT_NODE) { continue; } @@ -208,3 +386,27 @@ enum ivy_status ivy_codegen_push_node( return IVY_OK; } + +enum ivy_status ivy_codegen_push_eof(struct ivy_codegen *gen) +{ + struct code_generator_result result; + + while (!b_queue_empty(&gen->c_state)) { + struct mie_value *value = NULL; + codegen_pop_generator(gen, &value); + struct code_generator_state *state + = get_current_generator_state(gen); + + if (!state || !state->s_gen->g_value_received) { + continue; + } + + result = state->s_gen->g_value_received(gen, state, value); + + if (result.r_status != IVY_OK) { + break; + } + } + + return result.r_status; +} diff --git a/lang/codegen/codegen.h b/lang/codegen/codegen.h index 057b9da..46957f3 100644 --- a/lang/codegen/codegen.h +++ b/lang/codegen/codegen.h @@ -23,10 +23,30 @@ struct ivy_ast_node; struct mie_value; struct mie_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_type { CODE_GENERATOR_NONE = 0, CODE_GENERATOR_UNIT, CODE_GENERATOR_EXPR, + CODE_GENERATOR_VAR, +}; + +enum code_generator_scope_type { + CODE_GENERATOR_SCOPE_NONE = 0, + CODE_GENERATOR_SCOPE_UNIT, + CODE_GENERATOR_SCOPE_FUNC, + CODE_GENERATOR_SCOPE_BLOCK, }; struct code_generator_result { @@ -34,6 +54,7 @@ struct code_generator_result { enum code_generator_result_flags { CODEGEN_REPEAT_NODE = 0x01u, + CODEGEN_POP_GENERATOR = 0x02u, } r_flags; }; @@ -42,11 +63,14 @@ struct code_generator_state; typedef enum ivy_status (*code_generator_state_init_callback)( struct ivy_codegen *, struct code_generator_state *); typedef enum ivy_status (*code_generator_state_fini_callback)( - struct ivy_codegen *, struct code_generator_state *); + struct ivy_codegen *, struct code_generator_state *, struct mie_value **); typedef struct code_generator_result (*code_generator_callback)( struct ivy_codegen *); typedef struct code_generator_result (*code_generator_node_callback)( - struct ivy_codegen *, struct code_generator_state *, struct ivy_ast_node *); + struct ivy_codegen *, struct code_generator_state *, + 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 *); struct code_generator { enum code_generator_type g_type; @@ -54,19 +78,29 @@ struct code_generator { code_generator_state_init_callback g_state_init; code_generator_state_fini_callback g_state_fini; - code_generator_node_callback g_node_generators_pre[IVY_AST_TYPE_COUNT]; - code_generator_node_callback g_node_generators_post[IVY_AST_TYPE_COUNT]; + code_generator_node_callback g_node_generators[IVY_AST_TYPE_COUNT]; + code_generator_value_received_callback g_value_received; }; struct code_generator_state { b_queue_entry s_entry; void *s_arg; const struct code_generator *s_gen; + struct ivy_ast_node *s_root; + 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_ir_values; + b_queue c_values; b_queue c_state; + b_queue c_scope; struct mie_builder *c_builder; struct mie_ctx *c_ctx; struct mie_module *c_module; @@ -74,12 +108,31 @@ struct ivy_codegen { extern const struct code_generator *get_code_generator( enum code_generator_type type); +extern const struct code_generator *get_root_code_generator( + enum ivy_ast_node_type type); extern enum ivy_status codegen_push_generator( struct ivy_codegen *gen, enum code_generator_type gen_type, void *arg); -extern enum ivy_status codegen_pop_generator(struct ivy_codegen *gen); +extern enum ivy_status codegen_pop_generator( + struct ivy_codegen *gen, struct mie_value **result); -extern void codegen_push_value(struct ivy_codegen *gen, struct mie_value *value); -extern struct mie_value *codegen_pop_value(struct ivy_codegen *gen); +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); + +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); #endif diff --git a/lang/codegen/expr.c b/lang/codegen/expr.c index a0e3c8d..4802472 100644 --- a/lang/codegen/expr.c +++ b/lang/codegen/expr.c @@ -2,15 +2,32 @@ #include "codegen.h" #include +#include +#include + +enum expr_item_type { + EXPR_NONE = 0, + EXPR_OPERATOR, + EXPR_OPERAND, +}; + +struct expr_item { + b_queue_entry i_entry; + enum expr_item_type i_type; + struct ivy_ast_node *i_node; + struct mie_value *i_value; +}; struct expr_codegen_state { struct code_generator_state s_base; struct ivy_ast_node *s_expr_root; + b_queue s_item_queue; }; +#if 0 static struct code_generator_result check_expr_root( - struct ivy_codegen *gen, struct code_generator_state *state, - struct ivy_ast_node *node) + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node) { struct expr_codegen_state *expr = (struct expr_codegen_state *)state; if (!expr->s_expr_root) { @@ -19,23 +36,57 @@ static struct code_generator_result check_expr_root( return CODEGEN_RESULT_OK(0); } +#endif + +static enum ivy_status push_operand( + struct expr_codegen_state *expr, struct ivy_ast_node *node, + struct mie_value *value) +{ + struct expr_item *item = malloc(sizeof *item); + if (!item) { + return IVY_ERR_NO_MEMORY; + } + + memset(item, 0x0, sizeof *item); + + item->i_type = EXPR_OPERAND; + item->i_node = node; + item->i_value = value; + + b_queue_push_back(&expr->s_item_queue, &item->i_entry); + return IVY_OK; +} + +static enum ivy_status push_operator( + struct expr_codegen_state *expr, struct ivy_ast_node *node) +{ + struct expr_item *item = malloc(sizeof *item); + if (!item) { + return IVY_ERR_NO_MEMORY; + } + + memset(item, 0x0, sizeof *item); + + item->i_type = EXPR_OPERATOR; + item->i_node = node; + + b_queue_push_back(&expr->s_item_queue, &item->i_entry); + return IVY_OK; +} static struct code_generator_result gen_int( struct ivy_codegen *gen, struct code_generator_state *state, - struct ivy_ast_node *node) + struct ivy_ast_node *node, size_t depth) { struct expr_codegen_state *expr = (struct expr_codegen_state *)state; debug_printf("codegen: got int\n"); - struct ivy_ast_int_node *int_node = (struct ivy_ast_int_node *)node; struct mie_value *value = mie_ctx_get_int(gen->c_ctx, int_node->n_value->t_int, 32); - - codegen_push_value(gen, value); - - if (node == expr->s_expr_root) { - codegen_pop_generator(gen); + enum ivy_status status = push_operand(expr, node, value); + if (status != IVY_OK) { + return CODEGEN_RESULT_ERR(status); } return CODEGEN_RESULT_OK(0); @@ -43,53 +94,148 @@ static struct code_generator_result gen_int( static struct code_generator_result gen_op( struct ivy_codegen *gen, struct code_generator_state *state, - struct ivy_ast_node *node) + struct ivy_ast_node *node, size_t depth) +{ + struct expr_codegen_state *expr = (struct expr_codegen_state *)state; + + debug_printf("codegen: got op\n"); + enum ivy_status status = push_operator(expr, node); + if (status != IVY_OK) { + return CODEGEN_RESULT_ERR(status); + } + + return CODEGEN_RESULT_OK(0); +} + +static struct code_generator_result gen_var_reference( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node, size_t depth) +{ + debug_printf("codegen: got var reference\n"); + + struct expr_codegen_state *expr = (struct expr_codegen_state *)state; + 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); + if (var) { + /* this is a local variable */ + var_ptr = var->v_ptr; + } else { + /* this is a global variable, and needs to be loaded via a data ptr */ + /* TODO */ + } + + 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); + + enum ivy_status status = push_operand(expr, node, var_value); + + if (status != IVY_OK) { + return CODEGEN_RESULT_ERR(status); + } + + 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); +} + +static struct code_generator_result gen_op( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node) { struct expr_codegen_state *expr = (struct expr_codegen_state *)state; debug_printf("codegen: got operator\n"); - struct mie_value *left = codegen_pop_value(gen); - struct mie_value *right = codegen_pop_value(gen); + struct codegen_value *left = codegen_pop_value(gen); + struct codegen_value *right = codegen_pop_value(gen); if (!left || !right) { return CODEGEN_RESULT_ERR(IVY_ERR_INVALID_VALUE); } + struct mie_value *left_value = left->v_value; + struct mie_value *right_value = right->v_value; + + struct mie_type *left_type = mie_value_get_type(left_value); + struct mie_type *right_type = mie_value_get_type(right_value); + struct mie_type *i32 = mie_ctx_get_int_type(gen->c_ctx, 32); + + if (left_type && left_type->t_id == MIE_TYPE_PTR) { + left_value + = mie_builder_load(gen->c_builder, i32, left_value, NULL); + } + + if (right_type && right_type->t_id == MIE_TYPE_PTR) { + right_value = mie_builder_load( + gen->c_builder, i32, right_value, NULL); + } + struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)node; const struct ivy_operator *op = op_node->n_op; struct mie_value *op_instr = NULL; switch (op->op_id) { - case IVY_OP_ADD: - op_instr - = mie_builder_add(gen->c_builder, left, right, "addtmp"); - break; - case IVY_OP_SUBTRACT: - op_instr - = mie_builder_sub(gen->c_builder, left, right, "subtmp"); - break; - case IVY_OP_MULTIPLY: - op_instr - = mie_builder_mul(gen->c_builder, left, right, "multmp"); - break; - case IVY_OP_DIVIDE: - op_instr - = mie_builder_div(gen->c_builder, left, right, "divtmp"); - break; - default: - mie_value_destroy(left); - mie_value_destroy(right); - return CODEGEN_RESULT_ERR(IVY_ERR_NOT_SUPPORTED); + case IVY_OP_ADD: + op_instr = mie_builder_add( + gen->c_builder, left_value, right_value, "addtmp"); + break; + case IVY_OP_SUBTRACT: + op_instr = mie_builder_sub( + gen->c_builder, left_value, right_value, "subtmp"); + break; + case IVY_OP_MULTIPLY: + op_instr = mie_builder_mul( + gen->c_builder, left_value, right_value, "multmp"); + break; + case IVY_OP_DIVIDE: + op_instr = mie_builder_div( + gen->c_builder, left_value, right_value, "divtmp"); + break; + default: + mie_value_destroy(left->v_value); + mie_value_destroy(right->v_value); + codegen_value_destroy(left); + codegen_value_destroy(right); + return CODEGEN_RESULT_ERR(IVY_ERR_NOT_SUPPORTED); } if (!op_instr) { - mie_value_destroy(left); - mie_value_destroy(right); + mie_value_destroy(left->v_value); + mie_value_destroy(right->v_value); + codegen_value_destroy(left); + codegen_value_destroy(right); return CODEGEN_RESULT_ERR(IVY_ERR_NO_MEMORY); } - codegen_push_value(gen, op_instr); + struct codegen_value *op_value = codegen_value_create(node, op_instr); + codegen_push_value(gen, op_value); if (node == expr->s_expr_root) { codegen_pop_generator(gen); @@ -98,6 +244,18 @@ static struct code_generator_result gen_op( return CODEGEN_RESULT_OK(0); } +static struct code_generator_result cancel_expr( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node) +{ + debug_printf( + "codegen: expression stopped by %s\n", + ivy_ast_node_type_to_string(node->n_type)); + codegen_pop_generator(gen); + return CODEGEN_RESULT_OK(CODEGEN_REPEAT_NODE); +} +#endif + static enum ivy_status state_init( struct ivy_codegen *gen, struct code_generator_state *state) { @@ -106,23 +264,89 @@ static enum ivy_status state_init( } static enum ivy_status state_fini( - struct ivy_codegen *gen, struct code_generator_state *state) + struct ivy_codegen *gen, struct code_generator_state *state, + struct mie_value **result) { debug_printf("codegen: end of expression\n"); + + struct expr_codegen_state *expr = (struct expr_codegen_state *)state; + b_queue stack = B_QUEUE_INIT; + + b_queue_entry *cur = NULL; + while ((cur = b_queue_pop_back(&expr->s_item_queue))) { + struct expr_item *item = b_unbox(struct expr_item, cur, i_entry); + + if (item->i_type == EXPR_OPERAND) { + b_queue_push_back(&stack, &item->i_entry); + continue; + } + + struct ivy_ast_op_node *op = (struct ivy_ast_op_node *)item->i_node; + b_queue_entry *left_entry = b_queue_pop_back(&stack); + b_queue_entry *right_entry = b_queue_pop_back(&stack); + struct expr_item *left + = b_unbox(struct expr_item, left_entry, i_entry); + struct expr_item *right + = b_unbox(struct expr_item, right_entry, i_entry); + + struct mie_value *op_value = NULL; + + switch (op->n_op->op_id) { + case IVY_OP_ADD: + op_value = mie_builder_add( + gen->c_builder, left->i_value, right->i_value, + "addtmp"); + break; + case IVY_OP_SUBTRACT: + op_value = mie_builder_sub( + gen->c_builder, left->i_value, right->i_value, + "subtmp"); + break; + case IVY_OP_MULTIPLY: + op_value = mie_builder_mul( + gen->c_builder, left->i_value, right->i_value, + "multmp"); + break; + case IVY_OP_DIVIDE: + op_value = mie_builder_div( + gen->c_builder, left->i_value, right->i_value, + "divtmp"); + break; + default: + return IVY_ERR_NOT_SUPPORTED; + } + + if (!op_value) { + return IVY_ERR_NO_MEMORY; + } + + free(left); + free(right); + + item->i_value = op_value; + b_queue_push_back(&stack, &item->i_entry); + } + + cur = b_queue_pop_back(&stack); + if (!cur) { + return IVY_ERR_INTERNAL_FAILURE; + } + + struct expr_item *result_item = b_unbox(struct expr_item, cur, i_entry); + *result = result_item->i_value; + free(result_item); + return IVY_OK; } struct code_generator expr_generator = { - .g_type = CODE_GENERATOR_UNIT, + .g_type = CODE_GENERATOR_EXPR, .g_state_size = sizeof(struct expr_codegen_state), .g_state_init = state_init, .g_state_fini = state_fini, - .g_node_generators_pre = { - [IVY_AST_INT] = check_expr_root, - [IVY_AST_OP] = check_expr_root, - }, - .g_node_generators_post = { + .g_node_generators = { [IVY_AST_INT] = gen_int, [IVY_AST_OP] = gen_op, + [IVY_AST_IDENT] = gen_var_reference, }, }; diff --git a/lang/codegen/generator.c b/lang/codegen/generator.c index 9eadb36..37ee4dc 100644 --- a/lang/codegen/generator.c +++ b/lang/codegen/generator.c @@ -2,14 +2,25 @@ extern const struct code_generator unit_generator; extern const struct code_generator expr_generator; +extern const struct code_generator var_generator; static const struct code_generator *code_generators[] = { [CODE_GENERATOR_UNIT] = &unit_generator, [CODE_GENERATOR_EXPR] = &expr_generator, + [CODE_GENERATOR_VAR] = &var_generator, }; static const size_t nr_code_generators = sizeof code_generators / sizeof code_generators[0]; +static const struct code_generator *root_code_generators[] = { + [IVY_AST_UNIT] = &unit_generator, + [IVY_AST_OP] = &expr_generator, + [IVY_AST_INT] = &expr_generator, + [IVY_AST_IDENT] = &expr_generator, +}; +static const size_t nr_root_code_generators + = sizeof root_code_generators / sizeof root_code_generators[0]; + const struct code_generator *get_code_generator(enum code_generator_type type) { if (type >= nr_code_generators) { @@ -18,3 +29,12 @@ const struct code_generator *get_code_generator(enum code_generator_type type) return code_generators[type]; } + +const struct code_generator *get_root_code_generator(enum ivy_ast_node_type type) +{ + if (type >= nr_root_code_generators) { + return NULL; + } + + return root_code_generators[type]; +} diff --git a/lang/codegen/unit.c b/lang/codegen/unit.c index 6dd9c69..a98164e 100644 --- a/lang/codegen/unit.c +++ b/lang/codegen/unit.c @@ -6,7 +6,9 @@ struct unit_codegen_state { struct code_generator_state s_base; + struct code_generator_scope *s_scope; /* function for top-level statements */ + // struct mie_block *s_immediate_alloca; struct mie_func *s_immediate; }; @@ -27,7 +29,18 @@ static enum ivy_status switch_to_immediate_func( } struct mie_block *block = mie_func_get_last_block(unit->s_immediate); - if (!block || mie_block_is_terminated(block)) { + if (!block) { +#if 0 + unit->s_immediate_alloca + = mie_func_create_block(unit->s_immediate, "alloca"); + mie_func_insert_block( + unit->s_immediate, unit->s_immediate_alloca, NULL); +#endif + block = mie_func_create_block(unit->s_immediate, "entry"); + mie_func_insert_block(unit->s_immediate, block, NULL); + } + + if (mie_block_is_terminated(block)) { block = mie_func_create_block(unit->s_immediate, NULL); mie_func_insert_block(unit->s_immediate, block, NULL); } @@ -37,9 +50,25 @@ static enum ivy_status switch_to_immediate_func( return IVY_OK; } +#if 0 +static enum ivy_status switch_to_immediate_alloca( + struct ivy_codegen *gen, struct unit_codegen_state *unit) +{ + enum ivy_status status = switch_to_immediate_func(gen, unit); + + if (status != IVY_OK) { + return status; + } + + mie_builder_set_insert_point(gen->c_builder, unit->s_immediate_alloca); + + return IVY_OK; +} +#endif + static struct code_generator_result gen_expr( struct ivy_codegen *gen, struct code_generator_state *state, - struct ivy_ast_node *node) + struct ivy_ast_node *node, size_t depth) { struct unit_codegen_state *unit = (struct unit_codegen_state *)state; struct mie_builder *builder = gen->c_builder; @@ -58,11 +87,91 @@ static struct code_generator_result gen_expr( return CODEGEN_RESULT_OK(CODEGEN_REPEAT_NODE); } +static struct code_generator_result gen_var_declaration( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node, size_t depth) +{ + struct unit_codegen_state *unit = (struct unit_codegen_state *)state; + struct mie_builder *builder = gen->c_builder; + struct mie_func *current = mie_builder_get_current_func(builder); + + enum ivy_status status = IVY_OK; + if (!current || current != unit->s_immediate) { + status = switch_to_immediate_func(gen, unit); + } + + if (status != IVY_OK) { + return CODEGEN_RESULT_ERR(status); + } + + codegen_push_generator(gen, CODE_GENERATOR_VAR, NULL); + return CODEGEN_RESULT_OK(CODEGEN_REPEAT_NODE); +} + +#if 0 +static struct code_generator_result gen_var_declaration( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node) +{ + struct unit_codegen_state *unit = (struct unit_codegen_state *)state; + struct mie_builder *builder = gen->c_builder; + + struct mie_block *current_block + = mie_builder_get_current_block(gen->c_builder); + + enum ivy_status status = IVY_OK; + if (!current_block || current_block != unit->s_immediate_alloca) { + status = switch_to_immediate_alloca(gen, unit); + } + + struct codegen_value *value = codegen_pop_value(gen); + struct codegen_value *dest = codegen_pop_value(gen); + + if (!dest) { + return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX); + } + + struct mie_type *id_type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID); + struct mie_value *var_ptr = mie_builder_alloca(builder, id_type, NULL); + + if (value) { + mie_builder_store(builder, value->v_value, var_ptr); + } + + code_generator_scope_put_variable( + unit->s_scope, (struct ivy_ast_ident_node *)dest->v_node, var_ptr); + + return CODEGEN_RESULT_OK(0); +} +#endif + +static enum ivy_status state_init( + struct ivy_codegen *gen, struct code_generator_state *state) +{ + struct unit_codegen_state *unit = (struct unit_codegen_state *)state; + unit->s_scope = codegen_push_scope(gen); + + return IVY_OK; +} + +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; +} + struct code_generator unit_generator = { .g_type = CODE_GENERATOR_UNIT, .g_state_size = sizeof(struct unit_codegen_state), - .g_node_generators_pre = { + .g_state_init = state_init, + .g_state_fini = state_fini, + .g_node_generators = { [IVY_AST_INT] = gen_expr, [IVY_AST_OP] = gen_expr, + [IVY_AST_IDENT] = gen_expr, + [IVY_AST_VAR] = gen_var_declaration, }, }; diff --git a/lang/codegen/var.c b/lang/codegen/var.c new file mode 100644 index 0000000..56b0550 --- /dev/null +++ b/lang/codegen/var.c @@ -0,0 +1,146 @@ +#include "../debug.h" +#include "codegen.h" + +#include +#include +#include + +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_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) { + /* TODO support tuple assignment */ + return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX); + } + + 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); +} + +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); + + return CODEGEN_RESULT_OK(CODEGEN_REPEAT_NODE); +} + +#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) +{ + 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) +{ + 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); + + 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) +{ + 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_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_node_generators = { + [IVY_AST_VAR] = gen_var, + [IVY_AST_IDENT] = gen_ident, + [IVY_AST_INT] = gen_value_expr, + [IVY_AST_OP] = gen_value_expr, + }, +}; diff --git a/lang/include/ivy/lang/ast.h b/lang/include/ivy/lang/ast.h index 8236276..43d1678 100644 --- a/lang/include/ivy/lang/ast.h +++ b/lang/include/ivy/lang/ast.h @@ -339,6 +339,7 @@ IVY_API struct ivy_ast_node *ivy_parser_dequeue_node(struct ivy_parser *parser); IVY_API enum ivy_status ivy_parser_push_token( struct ivy_parser *parser, struct ivy_token *tok); +IVY_API struct ivy_ast_node *ivy_ast_node_create(enum ivy_ast_node_type type); IVY_API enum ivy_status ivy_ast_node_iterate( struct ivy_ast_node *node, struct ivy_ast_node_iterator *it, ivy_ast_node_iteration_callback callback, void *arg); @@ -347,4 +348,9 @@ IVY_API void ivy_ast_node_destroy(struct ivy_ast_node *node); IVY_API const char *ivy_ast_node_type_to_string(enum ivy_ast_node_type v); +IVY_API void ivy_ast_unit_add_node( + struct ivy_ast_unit_node *unit, struct ivy_ast_node *child); +IVY_API struct ivy_ast_node *ivy_ast_unit_dequeue_node( + struct ivy_ast_unit_node *unit); + #endif diff --git a/lang/include/ivy/lang/codegen.h b/lang/include/ivy/lang/codegen.h index 8d24de0..81d570c 100644 --- a/lang/include/ivy/lang/codegen.h +++ b/lang/include/ivy/lang/codegen.h @@ -3,6 +3,7 @@ #include #include +#include struct ivy_codegen; struct ivy_ast_node; @@ -19,7 +20,7 @@ IVY_API enum ivy_status ivy_codegen_end_module( IVY_API struct mie_module *ivy_codegen_get_current_module(struct ivy_codegen *gen); IVY_API enum ivy_status ivy_codegen_push_node( - struct ivy_codegen *gen, struct ivy_ast_node *node, - enum ivy_ast_iteration_type node_type); + struct ivy_codegen *gen, struct ivy_ast_node *node, size_t node_depth); +IVY_API enum ivy_status ivy_codegen_push_eof(struct ivy_codegen *gen); #endif