From 596a2c835554a26cb0ad1f83892a3a11c04bad25 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 3 Dec 2017 23:03:40 +0000 Subject: [PATCH] Procedure grouping `foo :: proc[foo16, foo32];` --- src/check_decl.cpp | 46 ++++++++++++++++++++++++++++++++++ src/check_expr.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++--- src/checker.cpp | 7 ++++++ src/entity.cpp | 10 ++++++++ src/parser.cpp | 47 ++++++++++++++++++++++++++++++++++- 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_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) \ @@ -107,6 +108,9 @@ struct Entity { Entity * foreign_library; AstNode * foreign_library_ident; } Procedure; + struct { + Array entities; + } ProcedureGrouping; struct { i32 id; } Builtin; @@ -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 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 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 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 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) {