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 mie_value *var_ptr = NULL;
|
||||||
|
|
||||||
struct ivy_ast_ident_node *ident = (struct ivy_ast_ident_node *)node;
|
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
|
enum ivy_status status
|
||||||
= codegen_resolve_variable(gen, ident->n_content->t_str, &var);
|
= codegen_resolve_variable(gen, ident->n_content->t_str, &var);
|
||||||
if (status != IVY_OK) {
|
|
||||||
return CODEGEN_RESULT_ERR(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (var) {
|
if (var) {
|
||||||
@@ -391,16 +388,143 @@ static enum ivy_status state_init(
|
|||||||
uintptr_t argv, void *argp)
|
uintptr_t argv, void *argp)
|
||||||
{
|
{
|
||||||
debug_printf("codegen: start of expression\n");
|
debug_printf("codegen: start of expression\n");
|
||||||
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
||||||
|
|
||||||
return IVY_OK;
|
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(
|
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 code_generator_value *result)
|
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");
|
debug_printf("codegen: end of expression\n");
|
||||||
|
|
||||||
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
||||||
|
enum ivy_status status = IVY_OK;
|
||||||
b_queue stack = B_QUEUE_INIT;
|
b_queue stack = B_QUEUE_INIT;
|
||||||
|
|
||||||
b_queue_entry *cur = NULL;
|
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 *left_value = left->i_value;
|
||||||
struct mie_value *right_value = right->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) {
|
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) {
|
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) {
|
switch (op->n_op->op_id) {
|
||||||
case IVY_OP_ADD:
|
case IVY_OP_ADD:
|
||||||
@@ -495,10 +650,15 @@ static enum ivy_status state_fini(
|
|||||||
free(left);
|
free(left);
|
||||||
free(right);
|
free(right);
|
||||||
|
|
||||||
|
skip_op:
|
||||||
item->i_value = op_value;
|
item->i_value = op_value;
|
||||||
b_queue_push_back(&stack, &item->i_entry);
|
b_queue_push_back(&stack, &item->i_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status != IVY_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
cur = b_queue_pop_back(&stack);
|
cur = b_queue_pop_back(&stack);
|
||||||
if (!cur) {
|
if (!cur) {
|
||||||
return IVY_ERR_INTERNAL_FAILURE;
|
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;
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
||||||
|
|
||||||
debug_printf("codegen: got sub-expr\n");
|
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) {
|
if (status != IVY_OK) {
|
||||||
return CODEGEN_RESULT_ERR(status);
|
return CODEGEN_RESULT_ERR(status);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user