diff --git a/lang/codegen/block.c b/lang/codegen/block.c new file mode 100644 index 0000000..4668702 --- /dev/null +++ b/lang/codegen/block.c @@ -0,0 +1,71 @@ +#include "codegen.h" + +#include +#include +#include + +struct block_codegen_state { + struct code_generator_state s_base; + struct code_generator_scope *s_scope; +}; + +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 unit_codegen_state *unit = (struct unit_codegen_state *)state; + struct mie_builder *builder = gen->c_builder; + struct mie_func *current = mie_builder_get_current_func(builder); + + codegen_push_generator( + gen, CODE_GENERATOR_EXPR, CODEGEN_F_IGNORE_RESULT, NULL); + return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE); +} + +static struct code_generator_result gen_var_declaration( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node, size_t depth) +{ + struct block_codegen_state *block = (struct block_codegen_state *)state; + struct mie_builder *builder = gen->c_builder; + struct mie_func *current = mie_builder_get_current_func(builder); + + enum ivy_status status = IVY_OK; + + if (status != IVY_OK) { + return CODEGEN_RESULT_ERR(status); + } + + codegen_push_generator(gen, CODE_GENERATOR_VAR, 0, NULL); + return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE); +} + +static enum ivy_status state_init( + struct ivy_codegen *gen, struct code_generator_state *state, + uintptr_t argv, void *argp) +{ + struct block_codegen_state *block = (struct block_codegen_state *)state; + block->s_scope = codegen_push_scope(gen); + + return IVY_OK; +} + +static enum ivy_status state_fini( + struct ivy_codegen *gen, struct code_generator_state *state, + struct mie_value **result) +{ + codegen_pop_scope(gen); + + return IVY_OK; +} + +struct code_generator block_generator = { + .g_type = CODE_GENERATOR_BLOCK, + .g_state_size = sizeof(struct block_codegen_state), + .g_state_init = state_init, + .g_state_fini = state_fini, + .g_node_generators = { + NODE_CODEGEN(VAR, gen_var_declaration), + }, + .g_expr_generator = gen_expr, +}; diff --git a/lang/codegen/codegen.h b/lang/codegen/codegen.h index 951687e..774315a 100644 --- a/lang/codegen/codegen.h +++ b/lang/codegen/codegen.h @@ -46,10 +46,12 @@ enum code_generator_flags { enum code_generator_type { CODE_GENERATOR_NONE = 0, CODE_GENERATOR_UNIT, + CODE_GENERATOR_BLOCK, CODE_GENERATOR_EXPR, CODE_GENERATOR_VAR, CODE_GENERATOR_MSG, CODE_GENERATOR_FSTRING, + CODE_GENERATOR_LAMBDA, }; enum code_generator_scope_type { diff --git a/lang/codegen/expr.c b/lang/codegen/expr.c index b8b7ece..e175a37 100644 --- a/lang/codegen/expr.c +++ b/lang/codegen/expr.c @@ -156,6 +156,18 @@ static struct code_generator_result gen_msg( return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE); } +static struct code_generator_result gen_lambda( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node, size_t depth) +{ + debug_printf("codegen: got lambda\n"); + struct expr_codegen_state *expr = (struct expr_codegen_state *)state; + + codegen_push_generator(gen, CODE_GENERATOR_LAMBDA, 0, NULL); + + return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE); +} + static struct code_generator_result gen_var_reference( struct ivy_codegen *gen, struct code_generator_state *state, struct ivy_ast_node *node, size_t depth) @@ -415,6 +427,7 @@ struct code_generator expr_generator = { NODE_CODEGEN(INT, gen_int), NODE_CODEGEN(OP, gen_op), NODE_CODEGEN(MSG, gen_msg), + NODE_CODEGEN(LAMBDA, gen_lambda), NODE_CODEGEN(STRING, gen_string), NODE_CODEGEN(FSTRING, gen_fstring), NODE_CODEGEN(IDENT, gen_var_reference), diff --git a/lang/codegen/generator.c b/lang/codegen/generator.c index 6c3e7e3..9428221 100644 --- a/lang/codegen/generator.c +++ b/lang/codegen/generator.c @@ -3,17 +3,21 @@ #include extern const struct code_generator unit_generator; +extern const struct code_generator block_generator; extern const struct code_generator expr_generator; extern const struct code_generator var_generator; extern const struct code_generator msg_generator; extern const struct code_generator fstring_generator; +extern const struct code_generator lambda_generator; static const struct code_generator *code_generators[] = { [CODE_GENERATOR_UNIT] = &unit_generator, + [CODE_GENERATOR_BLOCK] = &block_generator, [CODE_GENERATOR_EXPR] = &expr_generator, [CODE_GENERATOR_VAR] = &var_generator, [CODE_GENERATOR_MSG] = &msg_generator, [CODE_GENERATOR_FSTRING] = &fstring_generator, + [CODE_GENERATOR_LAMBDA] = &lambda_generator, }; static const size_t nr_code_generators = sizeof code_generators / sizeof code_generators[0]; diff --git a/lang/codegen/lambda.c b/lang/codegen/lambda.c new file mode 100644 index 0000000..0f05297 --- /dev/null +++ b/lang/codegen/lambda.c @@ -0,0 +1,149 @@ +#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), + }, +}; diff --git a/lang/codegen/unit.c b/lang/codegen/unit.c index 01fafa1..639d2e7 100644 --- a/lang/codegen/unit.c +++ b/lang/codegen/unit.c @@ -18,14 +18,14 @@ static enum ivy_status switch_to_immediate_func( if (!unit->s_immediate) { struct mie_type *ret_type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_VOID); - unit->s_immediate = mie_func_create( - "init", MIE_FUNC_STATIC, ret_type, NULL, 0); + unit->s_immediate = mie_func_create(MIE_FUNC_STATIC, ret_type); if (!unit->s_immediate) { return IVY_ERR_NO_MEMORY; } - mie_module_add_function(gen->c_module, unit->s_immediate); + mie_module_add_function( + gen->c_module, unit->s_immediate, "init"); } struct mie_block *block = mie_func_get_last_block(unit->s_immediate);