Explicit procedure group; Remove implicit procedure overloading

This commit is contained in:
gingerBill
2017-12-09 18:11:36 +00:00
parent 41b8281c73
commit 3703ca4df4
12 changed files with 359 additions and 532 deletions

View File

@@ -148,9 +148,10 @@ div :: proc[
];
inverse :: proc[mat4_inverse, quat_inverse];
dot :: proc[vec_dot, quat_dot];
cross :: proc[cross2, cross3];
dot :: proc(a, b: $T/[$N]$E) -> E {
vec_dot :: proc(a, b: $T/[$N]$E) -> E {
res: E;
for i in 0..N {
res += a[i] * b[i];
@@ -167,7 +168,6 @@ cross3 :: proc(a, b: $T/[3]$E) -> T {
j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0);
return T(i - j);
}
cross :: proc[cross2, cross3];
length :: proc(v: $T/[$N]$E) -> E { return sqrt(dot(v, v)); }

View File

@@ -1,5 +1,5 @@
import win32 "core:sys/windows.odin" when ODIN_OS == "windows";
import wgl "core:sys/wgl.odin" when ODIN_OS == "windows";
when ODIN_OS == "windows" do import win32 "core:sys/windows.odin";
when ODIN_OS == "windows" import wgl "core:sys/wgl.odin";
import "core:fmt.odin";
import "core:math.odin";
import "core:os.odin";

View File

@@ -308,7 +308,7 @@ String get_fullpath_core(gbAllocator a, String path) {
}
String const ODIN_VERSION = str_lit("0.7.1");
String const ODIN_VERSION = str_lit("0.8.0-dev");
String cross_compile_target = str_lit("");
String cross_compile_lib_dir = str_lit("");

View File

@@ -23,9 +23,9 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
}
if (operand->mode == Addressing_Overload) {
if (operand->mode == Addressing_ProcGroup) {
if (e->type == nullptr) {
error(operand->expr, "Cannot determine type from overloaded procedure '%.*s'", LIT(operand->overload_entities[0]->token.string));
error(operand->expr, "Cannot determine type from overloaded procedure '%.*s'", LIT(operand->proc_group->token.string));
} else {
check_assignment(c, operand, e->type, str_lit("variable assignment"));
if (operand->mode != Addressing_Type) {
@@ -275,11 +275,15 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
e->type = t_invalid;
return;
case Addressing_Overload:
e->kind = Entity_Alias;
e->Alias.base = operand.overload_entities[0];
case Addressing_ProcGroup: {
GB_ASSERT(operand.proc_group != nullptr);
GB_ASSERT(operand.proc_group->kind == Entity_ProcGroup);
e->kind = Entity_ProcGroup;
e->type = t_invalid;
gb_memcopy(&e->ProcGroup, &operand.proc_group->ProcGroup, gb_size_of(e->ProcGroup));
return;
}
#endif
}
#if 1
@@ -708,11 +712,11 @@ 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;
void check_proc_group_decl(Checker *c, Entity *pg_entity, DeclInfo *d) {
GB_ASSERT(pg_entity->kind == Entity_ProcGroup);
auto *pge = &pg_entity->ProcGroup;
ast_node(pg, ProcGrouping, d->init_expr);
ast_node(pg, ProcGroup, d->init_expr);
array_init(&pge->entities, c->allocator, pg->args.count);
@@ -731,22 +735,87 @@ void check_proc_grouping_decl(Checker *c, Entity *pg_entity, DeclInfo *d) {
e = check_selector(c, &o, arg, nullptr);
}
if (e == nullptr) {
error(arg, "Expected a valid entity name in procedure grouping");
error(arg, "Expected a valid entity name in procedure group");
continue;
}
if (e->kind != Entity_Procedure) {
if (e->kind == Entity_Variable) {
if (!is_type_proc(e->type)) {
error(arg, "Expected a procedure variable");
continue;
}
} else 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));
error(arg, "Previous use of `%.*s` in procedure group", LIT(e->token.string));
continue;
}
ptr_set_add(&entity_map, e);
array_add(&pge->entities, e);
}
for_array(j, pge->entities) {
Entity *p = pge->entities[j];
if (p->type == t_invalid) {
// NOTE(bill): This invalid overload has already been handled
continue;
}
String name = p->token.string;
for (isize k = j+1; k < pge->entities.count; k++) {
Entity *q = pge->entities[k];
GB_ASSERT(p != q);
bool is_invalid = false;
TokenPos pos = q->token.pos;
if (q->type == nullptr || q->type == t_invalid) {
continue;
}
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
switch (kind) {
case ProcOverload_Identical:
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
is_invalid = true;
break;
// case ProcOverload_CallingConvention:
// error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
// is_invalid = true;
// break;
case ProcOverload_ParamVariadic:
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
is_invalid = true;
break;
case ProcOverload_ResultCount:
case ProcOverload_ResultTypes:
error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in this scope", LIT(name));
is_invalid = true;
break;
case ProcOverload_Polymorphic:
#if 0
error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in this scope which is not allowed", LIT(name));
is_invalid = true;
#endif
break;
case ProcOverload_ParamCount:
case ProcOverload_ParamTypes:
// This is okay :)
break;
}
if (is_invalid) {
gb_printf_err("\tprevious procedure at %.*s(%td:%td)\n", LIT(pos.file), pos.line, pos.column);
q->type = t_invalid;
}
}
}
}
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
@@ -787,9 +856,8 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
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);
case Entity_ProcGroup:
check_proc_group_decl(c, e, d);
break;
}

