Browse Source

Procedure grouping `foo :: proc[foo16, foo32];`

gingerBill 7 years ago
parent
commit
596a2c8355
5 changed files with 167 additions and 5 deletions
  1. 46 0
      src/check_decl.cpp
  2. 58 4
      src/check_expr.cpp
  3. 7 0
      src/checker.cpp
  4. 10 0
      src/entity.cpp
  5. 46 1
      src/parser.cpp

+ 46 - 0
src/check_decl.cpp

@@ -708,6 +708,47 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
 	check_init_variables(c, entities, entity_count, init_expr_list, context_name);
 	check_init_variables(c, entities, entity_count, init_expr_list, context_name);
 }
 }
 
 
+void check_proc_grouping_decl(Checker *c, Entity *pg_entity, DeclInfo *d) {
+	GB_ASSERT(pg_entity->kind == Entity_ProcedureGrouping);
+	auto *pge = &pg_entity->ProcedureGrouping;
+
+	ast_node(pg, ProcGrouping, d->init_expr);
+
+	array_init(&pge->entities, c->allocator, pg->args.count);
+
+
+	PtrSet<Entity *> entity_map = {};
+	ptr_set_init(&entity_map, heap_allocator());
+	defer (ptr_set_destroy(&entity_map));
+
+	for_array(i, pg->args) {
+		AstNode *arg = pg->args[i];
+		Entity *e = nullptr;
+		Operand o = {};
+		if (arg->kind == AstNode_Ident) {
+			e = check_ident(c, &o, arg, nullptr, nullptr, true);
+		} else if (arg->kind == AstNode_SelectorExpr) {
+			e = check_selector(c, &o, arg, nullptr);
+		}
+		if (e == nullptr) {
+			error(arg, "Expected a valid entity name in procedure grouping");
+			continue;
+		}
+		if (e->kind != Entity_Procedure) {
+			error(arg, "Expected a procedure entity");
+			continue;
+		}
+
+		if (ptr_set_exists(&entity_map, e)) {
+			error(arg, "Previous use of `%.*s` in procedure grouping", LIT(e->token.string));
+			continue;
+		}
+		ptr_set_add(&entity_map, e);
+
+		array_add(&pge->entities, e);
+	}
+}
+
 void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
 void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
 	if (e->type != nullptr) {
 	if (e->type != nullptr) {
 		return;
 		return;
@@ -745,6 +786,11 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
 	case Entity_Procedure:
 	case Entity_Procedure:
 		check_proc_decl(c, e, d);
 		check_proc_decl(c, e, d);
 		break;
 		break;
+
+	case Entity_ProcedureGrouping:
+		// error(e->token, "Procedure groupings are not yet supported");
+		check_proc_grouping_decl(c, e, d);
+		break;
 	}
 	}
 
 
 	c->context = prev;
 	c->context = prev;

+ 58 - 4
src/check_expr.cpp

@@ -997,6 +997,43 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
 		gb_free(heap_allocator(), procs);
 		gb_free(heap_allocator(), procs);
 	}
 	}
 
 
+	if (e->kind == Entity_ProcedureGrouping) {
+		auto *pge = &e->ProcedureGrouping;
+		Entity **procs = pge->entities.data;
+		isize overload_count = pge->entities.count;
+		bool skip = false;
+
+		if (type_hint != nullptr) {
+			gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
+			defer (gb_temp_arena_memory_end(tmp));
+
+			// NOTE(bill): These should be done
+			for (isize i = 0; i < overload_count; i++) {
+				Type *t = base_type(procs[i]->type);
+				if (t == t_invalid) {
+					continue;
+				}
+				Operand x = {};
+				x.mode = Addressing_Value;
+				x.type = t;
+				if (check_is_assignable_to(c, &x, type_hint)) {
+					e = procs[i];
+					add_entity_use(c, n, e);
+					skip = true;
+					break;
+				}
+			}
+		}
+
+		if (!skip) {
+			o->mode              = Addressing_Overload;
+			o->type              = t_invalid;
+			o->overload_count    = overload_count;
+			o->overload_entities = procs;
+			return nullptr;
+		}
+	}
+
 	add_entity_use(c, n, e);
 	add_entity_use(c, n, e);
 	check_entity_decl(c, e, nullptr, named_type);
 	check_entity_decl(c, e, nullptr, named_type);
 
 
