mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-23 07:57:52 +00:00
Better using; foreign system libraries; optional semicolons
This commit is contained in:
@@ -530,7 +530,7 @@ void add_entity_definition(CheckerInfo *i, AstNode *identifier, Entity *entity)
|
||||
map_set(&i->definitions, key, entity);
|
||||
}
|
||||
|
||||
void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
|
||||
b32 add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
|
||||
if (!are_strings_equal(entity->token.string, make_string("_"))) {
|
||||
Entity *insert_entity = scope_insert_entity(scope, entity);
|
||||
if (insert_entity) {
|
||||
@@ -541,18 +541,20 @@ void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(entity->token.string),
|
||||
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
|
||||
return false;
|
||||
} else {
|
||||
error(&c->error_collector, entity->token,
|
||||
"Redeclararation of `%.*s` in this scope\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(entity->token.string),
|
||||
LIT(entity->token.pos.file), entity->token.pos.line, entity->token.pos.column);
|
||||
return false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (identifier != NULL)
|
||||
add_entity_definition(&c->info, identifier, entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
void add_entity_use(CheckerInfo *i, AstNode *identifier, Entity *entity) {
|
||||
@@ -733,6 +735,10 @@ void check_parsed_files(Checker *c) {
|
||||
case_ast_node(ld, LoadDecl, decl);
|
||||
// NOTE(bill): ignore
|
||||
case_end;
|
||||
case_ast_node(fsl, ForeignSystemLibrary, decl);
|
||||
// NOTE(bill): ignore
|
||||
case_end;
|
||||
|
||||
|
||||
default:
|
||||
error(&c->error_collector, ast_node_token(decl), "Only declarations are allowed at file scope");
|
||||
|
||||
+13
-3
@@ -6,6 +6,7 @@ enum BuiltinProcId;
|
||||
ENTITY_KIND(Invalid), \
|
||||
ENTITY_KIND(Constant), \
|
||||
ENTITY_KIND(Variable), \
|
||||
ENTITY_KIND(UsingVariable), \
|
||||
ENTITY_KIND(TypeName), \
|
||||
ENTITY_KIND(Procedure), \
|
||||
ENTITY_KIND(Builtin), \
|
||||
@@ -35,6 +36,7 @@ struct Entity {
|
||||
Token token;
|
||||
Type *type;
|
||||
Entity *using_parent;
|
||||
AstNode *using_expr;
|
||||
|
||||
union {
|
||||
struct { ExactValue value; } Constant;
|
||||
@@ -44,9 +46,9 @@ struct Entity {
|
||||
b8 is_field; // Is struct field
|
||||
b8 anonymous; // Variable is an anonymous
|
||||
} Variable;
|
||||
struct {
|
||||
b8 used;
|
||||
} Procedure;
|
||||
struct {} UsingVariable;
|
||||
struct {} TypeName;
|
||||
struct { b8 used; } Procedure;
|
||||
struct { BuiltinProcId id; } Builtin;
|
||||
};
|
||||
};
|
||||
@@ -72,6 +74,14 @@ Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *typ
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
|
||||
GB_ASSERT(parent != NULL);
|
||||
Entity *entity = alloc_entity(a, Entity_UsingVariable, parent->scope, token, type);
|
||||
entity->using_parent = parent;
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
Entity *make_entity_constant(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value) {
|
||||
Entity *entity = alloc_entity(a, Entity_Constant, scope, token, type);
|
||||
entity->Constant.value = value;
|
||||
|
||||
+23
-5
@@ -4,7 +4,7 @@ void check_expr_or_type (Checker *c, Operand *operand, AstNode *expre
|
||||
ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL);
|
||||
Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL, CycleChecker *cycle_checker = NULL);
|
||||
void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker);
|
||||
void check_selector (Checker *c, Operand *operand, AstNode *node);
|
||||
Entity * check_selector (Checker *c, Operand *operand, AstNode *node);
|
||||
void check_not_tuple (Checker *c, Operand *operand);
|
||||
b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value);
|
||||
void convert_to_typed (Checker *c, Operand *operand, Type *target_type);
|
||||
@@ -143,6 +143,7 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map<Entity *>
|
||||
error(&c->error_collector, e->token, "`%.*s` is already declared in `%s`", LIT(name), str);
|
||||
} else {
|
||||
map_set(entity_map, key, f);
|
||||
add_entity(c, c->context.scope, NULL, f);
|
||||
if (f->Variable.anonymous) {
|
||||
populate_using_entity_map(c, node, f->type, entity_map);
|
||||
}
|
||||
@@ -338,6 +339,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecke
|
||||
} else {
|
||||
map_set(&entity_map, key, e);
|
||||
fields[field_index++] = e;
|
||||
add_entity(c, c->context.scope, name, e);
|
||||
}
|
||||
add_entity_use(&c->info, name, e);
|
||||
}
|
||||
@@ -610,6 +612,11 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
|
||||
o->mode = Addressing_Builtin;
|
||||
break;
|
||||
|
||||
case Entity_UsingVariable:
|
||||
// TODO(bill): Entity_UsingVariable: is this correct?
|
||||
o->mode = Addressing_Variable;
|
||||
break;
|
||||
|
||||
default:
|
||||
GB_PANIC("Compiler error: Unknown EntityKind");
|
||||
break;
|
||||
@@ -727,6 +734,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
|
||||
check_open_scope(c, e);
|
||||
check_struct_type(c, type, e, cycle_checker);
|
||||
check_close_scope(c);
|
||||
type->Struct.node = e;
|
||||
goto end;
|
||||
case_end;
|
||||
|
||||
@@ -736,6 +744,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
|
||||
check_open_scope(c, e);
|
||||
check_union_type(c, type, e, cycle_checker);
|
||||
check_close_scope(c);
|
||||
type->Union.node = e;
|
||||
goto end;
|
||||
case_end;
|
||||
|
||||
@@ -1746,7 +1755,7 @@ Selection lookup_field(Type *type_, String field_name, AddressingMode mode, Sele
|
||||
return sel;
|
||||
}
|
||||
|
||||
void check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
GB_ASSERT(node->kind == AstNode_SelectorExpr);
|
||||
|
||||
ast_node(se, SelectorExpr, node);
|
||||
@@ -1764,7 +1773,7 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
error(&c->error_collector, ast_node_token(op_expr), "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str);
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->expr = node;
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
add_entity_use(&c->info, selector, entity);
|
||||
|
||||
@@ -1779,11 +1788,12 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
if (operand->mode != Addressing_Variable)
|
||||
operand->mode = Addressing_Value;
|
||||
}
|
||||
return entity;
|
||||
} else {
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->expr = node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) {
|
||||
@@ -1886,7 +1896,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->mode = Addressing_Value;
|
||||
operand->mode = Addressing_NoValue;
|
||||
operand->type = NULL;
|
||||
} break;
|
||||
|
||||
@@ -2967,6 +2977,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
case AstNode_ArrayType:
|
||||
case AstNode_VectorType:
|
||||
case AstNode_StructType:
|
||||
case AstNode_UnionType:
|
||||
o->mode = Addressing_Type;
|
||||
o->type = check_type(c, node);
|
||||
break;
|
||||
@@ -3240,6 +3251,13 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
str = gb_string_appendc(str, "}");
|
||||
case_end;
|
||||
|
||||
case_ast_node(st, UnionType, node);
|
||||
str = gb_string_appendc(str, "union{");
|
||||
// str = write_field_list_to_string(str, st->decl_list, ", ");
|
||||
str = gb_string_appendc(str, "}");
|
||||
case_end;
|
||||
|
||||
|
||||
case_ast_node(et, EnumType, node);
|
||||
str = gb_string_appendc(str, "enum ");
|
||||
if (et->base_type != NULL) {
|
||||
|
||||
+198
-110
@@ -436,6 +436,107 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc
|
||||
|
||||
|
||||
|
||||
void check_var_decl(Checker *c, AstNode *node) {
|
||||
ast_node(vd, VarDecl, node);
|
||||
isize entity_count = vd->name_count;
|
||||
isize entity_index = 0;
|
||||
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
||||
switch (vd->kind) {
|
||||
case Declaration_Mutable: {
|
||||
Entity **new_entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
||||
isize new_entity_count = 0;
|
||||
|
||||
for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
|
||||
Entity *entity = NULL;
|
||||
Token token = name->Ident.token;
|
||||
if (name->kind == AstNode_Ident) {
|
||||
String str = token.string;
|
||||
Entity *found = NULL;
|
||||
// NOTE(bill): Ignore assignments to `_`
|
||||
b32 can_be_ignored = are_strings_equal(str, make_string("_"));
|
||||
if (!can_be_ignored) {
|
||||
found = current_scope_lookup_entity(c->context.scope, str);
|
||||
}
|
||||
if (found == NULL) {
|
||||
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
|
||||
if (!can_be_ignored) {
|
||||
new_entities[new_entity_count++] = entity;
|
||||
}
|
||||
add_entity_definition(&c->info, name, entity);
|
||||
} else {
|
||||
entity = found;
|
||||
}
|
||||
} else {
|
||||
error(&c->error_collector, token, "A variable declaration must be an identifier");
|
||||
}
|
||||
if (entity == NULL)
|
||||
entity = make_entity_dummy_variable(c->allocator, c->global_scope, token);
|
||||
entities[entity_index++] = entity;
|
||||
}
|
||||
|
||||
Type *init_type = NULL;
|
||||
if (vd->type) {
|
||||
init_type = check_type(c, vd->type, NULL);
|
||||
if (init_type == NULL)
|
||||
init_type = t_invalid;
|
||||
}
|
||||
|
||||
for (isize i = 0; i < entity_count; i++) {
|
||||
Entity *e = entities[i];
|
||||
GB_ASSERT(e != NULL);
|
||||
if (e->Variable.visited) {
|
||||
e->type = t_invalid;
|
||||
continue;
|
||||
}
|
||||
e->Variable.visited = true;
|
||||
|
||||
if (e->type == NULL)
|
||||
e->type = init_type;
|
||||
}
|
||||
|
||||
check_init_variables(c, entities, entity_count, vd->value_list, vd->value_count, make_string("variable declaration"));
|
||||
|
||||
AstNode *name = vd->name_list;
|
||||
for (isize i = 0; i < new_entity_count; i++, name = name->next) {
|
||||
add_entity(c, c->context.scope, name, new_entities[i]);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case Declaration_Immutable: {
|
||||
for (AstNode *name = vd->name_list, *value = vd->value_list;
|
||||
name != NULL && value != NULL;
|
||||
name = name->next, value = value->next) {
|
||||
GB_ASSERT(name->kind == AstNode_Ident);
|
||||
ExactValue v = {ExactValue_Invalid};
|
||||
ast_node(i, Ident, name);
|
||||
Entity *e = make_entity_constant(c->allocator, c->context.scope, i->token, NULL, v);
|
||||
entities[entity_index++] = e;
|
||||
check_const_decl(c, e, vd->type, value);
|
||||
}
|
||||
|
||||
isize lhs_count = vd->name_count;
|
||||
isize rhs_count = vd->value_count;
|
||||
|
||||
// TODO(bill): Better error messages or is this good enough?
|
||||
if (rhs_count == 0 && vd->type == NULL) {
|
||||
error(&c->error_collector, ast_node_token(node), "Missing type or initial expression");
|
||||
} else if (lhs_count < rhs_count) {
|
||||
error(&c->error_collector, ast_node_token(node), "Extra initial expression");
|
||||
}
|
||||
|
||||
AstNode *name = vd->name_list;
|
||||
for (isize i = 0; i < entity_count; i++, name = name->next) {
|
||||
add_entity(c, c->context.scope, name, entities[i]);
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
error(&c->error_collector, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
switch (node->kind) {
|
||||
@@ -688,16 +789,28 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
case_ast_node(us, UsingStmt, node);
|
||||
switch (us->node->kind) {
|
||||
case_ast_node(es, ExprStmt, us->node);
|
||||
AstNode *ident = es->expr;
|
||||
GB_ASSERT(ident->kind == AstNode_Ident);
|
||||
String name = ident->Ident.token.string;
|
||||
Entity *e = NULL;
|
||||
|
||||
b32 is_selector = false;
|
||||
AstNode *expr = unparen_expr(es->expr);
|
||||
if (expr->kind == AstNode_Ident) {
|
||||
String name = expr->Ident.token.string;
|
||||
e = scope_lookup_entity(c, c->context.scope, name);
|
||||
} else if (expr->kind == AstNode_SelectorExpr) {
|
||||
Operand o = {};
|
||||
check_expr_base(c, &o, expr->SelectorExpr.expr);
|
||||
e = check_selector(c, &o, expr);
|
||||
is_selector = true;
|
||||
}
|
||||
|
||||
Entity *e = scope_lookup_entity(c, c->context.scope, name);
|
||||
if (e == NULL) {
|
||||
error(&c->error_collector, us->token, "`using` applied to an unknown entity");
|
||||
return;
|
||||
}
|
||||
|
||||
gbString expr_str = expr_to_string(expr);
|
||||
defer (gb_string_free(expr_str));
|
||||
|
||||
switch (e->kind) {
|
||||
case Entity_TypeName: {
|
||||
Type *t = get_base_type(e->type);
|
||||
@@ -706,20 +819,34 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
Entity *f = t->Enum.fields[i];
|
||||
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||
if (found != NULL) {
|
||||
error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of the constant: %.*s", LIT(name), LIT(found->token.string));
|
||||
error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of the constant: %.*s", expr_str, LIT(found->token.string));
|
||||
return;
|
||||
}
|
||||
f->using_parent = e;
|
||||
}
|
||||
} else if (t->kind == Type_Struct) {
|
||||
for (isize i = 0; i < t->Struct.other_field_count; i++) {
|
||||
Entity *f = t->Struct.other_fields[i];
|
||||
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||
if (found != NULL) {
|
||||
error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(found->token.string));
|
||||
return;
|
||||
Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node));
|
||||
if (found != NULL) {
|
||||
gb_for_array(i, (*found)->elements.entries) {
|
||||
Entity *f = (*found)->elements.entries[i].value;
|
||||
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||
if (found != NULL) {
|
||||
error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
|
||||
return;
|
||||
}
|
||||
f->using_parent = e;
|
||||
}
|
||||
} else {
|
||||
for (isize i = 0; i < t->Struct.other_field_count; i++) {
|
||||
// TODO(bill): using field types too
|
||||
Entity *f = t->Struct.other_fields[i];
|
||||
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||
if (found != NULL) {
|
||||
error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
|
||||
return;
|
||||
}
|
||||
f->using_parent = e;
|
||||
}
|
||||
f->using_parent = e;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
@@ -733,13 +860,70 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
error(&c->error_collector, us->token, "`using` cannot be applied to a procedure");
|
||||
break;
|
||||
|
||||
case Entity_Variable:
|
||||
case Entity_UsingVariable: {
|
||||
Type *t = get_base_type(type_deref(e->type));
|
||||
if (t->kind == Type_Struct || t->kind == Type_Union) {
|
||||
// IMPORTANT HACK(bill): Entity_(Struct|Union) overlap in some memory allowing
|
||||
// for some variables to accessed to same
|
||||
Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node));
|
||||
GB_ASSERT(found != NULL);
|
||||
gb_for_array(i, (*found)->elements.entries) {
|
||||
Entity *f = (*found)->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
if (is_selector) {
|
||||
uvar->using_expr = expr;
|
||||
}
|
||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||
if (prev != NULL) {
|
||||
error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error(&c->error_collector, us->token, "`using` can only be applied to variables of type struct or union");
|
||||
return;
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
GB_PANIC("TODO(bill): using Ident");
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(vd, VarDecl, us->node);
|
||||
GB_PANIC("TODO(bill): using VarDecl");
|
||||
if (vd->name_count > 1) {
|
||||
error(&c->error_collector, us->token, "`using` can only be applied to one variable of the same type");
|
||||
}
|
||||
check_var_decl(c, us->node);
|
||||
ast_node(i, Ident, vd->name_list);
|
||||
|
||||
String name = i->token.string;
|
||||
Entity *e = scope_lookup_entity(c, c->context.scope, name);
|
||||
|
||||
Type *t = get_base_type(type_deref(e->type));
|
||||
if (t->kind == Type_Struct || t->kind == Type_Union) {
|
||||
// IMPORTANT HACK(bill): Entity_(Struct|Union) overlap in some memory allowing
|
||||
// for some variables to accessed to same
|
||||
Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node));
|
||||
GB_ASSERT(found != NULL);
|
||||
gb_for_array(i, (*found)->elements.entries) {
|
||||
Entity *f = (*found)->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||
if (prev != NULL) {
|
||||
error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error(&c->error_collector, us->token, "`using` can only be applied to variables of type struct or union");
|
||||
return;
|
||||
}
|
||||
case_end;
|
||||
|
||||
|
||||
@@ -755,103 +939,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
|
||||
case_ast_node(vd, VarDecl, node);
|
||||
isize entity_count = vd->name_count;
|
||||
isize entity_index = 0;
|
||||
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
||||
switch (vd->kind) {
|
||||
case Declaration_Mutable: {
|
||||
Entity **new_entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
||||
isize new_entity_count = 0;
|
||||
|
||||
for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
|
||||
Entity *entity = NULL;
|
||||
Token token = name->Ident.token;
|
||||
if (name->kind == AstNode_Ident) {
|
||||
String str = token.string;
|
||||
Entity *found = NULL;
|
||||
// NOTE(bill): Ignore assignments to `_`
|
||||
b32 can_be_ignored = are_strings_equal(str, make_string("_"));
|
||||
if (!can_be_ignored) {
|
||||
found = current_scope_lookup_entity(c->context.scope, str);
|
||||
}
|
||||
if (found == NULL) {
|
||||
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
|
||||
if (!can_be_ignored) {
|
||||
new_entities[new_entity_count++] = entity;
|
||||
}
|
||||
add_entity_definition(&c->info, name, entity);
|
||||
} else {
|
||||
entity = found;
|
||||
}
|
||||
} else {
|
||||
error(&c->error_collector, token, "A variable declaration must be an identifier");
|
||||
}
|
||||
if (entity == NULL)
|
||||
entity = make_entity_dummy_variable(c->allocator, c->global_scope, token);
|
||||
entities[entity_index++] = entity;
|
||||
}
|
||||
|
||||
Type *init_type = NULL;
|
||||
if (vd->type) {
|
||||
init_type = check_type(c, vd->type, NULL);
|
||||
if (init_type == NULL)
|
||||
init_type = t_invalid;
|
||||
}
|
||||
|
||||
for (isize i = 0; i < entity_count; i++) {
|
||||
Entity *e = entities[i];
|
||||
GB_ASSERT(e != NULL);
|
||||
if (e->Variable.visited) {
|
||||
e->type = t_invalid;
|
||||
continue;
|
||||
}
|
||||
e->Variable.visited = true;
|
||||
|
||||
if (e->type == NULL)
|
||||
e->type = init_type;
|
||||
}
|
||||
|
||||
check_init_variables(c, entities, entity_count, vd->value_list, vd->value_count, make_string("variable declaration"));
|
||||
|
||||
AstNode *name = vd->name_list;
|
||||
for (isize i = 0; i < new_entity_count; i++, name = name->next) {
|
||||
add_entity(c, c->context.scope, name, new_entities[i]);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case Declaration_Immutable: {
|
||||
for (AstNode *name = vd->name_list, *value = vd->value_list;
|
||||
name != NULL && value != NULL;
|
||||
name = name->next, value = value->next) {
|
||||
GB_ASSERT(name->kind == AstNode_Ident);
|
||||
ExactValue v = {ExactValue_Invalid};
|
||||
ast_node(i, Ident, name);
|
||||
Entity *e = make_entity_constant(c->allocator, c->context.scope, i->token, NULL, v);
|
||||
entities[entity_index++] = e;
|
||||
check_const_decl(c, e, vd->type, value);
|
||||
}
|
||||
|
||||
isize lhs_count = vd->name_count;
|
||||
isize rhs_count = vd->value_count;
|
||||
|
||||
// TODO(bill): Better error messages or is this good enough?
|
||||
if (rhs_count == 0 && vd->type == NULL) {
|
||||
error(&c->error_collector, ast_node_token(node), "Missing type or initial expression");
|
||||
} else if (lhs_count < rhs_count) {
|
||||
error(&c->error_collector, ast_node_token(node), "Extra initial expression");
|
||||
}
|
||||
|
||||
AstNode *name = vd->name_list;
|
||||
for (isize i = 0; i < entity_count; i++, name = name->next) {
|
||||
add_entity(c, c->context.scope, name, entities[i]);
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
error(&c->error_collector, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST.");
|
||||
return;
|
||||
}
|
||||
check_var_decl(c, node);
|
||||
case_end;
|
||||
|
||||
case_ast_node(pd, ProcDecl, node);
|
||||
|
||||
@@ -107,18 +107,22 @@ struct Type {
|
||||
// Theses are arrays
|
||||
Entity **fields; // Entity_Variable
|
||||
isize field_count; // == offset_count
|
||||
AstNode *node;
|
||||
|
||||
i64 * offsets;
|
||||
b32 are_offsets_set;
|
||||
b32 is_packed;
|
||||
|
||||
Entity **other_fields; // Entity_Constant or Entity_TypeName
|
||||
isize other_field_count;
|
||||
|
||||
} Struct;
|
||||
struct {
|
||||
// IMPORTANT HACK(bill): The positions of fields and field_count
|
||||
// IMPORTANT HACK(bill): The positions of fields, field_count, and node
|
||||
// must be same for Struct and Union
|
||||
Entity **fields; // Entity_Variable
|
||||
isize field_count;
|
||||
AstNode *node;
|
||||
} Union;
|
||||
struct { Type *elem; } Pointer;
|
||||
struct {
|
||||
|
||||
Reference in New Issue
Block a user