#include "codegen.h" #include #include #include struct block_codegen_state { struct code_generator_state s_base; struct code_generator_scope *s_scope; struct codegen_var_map s_vars; /* the value of the final expression in the block */ struct mie_value *s_result; }; 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 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); 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_for_loop( struct ivy_codegen *gen, struct code_generator_state *state, struct ivy_ast_node *node, size_t depth) { codegen_push_generator( gen, CODE_GENERATOR_FOR_LOOP, CODEGEN_F_IGNORE_RESULT, NULL); return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE); } static struct code_generator_result gen_while_loop( struct ivy_codegen *gen, struct code_generator_state *state, struct ivy_ast_node *node, size_t depth) { codegen_push_generator( gen, CODE_GENERATOR_WHILE_LOOP, CODEGEN_F_IGNORE_RESULT, NULL); return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE); } static struct code_generator_result gen_return( 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_RETURN, 0, NULL); return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE); } static struct code_generator_result gen_loop_break( 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; if (!state->s_loop_break_target) { return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX); } mie_builder_br(gen->c_builder, state->s_loop_break_target); block->s_result = mie_ctx_get_null(gen->c_ctx); return CODEGEN_RESULT_OK(0); } static struct code_generator_result gen_loop_repeat( 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; if (!state->s_loop_repeat_target) { return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX); } mie_builder_br(gen->c_builder, state->s_loop_repeat_target); block->s_result = mie_ctx_get_null(gen->c_ctx); 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 block_codegen_state *block = (struct block_codegen_state *)state; codegen_var_map_init(&block->s_vars); return IVY_OK; } static enum ivy_status state_fini( struct ivy_codegen *gen, struct code_generator_state *state, struct code_generator_value *result) { struct block_codegen_state *block = (struct block_codegen_state *)state; code_generator_value_set_mie_value(result, block->s_result); codegen_var_map_fini(&block->s_vars); 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 block_codegen_state *block = (struct block_codegen_state *)state; block->s_result = code_generator_value_get_mie_value(value); return CODEGEN_RESULT_OK(0); } static enum ivy_status define_var( struct ivy_codegen *gen, struct code_generator_state *state, const char *ident, const struct codegen_var *var) { struct block_codegen_state *block = (struct block_codegen_state *)state; return codegen_var_map_put(&block->s_vars, ident, var); } static enum ivy_status resolve_var( struct ivy_codegen *gen, struct code_generator_state *state, const char *ident, struct codegen_var *var) { struct block_codegen_state *block = (struct block_codegen_state *)state; struct codegen_var *result = NULL; enum ivy_status status = codegen_var_map_get(&block->s_vars, ident, &result); if (status != IVY_OK) { return status; } memcpy(var, result, sizeof *var); 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_value_received = value_received, .g_node_generators = { NODE_CODEGEN(FOR_LOOP, gen_for_loop), NODE_CODEGEN(WHILE_LOOP, gen_while_loop), NODE_CODEGEN(RETURN, gen_return), NODE_CODEGEN(LOOP_BREAK, gen_loop_break), NODE_CODEGEN(LOOP_REPEAT, gen_loop_repeat), }, .g_expr_generator = gen_expr, .g_define_var = define_var, .g_resolve_var = resolve_var, };