View File

@@ -127,14 +127,6 @@ void check_scope_decls(Checker *c, Array<AstNode *> nodes, isize reserve_size) {
check_entity_decl(c, e, d, nullptr);
}
}
for_array(i, s->elements.entries) {
Entity *e = s->elements.entries[i].value;
if (e->kind != Entity_Procedure) {
continue;
}
check_procedure_overloading(c, e);
}
}
@@ -659,18 +651,16 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
return;
}
if (operand->mode == Addressing_Overload) {
if (operand->mode == Addressing_ProcGroup) {
// GB_PANIC("HERE!\n");
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
defer (gb_temp_arena_memory_end(tmp));
Entity **procs = operand->overload_entities;
isize overload_count = operand->overload_count;
Array<Entity *> procs = proc_group_entities(c, *operand);
bool good = false;
// NOTE(bill): These should be done
for (isize i = 0; i < overload_count; i++) {
for_array(i, procs) {
Type *t = base_type(procs[i]->type);
if (t == t_invalid) {
continue;
@@ -783,7 +773,10 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
return false;
case Type_Array:
if (source->kind == Type_Array) {
if (poly->Array.generic_type && modify_type) {
// IMPORTANT TODO(bill): Which is correct?
// if (poly->Array.generic_type != nullptr && modify_type) {
if (poly->Array.generic_type != nullptr) {
Type *gt = poly->Array.generic_type;
GB_ASSERT(gt->kind == Type_Generic);
Entity *e = scope_lookup_entity(gt->Generic.scope, gt->Generic.name);
@@ -808,8 +801,6 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
} else {
return false;
}
return is_polymorphic_type_assignable(c, poly->Array.elem, source->Array.elem, true, modify_type);
}
if (poly->Array.count == source->Array.count) {
return is_polymorphic_type_assignable(c, poly->Array.elem, source->Array.elem, true, modify_type);
@@ -936,10 +927,6 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
return nullptr;
}
}
bool is_overloaded = false;
isize overload_count = 0;
bool is_alias = false;
while (e->kind == Entity_Alias) {
GB_ASSERT(e->Alias.base != nullptr);
@@ -949,63 +936,14 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
HashKey key = hash_string(e->token.string);
if (e->kind == Entity_Procedure) {
// NOTE(bill): Overloads are only allowed with the same scope
Scope *s = e->scope;
overload_count = multi_map_count(&s->elements, key);
if (overload_count > 1) {
is_overloaded = true;
}
}
if (is_overloaded) {
Scope *s = e->scope;
bool skip = false;
Entity **procs = gb_alloc_array(heap_allocator(), Entity *, overload_count);
multi_map_get_all(&s->elements, key, procs);
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;
}
gb_free(heap_allocator(), procs);
}
if (e->kind == Entity_ProcedureGrouping) {
auto *pge = &e->ProcedureGrouping;
if (e->kind == Entity_ProcGroup) {
auto *pge = &e->ProcGroup;
DeclInfo *d = decl_info_of_entity(&c->info, e);
check_entity_decl(c, e, d, nullptr);
Entity **procs = pge->entities.data;
isize overload_count = pge->entities.count;
Array<Entity *> procs = pge->entities;
bool skip = false;
if (type_hint != nullptr) {
@@ -1013,7 +951,7 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
defer (gb_temp_arena_memory_end(tmp));
// NOTE(bill): These should be done
for (isize i = 0; i < overload_count; i++) {
for_array(i, procs) {
Type *t = base_type(procs[i]->type);
if (t == t_invalid) {
continue;
@@ -1031,10 +969,9 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
}
if (!skip) {
o->mode = Addressing_Overload;
o->type = t_invalid;
o->overload_count = overload_count;
o->overload_entities = procs;
o->mode = Addressing_ProcGroup;
o->type = t_invalid;
o->proc_group = e;
return nullptr;
}
}
@@ -1550,13 +1487,13 @@ void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) {
}
} else {
gbString xt, yt;
if (x->mode == Addressing_Overload) {
xt = gb_string_make(heap_allocator(), "overloaded procedure");
if (x->mode == Addressing_ProcGroup) {
xt = gb_string_make(heap_allocator(), "procedure group");
} else {
xt = type_to_string(x->type);
}
if (y->mode == Addressing_Overload) {
yt = gb_string_make(heap_allocator(), "overloaded procedure");
if (y->mode == Addressing_ProcGroup) {
yt = gb_string_make(heap_allocator(), "procedure group");
} else {
yt = type_to_string(y->type);
}
@@ -2483,18 +2420,6 @@ bool check_index_value(Checker *c, bool open_range, AstNode *index_value, i64 ma
return true;
}
isize entity_overload_count(Scope *s, String name) {
Entity *e = scope_lookup_entity(s, name);
if (e == nullptr) {
return 0;
}
if (e->kind == Entity_Procedure) {
// NOTE(bill): Overloads are only allowed with the same scope
return multi_map_count(&s->elements, hash_string(e->token.string));
}
return 1;
}
Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_hint) {
ast_node(se, SelectorExpr, node);
@@ -2572,7 +2497,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
}
check_entity_decl(c, entity, nullptr, nullptr);
GB_ASSERT(entity->type != nullptr || entity->kind == Entity_ProcedureGrouping);
GB_ASSERT(entity->type != nullptr || entity->kind == Entity_ProcGroup);
if (is_alias) {
// TODO(bill): Which scope do you search for for an alias?
@@ -2580,46 +2505,26 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
entity_name = entity->token.string;
}
isize overload_count = entity_overload_count(import_scope, entity_name);
bool is_overloaded = overload_count > 1;
bool implicit_is_found = is_entity_implicitly_imported(e, entity);
bool is_not_exported = !is_entity_exported(entity);
if (entity->kind == Entity_ImportName) {
is_not_exported = true;
} else if (implicit_is_found) {
is_not_exported = !is_overloaded;
is_not_exported = true;
}
Entity **procs = nullptr;
if (is_overloaded) {
HashKey key = hash_string(entity_name);
procs = gb_alloc_array(heap_allocator(), Entity *, overload_count);
multi_map_get_all(&import_scope->elements, key, procs);
} else if (entity->kind == Entity_ProcedureGrouping) {
is_overloaded = true;
procs = entity->ProcedureGrouping.entities.data;
overload_count = entity->ProcedureGrouping.entities.count;
}
if (is_overloaded) {
if (is_not_exported && entity->kind == Entity_ProcGroup) {
check_entity_decl(c, entity, nullptr, nullptr);
auto *pge = &entity->ProcGroup;
Array<Entity *> procs = pge->entities;
bool skip = false;
for (isize i = 0; i < overload_count; i++) {
for_array(i, procs) {
Type *t = base_type(procs[i]->type);
if (t == t_invalid) {
continue;
}
// NOTE(bill): Check to see if it's imported
if (is_entity_implicitly_imported(e, procs[i])) {
gb_swap(Entity *, procs[i], procs[overload_count-1]);
overload_count--;
i--; // NOTE(bill): Counteract the post event
continue;
}
Operand x = {};
x.mode = Addressing_Value;
x.type = t;
@@ -2633,16 +2538,12 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
}
if (!skip) {
if (overload_count > 0) {
operand->mode = Addressing_Overload;
operand->type = t_invalid;
operand->expr = node;
operand->overload_count = overload_count;
operand->overload_entities = procs;
return procs[0];
} else {
is_not_exported = true;
}
GB_ASSERT(e != nullptr);
operand->mode = Addressing_ProcGroup;
operand->type = t_invalid;
operand->expr = node;
operand->proc_group = e;
return e;
}
}
@@ -2791,7 +2692,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
operand->builtin_id = cast(BuiltinProcId)entity->Builtin.id;
break;
case Entity_ProcedureGrouping:
case Entity_ProcGroup:
entity->type = t_invalid;
break;
@@ -4439,7 +4340,6 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
return err;
}
CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) {
ast_node(ce, CallExpr, call);
@@ -4469,31 +4369,19 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
check_unpack_arguments(c, nullptr, -1, &operands, ce->args, false);
}
if (operand->mode == Addressing_Overload) {
// GB_ASSERT_MSG(operand->overload_entities != nullptr &&
// operand->overload_count > 0,
// "%p %td", operand->overload_entities, operand->overload_count);
isize overload_count = operand->overload_count;
Entity ** procs = operand->overload_entities;
ValidIndexAndScore *valids = gb_alloc_array(heap_allocator(), ValidIndexAndScore, overload_count);
isize valid_count = 0;
if (operand->mode == Addressing_ProcGroup) {
Array<Entity *> procs = proc_group_entities(c, *operand);
defer (gb_free(heap_allocator(), procs));
ValidIndexAndScore *valids = gb_alloc_array(heap_allocator(), ValidIndexAndScore, procs.count);
isize valid_count = 0;
defer (gb_free(heap_allocator(), valids));
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);
DeclInfo *d = decl_info_of_entity(&c->info, e);
GB_ASSERT(d != nullptr);
check_entity_decl(c, e, d, nullptr);
}
for (isize i = 0; i < overload_count; i++) {
for_array(i, procs) {
Entity *p = procs[i];
check_entity_decl(c, p, nullptr, nullptr);
Type *pt = base_type(p->type);
if (pt != nullptr && is_type_proc(pt)) {
CallArgumentError err = CallArgumentError_None;
@@ -4502,6 +4390,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
defer (c->context = prev_context);
c->context.no_polymorphic_errors = true;
c->context.allow_polymorphic_types = is_type_polymorphic(pt);
err = call_checker(c, call, pt, p, operands, CallArgumentMode_NoErrors, &data);
if (err == CallArgumentError_None) {
@@ -4531,7 +4420,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", expr_name);
error(operand->expr, "No procedures or ambiguous call for procedure group '%s' that match with the given arguments", expr_name);
gb_printf_err("\tGiven argument types -> (");
for_array(i, operands) {
Operand o = operands[i];
@@ -4542,10 +4431,10 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
}
gb_printf_err(")\n");
if (overload_count > 0) {
if (procs.count > 0) {
gb_printf_err("Did you mean to use one of the following:\n");
}
for (isize i = 0; i < overload_count; i++) {
for_array(i, procs) {
Entity *proc = procs[i];
TokenPos pos = proc->token.pos;
Type *t = base_type(proc->type);
@@ -4562,12 +4451,12 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
// 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);
}
if (overload_count > 0) {
if (procs.count > 0) {
gb_printf_err("\n");
}
result_type = t_invalid;
} else if (valid_count > 1) {
error(operand->expr, "Ambiguous procedure call '%s' tha match with the given arguments", expr_name);
error(operand->expr, "Ambiguous procedure group call '%s' that match with the given arguments", expr_name);
gb_printf_err("\tGiven argument types -> (");
for_array(i, operands) {
Operand o = operands[i];
@@ -4606,11 +4495,8 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
proc_type = e->type;
CallArgumentData data = {};
CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data);
if (data.gen_entity != nullptr) {
add_entity_use(c, ident, data.gen_entity);
} else {
add_entity_use(c, ident, e);
}
Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e;
add_entity_use(c, ident, entity_to_use);
return data;
}
} else {
@@ -4623,11 +4509,8 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
Entity *e = entity_of_ident(&c->info, ident);
CallArgumentData data = {};
CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data);
if (data.gen_entity != nullptr) {
add_entity_use(c, ident, data.gen_entity);
} else {
add_entity_use(c, ident, e);
}
Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e;
add_entity_use(c, ident, entity_to_use);
return data;
}
@@ -4953,7 +4836,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
}
Type *proc_type = base_type(operand->type);
if (operand->mode != Addressing_Overload) {
if (operand->mode != Addressing_ProcGroup) {
bool valid_type = (proc_type != nullptr) && is_type_proc(proc_type);
bool valid_mode = is_operand_value(*operand);
if (!valid_type || !valid_mode) {
@@ -5206,8 +5089,8 @@ 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");
case_ast_node(pg, ProcGroup, node);
error(node, "Illegal use of a procedure group");
o->mode = Addressing_Invalid;
case_end;
@@ -6205,7 +6088,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
str = gb_string_appendc(str, "---");
case_end;
case_ast_node(pg, ProcGrouping, node);
case_ast_node(pg, ProcGroup, node);
str = gb_string_appendc(str, "proc[");
for_array(i, pg->args) {
if (i > 0) str = gb_string_appendc(str, ", ");

View File

@@ -30,7 +30,7 @@ void check_stmt_list(Checker *c, Array<AstNode *> stmts, u32 flags) {
if (i+1 < max) {
switch (n->kind) {
case AstNode_ReturnStmt:
error(n, "Statements after this 'return' are never executed");
error(n, "Statements after this 'return' are never execu");
break;
case AstNode_BranchStmt:
@@ -182,7 +182,7 @@ Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) {
return nullptr;
}
if (rhs->type == t_invalid &&
rhs->mode != Addressing_Overload &&
rhs->mode != Addressing_ProcGroup &&
rhs->mode != Addressing_Builtin) {
return nullptr;
}
@@ -203,17 +203,16 @@ Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) {
bool used = false;
if (lhs->mode == Addressing_Invalid ||
(lhs->type == t_invalid && lhs->mode != Addressing_Overload)) {
(lhs->type == t_invalid && lhs->mode != Addressing_ProcGroup)) {
return nullptr;
}
if (rhs->mode == Addressing_Overload) {
isize overload_count = rhs->overload_count;
Entity **procs = rhs->overload_entities;
GB_ASSERT(procs != nullptr && overload_count > 0);
if (rhs->mode == Addressing_ProcGroup) {
Array<Entity *> procs = proc_group_entities(c, *rhs);
GB_ASSERT(procs.count > 0);
// NOTE(bill): These should be done
for (isize i = 0; i < overload_count; i++) {
for_array(i, procs) {
Type *t = base_type(procs[i]->type);
if (t == t_invalid) {
continue;
@@ -232,8 +231,7 @@ Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) {
// HACK TODO(bill): Should the entities be freed as it's technically a leak
rhs->mode = Addressing_Value;
rhs->type = e->type;
rhs->overload_count = 0;
rhs->overload_entities = nullptr;
rhs->proc_group = nullptr;
}
} else {
if (node->kind == AstNode_Ident) {
@@ -1680,176 +1678,177 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_end;
case_ast_node(vd, ValueDecl, node);
if (!vd->is_mutable) {
break;
}
Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count);
isize entity_count = 0;
if (vd->is_mutable) {
Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count);
isize entity_count = 0;
for_array(i, vd->names) {
AstNode *name = vd->names[i];
Entity *entity = nullptr;
if (name->kind != AstNode_Ident) {
error(name, "A variable declaration must be an identifier");
} else {
Token token = name->Ident.token;
String str = token.string;
Entity *found = nullptr;
// NOTE(bill): Ignore assignments to '_'
if (!is_blank_ident(str)) {
found = current_scope_lookup_entity(c->context.scope, str);
}
if (found == nullptr) {
entity = make_entity_variable(c->allocator, c->context.scope, token, nullptr, false);
entity->identifier = name;
AstNode *fl = c->context.foreign_context.curr_library;
if (fl != nullptr) {
GB_ASSERT(fl->kind == AstNode_Ident);
entity->Variable.is_foreign = true;
entity->Variable.foreign_library_ident = fl;
}
for_array(i, vd->names) {
AstNode *name = vd->names[i];
Entity *entity = nullptr;
if (name->kind != AstNode_Ident) {
error(name, "A variable declaration must be an identifier");
} else {
TokenPos pos = found->token.pos;
error(token,
"Redeclaration of '%.*s' in this scope\n"
"\tat %.*s(%td:%td)",
LIT(str), LIT(pos.file), pos.line, pos.column);
entity = found;
}
}
if (entity == nullptr) {
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
}
entity->parent_proc_decl = c->context.curr_proc_decl;
entities[entity_count++] = entity;
}
Token token = name->Ident.token;
String str = token.string;
Entity *found = nullptr;
// NOTE(bill): Ignore assignments to '_'
if (!is_blank_ident(str)) {
found = current_scope_lookup_entity(c->context.scope, str);
}
if (found == nullptr) {
entity = make_entity_variable(c->allocator, c->context.scope, token, nullptr, false);
entity->identifier = name;
Type *init_type = nullptr;
if (vd->type != nullptr) {
init_type = check_type(c, vd->type, nullptr);
if (init_type == nullptr) {
init_type = t_invalid;
} else if (is_type_polymorphic(base_type(init_type))) {
gbString str = type_to_string(init_type);
error(vd->type, "Invalid use of a polymorphic type '%s' in variable declaration", str);
gb_string_free(str);
init_type = t_invalid;
} else if (is_type_empty_union(init_type)) {
gbString str = type_to_string(init_type);
error(vd->type, "An empty union '%s' cannot be instantiated in variable declaration", str);
gb_string_free(str);
init_type = t_invalid;
}
}
// TODO NOTE(bill): This technically checks things multple times
AttributeContext ac = make_attribute_context(c->context.foreign_context.link_prefix);
check_decl_attributes(c, vd->attributes, var_decl_attribute, &ac);
for (isize i = 0; i < entity_count; i++) {
Entity *e = entities[i];
GB_ASSERT(e != nullptr);
if (e->flags & EntityFlag_Visited) {
e->type = t_invalid;
continue;
}
e->flags |= EntityFlag_Visited;
if (e->type == nullptr) {
e->type = init_type;
}
ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
e->Variable.thread_local_model = ac.thread_local_model;
if (ac.link_name.len > 0) {
e->Variable.link_name = ac.link_name;
}
}
check_arity_match(c, vd);
check_init_variables(c, entities, entity_count, vd->values, str_lit("variable declaration"));
for (isize i = 0; i < entity_count; i++) {
Entity *e = entities[i];
if (e->Variable.is_foreign) {
if (vd->values.count > 0) {
error(e->token, "A foreign variable declaration cannot have a default value");
}
String name = e->token.string;
if (e->Variable.link_name.len > 0) {
name = e->Variable.link_name;
}
if (vd->values.count > 0) {
error(e->token, "A foreign variable declaration cannot have a default value");
}
init_entity_foreign_library(c, e);
auto *fp = &c->info.foreigns;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
Type *this_type = base_type(e->type);
Type *other_type = base_type(f->type);
if (!are_types_identical(this_type, other_type)) {
error(e->token,
"Foreign entity '%.*s' previously declared elsewhere with a different type\n"
AstNode *fl = c->context.foreign_context.curr_library;
if (fl != nullptr) {
GB_ASSERT(fl->kind == AstNode_Ident);
entity->Variable.is_foreign = true;
entity->Variable.foreign_library_ident = fl;
}
} else {
TokenPos pos = found->token.pos;
error(token,
"Redeclaration of '%.*s' in this scope\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
LIT(str), LIT(pos.file), pos.line, pos.column);
entity = found;
}
} else {
map_set(fp, key, e);
}
}
add_entity(c, c->context.scope, e->identifier, e);
}
if (vd->is_using != 0) {
Token token = ast_node_token(node);
if (vd->type != nullptr && entity_count > 1) {
error(token, "'using' can only be applied to one variable of the same type");
// TODO(bill): Should a 'continue' happen here?
if (entity == nullptr) {
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
}
entity->parent_proc_decl = c->context.curr_proc_decl;
entities[entity_count++] = entity;
}
for (isize entity_index = 0; entity_index < entity_count; entity_index++) {
Entity *e = entities[entity_index];
if (e == nullptr) {
continue;
Type *init_type = nullptr;
if (vd->type != nullptr) {
init_type = check_type(c, vd->type, nullptr);
if (init_type == nullptr) {
init_type = t_invalid;
} else if (is_type_polymorphic(base_type(init_type))) {
gbString str = type_to_string(init_type);
error(vd->type, "Invalid use of a polymorphic type '%s' in variable declaration", str);
gb_string_free(str);
init_type = t_invalid;
} else if (is_type_empty_union(init_type)) {
gbString str = type_to_string(init_type);
error(vd->type, "An empty union '%s' cannot be instantiated in variable declaration", str);
gb_string_free(str);
init_type = t_invalid;
}
if (e->kind != Entity_Variable) {
continue;
}
bool is_immutable = e->Variable.is_immutable;
String name = e->token.string;
Type *t = base_type(type_deref(e->type));
}
if (is_blank_ident(name)) {
error(token, "'using' cannot be applied variable declared as '_'");
} else if (is_type_struct(t) || is_type_raw_union(t)) {
Scope *scope = scope_of_node(&c->info, t->Struct.node);
for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
uvar->Variable.is_immutable = is_immutable;
Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != nullptr) {
error(token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
return;
// TODO NOTE(bill): This technically checks things multple times
AttributeContext ac = make_attribute_context(c->context.foreign_context.link_prefix);
check_decl_attributes(c, vd->attributes, var_decl_attribute, &ac);
for (isize i = 0; i < entity_count; i++) {
Entity *e = entities[i];
GB_ASSERT(e != nullptr);
if (e->flags & EntityFlag_Visited) {
e->type = t_invalid;
continue;
}
e->flags |= EntityFlag_Visited;
if (e->type == nullptr) {
e->type = init_type;
}
ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
e->Variable.thread_local_model = ac.thread_local_model;
if (ac.link_name.len > 0) {
e->Variable.link_name = ac.link_name;
}
}
check_arity_match(c, vd);
check_init_variables(c, entities, entity_count, vd->values, str_lit("variable declaration"));
for (isize i = 0; i < entity_count; i++) {
Entity *e = entities[i];
if (e->Variable.is_foreign) {
if (vd->values.count > 0) {
error(e->token, "A foreign variable declaration cannot have a default value");
}
String name = e->token.string;
if (e->Variable.link_name.len > 0) {
name = e->Variable.link_name;
}
if (vd->values.count > 0) {
error(e->token, "A foreign variable declaration cannot have a default value");
}
init_entity_foreign_library(c, e);
auto *fp = &c->info.foreigns;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
Type *this_type = base_type(e->type);
Type *other_type = base_type(f->type);
if (!are_types_identical(this_type, other_type)) {
error(e->token,
"Foreign entity '%.*s' previously declared elsewhere with a different type\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else {
map_set(fp, key, e);
}
}
add_entity(c, c->context.scope, e->identifier, e);
}
if (vd->is_using != 0) {
Token token = ast_node_token(node);
if (vd->type != nullptr && entity_count > 1) {
error(token, "'using' can only be applied to one variable of the same type");
// TODO(bill): Should a 'continue' happen here?
}
for (isize entity_index = 0; entity_index < entity_count; entity_index++) {
Entity *e = entities[entity_index];
if (e == nullptr) {
continue;
}
if (e->kind != Entity_Variable) {
continue;
}
bool is_immutable = e->Variable.is_immutable;
String name = e->token.string;
Type *t = base_type(type_deref(e->type));
if (is_blank_ident(name)) {
error(token, "'using' cannot be applied variable declared as '_'");
} else if (is_type_struct(t) || is_type_raw_union(t)) {
Scope *scope = scope_of_node(&c->info, t->Struct.node);
for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
uvar->Variable.is_immutable = is_immutable;
Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != nullptr) {
error(token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
return;
}
}
}
} else {
// NOTE(bill): skip the rest to remove extra errors
error(token, "'using' can only be applied to variables of type struct or raw_union");
return;
}
} else {
// NOTE(bill): skip the rest to remove extra errors
error(token, "'using' can only be applied to variables of type struct or raw_union");
return;
}
}
} else {
// constant value declarations
}
case_end;
}

View File

@@ -120,7 +120,7 @@ enum AddressingMode {
Addressing_Constant, // constant
Addressing_Type, // type
Addressing_Builtin, // built-in procedure
Addressing_Overload, // overloaded procedure
Addressing_ProcGroup, // procedure group (overloaded procedure)
Addressing_MapIndex, // map index expression -
// lhs: acts like a Variable
// rhs: acts like OptionalOk
@@ -138,8 +138,7 @@ struct Operand {
ExactValue value;
AstNode * expr;
BuiltinProcId builtin_id;
isize overload_count;
Entity ** overload_entities;
Entity * proc_group;
};
struct TypeAndValue {
@@ -166,6 +165,8 @@ bool is_operand_undef(Operand o) {
return o.mode == Addressing_Value && o.type == t_untyped_undef;
}
struct BlockLabel {
String name;
AstNode *label; // AstNode_Label;
@@ -780,28 +781,10 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
HashKey key = hash_string(name);
Entity **found = map_get(&s->elements, key);
#ifndef DISABLE_PROCEDURE_OVERLOADING
// IMPORTANT NOTE(bill): Procedure overloading code
Entity *prev = nullptr;
if (found) {
prev = *found;
if (prev->kind != Entity_Procedure ||
entity->kind != Entity_Procedure) {
return prev;
}
}
if (prev != nullptr && entity->kind == Entity_Procedure) {
multi_map_insert(&s->elements, key, entity);
} else {
map_set(&s->elements, key, entity);
}
#else
if (found) {
return *found;
}
map_set(&s->elements, key, entity);
#endif
if (entity->scope == nullptr) {
entity->scope = s;
}
@@ -1620,6 +1603,18 @@ Type *find_core_type(Checker *c, String name) {
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type);
Array<Entity *> proc_group_entities(Checker *c, Operand o) {
Array<Entity *> procs = {};
if (o.mode == Addressing_ProcGroup) {
GB_ASSERT(o.proc_group != nullptr);
if (o.proc_group->kind == Entity_ProcGroup) {
check_entity_decl(c, o.proc_group, nullptr, nullptr);
return o.proc_group->ProcGroup.entities;
}
}
return procs;
}
void init_preload(Checker *c) {
if (t_type_info == nullptr) {
Entity *type_info_entity = find_core_entity(c, str_lit("Type_Info"));
@@ -1736,118 +1731,6 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes);
void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws);
void check_delayed_file_import_entity(Checker *c, AstNode *decl);
bool check_is_entity_overloaded(Entity *e) {
if (e->kind != Entity_Procedure) {
return false;
}
Scope *s = e->scope;
HashKey key = hash_string(e->token.string);
isize overload_count = multi_map_count(&s->elements, key);
return overload_count > 1;
}
void check_procedure_overloading(Checker *c, Entity *e) {
GB_ASSERT(e->kind == Entity_Procedure);
if (e->type == t_invalid) {
return;
}
if (e->Procedure.overload_kind != Overload_Unknown) {
// NOTE(bill): The overloading has already been handled
return;
}
// NOTE(bill): Procedures call only overload other procedures in the same scope
String name = e->token.string;
HashKey key = hash_string(name);
Scope *s = e->scope;
isize overload_count = multi_map_count(&s->elements, key);
GB_ASSERT(overload_count >= 1);
if (overload_count == 1) {
e->Procedure.overload_kind = Overload_No;
return;
}
GB_ASSERT(overload_count > 1);
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
Entity **procs = gb_alloc_array(c->tmp_allocator, Entity *, overload_count);
multi_map_get_all(&s->elements, key, procs);
for (isize j = 0; j < overload_count; j++) {
Entity *p = procs[j];
if (p->type == t_invalid) {
// NOTE(bill): This invalid overload has already been handled
continue;
}
String name = p->token.string;
GB_ASSERT(p->kind == Entity_Procedure);
for (isize k = j+1; k < overload_count; k++) {
Entity *q = procs[k];
GB_ASSERT(p != q);
bool is_invalid = false;
GB_ASSERT(q->kind == Entity_Procedure);
TokenPos pos = q->token.pos;
if (q->type == nullptr || q->type == t_invalid) {
continue;
}
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
switch (kind) {
case ProcOverload_Identical:
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
is_invalid = true;
break;
// case ProcOverload_CallingConvention:
// error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
// is_invalid = true;
// break;
case ProcOverload_ParamVariadic:
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
is_invalid = true;
break;
case ProcOverload_ResultCount:
case ProcOverload_ResultTypes:
error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in this scope", LIT(name));
is_invalid = true;
break;
case ProcOverload_Polymorphic:
#if 0
error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in this scope which is not allowed", LIT(name));
is_invalid = true;
#endif
break;
case ProcOverload_ParamCount:
case ProcOverload_ParamTypes:
// This is okay :)
break;
}
if (is_invalid) {
gb_printf_err("\tprevious procedure at %.*s(%td:%td)\n", LIT(pos.file), pos.line, pos.column);
q->type = t_invalid;
}
}
}
for (isize j = 0; j < overload_count; j++) {
Entity *p = procs[j];
if (p->type != t_invalid) {
p->Procedure.overload_kind = Overload_Yes;
}
}
gb_temp_arena_memory_end(tmp);
}
struct AttributeContext {
String link_name;
String link_prefix;
@@ -2259,11 +2142,11 @@ 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);
} else if (init->kind == AstNode_ProcGroup) {
ast_node(pg, ProcGroup, init);
e = make_entity_proc_group(c->allocator, d->scope, token, nullptr);
if (fl != nullptr) {
error(name, "Procedure groupings are not allowed within a foreign block");
error(name, "Procedure groups are not allowed within a foreign block");
}
d->init_expr = init;
} else {
@@ -2447,15 +2330,6 @@ void check_all_global_entities(Checker *c) {
init_preload(c);
}
}
for_array(i, c->info.entities.entries) {
auto *entry = &c->info.entities.entries[i];
Entity *e = cast(Entity *)entry->key.ptr;
if (e->kind != Entity_Procedure) {
continue;
}
check_procedure_overloading(c, e);
}
}

View File

@@ -10,7 +10,7 @@ struct DeclInfo;
ENTITY_KIND(Variable) \
ENTITY_KIND(TypeName) \
ENTITY_KIND(Procedure) \
ENTITY_KIND(ProcedureGrouping) \
ENTITY_KIND(ProcGroup) \
ENTITY_KIND(Builtin) \
ENTITY_KIND(Alias) \
ENTITY_KIND(ImportName) \
@@ -110,7 +110,7 @@ struct Entity {
} Procedure;
struct {
Array<Entity *> entities;
} ProcedureGrouping;
} ProcGroup;
struct {
i32 id;
} Builtin;
@@ -248,8 +248,8 @@ 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);
Entity *make_entity_proc_group(gbAllocator a, Scope *scope, Token token, Type *type) {
Entity *entity = alloc_entity(a, Entity_ProcGroup, scope, token, type);
return entity;
}

View File

@@ -3620,7 +3620,7 @@ String ir_mangle_name(irGen *s, String path, Entity *e) {
isize base_len = ext-1-base;
isize max_len = base_len + 1 + 1 + 10 + 1 + name.len;
bool require_suffix_id = check_is_entity_overloaded(e) || is_type_polymorphic(e->type);
bool require_suffix_id = is_type_polymorphic(e->type);
if (require_suffix_id) {
max_len += 21;
}
@@ -8304,19 +8304,22 @@ void ir_gen_tree(irGen *s) {
}
for_array(i, info->entities.entries) {
auto *entry = &info->entities.entries[i];
Entity *e = cast(Entity *)entry->key.ptr;
String name = e->token.string;
DeclInfo *decl = entry->value;
Scope *scope = e->scope;
auto * entry = &info->entities.entries[i];
Entity * e = cast(Entity *)entry->key.ptr;
String name = e->token.string;
DeclInfo *decl = entry->value;
Scope * scope = e->scope;
if (!scope->is_file) {
continue;
}
if (e->kind == Entity_Variable || e->kind == Entity_ProcedureGrouping) {
switch (e->kind) {
case Entity_Variable:
// NOTE(bill): Handled above as it requires a specific load order
continue;
case Entity_ProcGroup:
continue;
}
bool polymorphic_struct = false;
@@ -8341,8 +8344,6 @@ void ir_gen_tree(irGen *s) {
} else {
name = ir_mangle_name(s, e->token.pos.file, e);
}
} else if (check_is_entity_overloaded(e)) {
name = ir_mangle_name(s, e->token.pos.file, e);
}
ir_add_entity_name(m, e, name);
@@ -8373,7 +8374,7 @@ void ir_gen_tree(irGen *s) {
ir_module_add_value(m, e, p);
HashKey hash_name = hash_string(name);
if (map_get(&m->members, hash_name) == nullptr) {
multi_map_insert(&m->members, hash_name, p);
map_set(&m->members, hash_name, p);
}
break;
}

View File

@@ -1,5 +1,4 @@
#define ALLOW_ARRAY_PROGRAMMING
// #define DISABLE_PROCEDURE_OVERLOADING
// #define NO_ARRAY_BOUNDS_CHECK

View File

@@ -2,6 +2,8 @@
// with the use of the `multi_*` procedures.
// TODO(bill): I should probably allow the `multi_map_*` stuff to be #ifdefed out
#define MAP_ENABLE_MULTI_MAP 1
#ifndef MAP_UTIL_STUFF
#define MAP_UTIL_STUFF
// NOTE(bill): This util stuff is the same for every `Map`
@@ -110,6 +112,7 @@ template <typename T> void map_clear (Map<T> *h);
template <typename T> void map_grow (Map<T> *h);
template <typename T> void map_rehash (Map<T> *h, isize new_count);
#if MAP_ENABLE_MULTI_MAP
// Mutlivalued map procedure
template <typename T> MapEntry<T> * multi_map_find_first(Map<T> *h, HashKey key);
template <typename T> MapEntry<T> * multi_map_find_next (Map<T> *h, MapEntry<T> *e);
@@ -119,7 +122,7 @@ template <typename T> void multi_map_get_all (Map<T> *h, HashKey key, T *item
template <typename T> void multi_map_insert (Map<T> *h, HashKey key, T const &value);
template <typename T> void multi_map_remove (Map<T> *h, HashKey key, MapEntry<T> *e);
template <typename T> void multi_map_remove_all(Map<T> *h, HashKey key);
#endif
template <typename T>
gb_inline void map_init(Map<T> *h, gbAllocator a, isize capacity) {
@@ -291,7 +294,7 @@ gb_inline void map_clear(Map<T> *h) {
}
#if 1
#if MAP_ENABLE_MULTI_MAP
template <typename T>
MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey key) {
isize i = map__find(h, key).entry_index;

View File

@@ -164,7 +164,7 @@ Array<AstNode *> make_ast_node_array(AstFile *f, isize init_capacity = 8) {
Token token; \
AstNode *expr; \
}) \
AST_NODE_KIND(ProcGrouping, "procedure grouping", struct { \
AST_NODE_KIND(ProcGroup, "procedure group", struct { \
Token token; \
Token open; \
Token close; \
@@ -540,7 +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_ProcGroup: return node->ProcGroup.token;
case AstNode_ProcLit: return ast_node_token(node->ProcLit.type);
case AstNode_CompoundLit:
if (node->CompoundLit.type != nullptr) {
@@ -669,8 +669,8 @@ 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);
case AstNode_ProcGroup:
n->ProcGroup.args = clone_ast_node_array(a, n->ProcGroup.args);
break;
case AstNode_ProcLit:
n->ProcLit.type = clone_ast_node(a, n->ProcLit.type);
@@ -1121,12 +1121,12 @@ 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;
AstNode *ast_proc_group(AstFile *f, Token token, Token open, Token close, Array<AstNode *> args) {
AstNode *result = make_ast_node(f, AstNode_ProcGroup);
result->ProcGroup.token = token;
result->ProcGroup.open = open;
result->ProcGroup.close = close;
result->ProcGroup.args = args;
return result;
}
@@ -2266,11 +2266,11 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
return expr;
} break;
// Parse Procedure Type or Literal or Grouping
// Parse Procedure Type or Literal or Group
case Token_proc: {
Token token = expect_token(f, Token_proc);
if (f->curr_token.kind == Token_OpenBracket) { // ProcGrouping
if (f->curr_token.kind == Token_OpenBracket) { // ProcGroup
Token open = expect_token(f, Token_OpenBracket);
Array<AstNode *> args = {};
@@ -2289,10 +2289,10 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
Token close = expect_token(f, Token_CloseBracket);
if (args.count == 0) {
syntax_error(token, "Expected a least 1 argument in a procedure grouping");
syntax_error(token, "Expected a least 1 argument in a procedure group");
}
return ast_proc_grouping(f, token, open, close, args);
return ast_proc_group(f, token, open, close, args);
}
AstNode *type = parse_proc_type(f, token);