aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2016-08-30 00:04:14 +0100
committerGinger Bill <bill@gingerbill.org>2016-08-30 00:04:14 +0100
commit0eaf7bd830dcda6e00f80eefed36bdf7beb02d5d (patch)
tree3e65c52384458031b5ede490429c9c1938d8ba0b /src
parent593563d8eabf725ac851f4c3c72cd32b5a71aa7c (diff)
Begin "Everything's a namespace"
Diffstat (limited to 'src')
-rw-r--r--src/checker/checker.cpp49
-rw-r--r--src/checker/entity.cpp1
-rw-r--r--src/checker/expr.cpp331
-rw-r--r--src/checker/stmt.cpp69
-rw-r--r--src/checker/type.cpp3
-rw-r--r--src/codegen/codegen.cpp8
-rw-r--r--src/codegen/print_llvm.cpp25
-rw-r--r--src/codegen/ssa.cpp42
-rw-r--r--src/parser.cpp179
-rw-r--r--src/printer.cpp2
10 files changed, 530 insertions, 179 deletions
diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp
index 5bb2e53bb..717c70b57 100644
--- a/src/checker/checker.cpp
+++ b/src/checker/checker.cpp
@@ -2,19 +2,29 @@
#include "entity.cpp"
#include "type.cpp"
-enum AddressingMode {
- Addressing_Invalid,
+#define ADDRESSING_KINDS \
+ ADDRESSING_MODE(Invalid), \
+ ADDRESSING_MODE(NoValue), \
+ ADDRESSING_MODE(Value), \
+ ADDRESSING_MODE(Variable), \
+ ADDRESSING_MODE(Constant), \
+ ADDRESSING_MODE(Type), \
+ ADDRESSING_MODE(Builtin), \
+ ADDRESSING_MODE(Count), \
- Addressing_NoValue,
- Addressing_Value,
- Addressing_Variable,
- Addressing_Constant,
- Addressing_Type,
- Addressing_Builtin,
+enum AddressingMode {
+#define ADDRESSING_MODE(x) GB_JOIN2(Addressing_, x)
+ ADDRESSING_KINDS
+#undef ADDRESSING_MODE
+};
- Addressing_Count,
+String const addressing_mode_strings[] = {
+#define ADDRESSING_MODE(x) {cast(u8 *)#x, gb_size_of(#x)-1}
+ ADDRESSING_KINDS
+#undef ADDRESSING_MODE
};
+
struct Operand {
AddressingMode mode;
Type *type;
@@ -261,7 +271,7 @@ void add_scope(Checker *c, AstNode *node, Scope *scope) {
void check_open_scope(Checker *c, AstNode *stmt) {
- GB_ASSERT(is_ast_node_stmt(stmt) || stmt->kind == AstNode_ProcType);
+ GB_ASSERT(is_ast_node_stmt(stmt) || is_ast_node_type(stmt));
Scope *scope = make_scope(c->context.scope, c->allocator);
add_scope(c, stmt, scope);
if (stmt->kind == AstNode_ProcType) {
@@ -524,11 +534,20 @@ void 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) {
- 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);
+ Entity *up = insert_entity->using_parent;
+ if (up != NULL) {
+ error(&c->error_collector, entity->token,
+ "Redeclararation of `%.*s` in this scope through `using`\n"
+ "\tat %.*s(%td:%td)",
+ LIT(entity->token.string),
+ LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
+ } 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;
}
}
diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp
index 339eda248..de4095766 100644
--- a/src/checker/entity.cpp
+++ b/src/checker/entity.cpp
@@ -34,6 +34,7 @@ struct Entity {
Scope *scope;
Token token;
Type *type;
+ Entity *using_parent;
union {
struct { ExactValue value; } Constant;
diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp
index 2319131bc..c252871a8 100644
--- a/src/checker/expr.cpp
+++ b/src/checker/expr.cpp
@@ -3,6 +3,7 @@ void check_multi_expr (Checker *c, Operand *operand, AstNode *expre
void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression);
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);
void check_not_tuple (Checker *c, Operand *operand);
b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value);
@@ -202,24 +203,166 @@ void check_fields(Checker *c, AstNode *node,
}
}
+void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr);
+
void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecker *cycle_checker) {
GB_ASSERT(node->kind == AstNode_StructType);
GB_ASSERT(struct_type->kind == Type_Struct);
ast_node(st, StructType, node);
isize field_count = 0;
- for (AstNode *field = st->field_list; field != NULL; field = field->next) {
- for (AstNode *name = field->Field.name_list; name != NULL; name = name->next) {
- GB_ASSERT(name->kind == AstNode_Ident);
- field_count++;
+ isize other_field_count = 0;
+ for (AstNode *decl = st->decl_list; decl != NULL; decl = decl->next) {
+ switch (decl->kind) {
+ case_ast_node(vd, VarDecl, decl);
+ if (vd->kind == Declaration_Mutable) {
+ field_count += vd->name_count;
+ } else {
+ other_field_count += vd->name_count;
+ }
+ case_end;
+
+ case_ast_node(td, TypeDecl, decl);
+ other_field_count += 1;
+ case_end;
+ }
+ }
+
+ Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count);
+
+ Map<Entity *> entity_map = {};
+ map_init(&entity_map, gb_heap_allocator());
+ defer (map_destroy(&entity_map));
+
+ Entity **other_fields = gb_alloc_array(c->allocator, Entity *, other_field_count);
+ isize other_field_index = 0;
+ // TODO(bill): Random declarations with DeclInfo
+#if 0
+ Entity *e;
+ DeclInfo *d;d
+ check_entity_decl(c, e, d, NULL);
+#endif
+ for (AstNode *decl = st->decl_list; decl != NULL; decl = decl->next) {
+ if (decl->kind == AstNode_VarDecl) {
+ ast_node(vd, VarDecl, decl);
+ if (vd->kind != Declaration_Immutable)
+ continue;
+
+ isize entity_count = vd->name_count;
+ isize entity_index = 0;
+ Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
+
+ 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);
+ Token name_token = i->token;
+ Entity *e = make_entity_constant(c->allocator, c->context.scope, name_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) {
+ Entity *e = entities[i];
+ Token name_token = name->Ident.token;
+ HashKey key = hash_string(name_token.string);
+ if (map_get(&entity_map, key) != NULL) {
+ // TODO(bill): Scope checking already checks the declaration
+ error(&c->error_collector, name_token, "`%.*s` is already declared in this structure", LIT(name_token.string));
+ } else {
+ map_set(&entity_map, key, e);
+ other_fields[other_field_index++] = e;
+ }
+ add_entity(c, c->context.scope, name, e);
+ }
+ } else if (decl->kind == AstNode_TypeDecl) {
+ ast_node(td, TypeDecl, decl);
+ ast_node(name, Ident, td->name);
+ Token name_token = name->token;
+
+ Entity *e = make_entity_type_name(c->allocator, c->context.scope, name->token, NULL);
+ check_type_decl(c, e, td->type, NULL, NULL);
+ add_entity(c, c->context.scope, td->name, e);
+
+ HashKey key = hash_string(name_token.string);
+ if (map_get(&entity_map, key) != NULL) {
+ // TODO(bill): Scope checking already checks the declaration
+ error(&c->error_collector, name_token, "`%.*s` is already declared in this structure", LIT(name_token.string));
+ } else {
+ map_set(&entity_map, key, e);
+ other_fields[other_field_index++] = e;
+ }
+ add_entity_use(&c->info, td->name, e);
}
+
}
- Entity **fields = gb_alloc_array(c->allocator, Entity *, st->field_count);
- check_fields(c, node, st->field_list, fields, field_count, cycle_checker, make_string("structure"));
- struct_type->Struct.fields = fields;
- struct_type->Struct.field_count = field_count;
- struct_type->Struct.is_packed = st->is_packed;
+ isize field_index = 0;
+ for (AstNode *decl = st->decl_list; decl != NULL; decl = decl->next) {
+ if (decl->kind != AstNode_VarDecl)
+ continue;
+ ast_node(vd, VarDecl, decl);
+ if (vd->kind != Declaration_Mutable)
+ continue;
+ Type *type = check_type(c, vd->type, NULL, cycle_checker);
+
+ if (vd->is_using) {
+ if (vd->name_count > 1) {
+ error(&c->error_collector, ast_node_token(vd->name_list),
+ "Cannot apply `using` to more than one of the same type");
+ }
+ }
+
+ for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
+ ast_node(i, Ident, name);
+ Token name_token = i->token;
+
+ Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, vd->is_using);
+ HashKey key = hash_string(name_token.string);
+ if (map_get(&entity_map, key) != NULL) {
+ // TODO(bill): Scope checking already checks the declaration
+ error(&c->error_collector, name_token, "`%.*s` is already declared in this structure", LIT(name_token.string));
+ } else {
+ map_set(&entity_map, key, e);
+ fields[field_index++] = e;
+ }
+ add_entity_use(&c->info, name, e);
+ }
+
+
+ if (vd->is_using) {
+ Type *t = get_base_type(type_deref(type));
+ if (t->kind != Type_Struct &&
+ t->kind != Type_Union) {
+ Token name_token = vd->name_list->Ident.token;
+ error(&c->error_collector, name_token, "`using` on a field `%.*s` must be a structure or union", LIT(name_token.string));
+ continue;
+ }
+
+ populate_using_entity_map(c, node, type, &entity_map);
+ }
+ }
+
+
+
+ struct_type->Struct.is_packed = st->is_packed;
+ struct_type->Struct.fields = fields;
+ struct_type->Struct.field_count = field_count;
+ struct_type->Struct.other_fields = other_fields;
+ struct_type->Struct.other_field_count = other_field_count;
}
void check_union_type(Checker *c, Type *union_type, AstNode *node, CycleChecker *cycle_checker) {
@@ -235,7 +378,7 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node, CycleChecker
}
}
- Entity **fields = gb_alloc_array(c->allocator, Entity *, ut->field_count);
+ Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count);
check_fields(c, node, ut->field_list, fields, field_count, cycle_checker, make_string("union"));
union_type->Union.fields = fields;
union_type->Union.field_count = field_count;
@@ -533,7 +676,13 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
case_ast_node(se, SelectorExpr, e);
Operand o = {};
+ o.mode = Addressing_Type;
+ o.type = check_type(c, se->expr, named_type, cycle_checker);
+ // gb_printf_err("mode: %.*s\n", LIT(addressing_mode_strings[o.mode]));
check_selector(c, &o, e);
+ // gb_printf_err("%s.%s\n", expr_to_string(se->expr), expr_to_string(se->selector));
+ // gb_printf_err("%s\n", type_to_string(o.type));
+ // gb_printf_err("mode: %.*s\n", LIT(addressing_mode_strings[o.mode]));
if (o.mode == Addressing_Type) {
set_base_type(type, o.type);
@@ -575,14 +724,18 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
case_ast_node(st, StructType, e);
type = make_type_struct(c->allocator);
set_base_type(named_type, type);
+ check_open_scope(c, e);
check_struct_type(c, type, e, cycle_checker);
+ check_close_scope(c);
goto end;
case_end;
case_ast_node(st, UnionType, e);
type = make_type_union(c->allocator);
set_base_type(named_type, type);
+ check_open_scope(c, e);
check_union_type(c, type, e, cycle_checker);
+ check_close_scope(c);
goto end;
case_end;
@@ -1493,7 +1646,7 @@ void selection_add_index(Selection *s, isize index) {
gb_array_append(s->index, index);
}
-Selection lookup_field(Type *type_, String field_name, Selection sel = empty_selection) {
+Selection lookup_field(Type *type_, String field_name, AddressingMode mode, Selection sel = empty_selection) {
GB_ASSERT(type_ != NULL);
if (are_strings_equal(field_name, make_string("_"))) {
@@ -1506,32 +1659,45 @@ Selection lookup_field(Type *type_, String field_name, Selection sel = empty_sel
switch (type->kind) {
case Type_Struct:
- for (isize i = 0; i < type->Struct.field_count; i++) {
- Entity *f = type->Struct.fields[i];
- GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
- String str = f->token.string;
- if (are_strings_equal(field_name, str)) {
- selection_add_index(&sel, i);
- sel.entity = f;
- return sel;
+ if (mode == Addressing_Type) {
+ for (isize i = 0; i < type->Struct.other_field_count; i++) {
+ Entity *f = type->Struct.other_fields[i];
+ GB_ASSERT(f->kind != Entity_Variable);
+ String str = f->token.string;
+ if (are_strings_equal(field_name, str)) {
+ selection_add_index(&sel, i);
+ sel.entity = f;
+ return sel;
+ }
}
-
- if (f->Variable.anonymous) {
- isize prev_count = 0;
- if (sel.index != NULL) {
- prev_count = gb_array_count(sel.index);
+ } else {
+ for (isize i = 0; i < type->Struct.field_count; i++) {
+ Entity *f = type->Struct.fields[i];
+ GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
+ String str = f->token.string;
+ if (are_strings_equal(field_name, str)) {
+ selection_add_index(&sel, i);
+ sel.entity = f;
+ return sel;
}
- selection_add_index(&sel, i); // HACK(bill): Leaky memory
- sel = lookup_field(f->type, field_name, sel);
+ if (f->Variable.anonymous) {
+ isize prev_count = 0;
+ if (sel.index != NULL) {
+ prev_count = gb_array_count(sel.index);
+ }
+ selection_add_index(&sel, i); // HACK(bill): Leaky memory
- if (sel.entity != NULL) {
- // gb_printf("%.*s, %.*s, %.*s\n", LIT(field_name), LIT(str), LIT(sel.entity->token.string));
- if (is_type_pointer(f->type))
- sel.indirect = true;
- return sel;
+ sel = lookup_field(f->type, field_name, mode, sel);
+
+ if (sel.entity != NULL) {
+ // gb_printf("%.*s, %.*s, %.*s\n", LIT(field_name), LIT(str), LIT(sel.entity->token.string));
+ if (is_type_pointer(f->type))
+ sel.indirect = true;
+ return sel;
+ }
+ gb_array_count(sel.index) = prev_count;
}
- gb_array_count(sel.index) = prev_count;
}
}
break;
@@ -1553,7 +1719,7 @@ Selection lookup_field(Type *type_, String field_name, Selection sel = empty_sel
String str = f->token.string;
if (f->Variable.anonymous) {
selection_add_index(&sel, i); // HACK(bill): Leaky memory
- sel = lookup_field(f->type, field_name, sel);
+ sel = lookup_field(f->type, field_name, mode, sel);
if (sel.entity != NULL && is_type_pointer(f->type)) {
sel.indirect = true;
}
@@ -1563,67 +1729,21 @@ Selection lookup_field(Type *type_, String field_name, Selection sel = empty_sel
break;
case Type_Enum:
- for (isize i = 0; i < type->Enum.field_count; i++) {
- Entity *f = type->Enum.fields[i];
- GB_ASSERT(f->kind == Entity_Constant);
- String str = f->token.string;
- if (are_strings_equal(field_name, str)) {
- // Enums are constant expression
- return make_selection(f, NULL, i);
+ if (mode == Addressing_Type) {
+ for (isize i = 0; i < type->Enum.field_count; i++) {
+ Entity *f = type->Enum.fields[i];
+ GB_ASSERT(f->kind == Entity_Constant);
+ String str = f->token.string;
+ if (are_strings_equal(field_name, str)) {
+ // Enums are constant expression
+ return make_selection(f, NULL, i);
+ }
}
}
break;
}
return sel;
-
-/*
- switch (type->kind) {
- case Type_Struct:
- for (isize i = 0; i < type->Struct.field_count; i++) {
- Entity *f = type->Struct.fields[i];
- GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
- String str = f->token.string;
- if (are_strings_equal(field_name, str)) {
- make_selection()
- FoundField ff = {f, i, offset+field_offset};
- return ff;
- }
- if (f->Variable.anonymous) {
- return lookup_field(f->type, field_node, offset+field_offset);
- }
- }
- break;
-
- case Type_Union:
- for (isize i = 0; i < type->Union.field_count; i++) {
- Entity *f = type->Union.fields[i];
- GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
- String str = f->token.string;
- if (are_strings_equal(field_name, str)) {
- if (index) *index = i;
- return f;
- }
- }
- break;
-
- case Type_Enum:
- for (isize i = 0; i < type->Enum.field_count; i++) {
- Entity *f = type->Enum.fields[i];
- GB_ASSERT(f->kind == Entity_Constant);
- String str = f->token.string;
- if (are_strings_equal(field_name, str)) {
- if (index) *index = i;
- return f;
- }
- }
- break;
- // TODO(bill): Other types and extra "hidden" fields (e.g. introspection stuff)
- // TODO(bill): Allow for access of field through index? e.g. `x.3` will get member of index 3
- // Or is this only suitable if tuples are first-class?
- }
-
-*/
}
void check_selector(Checker *c, Operand *operand, AstNode *node) {
@@ -1633,34 +1753,29 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) {
AstNode *op_expr = se->expr;
AstNode *selector = se->selector;
if (selector) {
- Entity *entity = NULL;
- if (is_type_enum(operand->type)) {
- if (operand->mode == Addressing_Type) {
- entity = lookup_field(operand->type, selector->Ident.token.string).entity;
- }
- } else {
- entity = lookup_field(operand->type, selector->Ident.token.string).entity;
- }
+ Entity *entity = lookup_field(operand->type, selector->Ident.token.string, operand->mode).entity;
if (entity == NULL) {
- gbString op_str = expr_to_string(op_expr);
- gbString sel_str = expr_to_string(selector);
+ gbString op_str = expr_to_string(op_expr);
+ gbString type_str = type_to_string(operand->type);
+ gbString sel_str = expr_to_string(selector);
defer (gb_string_free(op_str));
+ defer (gb_string_free(type_str));
defer (gb_string_free(sel_str));
- error(&c->error_collector, ast_node_token(op_expr), "`%s` has no field `%s`", op_str, sel_str);
+ 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;
}
add_entity_use(&c->info, selector, entity);
- if (is_type_enum(operand->type)) {
- operand->type = entity->type;
- operand->expr = node;
+ operand->type = entity->type;
+ operand->expr = node;
+ if (entity->kind == Entity_Constant) {
operand->mode = Addressing_Constant;
operand->value = entity->Constant.value;
+ } else if (entity->kind == Entity_TypeName) {
+ operand->mode = Addressing_Type;
} else {
- operand->type = entity->type;
- operand->expr = node;
if (operand->mode != Addressing_Variable)
operand->mode = Addressing_Value;
}
@@ -1841,7 +1956,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
ast_node(arg, Ident, field_arg);
- Selection sel = lookup_field(type, arg->token.string);
+ Selection sel = lookup_field(type, arg->token.string, operand->mode);
if (sel.entity == NULL) {
gbString type_str = type_to_string(type);
error(&c->error_collector, ast_node_token(ce->arg_list),
@@ -1878,7 +1993,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
ast_node(i, Ident, s->selector);
- Selection sel = lookup_field(type, i->token.string);
+ Selection sel = lookup_field(type, i->token.string, operand->mode);
if (sel.entity == NULL) {
gbString type_str = type_to_string(type);
error(&c->error_collector, ast_node_token(arg),
@@ -2504,7 +2619,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
}
String name = kv->field->Ident.token.string;
- Selection sel = lookup_field(type, kv->field->Ident.token.string);
+ Selection sel = lookup_field(type, kv->field->Ident.token.string, o->mode);
if (sel.entity == NULL) {
error(&c->error_collector, ast_node_token(elem),
"Unknown field `%.*s` in structure literal", LIT(name));
@@ -3121,7 +3236,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
case_ast_node(st, StructType, node);
str = gb_string_appendc(str, "struct{");
- str = write_field_list_to_string(str, st->field_list, ", ");
+ // str = write_field_list_to_string(str, st->decl_list, ", ");
str = gb_string_appendc(str, "}");
case_end;
diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp
index 9e54a73e3..a0d1838a8 100644
--- a/src/checker/stmt.cpp
+++ b/src/checker/stmt.cpp
@@ -685,6 +685,75 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
}
case_end;
+ 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 = scope_lookup_entity(c, c->context.scope, name);
+ if (e == NULL) {
+ error(&c->error_collector, us->token, "`using` applied to an unknown entity");
+ return;
+ }
+
+ switch (e->kind) {
+ case Entity_TypeName: {
+ Type *t = get_base_type(e->type);
+ if (t->kind == Type_Enum) {
+ for (isize i = 0; i < t->Enum.field_count; i++) {
+ 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));
+ 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;
+ }
+ f->using_parent = e;
+ }
+ }
+ } break;
+
+ case Entity_Constant:
+ error(&c->error_collector, us->token, "`using` cannot be applied to a constant");
+ break;
+
+ case Entity_Procedure:
+ case Entity_Builtin:
+ error(&c->error_collector, us->token, "`using` cannot be applied to a procedure");
+ break;
+
+ default:
+ GB_PANIC("TODO(bill): using Ident");
+ }
+ case_end;
+
+ case_ast_node(vd, VarDecl, us->node);
+ GB_PANIC("TODO(bill): using VarDecl");
+ case_end;
+
+
+ default:
+ error(&c->error_collector, us->token, "Invalid AST: Using Statement");
+ break;
+ }
+ case_end;
+
+
+
+
+
+
case_ast_node(vd, VarDecl, node);
isize entity_count = vd->name_count;
isize entity_index = 0;
diff --git a/src/checker/type.cpp b/src/checker/type.cpp
index 26bb2dc40..bd1ff223e 100644
--- a/src/checker/type.cpp
+++ b/src/checker/type.cpp
@@ -110,6 +110,9 @@ struct Type {
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
diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp
index 795d43a07..88260be8c 100644
--- a/src/codegen/codegen.cpp
+++ b/src/codegen/codegen.cpp
@@ -70,11 +70,9 @@ void ssa_gen_code(ssaGen *s) {
String name = e->token.string;
switch (e->kind) {
- case Entity_TypeName: {
- ssaValue *t = ssa_make_value_type_name(a, e->token.string, e->type);
- map_set(&m->values, hash_pointer(e), t);
- map_set(&m->members, hash_string(name), t);
- } break;
+ case Entity_TypeName:
+ ssa_gen_global_type_name(m, e, name);
+ break;
case Entity_Variable: {
ssaValue *g = ssa_make_value_global(a, e, NULL);
diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp
index c5571712c..689b19ac8 100644
--- a/src/codegen/print_llvm.cpp
+++ b/src/codegen/print_llvm.cpp
@@ -169,7 +169,11 @@ void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) {
ssa_fprintf(f, "*");
break;
case Type_Named:
- ssa_print_encoded_local(f, t->Named.name);
+ if (get_base_type(t)->kind == Type_Struct) {
+ ssa_print_encoded_local(f, t->Named.name);
+ } else {
+ ssa_print_type(f, s, get_base_type(t));
+ }
break;
case Type_Tuple:
if (t->Tuple.variable_count == 1) {
@@ -748,13 +752,15 @@ void ssa_print_proc(gbFile *f, ssaModule *m, ssaProcedure *proc) {
void ssa_print_type_name(gbFile *f, ssaModule *m, ssaValue *v) {
GB_ASSERT(v->kind == ssaValue_TypeName);
+ Type *base_type = get_base_type(ssa_type(v));
+ if (base_type->kind != Type_Struct)
+ return;
ssa_print_encoded_local(f, v->TypeName.name);
ssa_fprintf(f, " = type ");
ssa_print_type(f, m->sizes, get_base_type(v->TypeName.type));
ssa_fprintf(f, "\n");
}
-
void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
if (m->layout.len > 0) {
ssa_fprintf(f, "target datalayout = \"%.*s\"\n", LIT(m->layout));
@@ -772,21 +778,12 @@ void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
auto *entry = &m->members.entries[member_index];
ssaValue *v = entry->value;
switch (v->kind) {
- case ssaValue_TypeName: {
- ssa_print_encoded_local(f, v->TypeName.name);
- ssa_fprintf(f, " = type ");
- ssa_print_type(f, m->sizes, get_base_type(v->TypeName.type));
- ssa_fprintf(f, "\n");
- } break;
+ case ssaValue_TypeName:
+ ssa_print_type_name(f, m, v);
+ break;
}
}
- gb_for_array(i, m->nested_type_names) {
- ssaValue *v = m->nested_type_names[i];
- ssa_print_type_name(f, m, v);
- }
-
-
gb_for_array(member_index, m->members.entries) {
auto *entry = &m->members.entries[member_index];
ssaValue *v = entry->value;
diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp
index d52aff90d..bf2470a28 100644
--- a/src/codegen/ssa.cpp
+++ b/src/codegen/ssa.cpp
@@ -14,7 +14,6 @@ struct ssaModule {
Map<ssaValue *> values; // Key: Entity *
Map<ssaValue *> members; // Key: String
- gbArray(ssaValue *) nested_type_names; // ssaValue_TypeName
i32 global_string_index;
};
@@ -308,13 +307,11 @@ void ssa_module_init(ssaModule *m, Checker *c) {
map_init(&m->values, m->allocator);
map_init(&m->members, m->allocator);
- gb_array_init(m->nested_type_names, m->allocator);
}
void ssa_module_destroy(ssaModule *m) {
map_destroy(&m->values);
map_destroy(&m->members);
- gb_array_free(m->nested_type_names);
gb_arena_free(&m->arena);
}
@@ -1606,7 +1603,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
if (elem->kind == AstNode_FieldValue) {
ast_node(kv, FieldValue, elem);
- Selection sel = lookup_field(base_type, kv->field->Ident.token.string);
+ Selection sel = lookup_field(base_type, kv->field->Ident.token.string, Addressing_Value);
field_index = sel.index[0];
field_expr = ssa_build_expr(proc, kv->value);
} else {
@@ -2063,7 +2060,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
case_ast_node(se, SelectorExpr, expr);
Type *type = get_base_type(type_of_expr(proc->module->info, se->expr));
- Selection sel = lookup_field(type, unparen_expr(se->selector)->Ident.token.string);
+ Selection sel = lookup_field(type, unparen_expr(se->selector)->Ident.token.string, Addressing_Value);
GB_ASSERT(sel.entity != NULL);
ssaValue *e = ssa_build_addr(proc, se->expr).addr;
@@ -2248,6 +2245,36 @@ void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssa
}
+void ssa_gen_global_type_name(ssaModule *m, Entity *e, String name) {
+ ssaValue *t = ssa_make_value_type_name(m->allocator, name, e->type);
+ map_set(&m->values, hash_pointer(e), t);
+ map_set(&m->members, hash_string(name), t);
+
+ Type *bt = get_base_type(e->type);
+ if (bt->kind == Type_Struct) {
+ auto *s = &bt->Struct;
+ for (isize j = 0; j < s->other_field_count; j++) {
+ Entity *field = s->other_fields[j];
+ if (field->kind == Entity_TypeName) {
+ // HACK(bill): Override name of type so printer prints it correctly
+ auto *tn = &field->type->Named;
+ String cn = field->token.string;
+ isize len = name.len + 1 + cn.len;
+ String child = {NULL, len};
+ child.text = gb_alloc_array(m->allocator, u8, len);
+ isize i = 0;
+ gb_memcopy(child.text+i, name.text, name.len);
+ i += name.len;
+ child.text[i++] = '.';
+ gb_memcopy(child.text+i, cn.text, cn.len);
+ tn->name = child;
+ ssa_gen_global_type_name(m, field, tn->name);
+ }
+ }
+ }
+}
+
+
void ssa_build_stmt_list(ssaProcedure *proc, AstNode *list) {
for (AstNode *stmt = list ; stmt != NULL; stmt = stmt->next)
@@ -2389,7 +2416,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
String td_name = td->name->Ident.token.string;
isize name_len = proc->name.len + 1 + td_name.len + 1 + 10 + 1;
u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
- i32 guid = cast(i32)gb_array_count(proc->module->nested_type_names);
+ i32 guid = cast(i32)gb_array_count(proc->module->members.entries);
name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(td_name), guid);
String name = make_string(name_text, name_len-1);
@@ -2400,8 +2427,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
name, e->type);
// HACK(bill): Override name of type so printer prints it correctly
e->type->Named.name = name;
- ssa_module_add_value(proc->module, e, value);
- gb_array_append(proc->module->nested_type_names, value);
+ ssa_gen_global_type_name(proc->module, e, name);
case_end;
case_ast_node(ids, IncDecStmt, node);
diff --git a/src/parser.cpp b/src/parser.cpp
index a79cae37e..e3be11940 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -169,6 +169,7 @@ AST_NODE_KIND(_ComplexStmtBegin, struct{}) \
}) \
AST_NODE_KIND(DeferStmt, struct { Token token; AstNode *stmt; }) \
AST_NODE_KIND(BranchStmt, struct { Token token; }) \
+ AST_NODE_KIND(UsingStmt, struct { Token token; AstNode *node; }) \
\
AST_NODE_KIND(_ComplexStmtEnd, struct{}) \
AST_NODE_KIND(_StmtEnd, struct{}) \
@@ -177,6 +178,7 @@ AST_NODE_KIND(_DeclBegin, struct{}) \
AST_NODE_KIND(VarDecl, struct { \
DeclKind kind; \
u32 tags; \
+ b32 is_using; \
AstNode *name_list; \
AstNode *type; \
AstNode *value_list; \
@@ -222,8 +224,8 @@ AST_NODE_KIND(_TypeBegin, struct{}) \
}) \
AST_NODE_KIND(StructType, struct { \
Token token; \
- AstNode *field_list; \
- isize field_count; \
+ AstNode *decl_list; \
+ isize decl_count; \
b32 is_packed; \
}) \
AST_NODE_KIND(UnionType, struct { \
@@ -354,6 +356,8 @@ Token ast_node_token(AstNode *node) {
return node->DeferStmt.token;
case AstNode_BranchStmt:
return node->BranchStmt.token;
+ case AstNode_UsingStmt:
+ return node->UsingStmt.token;
case AstNode_BadDecl:
return node->BadDecl.begin;
case AstNode_VarDecl:
@@ -707,6 +711,13 @@ gb_inline AstNode *make_branch_stmt(AstFile *f, Token token) {
return result;
}
+gb_inline AstNode *make_using_stmt(AstFile *f, Token token, AstNode *node) {
+ AstNode *result = make_node(f, AstNode_UsingStmt);
+ result->UsingStmt.token = token;
+ result->UsingStmt.node = node;
+ return result;
+}
+
gb_inline AstNode *make_bad_decl(AstFile *f, Token begin, Token end) {
AstNode *result = make_node(f, AstNode_BadDecl);
@@ -778,11 +789,11 @@ gb_inline AstNode *make_vector_type(AstFile *f, Token token, AstNode *count, Ast
return result;
}
-gb_inline AstNode *make_struct_type(AstFile *f, Token token, AstNode *field_list, isize field_count, b32 is_packed) {
+gb_inline AstNode *make_struct_type(AstFile *f, Token token, AstNode *decl_list, isize decl_count, b32 is_packed) {
AstNode *result = make_node(f, AstNode_StructType);
result->StructType.token = token;
- result->StructType.field_list = field_list;
- result->StructType.field_count = field_count;
+ result->StructType.decl_list = decl_list;
+ result->StructType.decl_count = decl_count;
result->StructType.is_packed = is_packed;
return result;
}
@@ -938,6 +949,32 @@ void fix_advance_to_next_stmt(AstFile *f) {
#endif
}
+b32 expect_semicolon_after_stmt(AstFile *f, AstNode *s) {
+ if (s != NULL) {
+ switch (s->kind) {
+ case AstNode_ProcDecl:
+ return true;
+ case AstNode_TypeDecl: {
+ switch (s->TypeDecl.type->kind) {
+ case AstNode_StructType:
+ case AstNode_UnionType:
+ case AstNode_EnumType:
+ case AstNode_ProcType:
+ return true;
+ }
+ } break;
+ }
+ }
+
+ if (!allow_token(f, Token_Semicolon)) {
+ // CLEANUP(bill): Semicolon handling in parser
+ ast_file_err(f, f->cursor[0],
+ "Expected `;` after %.*s, got `%.*s`",
+ LIT(ast_node_strings[s->kind]), LIT(token_strings[f->cursor[0].kind]));
+ return false;
+ }
+ return true;
+}
AstNode *parse_expr(AstFile *f, b32 lhs);
@@ -1211,6 +1248,7 @@ b32 is_literal_type(AstNode *node) {
switch (node->kind) {
case AstNode_BadExpr:
case AstNode_Ident:
+ case AstNode_SelectorExpr:
case AstNode_ArrayType:
case AstNode_VectorType:
case AstNode_StructType:
@@ -1652,10 +1690,19 @@ AstNode *parse_parameter_list(AstFile *f, AstScope *scope, isize *param_count_,
return param_list;
}
+
AstNode *parse_identifier_or_type(AstFile *f) {
switch (f->cursor[0].kind) {
- case Token_Identifier:
- return parse_identifier(f);
+ case Token_Identifier: {
+ AstNode *ident = parse_identifier(f);
+ while (f->cursor[0].kind == Token_Period) {
+ Token token = f->cursor[0];
+ next_token(f);
+ AstNode *sel = parse_identifier(f);
+ ident = make_selector_expr(f, token, ident, sel);
+ }
+ return ident;
+ }
case Token_Pointer:
return make_pointer_type(f, expect_token(f, Token_Pointer), parse_type(f));
@@ -1687,10 +1734,6 @@ AstNode *parse_identifier_or_type(AstFile *f) {
case Token_struct: {
Token token = expect_token(f, Token_struct);
- Token open, close;
- AstNode *params = NULL;
- isize param_count = 0;
- AstScope *scope = make_ast_scope(f, NULL); // NOTE(bill): The struct needs its own scope with NO parent
b32 is_packed = false;
if (allow_token(f, Token_Hash)) {
Token tag = expect_token(f, Token_Identifier);
@@ -1701,12 +1744,72 @@ AstNode *parse_identifier_or_type(AstFile *f) {
}
}
- open = expect_token(f, Token_OpenBrace);
- params = parse_parameter_list(f, scope, &param_count, Token_Semicolon, true);
- close = expect_token(f, Token_CloseBrace);
+ AstScope *scope = make_ast_scope(f, NULL); // NOTE(bill): The struct needs its own scope with NO parent
+ AstScope *curr_scope = f->curr_scope;
+ f->curr_scope = scope;
+ defer (f->curr_scope = curr_scope);
- return make_struct_type(f, token, params, param_count, is_packed);
- }
+
+ Token open = expect_token(f, Token_OpenBrace);
+ AstNode *decls = NULL;
+ AstNode *decls_curr = NULL;
+ isize decl_count = 0;
+
+ while (f->cursor[0].kind == Token_Identifier ||
+ f->cursor[0].kind == Token_using) {
+ b32 is_using = false;
+ if (allow_token(f, Token_using)) {
+ is_using = true;
+ }
+ isize name_count = 0;
+ AstNode *name_list = parse_lhs_expr_list(f, &name_count);
+ if (name_count == 0) {
+ ast_file_err(f, f->cursor[0], "Empty field declaration");
+ }
+
+ if (name_count > 1 && is_using) {
+ ast_file_err(f, f->cursor[0], "Cannot apply `using` to more than one of the same type");
+ }
+
+ AstNode *decl = NULL;
+
+ if (f->cursor[0].kind == Token_Colon) {
+ decl = parse_decl(f, name_list, name_count);
+
+ if (decl->kind == AstNode_ProcDecl) {
+ ast_file_err(f, f->cursor[0], "Procedure declarations are not allowed within a structure");
+ decl = make_bad_decl(f, ast_node_token(name_list), f->cursor[0]);
+ }
+ } else {
+ ast_file_err(f, f->cursor[0], "Illegal structure field");
+ decl = make_bad_decl(f, ast_node_token(name_list), f->cursor[0]);
+ }
+
+ expect_semicolon_after_stmt(f, decl);
+
+ if (decl != NULL && is_ast_node_decl(decl)) {
+ DLIST_APPEND(decls, decls_curr, decl);
+ if (decl->kind == AstNode_VarDecl) {
+ decl_count += decl->VarDecl.name_count;
+ decl->VarDecl.is_using = is_using;
+
+ if (decl->VarDecl.kind == Declaration_Mutable) {
+ if (decl->VarDecl.value_count > 0) {
+ ast_file_err(f, f->cursor[0], "Default variable assignments within a structure will be ignored (at the moment)");
+ }
+ }
+
+ } else {
+ decl_count += 1;
+ }
+ }
+ }
+ Token close = expect_token(f, Token_CloseBrace);
+
+ // params = parse_parameter_list(f, scope, &param_count, Token_Semicolon, true);
+
+ return make_struct_type(f, token, decls, decl_count, is_packed);
+ } break;
case Token_union: {
Token token = expect_token(f, Token_union);
@@ -2100,6 +2203,7 @@ AstNode *parse_defer_stmt(AstFile *f) {
return make_defer_stmt(f, token, statement);
}
+
AstNode *parse_stmt(AstFile *f) {
AstNode *s = NULL;
Token token = f->cursor[0];
@@ -2117,18 +2221,7 @@ AstNode *parse_stmt(AstFile *f) {
case Token_Xor:
case Token_Not:
s = parse_simple_stmt(f);
- if (s->kind != AstNode_ProcDecl &&
- (s->kind == AstNode_TypeDecl &&
- s->TypeDecl.type->kind != AstNode_StructType &&
- s->TypeDecl.type->kind != AstNode_UnionType &&
- s->TypeDecl.type->kind != AstNode_EnumType &&
- s->TypeDecl.type->kind != AstNode_ProcType) &&
- !allow_token(f, Token_Semicolon)) {
- // CLEANUP(bill): Semicolon handling in parser
- ast_file_err(f, f->cursor[0],
- "Expected `;` after statement, got `%.*s`",
- LIT(token_strings[f->cursor[0].kind]));
- }
+ expect_semicolon_after_stmt(f, s);
return s;
// TODO(bill): other keywords
@@ -2146,6 +2239,36 @@ AstNode *parse_stmt(AstFile *f) {
expect_token(f, Token_Semicolon);
return make_branch_stmt(f, token);
+ case Token_using: {
+ AstNode *node = NULL;
+
+ next_token(f);
+ node = parse_stmt(f);
+
+ b32 valid = false;
+
+ switch (node->kind) {
+ case AstNode_ExprStmt:
+ if (node->ExprStmt.expr->kind == AstNode_Ident) {
+ valid = true;
+ }
+ break;
+ case AstNode_VarDecl:
+ if (node->VarDecl.kind == Declaration_Mutable) {
+ valid = true;
+ }
+ break;
+ }
+
+ if (!valid) {
+ ast_file_err(f, token, "Illegal use of `using` statement.");
+ return make_bad_stmt(f, token, f->cursor[0]);
+ }
+
+
+ return make_using_stmt(f, token, node);
+ } break;
+
case Token_Hash: {
s = parse_tag_stmt(f, NULL);
diff --git a/src/printer.cpp b/src/printer.cpp
index f2e215fb3..df93a92db 100644
--- a/src/printer.cpp
+++ b/src/printer.cpp
@@ -180,7 +180,7 @@ void print_ast(AstNode *node, isize indent) {
case AstNode_StructType:
print_indent(indent);
gb_printf("(struct)\n");
- print_ast(node->StructType.field_list, indent+1);
+ print_ast(node->StructType.decl_list, indent+1);
break;
}