Bladeren bron

Begin mocking out `me_build_stmt`

gingerBill 3 jaren geleden
bovenliggende
commit
921601766d
5 gewijzigde bestanden met toevoegingen van 445 en 4 verwijderingen
  1. 42 0
      src/middle_end.cpp
  2. 10 0
      src/middle_end.hpp
  3. 1 4
      src/middle_end_core.cpp
  4. 3 0
      src/middle_end_expr.cpp
  5. 389 0
      src/middle_end_stmt.cpp

+ 42 - 0
src/middle_end.cpp

@@ -1,5 +1,7 @@
 #include "middle_end.hpp"
 #include "middle_end_core.cpp"
+#include "middle_end_stmt.cpp"
+#include "middle_end_expr.cpp"
 
 
 void me_module_init(meModule *m, Checker *c) {
@@ -250,6 +252,46 @@ void me_procedure_body_end(meProcedure *p) {
 }
 
 
+void me_build_nested_proc(meProcedure *p, AstProcLit *pd, Entity *e) {
+	GB_ASSERT(pd->body != nullptr);
+	meModule *m = p->module;
+	auto *min_dep_set = &m->info->minimum_dependency_set;
+
+	if (ptr_set_exists(min_dep_set, e) == false) {
+		// NOTE(bill): Nothing depends upon it so doesn't need to be built
+		return;
+	}
+
+	// NOTE(bill): Generate a new name
+	// parent.name-guid
+	String original_name = e->token.string;
+	String pd_name = original_name;
+	if (e->Procedure.link_name.len > 0) {
+		pd_name = e->Procedure.link_name;
+	}
+
+
+	isize name_len = p->name.len + 1 + pd_name.len + 1 + 10 + 1;
+	char *name_text = gb_alloc_array(permanent_allocator(), char, name_len);
+
+	i32 guid = cast(i32)p->children.count;
+	name_len = gb_snprintf(name_text, name_len, "%.*s.%.*s-%d", LIT(p->name), LIT(pd_name), guid);
+	String name = make_string(cast(u8 *)name_text, name_len-1);
+
+	e->Procedure.link_name = name;
+
+	meProcedure *nested_proc = me_procedure_create(p->module, e);
+	e->me_procedure = nested_proc;
+
+	meValue value = me_value(nested_proc);
+
+	me_add_entity(m, e, value);
+	array_add(&p->children, nested_proc);
+	array_add(&m->procedures_to_generate, nested_proc);
+}
+
+
+
 void me_generate_procedure(meModule *m, meProcedure *p) {
 	if (p->is_done) {
 		return;

+ 10 - 0
src/middle_end.hpp

@@ -286,6 +286,13 @@ struct meDefer {
 	};
 };
 
+enum meDeferExitKind {
+	meDeferExit_Default,
+	meDeferExit_Return,
+	meDeferExit_Branch,
+};
+
+
 
 enum meProcedureFlags : u32 {
 	meProcedureFlag_Foreign    = 1<<1,
@@ -386,4 +393,7 @@ meValue me_value(meGlobalVariable *global);
 meValue me_value(meParameter *param);
 
 
+void me_build_stmt(meProcedure *p, Ast *stmt);
+meValue me_build_expr(meProcedure *p, Ast *expr);
 meValue me_emit_conv(meProcedure *p, meValue value, Type *type);
+

+ 1 - 4
src/middle_end_core.cpp

@@ -386,9 +386,6 @@ void me_block_start(meProcedure *p, meBlock *b) {
 	p->curr_block = b;
 }
 
-void me_build_stmt(meProcedure *p, Ast *stmt) {
-
-}
 
 meContextData *me_push_context_onto_stack_from_implicit_parameter(meProcedure *p) {
 	// TODO(bill): me_push_context_onto_stack_from_implicit_parameter
@@ -881,7 +878,7 @@ meValue me_emit_select(meProcedure *p, meValue cond, meValue left, meValue right
 	return me_value(v);
 }
 
-meValue me_emit_call(meProcedure *p, meValue proc, Slice<meValue> const &arguments, u16 instruction_flags) {
+meValue me_emit_call(meProcedure *p, meValue proc, Slice<meValue> const &arguments, u16 instruction_flags = 0) {
 	GB_PANIC("TODO");
 	return {};
 }

+ 3 - 0
src/middle_end_expr.cpp

@@ -0,0 +1,3 @@
+meValue me_build_expr(meProcedure *p, Ast *expr) {
+	return {};
+}

+ 389 - 0
src/middle_end_stmt.cpp

@@ -0,0 +1,389 @@
+void me_build_nested_proc(meProcedure *p, AstProcLit *pd, Entity *e);
+
+void me_build_constant_value_decl(meProcedure *p, AstValueDecl *vd) {
+	if (vd == nullptr || vd->is_mutable) {
+		return;
+	}
+
+	auto *min_dep_set = &p->module->info->minimum_dependency_set;
+
+	static i32 global_guid = 0;
+
+	for_array(i, vd->names) {
+		Ast *ident = vd->names[i];
+		GB_ASSERT(ident->kind == Ast_Ident);
+		Entity *e = entity_of_node(ident);
+		GB_ASSERT(e != nullptr);
+		if (e->kind != Entity_TypeName) {
+			continue;
+		}
+
+		bool polymorphic_struct = false;
+		if (e->type != nullptr && e->kind == Entity_TypeName) {
+			Type *bt = base_type(e->type);
+			if (bt->kind == Type_Struct) {
+				polymorphic_struct = bt->Struct.is_polymorphic;
+			}
+		}
+
+		if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) {
+			continue;
+		}
+
+		if (e->TypeName.ir_mangled_name.len != 0) {
+			// NOTE(bill): Already set
+			continue;
+		}
+
+		me_set_nested_type_name_ir_mangled_name(e, p);
+	}
+
+	for_array(i, vd->names) {
+		Ast *ident = vd->names[i];
+		GB_ASSERT(ident->kind == Ast_Ident);
+		Entity *e = entity_of_node(ident);
+		GB_ASSERT(e != nullptr);
+		if (e->kind != Entity_Procedure) {
+			continue;
+		}
+		GB_ASSERT (vd->values[i] != nullptr);
+
+		Ast *value = unparen_expr(vd->values[i]);
+		if (value->kind != Ast_ProcLit) {
+			continue; // It's an alias
+		}
+
+		CheckerInfo *info = p->module->info;
+		DeclInfo *decl = decl_info_of_entity(e);
+		ast_node(pl, ProcLit, decl->proc_lit);
+		if (pl->body != nullptr) {
+			auto *found = map_get(&info->gen_procs, ident);
+			if (found) {
+				auto procs = *found;
+				for_array(i, procs) {
+					Entity *e = procs[i];
+					if (!ptr_set_exists(min_dep_set, e)) {
+						continue;
+					}
+					DeclInfo *d = decl_info_of_entity(e);
+					me_build_nested_proc(p, &d->proc_lit->ProcLit, e);
+				}
+			} else {
+				me_build_nested_proc(p, pl, e);
+			}
+		} else {
+
+			// FFI - Foreign function interace
+			String original_name = e->token.string;
+			String name = original_name;
+
+			if (e->Procedure.is_foreign) {
+				me_add_foreign_library_path(p->module, e->Procedure.foreign_library);
+			}
+
+			if (e->Procedure.link_name.len > 0) {
+				name = e->Procedure.link_name;
+			}
+
+			meValue *prev_value = string_map_get(&p->module->members, name);
+			if (prev_value != nullptr) {
+				// NOTE(bill): Don't do mutliple declarations in the IR
+				return;
+			}
+
+			e->Procedure.link_name = name;
+
+			meProcedure *nested_proc = me_procedure_create(p->module, e);
+
+			meValue value = me_value(nested_proc);
+
+			array_add(&p->module->procedures_to_generate, nested_proc);
+			array_add(&p->children, nested_proc);
+			string_map_set(&p->module->members, name, value);
+		}
+	}
+}
+
+void me_build_defer_stmt(meProcedure *p, meDefer const &d) {
+	if (p->curr_block == nullptr) {
+		return;
+	}
+	// NOTE(bill): The prev block may defer injection before it's terminator
+	meInstruction *last_instr = me_last_instruction(p->curr_block);
+	if (last_instr != nullptr && last_instr->op == meOp_Return) {
+		// NOTE(bill): ReturnStmt defer stuff will be handled previously
+		return;
+	}
+
+	isize prev_context_stack_count = p->context_stack.count;
+	GB_ASSERT(prev_context_stack_count <= p->context_stack.capacity);
+	defer (p->context_stack.count = prev_context_stack_count);
+	p->context_stack.count = d.context_stack_count;
+
+	meBlock *b = me_block_create(p, "defer");
+	if (last_instr == nullptr || !me_is_instruction_terminator(last_instr->op)) {
+		me_emit_jump(p, b);
+	}
+
+	me_block_start(p, b);
+	if (d.kind == meDefer_Node) {
+		me_build_stmt(p, d.stmt);
+	} else if (d.kind == meDefer_Proc) {
+		me_emit_call(p, d.proc.deferred, slice_from_array(d.proc.result_as_args));
+	}
+}
+
+void me_emit_defer_stmts(meProcedure *p, meDeferExitKind kind, meBlock *block) {
+	isize count = p->defer_stmts.count;
+	isize i = count;
+	while (i --> 0) {
+		meDefer const &d = p->defer_stmts[i];
+
+		if (kind == meDeferExit_Default) {
+			if (p->scope_index == d.scope_index &&
+			    d.scope_index > 0) { // TODO(bill): Which is correct: > 0 or > 1?
+				me_build_defer_stmt(p, d);
+				array_pop(&p->defer_stmts);
+				continue;
+			} else {
+				break;
+			}
+		} else if (kind == meDeferExit_Return) {
+			me_build_defer_stmt(p, d);
+		} else if (kind == meDeferExit_Branch) {
+			GB_ASSERT(block != nullptr);
+			isize lower_limit = block->scope_index;
+			if (lower_limit < d.scope_index) {
+				me_build_defer_stmt(p, d);
+			}
+		}
+	}
+}
+
+
+
+
+meBranchBlocks me_lookup_branch_blocks(meProcedure *p, Ast *ident) {
+	GB_ASSERT(ident->kind == Ast_Ident);
+	Entity *e = entity_of_node(ident);
+	GB_ASSERT(e->kind == Entity_Label);
+	for_array(i, p->branch_blocks) {
+		meBranchBlocks *b = &p->branch_blocks[i];
+		if (b->label == e->Label.node) {
+			return *b;
+		}
+	}
+
+	GB_PANIC("Unreachable");
+	meBranchBlocks empty = {};
+	return empty;
+}
+
+
+meTargetList *me_target_list_push(meProcedure *p, Ast *label, meBlock *break_, meBlock *continue_, meBlock *fallthrough_) {
+	meTargetList *tl = gb_alloc_item(permanent_allocator(), meTargetList);
+	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_array(i, p->branch_blocks) {
+			meBranchBlocks *b = &p->branch_blocks[i];
+			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;
+}
+
+void me_target_list_pop(meProcedure *p) {
+	p->target_list = p->target_list->prev;
+}
+
+void me_scope_open(meProcedure *p, Scope *s) {
+	p->scope_index += 1;
+	array_add(&p->scope_stack, s);
+
+}
+
+void me_scope_close(meProcedure *p, meDeferExitKind kind, meBlock *block, bool pop_stack=true) {
+	me_emit_defer_stmts(p, kind, block);
+	GB_ASSERT(p->scope_index > 0);
+
+	// NOTE(bill): Remove `context`s made in that scope
+	while (p->context_stack.count > 0) {
+		meContextData *ctx = &p->context_stack[p->context_stack.count-1];
+		if (ctx->scope_index >= p->scope_index) {
+			array_pop(&p->context_stack);
+		} else {
+			break;
+		}
+
+	}
+
+	p->scope_index -= 1;
+	array_pop(&p->scope_stack);
+}
+
+void me_build_stmt_list(meProcedure *p, Slice<Ast *> const &stmts) {
+	for_array(i, stmts) {
+		Ast *stmt = stmts[i];
+		switch (stmt->kind) {
+		case_ast_node(vd, ValueDecl, stmt);
+			// me_build_constant_value_decl(p, vd);
+		case_end;
+		case_ast_node(fb, ForeignBlockDecl, stmt);
+			ast_node(block, BlockStmt, fb->body);
+			me_build_stmt_list(p, block->stmts);
+		case_end;
+		}
+	}
+	for_array(i, stmts) {
+		me_build_stmt(p, stmts[i]);
+	}
+}
+
+void me_build_when_stmt(meProcedure *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) {
+		me_build_stmt_list(p, ws->body->BlockStmt.stmts);
+	} else if (ws->else_stmt) {
+		switch (ws->else_stmt->kind) {
+		case Ast_BlockStmt:
+			me_build_stmt_list(p, ws->else_stmt->BlockStmt.stmts);
+			break;
+		case Ast_WhenStmt:
+			me_build_when_stmt(p, &ws->else_stmt->WhenStmt);
+			break;
+		default:
+			GB_PANIC("Invalid 'else' statement in 'when' statement");
+			break;
+		}
+	}
+}
+
+
+
+void me_build_stmt(meProcedure *p, Ast *node) {
+	Ast *prev_stmt = p->curr_stmt;
+	defer (p->curr_stmt = prev_stmt);
+	p->curr_stmt = node;
+
+	if (me_is_last_instruction_terminator(p->curr_block)) {
+		return;
+	}
+
+	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);
+		me_build_when_stmt(p, ws);
+	case_end;
+
+	case_ast_node(bs, BlockStmt, node);
+		meBlock *done = nullptr;
+		if (bs->label != nullptr) {
+			done = me_block_create(p, "block.done");
+			meTargetList *tl = me_target_list_push(p, bs->label, done, nullptr, nullptr);
+			tl->is_block = true;
+		}
+
+		me_scope_open(p, bs->scope);
+		me_build_stmt_list(p, bs->stmts);
+		me_scope_close(p, meDeferExit_Default, nullptr);
+
+		if (done != nullptr) {
+			me_emit_jump(p, done);
+			me_block_start(p, done);
+		}
+
+		if (bs->label != nullptr) {
+			me_target_list_pop(p);
+		}
+	case_end;
+
+	case_ast_node(bs, BranchStmt, node);
+		meBlock *block = nullptr;
+
+		if (bs->label != nullptr) {
+			meBranchBlocks bb = me_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 (meTargetList *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) {
+			me_emit_defer_stmts(p, meDeferExit_Branch, block);
+		}
+		me_emit_jump(p, block);
+		me_block_start(p, me_block_create(p, "unreachable"));
+	case_end;
+
+	case_ast_node(vd, ValueDecl, node);
+		if (!vd->is_mutable) {
+			return;
+		}
+
+		// TODO: ValueDecl
+
+	case_end;
+	}
+}