Browse Source

Generate anonymous procedure literals

gingerBill 2 years ago
parent
commit
baea6a1da8
5 changed files with 112 additions and 17 deletions
  1. 17 7
      src/tilde.cpp
  2. 7 0
      src/tilde.hpp
  3. 15 8
      src/tilde_const.cpp
  4. 15 1
      src/tilde_expr.cpp
  5. 58 1
      src/tilde_proc.cpp

+ 17 - 7
src/tilde.cpp

@@ -238,14 +238,21 @@ gb_internal void cg_add_procedure_value(cgModule *m, cgProcedure *p) {
 }
 
 gb_internal TB_Symbol *cg_find_symbol_from_entity(cgModule *m, Entity *e) {
-	if (e) {
-		rw_mutex_lock(&m->values_mutex);
-		defer (rw_mutex_unlock(&m->values_mutex));
-		TB_Symbol **found = map_get(&m->symbols, e);
-		if (found) {
-			return *found;
-		}
+	GB_ASSERT(e != nullptr);
+
+	rw_mutex_lock(&m->values_mutex);
+	defer (rw_mutex_unlock(&m->values_mutex));
+	TB_Symbol **found = map_get(&m->symbols, e);
+	if (found) {
+		return *found;
+	}
+
+	String link_name = cg_get_entity_name(m, e);
+	cgProcedure **proc_found = string_map_get(&m->procedures, link_name);
+	if (proc_found) {
+		return (*proc_found)->symbol;
 	}
+	GB_PANIC("could not find entity's symbol %.*s", LIT(e->token.string));
 	return nullptr;
 }
 
@@ -397,6 +404,8 @@ gb_internal cgModule *cg_module_create(Checker *c) {
 	map_init(&m->proc_debug_type_map);
 	map_init(&m->proc_proto_map);
 
+	map_init(&m->anonymous_proc_lits_map);
+
 	array_init(&m->single_threaded_procedure_queue, heap_allocator());
 
 
@@ -417,6 +426,7 @@ gb_internal void cg_module_destroy(cgModule *m) {
 	map_destroy(&m->debug_type_map);
 	map_destroy(&m->proc_debug_type_map);
 	map_destroy(&m->proc_proto_map);
+	map_destroy(&m->anonymous_proc_lits_map);
 
 	array_free(&m->single_threaded_procedure_queue);
 

+ 7 - 0
src/tilde.hpp

@@ -227,6 +227,10 @@ struct cgModule {
 	RecursiveMutex proc_proto_mutex;
 	PtrMap<Type *, TB_FunctionPrototype *> proc_proto_map;
 
+	BlockingMutex anonymous_proc_lits_mutex;
+	PtrMap<Ast *, cgProcedure *> anonymous_proc_lits_map;
+
+
 	// NOTE(bill): no need to protect this with a mutex
 	PtrMap<uintptr, TB_FileID> file_id_map; // Key: AstFile.id (i32 cast to uintptr)
 
@@ -259,11 +263,14 @@ gb_internal TB_Arena *cg_arena(void);
 
 gb_internal void cg_add_procedure_to_queue(cgProcedure *p);
 gb_internal void cg_setup_type_info_data(cgModule *m);
+gb_internal cgProcedure *cg_procedure_generate_anonymous(cgModule *m, Ast *expr, cgProcedure *parent);
 
 gb_internal isize cg_global_const_calculate_region_count(ExactValue const &value, Type *type);
 gb_internal i64   cg_global_const_calculate_region_count_from_basic_type(Type *type);
 gb_internal bool  cg_global_const_add_region(cgModule *m, ExactValue const &value, Type *type, TB_Global *global, i64 offset);
 
+gb_internal String cg_get_entity_name(cgModule *m, Entity *e);
+
 gb_internal cgValue cg_value(TB_Global *  g,    Type *type);
 gb_internal cgValue cg_value(TB_External *e,    Type *type);
 gb_internal cgValue cg_value(TB_Function *f,    Type *type);

+ 15 - 8
src/tilde_const.cpp

@@ -911,17 +911,24 @@ gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const
 	case ExactValue_Procedure:
 		{
 			Ast *expr = unparen_expr(value.value_procedure);
+			if (expr->kind == Ast_ProcLit) {
+				cgProcedure *anon = cg_procedure_generate_anonymous(p->module, expr, p);
+				TB_Node *ptr = tb_inst_get_symbol_address(p->func, anon->symbol);
+				GB_ASSERT(are_types_identical(type, anon->type));
+				return cg_value(ptr, type);
+			}
+
 			Entity *e = entity_of_node(expr);
 			if (e != nullptr) {
-				cgValue found = cg_find_procedure_value_from_entity(p->module, e);
-				GB_ASSERT_MSG(are_types_identical(type, found.type),
-				              "%.*s %s == %s",
-				              LIT(p->name),
-				              type_to_string(type), type_to_string(found.type));
-				GB_ASSERT(found.kind == cgValue_Symbol);
-				return cg_flatten_value(p, found);
+				TB_Symbol *found = cg_find_symbol_from_entity(p->module, e);
+				GB_ASSERT_MSG(found != nullptr, "could not find '%.*s'", LIT(e->token.string));
+				TB_Node *ptr = tb_inst_get_symbol_address(p->func, found);
+				GB_ASSERT(type != nullptr);
+				GB_ASSERT(are_types_identical(type, e->type));
+				return cg_value(ptr, type);
 			}
-			GB_PANIC("TODO(bill): cg_const_value ExactValue_Procedure");
+
+			GB_PANIC("TODO(bill): cg_const_value ExactValue_Procedure %s", expr_to_string(expr));
 		}
 		break;
 	}

+ 15 - 1
src/tilde_expr.cpp

@@ -3090,7 +3090,6 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
 		// 	gb_printf_err("%s %s : %s @ %p\n", token_pos_to_string(expr_pos), expr_to_string(expr), type_to_string(expr->tav.type), expr);
 		// 	GB_PANIC("%s\n", type_to_string(tv.type));
 		// }
-
 		// NOTE(bill): Short on constant values
 		return cg_const_value(p, type, tv.value);
 	} else if (tv.mode == Addressing_Type) {
@@ -3289,7 +3288,22 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
 	case_ast_node(ta, TypeAssertion, expr);
 		return cg_build_type_assertion(p, expr, tv.type);
 	case_end;
+
+	case_ast_node(pl, ProcLit, expr);
+		cgProcedure *anon = cg_procedure_generate_anonymous(p->module, expr, p);
+		GB_ASSERT(anon != nullptr);
+		GB_ASSERT(anon->symbol != nullptr);
+		return cg_value(tb_inst_get_symbol_address(p->func, anon->symbol), type);
+	case_end;
+
 	}
+	TokenPos token_pos = ast_token(expr).pos;
+	GB_PANIC("Unexpected expression\n"
+	         "\tAst: %.*s @ "
+	         "%s\n",
+	         LIT(ast_strings[expr->kind]),
+	         token_pos_to_string(token_pos));
+
 	return {};
 
 }

+ 58 - 1
src/tilde_proc.cpp

@@ -161,6 +161,63 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li
 	return p;
 }
 
