lang: codegen: expr: implement assignment and arithmetic-and-assign operator support

This commit is contained in:
2025-09-08 16:22:31 +01:00
parent 97f7782968
commit 84e6d4f2ed

View File

@@ -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);
}