aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2016-09-14 19:35:13 +0100
committerGinger Bill <bill@gingerbill.org>2016-09-14 19:35:13 +0100
commit79f575ae8e7dda58a842dda3690b691e942ea86e (patch)
treeae339da6303711c3dad8815ef3ba0ea18ae31e2f /src
parentbb109b47d6b43547481a695ed9401aca95cbdf0e (diff)
#import "" as namespace
Diffstat (limited to 'src')
-rw-r--r--src/checker/checker.cpp50
-rw-r--r--src/checker/entity.cpp20
-rw-r--r--src/checker/expr.cpp173
-rw-r--r--src/checker/stmt.cpp50
-rw-r--r--src/codegen/codegen.cpp1
-rw-r--r--src/codegen/print_llvm.cpp81
-rw-r--r--src/codegen/ssa.cpp24
-rw-r--r--src/parser.cpp41
8 files changed, 297 insertions, 143 deletions
diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp
index 19df9a1b4..6de9858eb 100644
--- a/src/checker/checker.cpp
+++ b/src/checker/checker.cpp
@@ -315,7 +315,7 @@ void check_close_scope(Checker *c) {
c->context.scope = c->context.scope->parent;
}
-void scope_lookup_parent_entity(Checker *c, Scope *scope, String name, Scope **scope_, Entity **entity_) {
+void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entity **entity_) {
b32 gone_thru_proc = false;
HashKey key = hash_string(name);
for (Scope *s = scope; s != NULL; s = s->parent) {
@@ -366,9 +366,9 @@ void scope_lookup_parent_entity(Checker *c, Scope *scope, String name, Scope **s
if (scope_) *scope_ = NULL;
}
-Entity *scope_lookup_entity(Checker *c, Scope *s, String name) {
+Entity *scope_lookup_entity(Scope *s, String name) {
Entity *entity = NULL;
- scope_lookup_parent_entity(c, s, name, NULL, &entity);
+ scope_lookup_parent_entity(s, name, NULL, &entity);
return entity;
}
@@ -949,33 +949,41 @@ void check_parsed_files(Checker *c) {
gb_for_array(decl_index, f->decls) {
AstNode *decl = f->decls[decl_index];
- switch (decl->kind) {
- case_ast_node(id, ImportDecl, decl);
- HashKey key = hash_string(id->fullpath);
- auto found = map_get(&file_scopes, key);
- GB_ASSERT_MSG(found != NULL, "Unable to find scope for file: %.*s", LIT(id->fullpath));
- Scope *scope = *found;
- b32 previously_added = false;
- gb_for_array(import_index, file_scope->imported) {
- Scope *prev = file_scope->imported[import_index];
- if (prev == scope) {
- previously_added = true;
- break;
- }
- }
- if (!previously_added) {
- gb_array_append(file_scope->imported, scope);
+ if (decl->kind != AstNode_ImportDecl) {
+ continue;
+ }
+ ast_node(id, ImportDecl, decl);
+
+ HashKey key = hash_string(id->fullpath);
+ auto found = map_get(&file_scopes, key);
+ GB_ASSERT_MSG(found != NULL, "Unable to find scope for file: %.*s", LIT(id->fullpath));
+ Scope *scope = *found;
+ b32 previously_added = false;
+ gb_for_array(import_index, file_scope->imported) {
+ Scope *prev = file_scope->imported[import_index];
+ if (prev == scope) {
+ previously_added = true;
+ break;
}
+ }
+ if (!previously_added) {
+ gb_array_append(file_scope->imported, scope);
+ }
+ if (are_strings_equal(id->import_name.string, make_string("_"))) {
// NOTE(bill): Add imported entities to this file's scope
gb_for_array(elem_index, scope->elements.entries) {
Entity *e = scope->elements.entries[elem_index].value;
// NOTE(bill): Do not add other imported entities
- if (e->scope == scope) {
+ if (e->scope == scope && e->kind != Entity_ImportName) {
add_entity(c, file_scope, NULL, e);
}
}
- case_end;
+ } else {
+ Entity *e = make_entity_import_name(c->allocator, file_scope, id->import_name, t_invalid,
+ id->fullpath, id->import_name.string,
+ scope);
+ add_entity(c, file_scope, NULL, e);
}
}
}
diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp
index 85e668c0d..3814f38f0 100644
--- a/src/checker/entity.cpp
+++ b/src/checker/entity.cpp
@@ -9,6 +9,7 @@ enum BuiltinProcId;
ENTITY_KIND(TypeName), \
ENTITY_KIND(Procedure), \
ENTITY_KIND(Builtin), \
+ ENTITY_KIND(ImportName), \
ENTITY_KIND(Count),
@@ -49,11 +50,19 @@ struct Entity {
i32 field_index; // Order in source
b8 is_field; // Is struct field
} Variable;
- struct {} TypeName;
+ struct {
+ struct DeclInfo *decl; // Usually NULL
+ } TypeName;
struct {
b8 pure;
} Procedure;
struct { BuiltinProcId id; } Builtin;
+ struct {
+ String path;
+ String name;
+ Scope *scope;
+ b32 used;
+ } ImportName;
};
};
@@ -124,6 +133,15 @@ Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type
return entity;
}
+Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *type,
+ String path, String name, Scope *import_scope) {
+ Entity *entity = alloc_entity(a, Entity_ImportName, scope, token, type);
+ entity->ImportName.path = path;
+ entity->ImportName.name = name;
+ entity->ImportName.scope = import_scope;
+ return entity;
+}
+
Entity *make_entity_dummy_variable(gbAllocator a, Scope *file_scope, Token token) {
token.string = make_string("_");
return make_entity_variable(a, file_scope, token, NULL);
diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp
index 4389b7884..0d113af23 100644
--- a/src/checker/expr.cpp
+++ b/src/checker/expr.cpp
@@ -286,8 +286,9 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
Token name_token = td->name->Ident;
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);
+ gb_printf("%.*s\n", LIT(e->token.string));
+ check_type_decl(c, e, td->type, NULL, NULL);
HashKey key = hash_string(name_token.string);
if (map_get(&entity_map, key) != NULL) {
@@ -728,10 +729,14 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
GB_ASSERT(n->kind == AstNode_Ident);
o->mode = Addressing_Invalid;
o->expr = n;
- Entity *e = scope_lookup_entity(c, c->context.scope, n->Ident.string);
+ Entity *e = scope_lookup_entity(c->context.scope, n->Ident.string);
if (e == NULL) {
- error(&c->error_collector, n->Ident,
- "Undeclared type or identifier `%.*s`", LIT(n->Ident.string));
+ if (are_strings_equal(n->Ident.string, make_string("_"))) {
+ error(&c->error_collector, n->Ident, "`_` cannot be used as a value type");
+ } else {
+ error(&c->error_collector, n->Ident,
+ "Undeclared named: `%.*s`", LIT(n->Ident.string));
+ }
return;
}
add_entity_use(&c->info, n, e);
@@ -744,14 +749,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
gb_array_free(local_cycle_checker.path);
});
- if (e->type == NULL) {
- auto *found = map_get(&c->info.entities, hash_pointer(e));
- if (found != NULL) {
- check_entity_decl(c, e, *found, named_type, cycle_checker);
- } else {
- GB_PANIC("Internal Compiler Error: DeclInfo not found!");
- }
- }
+ check_entity_decl(c, e, NULL, named_type, cycle_checker);
if (e->type == NULL) {
GB_PANIC("Compiler error: How did this happen? type: %s; identifier: %.*s\n", type_to_string(e->type), LIT(n->Ident.string));
@@ -808,6 +806,10 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
o->mode = Addressing_Builtin;
break;
+ case Entity_ImportName:
+ error(&c->error_collector, ast_node_token(n), "Use of import `%.*s` not in selector", LIT(e->ImportName.name));
+ return;
+
default:
GB_PANIC("Compiler error: Unknown EntityKind");
break;
@@ -875,18 +877,30 @@ 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) {
+ switch (o.mode) {
+ case Addressing_Type:
+ GB_ASSERT(o.type != NULL);
set_base_type(type, o.type);
o.type->flags |= e->type_flags;
return o.type;
+
+ case Addressing_Invalid:
+ break;
+ case Addressing_NoValue: {
+ gbString err = expr_to_string(e);
+ defer (gb_string_free(err));
+ error(&c->error_collector, ast_node_token(e), "`%s` used as a type", err);
+ } break;
+ default: {
+ gbString err = expr_to_string(e);
+ defer (gb_string_free(err));
+ error(&c->error_collector, ast_node_token(e), "`%s` is not a type", err);
+ } break;
+ }
+
+ if (o.mode == Addressing_Type) {
}
case_end;
@@ -1959,54 +1973,90 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu
}
Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
- GB_ASSERT(node->kind == AstNode_SelectorExpr);
-
ast_node(se, SelectorExpr, node);
+
+ b32 check_op_expr = true;
+ Entity *entity = NULL;
+
AstNode *op_expr = se->expr;
- AstNode *selector = se->selector;
- if (selector) {
- Entity *entity = lookup_field(operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity;
- if (entity == NULL) {
- 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` (`%s`) has no field `%s`", op_str, type_str, sel_str);
- operand->mode = Addressing_Invalid;
- operand->expr = node;
- return NULL;
- }
- add_entity_use(&c->info, selector, entity);
+ AstNode *selector = unparen_expr(se->selector);
+ if (selector == NULL) {
+ goto error;
+ }
- operand->type = entity->type;
- operand->expr = node;
- switch (entity->kind) {
- case Entity_Constant:
- operand->mode = Addressing_Constant;
- operand->value = entity->Constant.value;
- break;
- case Entity_Variable:
- operand->mode = Addressing_Variable;
- break;
- case Entity_TypeName:
- operand->mode = Addressing_Type;
- break;
- case Entity_Procedure:
- operand->mode = Addressing_Value;
- break;
- case Entity_Builtin:
- operand->mode = Addressing_Builtin;
- operand->builtin_id = entity->Builtin.id;
- break;
+ GB_ASSERT(selector->kind == AstNode_Ident);
+
+ if (op_expr->kind == AstNode_Ident) {
+ String name = op_expr->Ident.string;
+ Entity *e = scope_lookup_entity(c->context.scope, name);
+ add_entity_use(&c->info, op_expr, e);
+ if (e != NULL && e->kind == Entity_ImportName) {
+ check_op_expr = false;
+ entity = scope_lookup_entity(e->ImportName.scope, selector->Ident.string);
+ add_entity_use(&c->info, selector, entity);
+ if (entity == NULL) {
+ gbString sel_str = expr_to_string(selector);
+ defer (gb_string_free(sel_str));
+ error(&c->error_collector, ast_node_token(op_expr), "`%s` is not declared in `%.*s`", sel_str, LIT(name));
+ goto error;
+ }
+ if (entity->type == NULL) { // Not setup yet
+ check_entity_decl(c, entity, NULL, NULL);
+ }
+ GB_ASSERT(entity->type != NULL);
+ }
+ }
+ if (check_op_expr) {
+ check_expr_base(c, operand, op_expr);
+ if (operand->mode == Addressing_Invalid) {
+ goto error;
}
+ }
- return entity;
- } else {
- operand->mode = Addressing_Invalid;
- operand->expr = node;
+ if (entity == NULL) {
+ entity = lookup_field(operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity;
+ }
+ if (entity == NULL) {
+ 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` (`%s`) has no field `%s`", op_str, type_str, sel_str);
+ goto error;
+ }
+
+
+ add_entity_use(&c->info, selector, entity);
+
+ operand->type = entity->type;
+ operand->expr = node;
+ switch (entity->kind) {
+ case Entity_Constant:
+ operand->mode = Addressing_Constant;
+ operand->value = entity->Constant.value;
+ break;
+ case Entity_Variable:
+ operand->mode = Addressing_Variable;
+ break;
+ case Entity_TypeName:
+ operand->mode = Addressing_Type;
+ break;
+ case Entity_Procedure:
+ operand->mode = Addressing_Value;
+ break;
+ case Entity_Builtin:
+ operand->mode = Addressing_Builtin;
+ operand->builtin_id = entity->Builtin.id;
+ break;
}
+
+ return entity;
+
+error:
+ operand->mode = Addressing_Invalid;
+ operand->expr = node;
return NULL;
}
@@ -3202,7 +3252,6 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
case_ast_node(se, SelectorExpr, node);
- check_expr_base(c, o, se->expr);
check_selector(c, o, node);
case_end;
diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp
index 79d4266fd..d97b68d14 100644
--- a/src/checker/stmt.cpp
+++ b/src/checker/stmt.cpp
@@ -171,7 +171,7 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
b32 used = false;
if (node->kind == AstNode_Ident) {
ast_node(i, Ident, node);
- e = scope_lookup_entity(c, c->context.scope, i->string);
+ e = scope_lookup_entity(c->context.scope, i->string);
if (e != NULL && e->kind == Entity_Variable) {
used = e->Variable.used; // TODO(bill): Make backup just in case
}
@@ -374,9 +374,8 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, Cycle
gb_array_free(local_cycle_checker.path);
});
- check_type(c, type_expr, named, cycle_checker_add(cycle_checker, e));
-
-
+ Type *base_type = check_type(c, type_expr, named, cycle_checker_add(cycle_checker, e));
+ named->Named.base = base_type;
named->Named.base = get_base_type(named->Named.base);
if (named->Named.base == t_invalid) {
// gb_printf("check_type_decl: %s\n", type_to_string(named));
@@ -562,22 +561,41 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, CycleChecker *cycle_checker) {
- if (e->type != NULL)
- return;
+ if (e->type != NULL) {
+ if (e->type->kind == Type_Named && e->type->Named.base == NULL) {
+ // NOTE(bill): Some weird declaration error from Entity_ImportName
+ } else {
+ return;
+ }
+ }
+
+ if (d == NULL) {
+ DeclInfo **found = map_get(&c->info.entities, hash_pointer(e));
+ if (found) {
+ d = *found;
+ } else {
+ GB_PANIC("`%.*s` should been declared!", LIT(e->token.string));
+ }
+ }
+
switch (e->kind) {
case Entity_Constant: {
Scope *prev = c->context.scope;
c->context.scope = d->scope;
- defer (c->context.scope = prev);
c->context.decl = d;
+
check_const_decl(c, e, d->type_expr, d->init_expr);
+
+ c->context.scope = prev;
} break;
case Entity_Variable: {
Scope *prev = c->context.scope;
c->context.scope = d->scope;
- defer (c->context.scope = prev);
c->context.decl = d;
+
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
+
+ c->context.scope = prev;
} break;
case Entity_TypeName: {
CycleChecker local_cycle_checker = {};
@@ -1234,7 +1252,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
AstNode *expr = unparen_expr(es->expr);
if (expr->kind == AstNode_Ident) {
String name = expr->Ident.string;
- e = scope_lookup_entity(c, c->context.scope, name);
+ e = scope_lookup_entity(c->context.scope, name);
} else if (expr->kind == AstNode_SelectorExpr) {
Operand o = {};
check_expr_base(c, &o, expr->SelectorExpr.expr);
@@ -1285,6 +1303,18 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
}
} break;
+ case Entity_ImportName: {
+ Scope *scope = e->ImportName.scope;
+ gb_for_array(i, scope->elements.entries) {
+ Entity *decl = scope->elements.entries[i].value;
+ Entity *found = scope_insert_entity(c->context.scope, decl);
+ if (found != NULL) {
+ error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
+ return;
+ }
+ }
+ } break;
+
case Entity_Constant:
error(&c->error_collector, us->token, "`using` cannot be applied to a constant");
break;
@@ -1334,7 +1364,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
AstNode *item = vd->names[name_index];
ast_node(i, Ident, item);
String name = i->string;
- Entity *e = scope_lookup_entity(c, c->context.scope, name);
+ Entity *e = scope_lookup_entity(c->context.scope, name);
Type *t = get_base_type(type_deref(e->type));
if (is_type_struct(t) || is_type_raw_union(t)) {
Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node));
diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp
index 43f894fb4..f45c852c8 100644
--- a/src/codegen/codegen.cpp
+++ b/src/codegen/codegen.cpp
@@ -84,6 +84,7 @@ void ssa_gen_tree(ssaGen *s) {
if (str[i] == '\\') {
str[i] = '/';
}
+
}
char const *base = gb_path_base_name(str);
char const *ext = gb_path_extension(base);
diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp
index 7ec3b369d..1015207c4 100644
--- a/src/codegen/print_llvm.cpp
+++ b/src/codegen/print_llvm.cpp
@@ -744,7 +744,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
if (proc->body == NULL) {
- ssa_fprintf(f, "\ndeclare ");
+ ssa_fprintf(f, "declare ");
} else {
ssa_fprintf(f, "\ndefine ");
}
@@ -844,47 +844,64 @@ void ssa_print_llvm_ir(ssaFileBuffer *f, ssaModule *m) {
gb_for_array(member_index, m->members.entries) {
auto *entry = &m->members.entries[member_index];
ssaValue *v = entry->value;
- switch (v->kind) {
- case ssaValue_TypeName:
- ssa_print_type_name(f, m, v);
- break;
+ if (v->kind != ssaValue_TypeName) {
+ continue;
}
+ 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;
- switch (v->kind) {
- case ssaValue_Global: {
- auto *g = &v->Global;
- ssa_print_encoded_global(f, g->entity->token.string);
- ssa_fprintf(f, " = ");
- if (g->is_thread_local) {
- ssa_fprintf(f, "thread_local ");
- }
- if (g->is_constant) {
- if (g->is_private) {
- ssa_fprintf(f, "private ");
- }
- ssa_fprintf(f, "constant ");
- } else {
- ssa_fprintf(f, "global ");
- }
+ if (v->kind != ssaValue_Proc) {
+ continue;
+ }
+ if (v->Proc.body == NULL) {
+ ssa_print_proc(f, m, &v->Proc);
+ }
+ }
+ gb_for_array(member_index, m->members.entries) {
+ auto *entry = &m->members.entries[member_index];
+ ssaValue *v = entry->value;
+ if (v->kind != ssaValue_Proc) {
+ continue;
+ }
+ if (v->Proc.body != NULL) {
+ ssa_print_proc(f, m, &v->Proc);
+ }
+ }
- ssa_print_type(f, m->sizes, g->entity->type);
- ssa_fprintf(f, " ");
- if (g->value != NULL) {
- ssa_print_value(f, m, g->value, g->entity->type);
- } else {
- ssa_fprintf(f, "zeroinitializer");
+
+ gb_for_array(member_index, m->members.entries) {
+ auto *entry = &m->members.entries[member_index];
+ ssaValue *v = entry->value;
+ if (v->kind != ssaValue_Global) {
+ continue;
+ }
+ auto *g = &v->Global;
+ ssa_print_encoded_global(f, g->entity->token.string);
+ ssa_fprintf(f, " = ");
+ if (g->is_thread_local) {
+ ssa_fprintf(f, "thread_local ");
+ }
+ if (g->is_constant) {
+ if (g->is_private) {
+ ssa_fprintf(f, "private ");
}
- ssa_fprintf(f, "\n");
- } break;
+ ssa_fprintf(f, "constant ");
+ } else {
+ ssa_fprintf(f, "global ");
+ }
- case ssaValue_Proc: {
- ssa_print_proc(f, m, &v->Proc);
- } break;
+
+ ssa_print_type(f, m->sizes, g->entity->type);
+ ssa_fprintf(f, " ");
+ if (g->value != NULL) {
+ ssa_print_value(f, m, g->value, g->entity->type);
+ } else {
+ ssa_fprintf(f, "zeroinitializer");
}
+ ssa_fprintf(f, "\n");
}
}
diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp
index 89443a1dd..268778493 100644
--- a/src/codegen/ssa.cpp
+++ b/src/codegen/ssa.cpp
@@ -927,6 +927,11 @@ ssaValue *ssa_lvalue_load(ssaProcedure *proc, ssaAddr lval) {
ssaValue *v = ssa_emit_load(proc, lval.addr);
return ssa_emit(proc, ssa_make_instr_extract_element(proc, v, lval.index));
}
+ // HACK(bill): Imported procedures don't require a load
+ Type *t = get_base_type(ssa_type(lval.addr));
+ if (t->kind == Type_Proc) {
+ return lval.addr;
+ }
return ssa_emit_load(proc, lval.addr);
}
GB_PANIC("Illegal lvalue load");
@@ -2519,13 +2524,20 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
case_ast_node(se, SelectorExpr, expr);
ssa_emit_comment(proc, make_string("SelectorExpr"));
Type *type = get_base_type(type_of_expr(proc->module->info, se->expr));
+ String selector = unparen_expr(se->selector)->Ident.string;
+ if (type == t_invalid) {
+ Entity *imp = entity_of_ident(proc->module->info, se->expr);
+ GB_ASSERT(imp->kind == Entity_ImportName);
+ // Entity *e = scope_lookup_entity(e->ImportName.scope, selector);
+ return ssa_build_addr(proc, unparen_expr(se->selector));
+ } else {
+ Selection sel = lookup_field(type, selector, false);
+ GB_ASSERT(sel.entity != NULL);
- Selection sel = lookup_field(type, unparen_expr(se->selector)->Ident.string, false);
- GB_ASSERT(sel.entity != NULL);
-
- ssaValue *e = ssa_build_addr(proc, se->expr).addr;
- e = ssa_emit_deep_field_gep(proc, type, e, sel);
- return ssa_make_addr(e, expr);
+ ssaValue *e = ssa_build_addr(proc, se->expr).addr;
+ e = ssa_emit_deep_field_gep(proc, type, e, sel);
+ return ssa_make_addr(e, expr);
+ }
case_end;
case_ast_node(ue, UnaryExpr, expr);
diff --git a/src/parser.cpp b/src/parser.cpp
index 7f4e842ae..57f5f8eff 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -43,11 +43,15 @@ struct AstFile {
TokenPos fix_prev_pos;
};
+struct ImportedFile {
+ String path;
+ TokenPos pos; // #import
+};
struct Parser {
String init_fullpath;
gbArray(AstFile) files;
- gbArray(String) imports;
+ gbArray(ImportedFile) imports;
gbArray(String) libraries;
gbArray(String) system_libraries;
isize load_index;
@@ -232,7 +236,8 @@ AST_NODE_KIND(_DeclBegin, "", struct{}) \
AST_NODE_KIND(TypeDecl, "type declaration", struct { Token token; AstNode *name, *type; }) \
AST_NODE_KIND(ImportDecl, "import declaration", struct { \
Token token, relpath; \
- String fullpath; \
+ String fullpath; \
+ Token import_name; \
}) \
AST_NODE_KIND(ForeignSystemLibrary, "foreign system library", struct { Token token, filepath; }) \
AST_NODE_KIND(_DeclEnd, "", struct{}) \
@@ -883,10 +888,11 @@ gb_inline AstNode *make_type_decl(AstFile *f, Token token, AstNode *name, AstNod
return result;
}
-gb_inline AstNode *make_import_decl(AstFile *f, Token token, Token relpath) {
+gb_inline AstNode *make_import_decl(AstFile *f, Token token, Token relpath, Token import_name) {
AstNode *result = make_node(f, AstNode_ImportDecl);
result->ImportDecl.token = token;
result->ImportDecl.relpath = relpath;
+ result->ImportDecl.import_name = import_name;
return result;
}
@@ -2541,9 +2547,13 @@ AstNode *parse_stmt(AstFile *f) {
ast_file_err(f, token, "You cannot use #global_scope within a procedure. This must be done at the file scope.");
return make_bad_decl(f, token, f->cursor[0]);
} else if (are_strings_equal(tag, make_string("import"))) {
+ // TODO(bill): better error messages
Token file_path = expect_token(f, Token_String);
+ Token as = expect_token(f, Token_as);
+ Token import_name = expect_token(f, Token_Identifier);
+
if (f->curr_proc == NULL) {
- return make_import_decl(f, s->TagStmt.token, file_path);
+ return make_import_decl(f, s->TagStmt.token, file_path, import_name);
}
ast_file_err(f, token, "You cannot use #import within a procedure. This must be done at the file scope.");
return make_bad_decl(f, token, file_path);
@@ -2695,15 +2705,18 @@ void destroy_parser(Parser *p) {
}
// NOTE(bill): Returns true if it's added
-b32 try_add_import_path(Parser *p, String import_file, AstNode *node) {
+b32 try_add_import_path(Parser *p, String path, TokenPos pos) {
gb_for_array(i, p->imports) {
- String import = p->imports[i];
- if (are_strings_equal(import, import_file)) {
+ String import = p->imports[i].path;
+ if (are_strings_equal(import, path)) {
return false;
}
}
- gb_array_append(p->imports, import_file);
+ ImportedFile item;
+ item.path = path;
+ item.pos = pos;
+ gb_array_append(p->imports, item);
return true;
}
@@ -2799,7 +2812,7 @@ void parse_file(Parser *p, AstFile *f) {
String import_file = make_string(path_str);
id->fullpath = import_file;
- if (!try_add_import_path(p, import_file, node)) {
+ if (!try_add_import_path(p, import_file, ast_node_token(node).pos)) {
// gb_free(gb_heap_allocator(), import_file.text);
}
} else if (node->kind == AstNode_ForeignSystemLibrary) {
@@ -2821,14 +2834,20 @@ void parse_file(Parser *p, AstFile *f) {
ParseFileError parse_files(Parser *p, char *init_filename) {
char *fullpath_str = gb_path_get_full_name(gb_heap_allocator(), init_filename);
String init_fullpath = make_string(fullpath_str);
- gb_array_append(p->imports, init_fullpath);
+ TokenPos init_pos = {};
+ ImportedFile init_imported_file = {init_fullpath, init_pos};
+ gb_array_append(p->imports, init_imported_file);
p->init_fullpath = init_fullpath;
gb_for_array(i, p->imports) {
- String import_path = p->imports[i];
+ String import_path = p->imports[i].path;
+ TokenPos pos = p->imports[i].pos;
AstFile file = {};
ParseFileError err = init_ast_file(&file, import_path);
if (err != ParseFile_None) {
+ if (pos.line != 0) {
+ gb_printf_err("%.*s(%td:%td) ", LIT(pos.file), pos.line, pos.column);
+ }
gb_printf_err("Failed to parse file: %.*s\n", LIT(import_path));
switch (err) {
case ParseFile_WrongExtension: