aboutsummaryrefslogtreecommitdiff
path: root/src/checker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/checker.cpp')
-rw-r--r--src/checker.cpp283
1 files changed, 150 insertions, 133 deletions
diff --git a/src/checker.cpp b/src/checker.cpp
index 26ef9992f..9b6c81622 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -1249,7 +1249,7 @@ void init_preload(Checker *c) {
-bool check_arity_match(Checker *c, AstNodeValueDecl *d);
+bool check_arity_match(Checker *c, AstNodeValueSpec *s);
void check_collect_entities(Checker *c, Array<AstNode *> nodes, bool is_file_scope);
void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws, bool is_file_scope);
@@ -1362,27 +1362,27 @@ void check_procedure_overloading(Checker *c, Entity *e) {
-bool check_arity_match(Checker *c, AstNodeValueDecl *d) {
- isize lhs = d->names.count;
- isize rhs = d->values.count;
+bool check_arity_match(Checker *c, AstNodeValueSpec *spec) {
+ isize lhs = spec->names.count;
+ isize rhs = spec->values.count;
if (rhs == 0) {
- if (d->type == NULL) {
- error_node(d->names[0], "Missing type or initial expression");
+ if (spec->type == NULL) {
+ error_node(spec->names[0], "Missing type or initial expression");
return false;
}
} else if (lhs < rhs) {
- if (lhs < d->values.count) {
- AstNode *n = d->values[lhs];
+ if (lhs < spec->values.count) {
+ AstNode *n = spec->values[lhs];
gbString str = expr_to_string(n);
error_node(n, "Extra initial expression `%s`", str);
gb_string_free(str);
} else {
- error_node(d->names[0], "Extra initial expression");
+ error_node(spec->names[0], "Extra initial expression");
}
return false;
} else if (lhs > rhs && rhs != 1) {
- AstNode *n = d->names[rhs];
+ AstNode *n = spec->names[rhs];
gbString str = expr_to_string(n);
error_node(n, "Missing expression for `%s`", str);
gb_string_free(str);
@@ -1450,114 +1450,166 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes, bool is_file_sco
}
case_end;
- case_ast_node(vd, ValueDecl, decl);
- if (vd->token.kind != Token_const) {
- if (!c->context.scope->is_file) {
- // NOTE(bill): local scope -> handle later and in order
- break;
- }
- // NOTE(bill): You need to store the entity information here unline a constant declaration
- isize entity_cap = vd->names.count;
- isize entity_count = 0;
- Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_cap);
- DeclInfo *di = NULL;
- if (vd->values.count > 0) {
- di = make_declaration_info(heap_allocator(), c->context.scope, c->context.decl);
- di->entities = entities;
- di->type_expr = vd->type;
- di->init_expr = vd->values[0];
-
-
- if (vd->flags & VarDeclFlag_thread_local) {
- error_node(decl, "#thread_local variable declarations cannot have initialization values");
+ case_ast_node(gd, GenDecl, decl);
+ for_array(i, gd->specs) {
+ AstNode *spec = gd->specs[i];
+ switch (gd->token.kind) {
+ case Token_var:
+ case Token_let: {
+ if (!c->context.scope->is_file) {
+ // NOTE(bill): local scope -> handle later and in order
+ break;
+ }
+ ast_node(vd, ValueSpec, spec);
+
+ // NOTE(bill): You need to store the entity information here unline a constant declaration
+ isize entity_cap = vd->names.count;
+ isize entity_count = 0;
+ Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_cap);
+ DeclInfo *di = NULL;
+ if (vd->values.count > 0) {
+ di = make_declaration_info(heap_allocator(), c->context.scope, c->context.decl);
+ di->entities = entities;
+ di->type_expr = vd->type;
+ di->init_expr = vd->values[0];
+
+
+ if (gd->flags & VarDeclFlag_thread_local) {
+ error_node(decl, "#thread_local variable declarations cannot have initialization values");
+ }
}
- }
- for_array(i, vd->names) {
- AstNode *name = vd->names[i];
- AstNode *value = NULL;
- if (i < vd->values.count) {
- value = vd->values[i];
- }
- if (name->kind != AstNode_Ident) {
- error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
- continue;
+ for_array(i, vd->names) {
+ AstNode *name = vd->names[i];
+ AstNode *value = NULL;
+ if (i < vd->values.count) {
+ value = vd->values[i];
+ }
+ if (name->kind != AstNode_Ident) {
+ error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
+ continue;
+ }
+ Entity *e = make_entity_variable(c->allocator, c->context.scope, name->Ident, NULL, (gd->flags&VarDeclFlag_immutable) != 0);
+ e->Variable.is_thread_local = (gd->flags & VarDeclFlag_thread_local) != 0;
+ e->identifier = name;
+
+ if (gd->flags & VarDeclFlag_using) {
+ gd->flags &= ~VarDeclFlag_using; // NOTE(bill): This error will be only caught once
+ error_node(name, "`using` is not allowed at the file scope");
+ }
+ entities[entity_count++] = e;
+
+ DeclInfo *d = di;
+ if (d == NULL) {
+ AstNode *init_expr = value;
+ d = make_declaration_info(heap_allocator(), e->scope, c->context.decl);
+ d->type_expr = vd->type;
+ d->init_expr = init_expr;
+ }
+
+ add_entity_and_decl_info(c, name, e, d);
}
- Entity *e = make_entity_variable(c->allocator, c->context.scope, name->Ident, NULL, (vd->flags&VarDeclFlag_immutable) != 0);
- e->Variable.is_thread_local = (vd->flags & VarDeclFlag_thread_local) != 0;
- e->identifier = name;
- if (vd->flags & VarDeclFlag_using) {
- vd->flags &= ~VarDeclFlag_using; // NOTE(bill): This error will be only caught once
- error_node(name, "`using` is not allowed at the file scope");
+ if (di != NULL) {
+ di->entity_count = entity_count;
}
- entities[entity_count++] = e;
-
- DeclInfo *d = di;
- if (d == NULL) {
- AstNode *init_expr = value;
- d = make_declaration_info(heap_allocator(), e->scope, c->context.decl);
- d->type_expr = vd->type;
- d->init_expr = init_expr;
+
+ check_arity_match(c, vd);
+ } break;
+
+ case Token_const: {
+ ast_node(vd, ValueSpec, spec);
+
+ for_array(i, vd->names) {
+ AstNode *name = vd->names[i];
+ if (name->kind != AstNode_Ident) {
+ error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
+ continue;
+ }
+
+ AstNode *init = NULL;
+ if (i < vd->values.count) {
+ init = vd->values[i];
+ }
+
+ DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, c->context.decl);
+ Entity *e = NULL;
+
+ AstNode *up_init = unparen_expr(init);
+ // if (up_init != NULL && is_ast_node_type(up_init)) {
+ // AstNode *type = up_init;
+ // e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
+ // // TODO(bill): What if vd->type != NULL??? How to handle this case?
+ // d->type_expr = type;
+ // d->init_expr = type;
+ // } else if (up_init != NULL && up_init->kind == AstNode_Alias) {
+ // #if 1
+ // error_node(up_init, "#alias declarations are not yet supported");
+ // continue;
+ // #else
+ // e = make_entity_alias(c->allocator, d->scope, name->Ident, NULL, EntityAlias_Invalid, NULL);
+ // d->type_expr = vd->type;
+ // d->init_expr = up_init->Alias.expr;
+ // #endif
+ // // } 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_lit = up_init;
+ // // d->type_expr = vd->type;
+ // } else {
+ e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, empty_exact_value);
+ d->type_expr = vd->type;
+ d->init_expr = init;
+ // }
+ GB_ASSERT(e != NULL);
+ e->identifier = name;
+
+ add_entity_and_decl_info(c, name, e, d);
}
- add_entity_and_decl_info(c, name, e, d);
- }
+ check_arity_match(c, vd);
+ } break;
- if (di != NULL) {
- di->entity_count = entity_count;
- }
+ case Token_type: {
+ ast_node(td, TypeSpec, spec);
- check_arity_match(c, vd);
- } else {
- for_array(i, vd->names) {
- AstNode *name = vd->names[i];
+ AstNode *name = td->name;
if (name->kind != AstNode_Ident) {
error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
- continue;
+ break;
}
- AstNode *init = NULL;
- if (i < vd->values.count) {
- init = vd->values[i];
- }
DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, c->context.decl);
Entity *e = NULL;
- AstNode *up_init = unparen_expr(init);
- // if (up_init != NULL && is_ast_node_type(up_init)) {
- // AstNode *type = up_init;
- // e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
- // // TODO(bill): What if vd->type != NULL??? How to handle this case?
- // d->type_expr = type;
- // d->init_expr = type;
- // } else if (up_init != NULL && up_init->kind == AstNode_Alias) {
- // #if 1
- // error_node(up_init, "#alias declarations are not yet supported");
- // continue;
- // #else
- // e = make_entity_alias(c->allocator, d->scope, name->Ident, NULL, EntityAlias_Invalid, NULL);
- // d->type_expr = vd->type;
- // d->init_expr = up_init->Alias.expr;
- // #endif
- // // } 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_lit = up_init;
- // // d->type_expr = vd->type;
- // } else {
- e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, empty_exact_value);
- d->type_expr = vd->type;
- d->init_expr = init;
- // }
- GB_ASSERT(e != NULL);
- e->identifier = name;
+ AstNode *type = unparen_expr(td->type);
+ e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
+ // TODO(bill): What if vd->type != NULL??? How to handle this case?
+ d->type_expr = type;
+ d->init_expr = type;
+ e->identifier = name;
add_entity_and_decl_info(c, name, e, d);
+ } break;
+
+ case Token_import:
+ case Token_import_load: {
+ ast_node(id, ImportSpec, spec);
+ if (!c->context.scope->is_file) {
+ if (id->is_import) {
+ error_node(decl, "import declarations are only allowed in the file scope");
+ } else {
+ error_node(decl, "import_load declarations are only allowed in the file scope");
+ }
+ // NOTE(bill): _Should_ be caught by the parser
+ // TODO(bill): Better error handling if it isn't
+ continue;
+ }
+ DelayedDecl di = {c->context.scope, spec};
+ array_add(&c->delayed_imports, di);
+ } break;
}
-
- check_arity_match(c, vd);
}
case_end;
@@ -1579,41 +1631,6 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes, bool is_file_sco
add_entity_and_decl_info(c, name, e, d);
case_end;
- case_ast_node(td, TypeDecl, decl);
- AstNode *name = td->name;
- if (name->kind != AstNode_Ident) {
- error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
- break;
- }
-
-
- DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, c->context.decl);
- Entity *e = NULL;
-
- AstNode *type = unparen_expr(td->type);
- e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
- // TODO(bill): What if vd->type != NULL??? How to handle this case?
- d->type_expr = type;
- d->init_expr = type;
-
- e->identifier = name;
- add_entity_and_decl_info(c, name, e, d);
- case_end;
-
- case_ast_node(id, ImportDecl, decl);
- if (!c->context.scope->is_file) {
- if (id->is_import) {
- error_node(decl, "#import declarations are only allowed in the file scope");
- } else {
- error_node(decl, "#load declarations are only allowed in the file scope");
- }
- // NOTE(bill): _Should_ be caught by the parser
- // TODO(bill): Better error handling if it isn't
- continue;
- }
- DelayedDecl di = {c->context.scope, decl};
- array_add(&c->delayed_imports, di);
- case_end;
case_ast_node(fl, ForeignLibrary, decl);
if (!c->context.scope->is_file) {
if (fl->is_system) {
@@ -1882,7 +1899,7 @@ void check_import_entities(Checker *c, Map<Scope *> *file_scopes) {
for_array(i, c->delayed_imports) {
Scope *parent_scope = c->delayed_imports[i].parent;
AstNode *decl = c->delayed_imports[i].decl;
- ast_node(id, ImportDecl, decl);
+ ast_node(id, ImportSpec, decl);
Token token = id->relpath;
GB_ASSERT(parent_scope->is_file);