+gb_internal cgProcedure *cg_procedure_generate_anonymous(cgModule *m, Ast *expr, cgProcedure *parent) {
+	expr = unparen_expr(expr);
+	ast_node(pl, ProcLit, expr);
+
+	mutex_lock(&m->anonymous_proc_lits_mutex);
+	defer (mutex_unlock(&m->anonymous_proc_lits_mutex));
+
+	cgProcedure **found = map_get(&m->anonymous_proc_lits_map, expr);
+	if (found) {
+		return *found;
+	}
+
+	TokenPos pos = ast_token(expr).pos;
+
+	// NOTE(bill): Generate a new name
+	// parent$count
+
+	String prefix_name = str_lit("proc_lit");
+	if (parent) {
+		prefix_name = parent->name;
+	}
+
+	isize name_len = prefix_name.len + 6 + 11;
+	char *name_text = gb_alloc_array(permanent_allocator(), char, name_len);
+
+	static std::atomic<i32> name_id;
+	name_len = gb_snprintf(name_text, name_len, "%.*s$anon-%d", LIT(prefix_name), 1+name_id.fetch_add(1));
+	String name = make_string((u8 *)name_text, name_len-1);
+
+	Type *type = type_of_expr(expr);
+
+	GB_ASSERT(pl->decl->entity == nullptr);
+	Token token = {};
+	token.pos = ast_token(expr).pos;
+	token.kind = Token_Ident;
+	token.string = name;
+	Entity *e = alloc_entity_procedure(nullptr, token, type, pl->tags);
+	e->file = expr->file();
+
+	// NOTE(bill): this is to prevent a race condition since these procedure literals can be created anywhere at any time
+	e->decl_info = pl->decl;
+	pl->decl->entity = e;
+	e->flags |= EntityFlag_ProcBodyChecked;
+
+	cgProcedure *p = cg_procedure_create(m, e);
+
+	map_set(&m->anonymous_proc_lits_map, expr, p);
+
+	if (parent != nullptr) {
+		array_add(&parent->children, p);
+	}
+
+	cg_add_procedure_to_queue(p);
+	return p;
+
+}
+
 gb_internal void cg_procedure_begin(cgProcedure *p) {
 	if (p == nullptr || p->func == nullptr) {
 		return;
@@ -374,7 +431,7 @@ gb_internal void cg_procedure_generate(cgProcedure *p) {
 
 
 	if (
-	    string_starts_with(p->name, str_lit("bug@main")) ||
+	    // string_starts_with(p->name, str_lit("bug@main")) ||
 	    false
 	) { // IR Printing
 		TB_Arena *arena = tb_default_arena();