mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 06:38:47 +00:00
Delay importing entities till all other entities are collected
This commit is contained in:
+2
-6
@@ -2,16 +2,12 @@
|
|||||||
#import "utf8.odin"
|
#import "utf8.odin"
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
|
MAX :: 64
|
||||||
buf: [MAX]rune
|
buf: [MAX]rune
|
||||||
backing: [MAX]byte
|
backing: [MAX]byte
|
||||||
offset: int
|
offset: int
|
||||||
|
|
||||||
when MAX > 0 {
|
msg := "Hello"
|
||||||
msg := "Hello"
|
|
||||||
}
|
|
||||||
|
|
||||||
MAX :: 64
|
|
||||||
|
|
||||||
count := utf8.rune_count(msg)
|
count := utf8.rune_count(msg)
|
||||||
assert(count <= MAX)
|
assert(count <= MAX)
|
||||||
|
|||||||
+1
-173
@@ -1,175 +1,3 @@
|
|||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == "windows" {
|
||||||
#import "win32.odin"
|
#load "os_windows.odin"
|
||||||
}
|
}
|
||||||
#import "fmt.odin"
|
|
||||||
|
|
||||||
File_Time :: type u64
|
|
||||||
|
|
||||||
File :: struct {
|
|
||||||
Handle :: raw_union {
|
|
||||||
p: rawptr
|
|
||||||
i: int
|
|
||||||
}
|
|
||||||
handle: Handle
|
|
||||||
last_write_time: File_Time
|
|
||||||
}
|
|
||||||
|
|
||||||
open :: proc(name: string) -> (File, bool) {
|
|
||||||
using win32
|
|
||||||
buf: [300]byte
|
|
||||||
copy(buf[:], name as []byte)
|
|
||||||
f: File
|
|
||||||
f.handle.p = CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, nil) as rawptr
|
|
||||||
success := f.handle.p != INVALID_HANDLE_VALUE
|
|
||||||
f.last_write_time = last_write_time(^f)
|
|
||||||
return f, success
|
|
||||||
}
|
|
||||||
|
|
||||||
create :: proc(name: string) -> (File, bool) {
|
|
||||||
using win32
|
|
||||||
buf: [300]byte
|
|
||||||
copy(buf[:], name as []byte)
|
|
||||||
f: File
|
|
||||||
f.handle.p = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_ALWAYS, 0, nil) as rawptr
|
|
||||||
success := f.handle.p != INVALID_HANDLE_VALUE
|
|
||||||
f.last_write_time = last_write_time(^f)
|
|
||||||
return f, success
|
|
||||||
}
|
|
||||||
|
|
||||||
close :: proc(using f: ^File) {
|
|
||||||
win32.CloseHandle(handle.p as win32.HANDLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
write :: proc(using f: ^File, buf: []byte) -> bool {
|
|
||||||
bytes_written: i32
|
|
||||||
return win32.WriteFile(handle.p as win32.HANDLE, buf.data, buf.count as i32, ^bytes_written, nil) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
file_has_changed :: proc(f: ^File) -> bool {
|
|
||||||
last_write_time := last_write_time(f)
|
|
||||||
if f.last_write_time != last_write_time {
|
|
||||||
f.last_write_time = last_write_time
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
last_write_time :: proc(f: ^File) -> File_Time {
|
|
||||||
file_info: win32.BY_HANDLE_FILE_INFORMATION
|
|
||||||
win32.GetFileInformationByHandle(f.handle.p as win32.HANDLE, ^file_info)
|
|
||||||
l := file_info.last_write_time.low_date_time as File_Time
|
|
||||||
h := file_info.last_write_time.high_date_time as File_Time
|
|
||||||
return l | h << 32
|
|
||||||
}
|
|
||||||
|
|
||||||
last_write_time_by_name :: proc(name: string) -> File_Time {
|
|
||||||
last_write_time: win32.FILETIME
|
|
||||||
data: win32.WIN32_FILE_ATTRIBUTE_DATA
|
|
||||||
|
|
||||||
buf: [1024]byte
|
|
||||||
path := buf[:0]
|
|
||||||
fmt.bprint(^path, name, "\x00")
|
|
||||||
|
|
||||||
if win32.GetFileAttributesExA(path.data, win32.GetFileExInfoStandard, ^data) != 0 {
|
|
||||||
last_write_time = data.last_write_time
|
|
||||||
}
|
|
||||||
|
|
||||||
l := last_write_time.low_date_time as File_Time
|
|
||||||
h := last_write_time.high_date_time as File_Time
|
|
||||||
return l | h << 32
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
File_Standard :: type enum {
|
|
||||||
INPUT,
|
|
||||||
OUTPUT,
|
|
||||||
ERROR,
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE(bill): Uses startup to initialize it
|
|
||||||
__std_files := [File_Standard.count]File{
|
|
||||||
{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE) transmute File.Handle },
|
|
||||||
{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE) transmute File.Handle },
|
|
||||||
{handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE) transmute File.Handle },
|
|
||||||
}
|
|
||||||
|
|
||||||
stdin := ^__std_files[File_Standard.INPUT]
|
|
||||||
stdout := ^__std_files[File_Standard.OUTPUT]
|
|
||||||
stderr := ^__std_files[File_Standard.ERROR]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
|
||||||
buf: [300]byte
|
|
||||||
copy(buf[:], name as []byte)
|
|
||||||
|
|
||||||
f, file_ok := open(name)
|
|
||||||
if !file_ok {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
defer close(^f)
|
|
||||||
|
|
||||||
length: i64
|
|
||||||
file_size_ok := win32.GetFileSizeEx(f.handle.p as win32.HANDLE, ^length) != 0
|
|
||||||
if !file_size_ok {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
data := new_slice(u8, length)
|
|
||||||
if data.data == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
single_read_length: i32
|
|
||||||
total_read: i64
|
|
||||||
|
|
||||||
for total_read < length {
|
|
||||||
remaining := length - total_read
|
|
||||||
to_read: u32
|
|
||||||
MAX :: 1<<32-1
|
|
||||||
if remaining <= MAX {
|
|
||||||
to_read = remaining as u32
|
|
||||||
} else {
|
|
||||||
to_read = MAX
|
|
||||||
}
|
|
||||||
|
|
||||||
win32.ReadFile(f.handle.p as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil)
|
|
||||||
if single_read_length <= 0 {
|
|
||||||
free(data.data)
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
total_read += single_read_length as i64
|
|
||||||
}
|
|
||||||
|
|
||||||
return data, true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr {
|
|
||||||
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size)
|
|
||||||
}
|
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
|
||||||
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size)
|
|
||||||
}
|
|
||||||
heap_free :: proc(ptr: rawptr) {
|
|
||||||
win32.HeapFree(win32.GetProcessHeap(), 0, ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
exit :: proc(code: int) {
|
|
||||||
win32.ExitProcess(code as u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
current_thread_id :: proc() -> int {
|
|
||||||
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
|
||||||
return GetCurrentThreadId() as int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
+132
-109
@@ -223,21 +223,26 @@ typedef struct CheckerContext {
|
|||||||
#define MAP_NAME MapExprInfo
|
#define MAP_NAME MapExprInfo
|
||||||
#include "../map.c"
|
#include "../map.c"
|
||||||
|
|
||||||
|
typedef struct DelayedImport {
|
||||||
|
Scope * parent;
|
||||||
|
AstNodeImportDecl *decl;
|
||||||
|
} DelayedImport;
|
||||||
|
|
||||||
|
|
||||||
// NOTE(bill): Symbol tables
|
// NOTE(bill): Symbol tables
|
||||||
typedef struct CheckerInfo {
|
typedef struct CheckerInfo {
|
||||||
MapTypeAndValue types; // Key: AstNode * | Expression -> Type (and value)
|
MapTypeAndValue types; // Key: AstNode * | Expression -> Type (and value)
|
||||||
MapEntity definitions; // Key: AstNode * | Identifier -> Entity
|
MapEntity definitions; // Key: AstNode * | Identifier -> Entity
|
||||||
MapEntity uses; // Key: AstNode * | Identifier -> Entity
|
MapEntity uses; // Key: AstNode * | Identifier -> Entity
|
||||||
MapScope scopes; // Key: AstNode * | Node -> Scope
|
MapScope scopes; // Key: AstNode * | Node -> Scope
|
||||||
MapExprInfo untyped; // Key: AstNode * | Expression -> ExprInfo
|
MapExprInfo untyped; // Key: AstNode * | Expression -> ExprInfo
|
||||||
MapDeclInfo entities; // Key: Entity *
|
MapDeclInfo entities; // Key: Entity *
|
||||||
MapEntity foreign_procs; // Key: String
|
MapEntity foreign_procs; // Key: String
|
||||||
MapAstFile files; // Key: String (full path)
|
MapAstFile files; // Key: String (full path)
|
||||||
MapIsize type_info_map; // Key: Type *
|
MapIsize type_info_map; // Key: Type *
|
||||||
isize type_info_count;
|
isize type_info_count;
|
||||||
Entity * implicit_values[ImplicitValue_Count];
|
Entity * implicit_values[ImplicitValue_Count];
|
||||||
Array(String) foreign_libraries; // For the linker
|
Array(String) foreign_libraries; // For the linker
|
||||||
} CheckerInfo;
|
} CheckerInfo;
|
||||||
|
|
||||||
typedef struct Checker {
|
typedef struct Checker {
|
||||||
@@ -248,6 +253,8 @@ typedef struct Checker {
|
|||||||
BaseTypeSizes sizes;
|
BaseTypeSizes sizes;
|
||||||
Scope * global_scope;
|
Scope * global_scope;
|
||||||
Array(ProcedureInfo) procs; // NOTE(bill): Procedures to check
|
Array(ProcedureInfo) procs; // NOTE(bill): Procedures to check
|
||||||
|
Array(DelayedImport) delayed_imports;
|
||||||
|
|
||||||
|
|
||||||
gbArena arena;
|
gbArena arena;
|
||||||
gbArena tmp_arena;
|
gbArena tmp_arena;
|
||||||
@@ -608,6 +615,7 @@ void init_checker(Checker *c, Parser *parser, BaseTypeSizes sizes) {
|
|||||||
|
|
||||||
array_init(&c->proc_stack, a);
|
array_init(&c->proc_stack, a);
|
||||||
array_init(&c->procs, a);
|
array_init(&c->procs, a);
|
||||||
|
array_init(&c->delayed_imports, a);
|
||||||
|
|
||||||
// NOTE(bill): Is this big enough or too small?
|
// NOTE(bill): Is this big enough or too small?
|
||||||
isize item_size = gb_max3(gb_size_of(Entity), gb_size_of(Type), gb_size_of(Scope));
|
isize item_size = gb_max3(gb_size_of(Entity), gb_size_of(Type), gb_size_of(Scope));
|
||||||
@@ -633,6 +641,7 @@ void destroy_checker(Checker *c) {
|
|||||||
destroy_scope(c->global_scope);
|
destroy_scope(c->global_scope);
|
||||||
array_free(&c->proc_stack);
|
array_free(&c->proc_stack);
|
||||||
array_free(&c->procs);
|
array_free(&c->procs);
|
||||||
|
array_free(&c->delayed_imports);
|
||||||
|
|
||||||
gb_arena_free(&c->arena);
|
gb_arena_free(&c->arena);
|
||||||
}
|
}
|
||||||
@@ -1117,106 +1126,17 @@ void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray
|
|||||||
switch (decl->kind) {
|
switch (decl->kind) {
|
||||||
case_ast_node(bd, BadDecl, decl);
|
case_ast_node(bd, BadDecl, decl);
|
||||||
case_end;
|
case_end;
|
||||||
|
case_ast_node(ws, WhenStmt, decl);
|
||||||
|
// Will be handled later
|
||||||
|
case_end;
|
||||||
case_ast_node(id, ImportDecl, decl);
|
case_ast_node(id, ImportDecl, decl);
|
||||||
if (!parent_scope->is_file) {
|
if (!parent_scope->is_file) {
|
||||||
// NOTE(bill): _Should_ be caught by the parser
|
// NOTE(bill): _Should_ be caught by the parser
|
||||||
// TODO(bill): Better error handling if it isn't
|
// TODO(bill): Better error handling if it isn't
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
DelayedImport di = {parent_scope, id};
|
||||||
HashKey key = hash_string(id->fullpath);
|
array_add(&c->delayed_imports, di);
|
||||||
Scope **found = map_scope_get(file_scopes, key);
|
|
||||||
if (found == NULL) {
|
|
||||||
for_array(scope_index, file_scopes->entries) {
|
|
||||||
Scope *scope = file_scopes->entries.e[scope_index].value;
|
|
||||||
gb_printf_err("%.*s\n", LIT(scope->file->tokenizer.fullpath));
|
|
||||||
}
|
|
||||||
gb_printf_err("%.*s(%td:%td)\n", LIT(id->token.pos.file), id->token.pos.line, id->token.pos.column);
|
|
||||||
GB_PANIC("Unable to find scope for file: %.*s", LIT(id->fullpath));
|
|
||||||
}
|
|
||||||
Scope *scope = *found;
|
|
||||||
|
|
||||||
if (scope->is_global) {
|
|
||||||
error(id->token, "Importing a #shared_global_scope is disallowed and unnecessary");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool previously_added = false;
|
|
||||||
for_array(import_index, parent_scope->imported) {
|
|
||||||
Scope *prev = parent_scope->imported.e[import_index];
|
|
||||||
if (prev == scope) {
|
|
||||||
previously_added = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!previously_added) {
|
|
||||||
array_add(&parent_scope->imported, scope);
|
|
||||||
} else {
|
|
||||||
warning(id->token, "Multiple #import of the same file within this scope");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (str_eq(id->import_name.string, str_lit("."))) {
|
|
||||||
// NOTE(bill): Add imported entities to this file's scope
|
|
||||||
for_array(elem_index, scope->elements.entries) {
|
|
||||||
Entity *e = scope->elements.entries.e[elem_index].value;
|
|
||||||
if (e->scope == parent_scope) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE(bill): Do not add other imported entities
|
|
||||||
add_entity(c, parent_scope, NULL, e);
|
|
||||||
if (!id->is_load) { // `#import`ed entities don't get exported
|
|
||||||
HashKey key = hash_string(e->token.string);
|
|
||||||
map_entity_set(&parent_scope->implicit, key, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
String import_name = id->import_name.string;
|
|
||||||
if (import_name.len == 0) {
|
|
||||||
// NOTE(bill): use file name (without extension) as the identifier
|
|
||||||
// If it is a valid identifier
|
|
||||||
String filename = id->fullpath;
|
|
||||||
isize slash = 0;
|
|
||||||
isize dot = 0;
|
|
||||||
for (isize i = filename.len-1; i >= 0; i--) {
|
|
||||||
u8 c = filename.text[i];
|
|
||||||
if (c == '/' || c == '\\') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
slash = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
filename.text += slash;
|
|
||||||
filename.len -= slash;
|
|
||||||
|
|
||||||
dot = filename.len;
|
|
||||||
while (dot --> 0) {
|
|
||||||
u8 c = filename.text[dot];
|
|
||||||
if (c == '.') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
filename.len = dot;
|
|
||||||
|
|
||||||
if (is_string_an_identifier(filename)) {
|
|
||||||
import_name = filename;
|
|
||||||
} else {
|
|
||||||
error_node(decl,
|
|
||||||
"File name, %.*s, cannot be as an import name as it is not a valid identifier",
|
|
||||||
LIT(filename));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (import_name.len > 0) {
|
|
||||||
id->import_name.string = import_name;
|
|
||||||
Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid,
|
|
||||||
id->fullpath, id->import_name.string,
|
|
||||||
scope);
|
|
||||||
add_entity(c, parent_scope, NULL, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case_end;
|
case_end;
|
||||||
case_ast_node(fl, ForeignLibrary, decl);
|
case_ast_node(fl, ForeignLibrary, decl);
|
||||||
if (!parent_scope->is_file) {
|
if (!parent_scope->is_file) {
|
||||||
@@ -1244,9 +1164,6 @@ void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray
|
|||||||
|
|
||||||
try_add_foreign_library_path(c, file_str);
|
try_add_foreign_library_path(c, file_str);
|
||||||
case_end;
|
case_end;
|
||||||
case_ast_node(ws, WhenStmt, decl);
|
|
||||||
// Will be handled later
|
|
||||||
case_end;
|
|
||||||
case_ast_node(cd, ConstDecl, decl);
|
case_ast_node(cd, ConstDecl, decl);
|
||||||
for_array(i, cd->values) {
|
for_array(i, cd->values) {
|
||||||
AstNode *name = cd->names.e[i];
|
AstNode *name = cd->names.e[i];
|
||||||
@@ -1347,6 +1264,110 @@ void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void check_import_entities(Checker *c, MapScope *file_scopes) {
|
||||||
|
for_array(i, c->delayed_imports) {
|
||||||
|
AstNodeImportDecl *id = c->delayed_imports.e[i].decl;
|
||||||
|
Scope *parent_scope = c->delayed_imports.e[i].parent;
|
||||||
|
|
||||||
|
HashKey key = hash_string(id->fullpath);
|
||||||
|
Scope **found = map_scope_get(file_scopes, key);
|
||||||
|
if (found == NULL) {
|
||||||
|
for_array(scope_index, file_scopes->entries) {
|
||||||
|
Scope *scope = file_scopes->entries.e[scope_index].value;
|
||||||
|
gb_printf_err("%.*s\n", LIT(scope->file->tokenizer.fullpath));
|
||||||
|
}
|
||||||
|
gb_printf_err("%.*s(%td:%td)\n", LIT(id->token.pos.file), id->token.pos.line, id->token.pos.column);
|
||||||
|
GB_PANIC("Unable to find scope for file: %.*s", LIT(id->fullpath));
|
||||||
|
}
|
||||||
|
Scope *scope = *found;
|
||||||
|
|
||||||
|
if (scope->is_global) {
|
||||||
|
error(id->token, "Importing a #shared_global_scope is disallowed and unnecessary");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool previously_added = false;
|
||||||
|
for_array(import_index, parent_scope->imported) {
|
||||||
|
Scope *prev = parent_scope->imported.e[import_index];
|
||||||
|
if (prev == scope) {
|
||||||
|
previously_added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!previously_added) {
|
||||||
|
array_add(&parent_scope->imported, scope);
|
||||||
|
} else {
|
||||||
|
warning(id->token, "Multiple #import of the same file within this scope");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_eq(id->import_name.string, str_lit("."))) {
|
||||||
|
// NOTE(bill): Add imported entities to this file's scope
|
||||||
|
for_array(elem_index, scope->elements.entries) {
|
||||||
|
Entity *e = scope->elements.entries.e[elem_index].value;
|
||||||
|
if (e->scope == parent_scope) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE(bill): Do not add other imported entities
|
||||||
|
add_entity(c, parent_scope, NULL, e);
|
||||||
|
if (!id->is_load) { // `#import`ed entities don't get exported
|
||||||
|
HashKey key = hash_string(e->token.string);
|
||||||
|
map_entity_set(&parent_scope->implicit, key, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String import_name = id->import_name.string;
|
||||||
|
if (import_name.len == 0) {
|
||||||
|
// NOTE(bill): use file name (without extension) as the identifier
|
||||||
|
// If it is a valid identifier
|
||||||
|
String filename = id->fullpath;
|
||||||
|
isize slash = 0;
|
||||||
|
isize dot = 0;
|
||||||
|
for (isize i = filename.len-1; i >= 0; i--) {
|
||||||
|
u8 c = filename.text[i];
|
||||||
|
if (c == '/' || c == '\\') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
slash = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
filename.text += slash;
|
||||||
|
filename.len -= slash;
|
||||||
|
|
||||||
|
dot = filename.len;
|
||||||
|
while (dot --> 0) {
|
||||||
|
u8 c = filename.text[dot];
|
||||||
|
if (c == '.') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filename.len = dot;
|
||||||
|
|
||||||
|
if (is_string_an_identifier(filename)) {
|
||||||
|
import_name = filename;
|
||||||
|
} else {
|
||||||
|
error(id->token,
|
||||||
|
"File name, %.*s, cannot be as an import name as it is not a valid identifier",
|
||||||
|
LIT(filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (import_name.len > 0) {
|
||||||
|
id->import_name.string = import_name;
|
||||||
|
Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid,
|
||||||
|
id->fullpath, id->import_name.string,
|
||||||
|
scope);
|
||||||
|
add_entity(c, parent_scope, NULL, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void check_parsed_files(Checker *c) {
|
void check_parsed_files(Checker *c) {
|
||||||
MapScope file_scopes; // Key: String (fullpath)
|
MapScope file_scopes; // Key: String (fullpath)
|
||||||
@@ -1384,6 +1405,8 @@ void check_parsed_files(Checker *c) {
|
|||||||
check_global_collect_entities(c, f->scope, f->decls, &file_scopes);
|
check_global_collect_entities(c, f->scope, f->decls, &file_scopes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_import_entities(c, &file_scopes);
|
||||||
|
|
||||||
check_global_entities_by_kind(c, Entity_TypeName);
|
check_global_entities_by_kind(c, Entity_TypeName);
|
||||||
init_preload_types(c);
|
init_preload_types(c);
|
||||||
add_implicit_value(c, ImplicitValue_context, str_lit("context"), str_lit("__context"), t_context);
|
add_implicit_value(c, ImplicitValue_context, str_lit("context"), str_lit("__context"), t_context);
|
||||||
|
|||||||
+6
-5
@@ -2367,8 +2367,7 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return make_type_decl(f, token, names.e[0], parse_type(f));
|
return make_type_decl(f, token, names.e[0], parse_type(f));
|
||||||
} else if (f->curr_token.kind == Token_proc &&
|
} else if (f->curr_token.kind == Token_proc && is_mutable == false) {
|
||||||
is_mutable == false) {
|
|
||||||
// NOTE(bill): Procedure declarations
|
// NOTE(bill): Procedure declarations
|
||||||
Token proc_token = f->curr_token;
|
Token proc_token = f->curr_token;
|
||||||
AstNode *name = names.e[0];
|
AstNode *name = names.e[0];
|
||||||
@@ -2904,7 +2903,7 @@ AstNode *parse_stmt(AstFile *f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return make_import_decl(f, s->TagStmt.token, file_path, import_name, os, arch, false);
|
return make_import_decl(f, s->TagStmt.token, file_path, import_name, os, arch, false);
|
||||||
} else if (str_eq(tag, str_lit("include"))) {
|
} else if (str_eq(tag, str_lit("load"))) {
|
||||||
String os = {0};
|
String os = {0};
|
||||||
String arch = {0};
|
String arch = {0};
|
||||||
// TODO(bill): better error messages
|
// TODO(bill): better error messages
|
||||||
@@ -2912,10 +2911,12 @@ AstNode *parse_stmt(AstFile *f) {
|
|||||||
Token import_name = file_path;
|
Token import_name = file_path;
|
||||||
import_name.string = str_lit(".");
|
import_name.string = str_lit(".");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (f->curr_proc == NULL) {
|
if (f->curr_proc == NULL) {
|
||||||
return make_import_decl(f, s->TagStmt.token, file_path, import_name, os, arch, true);
|
return make_import_decl(f, s->TagStmt.token, file_path, import_name, os, arch, true);
|
||||||
}
|
}
|
||||||
syntax_error(token, "You cannot use #include within a procedure. This must be done at the file scope");
|
syntax_error(token, "You cannot use #load within a procedure. This must be done at the file scope");
|
||||||
return make_bad_decl(f, token, file_path);
|
return make_bad_decl(f, token, file_path);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -3195,7 +3196,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray
|
|||||||
node->kind != AstNode_BadStmt &&
|
node->kind != AstNode_BadStmt &&
|
||||||
node->kind != AstNode_EmptyStmt) {
|
node->kind != AstNode_EmptyStmt) {
|
||||||
// NOTE(bill): Sanity check
|
// NOTE(bill): Sanity check
|
||||||
syntax_error_node(node, "Only declarations are allowed at file scope");
|
syntax_error_node(node, "Only declarations are allowed at file scope %.*s", LIT(ast_node_strings[node->kind]));
|
||||||
} else if (node->kind == AstNode_WhenStmt) {
|
} else if (node->kind == AstNode_WhenStmt) {
|
||||||
parse_setup_file_when_stmt(p, f, base_dir, &node->WhenStmt);
|
parse_setup_file_when_stmt(p, f, base_dir, &node->WhenStmt);
|
||||||
} else if (node->kind == AstNode_ImportDecl) {
|
} else if (node->kind == AstNode_ImportDecl) {
|
||||||
|
|||||||
Reference in New Issue
Block a user