2025-04-17 21:44:38 +01:00
|
|
|
#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;
|
|
|
|
|
|
2025-04-18 23:15:28 +01:00
|
|
|
#if 0
|
2025-04-17 21:44:38 +01:00
|
|
|
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";
|
|
|
|
|
}
|
2025-04-18 23:15:28 +01:00
|
|
|
#endif
|
|
|
|
|
ret_type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID);
|
|
|
|
|
value_name = "msgtmp";
|
2025-04-17 21:44:38 +01:00
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
};
|