#include "../debug.h" #include "codegen.h" #include #include #include #include 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); if (arg->t_type != IVY_TOK_IDENT && arg->t_type != IVY_TOK_LABEL) { b_stringstream_addf(out, "0"); continue; } const char *label = arg->t_str; if (label) { b_stringstream_addf(out, "%zu%s", strlen(label), label); } else { b_stringstream_addf(out, "0"); } } b_stringstream_add(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; 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 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, };