aboutsummaryrefslogtreecommitdiff
path: root/src/tilde_stmt.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2023-07-14 13:01:17 +0100
committergingerBill <bill@gingerbill.org>2023-07-14 13:01:17 +0100
commit2a10c8fe5c9d27e1a110346ef423c1cadc95daa3 (patch)
treeeac791bd5256f65844fc0a304ef1dfb0c2b53f8d /src/tilde_stmt.cpp
parent7cd2d14b6410a17783020cea390f2be9534fa432 (diff)
Begin work on building statements
Diffstat (limited to 'src/tilde_stmt.cpp')
-rw-r--r--src/tilde_stmt.cpp287
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;
+ }
+ }
+}
+