aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2017-12-17 11:44:26 +0000
committergingerBill <bill@gingerbill.org>2017-12-17 11:44:26 +0000
commit32a502d14ebea99ed1f526904635ff66afda8fd4 (patch)
tree3bc13428d8e0e4c07b313ffb39b35abf3dd3b149 /src
parent0d665c637f164bb077b9d63bb947690affede6dd (diff)
using x in bar;
Diffstat (limited to 'src')
-rw-r--r--src/check_stmt.cpp156
-rw-r--r--src/check_type.cpp1
-rw-r--r--src/checker.cpp3
-rw-r--r--src/parser.cpp25
4 files changed, 175 insertions, 10 deletions
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index 31caca15a..2f82d98e8 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -522,27 +522,25 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
case Entity_Variable: {
Type *t = base_type(type_deref(e->type));
- if (is_type_struct(t) || is_type_raw_union(t) || is_type_union(t)) {
+ if (t->kind == Type_Struct) {
// TODO(bill): Make it work for unions too
Scope *found = scope_of_node(&c->info, t->Struct.node);
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;
- // }
+ uvar->using_expr = expr;
Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != nullptr) {
gbString expr_str = expr_to_string(expr);
- error(us->token, "Namespace collision while 'using' '%s' of: %.*s", expr_str, LIT(prev->token.string));
+ error(us->token, "Namespace collision while using '%s' of: '%.*s'", expr_str, LIT(prev->token.string));
gb_string_free(expr_str);
return false;
}
}
}
} else {
- error(us->token, "'using' can only be applied to variables of type `struct`");
+ error(us->token, "'using' can only be applied to variables of type 'struct'");
return false;
}
@@ -554,6 +552,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
break;
case Entity_Procedure:
+ case Entity_ProcGroup:
case Entity_Builtin:
error(us->token, "'using' cannot be applied to a procedure");
break;
@@ -1646,6 +1645,151 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
case_end;
+ case_ast_node(uis, UsingInStmt, node);
+ if (uis->list.count == 0) {
+ error(node, "Empty 'using' list");
+ return;
+ }
+ AstNode *expr = uis->expr;
+ Entity *e = nullptr;
+ Operand o = {};
+ if (expr->kind == AstNode_Ident) {
+ e = check_ident(c, &o, expr, nullptr, nullptr, true);
+ } else if (expr->kind == AstNode_SelectorExpr) {
+ e = check_selector(c, &o, expr, nullptr);
+ }
+ if (e == nullptr) {
+ error(expr, "'using' applied to an unknown entity");
+ return;
+ }
+ add_entity_use(c, expr, e);
+
+
+ switch (e->kind) {
+ case Entity_TypeName: {
+ Type *t = base_type(e->type);
+ if (t->kind == Type_Enum) {
+ GB_ASSERT(t->Enum.scope != nullptr);
+ for_array(list_index, uis->list) {
+ AstNode *node = uis->list[list_index];
+ ast_node(ident, Ident, node);
+ String name = ident->token.string;
+ Entity *f = scope_lookup_entity(t->Enum.scope, name);
+
+ if (f == nullptr || !is_entity_exported(f)) {
+ if (is_blank_ident(name)) {
+ error(node, "'_' cannot be used as a value");
+ } else {
+ error(node, "Undeclared name in this enumeration: '%.*s'", LIT(name));
+ }
+ continue;
+ }
+
+ add_entity_use(c, node, f);
+ add_entity(c, c->context.scope, node, f);
+ }
+ } else {
+ error(node, "'using' can be only applied to enum type entities");
+ }
+
+ break;
+ }
+
+ case Entity_ImportName: {
+ Scope *scope = e->ImportName.scope;
+ for_array(list_index, uis->list) {
+ AstNode *node = uis->list[list_index];
+ ast_node(ident, Ident, node);
+ String name = ident->token.string;
+
+ Entity *f = scope_lookup_entity(scope, name);
+ if (f == nullptr) {
+ if (is_blank_ident(name)) {
+ error(node, "'_' cannot be used as a value");
+ } else {
+ error(node, "Undeclared name in this import name: '%.*s'", LIT(name));
+ }
+ continue;
+ }
+
+ bool implicit_is_found = ptr_set_exists(&scope->implicit, f);
+ if (is_entity_exported(f) && !implicit_is_found) {
+ add_entity_use(c, node, f);
+ add_entity(c, c->context.scope, node, f);
+ } else {
+ error(node, "'%.*s' is exported from '%.*s'", LIT(f->token.string), LIT(e->token.string));
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ case Entity_Variable: {
+ Type *t = base_type(type_deref(e->type));
+ if (t->kind == Type_Struct) {
+ // TODO(bill): Make it work for unions too
+ Scope *found = scope_of_node(&c->info, t->Struct.node);
+ for_array(list_index, uis->list) {
+ AstNode *node = uis->list[list_index];
+ ast_node(ident, Ident, node);
+ String name = ident->token.string;
+
+ Entity *f = scope_lookup_entity(found, name);
+ if (f == nullptr || f->kind != Entity_Variable) {
+ if (is_blank_ident(name)) {
+ error(node, "'_' cannot be used as a value");
+ } else {
+ error(node, "Undeclared name in this variable: '%.*s'", LIT(name));
+ }
+ continue;
+ }
+
+ Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
+ uvar->using_expr = expr;
+ Entity *prev = scope_insert_entity(c->context.scope, uvar);
+ if (prev != nullptr) {
+ gbString expr_str = expr_to_string(expr);
+ error(node, "Namespace collision while using '%s' of: '%.*s'", expr_str, LIT(prev->token.string));
+ gb_string_free(expr_str);
+ continue;
+ }
+ }
+ } else {
+ error(node, "'using' can only be applied to variables of type `struct`");
+ return;
+ }
+
+ break;
+ }
+
+ case Entity_Constant:
+ error(node, "'using' cannot be applied to a constant");
+ break;
+
+ case Entity_Procedure:
+ case Entity_ProcGroup:
+ case Entity_Builtin:
+ error(node, "'using' cannot be applied to a procedure");
+ break;
+
+ case Entity_Nil:
+ error(node, "'using' cannot be applied to 'nil'");
+ break;
+
+ case Entity_Label:
+ error(node, "'using' cannot be applied to a label");
+ break;
+
+ case Entity_Invalid:
+ error(node, "'using' cannot be applied to an invalid entity");
+ break;
+
+ default:
+ GB_PANIC("TODO(bill): 'using' other expressions?");
+ }
+ case_end;
+
case_ast_node(pa, PushContext, node);
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 8600f1a55..0bee3171f 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -697,6 +697,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
// NOTE(bill): Must be up here for the 'check_init_constant' system
enum_type->Enum.base_type = base_type;
+ enum_type->Enum.scope = c->context.scope;
Map<Entity *> entity_map = {}; // Key: String
map_init(&entity_map, c->tmp_allocator, 2*(et->fields.count));
diff --git a/src/checker.cpp b/src/checker.cpp
index d8ada0bfc..47d550070 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -2688,8 +2688,7 @@ void check_add_import_decl(Checker *c, AstNodeImportDecl *id) {
bool implicit_is_found = ptr_set_exists(&scope->implicit, e);
if (is_entity_exported(e) && !implicit_is_found) {
- Entity *prev = scope_lookup_entity(parent_scope, e->token.string);
- // if (prev) gb_printf_err("%.*s\n", LIT(prev->token.string));
+ add_entity_use(c, node, e);
bool ok = add_entity(c, parent_scope, e->identifier, e);
if (ok) ptr_set_add(&parent_scope->implicit, e);
} else {
diff --git a/src/parser.cpp b/src/parser.cpp
index 8c96b1fb2..e8dbd1a05 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -307,6 +307,12 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
Token token; \
Array<AstNode *> list; \
}) \
+ AST_NODE_KIND(UsingInStmt, "using in statement", struct { \
+ Token using_token; \
+ Array<AstNode *> list; \
+ Token in_token; \
+ AstNode *expr; \
+ }) \
AST_NODE_KIND(AsmOperand, "assembly operand", struct { \
Token string; \
AstNode *operand; \
@@ -598,6 +604,7 @@ Token ast_node_token(AstNode *node) {
case AstNode_DeferStmt: return node->DeferStmt.token;
case AstNode_BranchStmt: return node->BranchStmt.token;
case AstNode_UsingStmt: return node->UsingStmt.token;
+ case AstNode_UsingInStmt: return node->UsingInStmt.using_token;
case AstNode_AsmStmt: return node->AsmStmt.token;
case AstNode_PushContext: return node->PushContext.token;
@@ -827,6 +834,10 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
case AstNode_UsingStmt:
n->UsingStmt.list = clone_ast_node_array(a, n->UsingStmt.list);
break;
+ case AstNode_UsingInStmt:
+ n->UsingInStmt.list = clone_ast_node_array(a, n->UsingInStmt.list);
+ n->UsingInStmt.expr = clone_ast_node(a, n->UsingInStmt.expr);
+ break;
case AstNode_AsmOperand:
n->AsmOperand.operand = clone_ast_node(a, n->AsmOperand.operand);
break;
@@ -1341,6 +1352,14 @@ AstNode *ast_using_stmt(AstFile *f, Token token, Array<AstNode *> list) {
result->UsingStmt.list = list;
return result;
}
+AstNode *ast_using_in_stmt(AstFile *f, Token using_token, Array<AstNode *> list, Token in_token, AstNode *expr) {
+ AstNode *result = make_ast_node(f, AstNode_UsingInStmt);
+ result->UsingInStmt.using_token = using_token;
+ result->UsingInStmt.list = list;
+ result->UsingInStmt.in_token = in_token;
+ result->UsingInStmt.expr = expr;
+ return result;
+}
AstNode *ast_asm_operand(AstFile *f, Token string, AstNode *operand) {
@@ -4535,8 +4554,10 @@ AstNode *parse_stmt(AstFile *f) {
}
return export_decl;
}
- syntax_error(token, "Illegal use of 'using' statement");
- return ast_bad_stmt(f, token, f->curr_token);
+
+ AstNode *expr = parse_expr(f, true);
+ expect_semicolon(f, expr);
+ return ast_using_in_stmt(f, token, list, in_token, expr);
}
if (f->curr_token.kind != Token_Colon) {