mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-02 20:58:15 +00:00
Nearly finished Jai-like declarations
This commit is contained in:
@@ -308,11 +308,6 @@ bool decl_info_has_init(DeclInfo *d) {
|
||||
}
|
||||
if (d->proc_decl != NULL) {
|
||||
switch (d->proc_decl->kind) {
|
||||
case_ast_node(pd, ProcDecl, d->proc_decl);
|
||||
if (pd->body != NULL) {
|
||||
return true;
|
||||
}
|
||||
case_end;
|
||||
case_ast_node(pd, ProcLit, d->proc_decl);
|
||||
if (pd->body != NULL) {
|
||||
return true;
|
||||
@@ -1260,23 +1255,6 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
|
||||
DelayedDecl di = {parent_scope, spec};
|
||||
array_add(&c->delayed_imports, di);
|
||||
case_end;
|
||||
|
||||
case_ast_node(ts, TypeSpec, spec);
|
||||
if (ts->name->kind != AstNode_Ident) {
|
||||
error_node(ts->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[ts->name->kind]));
|
||||
continue;
|
||||
}
|
||||
ast_node(n, Ident, ts->name);
|
||||
|
||||
Entity *e = make_entity_type_name(c->allocator, parent_scope, *n, NULL);
|
||||
e->identifier = ts->name;
|
||||
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->type_expr = ts->type;
|
||||
d->init_expr = ts->type;
|
||||
add_entity_and_decl_info(c, ts->name, e, d);
|
||||
case_end;
|
||||
|
||||
default:
|
||||
error(ast_node_token(spec), "Invalid specification in declaration: `%.*s`", LIT(ast_node_strings[spec->kind]));
|
||||
break;
|
||||
@@ -1293,20 +1271,6 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
|
||||
DelayedDecl di = {parent_scope, decl};
|
||||
array_add(&c->delayed_foreign_libraries, di);
|
||||
case_end;
|
||||
case_ast_node(pd, ProcDecl, decl);
|
||||
if (pd->name->kind != AstNode_Ident) {
|
||||
error_node(pd->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[pd->name->kind]));
|
||||
continue;
|
||||
}
|
||||
ast_node(n, Ident, pd->name);
|
||||
Token token = *n;
|
||||
Entity *e = make_entity_procedure(c->allocator, parent_scope, token, NULL, pd->tags);
|
||||
e->identifier = pd->name;
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->proc_decl = decl;
|
||||
add_entity_and_decl_info(c, pd->name, e, d);
|
||||
case_end;
|
||||
|
||||
default:
|
||||
if (parent_scope->is_file) {
|
||||
error_node(decl, "Only declarations are allowed at file scope");
|
||||
|
||||
+108
-209
@@ -282,6 +282,10 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
|
||||
check_init_constant(c, e, &operand);
|
||||
c->context.iota = (ExactValue){0};
|
||||
|
||||
if (e->type == t_invalid) {
|
||||
error(e->token, "Illegal cyclic declaration");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -326,224 +330,119 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||
|
||||
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
GB_ASSERT(e->type == NULL);
|
||||
if (d->proc_decl->kind != AstNode_ProcLit) {
|
||||
// TOOD(bill): Better error message
|
||||
error_node(d->proc_decl, "Expected a procedure to check");
|
||||
return;
|
||||
}
|
||||
|
||||
Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
|
||||
e->type = proc_type;
|
||||
if (d->proc_decl->kind == AstNode_ProcDecl) {
|
||||
ast_node(pd, ProcDecl, d->proc_decl);
|
||||
ast_node(pd, ProcLit, d->proc_decl);
|
||||
|
||||
check_open_scope(c, pd->type);
|
||||
check_procedure_type(c, proc_type, pd->type);
|
||||
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;
|
||||
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 ((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;
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
+11
-38
@@ -137,43 +137,6 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
|
||||
switch (spec->kind) {
|
||||
case_ast_node(bd, BadDecl, spec);
|
||||
case_end;
|
||||
case_ast_node(ts, TypeSpec, spec);
|
||||
if (ts->name->kind != AstNode_Ident) {
|
||||
error_node(ts->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[ts->name->kind]));
|
||||
break;
|
||||
}
|
||||
|
||||
Token name_token = ts->name->Ident;
|
||||
|
||||
Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, NULL);
|
||||
e->identifier = ts->name;
|
||||
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->type_expr = ts->type;
|
||||
|
||||
add_entity_and_decl_info(c, ts->name, e, d);
|
||||
|
||||
DelayedEntity delay = {ts->name, e, d};
|
||||
array_add(delayed_entities, delay);
|
||||
|
||||
|
||||
if (dof != NULL) {
|
||||
if (str_eq(name_token.string, str_lit("_"))) {
|
||||
dof->other_fields[dof->other_field_index++] = e;
|
||||
} else {
|
||||
HashKey key = hash_string(name_token.string);
|
||||
if (map_entity_get(dof->entity_map, key) != NULL) {
|
||||
// TODO(bill): Scope checking already checks the declaration
|
||||
error(name_token, "`%.*s` is already declared in this record", LIT(name_token.string));
|
||||
} else {
|
||||
map_entity_set(dof->entity_map, key, e);
|
||||
dof->other_fields[dof->other_field_index++] = e;
|
||||
}
|
||||
add_entity(c, c->context.scope, ts->name, e);
|
||||
add_entity_use(c, ts->name, e);
|
||||
}
|
||||
}
|
||||
case_end;
|
||||
}
|
||||
}
|
||||
case_end;
|
||||
@@ -975,7 +938,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) {
|
||||
}
|
||||
if (e == e_iota) {
|
||||
if (c->context.iota.kind == ExactValue_Invalid) {
|
||||
error(e->token, "Use of `iota` outside a constant declaration is not allowed");
|
||||
error(e->token, "Use of `iota` outside a enumeration is not allowed");
|
||||
return;
|
||||
}
|
||||
o->value = c->context.iota;
|
||||
@@ -1141,6 +1104,11 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(ht, HelperType, e);
|
||||
type = check_type(c, ht->type);
|
||||
goto end;
|
||||
case_end;
|
||||
|
||||
case_ast_node(pt, PointerType, e);
|
||||
Type *elem = check_type(c, pt->type);
|
||||
type = make_type_pointer(c->allocator, elem);
|
||||
@@ -4825,6 +4793,11 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
str = gb_string_appendc(str, "{");
|
||||
str = gb_string_appendc(str, "}");
|
||||
case_end;
|
||||
|
||||
case_ast_node(ht, HelperType, node);
|
||||
str = gb_string_appendc(str, "type ");
|
||||
str = write_expr_to_string(str, ht->type);
|
||||
case_end;
|
||||
}
|
||||
|
||||
return str;
|
||||
|
||||
@@ -1170,36 +1170,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
switch (spec->kind) {
|
||||
case_ast_node(bd, BadDecl, spec);
|
||||
case_end;
|
||||
case_ast_node(ts, TypeSpec, spec);
|
||||
// NOTE(bill): Handled elsewhere
|
||||
case_end;
|
||||
|
||||
default:
|
||||
error(ast_node_token(spec), "Invalid specification in declaration: `%.*s`", LIT(ast_node_strings[spec->kind]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(pd, ProcDecl, node);
|
||||
// NOTE(bill): Handled elsewhere
|
||||
#if 1
|
||||
// NOTE(bill): This must be handled here so it has access to the parent scope stuff
|
||||
// e.g. using
|
||||
if (pd->name->kind != AstNode_Ident) {
|
||||
error_node(pd->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[pd->name->kind]));
|
||||
break;
|
||||
}
|
||||
|
||||
Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL, pd->tags);
|
||||
e->identifier = pd->name;
|
||||
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->proc_decl = node;
|
||||
|
||||
add_entity_and_decl_info(c, pd->name, e, d);
|
||||
check_entity_decl(c, e, d, NULL);
|
||||
#endif
|
||||
case_end;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user