mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-18 16:51:31 -07: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;
|
||||
}
|
||||
}
|
||||
|
||||
+81
-56
@@ -281,15 +281,6 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
|
||||
AstNodeArray values; \
|
||||
u64 tags; \
|
||||
}) \
|
||||
AST_NODE_KIND(ProcDecl, "procedure declaration", struct { \
|
||||
AstNode *name; \
|
||||
AstNode *type; \
|
||||
AstNode *body; \
|
||||
u64 tags; \
|
||||
String foreign_name; \
|
||||
String link_name; \
|
||||
AstNode *note; \
|
||||
}) \
|
||||
AST_NODE_KIND(ForeignLibrary, "foreign library", struct { \
|
||||
Token token, filepath; \
|
||||
String base_dir; \
|
||||
@@ -303,6 +294,10 @@ AST_NODE_KIND(_DeclEnd, "", i32) \
|
||||
bool is_using; \
|
||||
}) \
|
||||
AST_NODE_KIND(_TypeBegin, "", i32) \
|
||||
AST_NODE_KIND(HelperType, "type", struct { \
|
||||
Token token; \
|
||||
AstNode *type; \
|
||||
}) \
|
||||
AST_NODE_KIND(ProcType, "procedure type", struct { \
|
||||
Token token; \
|
||||
AstNodeArray params; \
|
||||
@@ -501,8 +496,6 @@ Token ast_node_token(AstNode *node) {
|
||||
return node->GenericDecl.token;
|
||||
case AstNode_ValueDecl:
|
||||
return ast_node_token(node->ValueDecl.names.e[0]);
|
||||
case AstNode_ProcDecl:
|
||||
return ast_node_token(node->ProcDecl.name);
|
||||
|
||||
case AstNode_ForeignLibrary:
|
||||
return node->ForeignLibrary.token;
|
||||
@@ -519,6 +512,10 @@ Token ast_node_token(AstNode *node) {
|
||||
return ast_node_token(node->Field.type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case AstNode_HelperType:
|
||||
return node->HelperType.token;
|
||||
case AstNode_ProcType:
|
||||
return node->ProcType.token;
|
||||
case AstNode_PointerType:
|
||||
@@ -969,6 +966,15 @@ AstNode *make_field(AstFile *f, AstNodeArray names, AstNode *type, bool is_using
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AstNode *make_helper_type(AstFile *f, Token token, AstNode *type) {
|
||||
AstNode *result = make_node(f, AstNode_HelperType);
|
||||
result->HelperType.token = token;
|
||||
result->HelperType.type = type;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags, ProcCallingConvention calling_convention) {
|
||||
AstNode *result = make_node(f, AstNode_ProcType);
|
||||
result->ProcType.token = token;
|
||||
@@ -979,17 +985,6 @@ AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArr
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, AstNode *body, u64 tags, String foreign_name, String link_name) {
|
||||
AstNode *result = make_node(f, AstNode_ProcDecl);
|
||||
result->ProcDecl.name = name;
|
||||
result->ProcDecl.type = proc_type;
|
||||
result->ProcDecl.body = body;
|
||||
result->ProcDecl.tags = tags;
|
||||
result->ProcDecl.foreign_name = foreign_name;
|
||||
result->ProcDecl.link_name = link_name;
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *make_pointer_type(AstFile *f, Token token, AstNode *type) {
|
||||
AstNode *result = make_node(f, AstNode_PointerType);
|
||||
result->PointerType.token = token;
|
||||
@@ -1264,6 +1259,52 @@ Token expect_closing(AstFile *f, TokenKind kind, String context) {
|
||||
return expect_token(f, kind);
|
||||
}
|
||||
|
||||
bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) {
|
||||
if (s == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (s->kind) {
|
||||
case AstNode_HelperType:
|
||||
return is_semicolon_optional_for_node(f, s->HelperType.type);
|
||||
|
||||
case AstNode_StructType:
|
||||
case AstNode_UnionType:
|
||||
case AstNode_RawUnionType:
|
||||
case AstNode_EnumType:
|
||||
return true;
|
||||
case AstNode_ProcLit:
|
||||
return true;
|
||||
|
||||
case AstNode_ValueDecl:
|
||||
if (!s->ValueDecl.is_var) {
|
||||
if (s->ValueDecl.values.count > 0) {
|
||||
AstNode *last = s->ValueDecl.values.e[s->ValueDecl.values.count-1];
|
||||
return is_semicolon_optional_for_node(f, last);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AstNode_GenericDecl:
|
||||
if (s->GenericDecl.close.kind == Token_CloseBrace) {
|
||||
return true;
|
||||
} else if (s->GenericDecl.token.kind == Token_type) {
|
||||
if (f->prev_token.kind == Token_CloseBrace) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AstNode_TypeSpec:
|
||||
if (f->prev_token.kind == Token_CloseBrace) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void expect_semicolon(AstFile *f, AstNode *s) {
|
||||
if (allow_token(f, Token_Semicolon)) {
|
||||
return;
|
||||
@@ -1277,24 +1318,8 @@ void expect_semicolon(AstFile *f, AstNode *s) {
|
||||
|
||||
if (s != NULL) {
|
||||
if (prev_token.pos.line != f->curr_token.pos.line) {
|
||||
switch (s->kind) {
|
||||
case AstNode_ProcDecl:
|
||||
if (is_semicolon_optional_for_node(f, s)) {
|
||||
return;
|
||||
case AstNode_GenericDecl:
|
||||
if (s->GenericDecl.close.kind == Token_CloseBrace) {
|
||||
return;
|
||||
} else if (s->GenericDecl.token.kind == Token_type) {
|
||||
if (f->prev_token.kind == Token_CloseBrace) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AstNode_TypeSpec:
|
||||
if (f->prev_token.kind == Token_CloseBrace) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (s->kind) {
|
||||
@@ -1319,7 +1344,6 @@ AstNode * parse_proc_type(AstFile *f, String *foreign_name_, String *link_nam
|
||||
AstNodeArray parse_stmt_list(AstFile *f);
|
||||
AstNode * parse_stmt(AstFile *f);
|
||||
AstNode * parse_body(AstFile *f);
|
||||
AstNode * parse_proc_decl(AstFile *f);
|
||||
void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results);
|
||||
|
||||
|
||||
@@ -1571,6 +1595,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
|
||||
AstNodeArray parse_lhs_expr_list(AstFile *f);
|
||||
AstNodeArray parse_rhs_expr_list(AstFile *f);
|
||||
AstNode * parse_simple_stmt (AstFile *f);
|
||||
AstNode * parse_type (AstFile *f);
|
||||
|
||||
AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) {
|
||||
if (statement == NULL) {
|
||||
@@ -1745,10 +1770,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
String foreign_name = {0};
|
||||
String link_name = {0};
|
||||
AstNode *type = parse_proc_type(f, &foreign_name, &link_name);
|
||||
u64 tags = type->ProcType.tags;
|
||||
|
||||
if (f->curr_token.kind == Token_OpenBrace) {
|
||||
u64 tags = type->ProcType.tags;
|
||||
|
||||
if ((tags & ProcTag_foreign) != 0) {
|
||||
syntax_error(token, "A procedure tagged as `#foreign` cannot have a body");
|
||||
}
|
||||
@@ -1760,6 +1784,13 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
return make_proc_lit(f, type, body, tags, foreign_name, link_name);
|
||||
}
|
||||
|
||||
if ((tags & ProcTag_foreign) != 0) {
|
||||
return make_proc_lit(f, type, NULL, tags, foreign_name, link_name);
|
||||
}
|
||||
if ((tags & ProcTag_link_name) != 0) {
|
||||
syntax_error(token, "A procedure typed cannot be tagged with `#link_name`");
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -1932,7 +1963,6 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
|
||||
return operand;
|
||||
}
|
||||
|
||||
AstNode *parse_type(AstFile *f);
|
||||
|
||||
AstNode *parse_unary_expr(AstFile *f, bool lhs) {
|
||||
switch (f->curr_token.kind) {
|
||||
@@ -2240,17 +2270,6 @@ PARSE_SPEC_PROC(parse_include_spec) {
|
||||
|
||||
AstNode *parse_decl(AstFile *f) {
|
||||
switch (f->curr_token.kind) {
|
||||
// case Token_var:
|
||||
// case Token_const:
|
||||
// return parse_generic_decl(f, f->curr_token.kind, parse_value_spec);
|
||||
|
||||
case Token_type:
|
||||
return parse_generic_decl(f, f->curr_token.kind, parse_type_spec);
|
||||
|
||||
case Token_proc:
|
||||
// TODO(bill): Should I allow procedures to use the generic declaration syntax?
|
||||
return parse_proc_decl(f);
|
||||
|
||||
case Token_import:
|
||||
return parse_generic_decl(f, f->curr_token.kind, parse_import_spec);
|
||||
case Token_include:
|
||||
@@ -2504,6 +2523,12 @@ AstNode *parse_identifier_or_type(AstFile *f) {
|
||||
return e;
|
||||
}
|
||||
|
||||
case Token_type: {
|
||||
Token token = expect_token(f, Token_type);
|
||||
AstNode *type = parse_type(f);
|
||||
return make_helper_type(f, token, type);
|
||||
}
|
||||
|
||||
case Token_Pointer: {
|
||||
Token token = expect_token(f, Token_Pointer);
|
||||
AstNode *elem = parse_type(f);
|
||||
@@ -2681,7 +2706,7 @@ AstNode *parse_body(AstFile *f) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
AstNode *parse_proc_decl(AstFile *f) {
|
||||
if (look_ahead_token_kind(f, 1) == Token_OpenParen) {
|
||||
// NOTE(bill): It's an anonymous procedure
|
||||
@@ -2720,7 +2745,7 @@ AstNode *parse_proc_decl(AstFile *f) {
|
||||
}
|
||||
|
||||
return make_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name);
|
||||
}
|
||||
} */
|
||||
|
||||
AstNode *parse_if_stmt(AstFile *f) {
|
||||
if (f->curr_proc == NULL) {
|
||||
|
||||
@@ -3978,104 +3978,96 @@ void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) {
|
||||
}
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(gd, GenericDecl, node);
|
||||
for_array(spec_index, gd->specs) {
|
||||
AstNode *spec = gd->specs.e[spec_index];
|
||||
switch (spec->kind) {
|
||||
case_ast_node(ts, TypeSpec, spec);
|
||||
// NOTE(bill): Generate a new name
|
||||
// parent_proc.name-guid
|
||||
String ts_name = ts->name->Ident.string;
|
||||
isize name_len = proc->name.len + 1 + ts_name.len + 1 + 10 + 1;
|
||||
u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
|
||||
i32 guid = cast(i32)proc->module->members.entries.count;
|
||||
name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(ts_name), guid);
|
||||
String name = make_string(name_text, name_len-1);
|
||||
|
||||
Entity **found = map_entity_get(&proc->module->info->definitions, hash_pointer(ts->name));
|
||||
GB_ASSERT(found != NULL);
|
||||
Entity *e = *found;
|
||||
ssaValue *value = ssa_make_value_type_name(proc->module->allocator,
|
||||
name, e->type);
|
||||
map_string_set(&proc->module->type_names, hash_pointer(e->type), name);
|
||||
ssa_gen_global_type_name(proc->module, e, name);
|
||||
case_end;
|
||||
}
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(pd, ProcDecl, node);
|
||||
if (pd->body != NULL) {
|
||||
CheckerInfo *info = proc->module->info;
|
||||
|
||||
Entity **found = map_entity_get(&info->definitions, hash_pointer(pd->name));
|
||||
GB_ASSERT_MSG(found != NULL, "Unable to find: %.*s", LIT(pd->name->Ident.string));
|
||||
Entity *e = *found;
|
||||
|
||||
|
||||
if (map_entity_get(&proc->module->min_dep_map, hash_pointer(e)) == NULL) {
|
||||
// NOTE(bill): Nothing depends upon it so doesn't need to be built
|
||||
break;
|
||||
}
|
||||
|
||||
// NOTE(bill): Generate a new name
|
||||
// parent.name-guid
|
||||
String original_name = pd->name->Ident.string;
|
||||
String pd_name = original_name;
|
||||
if (pd->link_name.len > 0) {
|
||||
pd_name = pd->link_name;
|
||||
}
|
||||
|
||||
isize name_len = proc->name.len + 1 + pd_name.len + 1 + 10 + 1;
|
||||
u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
|
||||
i32 guid = cast(i32)proc->children.count;
|
||||
name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(pd_name), guid);
|
||||
String name = make_string(name_text, name_len-1);
|
||||
|
||||
|
||||
ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
|
||||
proc->module, e, e->type, pd->type, pd->body, name);
|
||||
|
||||
value->Proc.tags = pd->tags;
|
||||
value->Proc.parent = proc;
|
||||
|
||||
ssa_module_add_value(proc->module, e, value);
|
||||
array_add(&proc->children, &value->Proc);
|
||||
array_add(&proc->module->procs_to_generate, value);
|
||||
} else {
|
||||
CheckerInfo *info = proc->module->info;
|
||||
for_array(i, vd->names) {
|
||||
AstNode *ident = vd->names.e[i];
|
||||
GB_ASSERT(ident->kind == AstNode_Ident);
|
||||
Entity *e = entity_of_ident(proc->module->info, ident);
|
||||
GB_ASSERT(e != NULL);
|
||||
switch (e->kind) {
|
||||
case Entity_TypeName: {
|
||||
// NOTE(bill): Generate a new name
|
||||
// parent_proc.name-guid
|
||||
String ts_name = e->token.string;
|
||||
isize name_len = proc->name.len + 1 + ts_name.len + 1 + 10 + 1;
|
||||
u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
|
||||
i32 guid = cast(i32)proc->module->members.entries.count;
|
||||
name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(ts_name), guid);
|
||||
String name = make_string(name_text, name_len-1);
|
||||
|
||||
Entity **found = map_entity_get(&info->definitions, hash_pointer(pd->name));
|
||||
GB_ASSERT_MSG(found != NULL, "Unable to find: %.*s", LIT(pd->name->Ident.string));
|
||||
Entity *e = *found;
|
||||
ssaValue *value = ssa_make_value_type_name(proc->module->allocator,
|
||||
name, e->type);
|
||||
map_string_set(&proc->module->type_names, hash_pointer(e->type), name);
|
||||
ssa_gen_global_type_name(proc->module, e, name);
|
||||
} break;
|
||||
case Entity_Procedure: {
|
||||
DeclInfo **decl_info = map_decl_info_get(&proc->module->info->entities, hash_pointer(e));
|
||||
GB_ASSERT(decl_info != NULL);
|
||||
DeclInfo *dl = *decl_info;
|
||||
ast_node(pd, ProcLit, dl->proc_decl);
|
||||
if (pd->body != NULL) {
|
||||
CheckerInfo *info = proc->module->info;
|
||||
|
||||
// FFI - Foreign function interace
|
||||
String original_name = pd->name->Ident.string;
|
||||
String name = original_name;
|
||||
if (pd->foreign_name.len > 0) {
|
||||
name = pd->foreign_name;
|
||||
}
|
||||
if (map_entity_get(&proc->module->min_dep_map, hash_pointer(e)) == NULL) {
|
||||
// NOTE(bill): Nothing depends upon it so doesn't need to be built
|
||||
break;
|
||||
}
|
||||
|
||||
ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
|
||||
proc->module, e, e->type, pd->type, pd->body, name);
|
||||
// NOTE(bill): Generate a new name
|
||||
// parent.name-guid
|
||||
String original_name = e->token.string;
|
||||
String pd_name = original_name;
|
||||
if (pd->link_name.len > 0) {
|
||||
pd_name = pd->link_name;
|
||||
}
|
||||
|
||||
value->Proc.tags = pd->tags;
|
||||
isize name_len = proc->name.len + 1 + pd_name.len + 1 + 10 + 1;
|
||||
u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
|
||||
i32 guid = cast(i32)proc->children.count;
|
||||
name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(pd_name), guid);
|
||||
String name = make_string(name_text, name_len-1);
|
||||
|
||||
ssa_module_add_value(proc->module, e, value);
|
||||
ssa_build_proc(value, proc);
|
||||
|
||||
if (value->Proc.tags & ProcTag_foreign) {
|
||||
HashKey key = hash_string(name);
|
||||
ssaValue **prev_value = map_ssa_value_get(&proc->module->members, key);
|
||||
if (prev_value == NULL) {
|
||||
// NOTE(bill): Don't do mutliple declarations in the IR
|
||||
map_ssa_value_set(&proc->module->members, key, value);
|
||||
ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
|
||||
proc->module, e, e->type, pd->type, pd->body, name);
|
||||
|
||||
value->Proc.tags = pd->tags;
|
||||
value->Proc.parent = proc;
|
||||
|
||||
ssa_module_add_value(proc->module, e, value);
|
||||
array_add(&proc->children, &value->Proc);
|
||||
array_add(&proc->module->procs_to_generate, value);
|
||||
} else {
|
||||
CheckerInfo *info = proc->module->info;
|
||||
|
||||
// FFI - Foreign function interace
|
||||
String original_name = e->token.string;
|
||||
String name = original_name;
|
||||
if (pd->foreign_name.len > 0) {
|
||||
name = pd->foreign_name;
|
||||
}
|
||||
|
||||
ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
|
||||
proc->module, e, e->type, pd->type, pd->body, name);
|
||||
|
||||
value->Proc.tags = pd->tags;
|
||||
|
||||
ssa_module_add_value(proc->module, e, value);
|
||||
ssa_build_proc(value, proc);
|
||||
|
||||
if (value->Proc.tags & ProcTag_foreign) {
|
||||
HashKey key = hash_string(name);
|
||||
ssaValue **prev_value = map_ssa_value_get(&proc->module->members, key);
|
||||
if (prev_value == NULL) {
|
||||
// NOTE(bill): Don't do mutliple declarations in the IR
|
||||
map_ssa_value_set(&proc->module->members, key, value);
|
||||
}
|
||||
} else {
|
||||
array_add(&proc->children, &value->Proc);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
} else {
|
||||
array_add(&proc->children, &value->Proc);
|
||||
}
|
||||
}
|
||||
case_end;
|
||||
@@ -5034,48 +5026,25 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
} break;
|
||||
|
||||
case Entity_Procedure: {
|
||||
if (decl->proc_decl->kind == AstNode_ProcDecl) {
|
||||
AstNodeProcDecl *pd = &decl->proc_decl->ProcDecl;
|
||||
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;
|
||||
}
|
||||
ast_node(pd, ProcLit, decl->proc_decl);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user