Files

250 lines
6.3 KiB
C
Raw Permalink Normal View History

#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,
};
enum msg_codegen_flags {
MSG_F_SKIP_RECIPIENT = 0x01u,
MSG_F_SKIP_RECIPIENT_DONE = 0x02u,
};
struct msg_codegen_state {
struct code_generator_state s_base;
enum msg_part s_prev_part;
enum code_generator_flags s_flags;
enum msg_codegen_flags s_msg_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);
}
if (msg->s_msg_flags & MSG_F_SKIP_RECIPIENT
&& !(msg->s_msg_flags & MSG_F_SKIP_RECIPIENT_DONE)) {
msg->s_msg_flags |= MSG_F_SKIP_RECIPIENT_DONE;
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;
if (argp) {
msg->s_recipient = argp;
msg->s_prev_part = MSG_RECIPIENT;
msg->s_msg_flags = MSG_F_SKIP_RECIPIENT;
}
return IVY_OK;
}
static void serialise_selector(
struct ivy_ast_selector_node *sel, b_stringstream *out)
{
2025-11-06 10:38:32 +00:00
b_stream_write_string(out, "_M", NULL);
if (sel->n_msg_name) {
const char *msg_name = sel->n_msg_name->t_str;
2025-11-06 10:38:32 +00:00
b_stream_write_fmt(out, NULL, "%zu%s", strlen(msg_name), msg_name);
} else {
2025-11-06 10:38:32 +00:00
b_stream_write_char(out, '0');
}
2025-11-06 10:38:32 +00:00
b_queue_entry *entry = b_queue_first(&sel->n_arg_labels);
while (entry) {
struct ivy_token *arg = b_unbox(struct ivy_token, entry, t_entry);
if (arg->t_type != IVY_TOK_IDENT && arg->t_type != IVY_TOK_LABEL) {
2025-11-06 10:38:32 +00:00
b_stream_write_char(out, '0');
goto next;
}
const char *label = arg->t_str;
if (label) {
2025-11-06 10:38:32 +00:00
b_stream_write_fmt(out, NULL, "%zu%s", strlen(label), label);
} else {
2025-11-06 10:38:32 +00:00
b_stream_write_char(out, '0');
}
2025-11-06 10:38:32 +00:00
next:
entry = b_queue_next(entry);
}
2025-11-06 10:38:32 +00:00
b_stream_write_char(out, 'E');
}
static enum ivy_status state_fini(
struct ivy_codegen *gen, struct code_generator_state *state,
struct code_generator_value *result)
{
debug_printf("codegen: end of msg\n");
struct msg_codegen_state *msg = (struct msg_codegen_state *)state;
2025-11-06 10:38:32 +00:00
b_stringstream *str = b_stringstream_create();
serialise_selector(msg->s_selector, str);
char *sel = b_stringstream_steal(str);
b_stringstream_unref(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 0
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";
}
#endif
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->v_type = CODE_GENERATOR_VALUE_MIE_VALUE;
result->v_value.mie_value = msg_send;
return IVY_OK;
}
static struct code_generator_result value_received(
struct ivy_codegen *gen, struct code_generator_state *state,
struct code_generator_value *value)
{
struct msg_codegen_state *msg = (struct msg_codegen_state *)state;
switch (msg->s_prev_part) {
case MSG_START:
msg->s_recipient = value->v_value.mie_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->v_value.mie_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,
};