@@ -4427,11 +4464,12 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
 		defer (gb_free(heap_allocator(), procs));
 		defer (gb_free(heap_allocator(), procs));
 		defer (gb_free(heap_allocator(), valids));
 		defer (gb_free(heap_allocator(), valids));
 
 
-		String name = procs[0]->token.string;
+		gbString expr_name = expr_to_string(operand->expr);
+		defer (gb_string_free(expr_name));
 
 
 		for (isize i = 0; i < overload_count; i++) {
 		for (isize i = 0; i < overload_count; i++) {
 			Entity *e = procs[i];
 			Entity *e = procs[i];
-			GB_ASSERT(e->token.string == name);
+			// GB_ASSERT(e->token.string == name);
 			DeclInfo *d = decl_info_of_entity(&c->info, e);
 			DeclInfo *d = decl_info_of_entity(&c->info, e);
 			GB_ASSERT(d != nullptr);
 			GB_ASSERT(d != nullptr);
 			check_entity_decl(c, e, d, nullptr);
 			check_entity_decl(c, e, d, nullptr);
@@ -4476,7 +4514,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
 
 
 
 
 		if (valid_count == 0) {
 		if (valid_count == 0) {
-			error(operand->expr, "No overloads or ambiguous call for '%.*s' that match with the given arguments", LIT(name));
+			error(operand->expr, "No overloads or ambiguous call for '%s' that match with the given arguments", expr_name);
 			gb_printf_err("\tGiven argument types -> (");
 			gb_printf_err("\tGiven argument types -> (");
 			for_array(i, operands) {
 			for_array(i, operands) {
 				Operand o = operands[i];
 				Operand o = operands[i];
@@ -4502,6 +4540,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
 				} else {
 				} else {
 					pt = type_to_string(t);
 					pt = type_to_string(t);
 				}
 				}
+				String name = proc->token.string;
 				gb_printf_err("\t%.*s :: %s at %.*s(%td:%td) with score %lld\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column, cast(long long)valids[i].score);
 				gb_printf_err("\t%.*s :: %s at %.*s(%td:%td) with score %lld\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column, cast(long long)valids[i].score);
 				// gb_printf_err("\t%.*s :: %s at %.*s(%td:%td)\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column);
 				// gb_printf_err("\t%.*s :: %s at %.*s(%td:%td)\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column);
 				gb_string_free(pt);
 				gb_string_free(pt);
@@ -4511,7 +4550,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
 			}
 			}
 			result_type = t_invalid;
 			result_type = t_invalid;
 		} else if (valid_count > 1) {
 		} else if (valid_count > 1) {
-			error(operand->expr, "Ambiguous procedure call '%.*s' tha match with the given arguments", LIT(name));
+			error(operand->expr, "Ambiguous procedure call '%s' tha match with the given arguments", expr_name);
 			gb_printf_err("\tGiven argument types -> (");
 			gb_printf_err("\tGiven argument types -> (");
 			for_array(i, operands) {
 			for_array(i, operands) {
 				Operand o = operands[i];
 				Operand o = operands[i];
@@ -4532,6 +4571,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
 				} else {
 				} else {
 					pt = type_to_string(t);
 					pt = type_to_string(t);
 				}
 				}
+				String name = proc->token.string;
 				// gb_printf_err("\t%.*s :: %s at %.*s(%td:%td) with score %lld\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column, cast(long long)valids[i].score);
 				// gb_printf_err("\t%.*s :: %s at %.*s(%td:%td) with score %lld\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column, cast(long long)valids[i].score);
 				gb_printf_err("\t%.*s :: %s at %.*s(%td:%td)\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column);
 				gb_printf_err("\t%.*s :: %s at %.*s(%td:%td)\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column);
 				gb_string_free(pt);
 				gb_string_free(pt);
@@ -5149,6 +5189,11 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 		o->mode = Addressing_Constant;
 		o->mode = Addressing_Constant;
 	case_end;
 	case_end;
 
 
+	case_ast_node(pg, ProcGrouping, node);
+		error(node, "Illegal use of a procedure grouping");
+		o->mode = Addressing_Invalid;
+	case_end;
+
 	case_ast_node(pl, ProcLit, node);
 	case_ast_node(pl, ProcLit, node);
 		CheckerContext prev_context = c->context;
 		CheckerContext prev_context = c->context;
 		DeclInfo *decl = nullptr;
 		DeclInfo *decl = nullptr;
@@ -6143,6 +6188,15 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = gb_string_appendc(str, "---");
 		str = gb_string_appendc(str, "---");
 	case_end;
 	case_end;
 
 
+	case_ast_node(pg, ProcGrouping, node);
+		str = gb_string_appendc(str, "proc[");
+		for_array(i, pg->args) {
+			if (i > 0) str = gb_string_appendc(str, ", ");
+			str = write_expr_to_string(str, pg->args[i]);
+		}
+		str = gb_string_append_rune(str, ']');
+	case_end;
+
 	case_ast_node(pl, ProcLit, node);
 	case_ast_node(pl, ProcLit, node);
 		str = write_expr_to_string(str, pl->type);
 		str = write_expr_to_string(str, pl->type);
 	case_end;
 	case_end;

+ 7 - 0
src/checker.cpp

@@ -2259,6 +2259,13 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
 				}
 				}
 				d->proc_lit = init;
 				d->proc_lit = init;
 				d->type_expr = pl->type;
 				d->type_expr = pl->type;
+			} else if (init->kind == AstNode_ProcGrouping) {
+				ast_node(pg, ProcGrouping, init);
+				e = make_entity_procedure_grouping(c->allocator, d->scope, token, nullptr);
+				if (fl != nullptr) {
+					error(name, "Procedure groupings are not allowed within a foreign block");
+				}
+				d->init_expr = init;
 			} else {
 			} else {
 				e = make_entity_constant(c->allocator, d->scope, token, nullptr, empty_exact_value);
 				e = make_entity_constant(c->allocator, d->scope, token, nullptr, empty_exact_value);
 				d->type_expr = vd->type;
 				d->type_expr = vd->type;

+ 10 - 0
src/entity.cpp

@@ -10,6 +10,7 @@ struct DeclInfo;
 	ENTITY_KIND(Variable) \
 	ENTITY_KIND(Variable) \
 	ENTITY_KIND(TypeName) \
 	ENTITY_KIND(TypeName) \
 	ENTITY_KIND(Procedure) \
 	ENTITY_KIND(Procedure) \
+	ENTITY_KIND(ProcedureGrouping) \
 	ENTITY_KIND(Builtin) \
 	ENTITY_KIND(Builtin) \
 	ENTITY_KIND(Alias) \
 	ENTITY_KIND(Alias) \
 	ENTITY_KIND(ImportName) \
 	ENTITY_KIND(ImportName) \
@@ -107,6 +108,9 @@ struct Entity {
 			Entity *     foreign_library;
 			Entity *     foreign_library;
 			AstNode *    foreign_library_ident;
 			AstNode *    foreign_library_ident;
 		} Procedure;
 		} Procedure;
+		struct {
+			Array<Entity *> entities;
+		} ProcedureGrouping;
 		struct {
 		struct {
 			i32 id;
 			i32 id;
 		} Builtin;
 		} Builtin;
@@ -244,6 +248,12 @@ Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *si
 	return entity;
 	return entity;
 }
 }
 
 
+Entity *make_entity_procedure_grouping(gbAllocator a, Scope *scope, Token token, Type *type) {
+	Entity *entity = alloc_entity(a, Entity_ProcedureGrouping, scope, token, type);
+	return entity;
+}
+
+
 Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type, i32 id) {
 Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type, i32 id) {
 	Entity *entity = alloc_entity(a, Entity_Builtin, scope, token, type);
 	Entity *entity = alloc_entity(a, Entity_Builtin, scope, token, type);
 	entity->Builtin.id = id;
 	entity->Builtin.id = id;

+ 46 - 1
src/parser.cpp

@@ -164,6 +164,12 @@ Array<AstNode *> make_ast_node_array(AstFile *f, isize init_capacity = 8) {
 		Token token; \
 		Token token; \
 		AstNode *expr; \
 		AstNode *expr; \
 	}) \
 	}) \
