lang: codegen: expr: implement assignment and arithmetic-and-assign operator support
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user