2025-04-14 09:48:16 +01:00
|
|
|
#include "codegen.h"
|
|
|
|
|
|
|
|
|
|
#include <ivy/lang/codegen.h>
|
2025-06-02 11:31:35 +01:00
|
|
|
#include <mie/ir/builder.h>
|
|
|
|
|
#include <mie/ir/module.h>
|
|
|
|
|
#include <mie/ir/value.h>
|
2025-04-14 09:48:16 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
/* new codegen layout:
|
|
|
|
|
* - traverse the AST in pre-order (i.e. in the order it's displayed by debug)
|
|
|
|
|
* - each node type (var, msg, expr) gets its own code generator type
|
|
|
|
|
* - expr code generator is limited to simple operator arithmetic.
|
|
|
|
|
* - when a code generator encounters a node of an equal or lower depth than
|
|
|
|
|
* the node that started it, it has reached the end of its subtree.
|
|
|
|
|
* - depth is supplied by the ast iterator.
|
|
|
|
|
* - need to devise a way for expression code generator to "return" a
|
|
|
|
|
* mie_value for its parent generator to use.
|
|
|
|
|
*/
|
|
|
|
|
|
2025-04-14 20:15:05 +01:00
|
|
|
enum ivy_status codegen_push_generator(
|
2025-04-17 21:44:38 +01:00
|
|
|
struct ivy_codegen *gen, enum code_generator_type gen_type,
|
|
|
|
|
uintptr_t argv, void *argp)
|
2025-04-14 20:15:05 +01:00
|
|
|
{
|
|
|
|
|
const struct code_generator *generator = get_code_generator(gen_type);
|
|
|
|
|
if (!generator) {
|
|
|
|
|
return IVY_ERR_INVALID_VALUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (generator->g_state_size < sizeof(struct code_generator_state)) {
|
|
|
|
|
return IVY_ERR_INTERNAL_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct code_generator_state *state = malloc(generator->g_state_size);
|
|
|
|
|
if (!state) {
|
|
|
|
|
return IVY_ERR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(state, 0x0, generator->g_state_size);
|
|
|
|
|
|
|
|
|
|
state->s_gen = generator;
|
|
|
|
|
|
|
|
|
|
enum ivy_status status = IVY_OK;
|
|
|
|
|
|
|
|
|
|
if (generator->g_state_init) {
|
2025-04-17 21:44:38 +01:00
|
|
|
status = generator->g_state_init(gen, state, argv, argp);
|
2025-04-14 20:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status != IVY_OK) {
|
|
|
|
|
free(state);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b_queue_push_back(&gen->c_state, &state->s_entry);
|
|
|
|
|
|
|
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
enum ivy_status codegen_pop_generator(
|
2025-09-08 16:17:29 +01:00
|
|
|
struct ivy_codegen *gen, struct code_generator_value *result)
|
2025-04-14 20:15:05 +01:00
|
|
|
{
|
|
|
|
|
b_queue_entry *entry = b_queue_pop_back(&gen->c_state);
|
|
|
|
|
if (!entry) {
|
|
|
|
|
return IVY_ERR_BAD_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct code_generator_state *state
|
|
|
|
|
= b_unbox(struct code_generator_state, entry, s_entry);
|
|
|
|
|
|
|
|
|
|
enum ivy_status status = IVY_OK;
|
|
|
|
|
|
|
|
|
|
if (state->s_gen->g_state_fini) {
|
2025-04-16 21:58:52 +01:00
|
|
|
status = state->s_gen->g_state_fini(gen, state, result);
|
2025-04-14 20:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status != IVY_OK) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(state);
|
|
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
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 codegen_define_variable(
|
|
|
|
|
struct ivy_codegen *gen, const char *ident, const struct codegen_var *var)
|
2025-04-16 21:58:52 +01:00
|
|
|
{
|
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
|
|
|
b_queue_entry *entry = b_queue_last(&gen->c_state);
|
|
|
|
|
if (!entry) {
|
|
|
|
|
return IVY_ERR_NO_ENTRY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool resolved = false;
|
|
|
|
|
|
|
|
|
|
while (entry) {
|
|
|
|
|
struct code_generator_state *state
|
|
|
|
|
= b_unbox(struct code_generator_state, entry, s_entry);
|
|
|
|
|
const struct code_generator *generator = state->s_gen;
|
|
|
|
|
enum ivy_status status = IVY_ERR_NO_ENTRY;
|
|
|
|
|
|
|
|
|
|
if (generator->g_define_var) {
|
|
|
|
|
status = generator->g_define_var(gen, state, ident, var);
|
2025-04-16 21:58:52 +01:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
if (status == IVY_OK) {
|
2025-04-16 21:58:52 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2025-04-17 21:44:38 +01:00
|
|
|
|
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
|
|
|
entry = b_queue_prev(entry);
|
2025-04-16 21:58:52 +01:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
return IVY_ERR_NOT_SUPPORTED;
|
2025-04-16 21:58:52 +01:00
|
|
|
}
|
|
|
|
|
|
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 resolve_global_variable(
|
|
|
|
|
struct ivy_codegen *gen, const char *ident, struct codegen_var *out)
|
2025-04-16 21:58:52 +01:00
|
|
|
{
|
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
|
|
|
struct mie_value *var_ptr
|
|
|
|
|
= mie_builder_get_data_ptr(gen->c_builder, ident);
|
|
|
|
|
|
|
|
|
|
out->v_type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID);
|
|
|
|
|
out->v_node = NULL;
|
|
|
|
|
out->v_flags = CODEGEN_VAR_F_PTR;
|
|
|
|
|
out->v_value = var_ptr;
|
|
|
|
|
|
|
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ivy_status codegen_resolve_variable(
|
|
|
|
|
struct ivy_codegen *gen, const char *ident, struct codegen_var *out)
|
|
|
|
|
{
|
|
|
|
|
b_queue_entry *entry = b_queue_last(&gen->c_state);
|
|
|
|
|
if (!entry) {
|
|
|
|
|
return IVY_ERR_NO_ENTRY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool resolved = false;
|
|
|
|
|
|
|
|
|
|
while (entry) {
|
|
|
|
|
struct code_generator_state *state
|
|
|
|
|
= b_unbox(struct code_generator_state, entry, s_entry);
|
|
|
|
|
const struct code_generator *generator = state->s_gen;
|
|
|
|
|
enum ivy_status status = IVY_ERR_NO_ENTRY;
|
|
|
|
|
|
|
|
|
|
if (generator->g_resolve_var) {
|
|
|
|
|
status = generator->g_resolve_var(gen, state, ident, out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status == IVY_OK) {
|
|
|
|
|
resolved = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entry = b_queue_prev(entry);
|
2025-04-16 21:58:52 +01:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
if (!resolved) {
|
|
|
|
|
return resolve_global_variable(gen, ident, out);
|
|
|
|
|
}
|
2025-04-16 21:58:52 +01:00
|
|
|
|
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
|
|
|
if (entry) {
|
|
|
|
|
entry = b_queue_next(entry);
|
|
|
|
|
}
|
2025-04-16 21:58:52 +01:00
|
|
|
|
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
|
|
|
while (entry) {
|
|
|
|
|
struct code_generator_state *state
|
|
|
|
|
= b_unbox(struct code_generator_state, entry, s_entry);
|
|
|
|
|
const struct code_generator *generator = state->s_gen;
|
|
|
|
|
enum ivy_status status = IVY_OK;
|
|
|
|
|
|
|
|
|
|
if (generator->g_capture_var) {
|
|
|
|
|
status = generator->g_capture_var(gen, state, ident, out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status != IVY_OK) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entry = b_queue_next(entry);
|
|
|
|
|
}
|
2025-04-16 21:58:52 +01:00
|
|
|
|
|
|
|
|
return IVY_OK;
|
2025-04-14 20:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
struct mie_value *codegen_load_variable(
|
|
|
|
|
struct ivy_codegen *gen, struct codegen_var *var)
|
|
|
|
|
{
|
2025-04-23 11:00:16 +01:00
|
|
|
if (var->v_flags & CODEGEN_VAR_F_PTR) {
|
|
|
|
|
return mie_builder_load(
|
|
|
|
|
gen->c_builder, var->v_type, var->v_value, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return var->v_value;
|
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
|
|
|
}
|
|
|
|
|
|
2025-04-14 20:15:05 +01:00
|
|
|
static struct code_generator_state *get_current_generator_state(
|
|
|
|
|
struct ivy_codegen *gen)
|
|
|
|
|
{
|
|
|
|
|
b_queue_entry *entry = b_queue_last(&gen->c_state);
|
|
|
|
|
if (!entry) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return b_unbox(struct code_generator_state, entry, s_entry);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-28 15:44:44 +01:00
|
|
|
enum ivy_status ivy_codegen_create(struct mie_ctx *ctx, struct ivy_codegen **out)
|
2025-04-14 09:48:16 +01:00
|
|
|
{
|
|
|
|
|
struct ivy_codegen *gen = malloc(sizeof *gen);
|
|
|
|
|
if (!gen) {
|
|
|
|
|
return IVY_ERR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(gen, 0x0, sizeof *gen);
|
|
|
|
|
|
2025-04-28 15:44:44 +01:00
|
|
|
gen->c_ctx = ctx;
|
2025-04-14 09:48:16 +01:00
|
|
|
|
|
|
|
|
*out = gen;
|
|
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ivy_codegen_destroy(struct ivy_codegen *gen)
|
|
|
|
|
{
|
|
|
|
|
if (gen->c_module) {
|
|
|
|
|
mie_value_destroy(MIE_VALUE(gen->c_module));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gen->c_builder) {
|
|
|
|
|
mie_builder_destroy(gen->c_builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(gen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ivy_status ivy_codegen_start_module(struct ivy_codegen *gen)
|
|
|
|
|
{
|
|
|
|
|
if (gen->c_module || gen->c_builder) {
|
|
|
|
|
return IVY_ERR_BAD_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gen->c_module = mie_module_create();
|
|
|
|
|
gen->c_builder = mie_builder_create(gen->c_ctx, gen->c_module);
|
|
|
|
|
|
|
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ivy_status ivy_codegen_end_module(
|
|
|
|
|
struct ivy_codegen *gen, struct mie_module **out)
|
|
|
|
|
{
|
|
|
|
|
if (!gen->c_module) {
|
|
|
|
|
return IVY_ERR_BAD_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct mie_module *module = gen->c_module;
|
|
|
|
|
mie_builder_destroy(gen->c_builder);
|
|
|
|
|
|
|
|
|
|
gen->c_module = NULL;
|
|
|
|
|
gen->c_builder = NULL;
|
|
|
|
|
|
|
|
|
|
*out = module;
|
|
|
|
|
|
|
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
2025-04-14 20:15:05 +01:00
|
|
|
|
|
|
|
|
struct mie_module *ivy_codegen_get_current_module(struct ivy_codegen *gen)
|
|
|
|
|
{
|
|
|
|
|
return gen->c_module;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-17 21:44:38 +01:00
|
|
|
static enum ivy_status pop_generator_recurse(
|
|
|
|
|
struct ivy_codegen *gen, size_t node_depth)
|
2025-04-16 21:58:52 +01:00
|
|
|
{
|
2025-09-08 16:17:29 +01:00
|
|
|
enum ivy_status status;
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
while (1) {
|
2025-09-08 16:17:29 +01:00
|
|
|
struct code_generator_value value = {0};
|
|
|
|
|
status = codegen_pop_generator(gen, &value);
|
|
|
|
|
if (status != IVY_OK) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
struct code_generator_state *state
|
|
|
|
|
= get_current_generator_state(gen);
|
|
|
|
|
|
2025-04-23 11:01:12 +01:00
|
|
|
if (!state) {
|
2025-04-16 21:58:52 +01:00
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-23 11:01:12 +01:00
|
|
|
struct code_generator_result result = {
|
|
|
|
|
.r_status = IVY_OK,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (state->s_gen->g_value_received) {
|
2025-09-08 16:17:29 +01:00
|
|
|
state->s_gen->g_value_received(gen, state, &value);
|
2025-04-23 11:01:12 +01:00
|
|
|
}
|
2025-04-16 21:58:52 +01:00
|
|
|
|
2025-04-17 21:44:38 +01:00
|
|
|
bool should_pop = ((result.r_flags & CODEGEN_R_POP_GENERATOR) != 0)
|
|
|
|
|
|| node_depth <= state->s_depth;
|
|
|
|
|
|
|
|
|
|
if (result.r_status != IVY_OK) {
|
2025-04-16 21:58:52 +01:00
|
|
|
return result.r_status;
|
|
|
|
|
}
|
2025-04-17 21:44:38 +01:00
|
|
|
|
|
|
|
|
if (!should_pop) {
|
|
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
2025-04-16 21:58:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-17 21:44:38 +01:00
|
|
|
static bool node_is_expr(struct ivy_ast_node *node)
|
|
|
|
|
{
|
|
|
|
|
switch (node->n_type) {
|
|
|
|
|
case IVY_AST_OP:
|
|
|
|
|
case IVY_AST_MSG:
|
|
|
|
|
case IVY_AST_LAMBDA:
|
|
|
|
|
case IVY_AST_DISCARD:
|
|
|
|
|
case IVY_AST_INT:
|
|
|
|
|
case IVY_AST_DOUBLE:
|
|
|
|
|
case IVY_AST_STRING:
|
|
|
|
|
case IVY_AST_FSTRING:
|
|
|
|
|
case IVY_AST_ATOM:
|
|
|
|
|
case IVY_AST_IDENT:
|
|
|
|
|
case IVY_AST_CASCADE:
|
|
|
|
|
case IVY_AST_MATCH:
|
|
|
|
|
case IVY_AST_COND_GROUP:
|
|
|
|
|
case IVY_AST_TUPLE:
|
|
|
|
|
case IVY_AST_PKG_STATIC:
|
|
|
|
|
case IVY_AST_PKG_DYNAMIC:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 20:15:05 +01:00
|
|
|
enum ivy_status ivy_codegen_push_node(
|
2025-04-16 21:58:52 +01:00
|
|
|
struct ivy_codegen *gen, struct ivy_ast_node *node, size_t node_depth)
|
2025-04-14 20:15:05 +01:00
|
|
|
{
|
|
|
|
|
if (!gen->c_builder) {
|
|
|
|
|
return IVY_ERR_BAD_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
if (b_queue_empty(&gen->c_state)) {
|
|
|
|
|
const struct code_generator *generator
|
|
|
|
|
= get_root_code_generator(node->n_type);
|
|
|
|
|
if (!generator) {
|
|
|
|
|
return IVY_ERR_BAD_SYNTAX;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-17 21:44:38 +01:00
|
|
|
codegen_push_generator(gen, generator->g_type, 0, NULL);
|
2025-04-16 21:58:52 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-14 20:15:05 +01:00
|
|
|
while (true) {
|
|
|
|
|
struct code_generator_state *state
|
|
|
|
|
= get_current_generator_state(gen);
|
|
|
|
|
|
|
|
|
|
if (!state) {
|
|
|
|
|
return IVY_ERR_BAD_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
enum ivy_status status = IVY_OK;
|
|
|
|
|
struct code_generator_result result = {};
|
2025-04-14 20:15:05 +01:00
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
if (!state->s_root) {
|
|
|
|
|
state->s_root = node;
|
|
|
|
|
state->s_depth = node_depth;
|
|
|
|
|
} else if (node_depth <= state->s_depth) {
|
2025-04-17 21:44:38 +01:00
|
|
|
status = pop_generator_recurse(gen, node_depth);
|
2025-04-16 21:58:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status != IVY_OK) {
|
|
|
|
|
return status;
|
2025-04-14 20:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
state = get_current_generator_state(gen);
|
|
|
|
|
const struct code_generator *generator = state->s_gen;
|
|
|
|
|
|
2025-04-17 21:44:38 +01:00
|
|
|
bool is_expr = node_is_expr(node);
|
2025-04-16 21:58:52 +01:00
|
|
|
code_generator_node_callback func
|
|
|
|
|
= generator->g_node_generators[node->n_type];
|
|
|
|
|
|
2025-04-17 21:44:38 +01:00
|
|
|
if (!func && is_expr) {
|
|
|
|
|
func = generator->g_expr_generator;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 20:15:05 +01:00
|
|
|
if (!func) {
|
2025-04-16 21:58:52 +01:00
|
|
|
return IVY_OK;
|
2025-04-14 20:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
result = func(gen, state, node, node_depth);
|
|
|
|
|
|
2025-04-17 21:44:38 +01:00
|
|
|
if (result.r_flags & CODEGEN_R_REPEAT_NODE) {
|
2025-04-14 20:15:05 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result.r_status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IVY_OK;
|
|
|
|
|
}
|
2025-04-16 21:58:52 +01:00
|
|
|
|
|
|
|
|
enum ivy_status ivy_codegen_push_eof(struct ivy_codegen *gen)
|
|
|
|
|
{
|
2025-09-08 16:17:29 +01:00
|
|
|
enum ivy_status status = IVY_OK;
|
|
|
|
|
struct code_generator_result result = {
|
|
|
|
|
.r_status = IVY_OK,
|
|
|
|
|
};
|
2025-04-16 21:58:52 +01:00
|
|
|
|
|
|
|
|
while (!b_queue_empty(&gen->c_state)) {
|
2025-09-08 16:17:29 +01:00
|
|
|
struct code_generator_value value = {0};
|
|
|
|
|
status = codegen_pop_generator(gen, &value);
|
|
|
|
|
if (status != IVY_OK) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-16 21:58:52 +01:00
|
|
|
struct code_generator_state *state
|
|
|
|
|
= get_current_generator_state(gen);
|
|
|
|
|
|
|
|
|
|
if (!state || !state->s_gen->g_value_received) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-08 16:17:29 +01:00
|
|
|
result = state->s_gen->g_value_received(gen, state, &value);
|
2025-04-16 21:58:52 +01:00
|
|
|
|
|
|
|
|
if (result.r_status != IVY_OK) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result.r_status;
|
|
|
|
|
}
|
2025-09-08 16:17:29 +01:00
|
|
|
|
|
|
|
|
struct mie_value *code_generator_value_get_mie_value(struct code_generator_value *vp)
|
|
|
|
|
{
|
|
|
|
|
if (vp->v_type != CODE_GENERATOR_VALUE_MIE_VALUE) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return vp->v_value.mie_value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void code_generator_value_set_mie_value(
|
|
|
|
|
struct code_generator_value *vp, struct mie_value *value)
|
|
|
|
|
{
|
|
|
|
|
vp->v_type = CODE_GENERATOR_VALUE_MIE_VALUE;
|
|
|
|
|
vp->v_value.mie_value = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern struct mie_phi_edge *code_generator_value_get_phi_edge(
|
|
|
|
|
struct code_generator_value *vp)
|
|
|
|
|
{
|
|
|
|
|
if (vp->v_type != CODE_GENERATOR_VALUE_PHI_EDGE) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return vp->v_value.phi_edge;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void code_generator_value_set_phi_edge(
|
|
|
|
|
struct code_generator_value *vp, struct mie_phi_edge *edge)
|
|
|
|
|
{
|
|
|
|
|
vp->v_type = CODE_GENERATOR_VALUE_PHI_EDGE;
|
|
|
|
|
vp->v_value.phi_edge = edge;
|
|
|
|
|
}
|