+	AST_NODE_KIND(ProcGrouping, "procedure grouping", struct { \
+		Token token; \
+		Token open;  \
+		Token close; \
+		Array<AstNode *> args; \
+	}) \
 	AST_NODE_KIND(ProcLit, "procedure literal", struct { \
 	AST_NODE_KIND(ProcLit, "procedure literal", struct { \
 		AstNode *type; \
 		AstNode *type; \
 		AstNode *body; \
 		AstNode *body; \
@@ -534,6 +540,7 @@ Token ast_node_token(AstNode *node) {
 	case AstNode_Undef:          return node->Undef;
 	case AstNode_Undef:          return node->Undef;
 	case AstNode_BasicLit:       return node->BasicLit;
 	case AstNode_BasicLit:       return node->BasicLit;
 	case AstNode_BasicDirective: return node->BasicDirective.token;
 	case AstNode_BasicDirective: return node->BasicDirective.token;
+	case AstNode_ProcGrouping:   return node->ProcGrouping.token;
 	case AstNode_ProcLit:        return ast_node_token(node->ProcLit.type);
 	case AstNode_ProcLit:        return ast_node_token(node->ProcLit.type);
 	case AstNode_CompoundLit:
 	case AstNode_CompoundLit:
 		if (node->CompoundLit.type != nullptr) {
 		if (node->CompoundLit.type != nullptr) {
@@ -662,6 +669,9 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
 	case AstNode_Ellipsis:
 	case AstNode_Ellipsis:
 		n->Ellipsis.expr = clone_ast_node(a, n->Ellipsis.expr);
 		n->Ellipsis.expr = clone_ast_node(a, n->Ellipsis.expr);
 		break;
 		break;
+	case AstNode_ProcGrouping:
+		n->ProcGrouping.args = clone_ast_node_array(a, n->ProcGrouping.args);
+		break;
 	case AstNode_ProcLit:
 	case AstNode_ProcLit:
 		n->ProcLit.type = clone_ast_node(a, n->ProcLit.type);
 		n->ProcLit.type = clone_ast_node(a, n->ProcLit.type);
 		n->ProcLit.body = clone_ast_node(a, n->ProcLit.body);
 		n->ProcLit.body = clone_ast_node(a, n->ProcLit.body);
@@ -1111,6 +1121,15 @@ AstNode *ast_ellipsis(AstFile *f, Token token, AstNode *expr) {
 }
 }
 
 
 
 
+AstNode *ast_proc_grouping(AstFile *f, Token token, Token open, Token close, Array<AstNode *> args) {
+	AstNode *result = make_ast_node(f, AstNode_ProcGrouping);
+	result->ProcGrouping.token = token;
+	result->ProcGrouping.open  = open;
+	result->ProcGrouping.close = close;
+	result->ProcGrouping.args = args;
+	return result;
+}
+
 AstNode *ast_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags) {
 AstNode *ast_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags) {
 	AstNode *result = make_ast_node(f, AstNode_ProcLit);
 	AstNode *result = make_ast_node(f, AstNode_ProcLit);
 	result->ProcLit.type = type;
 	result->ProcLit.type = type;
@@ -2247,9 +2266,35 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 		return expr;
 		return expr;
 	} break;
 	} break;
 
 
-	// Parse Procedure Type or Literal
+	// Parse Procedure Type or Literal or Grouping
 	case Token_proc: {
 	case Token_proc: {
 		Token token = expect_token(f, Token_proc);
 		Token token = expect_token(f, Token_proc);
+
+		if (f->curr_token.kind == Token_OpenBracket) { // ProcGrouping
+			Token open = expect_token(f, Token_OpenBracket);
+
+			Array<AstNode *> args = {};
+			array_init(&args, heap_allocator());
+
+			while (f->curr_token.kind != Token_CloseBracket &&
+			       f->curr_token.kind != Token_EOF) {
+				AstNode *elem = parse_expr(f, false);
+				array_add(&args, elem);
+
+				if (!allow_token(f, Token_Comma)) {
+					break;
+				}
+			}
+
+			Token close = expect_token(f, Token_CloseBracket);
+
+			if (args.count == 0) {
+				syntax_error(token, "Expected a least 1 argument in a procedure grouping");
+			}
+
+			return ast_proc_grouping(f, token, open, close, args);
+		}
+
 		AstNode *type = parse_proc_type(f, token);
 		AstNode *type = parse_proc_type(f, token);
 
 
 		if (f->allow_type && f->expr_level < 0) {
 		if (f->allow_type && f->expr_level < 0) {