#include "codegen.h" #include #include #include #include #include #include #include enum lambda_part { LAMBDA_NONE, LAMBDA_START, LAMBDA_ARG, LAMBDA_BLOCK, }; struct lambda_codegen_state { struct code_generator_state s_base; enum lambda_part s_prev_part; struct mie_func *s_lambda; struct mie_value *s_self; struct mie_block *s_outer_block; b_queue s_args; }; static enum ivy_status switch_to_lambda_func( struct ivy_codegen *gen, struct lambda_codegen_state *lambda) { lambda->s_outer_block = mie_builder_get_current_block(gen->c_builder); struct mie_block *block = mie_func_get_last_block(lambda->s_lambda); if (!block) { block = mie_func_create_block(lambda->s_lambda, "entry"); mie_func_insert_block(lambda->s_lambda, block, NULL); } if (mie_block_is_terminated(block)) { block = mie_func_create_block(lambda->s_lambda, NULL); mie_func_insert_block(lambda->s_lambda, block, NULL); } mie_builder_set_insert_point(gen->c_builder, block); return IVY_OK; } static enum ivy_status switch_to_outer_block( struct ivy_codegen *gen, struct lambda_codegen_state *lambda) { mie_builder_set_insert_point(gen->c_builder, lambda->s_outer_block); return IVY_OK; } static struct code_generator_result gen_lambda( struct ivy_codegen *gen, struct code_generator_state *state, struct ivy_ast_node *node, size_t depth) { struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state; if (lambda->s_prev_part != LAMBDA_NONE) { return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX); } struct mie_type *id = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID); lambda->s_prev_part = LAMBDA_START; lambda->s_lambda = mie_func_create(MIE_FUNC_STATIC, id); lambda->s_self = mie_func_add_arg(lambda->s_lambda, id, "ctx"); switch_to_lambda_func(gen, lambda); return CODEGEN_RESULT_OK(0); } 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 lambda_codegen_state *lambda = (struct lambda_codegen_state *)state; if (lambda->s_prev_part != LAMBDA_START && lambda->s_prev_part != LAMBDA_ARG) { return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX); } lambda->s_prev_part = LAMBDA_ARG; struct ivy_ast_ident_node *ident = (struct ivy_ast_ident_node *)node; const char *arg_name = ident->n_content->t_str; struct mie_type *id = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID); struct mie_value *arg = mie_func_add_arg(lambda->s_lambda, id, arg_name); return CODEGEN_RESULT_OK(0); } static struct code_generator_result gen_block( struct ivy_codegen *gen, struct code_generator_state *state, struct ivy_ast_node *node, size_t depth) { struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state; if (lambda->s_prev_part != LAMBDA_START && lambda->s_prev_part != LAMBDA_ARG) { return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX); } codegen_push_generator(gen, CODE_GENERATOR_BLOCK, 0, NULL); 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) { struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state; lambda->s_args = B_QUEUE_INIT; lambda->s_prev_part = LAMBDA_NONE; return IVY_OK; } static enum ivy_status state_fini( struct ivy_codegen *gen, struct code_generator_state *state, struct mie_value **result) { struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state; switch_to_outer_block(gen, lambda); mie_module_add_function(gen->c_module, lambda->s_lambda, ".anon"); *result = MIE_VALUE(lambda->s_lambda); return IVY_OK; } static struct code_generator_result value_received( struct ivy_codegen *gen, struct code_generator_state *state, struct mie_value *value) { return CODEGEN_RESULT_OK(0); } struct code_generator lambda_generator = { .g_type = CODE_GENERATOR_LAMBDA, .g_state_size = sizeof(struct lambda_codegen_state), .g_state_init = state_init, .g_state_fini = state_fini, .g_value_received = value_received, .g_node_generators = { NODE_CODEGEN(LAMBDA, gen_lambda), NODE_CODEGEN(IDENT, gen_ident), NODE_CODEGEN(BLOCK, gen_block), }, };