mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 23:28:48 +00:00
#import "" as namespace
This commit is contained in:
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
#import "print.odin"
|
#import "print.odin" as _
|
||||||
|
|
||||||
test_proc :: proc() {
|
test_proc :: proc() {
|
||||||
println("Hello?")
|
println("Hello?")
|
||||||
|
|||||||
-106
@@ -1,106 +0,0 @@
|
|||||||
#import "win32.odin"
|
|
||||||
|
|
||||||
File :: type struct {
|
|
||||||
Handle :: type HANDLE
|
|
||||||
handle: Handle
|
|
||||||
}
|
|
||||||
|
|
||||||
file_open :: proc(name: string) -> (File, bool) {
|
|
||||||
buf: [300]byte
|
|
||||||
_ = copy(buf[:], name as []byte)
|
|
||||||
f := File{CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null)}
|
|
||||||
success := f.handle != INVALID_HANDLE_VALUE as File.Handle
|
|
||||||
|
|
||||||
return f, success
|
|
||||||
}
|
|
||||||
|
|
||||||
file_create :: proc(name: string) -> (File, bool) {
|
|
||||||
buf: [300]byte
|
|
||||||
_ = copy(buf[:], name as []byte)
|
|
||||||
f := File{
|
|
||||||
handle = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, 0, null),
|
|
||||||
}
|
|
||||||
success := f.handle != INVALID_HANDLE_VALUE as File.Handle
|
|
||||||
return f, success
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
file_close :: proc(f: ^File) {
|
|
||||||
CloseHandle(f.handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
file_write :: proc(f: ^File, buf: []byte) -> bool {
|
|
||||||
bytes_written: i32
|
|
||||||
return WriteFile(f.handle, ^buf[0], buf.count as i32, ^bytes_written, null) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
File_Standard :: type enum {
|
|
||||||
INPUT,
|
|
||||||
OUTPUT,
|
|
||||||
ERROR,
|
|
||||||
COUNT,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
__std_files := __set_file_standards();
|
|
||||||
|
|
||||||
__set_file_standards :: proc() -> [File_Standard.COUNT as int]File {
|
|
||||||
return [File_Standard.COUNT as int]File{
|
|
||||||
File{handle = GetStdHandle(STD_INPUT_HANDLE)},
|
|
||||||
File{handle = GetStdHandle(STD_OUTPUT_HANDLE)},
|
|
||||||
File{handle = GetStdHandle(STD_ERROR_HANDLE)},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file_get_standard :: proc(std: File_Standard) -> ^File {
|
|
||||||
return ^__std_files[std]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
read_entire_file :: proc(name: string) -> (string, bool) {
|
|
||||||
buf: [300]byte
|
|
||||||
_ = copy(buf[:], name as []byte)
|
|
||||||
c_string := ^buf[0]
|
|
||||||
|
|
||||||
|
|
||||||
f, file_ok := file_open(name)
|
|
||||||
if !file_ok {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
defer file_close(^f)
|
|
||||||
|
|
||||||
length: i64
|
|
||||||
file_size_ok := GetFileSizeEx(f.handle as HANDLE, ^length) != 0
|
|
||||||
if !file_size_ok {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
data := new_slice(u8, length)
|
|
||||||
if ^data[0] == null {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
single_read_length: i32
|
|
||||||
total_read: i64
|
|
||||||
|
|
||||||
for total_read < length {
|
|
||||||
remaining := length - total_read
|
|
||||||
to_read: u32
|
|
||||||
MAX :: 0x7fffffff
|
|
||||||
if remaining <= MAX {
|
|
||||||
to_read = remaining as u32
|
|
||||||
} else {
|
|
||||||
to_read = MAX
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadFile(f.handle as HANDLE, ^data[total_read], to_read, ^single_read_length, null)
|
|
||||||
if single_read_length <= 0 {
|
|
||||||
free(^data[0])
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
total_read += single_read_length as i64
|
|
||||||
}
|
|
||||||
|
|
||||||
return data as string, true
|
|
||||||
}
|
|
||||||
+10
-11
@@ -1,6 +1,5 @@
|
|||||||
#import "runtime.odin"
|
#import "runtime.odin" as _
|
||||||
#import "win32.odin"
|
#import "os.odin" as os
|
||||||
#import "file.odin"
|
|
||||||
|
|
||||||
print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
|
print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
|
||||||
if buf.count < buf.capacity {
|
if buf.count < buf.capacity {
|
||||||
@@ -555,31 +554,31 @@ print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) {
|
|||||||
|
|
||||||
PRINT_BUF_SIZE :: 1<<12
|
PRINT_BUF_SIZE :: 1<<12
|
||||||
|
|
||||||
print_to_file :: proc(f: ^File, fmt: string, args: ..any) {
|
print_to_file :: proc(f: ^os.File, fmt: string, args: ..any) {
|
||||||
data: [PRINT_BUF_SIZE]byte
|
data: [PRINT_BUF_SIZE]byte
|
||||||
buf := data[:0]
|
buf := data[:0]
|
||||||
print_to_buffer(^buf, fmt, ..args)
|
print_to_buffer(^buf, fmt, ..args)
|
||||||
file_write(f, buf)
|
os.write(f, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
println_to_file :: proc(f: ^File, fmt: string, args: ..any) {
|
println_to_file :: proc(f: ^os.File, fmt: string, args: ..any) {
|
||||||
data: [PRINT_BUF_SIZE]byte
|
data: [PRINT_BUF_SIZE]byte
|
||||||
buf := data[:0]
|
buf := data[:0]
|
||||||
print_to_buffer(^buf, fmt, ..args)
|
print_to_buffer(^buf, fmt, ..args)
|
||||||
print_nl_to_buffer(^buf)
|
print_nl_to_buffer(^buf)
|
||||||
file_write(f, buf)
|
os.write(f, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
print :: proc(fmt: string, args: ..any) {
|
print :: proc(fmt: string, args: ..any) {
|
||||||
print_to_file(file_get_standard(File_Standard.OUTPUT), fmt, ..args)
|
print_to_file(os.file_get_standard(os.File_Standard.OUTPUT), fmt, ..args)
|
||||||
}
|
}
|
||||||
print_err :: proc(fmt: string, args: ..any) {
|
print_err :: proc(fmt: string, args: ..any) {
|
||||||
print_to_file(file_get_standard(File_Standard.ERROR), fmt, ..args)
|
print_to_file(os.file_get_standard(os.File_Standard.ERROR), fmt, ..args)
|
||||||
}
|
}
|
||||||
println :: proc(fmt: string, args: ..any) {
|
println :: proc(fmt: string, args: ..any) {
|
||||||
println_to_file(file_get_standard(File_Standard.OUTPUT), fmt, ..args)
|
println_to_file(os.file_get_standard(os.File_Standard.OUTPUT), fmt, ..args)
|
||||||
}
|
}
|
||||||
println_err :: proc(fmt: string, args: ..any) {
|
println_err :: proc(fmt: string, args: ..any) {
|
||||||
println_to_file(file_get_standard(File_Standard.ERROR), fmt, ..args)
|
println_to_file(os.file_get_standard(os.File_Standard.ERROR), fmt, ..args)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-7
@@ -1,9 +1,9 @@
|
|||||||
#global_scope
|
#global_scope
|
||||||
|
|
||||||
// TODO(bill): Remove #import in runtime.odin
|
// TODO(bill): Remove #import in runtime.odin
|
||||||
#import "win32.odin"
|
#import "win32.odin" as win32
|
||||||
#import "file.odin"
|
#import "os.odin" as os
|
||||||
#import "print.odin"
|
#import "print.odin" as _
|
||||||
|
|
||||||
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
||||||
// The compiler relies upon this _exact_ order
|
// The compiler relies upon this _exact_ order
|
||||||
@@ -84,15 +84,15 @@ fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
|
|||||||
fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
|
fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
|
||||||
|
|
||||||
heap_alloc :: proc(len: int) -> rawptr {
|
heap_alloc :: proc(len: int) -> rawptr {
|
||||||
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len)
|
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, len)
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_free :: proc(ptr: rawptr) {
|
heap_free :: proc(ptr: rawptr) {
|
||||||
_ = HeapFree(GetProcessHeap(), 0, ptr)
|
_ = win32.HeapFree(win32.GetProcessHeap(), 0, ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
current_thread_id :: proc() -> int {
|
current_thread_id :: proc() -> int {
|
||||||
id := GetCurrentThreadId()
|
id := win32.GetCurrentThreadId()
|
||||||
return id as int
|
return id as int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ __string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >
|
|||||||
|
|
||||||
|
|
||||||
__assert :: proc(msg: string) {
|
__assert :: proc(msg: string) {
|
||||||
file_write(file_get_standard(File_Standard.ERROR), msg as []byte)
|
os.write(os.file_get_standard(os.File_Standard.ERROR), msg as []byte)
|
||||||
__debug_trap()
|
__debug_trap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+30
-22
@@ -315,7 +315,7 @@ void check_close_scope(Checker *c) {
|
|||||||
c->context.scope = c->context.scope->parent;
|
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;
|
b32 gone_thru_proc = false;
|
||||||
HashKey key = hash_string(name);
|
HashKey key = hash_string(name);
|
||||||
for (Scope *s = scope; s != NULL; s = s->parent) {
|
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;
|
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;
|
Entity *entity = NULL;
|
||||||
scope_lookup_parent_entity(c, s, name, NULL, &entity);
|
scope_lookup_parent_entity(s, name, NULL, &entity);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -949,33 +949,41 @@ void check_parsed_files(Checker *c) {
|
|||||||
|
|
||||||
gb_for_array(decl_index, f->decls) {
|
gb_for_array(decl_index, f->decls) {
|
||||||
AstNode *decl = f->decls[decl_index];
|
AstNode *decl = f->decls[decl_index];
|
||||||
switch (decl->kind) {
|
if (decl->kind != AstNode_ImportDecl) {
|
||||||
case_ast_node(id, ImportDecl, decl);
|
continue;
|
||||||
HashKey key = hash_string(id->fullpath);
|
}
|
||||||
auto found = map_get(&file_scopes, key);
|
ast_node(id, ImportDecl, decl);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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
|
// NOTE(bill): Add imported entities to this file's scope
|
||||||
gb_for_array(elem_index, scope->elements.entries) {
|
gb_for_array(elem_index, scope->elements.entries) {
|
||||||
Entity *e = scope->elements.entries[elem_index].value;
|
Entity *e = scope->elements.entries[elem_index].value;
|
||||||
// NOTE(bill): Do not add other imported entities
|
// 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);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-1
@@ -9,6 +9,7 @@ enum BuiltinProcId;
|
|||||||
ENTITY_KIND(TypeName), \
|
ENTITY_KIND(TypeName), \
|
||||||
ENTITY_KIND(Procedure), \
|
ENTITY_KIND(Procedure), \
|
||||||
ENTITY_KIND(Builtin), \
|
ENTITY_KIND(Builtin), \
|
||||||
|
ENTITY_KIND(ImportName), \
|
||||||
ENTITY_KIND(Count),
|
ENTITY_KIND(Count),
|
||||||
|
|
||||||
|
|
||||||
@@ -49,11 +50,19 @@ struct Entity {
|
|||||||
i32 field_index; // Order in source
|
i32 field_index; // Order in source
|
||||||
b8 is_field; // Is struct field
|
b8 is_field; // Is struct field
|
||||||
} Variable;
|
} Variable;
|
||||||
struct {} TypeName;
|
struct {
|
||||||
|
struct DeclInfo *decl; // Usually NULL
|
||||||
|
} TypeName;
|
||||||
struct {
|
struct {
|
||||||
b8 pure;
|
b8 pure;
|
||||||
} Procedure;
|
} Procedure;
|
||||||
struct { BuiltinProcId id; } Builtin;
|
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;
|
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) {
|
Entity *make_entity_dummy_variable(gbAllocator a, Scope *file_scope, Token token) {
|
||||||
token.string = make_string("_");
|
token.string = make_string("_");
|
||||||
return make_entity_variable(a, file_scope, token, NULL);
|
return make_entity_variable(a, file_scope, token, NULL);
|
||||||
|
|||||||
+114
-65
@@ -286,8 +286,9 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
|||||||
Token name_token = td->name->Ident;
|
Token name_token = td->name->Ident;
|
||||||
|
|
||||||
Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, NULL);
|
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);
|
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);
|
HashKey key = hash_string(name_token.string);
|
||||||
if (map_get(&entity_map, key) != NULL) {
|
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);
|
GB_ASSERT(n->kind == AstNode_Ident);
|
||||||
o->mode = Addressing_Invalid;
|
o->mode = Addressing_Invalid;
|
||||||
o->expr = n;
|
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) {
|
if (e == NULL) {
|
||||||
error(&c->error_collector, n->Ident,
|
if (are_strings_equal(n->Ident.string, make_string("_"))) {
|
||||||
"Undeclared type or identifier `%.*s`", LIT(n->Ident.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;
|
return;
|
||||||
}
|
}
|
||||||
add_entity_use(&c->info, n, e);
|
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);
|
gb_array_free(local_cycle_checker.path);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (e->type == NULL) {
|
check_entity_decl(c, e, NULL, named_type, cycle_checker);
|
||||||
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!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e->type == NULL) {
|
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));
|
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;
|
o->mode = Addressing_Builtin;
|
||||||
break;
|
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:
|
default:
|
||||||
GB_PANIC("Compiler error: Unknown EntityKind");
|
GB_PANIC("Compiler error: Unknown EntityKind");
|
||||||
break;
|
break;
|
||||||
@@ -875,18 +877,30 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
|
|||||||
|
|
||||||
case_ast_node(se, SelectorExpr, e);
|
case_ast_node(se, SelectorExpr, e);
|
||||||
Operand o = {};
|
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);
|
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);
|
set_base_type(type, o.type);
|
||||||
o.type->flags |= e->type_flags;
|
o.type->flags |= e->type_flags;
|
||||||
return o.type;
|
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;
|
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) {
|
Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||||
GB_ASSERT(node->kind == AstNode_SelectorExpr);
|
|
||||||
|
|
||||||
ast_node(se, SelectorExpr, node);
|
ast_node(se, SelectorExpr, node);
|
||||||
|
|
||||||
|
b32 check_op_expr = true;
|
||||||
|
Entity *entity = NULL;
|
||||||
|
|
||||||
AstNode *op_expr = se->expr;
|
AstNode *op_expr = se->expr;
|
||||||
AstNode *selector = se->selector;
|
AstNode *selector = unparen_expr(se->selector);
|
||||||
if (selector) {
|
if (selector == NULL) {
|
||||||
Entity *entity = lookup_field(operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity;
|
goto error;
|
||||||
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);
|
|
||||||
|
|
||||||
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;
|
|
||||||
} else {
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
operand->expr = node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
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);
|
case_ast_node(se, SelectorExpr, node);
|
||||||
check_expr_base(c, o, se->expr);
|
|
||||||
check_selector(c, o, node);
|
check_selector(c, o, node);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
|||||||
+40
-10
@@ -171,7 +171,7 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
|||||||
b32 used = false;
|
b32 used = false;
|
||||||
if (node->kind == AstNode_Ident) {
|
if (node->kind == AstNode_Ident) {
|
||||||
ast_node(i, Ident, node);
|
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) {
|
if (e != NULL && e->kind == Entity_Variable) {
|
||||||
used = e->Variable.used; // TODO(bill): Make backup just in case
|
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);
|
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);
|
named->Named.base = get_base_type(named->Named.base);
|
||||||
if (named->Named.base == t_invalid) {
|
if (named->Named.base == t_invalid) {
|
||||||
// gb_printf("check_type_decl: %s\n", type_to_string(named));
|
// 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) {
|
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, CycleChecker *cycle_checker) {
|
||||||
if (e->type != NULL)
|
if (e->type != NULL) {
|
||||||
return;
|
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) {
|
switch (e->kind) {
|
||||||
case Entity_Constant: {
|
case Entity_Constant: {
|
||||||
Scope *prev = c->context.scope;
|
Scope *prev = c->context.scope;
|
||||||
c->context.scope = d->scope;
|
c->context.scope = d->scope;
|
||||||
defer (c->context.scope = prev);
|
|
||||||
c->context.decl = d;
|
c->context.decl = d;
|
||||||
|
|
||||||
check_const_decl(c, e, d->type_expr, d->init_expr);
|
check_const_decl(c, e, d->type_expr, d->init_expr);
|
||||||
|
|
||||||
|
c->context.scope = prev;
|
||||||
} break;
|
} break;
|
||||||
case Entity_Variable: {
|
case Entity_Variable: {
|
||||||
Scope *prev = c->context.scope;
|
Scope *prev = c->context.scope;
|
||||||
c->context.scope = d->scope;
|
c->context.scope = d->scope;
|
||||||
defer (c->context.scope = prev);
|
|
||||||
c->context.decl = d;
|
c->context.decl = d;
|
||||||
|
|
||||||
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
|
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
|
||||||
|
|
||||||
|
c->context.scope = prev;
|
||||||
} break;
|
} break;
|
||||||
case Entity_TypeName: {
|
case Entity_TypeName: {
|
||||||
CycleChecker local_cycle_checker = {};
|
CycleChecker local_cycle_checker = {};
|
||||||
@@ -1234,7 +1252,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
AstNode *expr = unparen_expr(es->expr);
|
AstNode *expr = unparen_expr(es->expr);
|
||||||
if (expr->kind == AstNode_Ident) {
|
if (expr->kind == AstNode_Ident) {
|
||||||
String name = expr->Ident.string;
|
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) {
|
} else if (expr->kind == AstNode_SelectorExpr) {
|
||||||
Operand o = {};
|
Operand o = {};
|
||||||
check_expr_base(c, &o, expr->SelectorExpr.expr);
|
check_expr_base(c, &o, expr->SelectorExpr.expr);
|
||||||
@@ -1285,6 +1303,18 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
} break;
|
} 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:
|
case Entity_Constant:
|
||||||
error(&c->error_collector, us->token, "`using` cannot be applied to a constant");
|
error(&c->error_collector, us->token, "`using` cannot be applied to a constant");
|
||||||
break;
|
break;
|
||||||
@@ -1334,7 +1364,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
AstNode *item = vd->names[name_index];
|
AstNode *item = vd->names[name_index];
|
||||||
ast_node(i, Ident, item);
|
ast_node(i, Ident, item);
|
||||||
String name = i->string;
|
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));
|
Type *t = get_base_type(type_deref(e->type));
|
||||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||||
Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node));
|
Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ void ssa_gen_tree(ssaGen *s) {
|
|||||||
if (str[i] == '\\') {
|
if (str[i] == '\\') {
|
||||||
str[i] = '/';
|
str[i] = '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
char const *base = gb_path_base_name(str);
|
char const *base = gb_path_base_name(str);
|
||||||
char const *ext = gb_path_extension(base);
|
char const *ext = gb_path_extension(base);
|
||||||
|
|||||||
+52
-35
@@ -744,7 +744,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
|
|||||||
|
|
||||||
void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
|
void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
|
||||||
if (proc->body == NULL) {
|
if (proc->body == NULL) {
|
||||||
ssa_fprintf(f, "\ndeclare ");
|
ssa_fprintf(f, "declare ");
|
||||||
} else {
|
} else {
|
||||||
ssa_fprintf(f, "\ndefine ");
|
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) {
|
gb_for_array(member_index, m->members.entries) {
|
||||||
auto *entry = &m->members.entries[member_index];
|
auto *entry = &m->members.entries[member_index];
|
||||||
ssaValue *v = entry->value;
|
ssaValue *v = entry->value;
|
||||||
switch (v->kind) {
|
if (v->kind != ssaValue_TypeName) {
|
||||||
case ssaValue_TypeName:
|
continue;
|
||||||
ssa_print_type_name(f, m, v);
|
}
|
||||||
break;
|
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;
|
||||||
|
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) {
|
gb_for_array(member_index, m->members.entries) {
|
||||||
auto *entry = &m->members.entries[member_index];
|
auto *entry = &m->members.entries[member_index];
|
||||||
ssaValue *v = entry->value;
|
ssaValue *v = entry->value;
|
||||||
switch (v->kind) {
|
if (v->kind != ssaValue_Proc) {
|
||||||
case ssaValue_Global: {
|
continue;
|
||||||
auto *g = &v->Global;
|
}
|
||||||
ssa_print_encoded_global(f, g->entity->token.string);
|
if (v->Proc.body != NULL) {
|
||||||
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 ");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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");
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case ssaValue_Proc: {
|
|
||||||
ssa_print_proc(f, m, &v->Proc);
|
ssa_print_proc(f, m, &v->Proc);
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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, "constant ");
|
||||||
|
} else {
|
||||||
|
ssa_fprintf(f, "global ");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-6
@@ -927,6 +927,11 @@ ssaValue *ssa_lvalue_load(ssaProcedure *proc, ssaAddr lval) {
|
|||||||
ssaValue *v = ssa_emit_load(proc, lval.addr);
|
ssaValue *v = ssa_emit_load(proc, lval.addr);
|
||||||
return ssa_emit(proc, ssa_make_instr_extract_element(proc, v, lval.index));
|
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);
|
return ssa_emit_load(proc, lval.addr);
|
||||||
}
|
}
|
||||||
GB_PANIC("Illegal lvalue load");
|
GB_PANIC("Illegal lvalue load");
|
||||||
@@ -2519,13 +2524,20 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
|||||||
case_ast_node(se, SelectorExpr, expr);
|
case_ast_node(se, SelectorExpr, expr);
|
||||||
ssa_emit_comment(proc, make_string("SelectorExpr"));
|
ssa_emit_comment(proc, make_string("SelectorExpr"));
|
||||||
Type *type = get_base_type(type_of_expr(proc->module->info, se->expr));
|
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);
|
ssaValue *e = ssa_build_addr(proc, se->expr).addr;
|
||||||
GB_ASSERT(sel.entity != NULL);
|
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_end;
|
||||||
|
|
||||||
case_ast_node(ue, UnaryExpr, expr);
|
case_ast_node(ue, UnaryExpr, expr);
|
||||||
|
|||||||
+30
-11
@@ -43,11 +43,15 @@ struct AstFile {
|
|||||||
TokenPos fix_prev_pos;
|
TokenPos fix_prev_pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ImportedFile {
|
||||||
|
String path;
|
||||||
|
TokenPos pos; // #import
|
||||||
|
};
|
||||||
|
|
||||||
struct Parser {
|
struct Parser {
|
||||||
String init_fullpath;
|
String init_fullpath;
|
||||||
gbArray(AstFile) files;
|
gbArray(AstFile) files;
|
||||||
gbArray(String) imports;
|
gbArray(ImportedFile) imports;
|
||||||
gbArray(String) libraries;
|
gbArray(String) libraries;
|
||||||
gbArray(String) system_libraries;
|
gbArray(String) system_libraries;
|
||||||
isize load_index;
|
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(TypeDecl, "type declaration", struct { Token token; AstNode *name, *type; }) \
|
||||||
AST_NODE_KIND(ImportDecl, "import declaration", struct { \
|
AST_NODE_KIND(ImportDecl, "import declaration", struct { \
|
||||||
Token token, relpath; \
|
Token token, relpath; \
|
||||||
String fullpath; \
|
String fullpath; \
|
||||||
|
Token import_name; \
|
||||||
}) \
|
}) \
|
||||||
AST_NODE_KIND(ForeignSystemLibrary, "foreign system library", struct { Token token, filepath; }) \
|
AST_NODE_KIND(ForeignSystemLibrary, "foreign system library", struct { Token token, filepath; }) \
|
||||||
AST_NODE_KIND(_DeclEnd, "", struct{}) \
|
AST_NODE_KIND(_DeclEnd, "", struct{}) \
|
||||||
@@ -883,10 +888,11 @@ gb_inline AstNode *make_type_decl(AstFile *f, Token token, AstNode *name, AstNod
|
|||||||
return result;
|
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);
|
AstNode *result = make_node(f, AstNode_ImportDecl);
|
||||||
result->ImportDecl.token = token;
|
result->ImportDecl.token = token;
|
||||||
result->ImportDecl.relpath = relpath;
|
result->ImportDecl.relpath = relpath;
|
||||||
|
result->ImportDecl.import_name = import_name;
|
||||||
return result;
|
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.");
|
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]);
|
return make_bad_decl(f, token, f->cursor[0]);
|
||||||
} else if (are_strings_equal(tag, make_string("import"))) {
|
} else if (are_strings_equal(tag, make_string("import"))) {
|
||||||
|
// TODO(bill): better error messages
|
||||||
Token file_path = expect_token(f, Token_String);
|
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) {
|
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.");
|
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);
|
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
|
// 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) {
|
gb_for_array(i, p->imports) {
|
||||||
String import = p->imports[i];
|
String import = p->imports[i].path;
|
||||||
if (are_strings_equal(import, import_file)) {
|
if (are_strings_equal(import, path)) {
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2799,7 +2812,7 @@ void parse_file(Parser *p, AstFile *f) {
|
|||||||
String import_file = make_string(path_str);
|
String import_file = make_string(path_str);
|
||||||
|
|
||||||
id->fullpath = import_file;
|
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);
|
// gb_free(gb_heap_allocator(), import_file.text);
|
||||||
}
|
}
|
||||||
} else if (node->kind == AstNode_ForeignSystemLibrary) {
|
} 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) {
|
ParseFileError parse_files(Parser *p, char *init_filename) {
|
||||||
char *fullpath_str = gb_path_get_full_name(gb_heap_allocator(), init_filename);
|
char *fullpath_str = gb_path_get_full_name(gb_heap_allocator(), init_filename);
|
||||||
String init_fullpath = make_string(fullpath_str);
|
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;
|
p->init_fullpath = init_fullpath;
|
||||||
|
|
||||||
gb_for_array(i, p->imports) {
|
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 = {};
|
AstFile file = {};
|
||||||
ParseFileError err = init_ast_file(&file, import_path);
|
ParseFileError err = init_ast_file(&file, import_path);
|
||||||
if (err != ParseFile_None) {
|
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));
|
gb_printf_err("Failed to parse file: %.*s\n", LIT(import_path));
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case ParseFile_WrongExtension:
|
case ParseFile_WrongExtension:
|
||||||
|
|||||||
Reference in New Issue
Block a user