lang: codegen: implement message-send code generation and global var references

This commit is contained in:
2025-04-17 21:44:38 +01:00
parent a4504c0507
commit 7b8d77a264
7 changed files with 359 additions and 55 deletions

View File

@@ -19,7 +19,8 @@
*/
enum ivy_status codegen_push_generator(
struct ivy_codegen *gen, enum code_generator_type gen_type, void *arg)
struct ivy_codegen *gen, enum code_generator_type gen_type,
uintptr_t argv, void *argp)
{
const struct code_generator *generator = get_code_generator(gen_type);
if (!generator) {
@@ -38,12 +39,11 @@ enum ivy_status codegen_push_generator(
memset(state, 0x0, generator->g_state_size);
state->s_gen = generator;
state->s_arg = arg;
enum ivy_status status = IVY_OK;
if (generator->g_state_init) {
status = generator->g_state_init(gen, state);
status = generator->g_state_init(gen, state, argv, argp);
}
if (status != IVY_OK) {
@@ -201,6 +201,8 @@ struct codegen_var *codegen_resolve_variable(
if (code_generator_scope_is_top_level(scope)) {
break;
}
cur = b_queue_prev(cur);
}
return NULL;
@@ -303,7 +305,8 @@ struct mie_module *ivy_codegen_get_current_module(struct ivy_codegen *gen)
return gen->c_module;
}
static enum ivy_status pop_generator_recurse(struct ivy_codegen *gen)
static enum ivy_status pop_generator_recurse(
struct ivy_codegen *gen, size_t node_depth)
{
while (1) {
struct mie_value *value = NULL;
@@ -318,14 +321,46 @@ static enum ivy_status pop_generator_recurse(struct ivy_codegen *gen)
struct code_generator_result result
= state->s_gen->g_value_received(gen, state, value);
if (!(result.r_flags & CODEGEN_POP_GENERATOR)) {
bool should_pop = ((result.r_flags & CODEGEN_R_POP_GENERATOR) != 0)
|| node_depth <= state->s_depth;
if (result.r_status != IVY_OK) {
return result.r_status;
}
if (!should_pop) {
return IVY_OK;
}
}
return IVY_OK;
}
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;
}
}
enum ivy_status ivy_codegen_push_node(
struct ivy_codegen *gen, struct ivy_ast_node *node, size_t node_depth)
{
@@ -340,7 +375,7 @@ enum ivy_status ivy_codegen_push_node(
return IVY_ERR_BAD_SYNTAX;
}
codegen_push_generator(gen, generator->g_type, 0);
codegen_push_generator(gen, generator->g_type, 0, NULL);
}
while (true) {
@@ -358,7 +393,7 @@ enum ivy_status ivy_codegen_push_node(
state->s_root = node;
state->s_depth = node_depth;
} else if (node_depth <= state->s_depth) {
status = pop_generator_recurse(gen);
status = pop_generator_recurse(gen, node_depth);
}
if (status != IVY_OK) {
@@ -368,16 +403,21 @@ enum ivy_status ivy_codegen_push_node(
state = get_current_generator_state(gen);
const struct code_generator *generator = state->s_gen;
bool is_expr = node_is_expr(node);
code_generator_node_callback func
= generator->g_node_generators[node->n_type];
if (!func && is_expr) {
func = generator->g_expr_generator;
}
if (!func) {
return IVY_OK;
}
result = func(gen, state, node, node_depth);
if (result.r_flags & CODEGEN_REPEAT_NODE) {
if (result.r_flags & CODEGEN_R_REPEAT_NODE) {
continue;
}

View File

@@ -6,6 +6,12 @@
#include <ivy/lang/lex.h>
#include <mie/builder.h>
struct ivy_codegen;
struct ivy_ast_node;
struct mie_value;
struct mie_func;
#define CODEGEN_RESULT_OK(flags) \
(struct code_generator_result) \
{ \
@@ -17,11 +23,8 @@
.r_status = (status), .r_flags = (0) \
}
struct ivy_codegen;
struct ivy_ast_node;
struct mie_value;
struct mie_func;
#define __AST_INDEX(type) IVY_AST_##type
#define NODE_CODEGEN(type, func) [__AST_INDEX(type)] = func
struct codegen_value {
b_queue_entry v_entry;
@@ -35,11 +38,16 @@ struct codegen_var {
struct mie_value *v_ptr;
};
enum code_generator_flags {
CODEGEN_F_IGNORE_RESULT = 0x01u,
};
enum code_generator_type {
CODE_GENERATOR_NONE = 0,
CODE_GENERATOR_UNIT,
CODE_GENERATOR_EXPR,
CODE_GENERATOR_VAR,
CODE_GENERATOR_MSG,
};
enum code_generator_scope_type {
@@ -53,15 +61,15 @@ struct code_generator_result {
enum ivy_status r_status;
enum code_generator_result_flags {
CODEGEN_REPEAT_NODE = 0x01u,
CODEGEN_POP_GENERATOR = 0x02u,
CODEGEN_R_REPEAT_NODE = 0x01u,
CODEGEN_R_POP_GENERATOR = 0x02u,
} r_flags;
};
struct code_generator_state;
typedef enum ivy_status (*code_generator_state_init_callback)(
struct ivy_codegen *, struct code_generator_state *);
struct ivy_codegen *, struct code_generator_state *, uintptr_t, void *);
typedef enum ivy_status (*code_generator_state_fini_callback)(
struct ivy_codegen *, struct code_generator_state *, struct mie_value **);
typedef struct code_generator_result (*code_generator_callback)(
@@ -79,12 +87,14 @@ struct code_generator {
code_generator_state_init_callback g_state_init;
code_generator_state_fini_callback g_state_fini;
code_generator_node_callback g_node_generators[IVY_AST_TYPE_COUNT];
code_generator_node_callback g_expr_generator;
code_generator_value_received_callback g_value_received;
};
struct code_generator_state {
b_queue_entry s_entry;
void *s_arg;
uintptr_t s_argv;
void *s_argp;
const struct code_generator *s_gen;
struct ivy_ast_node *s_root;
size_t s_depth;
@@ -112,7 +122,8 @@ extern const struct code_generator *get_root_code_generator(
enum ivy_ast_node_type type);
extern enum ivy_status codegen_push_generator(
struct ivy_codegen *gen, enum code_generator_type gen_type, void *arg);
struct ivy_codegen *gen, enum code_generator_type gen_type,
uintptr_t argv, void *argp);
extern enum ivy_status codegen_pop_generator(
struct ivy_codegen *gen, struct mie_value **result);

View File

@@ -21,6 +21,7 @@ struct expr_item {
struct expr_codegen_state {
struct code_generator_state s_base;
struct ivy_ast_node *s_expr_root;
uintptr_t s_flags;
b_queue s_item_queue;
};
@@ -107,6 +108,24 @@ static struct code_generator_result gen_op(
return CODEGEN_RESULT_OK(0);
}
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;
int flags = 0;
if (b_queue_empty(&expr->s_item_queue)
&& (expr->s_flags & CODEGEN_F_IGNORE_RESULT)) {
flags |= CODEGEN_F_IGNORE_RESULT;
}
codegen_push_generator(gen, CODE_GENERATOR_MSG, flags, NULL);
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
}
static struct code_generator_result gen_var_reference(
struct ivy_codegen *gen, struct code_generator_state *state,
struct ivy_ast_node *node, size_t depth)
@@ -124,7 +143,8 @@ static struct code_generator_result gen_var_reference(
var_ptr = var->v_ptr;
} else {
/* this is a global variable, and needs to be loaded via a data ptr */
/* TODO */
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);
@@ -257,7 +277,8 @@ static struct code_generator_result cancel_expr(
#endif
static enum ivy_status state_init(
struct ivy_codegen *gen, struct code_generator_state *state)
struct ivy_codegen *gen, struct code_generator_state *state,
uintptr_t argv, void *argp)
{
debug_printf("codegen: start of expression\n");
return IVY_OK;
@@ -339,14 +360,31 @@ static enum ivy_status state_fini(
return IVY_OK;
}
static struct code_generator_result value_received(
struct ivy_codegen *gen, struct code_generator_state *state,
struct mie_value *value)
{
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);
if (status != IVY_OK) {
return CODEGEN_RESULT_ERR(status);
}
return CODEGEN_RESULT_OK(0);
}
struct code_generator expr_generator = {
.g_type = CODE_GENERATOR_EXPR,
.g_state_size = sizeof(struct expr_codegen_state),
.g_state_init = state_init,
.g_state_fini = state_fini,
.g_value_received = value_received,
.g_node_generators = {
[IVY_AST_INT] = gen_int,
[IVY_AST_OP] = gen_op,
[IVY_AST_IDENT] = gen_var_reference,
NODE_CODEGEN(INT, gen_int),
NODE_CODEGEN(OP, gen_op),
NODE_CODEGEN(MSG, gen_msg),
NODE_CODEGEN(IDENT, gen_var_reference),
},
};

View File

@@ -3,11 +3,13 @@
extern const struct code_generator unit_generator;
extern const struct code_generator expr_generator;
extern const struct code_generator var_generator;
extern const struct code_generator msg_generator;
static const struct code_generator *code_generators[] = {
[CODE_GENERATOR_UNIT] = &unit_generator,
[CODE_GENERATOR_EXPR] = &expr_generator,
[CODE_GENERATOR_VAR] = &var_generator,
[CODE_GENERATOR_MSG] = &msg_generator,
};
static const size_t nr_code_generators
= sizeof code_generators / sizeof code_generators[0];

213
lang/codegen/msg.c Normal file
View File

@@ -0,0 +1,213 @@
#include "../debug.h"
#include "codegen.h"
#include <blue/core/stringstream.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum msg_part {
MSG_NONE = 0,
MSG_START,
MSG_RECIPIENT,
MSG_SELECTOR,
MSG_ARG,
};
struct msg_codegen_state {
struct code_generator_state s_base;
enum msg_part s_prev_part;
enum code_generator_flags s_flags;
struct mie_value *s_recipient;
struct ivy_ast_selector_node *s_selector;
struct mie_value **s_args;
/* the number of args we've collected so far */
size_t s_nr_args;
/* the number of args we're expecting based on the selector */
size_t s_max_args;
};
#if 0
static struct code_generator_result check_expr_root(
struct ivy_codegen *gen, struct code_generator_state *state,
struct ivy_ast_node *node)
{
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);
}
#endif
static struct code_generator_result gen_msg(
struct ivy_codegen *gen, struct code_generator_state *state,
struct ivy_ast_node *node, size_t depth)
{
struct msg_codegen_state *msg = (struct msg_codegen_state *)state;
if (msg->s_prev_part == MSG_NONE) {
msg->s_prev_part = MSG_START;
return CODEGEN_RESULT_OK(0);
}
codegen_push_generator(gen, CODE_GENERATOR_MSG, 0, NULL);
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
}
static struct code_generator_result gen_expr(
struct ivy_codegen *gen, struct code_generator_state *state,
struct ivy_ast_node *node, size_t depth)
{
struct msg_codegen_state *msg = (struct msg_codegen_state *)state;
if (msg->s_prev_part == MSG_RECIPIENT) {
/* expected message selector */
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
}
codegen_push_generator(gen, CODE_GENERATOR_EXPR, 0, NULL);
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
}
static struct code_generator_result gen_selector(
struct ivy_codegen *gen, struct code_generator_state *state,
struct ivy_ast_node *node, size_t depth)
{
struct msg_codegen_state *msg = (struct msg_codegen_state *)state;
if (msg->s_prev_part != MSG_RECIPIENT) {
/* expected something else */
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
}
msg->s_selector = (struct ivy_ast_selector_node *)node;
msg->s_prev_part = MSG_SELECTOR;
msg->s_nr_args = 0;
msg->s_max_args = b_queue_length(&msg->s_selector->n_arg_labels);
msg->s_args = calloc(msg->s_max_args, sizeof(struct mie_value *));
if (!msg->s_args) {
return CODEGEN_RESULT_ERR(IVY_ERR_NO_MEMORY);
}
return CODEGEN_RESULT_OK(0);
}
static enum ivy_status state_init(
struct ivy_codegen *gen, struct code_generator_state *state,
uintptr_t argv, void *argp)
{
debug_printf("codegen: start of msg\n");
struct msg_codegen_state *msg = (struct msg_codegen_state *)state;
msg->s_flags = argv;
return IVY_OK;
}
static void serialise_selector(
struct ivy_ast_selector_node *sel, b_stringstream *out)
{
b_stringstream_add(out, "_M");
if (sel->n_msg_name) {
const char *msg_name = sel->n_msg_name->t_str;
b_stringstream_addf(out, "%zu%s", strlen(msg_name), msg_name);
} else {
b_stringstream_add(out, "0");
}
b_queue_iterator it;
b_queue_foreach (&it, &sel->n_arg_labels) {
struct ivy_token *arg
= b_unbox(struct ivy_token, it.entry, t_entry);
const char *label = arg->t_str;
b_stringstream_addf(out, "%zu%s", strlen(label), label);
}
b_stringstream_add(out, "E");
}
static enum ivy_status state_fini(
struct ivy_codegen *gen, struct code_generator_state *state,
struct mie_value **result)
{
debug_printf("codegen: end of msg\n");
struct msg_codegen_state *msg = (struct msg_codegen_state *)state;
b_stringstream str;
b_stringstream_begin_dynamic(&str);
serialise_selector(msg->s_selector, &str);
char *sel = b_stringstream_end(&str);
struct mie_value *sel_value = mie_ctx_get_selector(gen->c_ctx, sel);
free(sel);
enum mie_builder_flags flags = 0;
struct mie_type *ret_type = NULL;
const char *value_name = NULL;
if (msg->s_flags & CODEGEN_F_IGNORE_RESULT) {
ret_type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_VOID);
flags = MIE_BUILDER_IGNORE_RESULT;
} else {
ret_type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID);
value_name = "msgtmp";
}
struct mie_value *msg_send = mie_builder_msg(
gen->c_builder, ret_type, msg->s_recipient, sel_value,
msg->s_args, msg->s_nr_args, flags, value_name);
if (msg->s_args) {
free(msg->s_args);
}
*result = msg_send;
return IVY_OK;
}
static struct code_generator_result value_received(
struct ivy_codegen *gen, struct code_generator_state *state,
struct mie_value *value)
{
struct msg_codegen_state *msg = (struct msg_codegen_state *)state;
switch (msg->s_prev_part) {
case MSG_START:
msg->s_recipient = value;
msg->s_prev_part = MSG_RECIPIENT;
break;
case MSG_RECIPIENT:
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
case MSG_SELECTOR:
msg->s_prev_part = MSG_ARG;
case MSG_ARG:
if (msg->s_nr_args == msg->s_max_args) {
/* too many args */
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
}
msg->s_args[msg->s_nr_args++] = value;
break;
default:
break;
}
return CODEGEN_RESULT_OK(0);
}
struct code_generator msg_generator = {
.g_type = CODE_GENERATOR_MSG,
.g_state_size = sizeof(struct msg_codegen_state),
.g_state_init = state_init,
.g_state_fini = state_fini,
.g_expr_generator = gen_expr,
.g_node_generators = {
NODE_CODEGEN(MSG, gen_msg),
NODE_CODEGEN(SELECTOR, gen_selector),
},
.g_value_received = value_received,
};

View File

@@ -83,8 +83,9 @@ static struct code_generator_result gen_expr(
return CODEGEN_RESULT_ERR(status);
}
codegen_push_generator(gen, CODE_GENERATOR_EXPR, NULL);
return CODEGEN_RESULT_OK(CODEGEN_REPEAT_NODE);
codegen_push_generator(
gen, CODE_GENERATOR_EXPR, CODEGEN_F_IGNORE_RESULT, NULL);
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
}
static struct code_generator_result gen_var_declaration(
@@ -104,8 +105,8 @@ static struct code_generator_result gen_var_declaration(
return CODEGEN_RESULT_ERR(status);
}
codegen_push_generator(gen, CODE_GENERATOR_VAR, NULL);
return CODEGEN_RESULT_OK(CODEGEN_REPEAT_NODE);
codegen_push_generator(gen, CODE_GENERATOR_VAR, 0, NULL);
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
}
#if 0
@@ -146,7 +147,8 @@ static struct code_generator_result gen_var_declaration(
#endif
static enum ivy_status state_init(
struct ivy_codegen *gen, struct code_generator_state *state)
struct ivy_codegen *gen, struct code_generator_state *state,
uintptr_t argv, void *argp)
{
struct unit_codegen_state *unit = (struct unit_codegen_state *)state;
unit->s_scope = codegen_push_scope(gen);
@@ -169,9 +171,7 @@ struct code_generator unit_generator = {
.g_state_init = state_init,
.g_state_fini = state_fini,
.g_node_generators = {
[IVY_AST_INT] = gen_expr,
[IVY_AST_OP] = gen_expr,
[IVY_AST_IDENT] = gen_expr,
[IVY_AST_VAR] = gen_var_declaration,
NODE_CODEGEN(VAR, gen_var_declaration),
},
.g_expr_generator = gen_expr,
};

View File

@@ -27,14 +27,27 @@ static struct code_generator_result gen_var(
return CODEGEN_RESULT_OK(0);
}
static struct code_generator_result gen_value_expr(
struct ivy_codegen *gen, struct code_generator_state *state,
struct ivy_ast_node *node, size_t depth)
{
struct var_codegen_state *var = (struct var_codegen_state *)state;
if (var->s_prev_node != IVY_AST_IDENT && var->s_prev_node != IVY_AST_TUPLE) {
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
}
codegen_push_generator(gen, CODE_GENERATOR_EXPR, 0, NULL);
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
}
static struct code_generator_result gen_ident(
struct ivy_codegen *gen, struct code_generator_state *state,
struct ivy_ast_node *node, size_t depth)
{
struct var_codegen_state *var = (struct var_codegen_state *)state;
if (var->s_prev_node != IVY_AST_VAR) {
/* TODO support tuple assignment */
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
return gen_value_expr(gen, state, node, depth);
}
struct ivy_ast_ident_node *ident = (struct ivy_ast_ident_node *)node;
@@ -52,20 +65,6 @@ static struct code_generator_result gen_ident(
return CODEGEN_RESULT_OK(0);
}
static struct code_generator_result gen_value_expr(
struct ivy_codegen *gen, struct code_generator_state *state,
struct ivy_ast_node *node, size_t depth)
{
struct var_codegen_state *var = (struct var_codegen_state *)state;
if (var->s_prev_node != IVY_AST_IDENT && var->s_prev_node != IVY_AST_TUPLE) {
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
}
codegen_push_generator(gen, CODE_GENERATOR_EXPR, 0);
return CODEGEN_RESULT_OK(CODEGEN_REPEAT_NODE);
}
#if 0
static struct code_generator_result gen_var_ref(
struct ivy_codegen *gen, struct code_generator_state *state,
@@ -93,9 +92,10 @@ static struct code_generator_result gen_var_ref(
#endif
static enum ivy_status state_init(
struct ivy_codegen *gen, struct code_generator_state *state)
struct ivy_codegen *gen, struct code_generator_state *state,
uintptr_t argv, void *argp)
{
printf("codegen: start of var decl\n");
debug_printf("codegen: start of var decl\n");
return IVY_OK;
}
@@ -103,7 +103,7 @@ static enum ivy_status state_fini(
struct ivy_codegen *gen, struct code_generator_state *state,
struct mie_value **result)
{
printf("codegen: end of var decl\n");
debug_printf("codegen: end of var decl\n");
struct var_codegen_state *var = (struct var_codegen_state *)state;
struct code_generator_scope *scope = codegen_get_current_scope(gen);
@@ -112,6 +112,7 @@ static enum ivy_status state_fini(
if (var->s_value) {
mie_builder_store(gen->c_builder, var->s_value, var->s_var_ptr);
}
return IVY_OK;
}
@@ -119,7 +120,7 @@ static struct code_generator_result value_received(
struct ivy_codegen *gen, struct code_generator_state *state,
struct mie_value *value)
{
printf("codegen: var decl value received\n");
debug_printf("codegen: var decl value received\n");
struct var_codegen_state *var = (struct var_codegen_state *)state;
if (!var->s_var_ptr) {
@@ -128,7 +129,7 @@ static struct code_generator_result value_received(
var->s_value = value;
return CODEGEN_RESULT_OK(CODEGEN_POP_GENERATOR);
return CODEGEN_RESULT_OK(CODEGEN_R_POP_GENERATOR);
}
struct code_generator var_generator = {
@@ -137,10 +138,9 @@ struct code_generator var_generator = {
.g_state_init = state_init,
.g_state_fini = state_fini,
.g_value_received = value_received,
.g_expr_generator = gen_value_expr,
.g_node_generators = {
[IVY_AST_VAR] = gen_var,
[IVY_AST_IDENT] = gen_ident,
[IVY_AST_INT] = gen_value_expr,
[IVY_AST_OP] = gen_value_expr,
},
};