aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2017-12-03 23:03:40 +0000
committergingerBill <bill@gingerbill.org>2017-12-03 23:03:40 +0000
commit596a2c835554a26cb0ad1f83892a3a11c04bad25 (patch)
tree432c9cbf862d33c840c8664a4f31587e142cfc35
parent9f52b2c2834a3a7248784492a3ede3a8a9063f6a (diff)
Procedure grouping `foo :: proc[foo16, foo32];`
-rw-r--r--src/check_decl.cpp46
-rw-r--r--src/check_expr.cpp62
-rw-r--r--src/checker.cpp7
-rw-r--r--src/entity.cpp10
-rw-r--r--src/parser.cpp47
5 files changed, 167 insertions, 5 deletions
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index b7bd91183..7b01c259e 100644
--- a/src/check_decl.cpp
+++ b/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);
}
+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) {
if (e->type != nullptr) {
return;
@@ -745,6 +786,11 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
case Entity_Procedure:
check_proc_decl(c, e, d);
break;
+
+ case Entity_ProcedureGrouping:
+ // error(e->token, "Procedure groupings are not yet supported");
+ check_proc_grouping_decl(c, e, d);
+ break;
}
c->context = prev;
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index eaa54306c..36419d172 100644
--- a/src/check_expr.cpp
+++ b/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);
}
+ 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);
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(), 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++) {
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);
GB_ASSERT(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) {
- 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 -> (");
for_array(i, operands) {
Operand o = operands[i];
@@ -4502,6 +4540,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
} else {
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)\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column);
gb_string_free(pt);
@@ -4511,7 +4550,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
}
result_type = t_invalid;
} 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 -> (");
for_array(i, operands) {
Operand o = operands[i];
@@ -4532,6 +4571,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
} else {
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)\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column);
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;
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);
CheckerContext prev_context = c->context;
DeclInfo *decl = nullptr;
@@ -6143,6 +6188,15 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
str = gb_string_appendc(str, "---");
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);
str = write_expr_to_string(str, pl->type);
case_end;
diff --git a/src/checker.cpp b/src/checker.cpp
index 2bdf72f79..41faba7c0 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -2259,6 +2259,13 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
}
d->proc_lit = init;
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 {
e = make_entity_constant(c->allocator, d->scope, token, nullptr, empty_exact_value);
d->type_expr = vd->type;
diff --git a/src/entity.cpp b/src/entity.cpp
index 940288957..ef49c4d0e 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -10,6 +10,7 @@ struct DeclInfo;
ENTITY_KIND(Variable) \
ENTITY_KIND(TypeName) \
ENTITY_KIND(Procedure) \
+ ENTITY_KIND(ProcedureGrouping) \
ENTITY_KIND(Builtin) \
ENTITY_KIND(Alias) \
ENTITY_KIND(ImportName) \
@@ -108,6 +109,9 @@ struct Entity {
AstNode * foreign_library_ident;
} Procedure;
struct {
+ Array<Entity *> entities;
+ } ProcedureGrouping;
+ struct {
i32 id;
} Builtin;
struct {
@@ -244,6 +248,12 @@ Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *si
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 *entity = alloc_entity(a, Entity_Builtin, scope, token, type);
entity->Builtin.id = id;
diff --git a/src/parser.cpp b/src/parser.cpp
index 62f6f6870..189e13f32 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -164,6 +164,12 @@ Array<AstNode *> make_ast_node_array(AstFile *f, isize init_capacity = 8) {
Token token; \
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 { \
AstNode *type; \
AstNode *body; \
@@ -534,6 +540,7 @@ Token ast_node_token(AstNode *node) {
case AstNode_Undef: return node->Undef;
case AstNode_BasicLit: return node->BasicLit;
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_CompoundLit:
if (node->CompoundLit.type != nullptr) {
@@ -662,6 +669,9 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
case AstNode_Ellipsis:
n->Ellipsis.expr = clone_ast_node(a, n->Ellipsis.expr);
break;
+ case AstNode_ProcGrouping:
+ n->ProcGrouping.args = clone_ast_node_array(a, n->ProcGrouping.args);
+ break;
case AstNode_ProcLit:
n->ProcLit.type = clone_ast_node(a, n->ProcLit.type);
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 *result = make_ast_node(f, AstNode_ProcLit);
result->ProcLit.type = type;
@@ -2247,9 +2266,35 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
return expr;
} break;
- // Parse Procedure Type or Literal
+ // Parse Procedure Type or Literal or Grouping
case 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);
if (f->allow_type && f->expr_level < 0) {