Generic (grouped) declarations: var, let, const, type, import, include

This commit is contained in:
Ginger Bill
2016-12-20 18:58:17 +00:00
parent 478d63424f
commit d0e1efe622
20 changed files with 763 additions and 730 deletions
+41 -40
View File
@@ -1137,13 +1137,23 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
}
AstNodeValueSpec empty_spec_ = {0}, *empty_spec = &empty_spec_;
AstNodeValueSpec *last = NULL;
AstNodeValueSpec *prev_spec = NULL;
for_array(iota, gd->specs) {
AstNode *spec = gd->specs.e[iota];
switch (spec->kind) {
case_ast_node(is, ImportSpec, spec);
if (!parent_scope->is_file) {
// NOTE(bill): _Should_ be caught by the parser
// TODO(bill): Better error handling if it isn't
continue;
}
DelayedDecl di = {parent_scope, spec};
array_add(&c->delayed_imports, di);
case_end;
case_ast_node(vs, ValueSpec, spec);
switch (vs->keyword) {
case Token_let:
case Token_var: {
// NOTE(bill): You need to store the entity information here unline a constant declaration
isize entity_count = vs->names.count;
@@ -1168,7 +1178,7 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
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, parent_scope, name->Ident, NULL);
Entity *e = make_entity_variable(c->allocator, parent_scope, name->Ident, NULL, vs->keyword == Token_let);
e->identifier = name;
entities[entity_index++] = e;
@@ -1189,9 +1199,9 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
case Token_const: {
if (vs->type != NULL || vs->values.count > 0) {
last = vs;
} else if (last == NULL) {
last = empty_spec;
prev_spec = vs;
} else if (prev_spec == NULL) {
prev_spec = empty_spec;
}
for_array(i, vs->names) {
@@ -1206,36 +1216,42 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
e->identifier = name;
AstNode *init = NULL;
if (i < last->values.count) {
init = last->values.e[i];
if (i < prev_spec->values.count) {
init = prev_spec->values.e[i];
}
DeclInfo *di = make_declaration_info(c->allocator, e->scope);
di->type_expr = last->type;
di->type_expr = prev_spec->type;
di->init_expr = init;
add_entity_and_decl_info(c, name, e, di);
}
check_arity_match(c, vs, last);
check_arity_match(c, vs, prev_spec);
} break;
}
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;
}
}
case_end;
case_ast_node(id, ImportDecl, decl);
if (!parent_scope->is_file) {
// NOTE(bill): _Should_ be caught by the parser
// TODO(bill): Better error handling if it isn't
continue;
}
DelayedDecl di = {parent_scope, decl};
array_add(&c->delayed_imports, di);
case_end;
case_ast_node(fl, ForeignLibrary, decl);
if (!parent_scope->is_file) {
// NOTE(bill): _Should_ be caught by the parser
@@ -1246,20 +1262,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(td, TypeDecl, decl);
if (td->name->kind != AstNode_Ident) {
error_node(td->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[td->name->kind]));
continue;
}
ast_node(n, Ident, td->name);
Entity *e = make_entity_type_name(c->allocator, parent_scope, *n, NULL);
e->identifier = td->name;
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
d->type_expr = td->type;
d->init_expr = td->type;
add_entity_and_decl_info(c, td->name, e, d);
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]));
@@ -1286,8 +1288,9 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
void check_import_entities(Checker *c, MapScope *file_scopes) {
for_array(i, c->delayed_imports) {
Scope *parent_scope = c->delayed_imports.e[i].parent;
AstNode *decl = c->delayed_imports.e[i].decl;
ast_node(id, ImportDecl, decl);
AstNode *spec = c->delayed_imports.e[i].decl;
ast_node(id, ImportSpec, spec);
Token token = id->relpath;
HashKey key = hash_string(id->fullpath);
Scope **found = map_scope_get(file_scopes, key);
@@ -1296,13 +1299,13 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
Scope *scope = file_scopes->entries.e[scope_index].value;
gb_printf_err("%.*s\n", LIT(scope->file->tokenizer.fullpath));
}
gb_printf_err("%.*s(%td:%td)\n", LIT(id->token.pos.file), id->token.pos.line, id->token.pos.column);
gb_printf_err("%.*s(%td:%td)\n", LIT(token.pos.file), token.pos.line, token.pos.column);
GB_PANIC("Unable to find scope for file: %.*s", LIT(id->fullpath));
}
Scope *scope = *found;
if (scope->is_global) {
error(id->token, "Importing a #shared_global_scope is disallowed and unnecessary");
error(token, "Importing a #shared_global_scope is disallowed and unnecessary");
continue;
}
@@ -1332,7 +1335,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
if (!previously_added) {
array_add(&parent_scope->imported, scope);
} else {
warning(id->token, "Multiple #import of the same file within this scope");
warning(token, "Multiple #import of the same file within this scope");
}
if (str_eq(id->import_name.string, str_lit("."))) {
@@ -1381,9 +1384,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
if (is_string_an_identifier(filename)) {
import_name = filename;
} else {
error(id->token,
"File name, %.*s, cannot be as an import name as it is not a valid identifier",
LIT(filename));
error(token, "File name, %.*s, cannot be as an import name as it is not a valid identifier", LIT(filename));
}
}
+3 -3
View File
@@ -99,7 +99,7 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
}
void check_var_spec_node(Checker *c, AstNodeValueSpec *vs) {
GB_ASSERT(vs->keyword == Token_var);
GB_ASSERT(vs->keyword == Token_var || vs->keyword == Token_let);
isize entity_count = vs->names.count;
isize entity_index = 0;
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
@@ -116,7 +116,7 @@ void check_var_spec_node(Checker *c, AstNodeValueSpec *vs) {
found = current_scope_lookup_entity(c->context.scope, str);
}
if (found == NULL) {
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL, vs->keyword == Token_let);
add_entity_definition(&c->info, name, entity);
} else {
TokenPos pos = found->token.pos;
@@ -156,7 +156,7 @@ void check_var_spec_node(Checker *c, AstNodeValueSpec *vs) {
e->type = init_type;
}
check_arity_match(c, vs, NULL);
check_init_variables(c, entities, entity_count, vs->values, str_lit("variable declaration"));
for_array(i, vs->names) {
+9 -8
View File
@@ -55,9 +55,9 @@ struct Entity {
ExactValue value;
} Constant;
struct {
b32 is_let;
i32 field_index;
i32 field_src_index;
i32 field_index;
i32 field_src_index;
bool is_let;
} Variable;
i32 TypeName;
struct {
@@ -97,8 +97,9 @@ Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token,
return entity;
}
Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *type) {
Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *type, bool is_let) {
Entity *entity = alloc_entity(a, Entity_Variable, scope, token, type);
entity->Variable.is_let = is_let;
return entity;
}
@@ -123,7 +124,7 @@ Entity *make_entity_type_name(gbAllocator a, Scope *scope, Token token, Type *ty
}
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous) {
Entity *entity = make_entity_variable(a, scope, token, type);
Entity *entity = make_entity_variable(a, scope, token, type, false);
entity->flags |= EntityFlag_Used;
entity->flags |= EntityFlag_Anonymous*(anonymous != 0);
entity->flags |= EntityFlag_Param;
@@ -131,7 +132,7 @@ Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type,
}
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous, i32 field_src_index) {
Entity *entity = make_entity_variable(a, scope, token, type);
Entity *entity = make_entity_variable(a, scope, token, type, false);
entity->Variable.field_src_index = field_src_index;
entity->Variable.field_index = field_src_index;
entity->flags |= EntityFlag_Field;
@@ -140,7 +141,7 @@ Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type,
}
Entity *make_entity_vector_elem(gbAllocator a, Scope *scope, Token token, Type *type, i32 field_src_index) {
Entity *entity = make_entity_variable(a, scope, token, type);
Entity *entity = make_entity_variable(a, scope, token, type, false);
entity->Variable.field_src_index = field_src_index;
entity->Variable.field_index = field_src_index;
entity->flags |= EntityFlag_Field;
@@ -185,6 +186,6 @@ Entity *make_entity_implicit_value(gbAllocator a, String name, Type *type, Impli
Entity *make_entity_dummy_variable(gbAllocator a, Scope *file_scope, Token token) {
token.string = str_lit("_");
return make_entity_variable(a, file_scope, token, NULL);
return make_entity_variable(a, file_scope, token, NULL, false);
}
+41 -41
View File
@@ -128,6 +128,44 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
} break;
}
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;
@@ -147,47 +185,6 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
check_entity_decl(c, e, d, NULL, NULL);
case_end;
#endif
case_ast_node(td, TypeDecl, node);
if (!ast_node_expect(td->name, AstNode_Ident)) {
break;
}
if (td->name->kind != AstNode_Ident) {
error_node(td->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[td->name->kind]));
continue;
}
Token name_token = td->name->Ident;
Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, NULL);
e->identifier = td->name;
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
d->type_expr = td->type;
add_entity_and_decl_info(c, td->name, e, d);
DelayedEntity delay = {td->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, td->name, e);
add_entity_use(c, td->name, e);
}
}
case_end;
}
}
@@ -900,6 +897,9 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) {
}
#else
o->mode = Addressing_Variable;
if (e->Variable.is_let) {
o->mode = Addressing_Value;
}
#endif
break;
+22 -8
View File
@@ -21,15 +21,27 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
bool ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
u32 f = flags & (~Stmt_FallthroughAllowed);
for_array(i, stmts) {
isize max = stmts.count;
for (isize i = stmts.count-1; i >= 0; i--) {
if (stmts.e[i]->kind != AstNode_EmptyStmt) {
break;
}
max--;
}
for (isize i = 0; i < max; i++) {
AstNode *n = stmts.e[i];
if (n->kind == AstNode_EmptyStmt) {
continue;
}
u32 new_flags = f;
if (ft_ok && i+1 == stmts.count) {
if (ft_ok && i+1 == max) {
new_flags |= Stmt_FallthroughAllowed;
}
if (n->kind == AstNode_ReturnStmt && i+1 < max) {
error_node(n, "Statements after this `return` are never executed");
}
check_stmt(c, n, new_flags);
}
@@ -835,7 +847,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
tt = make_type_pointer(c->allocator, case_type);
add_type_info_type(c, tt);
}
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, ms->var->Ident, tt);
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, ms->var->Ident, tt, false);
tag_var->flags |= EntityFlag_Used;
add_entity(c, c->context.scope, ms->var, tag_var);
add_entity_use(c, ms->var, tag_var);
@@ -1078,6 +1090,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
switch (spec->kind) {
case_ast_node(vs, ValueSpec, spec);
switch (vs->keyword) {
case Token_let:
case Token_var: {
isize entity_count = vs->names.count;
isize entity_index = 0;
@@ -1095,7 +1108,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
found = current_scope_lookup_entity(c->context.scope, str);
}
if (found == NULL) {
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL, vs->keyword == Token_let);
add_entity_definition(&c->info, name, entity);
} else {
TokenPos pos = found->token.pos;
@@ -1146,10 +1159,15 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} break;
case Token_const:
// NOTE(bill): Handled elsewhere
break;
}
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;
@@ -1157,10 +1175,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
case_end;
case_ast_node(td, TypeDecl, node);
// NOTE(bill): Handled elsewhere
case_end;
case_ast_node(pd, ProcDecl, node);
// NOTE(bill): Handled elsewhere
#if 1