2025-04-15 11:02:47 +01:00
|
|
|
#include "../debug.h"
|
2025-04-14 20:15:05 +01:00
|
|
|
#include "codegen.h"
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2025-04-16 21:58:52 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
enum expr_item_type {
|
|
|
|
|
EXPR_NONE = 0,
|
|
|
|
|
EXPR_OPERATOR,
|
|
|
|
|
EXPR_OPERAND,
|
|
|
|
|
};
|
|
|
|
|
|
2025-04-28 15:44:44 +01:00
|
|
|
enum expr_operand_type {
|
|
|
|
|
EXPR_OPERAND_OTHER,
|
|
|
|
|
EXPR_OPERAND_VAR,
|
|
|
|
|
};
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
struct expr_item {
|
|
|
|
|
b_queue_entry i_entry;
|
|
|
|
|
enum expr_item_type i_type;
|
2025-04-28 15:44:44 +01:00
|
|
|
enum expr_operand_type i_operand_type;
|
2025-04-16 21:58:52 +01:00
|
|
|
struct ivy_ast_node *i_node;
|
2025-04-28 15:44:44 +01:00
|
|
|
struct codegen_var i_var;
|
2025-04-16 21:58:52 +01:00
|
|
|
struct mie_value *i_value;
|
|
|
|
|
};
|
2025-04-14 20:15:05 +01:00
|
|
|
|
|
|
|
|
struct expr_codegen_state {
|
|
|
|
|
struct code_generator_state s_base;
|
|
|
|
|
struct ivy_ast_node *s_expr_root;
|
2025-04-17 21:44:38 +01:00
|
|
|
uintptr_t s_flags;
|
2025-04-16 21:58:52 +01:00
|
|
|
b_queue s_item_queue;
|
2025-04-14 20:15:05 +01:00
|
|
|
};
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
#if 0
|
2025-04-14 20:15:05 +01:00
|
|
|
static struct code_generator_result check_expr_root(
|
2025-04-16 21:58:52 +01:00
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
|
|
|
|
struct ivy_ast_node *node)
|
2025-04-14 20:15:05 +01:00
|
|
|
{
|
|
|
|
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
|
|
|
|
if (!expr->s_expr_root) {
|
|
|
|
|
expr->s_expr_root = node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CODEGEN_RESULT_OK(0);
|
|
|
|
|
}
|
2025-04-16 21:58:52 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static enum ivy_status push_operand(
|
|
|
|
|
struct expr_codegen_state *expr, struct ivy_ast_node *node,
|
2025-04-28 15:44:44 +01:00
|
|
|
struct mie_value *value, const struct codegen_var *var)
|
2025-04-16 21:58:52 +01:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
2025-04-28 15:44:44 +01:00
|
|
|
if (var) {
|
|
|
|
|
memcpy(&item->i_var, var, sizeof item->i_var);
|
|
|
|
|
item->i_operand_type = EXPR_OPERAND_VAR;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
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;
|
|
|
|
|
}
|
2025-04-14 20:15:05 +01:00
|
|
|
|
2025-09-12 10:01:07 +01:00
|
|
|
static struct code_generator_result gen_cascade(
|
|
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
|
|
|
|
struct ivy_ast_node *node, size_t depth)
|
|
|
|
|
{
|
|
|
|
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
|
|
|
|
|
|
|
|
|
codegen_push_generator(gen, CODE_GENERATOR_CASCADE, 0, NULL);
|
|
|
|
|
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 20:15:05 +01:00
|
|
|
static struct code_generator_result gen_int(
|
|
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
2025-04-16 21:58:52 +01:00
|
|
|
struct ivy_ast_node *node, size_t depth)
|
2025-04-14 20:15:05 +01:00
|
|
|
{
|
|
|
|
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
|
|
|
|
|
2025-04-15 11:02:47 +01:00
|
|
|
debug_printf("codegen: got int\n");
|
2025-04-14 20:15:05 +01:00
|
|
|
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);
|
2025-04-28 15:44:44 +01:00
|
|
|
enum ivy_status status = push_operand(expr, node, value, NULL);
|
2025-04-16 21:58:52 +01:00
|
|
|
if (status != IVY_OK) {
|
|
|
|
|
return CODEGEN_RESULT_ERR(status);
|
|
|
|
|
}
|
2025-04-14 20:15:05 +01:00
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
return CODEGEN_RESULT_OK(0);
|
|
|
|
|
}
|
2025-04-14 20:15:05 +01:00
|
|
|
|
2025-09-08 16:22:06 +01:00
|
|
|
static struct code_generator_result gen_keyword_const(
|
|
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
|
|
|
|
struct ivy_ast_node *node, size_t depth)
|
|
|
|
|
{
|
|
|
|
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
|
|
|
|
|
|
|
|
|
debug_printf("codegen: got keyword const\n");
|
|
|
|
|
|
|
|
|
|
struct mie_value *value = NULL;
|
|
|
|
|
|
|
|
|
|
switch (node->n_type) {
|
|
|
|
|
case IVY_AST_C_TRUE:
|
|
|
|
|
value = mie_ctx_get_int(gen->c_ctx, 1, 1);
|
|
|
|
|
break;
|
|
|
|
|
case IVY_AST_C_FALSE:
|
|
|
|
|
value = mie_ctx_get_int(gen->c_ctx, 0, 1);
|
|
|
|
|
break;
|
|
|
|
|
case IVY_AST_C_NULL:
|
|
|
|
|
value = mie_ctx_get_null(gen->c_ctx);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ivy_status status = push_operand(expr, node, value, NULL);
|
|
|
|
|
if (status != IVY_OK) {
|
|
|
|
|
return CODEGEN_RESULT_ERR(status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CODEGEN_RESULT_OK(0);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-17 22:55:40 +01:00
|
|
|
static struct code_generator_result gen_string(
|
|
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
|
|
|
|
struct ivy_ast_node *node, size_t depth)
|
|
|
|
|
{
|
|
|
|
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
|
|
|
|
|
|
|
|
|
debug_printf("codegen: got string\n");
|
|
|
|
|
struct ivy_ast_string_node *string_node
|
|
|
|
|
= (struct ivy_ast_string_node *)node;
|
|
|
|
|
|
|
|
|
|
struct mie_value *var_ptr = mie_builder_get_string_ptr(
|
|
|
|
|
gen->c_builder, string_node->n_value->t_str);
|
|
|
|
|
struct mie_type *str = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_STR);
|
|
|
|
|
struct mie_value *var_value
|
|
|
|
|
= mie_builder_load(gen->c_builder, str, var_ptr, NULL);
|
2025-04-28 15:44:44 +01:00
|
|
|
enum ivy_status status = push_operand(expr, node, var_value, NULL);
|
2025-04-17 22:55:40 +01:00
|
|
|
|
|
|
|
|
if (status != IVY_OK) {
|
|
|
|
|
return CODEGEN_RESULT_ERR(status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CODEGEN_RESULT_OK(0);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-18 23:17:39 +01:00
|
|
|
static struct code_generator_result gen_fstring(
|
|
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
|
|
|
|
struct ivy_ast_node *node, size_t depth)
|
|
|
|
|
{
|
|
|
|
|
debug_printf("codegen: got fstring\n");
|
|
|
|
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
|
|
|
|
|
|
|
|
|
codegen_push_generator(gen, CODE_GENERATOR_FSTRING, 0, NULL);
|
|
|
|
|
|
|
|
|
|
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
static struct code_generator_result gen_op(
|
|
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
|
|
|
|
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);
|
2025-04-14 20:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CODEGEN_RESULT_OK(0);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-17 21:44:38 +01:00
|
|
|
static struct code_generator_result gen_msg(
|
|
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
|
|
|
|
struct ivy_ast_node *node, size_t depth)
|
|
|
|
|
{
|
|
|
|
|
debug_printf("codegen: got msg\n");
|
|
|
|
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
|
|
|
|
|
2025-04-18 23:15:28 +01:00
|
|
|
codegen_push_generator(gen, CODE_GENERATOR_MSG, 0, NULL);
|
2025-04-17 21:44:38 +01:00
|
|
|
|
|
|
|
|
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-21 21:11:45 +01:00
|
|
|
static struct code_generator_result gen_lambda(
|
|
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
|
|
|
|
struct ivy_ast_node *node, size_t depth)
|
|
|
|
|
{
|
|
|
|
|
debug_printf("codegen: got lambda\n");
|
|
|
|
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
|
|
|
|
|
|
|
|
|
codegen_push_generator(gen, CODE_GENERATOR_LAMBDA, 0, NULL);
|
|
|
|
|
|
|
|
|
|
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
static struct code_generator_result gen_var_reference(
|
2025-04-14 20:15:05 +01:00
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
2025-04-16 21:58:52 +01:00
|
|
|
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;
|
2025-09-08 16:22:31 +01:00
|
|
|
struct codegen_var var = {.v_node = node};
|
lang: codegen: redesign variable definition/resolution system to support capturing
the codegen scope system has been removed. instead, each generator state in the stack,
from the current state backwards, is informed when a variable is defined, resolved, or
captured.
when a variable is defined, the state stack is traversed back-to-front (current generator
first). each state has a chance to record the variable definition. once one state has
signalled that it has recorded the variable definition, the traversal ends.
when a variable is resolved, the state stack is traversed back-to-front (current generator
first). each state is asked whether or not it recognises the variable identifier being resolved.
if a state has the variable in question defined, it returns information about the variable
definition, and the traversal stops.
once a variable has been resolved, the state stack is traversed front-to-back (current generator
last), starting from the generator /after/ the one that provided the variable definition. each
generator in the iteration is given the chance to adjust the variable information, or generate
IR in response to the variable being accessed. this is used to implement variable capture,
where the state of a variable in the enclosing context is captured for later use.
2025-04-22 15:23:42 +01:00
|
|
|
enum ivy_status status
|
|
|
|
|
= codegen_resolve_variable(gen, ident->n_content->t_str, &var);
|
|
|
|
|
|
|
|
|
|
#if 0
|
2025-04-16 21:58:52 +01:00
|
|
|
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 */
|
2025-04-17 21:44:38 +01:00
|
|
|
var_ptr = mie_builder_get_data_ptr(
|
|
|
|
|
gen->c_builder, ident->n_content->t_str);
|
2025-04-16 21:58:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
lang: codegen: redesign variable definition/resolution system to support capturing
the codegen scope system has been removed. instead, each generator state in the stack,
from the current state backwards, is informed when a variable is defined, resolved, or
captured.
when a variable is defined, the state stack is traversed back-to-front (current generator
first). each state has a chance to record the variable definition. once one state has
signalled that it has recorded the variable definition, the traversal ends.
when a variable is resolved, the state stack is traversed back-to-front (current generator
first). each state is asked whether or not it recognises the variable identifier being resolved.
if a state has the variable in question defined, it returns information about the variable
definition, and the traversal stops.
once a variable has been resolved, the state stack is traversed front-to-back (current generator
last), starting from the generator /after/ the one that provided the variable definition. each
generator in the iteration is given the chance to adjust the variable information, or generate
IR in response to the variable being accessed. this is used to implement variable capture,
where the state of a variable in the enclosing context is captured for later use.
2025-04-22 15:23:42 +01:00
|
|
|
#endif
|
2025-04-16 21:58:52 +01:00
|
|
|
|
2025-04-28 15:44:44 +01:00
|
|
|
status = push_operand(expr, node, NULL, &var);
|
2025-04-16 21:58:52 +01:00
|
|
|
|
|
|
|
|
if (status != IVY_OK) {
|
|
|
|
|
return CODEGEN_RESULT_ERR(status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CODEGEN_RESULT_OK(0);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-28 15:44:44 +01:00
|
|
|
static struct code_generator_result gen_cond_group(
|
|
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
|
|
|
|
struct ivy_ast_node *node, size_t depth)
|
|
|
|
|
{
|
|
|
|
|
codegen_push_generator(gen, CODE_GENERATOR_COND_GROUP, 0, NULL);
|
|
|
|
|
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-08 10:53:00 +01:00
|
|
|
static struct code_generator_result gen_for_loop(
|
|
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
|
|
|
|
struct ivy_ast_node *node, size_t depth)
|
|
|
|
|
{
|
|
|
|
|
codegen_push_generator(gen, CODE_GENERATOR_FOR_LOOP, 0, NULL);
|
|
|
|
|
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-04 10:35:52 +00:00
|
|
|
static struct code_generator_result gen_match(
|
|
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
|
|
|
|
struct ivy_ast_node *node, size_t depth)
|
|
|
|
|
{
|
|
|
|
|
codegen_push_generator(gen, CODE_GENERATOR_MATCH, 0, NULL);
|
|
|
|
|
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
#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)
|
2025-04-14 20:15:05 +01:00
|
|
|
{
|
|
|
|
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
|
|
|
|
|
2025-04-15 11:02:47 +01:00
|
|
|
debug_printf("codegen: got operator\n");
|
2025-04-14 20:15:05 +01:00
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
struct codegen_value *left = codegen_pop_value(gen);
|
|
|
|
|
struct codegen_value *right = codegen_pop_value(gen);
|
2025-04-14 20:15:05 +01:00
|
|
|
|
|
|
|
|
if (!left || !right) {
|
|
|
|
|
return CODEGEN_RESULT_ERR(IVY_ERR_INVALID_VALUE);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 20:15:05 +01:00
|
|
|
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) {
|
2025-04-16 21:58:52 +01:00
|
|
|
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);
|
2025-04-14 20:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!op_instr) {
|
2025-04-16 21:58:52 +01:00
|
|
|
mie_value_destroy(left->v_value);
|
|
|
|
|
mie_value_destroy(right->v_value);
|
|
|
|
|
codegen_value_destroy(left);
|
|
|
|
|
codegen_value_destroy(right);
|
2025-04-14 20:15:05 +01:00
|
|
|
return CODEGEN_RESULT_ERR(IVY_ERR_NO_MEMORY);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
struct codegen_value *op_value = codegen_value_create(node, op_instr);
|
|
|
|
|
codegen_push_value(gen, op_value);
|
2025-04-14 20:15:05 +01:00
|
|
|
|
|
|
|
|
if (node == expr->s_expr_root) {
|
|
|
|
|
codegen_pop_generator(gen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CODEGEN_RESULT_OK(0);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
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
|
|
|
|
|
|
2025-04-14 20:15:05 +01:00
|
|
|
static enum ivy_status state_init(
|
2025-04-17 21:44:38 +01:00
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
|
|
|
|
uintptr_t argv, void *argp)
|
2025-04-14 20:15:05 +01:00
|
|
|
{
|
2025-04-15 11:02:47 +01:00
|
|
|
debug_printf("codegen: start of expression\n");
|
2025-09-08 16:22:31 +01:00
|
|
|
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;
|
|
|
|
|
|
2025-04-14 20:15:05 +01:00
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-08 16:22:31 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 20:15:05 +01:00
|
|
|
static enum ivy_status state_fini(
|
2025-04-16 21:58:52 +01:00
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
2025-09-08 16:17:29 +01:00
|
|
|
struct code_generator_value *result)
|
2025-04-14 20:15:05 +01:00
|
|
|
{
|
2025-09-08 16:22:31 +01:00
|
|
|
#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)
|
2025-04-15 11:02:47 +01:00
|
|
|
debug_printf("codegen: end of expression\n");
|
2025-04-16 21:58:52 +01:00
|
|
|
|
|
|
|
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
2025-09-08 16:22:31 +01:00
|
|
|
enum ivy_status status = IVY_OK;
|
2025-04-16 21:58:52 +01:00
|
|
|
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);
|
|
|
|
|
|
2025-04-28 15:44:44 +01:00
|
|
|
struct mie_value *left_value = left->i_value;
|
2025-08-16 21:00:50 +01:00
|
|
|
struct mie_value *right_value = right->i_value;
|
2025-09-08 16:22:31 +01:00
|
|
|
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;
|
|
|
|
|
}
|
2025-04-28 15:44:44 +01:00
|
|
|
|
|
|
|
|
if (left->i_operand_type == EXPR_OPERAND_VAR) {
|
2025-09-08 16:22:31 +01:00
|
|
|
left_value = load_variable(gen, &left->i_var);
|
|
|
|
|
|
|
|
|
|
if (!left_value) {
|
|
|
|
|
/* cannot resolve variable */
|
|
|
|
|
return IVY_ERR_BAD_SYNTAX;
|
|
|
|
|
}
|
2025-04-28 15:44:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (right->i_operand_type == EXPR_OPERAND_VAR) {
|
2025-09-08 16:22:31 +01:00
|
|
|
right_value = load_variable(gen, &right->i_var);
|
2025-04-28 15:44:44 +01:00
|
|
|
|
2025-09-08 16:22:31 +01:00
|
|
|
if (!right_value) {
|
|
|
|
|
/* cannot resolve variable */
|
|
|
|
|
return IVY_ERR_BAD_SYNTAX;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-16 21:58:52 +01:00
|
|
|
|
|
|
|
|
switch (op->n_op->op_id) {
|
|
|
|
|
case IVY_OP_ADD:
|
|
|
|
|
op_value = mie_builder_add(
|
2025-04-28 15:44:44 +01:00
|
|
|
gen->c_builder, left_value, right_value,
|
2025-04-16 21:58:52 +01:00
|
|
|
"addtmp");
|
|
|
|
|
break;
|
|
|
|
|
case IVY_OP_SUBTRACT:
|
|
|
|
|
op_value = mie_builder_sub(
|
2025-04-28 15:44:44 +01:00
|
|
|
gen->c_builder, left_value, right_value,
|
2025-04-16 21:58:52 +01:00
|
|
|
"subtmp");
|
|
|
|
|
break;
|
|
|
|
|
case IVY_OP_MULTIPLY:
|
|
|
|
|
op_value = mie_builder_mul(
|
2025-04-28 15:44:44 +01:00
|
|
|
gen->c_builder, left_value, right_value,
|
2025-04-16 21:58:52 +01:00
|
|
|
"multmp");
|
|
|
|
|
break;
|
|
|
|
|
case IVY_OP_DIVIDE:
|
|
|
|
|
op_value = mie_builder_div(
|
2025-04-28 15:44:44 +01:00
|
|
|
gen->c_builder, left_value, right_value,
|
2025-04-16 21:58:52 +01:00
|
|
|
"divtmp");
|
|
|
|
|
break;
|
2025-04-28 15:44:44 +01:00
|
|
|
case IVY_OP_EQUAL:
|
|
|
|
|
op_value = mie_builder_cmp_eq(
|
|
|
|
|
gen->c_builder, left_value, right_value,
|
|
|
|
|
"cmptmp");
|
|
|
|
|
break;
|
|
|
|
|
case IVY_OP_NOT_EQUAL:
|
|
|
|
|
op_value = mie_builder_cmp_neq(
|
|
|
|
|
gen->c_builder, left_value, right_value,
|
|
|
|
|
"cmptmp");
|
|
|
|
|
break;
|
|
|
|
|
case IVY_OP_LESS_THAN:
|
|
|
|
|
op_value = mie_builder_cmp_lt(
|
|
|
|
|
gen->c_builder, left_value, right_value,
|
|
|
|
|
"cmptmp");
|
|
|
|
|
break;
|
|
|
|
|
case IVY_OP_LESS_EQUAL:
|
|
|
|
|
op_value = mie_builder_cmp_leq(
|
|
|
|
|
gen->c_builder, left_value, right_value,
|
|
|
|
|
"cmptmp");
|
|
|
|
|
break;
|
|
|
|
|
case IVY_OP_GREATER_THAN:
|
|
|
|
|
op_value = mie_builder_cmp_gt(
|
|
|
|
|
gen->c_builder, left_value, right_value,
|
|
|
|
|
"cmptmp");
|
|
|
|
|
break;
|
|
|
|
|
case IVY_OP_GREATER_EQUAL:
|
|
|
|
|
op_value = mie_builder_cmp_geq(
|
|
|
|
|
gen->c_builder, left_value, right_value,
|
|
|
|
|
"cmptmp");
|
|
|
|
|
break;
|
2025-04-16 21:58:52 +01:00
|
|
|
default:
|
|
|
|
|
return IVY_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!op_value) {
|
|
|
|
|
return IVY_ERR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(left);
|
|
|
|
|
free(right);
|
|
|
|
|
|
2025-09-08 16:22:31 +01:00
|
|
|
skip_op:
|
2025-04-16 21:58:52 +01:00
|
|
|
item->i_value = op_value;
|
|
|
|
|
b_queue_push_back(&stack, &item->i_entry);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-08 16:22:31 +01:00
|
|
|
if (status != IVY_OK) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
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);
|
2025-09-08 16:17:29 +01:00
|
|
|
struct mie_value *result_value;
|
2025-04-28 15:44:44 +01:00
|
|
|
if (result_item->i_operand_type == EXPR_OPERAND_VAR) {
|
2025-09-08 16:17:29 +01:00
|
|
|
result_value = load_variable(gen, &result_item->i_var);
|
2025-04-28 15:44:44 +01:00
|
|
|
} else {
|
2025-09-08 16:17:29 +01:00
|
|
|
result_value = result_item->i_value;
|
2025-04-28 15:44:44 +01:00
|
|
|
}
|
2025-04-16 21:58:52 +01:00
|
|
|
free(result_item);
|
|
|
|
|
|
2025-09-08 16:17:29 +01:00
|
|
|
result->v_type = CODE_GENERATOR_VALUE_MIE_VALUE;
|
|
|
|
|
result->v_value.mie_value = result_value;
|
|
|
|
|
|
|
|
|
|
return status;
|
2025-04-14 20:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-17 21:44:38 +01:00
|
|
|
static struct code_generator_result value_received(
|
|
|
|
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
2025-09-08 16:17:29 +01:00
|
|
|
struct code_generator_value *value)
|
2025-04-17 21:44:38 +01:00
|
|
|
{
|
|
|
|
|
struct expr_codegen_state *expr = (struct expr_codegen_state *)state;
|
|
|
|
|
|
|
|
|
|
debug_printf("codegen: got sub-expr\n");
|
2025-09-08 16:22:31 +01:00
|
|
|
enum ivy_status status
|
|
|
|
|
= push_operand(expr, NULL, value->v_value.mie_value, NULL);
|
2025-04-17 21:44:38 +01:00
|
|
|
if (status != IVY_OK) {
|
|
|
|
|
return CODEGEN_RESULT_ERR(status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CODEGEN_RESULT_OK(0);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 20:15:05 +01:00
|
|
|
struct code_generator expr_generator = {
|
2025-04-16 21:58:52 +01:00
|
|
|
.g_type = CODE_GENERATOR_EXPR,
|
2025-04-14 20:15:05 +01:00
|
|
|
.g_state_size = sizeof(struct expr_codegen_state),
|
|
|
|
|
.g_state_init = state_init,
|
|
|
|
|
.g_state_fini = state_fini,
|
2025-04-17 21:44:38 +01:00
|
|
|
.g_value_received = value_received,
|
2025-04-16 21:58:52 +01:00
|
|
|
.g_node_generators = {
|
2025-09-08 16:22:06 +01:00
|
|
|
NODE_CODEGEN(C_TRUE, gen_keyword_const),
|
|
|
|
|
NODE_CODEGEN(C_FALSE, gen_keyword_const),
|
|
|
|
|
NODE_CODEGEN(C_NULL, gen_keyword_const),
|
2025-09-12 10:01:07 +01:00
|
|
|
NODE_CODEGEN(CASCADE, gen_cascade),
|
2025-04-17 21:44:38 +01:00
|
|
|
NODE_CODEGEN(INT, gen_int),
|
|
|
|
|
NODE_CODEGEN(OP, gen_op),
|
|
|
|
|
NODE_CODEGEN(MSG, gen_msg),
|
2025-04-21 21:11:45 +01:00
|
|
|
NODE_CODEGEN(LAMBDA, gen_lambda),
|
2025-04-17 22:55:40 +01:00
|
|
|
NODE_CODEGEN(STRING, gen_string),
|
2025-04-18 23:17:39 +01:00
|
|
|
NODE_CODEGEN(FSTRING, gen_fstring),
|
2025-04-17 21:44:38 +01:00
|
|
|
NODE_CODEGEN(IDENT, gen_var_reference),
|
2025-04-28 15:44:44 +01:00
|
|
|
NODE_CODEGEN(COND_GROUP, gen_cond_group),
|
2025-05-08 10:53:00 +01:00
|
|
|
NODE_CODEGEN(FOR_LOOP, gen_for_loop),
|
2025-11-04 10:35:52 +00:00
|
|
|
NODE_CODEGEN(MATCH, gen_match),
|
2025-04-14 20:15:05 +01:00
|
|
|
},
|
|
|
|
|
};
|