mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Fix file load order and allow when statements at file scope
This commit is contained in:
@@ -19,6 +19,4 @@ if [[ "$(uname)" == "Darwin" ]]; then
|
|||||||
other_args="${other_args} -liconv"
|
other_args="${other_args} -liconv"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
${compiler} src/main.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin
|
${compiler} src/main.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin && ./odin run examples/demo.odin
|
||||||
|
|
||||||
./odin run code/demo.odin
|
|
||||||
|
|||||||
+3
-3
@@ -22,11 +22,11 @@ when ODIN_OS == "windows" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == "windows" {
|
||||||
c_long :: u32;
|
c_ulong :: u32;
|
||||||
} else when size_of(uint) == 4 {
|
} else when size_of(uint) == 4 {
|
||||||
c_long :: u32;
|
c_ulong :: u32;
|
||||||
} else {
|
} else {
|
||||||
c_long :: u64;
|
c_ulong :: u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
c_longlong :: i64;
|
c_longlong :: i64;
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import "core:fmt.odin";
|
|
||||||
import "core:os.odin";
|
|
||||||
import "core:raw.odin";
|
import "core:raw.odin";
|
||||||
|
|
||||||
foreign __llvm_core {
|
foreign __llvm_core {
|
||||||
@@ -146,7 +144,6 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
|||||||
total_size := size + alignment;
|
total_size := size + alignment;
|
||||||
|
|
||||||
if len(arena.memory) + total_size > cap(arena.memory) {
|
if len(arena.memory) + total_size > cap(arena.memory) {
|
||||||
fmt.fprintln(os.stderr, "Arena out of memory");
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -1,26 +1,25 @@
|
|||||||
import "core:fmt.odin";
|
import "core:fmt.odin";
|
||||||
import "core:strconv.odin";
|
import "core:strconv.odin";
|
||||||
import "core:mem.odin";
|
import "core:mem.odin";
|
||||||
import "core:atomics.odin";
|
|
||||||
import "core:bits.odin";
|
import "core:bits.odin";
|
||||||
import "core:hash.odin";
|
import "core:hash.odin";
|
||||||
import "core:math.odin";
|
import "core:math.odin";
|
||||||
import "core:opengl.odin";
|
|
||||||
import "core:os.odin";
|
import "core:os.odin";
|
||||||
import "core:raw.odin";
|
import "core:raw.odin";
|
||||||
import "core:sort.odin";
|
import "core:sort.odin";
|
||||||
import "core:strings.odin";
|
import "core:strings.odin";
|
||||||
import "core:sync.odin";
|
|
||||||
import "core:types.odin";
|
import "core:types.odin";
|
||||||
import "core:utf8.odin";
|
|
||||||
import "core:utf16.odin";
|
import "core:utf16.odin";
|
||||||
|
import "core:utf8.odin";
|
||||||
|
// import "core:sync.odin";
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == "windows" {
|
||||||
|
import "core:atomics.odin";
|
||||||
|
import "core:opengl.odin";
|
||||||
import "core:thread.odin";
|
import "core:thread.odin";
|
||||||
import win32 "core:sys/windows.odin";
|
import win32 "core:sys/windows.odin";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
general_stuff :: proc() {
|
general_stuff :: proc() {
|
||||||
{ // `do` for inline statmes rather than block
|
{ // `do` for inline statmes rather than block
|
||||||
foo :: proc() do fmt.println("Foo!");
|
foo :: proc() do fmt.println("Foo!");
|
||||||
@@ -585,6 +584,7 @@ threading_example :: proc() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
when false {
|
when false {
|
||||||
fmt.println("\n# general_stuff"); general_stuff();
|
fmt.println("\n# general_stuff"); general_stuff();
|
||||||
|
|||||||
+353
-76
@@ -227,6 +227,7 @@ struct Scope {
|
|||||||
Map<bool> implicit; // Key: Entity *
|
Map<bool> implicit; // Key: Entity *
|
||||||
|
|
||||||
Array<Scope *> shared;
|
Array<Scope *> shared;
|
||||||
|
Array<AstNode *> delayed_file_decls;
|
||||||
PtrSet<Scope *> import_succ;
|
PtrSet<Scope *> import_succ;
|
||||||
PtrSet<Scope *> imported;
|
PtrSet<Scope *> imported;
|
||||||
bool is_proc;
|
bool is_proc;
|
||||||
@@ -337,7 +338,7 @@ struct CheckerContext {
|
|||||||
DeclInfo * curr_proc_decl;
|
DeclInfo * curr_proc_decl;
|
||||||
AstNode * curr_foreign_library;
|
AstNode * curr_foreign_library;
|
||||||
|
|
||||||
bool allow_file_when_statement;
|
bool collect_delayed_decls;
|
||||||
bool allow_polymorphic_types;
|
bool allow_polymorphic_types;
|
||||||
bool no_polymorphic_errors;
|
bool no_polymorphic_errors;
|
||||||
Scope * polymorphic_scope;
|
Scope * polymorphic_scope;
|
||||||
@@ -388,6 +389,9 @@ struct Checker {
|
|||||||
|
|
||||||
Array<Type *> proc_stack;
|
Array<Type *> proc_stack;
|
||||||
bool done_preload;
|
bool done_preload;
|
||||||
|
|
||||||
|
PtrSet<AstFile *> checked_files;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -487,6 +491,8 @@ Scope *create_scope_from_file(Checker *c, AstFile *f) {
|
|||||||
|
|
||||||
Scope *s = create_scope(c->global_scope, c->allocator);
|
Scope *s = create_scope(c->global_scope, c->allocator);
|
||||||
|
|
||||||
|
array_init(&s->delayed_file_decls, heap_allocator());
|
||||||
|
|
||||||
s->file = f;
|
s->file = f;
|
||||||
f->scope = s;
|
f->scope = s;
|
||||||
s->is_file = true;
|
s->is_file = true;
|
||||||
@@ -527,6 +533,7 @@ void destroy_scope(Scope *scope) {
|
|||||||
map_destroy(&scope->elements);
|
map_destroy(&scope->elements);
|
||||||
map_destroy(&scope->implicit);
|
map_destroy(&scope->implicit);
|
||||||
array_free(&scope->shared);
|
array_free(&scope->shared);
|
||||||
|
array_free(&scope->delayed_file_decls);
|
||||||
ptr_set_destroy(&scope->imported);
|
ptr_set_destroy(&scope->imported);
|
||||||
ptr_set_destroy(&scope->import_succ);
|
ptr_set_destroy(&scope->import_succ);
|
||||||
|
|
||||||
@@ -887,6 +894,7 @@ void init_checker(Checker *c, Parser *parser) {
|
|||||||
c->context.scope = c->global_scope;
|
c->context.scope = c->global_scope;
|
||||||
|
|
||||||
map_init(&c->file_scopes, heap_allocator());
|
map_init(&c->file_scopes, heap_allocator());
|
||||||
|
ptr_set_init(&c->checked_files, heap_allocator());
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_checker(Checker *c) {
|
void destroy_checker(Checker *c) {
|
||||||
@@ -899,7 +907,7 @@ void destroy_checker(Checker *c) {
|
|||||||
gb_arena_free(&c->tmp_arena);
|
gb_arena_free(&c->tmp_arena);
|
||||||
|
|
||||||
map_destroy(&c->file_scopes);
|
map_destroy(&c->file_scopes);
|
||||||
// gb_arena_free(&c->arena);
|
ptr_set_destroy(&c->checked_files);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1476,6 +1484,7 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
|
|||||||
EntityGraphNode *n = G[i];
|
EntityGraphNode *n = G[i];
|
||||||
n->index = i;
|
n->index = i;
|
||||||
n->dep_count = n->succ.entries.count;
|
n->dep_count = n->succ.entries.count;
|
||||||
|
GB_ASSERT(n->dep_count >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return G;
|
return G;
|
||||||
@@ -1770,6 +1779,7 @@ bool check_arity_match(Checker *c, AstNodeValueDecl *vd, bool is_global) {
|
|||||||
|
|
||||||
void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws) {
|
void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws) {
|
||||||
Operand operand = {Addressing_Invalid};
|
Operand operand = {Addressing_Invalid};
|
||||||
|
if (!ws->is_cond_determined) {
|
||||||
check_expr(c, &operand, ws->cond);
|
check_expr(c, &operand, ws->cond);
|
||||||
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
|
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
|
||||||
error(ws->cond, "Non-boolean condition in `when` statement");
|
error(ws->cond, "Non-boolean condition in `when` statement");
|
||||||
@@ -1777,11 +1787,15 @@ void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws) {
|
|||||||
if (operand.mode != Addressing_Constant) {
|
if (operand.mode != Addressing_Constant) {
|
||||||
error(ws->cond, "Non-constant condition in `when` statement");
|
error(ws->cond, "Non-constant condition in `when` statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ws->is_cond_determined = true;
|
||||||
|
ws->determined_cond = operand.value.kind == ExactValue_Bool && operand.value.value_bool;
|
||||||
|
}
|
||||||
|
|
||||||
if (ws->body == nullptr || ws->body->kind != AstNode_BlockStmt) {
|
if (ws->body == nullptr || ws->body->kind != AstNode_BlockStmt) {
|
||||||
error(ws->cond, "Invalid body for `when` statement");
|
error(ws->cond, "Invalid body for `when` statement");
|
||||||
} else {
|
} else {
|
||||||
if (operand.value.kind == ExactValue_Bool &&
|
if (ws->determined_cond) {
|
||||||
operand.value.value_bool) {
|
|
||||||
check_collect_entities(c, ws->body->BlockStmt.stmts);
|
check_collect_entities(c, ws->body->BlockStmt.stmts);
|
||||||
} else if (ws->else_stmt) {
|
} else if (ws->else_stmt) {
|
||||||
switch (ws->else_stmt->kind) {
|
switch (ws->else_stmt->kind) {
|
||||||
@@ -1799,27 +1813,16 @@ void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): If file_scopes == nullptr, this will act like a local scope
|
void check_collect_value_decl(Checker *c, AstNode *decl) {
|
||||||
void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
|
ast_node(vd, ValueDecl, decl);
|
||||||
for_array(decl_index, nodes) {
|
|
||||||
AstNode *decl = nodes[decl_index];
|
|
||||||
if (!is_ast_node_decl(decl) && !is_ast_node_when_stmt(decl)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (decl->kind) {
|
if (vd->been_handled) return;
|
||||||
case_ast_node(bd, BadDecl, decl);
|
vd->been_handled = true;
|
||||||
case_end;
|
|
||||||
|
|
||||||
case_ast_node(ws, WhenStmt, decl);
|
|
||||||
// Will be handled later
|
|
||||||
case_end;
|
|
||||||
|
|
||||||
case_ast_node(vd, ValueDecl, decl);
|
|
||||||
if (vd->is_mutable) {
|
if (vd->is_mutable) {
|
||||||
if (!c->context.scope->is_file) {
|
if (!c->context.scope->is_file) {
|
||||||
// NOTE(bill): local scope -> handle later and in order
|
// NOTE(bill): local scope -> handle later and in order
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): You need to store the entity information here unline a constant declaration
|
// NOTE(bill): You need to store the entity information here unline a constant declaration
|
||||||
@@ -1944,13 +1947,50 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
|
|||||||
// continue;
|
// continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
add_entity_and_decl_info(c, name, e, d);
|
add_entity_and_decl_info(c, name, e, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
check_arity_match(c, vd, true);
|
check_arity_match(c, vd, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_add_foreign_block_decl(Checker *c, AstNode *decl) {
|
||||||
|
ast_node(fb, ForeignBlockDecl, decl);
|
||||||
|
|
||||||
|
if (fb->been_handled) return;
|
||||||
|
fb->been_handled = true;
|
||||||
|
|
||||||
|
AstNode *foreign_library = fb->foreign_library;
|
||||||
|
if (foreign_library->kind != AstNode_Ident) {
|
||||||
|
error(foreign_library, "foreign library name must be an identifier");
|
||||||
|
foreign_library = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckerContext prev_context = c->context;
|
||||||
|
c->context.curr_foreign_library = foreign_library;
|
||||||
|
c->context.collect_delayed_decls = true;
|
||||||
|
check_collect_entities(c, fb->decls);
|
||||||
|
c->context = prev_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): If file_scopes == nullptr, this will act like a local scope
|
||||||
|
void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
|
||||||
|
for_array(decl_index, nodes) {
|
||||||
|
AstNode *decl = nodes[decl_index];
|
||||||
|
if (!is_ast_node_decl(decl) && !is_ast_node_when_stmt(decl)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (decl->kind) {
|
||||||
|
case_ast_node(bd, BadDecl, decl);
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(ws, WhenStmt, decl);
|
||||||
|
// Will be handled later
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(vd, ValueDecl, decl);
|
||||||
|
check_collect_value_decl(c, decl);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(id, ImportDecl, decl);
|
case_ast_node(id, ImportDecl, decl);
|
||||||
@@ -1960,7 +2000,7 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
|
|||||||
// TODO(bill): Better error handling if it isn't
|
// TODO(bill): Better error handling if it isn't
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c->context.allow_file_when_statement) {
|
if (c->context.collect_delayed_decls) {
|
||||||
check_delayed_file_import_entity(c, decl);
|
check_delayed_file_import_entity(c, decl);
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
@@ -1972,7 +2012,7 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
|
|||||||
// TODO(bill): Better error handling if it isn't
|
// TODO(bill): Better error handling if it isn't
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c->context.allow_file_when_statement) {
|
if (c->context.collect_delayed_decls) {
|
||||||
check_delayed_file_import_entity(c, decl);
|
check_delayed_file_import_entity(c, decl);
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
@@ -1984,22 +2024,13 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
|
|||||||
// TODO(bill): Better error handling if it isn't
|
// TODO(bill): Better error handling if it isn't
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c->context.allow_file_when_statement) {
|
if (c->context.collect_delayed_decls) {
|
||||||
check_delayed_file_import_entity(c, decl);
|
check_delayed_file_import_entity(c, decl);
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(fb, ForeignBlockDecl, decl);
|
case_ast_node(fb, ForeignBlockDecl, decl);
|
||||||
AstNode *foreign_library = fb->foreign_library;
|
check_add_foreign_block_decl(c, decl);
|
||||||
if (foreign_library->kind != AstNode_Ident) {
|
|
||||||
error(foreign_library, "foreign library name must be an identifier");
|
|
||||||
foreign_library = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckerContext prev_context = c->context;
|
|
||||||
c->context.curr_foreign_library = foreign_library;
|
|
||||||
check_collect_entities(c, fb->decls);
|
|
||||||
c->context = prev_context;
|
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -2012,7 +2043,7 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
|
|||||||
|
|
||||||
// NOTE(bill): `when` stmts need to be handled after the other as the condition may refer to something
|
// NOTE(bill): `when` stmts need to be handled after the other as the condition may refer to something
|
||||||
// declared after this stmt in source
|
// declared after this stmt in source
|
||||||
if (!c->context.scope->is_file || c->context.allow_file_when_statement) {
|
if (!c->context.scope->is_file || c->context.collect_delayed_decls) {
|
||||||
for_array(i, nodes) {
|
for_array(i, nodes) {
|
||||||
AstNode *node = nodes[i];
|
AstNode *node = nodes[i];
|
||||||
switch (node->kind) {
|
switch (node->kind) {
|
||||||
@@ -2028,6 +2059,7 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
|
|||||||
void check_all_global_entities(Checker *c) {
|
void check_all_global_entities(Checker *c) {
|
||||||
Scope *prev_file = nullptr;
|
Scope *prev_file = nullptr;
|
||||||
|
|
||||||
|
bool processing_preload = true;
|
||||||
for_array(i, c->info.entities.entries) {
|
for_array(i, c->info.entities.entries) {
|
||||||
auto *entry = &c->info.entities.entries[i];
|
auto *entry = &c->info.entities.entries[i];
|
||||||
Entity *e = cast(Entity *)entry->key.ptr;
|
Entity *e = cast(Entity *)entry->key.ptr;
|
||||||
@@ -2036,7 +2068,6 @@ void check_all_global_entities(Checker *c) {
|
|||||||
if (d->scope != e->scope) {
|
if (d->scope != e->scope) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
add_curr_ast_file(c, d->scope->file);
|
|
||||||
|
|
||||||
if (!d->scope->has_been_imported) {
|
if (!d->scope->has_been_imported) {
|
||||||
// NOTE(bill): All of these unchecked entities could mean a lot of unused allocations
|
// NOTE(bill): All of these unchecked entities could mean a lot of unused allocations
|
||||||
@@ -2044,6 +2075,10 @@ void check_all_global_entities(Checker *c) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AstFile *file = d->scope->file;
|
||||||
|
add_curr_ast_file(c, file);
|
||||||
|
|
||||||
if (e->token.string == "main") {
|
if (e->token.string == "main") {
|
||||||
if (e->kind != Entity_Procedure) {
|
if (e->kind != Entity_Procedure) {
|
||||||
if (e->scope->is_init) {
|
if (e->scope->is_init) {
|
||||||
@@ -2063,7 +2098,11 @@ void check_all_global_entities(Checker *c) {
|
|||||||
c->context = prev_context;
|
c->context = prev_context;
|
||||||
|
|
||||||
|
|
||||||
if (d->scope->is_init && !c->done_preload) {
|
if (!d->scope->is_global) {
|
||||||
|
processing_preload = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!processing_preload) {
|
||||||
init_preload(c);
|
init_preload(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2247,22 +2286,25 @@ void add_import_dependency_node(Checker *c, AstNode *decl, Map<ImportGraphNode *
|
|||||||
Scope *scope = *found;
|
Scope *scope = *found;
|
||||||
GB_ASSERT(scope != nullptr);
|
GB_ASSERT(scope != nullptr);
|
||||||
|
|
||||||
|
|
||||||
|
ImportGraphNode **found_node = nullptr;
|
||||||
ImportGraphNode *m = nullptr;
|
ImportGraphNode *m = nullptr;
|
||||||
ImportGraphNode *n = nullptr;
|
ImportGraphNode *n = nullptr;
|
||||||
|
|
||||||
ImportGraphNode **found_node = map_get(M, hash_pointer(parent_file_scope));
|
found_node = map_get(M, hash_pointer(scope));
|
||||||
GB_ASSERT(found_node != nullptr);
|
GB_ASSERT(found_node != nullptr);
|
||||||
m = *found_node;
|
m = *found_node;
|
||||||
|
|
||||||
found_node = map_get(M, hash_pointer(scope));
|
found_node = map_get(M, hash_pointer(parent_file_scope));
|
||||||
GB_ASSERT(found_node != nullptr);
|
GB_ASSERT(found_node != nullptr);
|
||||||
n = *found_node;
|
n = *found_node;
|
||||||
|
|
||||||
|
// TODO(bill): How should the edges be attched for `import`?
|
||||||
if (id->is_using) {
|
if (id->is_using) {
|
||||||
import_graph_node_set_add(&n->pred, m);
|
|
||||||
import_graph_node_set_add(&m->succ, n);
|
|
||||||
ptr_set_add(&m->scope->imported, n->scope);
|
|
||||||
}
|
}
|
||||||
|
import_graph_node_set_add(&n->succ, m);
|
||||||
|
import_graph_node_set_add(&m->pred, n);
|
||||||
|
ptr_set_add(&m->scope->imported, n->scope);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
|
||||||
@@ -2282,19 +2324,20 @@ void add_import_dependency_node(Checker *c, AstNode *decl, Map<ImportGraphNode *
|
|||||||
Scope *scope = *found;
|
Scope *scope = *found;
|
||||||
GB_ASSERT(scope != nullptr);
|
GB_ASSERT(scope != nullptr);
|
||||||
|
|
||||||
|
ImportGraphNode **found_node = nullptr;
|
||||||
ImportGraphNode *m = nullptr;
|
ImportGraphNode *m = nullptr;
|
||||||
ImportGraphNode *n = nullptr;
|
ImportGraphNode *n = nullptr;
|
||||||
|
|
||||||
ImportGraphNode **found_node = map_get(M, hash_pointer(parent_file_scope));
|
found_node = map_get(M, hash_pointer(scope));
|
||||||
GB_ASSERT(found_node != nullptr);
|
GB_ASSERT(found_node != nullptr);
|
||||||
m = *found_node;
|
m = *found_node;
|
||||||
|
|
||||||
found_node = map_get(M, hash_pointer(scope));
|
found_node = map_get(M, hash_pointer(parent_file_scope));
|
||||||
GB_ASSERT(found_node != nullptr);
|
GB_ASSERT(found_node != nullptr);
|
||||||
n = *found_node;
|
n = *found_node;
|
||||||
|
|
||||||
import_graph_node_set_add(&n->pred, m);
|
import_graph_node_set_add(&n->succ, m);
|
||||||
import_graph_node_set_add(&m->succ, n);
|
import_graph_node_set_add(&m->pred, n);
|
||||||
ptr_set_add(&m->scope->imported, n->scope);
|
ptr_set_add(&m->scope->imported, n->scope);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
@@ -2357,6 +2400,7 @@ Array<ImportGraphNode *> generate_import_dependency_graph(Checker *c) {
|
|||||||
ImportGraphNode *n = G[i];
|
ImportGraphNode *n = G[i];
|
||||||
n->index = i;
|
n->index = i;
|
||||||
n->dep_count = n->succ.entries.count;
|
n->dep_count = n->succ.entries.count;
|
||||||
|
GB_ASSERT(n->dep_count >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return G;
|
return G;
|
||||||
@@ -2405,18 +2449,13 @@ Array<Scope *> find_import_path(Map<Scope *> *file_scopes, Scope *start, Scope *
|
|||||||
return empty_path;
|
return empty_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_delayed_file_import_entity(Checker *c, AstNode *decl) {
|
void check_add_import_decl(Checker *c, AstNodeImportDecl *id) {
|
||||||
GB_ASSERT(c->context.allow_file_when_statement);
|
if (id->been_handled) return;
|
||||||
|
id->been_handled = true;
|
||||||
|
|
||||||
Scope *parent_scope = c->context.scope;
|
Scope *parent_scope = c->context.scope;
|
||||||
GB_ASSERT(parent_scope->is_file);
|
GB_ASSERT(parent_scope->is_file);
|
||||||
|
|
||||||
switch (decl->kind) {
|
|
||||||
case_ast_node(ws, WhenStmt, decl);
|
|
||||||
check_collect_entities_from_when_stmt(c, ws);
|
|
||||||
case_end;
|
|
||||||
|
|
||||||
case_ast_node(id, ImportDecl, decl);
|
|
||||||
Token token = id->relpath;
|
Token token = id->relpath;
|
||||||
HashKey key = hash_string(id->fullpath);
|
HashKey key = hash_string(id->fullpath);
|
||||||
Scope **found = map_get(&c->file_scopes, key);
|
Scope **found = map_get(&c->file_scopes, key);
|
||||||
@@ -2441,12 +2480,11 @@ void check_delayed_file_import_entity(Checker *c, AstNode *decl) {
|
|||||||
ptr_set_add(&parent_scope->imported, scope);
|
ptr_set_add(&parent_scope->imported, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
scope->has_been_imported = true;
|
|
||||||
|
|
||||||
if (id->is_using) {
|
if (id->is_using) {
|
||||||
if (parent_scope->is_global) {
|
if (parent_scope->is_global) {
|
||||||
error(id->import_name, "#shared_global_scope imports cannot use using");
|
error(id->import_name, "#shared_global_scope imports cannot use using");
|
||||||
} else {
|
return;
|
||||||
|
}
|
||||||
// NOTE(bill): Add imported entities to this file's scope
|
// NOTE(bill): Add imported entities to this file's scope
|
||||||
for_array(elem_index, scope->elements.entries) {
|
for_array(elem_index, scope->elements.entries) {
|
||||||
Entity *e = scope->elements.entries[elem_index].value;
|
Entity *e = scope->elements.entries[elem_index].value;
|
||||||
@@ -2461,7 +2499,6 @@ void check_delayed_file_import_entity(Checker *c, AstNode *decl) {
|
|||||||
if (ok) map_set(&parent_scope->implicit, hash_entity(e), true);
|
if (ok) map_set(&parent_scope->implicit, hash_entity(e), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
String import_name = path_to_entity_name(id->import_name.string, id->fullpath);
|
String import_name = path_to_entity_name(id->import_name.string, id->fullpath);
|
||||||
if (is_blank_ident(import_name)) {
|
if (is_blank_ident(import_name)) {
|
||||||
@@ -2476,9 +2513,17 @@ void check_delayed_file_import_entity(Checker *c, AstNode *decl) {
|
|||||||
add_entity(c, parent_scope, nullptr, e);
|
add_entity(c, parent_scope, nullptr, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case_end;
|
ptr_set_add(&c->checked_files, scope->file);
|
||||||
|
scope->has_been_imported = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_add_export_decl(Checker *c, AstNodeExportDecl *ed) {
|
||||||
|
if (ed->been_handled) return;
|
||||||
|
ed->been_handled = true;
|
||||||
|
|
||||||
|
Scope *parent_scope = c->context.scope;
|
||||||
|
GB_ASSERT(parent_scope->is_file);
|
||||||
|
|
||||||
case_ast_node(ed, ExportDecl, decl);
|
|
||||||
Token token = ed->relpath;
|
Token token = ed->relpath;
|
||||||
HashKey key = hash_string(ed->fullpath);
|
HashKey key = hash_string(ed->fullpath);
|
||||||
Scope **found = map_get(&c->file_scopes, key);
|
Scope **found = map_get(&c->file_scopes, key);
|
||||||
@@ -2497,16 +2542,18 @@ void check_delayed_file_import_entity(Checker *c, AstNode *decl) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (parent_scope->is_global) {
|
||||||
|
error(ed->token, "`export` cannot be used on #shared_global_scope");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ptr_set_exists(&parent_scope->imported, scope)) {
|
if (ptr_set_exists(&parent_scope->imported, scope)) {
|
||||||
// error(token, "Multiple import of the same file within this scope");
|
// error(token, "Multiple import of the same file within this scope");
|
||||||
} else {
|
} else {
|
||||||
ptr_set_add(&parent_scope->imported, scope);
|
ptr_set_add(&parent_scope->imported, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
scope->has_been_imported = true;
|
|
||||||
if (parent_scope->is_global) {
|
|
||||||
error(decl, "`export` cannot be used on #shared_global_scope");
|
|
||||||
} else {
|
|
||||||
// NOTE(bill): Add imported entities to this file's scope
|
// NOTE(bill): Add imported entities to this file's scope
|
||||||
for_array(elem_index, scope->elements.entries) {
|
for_array(elem_index, scope->elements.entries) {
|
||||||
Entity *e = scope->elements.entries[elem_index].value;
|
Entity *e = scope->elements.entries[elem_index].value;
|
||||||
@@ -2516,10 +2563,20 @@ void check_delayed_file_import_entity(Checker *c, AstNode *decl) {
|
|||||||
add_entity(c, parent_scope, e->identifier, e);
|
add_entity(c, parent_scope, e->identifier, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
case_end;
|
|
||||||
|
|
||||||
case_ast_node(fl, ForeignLibraryDecl, decl);
|
ptr_set_add(&c->checked_files, scope->file);
|
||||||
|
scope->has_been_imported = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_add_foreign_library_decl(Checker *c, AstNode *decl) {
|
||||||
|
ast_node(fl, ForeignLibraryDecl, decl);
|
||||||
|
|
||||||
|
if (fl->been_handled) return;
|
||||||
|
fl->been_handled = true;
|
||||||
|
|
||||||
|
Scope *parent_scope = c->context.scope;
|
||||||
|
GB_ASSERT(parent_scope->is_file);
|
||||||
|
|
||||||
String file_str = fl->filepath.string;
|
String file_str = fl->filepath.string;
|
||||||
String base_dir = fl->base_dir;
|
String base_dir = fl->base_dir;
|
||||||
|
|
||||||
@@ -2539,7 +2596,7 @@ void check_delayed_file_import_entity(Checker *c, AstNode *decl) {
|
|||||||
|
|
||||||
String library_name = path_to_entity_name(fl->library_name.string, file_str);
|
String library_name = path_to_entity_name(fl->library_name.string, file_str);
|
||||||
if (is_blank_ident(library_name)) {
|
if (is_blank_ident(library_name)) {
|
||||||
error(decl, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string));
|
error(fl->token, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string));
|
||||||
} else {
|
} else {
|
||||||
GB_ASSERT(fl->library_name.pos.line != 0);
|
GB_ASSERT(fl->library_name.pos.line != 0);
|
||||||
fl->library_name.string = library_name;
|
fl->library_name.string = library_name;
|
||||||
@@ -2547,8 +2604,197 @@ void check_delayed_file_import_entity(Checker *c, AstNode *decl) {
|
|||||||
file_str, library_name);
|
file_str, library_name);
|
||||||
add_entity(c, parent_scope, nullptr, e);
|
add_entity(c, parent_scope, nullptr, e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool collect_checked_files_from_import_decl_list(Checker *c, Array<AstNode *> decls) {
|
||||||
|
bool new_files = false;
|
||||||
|
for_array(i, decls) {
|
||||||
|
AstNode *decl = decls[i];
|
||||||
|
switch (decl->kind) {
|
||||||
|
case_ast_node(id, ImportDecl, decl);
|
||||||
|
HashKey key = hash_string(id->fullpath);
|
||||||
|
Scope **found = map_get(&c->file_scopes, key);
|
||||||
|
if (found == nullptr) continue;
|
||||||
|
Scope *s = *found;
|
||||||
|
if (!ptr_set_exists(&c->checked_files, s->file)) {
|
||||||
|
new_files = true;
|
||||||
|
ptr_set_add(&c->checked_files, s->file);
|
||||||
|
}
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(ed, ExportDecl, decl);
|
||||||
|
HashKey key = hash_string(ed->fullpath);
|
||||||
|
Scope **found = map_get(&c->file_scopes, key);
|
||||||
|
if (found == nullptr) continue;
|
||||||
|
Scope *s = *found;
|
||||||
|
if (!ptr_set_exists(&c->checked_files, s->file)) {
|
||||||
|
new_files = true;
|
||||||
|
ptr_set_add(&c->checked_files, s->file);
|
||||||
|
}
|
||||||
case_end;
|
case_end;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return new_files;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool collect_checked_files_from_when_stmt(Checker *c, AstNodeWhenStmt *ws) {
|
||||||
|
Operand operand = {Addressing_Invalid};
|
||||||
|
if (!ws->is_cond_determined) {
|
||||||
|
check_expr(c, &operand, ws->cond);
|
||||||
|
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
|
||||||
|
error(ws->cond, "Non-boolean condition in `when` statement");
|
||||||
|
}
|
||||||
|
if (operand.mode != Addressing_Constant) {
|
||||||
|
error(ws->cond, "Non-constant condition in `when` statement");
|
||||||
|
}
|
||||||
|
|
||||||
|
ws->is_cond_determined = true;
|
||||||
|
ws->determined_cond = operand.value.kind == ExactValue_Bool && operand.value.value_bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ws->body == nullptr || ws->body->kind != AstNode_BlockStmt) {
|
||||||
|
error(ws->cond, "Invalid body for `when` statement");
|
||||||
|
} else {
|
||||||
|
if (ws->determined_cond) {
|
||||||
|
return collect_checked_files_from_import_decl_list(c, ws->body->BlockStmt.stmts);
|
||||||
|
} else if (ws->else_stmt) {
|
||||||
|
switch (ws->else_stmt->kind) {
|
||||||
|
case AstNode_BlockStmt:
|
||||||
|
return collect_checked_files_from_import_decl_list(c, ws->else_stmt->BlockStmt.stmts);
|
||||||
|
case AstNode_WhenStmt:
|
||||||
|
return collect_checked_files_from_when_stmt(c, &ws->else_stmt->WhenStmt);
|
||||||
|
default:
|
||||||
|
error(ws->else_stmt, "Invalid `else` statement in `when` statement");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_delayed_file_import_entity(Checker *c, AstNode *decl) {
|
||||||
|
GB_ASSERT(c->context.collect_delayed_decls);
|
||||||
|
|
||||||
|
Scope *parent_scope = c->context.scope;
|
||||||
|
GB_ASSERT(parent_scope->is_file);
|
||||||
|
|
||||||
|
switch (decl->kind) {
|
||||||
|
case_ast_node(ws, WhenStmt, decl);
|
||||||
|
check_collect_entities_from_when_stmt(c, ws);
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(id, ImportDecl, decl);
|
||||||
|
check_add_import_decl(c, id);
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(ed, ExportDecl, decl);
|
||||||
|
check_add_export_decl(c, ed);
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(fl, ForeignLibraryDecl, decl);
|
||||||
|
check_add_foreign_library_decl(c, decl);
|
||||||
|
case_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE(bill): Returns true if a new file is present
|
||||||
|
bool collect_file_decls(Checker *c, Array<AstNode *> decls);
|
||||||
|
bool collect_file_decls_from_when_stmt(Checker *c, AstNodeWhenStmt *ws);
|
||||||
|
|
||||||
|
bool collect_file_decls_from_when_stmt(Checker *c, AstNodeWhenStmt *ws) {
|
||||||
|
Operand operand = {Addressing_Invalid};
|
||||||
|
if (!ws->is_cond_determined) {
|
||||||
|
check_expr(c, &operand, ws->cond);
|
||||||
|
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
|
||||||
|
error(ws->cond, "Non-boolean condition in `when` statement");
|
||||||
|
}
|
||||||
|
if (operand.mode != Addressing_Constant) {
|
||||||
|
error(ws->cond, "Non-constant condition in `when` statement");
|
||||||
|
}
|
||||||
|
|
||||||
|
ws->is_cond_determined = true;
|
||||||
|
ws->determined_cond = operand.value.kind == ExactValue_Bool && operand.value.value_bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ws->body == nullptr || ws->body->kind != AstNode_BlockStmt) {
|
||||||
|
error(ws->cond, "Invalid body for `when` statement");
|
||||||
|
} else {
|
||||||
|
if (ws->determined_cond) {
|
||||||
|
return collect_file_decls(c, ws->body->BlockStmt.stmts);
|
||||||
|
} else if (ws->else_stmt) {
|
||||||
|
switch (ws->else_stmt->kind) {
|
||||||
|
case AstNode_BlockStmt:
|
||||||
|
return collect_file_decls(c, ws->else_stmt->BlockStmt.stmts);
|
||||||
|
case AstNode_WhenStmt:
|
||||||
|
return collect_file_decls_from_when_stmt(c, &ws->else_stmt->WhenStmt);
|
||||||
|
default:
|
||||||
|
error(ws->else_stmt, "Invalid `else` statement in `when` statement");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool collect_file_decls(Checker *c, Array<AstNode *> decls) {
|
||||||
|
for_array(i, decls) {
|
||||||
|
Scope *parent_scope = c->context.scope;
|
||||||
|
GB_ASSERT(parent_scope->is_file);
|
||||||
|
|
||||||
|
AstNode *decl = decls[i];
|
||||||
|
switch (decl->kind) {
|
||||||
|
case_ast_node(vd, ValueDecl, decl);
|
||||||
|
check_collect_value_decl(c, decl);
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(id, ImportDecl, decl);
|
||||||
|
check_add_import_decl(c, id);
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(ed, ExportDecl, decl);
|
||||||
|
check_add_export_decl(c, ed);
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(fl, ForeignLibraryDecl, decl);
|
||||||
|
check_add_foreign_library_decl(c, decl);
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(fb, ForeignBlockDecl, decl);
|
||||||
|
check_add_foreign_block_decl(c, decl);
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(ws, WhenStmt, decl);
|
||||||
|
if (ws->is_cond_determined) {
|
||||||
|
CheckerContext prev_context = c->context;
|
||||||
|
defer (c->context = prev_context);
|
||||||
|
c->context.collect_delayed_decls = true;
|
||||||
|
|
||||||
|
if (collect_file_decls_from_when_stmt(c, ws)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (collect_checked_files_from_when_stmt(c, ws)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckerContext prev_context = c->context;
|
||||||
|
defer (c->context = prev_context);
|
||||||
|
c->context.collect_delayed_decls = true;
|
||||||
|
|
||||||
|
if (collect_file_decls_from_when_stmt(c, ws)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_import_entities(Checker *c) {
|
void check_import_entities(Checker *c) {
|
||||||
@@ -2605,7 +2851,7 @@ void check_import_entities(Checker *c) {
|
|||||||
|
|
||||||
for_array(i, n->pred.entries) {
|
for_array(i, n->pred.entries) {
|
||||||
ImportGraphNode *p = n->pred.entries[i].ptr;
|
ImportGraphNode *p = n->pred.entries[i].ptr;
|
||||||
p->dep_count -= 1;
|
p->dep_count = gb_max(p->dep_count-1, 0);
|
||||||
priority_queue_fix(&pq, p->index);
|
priority_queue_fix(&pq, p->index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2620,20 +2866,52 @@ void check_import_entities(Checker *c) {
|
|||||||
array_add(&file_order, n);
|
array_add(&file_order, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for_array(file_index, c->parser->files) {
|
||||||
|
AstFile *f = c->parser->files[file_index];
|
||||||
|
Scope *s = f->scope;
|
||||||
|
if (s->is_init || s->is_global) {
|
||||||
|
ptr_set_add(&c->checked_files, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
bool new_files = false;
|
||||||
|
for_array(file_index, c->parser->files) {
|
||||||
|
AstFile *f = c->parser->files[file_index];
|
||||||
|
|
||||||
|
if (!ptr_set_exists(&c->checked_files, f)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_files |= collect_checked_files_from_import_decl_list(c, f->decls);
|
||||||
|
}
|
||||||
|
if (new_files) break;
|
||||||
|
}
|
||||||
|
|
||||||
for_array(file_index, file_order) {
|
for_array(file_index, file_order) {
|
||||||
ImportGraphNode *node = file_order[file_index];
|
ImportGraphNode *node = file_order[file_index];
|
||||||
AstFile *f = node->scope->file;
|
AstFile *f = node->scope->file;
|
||||||
|
|
||||||
|
if (!ptr_set_exists(&c->checked_files, f)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// gb_printf_err("%.*s\n", LIT(f->fullpath));
|
||||||
|
|
||||||
CheckerContext prev_context = c->context;
|
CheckerContext prev_context = c->context;
|
||||||
defer (c->context = prev_context);
|
defer (c->context = prev_context);
|
||||||
|
c->context.collect_delayed_decls = true;
|
||||||
add_curr_ast_file(c, f);
|
add_curr_ast_file(c, f);
|
||||||
|
|
||||||
c->context.allow_file_when_statement = true;
|
bool new_files = collect_file_decls(c, f->decls);
|
||||||
|
if (new_files) {
|
||||||
|
file_index = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for_array(i, f->decls) {
|
// gb_printf_err("End here!\n");
|
||||||
check_delayed_file_import_entity(c, f->decls[i]);
|
// gb_exit(1);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Array<Entity *> find_entity_path(Map<DeclInfo *> *map, Entity *start, Entity *end, Map<Entity *> *visited = nullptr) {
|
Array<Entity *> find_entity_path(Map<DeclInfo *> *map, Entity *start, Entity *end, Map<Entity *> *visited = nullptr) {
|
||||||
@@ -2782,7 +3060,6 @@ void check_parsed_files(Checker *c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
check_import_entities(c);
|
check_import_entities(c);
|
||||||
|
|
||||||
check_all_global_entities(c);
|
check_all_global_entities(c);
|
||||||
init_preload(c); // NOTE(bill): This could be setup previously through the use of `type_info(_of_val)`
|
init_preload(c); // NOTE(bill): This could be setup previously through the use of `type_info(_of_val)`
|
||||||
|
|
||||||
|
|||||||
+21
-4
@@ -37,6 +37,7 @@ struct ImportedFile {
|
|||||||
|
|
||||||
struct AstFile {
|
struct AstFile {
|
||||||
isize id;
|
isize id;
|
||||||
|
String fullpath;
|
||||||
gbArena arena;
|
gbArena arena;
|
||||||
Tokenizer tokenizer;
|
Tokenizer tokenizer;
|
||||||
Array<Token> tokens;
|
Array<Token> tokens;
|
||||||
@@ -51,6 +52,7 @@ struct AstFile {
|
|||||||
bool allow_range; // NOTE(bill): Ranges are only allowed in certain cases
|
bool allow_range; // NOTE(bill): Ranges are only allowed in certain cases
|
||||||
bool in_foreign_block;
|
bool in_foreign_block;
|
||||||
bool allow_type;
|
bool allow_type;
|
||||||
|
isize when_level;
|
||||||
|
|
||||||
Array<AstNode *> decls;
|
Array<AstNode *> decls;
|
||||||
ImportedFileKind file_kind;
|
ImportedFileKind file_kind;
|
||||||
@@ -249,6 +251,8 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
|
|||||||
AstNode *cond; \
|
AstNode *cond; \
|
||||||
AstNode *body; \
|
AstNode *body; \
|
||||||
AstNode *else_stmt; \
|
AstNode *else_stmt; \
|
||||||
|
bool is_cond_determined; \
|
||||||
|
bool determined_cond; \
|
||||||
}) \
|
}) \
|
||||||
AST_NODE_KIND(ReturnStmt, "return statement", struct { \
|
AST_NODE_KIND(ReturnStmt, "return statement", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
@@ -328,6 +332,7 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
|
|||||||
AstNode * foreign_library; \
|
AstNode * foreign_library; \
|
||||||
Token open, close; \
|
Token open, close; \
|
||||||
Array<AstNode *> decls; \
|
Array<AstNode *> decls; \
|
||||||
|
bool been_handled; \
|
||||||
CommentGroup docs; \
|
CommentGroup docs; \
|
||||||
}) \
|
}) \
|
||||||
AST_NODE_KIND(Label, "label", struct { \
|
AST_NODE_KIND(Label, "label", struct { \
|
||||||
@@ -340,15 +345,17 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
|
|||||||
Array<AstNode *> values; \
|
Array<AstNode *> values; \
|
||||||
u64 flags; \
|
u64 flags; \
|
||||||
bool is_mutable; \
|
bool is_mutable; \
|
||||||
|
bool been_handled; \
|
||||||
CommentGroup docs; \
|
CommentGroup docs; \
|
||||||
CommentGroup comment; \
|
CommentGroup comment; \
|
||||||
}) \
|
}) \
|
||||||
AST_NODE_KIND(ImportDecl, "import declaration", struct { \
|
AST_NODE_KIND(ImportDecl, "import declaration", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
bool is_using; \
|
|
||||||
Token relpath; \
|
Token relpath; \
|
||||||
String fullpath; \
|
String fullpath; \
|
||||||
Token import_name; \
|
Token import_name; \
|
||||||
|
bool is_using; \
|
||||||
|
bool been_handled; \
|
||||||
CommentGroup docs; \
|
CommentGroup docs; \
|
||||||
CommentGroup comment; \
|
CommentGroup comment; \
|
||||||
}) \
|
}) \
|
||||||
@@ -356,6 +363,7 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
|
|||||||
Token token; \
|
Token token; \
|
||||||
Token relpath; \
|
Token relpath; \
|
||||||
String fullpath; \
|
String fullpath; \
|
||||||
|
bool been_handled; \
|
||||||
CommentGroup docs; \
|
CommentGroup docs; \
|
||||||
CommentGroup comment; \
|
CommentGroup comment; \
|
||||||
}) \
|
}) \
|
||||||
@@ -364,6 +372,7 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
|
|||||||
Token filepath; \
|
Token filepath; \
|
||||||
Token library_name; \
|
Token library_name; \
|
||||||
String base_dir; \
|
String base_dir; \
|
||||||
|
bool been_handled; \
|
||||||
CommentGroup docs; \
|
CommentGroup docs; \
|
||||||
CommentGroup comment; \
|
CommentGroup comment; \
|
||||||
}) \
|
}) \
|
||||||
@@ -3993,7 +4002,10 @@ AstNode *parse_when_stmt(AstFile *f) {
|
|||||||
AstNode *else_stmt = nullptr;
|
AstNode *else_stmt = nullptr;
|
||||||
|
|
||||||
isize prev_level = f->expr_level;
|
isize prev_level = f->expr_level;
|
||||||
|
isize when_level = f->when_level;
|
||||||
|
defer (f->when_level = when_level);
|
||||||
f->expr_level = -1;
|
f->expr_level = -1;
|
||||||
|
f->when_level += 1;
|
||||||
|
|
||||||
cond = parse_expr(f, false);
|
cond = parse_expr(f, false);
|
||||||
|
|
||||||
@@ -4028,6 +4040,11 @@ AstNode *parse_when_stmt(AstFile *f) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (f->curr_proc == nullptr && f->when_level > 1) {
|
||||||
|
// syntax_error(token, "Nested when statements are not currently supported at the file scope");
|
||||||
|
// return ast_bad_stmt(f, token, f->curr_token);
|
||||||
|
// }
|
||||||
|
|
||||||
return ast_when_stmt(f, token, cond, body, else_stmt);
|
return ast_when_stmt(f, token, cond, body, else_stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4635,11 +4652,11 @@ Array<AstNode *> parse_stmt_list(AstFile *f) {
|
|||||||
|
|
||||||
|
|
||||||
ParseFileError init_ast_file(AstFile *f, String fullpath) {
|
ParseFileError init_ast_file(AstFile *f, String fullpath) {
|
||||||
fullpath = string_trim_whitespace(fullpath); // Just in case
|
f->fullpath = string_trim_whitespace(fullpath); // Just in case
|
||||||
if (!string_has_extension(fullpath, str_lit("odin"))) {
|
if (!string_has_extension(f->fullpath, str_lit("odin"))) {
|
||||||
return ParseFile_WrongExtension;
|
return ParseFile_WrongExtension;
|
||||||
}
|
}
|
||||||
TokenizerInitError err = init_tokenizer(&f->tokenizer, fullpath);
|
TokenizerInitError err = init_tokenizer(&f->tokenizer, f->fullpath);
|
||||||
if (err != TokenizerInit_None) {
|
if (err != TokenizerInit_None) {
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case TokenizerInit_NotExists:
|
case TokenizerInit_NotExists:
|
||||||
|
|||||||
Reference in New Issue
Block a user