lang: codegen: implement message-send code generation and global var references
This commit is contained in:
213
lang/codegen/msg.c
Normal file
213
lang/codegen/msg.c
Normal 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,
|
||||
};
|
||||
Reference in New Issue
Block a user