diff --git a/lang/codegen/expr.c b/lang/codegen/expr.c index 53a2ec9..a5be549 100644 --- a/lang/codegen/expr.c +++ b/lang/codegen/expr.c @@ -223,12 +223,9 @@ 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 = {}; + struct codegen_var var = {.v_node = node}; 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) { @@ -391,16 +388,143 @@ static enum ivy_status state_init( uintptr_t argv, void *argp) { debug_printf("codegen: start of expression\n"); + struct expr_codegen_state *expr = (struct expr_codegen_state *)state; + return IVY_OK; } +static enum ivy_status gen_assignment( + struct ivy_codegen *gen, struct expr_codegen_state *expr, + struct ivy_ast_op_node *op, struct expr_item *left, + struct expr_item *right, struct mie_value **result) +{ + struct mie_value *left_value = left->i_value; + struct mie_value *right_value = right->i_value; + + if (left->i_operand_type != EXPR_OPERAND_VAR) { + return IVY_ERR_BAD_SYNTAX; + } + + if (right->i_operand_type == EXPR_OPERAND_VAR) { + right_value = codegen_load_variable(gen, &right->i_var); + } else { + right_value = right->i_value; + } + + if (!left->i_var.v_type) { + struct mie_type *id_type + = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID); + struct ivy_ast_ident_node *ident + = (struct ivy_ast_ident_node *)left->i_node; + const char *ident_str = ident->n_content->t_str; + + struct mie_value *var_ptr + = mie_builder_alloca(gen->c_builder, id_type, ident_str); + struct codegen_var var_info = { + .v_node = (struct ivy_ast_node *)ident, + .v_type = id_type, + .v_flags = CODEGEN_VAR_F_PTR, + .v_value = var_ptr, + }; + + codegen_define_variable(gen, ident_str, &var_info); + + memcpy(&left->i_var, &var_info, sizeof var_info); + } + + codegen_store_variable(gen, &left->i_var, right_value); + *result = right_value; + + return IVY_OK; +} + +static enum ivy_status gen_op_assignment( + struct ivy_codegen *gen, struct expr_codegen_state *expr, + struct ivy_ast_op_node *op, struct expr_item *left, + struct expr_item *right, struct mie_value **result) +{ + struct mie_value *op_value = NULL; + + if (left->i_operand_type != EXPR_OPERAND_VAR) { + return IVY_ERR_BAD_SYNTAX; + } + + if (!left->i_var.v_type) { + return IVY_ERR_BAD_SYNTAX; + } + + struct mie_value *left_var = left->i_value; + struct mie_value *left_value = codegen_load_variable(gen, &left->i_var); + + struct mie_value *right_value = right->i_value; + if (right->i_operand_type == EXPR_OPERAND_VAR) { + right_value = codegen_load_variable(gen, &right->i_var); + } + + switch (op->n_op->op_id) { + case IVY_OP_ADD_ASSIGN: + op_value = mie_builder_add( + gen->c_builder, left_value, right_value, "addtmp"); + break; + case IVY_OP_SUBTRACT_ASSIGN: + op_value = mie_builder_sub( + gen->c_builder, left_value, right_value, "subtmp"); + break; + case IVY_OP_MULTIPLY_ASSIGN: + op_value = mie_builder_mul( + gen->c_builder, left_value, right_value, "multmp"); + break; + case IVY_OP_DIVIDE_ASSIGN: + op_value = mie_builder_div( + gen->c_builder, left_value, right_value, "divtmp"); + break; + default: + return IVY_ERR_NOT_SUPPORTED; + } + + codegen_store_variable(gen, &left->i_var, op_value); + *result = op_value; + + return IVY_OK; +} + +static struct mie_value *load_variable( + struct ivy_codegen *gen, struct codegen_var *var) +{ + struct ivy_ast_ident_node *ident = (struct ivy_ast_ident_node *)var->v_node; + struct mie_value *var_ptr = NULL; + + if (var->v_value) { + /* this is a local variable */ + var_ptr = var->v_value; + } else { + /* this is a global variable, and needs to be loaded via a data ptr */ + var_ptr = mie_builder_get_data_ptr( + gen->c_builder, ident->n_content->t_str); + } + + 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); + + return var_value; +} + static enum ivy_status state_fini( struct ivy_codegen *gen, struct code_generator_state *state, struct code_generator_value *result) { +#define OP_IS_ASSIGNMENT(id) \ + ((id) == IVY_OP_ASSIGN || (id) == IVY_OP_ADD_ASSIGN \ + || (id) == IVY_OP_SUBTRACT_ASSIGN || (id) == IVY_OP_MULTIPLY_ASSIGN \ + || (id) == IVY_OP_DIVIDE_ASSIGN || (id) == IVY_OP_MODULO_ASSIGN \ + || (id) == IVY_OP_LEFT_SHIFT_ASSIGN || (id) == IVY_OP_RIGHT_SHIFT_ASSIGN \ + || (id) == IVY_OP_BINARY_AND_ASSIGN || (id) == IVY_OP_BINARY_OR_ASSIGN \ + || (id) == IVY_OP_BINARY_XOR_ASSIGN) debug_printf("codegen: end of expression\n"); struct expr_codegen_state *expr = (struct expr_codegen_state *)state; + enum ivy_status status = IVY_OK; b_queue stack = B_QUEUE_INIT; b_queue_entry *cur = NULL; @@ -422,16 +546,47 @@ static enum ivy_status state_fini( struct mie_value *left_value = left->i_value; struct mie_value *right_value = right->i_value; + struct mie_value *op_value = NULL; + + if (op->n_op->op_id == IVY_OP_ASSIGN) { + status = gen_assignment( + gen, expr, op, left, right, &op_value); + if (status != IVY_OK) { + break; + } + + free(left); + goto skip_op; + } + + if (OP_IS_ASSIGNMENT(op->n_op->op_id)) { + status = gen_op_assignment( + gen, expr, op, left, right, &op_value); + if (status != IVY_OK) { + break; + } + + free(left); + goto skip_op; + } if (left->i_operand_type == EXPR_OPERAND_VAR) { - left_value = codegen_load_variable(gen, &left->i_var); + left_value = load_variable(gen, &left->i_var); + + if (!left_value) { + /* cannot resolve variable */ + return IVY_ERR_BAD_SYNTAX; + } } if (right->i_operand_type == EXPR_OPERAND_VAR) { - right_value = codegen_load_variable(gen, &right->i_var); - } + right_value = load_variable(gen, &right->i_var); - struct mie_value *op_value = NULL; + if (!right_value) { + /* cannot resolve variable */ + return IVY_ERR_BAD_SYNTAX; + } + } switch (op->n_op->op_id) { case IVY_OP_ADD: @@ -495,10 +650,15 @@ static enum ivy_status state_fini( free(left); free(right); + skip_op: item->i_value = op_value; b_queue_push_back(&stack, &item->i_entry); } + if (status != IVY_OK) { + return status; + } + cur = b_queue_pop_back(&stack); if (!cur) { return IVY_ERR_INTERNAL_FAILURE; @@ -526,7 +686,8 @@ static struct code_generator_result value_received( struct expr_codegen_state *expr = (struct expr_codegen_state *)state; debug_printf("codegen: got sub-expr\n"); - enum ivy_status status = push_operand(expr, NULL, value, NULL); + enum ivy_status status + = push_operand(expr, NULL, value->v_value.mie_value, NULL); if (status != IVY_OK) { return CODEGEN_RESULT_ERR(status); }