diff options
| author | gingerBill <bill@gingerbill.org> | 2023-07-14 13:01:17 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2023-07-14 13:01:17 +0100 |
| commit | 2a10c8fe5c9d27e1a110346ef423c1cadc95daa3 (patch) | |
| tree | eac791bd5256f65844fc0a304ef1dfb0c2b53f8d /src/tilde_stmt.cpp | |
| parent | 7cd2d14b6410a17783020cea390f2be9534fa432 (diff) | |
Begin work on building statements
Diffstat (limited to 'src/tilde_stmt.cpp')
| -rw-r--r-- | src/tilde_stmt.cpp | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp new file mode 100644 index 000000000..c277eae03 --- /dev/null +++ b/src/tilde_stmt.cpp @@ -0,0 +1,287 @@ +gb_internal cgBranchBlocks cg_lookup_branch_blocks(cgProcedure *p, Ast *ident) { + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_node(ident); + GB_ASSERT(e->kind == Entity_Label); + for (cgBranchBlocks const &b : p->branch_blocks) { + if (b.label == e->Label.node) { + return b; + } + } + + GB_PANIC("Unreachable"); + cgBranchBlocks empty = {}; + return empty; +} + +gb_internal cgTargetList *cg_push_target_list(cgProcedure *p, Ast *label, TB_Node *break_, TB_Node *continue_, TB_Node *fallthrough_) { + cgTargetList *tl = gb_alloc_item(permanent_allocator(), cgTargetList); + tl->prev = p->target_list; + tl->break_ = break_; + tl->continue_ = continue_; + tl->fallthrough_ = fallthrough_; + p->target_list = tl; + + if (label != nullptr) { // Set label blocks + GB_ASSERT(label->kind == Ast_Label); + + for (cgBranchBlocks &b : p->branch_blocks) { + GB_ASSERT(b.label != nullptr && label != nullptr); + GB_ASSERT(b.label->kind == Ast_Label); + if (b.label == label) { + b.break_ = break_; + b.continue_ = continue_; + return tl; + } + } + + GB_PANIC("Unreachable"); + } + + return tl; +} + +gb_internal void cg_pop_target_list(cgProcedure *p) { + p->target_list = p->target_list->prev; +} + +gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init) { + char const *name = ""; + if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { + // NOTE(bill): for debugging purposes only + name = alloc_cstring(permanent_allocator(), e->token.string); + } + + isize size = type_size_of(type); + TB_CharUnits alignment = cast(TB_CharUnits)type_align_of(type); + if (is_type_matrix(type)) { + alignment *= 2; // NOTE(bill): Just in case + } + + TB_Node *local = tb_inst_local(p->func, cast(u32)size, alignment); + + if (zero_init) { + bool is_volatile = false; + TB_Node *zero = tb_inst_uint(p->func, TB_TYPE_I8, 0); + TB_Node *count = tb_inst_uint(p->func, TB_TYPE_I32, cast(u64)size); + tb_inst_memset(p->func, local, zero, count, alignment, is_volatile); + } + + return cg_addr(cg_value(local, alloc_type_pointer(type))); +} + + +gb_internal void cg_scope_open(cgProcedure *p, Scope *scope) { + // TODO(bill): cg_scope_open +} + +gb_internal void cg_scope_close(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region, bool pop_stack=true) { + // TODO(bill): cg_scope_close +} + +gb_internal void cg_emit_defer_stmts(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region) { + // TODO(bill): cg_emit_defer_stmts +} + +gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { + Ast *prev_stmt = p->curr_stmt; + defer (p->curr_stmt = prev_stmt); + p->curr_stmt = node; + + // TODO(bill): check if last instruction was a terminating one or not + + { + TokenPos pos = ast_token(node).pos; + TB_FileID *file_id = map_get(&p->module->file_id_map, cast(uintptr)pos.file_id); + if (file_id) { + tb_inst_set_location(p->func, *file_id, pos.line); + } + } + + u16 prev_state_flags = p->state_flags; + defer (p->state_flags = prev_state_flags); + + if (node->state_flags != 0) { + u16 in = node->state_flags; + u16 out = p->state_flags; + + if (in & StateFlag_bounds_check) { + out |= StateFlag_bounds_check; + out &= ~StateFlag_no_bounds_check; + } else if (in & StateFlag_no_bounds_check) { + out |= StateFlag_no_bounds_check; + out &= ~StateFlag_bounds_check; + } + if (in & StateFlag_no_type_assert) { + out |= StateFlag_no_type_assert; + out &= ~StateFlag_type_assert; + } else if (in & StateFlag_type_assert) { + out |= StateFlag_type_assert; + out &= ~StateFlag_no_type_assert; + } + + p->state_flags = out; + } + + switch (node->kind) { + case_ast_node(bs, EmptyStmt, node); + case_end; + + case_ast_node(us, UsingStmt, node); + case_end; + + case_ast_node(ws, WhenStmt, node); + cg_build_when_stmt(p, ws); + case_end; + + case_ast_node(bs, BlockStmt, node); + TB_Node *done = nullptr; + if (bs->label != nullptr) { + done = tb_inst_region(p->func); + tb_inst_set_region_name(done, -1, "block.done"); + cgTargetList *tl = cg_push_target_list(p, bs->label, done, nullptr, nullptr); + tl->is_block = true; + } + + cg_scope_open(p, bs->scope); + cg_build_stmt_list(p, bs->stmts); + cg_scope_close(p, cgDeferExit_Default, nullptr); + + if (done != nullptr) { + tb_inst_goto(p->func, done); + tb_inst_set_control(p->func, done); + } + + if (bs->label != nullptr) { + cg_pop_target_list(p); + } + case_end; + + case_ast_node(vd, ValueDecl, node); + if (!vd->is_mutable) { + return; + } + + bool is_static = false; + if (vd->names.count > 0) { + for (Ast *name : vd->names) { + if (!is_blank_ident(name)) { + GB_ASSERT(name->kind == Ast_Ident); + Entity *e = entity_of_node(name); + TokenPos pos = ast_token(name).pos; + GB_ASSERT_MSG(e != nullptr, "\n%s missing entity for %.*s", token_pos_to_string(pos), LIT(name->Ident.token.string)); + if (e->flags & EntityFlag_Static) { + // NOTE(bill): If one of the entities is static, they all are + is_static = true; + break; + } + } + } + } + if (is_static) { + GB_PANIC("TODO(bill): build static variables"); + return; + } + + TEMPORARY_ALLOCATOR_GUARD(); + + auto const &values = vd->values; + if (values.count == 0) { + for (Ast *name : vd->names) { + if (!is_blank_ident(name)) { + Entity *e = entity_of_node(name); + bool zero_init = true; + cgAddr addr = cg_add_local(p, e->type, e, zero_init); + gb_unused(addr); + } + } + } else { + GB_PANIC("TODO multiple variables"); + } + case_end; + + case_ast_node(bs, BranchStmt, node); + TB_Node *prev_block = tb_inst_get_control(p->func); + + TB_Node *block = nullptr; + + if (bs->label != nullptr) { + cgBranchBlocks bb = cg_lookup_branch_blocks(p, bs->label); + switch (bs->token.kind) { + case Token_break: block = bb.break_; break; + case Token_continue: block = bb.continue_; break; + case Token_fallthrough: + GB_PANIC("fallthrough cannot have a label"); + break; + } + } else { + for (cgTargetList *t = p->target_list; t != nullptr && block == nullptr; t = t->prev) { + if (t->is_block) { + continue; + } + + switch (bs->token.kind) { + case Token_break: block = t->break_; break; + case Token_continue: block = t->continue_; break; + case Token_fallthrough: block = t->fallthrough_; break; + } + } + } + if (block != nullptr) { + cg_emit_defer_stmts(p, cgDeferExit_Branch, block); + } + + + tb_inst_goto(p->func, block); + tb_inst_set_control(p->func, block); + tb_inst_unreachable(p->func); + + tb_inst_set_control(p->func, prev_block); + case_end; + + default: + GB_PANIC("TODO cg_build_stmt %.*s", LIT(ast_strings[node->kind])); + break; + } +} + + +gb_internal void cg_build_stmt_list(cgProcedure *p, Slice<Ast *> const &stmts) { + for (Ast *stmt : stmts) { + switch (stmt->kind) { + case_ast_node(vd, ValueDecl, stmt); + // TODO(bill) + // cg_build_constant_value_decl(p, vd); + case_end; + case_ast_node(fb, ForeignBlockDecl, stmt); + ast_node(block, BlockStmt, fb->body); + cg_build_stmt_list(p, block->stmts); + case_end; + } + } + for (Ast *stmt : stmts) { + cg_build_stmt(p, stmt); + } +} + + +gb_internal void cg_build_when_stmt(cgProcedure *p, AstWhenStmt *ws) { + TypeAndValue tv = type_and_value_of_expr(ws->cond); + GB_ASSERT(is_type_boolean(tv.type)); + GB_ASSERT(tv.value.kind == ExactValue_Bool); + if (tv.value.value_bool) { + cg_build_stmt_list(p, ws->body->BlockStmt.stmts); + } else if (ws->else_stmt) { + switch (ws->else_stmt->kind) { + case Ast_BlockStmt: + cg_build_stmt_list(p, ws->else_stmt->BlockStmt.stmts); + break; + case Ast_WhenStmt: + cg_build_when_stmt(p, &ws->else_stmt->WhenStmt); + break; + default: + GB_PANIC("Invalid 'else' statement in 'when' statement"); + break; + } + } +} + |