mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
More declaration differentiation in semantic stage e.g. make only variables and constants
This commit is contained in:
+3
-19
@@ -11,8 +11,7 @@ import {
|
|||||||
win32 "sys/windows.odin";
|
win32 "sys/windows.odin";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Thing = enum f64 {
|
||||||
type Thing enum f64 {
|
|
||||||
_, // Ignore first value
|
_, // Ignore first value
|
||||||
A = 1<<(10*iota),
|
A = 1<<(10*iota),
|
||||||
B,
|
B,
|
||||||
@@ -20,21 +19,6 @@ type Thing enum f64 {
|
|||||||
D,
|
D,
|
||||||
};
|
};
|
||||||
|
|
||||||
proc main() {
|
const main = proc() {
|
||||||
var ti = type_info(Thing);
|
fmt.println(Thing.A, Thing.B, Thing.C, Thing.D);
|
||||||
match type info : type_info_base(ti) {
|
|
||||||
case Type_Info.Enum:
|
|
||||||
for var i = 0; i < info.names.count; i++ {
|
|
||||||
if i > 0 {
|
|
||||||
fmt.print(", ");
|
|
||||||
}
|
|
||||||
fmt.print(info.names[i]);
|
|
||||||
}
|
|
||||||
fmt.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
var x Thing = Thing.A;
|
|
||||||
|
|
||||||
fmt.println(x, Thing.B, Thing.C, Thing.D);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-9
@@ -883,6 +883,9 @@ void add_type_info_type(Checker *c, Type *t) {
|
|||||||
|
|
||||||
case Type_Record: {
|
case Type_Record: {
|
||||||
switch (bt->Record.kind) {
|
switch (bt->Record.kind) {
|
||||||
|
case TypeRecord_Enum:
|
||||||
|
add_type_info_type(c, bt->Record.enum_base_type);
|
||||||
|
break;
|
||||||
case TypeRecord_Union:
|
case TypeRecord_Union:
|
||||||
add_type_info_type(c, t_int);
|
add_type_info_type(c, t_int);
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
@@ -1072,13 +1075,13 @@ void init_preload(Checker *c) {
|
|||||||
c->done_preload = true;
|
c->done_preload = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init);
|
bool check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init);
|
||||||
|
|
||||||
#include "expr.c"
|
#include "expr.c"
|
||||||
#include "decl.c"
|
#include "decl.c"
|
||||||
#include "stmt.c"
|
#include "stmt.c"
|
||||||
|
|
||||||
void check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init) {
|
bool check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init) {
|
||||||
isize lhs = s->names.count;
|
isize lhs = s->names.count;
|
||||||
isize rhs = s->values.count;
|
isize rhs = s->values.count;
|
||||||
if (init != NULL) {
|
if (init != NULL) {
|
||||||
@@ -1088,6 +1091,7 @@ void check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init)
|
|||||||
if (init == NULL && rhs == 0) {
|
if (init == NULL && rhs == 0) {
|
||||||
if (s->type == NULL) {
|
if (s->type == NULL) {
|
||||||
error_node(s->names.e[0], "Missing type or initial expression");
|
error_node(s->names.e[0], "Missing type or initial expression");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} else if (lhs < rhs) {
|
} else if (lhs < rhs) {
|
||||||
if (lhs < s->values.count) {
|
if (lhs < s->values.count) {
|
||||||
@@ -1098,12 +1102,16 @@ void check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init)
|
|||||||
} else {
|
} else {
|
||||||
error_node(s->names.e[0], "Extra initial expression");
|
error_node(s->names.e[0], "Extra initial expression");
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
} else if (lhs > rhs && (init != NULL || rhs != 1)) {
|
} else if (lhs > rhs && (init != NULL || rhs != 1)) {
|
||||||
AstNode *n = s->names.e[rhs];
|
AstNode *n = s->names.e[rhs];
|
||||||
gbString str = expr_to_string(n);
|
gbString str = expr_to_string(n);
|
||||||
error_node(n, "Missing expression for `%s`", str);
|
error_node(n, "Missing expression for `%s`", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1234,19 +1242,34 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue v = make_exact_value_integer(iota);
|
|
||||||
Entity *e = make_entity_constant(c->allocator, parent_scope, name->Ident, NULL, v);
|
|
||||||
e->identifier = name;
|
|
||||||
|
|
||||||
AstNode *init = NULL;
|
AstNode *init = NULL;
|
||||||
if (i < prev_spec->values.count) {
|
if (i < prev_spec->values.count) {
|
||||||
init = prev_spec->values.e[i];
|
init = prev_spec->values.e[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclInfo *di = make_declaration_info(c->allocator, e->scope);
|
DeclInfo *d = make_declaration_info(c->allocator, parent_scope);
|
||||||
di->type_expr = prev_spec->type;
|
Entity *e = NULL;
|
||||||
di->init_expr = init;
|
|
||||||
add_entity_and_decl_info(c, name, e, di);
|
ExactValue v_iota = make_exact_value_integer(iota);
|
||||||
|
|
||||||
|
AstNode *up_init = unparen_expr(init);
|
||||||
|
if (init != NULL && is_ast_node_type(up_init)) {
|
||||||
|
e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
|
||||||
|
d->type_expr = init;
|
||||||
|
d->init_expr = init;
|
||||||
|
} else if (init != NULL && up_init->kind == AstNode_ProcLit) {
|
||||||
|
e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
|
||||||
|
d->proc_decl = init;
|
||||||
|
} else {
|
||||||
|
e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, v_iota);
|
||||||
|
d->type_expr = prev_spec->type;
|
||||||
|
d->init_expr = init;
|
||||||
|
}
|
||||||
|
GB_ASSERT(e != NULL);
|
||||||
|
e->identifier = name;
|
||||||
|
|
||||||
|
add_entity_and_decl_info(c, name, e, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
check_arity_match(c, vs, prev_spec);
|
check_arity_match(c, vs, prev_spec);
|
||||||
@@ -1263,6 +1286,7 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
|
|||||||
|
|
||||||
Entity *e = make_entity_type_name(c->allocator, parent_scope, *n, NULL);
|
Entity *e = make_entity_type_name(c->allocator, parent_scope, *n, NULL);
|
||||||
e->identifier = ts->name;
|
e->identifier = ts->name;
|
||||||
|
|
||||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||||
d->type_expr = ts->type;
|
d->type_expr = ts->type;
|
||||||
d->init_expr = ts->type;
|
d->init_expr = ts->type;
|
||||||
|
|||||||
+205
-87
@@ -248,7 +248,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
|||||||
}
|
}
|
||||||
e->flags |= EntityFlag_Visited;
|
e->flags |= EntityFlag_Visited;
|
||||||
|
|
||||||
GB_ASSERT(c->context.iota.kind == ExactValue_Invalid);
|
|
||||||
c->context.iota = e->Constant.value;
|
c->context.iota = e->Constant.value;
|
||||||
e->Constant.value = (ExactValue){0};
|
e->Constant.value = (ExactValue){0};
|
||||||
|
|
||||||
@@ -267,7 +266,18 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
|||||||
|
|
||||||
Operand operand = {0};
|
Operand operand = {0};
|
||||||
if (init != NULL) {
|
if (init != NULL) {
|
||||||
check_expr(c, &operand, init);
|
check_expr_or_type(c, &operand, init);
|
||||||
|
}
|
||||||
|
if (operand.mode == Addressing_Type) {
|
||||||
|
c->context.iota = (ExactValue){0};
|
||||||
|
|
||||||
|
e->Constant.value = (ExactValue){0};
|
||||||
|
e->kind = Entity_TypeName;
|
||||||
|
|
||||||
|
DeclInfo *d = c->context.decl;
|
||||||
|
d->type_expr = d->init_expr;
|
||||||
|
check_type_decl(c, e, d->type_expr, named_type);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_init_constant(c, e, &operand);
|
check_init_constant(c, e, &operand);
|
||||||
@@ -319,113 +329,221 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
|
|
||||||
Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
|
Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
|
||||||
e->type = proc_type;
|
e->type = proc_type;
|
||||||
ast_node(pd, ProcDecl, d->proc_decl);
|
if (d->proc_decl->kind == AstNode_ProcDecl) {
|
||||||
|
ast_node(pd, ProcDecl, d->proc_decl);
|
||||||
|
|
||||||
check_open_scope(c, pd->type);
|
check_open_scope(c, pd->type);
|
||||||
check_procedure_type(c, proc_type, pd->type);
|
check_procedure_type(c, proc_type, pd->type);
|
||||||
|
|
||||||
bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
|
bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
|
||||||
bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
|
bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
|
||||||
bool is_export = (pd->tags & ProcTag_export) != 0;
|
bool is_export = (pd->tags & ProcTag_export) != 0;
|
||||||
bool is_inline = (pd->tags & ProcTag_inline) != 0;
|
bool is_inline = (pd->tags & ProcTag_inline) != 0;
|
||||||
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
|
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
|
||||||
|
|
||||||
if ((d->scope->is_file || d->scope->is_global) &&
|
if ((d->scope->is_file || d->scope->is_global) &&
|
||||||
str_eq(e->token.string, str_lit("main"))) {
|
str_eq(e->token.string, str_lit("main"))) {
|
||||||
if (proc_type != NULL) {
|
if (proc_type != NULL) {
|
||||||
TypeProc *pt = &proc_type->Proc;
|
TypeProc *pt = &proc_type->Proc;
|
||||||
if (pt->param_count != 0 ||
|
if (pt->param_count != 0 ||
|
||||||
pt->result_count != 0) {
|
pt->result_count != 0) {
|
||||||
gbString str = type_to_string(proc_type);
|
gbString str = type_to_string(proc_type);
|
||||||
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
|
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (is_inline && is_no_inline) {
|
if (is_inline && is_no_inline) {
|
||||||
error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
|
error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_foreign && is_link_name) {
|
if (is_foreign && is_link_name) {
|
||||||
error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
|
error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
|
||||||
} else if (is_foreign && is_export) {
|
} else if (is_foreign && is_export) {
|
||||||
error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
|
error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (pd->body != NULL) {
|
if (pd->body != NULL) {
|
||||||
|
if (is_foreign) {
|
||||||
|
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc_type->Proc.calling_convention != ProcCC_Odin) {
|
||||||
|
error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
|
||||||
|
proc_type->Proc.calling_convention = ProcCC_Odin;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->scope = c->context.scope;
|
||||||
|
|
||||||
|
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
|
||||||
|
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
|
||||||
|
}
|
||||||
|
|
||||||
if (is_foreign) {
|
if (is_foreign) {
|
||||||
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proc_type->Proc.calling_convention != ProcCC_Odin) {
|
|
||||||
error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
|
|
||||||
proc_type->Proc.calling_convention = ProcCC_Odin;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->scope = c->context.scope;
|
|
||||||
|
|
||||||
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
|
|
||||||
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_foreign) {
|
|
||||||
MapEntity *fp = &c->info.foreign_procs;
|
|
||||||
AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
|
|
||||||
String name = proc_decl->name->Ident.string;
|
|
||||||
if (proc_decl->foreign_name.len > 0) {
|
|
||||||
name = proc_decl->foreign_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
e->Procedure.is_foreign = true;
|
|
||||||
e->Procedure.foreign_name = name;
|
|
||||||
|
|
||||||
HashKey key = hash_string(name);
|
|
||||||
Entity **found = map_entity_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_signatures_similar_enough(this_type, other_type)) {
|
|
||||||
error_node(d->proc_decl,
|
|
||||||
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
|
|
||||||
"\tat %.*s(%td:%td)",
|
|
||||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
map_entity_set(fp, key, e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
String name = e->token.string;
|
|
||||||
if (is_link_name) {
|
|
||||||
AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
|
|
||||||
name = proc_decl->link_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_link_name || is_export) {
|
|
||||||
MapEntity *fp = &c->info.foreign_procs;
|
MapEntity *fp = &c->info.foreign_procs;
|
||||||
|
AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
|
||||||
|
String name = proc_decl->name->Ident.string;
|
||||||
|
if (proc_decl->foreign_name.len > 0) {
|
||||||
|
name = proc_decl->foreign_name;
|
||||||
|
}
|
||||||
|
|
||||||
e->Procedure.link_name = name;
|
e->Procedure.is_foreign = true;
|
||||||
|
e->Procedure.foreign_name = name;
|
||||||
|
|
||||||
HashKey key = hash_string(name);
|
HashKey key = hash_string(name);
|
||||||
Entity **found = map_entity_get(fp, key);
|
Entity **found = map_entity_get(fp, key);
|
||||||
if (found) {
|
if (found) {
|
||||||
Entity *f = *found;
|
Entity *f = *found;
|
||||||
TokenPos pos = f->token.pos;
|
TokenPos pos = f->token.pos;
|
||||||
// TODO(bill): Better error message?
|
Type *this_type = base_type(e->type);
|
||||||
error_node(d->proc_decl,
|
Type *other_type = base_type(f->type);
|
||||||
"Non unique linking name for procedure `%.*s`\n"
|
if (!are_signatures_similar_enough(this_type, other_type)) {
|
||||||
"\tother at %.*s(%td:%td)",
|
error_node(d->proc_decl,
|
||||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
|
||||||
|
"\tat %.*s(%td:%td)",
|
||||||
|
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
map_entity_set(fp, key, e);
|
map_entity_set(fp, key, e);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
}
|
String name = e->token.string;
|
||||||
|
if (is_link_name) {
|
||||||
|
AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
|
||||||
|
name = proc_decl->link_name;
|
||||||
|
}
|
||||||
|
|
||||||
check_close_scope(c);
|
if (is_link_name || is_export) {
|
||||||
|
MapEntity *fp = &c->info.foreign_procs;
|
||||||
|
|
||||||
|
e->Procedure.link_name = name;
|
||||||
|
|
||||||
|
HashKey key = hash_string(name);
|
||||||
|
Entity **found = map_entity_get(fp, key);
|
||||||
|
if (found) {
|
||||||
|
Entity *f = *found;
|
||||||
|
TokenPos pos = f->token.pos;
|
||||||
|
// TODO(bill): Better error message?
|
||||||
|
error_node(d->proc_decl,
|
||||||
|
"Non unique linking name for procedure `%.*s`\n"
|
||||||
|
"\tother at %.*s(%td:%td)",
|
||||||
|
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||||
|
} else {
|
||||||
|
map_entity_set(fp, key, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check_close_scope(c);
|
||||||
|
} else if (d->proc_decl->kind == AstNode_ProcLit) {
|
||||||
|
ast_node(pd, ProcLit, d->proc_decl);
|
||||||
|
|
||||||
|
check_open_scope(c, pd->type);
|
||||||
|
check_procedure_type(c, proc_type, pd->type);
|
||||||
|
|
||||||
|
bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
|
||||||
|
bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
|
||||||
|
bool is_export = (pd->tags & ProcTag_export) != 0;
|
||||||
|
bool is_inline = (pd->tags & ProcTag_inline) != 0;
|
||||||
|
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
|
||||||
|
|
||||||
|
if ((d->scope->is_file || d->scope->is_global) &&
|
||||||
|
str_eq(e->token.string, str_lit("main"))) {
|
||||||
|
if (proc_type != NULL) {
|
||||||
|
TypeProc *pt = &proc_type->Proc;
|
||||||
|
if (pt->param_count != 0 ||
|
||||||
|
pt->result_count != 0) {
|
||||||
|
gbString str = type_to_string(proc_type);
|
||||||
|
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
|
||||||
|
gb_string_free(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_inline && is_no_inline) {
|
||||||
|
error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_foreign && is_link_name) {
|
||||||
|
error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
|
||||||
|
} else if (is_foreign && is_export) {
|
||||||
|
error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (pd->body != NULL) {
|
||||||
|
if (is_foreign) {
|
||||||
|
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc_type->Proc.calling_convention != ProcCC_Odin) {
|
||||||
|
error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
|
||||||
|
proc_type->Proc.calling_convention = ProcCC_Odin;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->scope = c->context.scope;
|
||||||
|
|
||||||
|
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
|
||||||
|
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_foreign) {
|
||||||
|
MapEntity *fp = &c->info.foreign_procs;
|
||||||
|
String name = e->token.string;
|
||||||
|
if (pd->foreign_name.len > 0) {
|
||||||
|
name = pd->foreign_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
e->Procedure.is_foreign = true;
|
||||||
|
e->Procedure.foreign_name = name;
|
||||||
|
|
||||||
|
HashKey key = hash_string(name);
|
||||||
|
Entity **found = map_entity_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_signatures_similar_enough(this_type, other_type)) {
|
||||||
|
error_node(d->proc_decl,
|
||||||
|
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
|
||||||
|
"\tat %.*s(%td:%td)",
|
||||||
|
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
map_entity_set(fp, key, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String name = e->token.string;
|
||||||
|
if (is_link_name) {
|
||||||
|
name = pd->link_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_link_name || is_export) {
|
||||||
|
MapEntity *fp = &c->info.foreign_procs;
|
||||||
|
|
||||||
|
e->Procedure.link_name = name;
|
||||||
|
|
||||||
|
HashKey key = hash_string(name);
|
||||||
|
Entity **found = map_entity_get(fp, key);
|
||||||
|
if (found) {
|
||||||
|
Entity *f = *found;
|
||||||
|
TokenPos pos = f->token.pos;
|
||||||
|
// TODO(bill): Better error message?
|
||||||
|
error_node(d->proc_decl,
|
||||||
|
"Non unique linking name for procedure `%.*s`\n"
|
||||||
|
"\tother at %.*s(%td:%td)",
|
||||||
|
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||||
|
} else {
|
||||||
|
map_entity_set(fp, key, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check_close_scope(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) {
|
void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) {
|
||||||
|
|||||||
+25
-11
@@ -113,21 +113,35 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue v = make_exact_value_integer(iota);
|
|
||||||
Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v);
|
|
||||||
e->identifier = name;
|
|
||||||
|
|
||||||
AstNode *init = NULL;
|
AstNode *init = NULL;
|
||||||
if (i < last->values.count) {
|
if (i < vs->values.count) {
|
||||||
init = last->values.e[i];
|
init = vs->values.e[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclInfo *di = make_declaration_info(c->allocator, e->scope);
|
DeclInfo *d = make_declaration_info(c->allocator, c->context.scope);
|
||||||
di->type_expr = last->type;
|
Entity *e = NULL;
|
||||||
di->init_expr = init;
|
|
||||||
add_entity_and_decl_info(c, name, e, di);
|
|
||||||
|
|
||||||
DelayedEntity delay = {name, e, di};
|
ExactValue v_iota = make_exact_value_integer(iota);
|
||||||
|
|
||||||
|
AstNode *up_init = unparen_expr(init);
|
||||||
|
if (init != NULL && is_ast_node_type(up_init)) {
|
||||||
|
e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
|
||||||
|
d->type_expr = init;
|
||||||
|
d->init_expr = init;
|
||||||
|
} else if (init != NULL && up_init->kind == AstNode_ProcLit) {
|
||||||
|
e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
|
||||||
|
d->proc_decl = init;
|
||||||
|
} else {
|
||||||
|
e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, v_iota);
|
||||||
|
d->type_expr = vs->type;
|
||||||
|
d->init_expr = init;
|
||||||
|
}
|
||||||
|
GB_ASSERT(e != NULL);
|
||||||
|
e->identifier = name;
|
||||||
|
|
||||||
|
add_entity_and_decl_info(c, name, e, d);
|
||||||
|
|
||||||
|
DelayedEntity delay = {name, e, d};
|
||||||
array_add(delayed_entities, delay);
|
array_add(delayed_entities, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-16
@@ -1740,31 +1740,25 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
|||||||
|
|
||||||
// Parse Procedure Type or Literal
|
// Parse Procedure Type or Literal
|
||||||
case Token_proc: {
|
case Token_proc: {
|
||||||
|
Token token = f->curr_token;
|
||||||
String foreign_name = {0};
|
String foreign_name = {0};
|
||||||
String link_name = {0};
|
String link_name = {0};
|
||||||
AstNode *curr_proc = f->curr_proc;
|
|
||||||
AstNode *type = parse_proc_type(f, &foreign_name, &link_name);
|
AstNode *type = parse_proc_type(f, &foreign_name, &link_name);
|
||||||
f->curr_proc = type;
|
|
||||||
|
|
||||||
if (type->ProcType.tags & ProcTag_foreign) {
|
|
||||||
syntax_error(f->curr_token, "#foreign cannot be applied to procedure literals");
|
|
||||||
}
|
|
||||||
if (type->ProcType.tags & ProcTag_export) {
|
|
||||||
syntax_error(f->curr_token, "#export cannot be applied to procedure literals");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f->curr_token.kind == Token_OpenBrace) {
|
if (f->curr_token.kind == Token_OpenBrace) {
|
||||||
AstNode *body;
|
u64 tags = type->ProcType.tags;
|
||||||
|
|
||||||
if ((type->ProcType.tags & ProcTag_foreign) != 0) {
|
if ((tags & ProcTag_foreign) != 0) {
|
||||||
syntax_error(f->curr_token, "A procedure tagged as `#foreign` cannot have a body");
|
syntax_error(token, "A procedure tagged as `#foreign` cannot have a body");
|
||||||
}
|
}
|
||||||
|
AstNode *curr_proc = f->curr_proc;
|
||||||
|
f->curr_proc = type;
|
||||||
|
AstNode *body = parse_body(f);
|
||||||
|
f->curr_proc = curr_proc;
|
||||||
|
|
||||||
body = parse_body(f);
|
return make_proc_lit(f, type, body, tags, foreign_name, link_name);
|
||||||
type = make_proc_lit(f, type, body, type->ProcType.tags, foreign_name, link_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f->curr_proc = curr_proc;
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1941,7 +1935,15 @@ AstNode *parse_type(AstFile *f);
|
|||||||
|
|
||||||
AstNode *parse_unary_expr(AstFile *f, bool lhs) {
|
AstNode *parse_unary_expr(AstFile *f, bool lhs) {
|
||||||
switch (f->curr_token.kind) {
|
switch (f->curr_token.kind) {
|
||||||
case Token_Pointer:
|
case Token_Pointer: {
|
||||||
|
Token op = f->curr_token;
|
||||||
|
next_token(f);
|
||||||
|
AstNode *expr = parse_unary_expr(f, lhs);
|
||||||
|
if (is_ast_node_type(expr)) {
|
||||||
|
return make_pointer_type(f, op, expr);
|
||||||
|
}
|
||||||
|
return make_unary_expr(f, op, expr);
|
||||||
|
} break;
|
||||||
case Token_Maybe:
|
case Token_Maybe:
|
||||||
case Token_Add:
|
case Token_Add:
|
||||||
case Token_Sub:
|
case Token_Sub:
|
||||||
|
|||||||
@@ -5038,25 +5038,48 @@ void ssa_gen_tree(ssaGen *s) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Entity_Procedure: {
|
case Entity_Procedure: {
|
||||||
AstNodeProcDecl *pd = &decl->proc_decl->ProcDecl;
|
if (decl->proc_decl->kind == AstNode_ProcDecl) {
|
||||||
String original_name = name;
|
AstNodeProcDecl *pd = &decl->proc_decl->ProcDecl;
|
||||||
AstNode *body = pd->body;
|
String original_name = name;
|
||||||
if (e->Procedure.is_foreign) {
|
AstNode *body = pd->body;
|
||||||
name = e->token.string; // NOTE(bill): Don't use the mangled name
|
if (e->Procedure.is_foreign) {
|
||||||
}
|
name = e->token.string; // NOTE(bill): Don't use the mangled name
|
||||||
if (pd->foreign_name.len > 0) {
|
}
|
||||||
name = pd->foreign_name;
|
if (pd->foreign_name.len > 0) {
|
||||||
} else if (pd->link_name.len > 0) {
|
name = pd->foreign_name;
|
||||||
name = pd->link_name;
|
} else if (pd->link_name.len > 0) {
|
||||||
}
|
name = pd->link_name;
|
||||||
|
}
|
||||||
|
|
||||||
ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
|
ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
|
||||||
p->Proc.tags = pd->tags;
|
p->Proc.tags = pd->tags;
|
||||||
|
|
||||||
ssa_module_add_value(m, e, p);
|
ssa_module_add_value(m, e, p);
|
||||||
HashKey hash_name = hash_string(name);
|
HashKey hash_name = hash_string(name);
|
||||||
if (map_ssa_value_get(&m->members, hash_name) == NULL) {
|
if (map_ssa_value_get(&m->members, hash_name) == NULL) {
|
||||||
map_ssa_value_set(&m->members, hash_name, p);
|
map_ssa_value_set(&m->members, hash_name, p);
|
||||||
|
}
|
||||||
|
} else if (decl->proc_decl->kind == AstNode_ProcLit) {
|
||||||
|
AstNodeProcLit *pd = &decl->proc_decl->ProcLit;
|
||||||
|
String original_name = name;
|
||||||
|
AstNode *body = pd->body;
|
||||||
|
if (e->Procedure.is_foreign) {
|
||||||
|
name = e->token.string; // NOTE(bill): Don't use the mangled name
|
||||||
|
}
|
||||||
|
if (pd->foreign_name.len > 0) {
|
||||||
|
name = pd->foreign_name;
|
||||||
|
} else if (pd->link_name.len > 0) {
|
||||||
|
name = pd->link_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
|
||||||
|
p->Proc.tags = pd->tags;
|
||||||
|
|
||||||
|
ssa_module_add_value(m, e, p);
|
||||||
|
HashKey hash_name = hash_string(name);
|
||||||
|
if (map_ssa_value_get(&m->members, hash_name) == NULL) {
|
||||||
|
map_ssa_value_set(&m->members, hash_name, p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user