mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 16:18:52 +00:00
This commit is contained in:
+19
-19
@@ -1,4 +1,4 @@
|
|||||||
#import "fmt.odin";
|
#import . "fmt.odin";
|
||||||
#import "atomic.odin";
|
#import "atomic.odin";
|
||||||
#import "hash.odin";
|
#import "hash.odin";
|
||||||
#import "math.odin";
|
#import "math.odin";
|
||||||
@@ -6,18 +6,18 @@
|
|||||||
#import "opengl.odin";
|
#import "opengl.odin";
|
||||||
#import "os.odin";
|
#import "os.odin";
|
||||||
#import "sync.odin";
|
#import "sync.odin";
|
||||||
|
#import "types.odin";
|
||||||
#import "utf8.odin";
|
#import "utf8.odin";
|
||||||
#import ht "http_test.odin";
|
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
|
|
||||||
{
|
{
|
||||||
Fruit :: enum {
|
Fruit :: enum {
|
||||||
APPLE,
|
APPLE,
|
||||||
BANANA,
|
BANANA,
|
||||||
COCONUT,
|
COCONUT,
|
||||||
}
|
}
|
||||||
|
println(x, Fruit.names);
|
||||||
fmt.println(Fruit.names);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
when false {
|
when false {
|
||||||
@@ -33,16 +33,16 @@ when false {
|
|||||||
c := m[3.0];
|
c := m[3.0];
|
||||||
assert(ok && c == 564);
|
assert(ok && c == 564);
|
||||||
|
|
||||||
fmt.print("map[");
|
print("map[");
|
||||||
i := 0;
|
i := 0;
|
||||||
for val, key in m {
|
for val, key in m {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
fmt.print(", ");
|
print(", ");
|
||||||
}
|
}
|
||||||
fmt.printf("%v=%v", key, val);
|
printf("%v=%v", key, val);
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
fmt.println("]");
|
println("]");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
m := map[string]u32{
|
m := map[string]u32{
|
||||||
@@ -56,11 +56,11 @@ when false {
|
|||||||
_, ok := m["c"];
|
_, ok := m["c"];
|
||||||
assert(ok && c == 7654);
|
assert(ok && c == 7654);
|
||||||
|
|
||||||
fmt.println(m);
|
println(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
fmt.println("Hellope!");
|
println("Hellope!");
|
||||||
|
|
||||||
x: [dynamic]f64;
|
x: [dynamic]f64;
|
||||||
reserve(x, 16);
|
reserve(x, 16);
|
||||||
@@ -68,24 +68,24 @@ when false {
|
|||||||
append(x, 2_000_000.500_000, 3, 5, 7);
|
append(x, 2_000_000.500_000, 3, 5, 7);
|
||||||
|
|
||||||
for p, i in x {
|
for p, i in x {
|
||||||
if i > 0 { fmt.print(", "); }
|
if i > 0 { print(", "); }
|
||||||
fmt.print(p);
|
print(p);
|
||||||
}
|
}
|
||||||
fmt.println();
|
println();
|
||||||
|
|
||||||
{
|
{
|
||||||
Vec3 :: [vector 3]f32;
|
Vec3 :: [vector 3]f32;
|
||||||
|
|
||||||
x := Vec3{1, 2, 3};
|
x := Vec3{1, 2, 3};
|
||||||
y := Vec3{4, 5, 6};
|
y := Vec3{4, 5, 6};
|
||||||
fmt.println(x < y);
|
println(x < y);
|
||||||
fmt.println(x + y);
|
println(x + y);
|
||||||
fmt.println(x - y);
|
println(x - y);
|
||||||
fmt.println(x * y);
|
println(x * y);
|
||||||
fmt.println(x / y);
|
println(x / y);
|
||||||
|
|
||||||
for i in x {
|
for i in x {
|
||||||
fmt.println(i);
|
println(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -17,7 +17,7 @@
|
|||||||
Type_Info_Member :: struct #ordered {
|
Type_Info_Member :: struct #ordered {
|
||||||
name: string, // can be empty if tuple
|
name: string, // can be empty if tuple
|
||||||
type_info: ^Type_Info,
|
type_info: ^Type_Info,
|
||||||
offset: int, // offsets are not used in tuples
|
offset: int, // offsets may not be used in tuples
|
||||||
}
|
}
|
||||||
Type_Info_Record :: struct #ordered {
|
Type_Info_Record :: struct #ordered {
|
||||||
fields: []Type_Info_Member,
|
fields: []Type_Info_Member,
|
||||||
@@ -83,7 +83,7 @@ Type_Info :: union {
|
|||||||
count: int,
|
count: int,
|
||||||
align: int,
|
align: int,
|
||||||
},
|
},
|
||||||
Tuple: Type_Info_Record,
|
Tuple: Type_Info_Record, // Only really used for procedures
|
||||||
Struct: Type_Info_Record,
|
Struct: Type_Info_Record,
|
||||||
Union: Type_Info_Record,
|
Union: Type_Info_Record,
|
||||||
Raw_Union: Type_Info_Record,
|
Raw_Union: Type_Info_Record,
|
||||||
@@ -373,7 +373,7 @@ Raw_Dynamic_Array :: struct #ordered {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Raw_Dynamic_Map :: struct #ordered {
|
Raw_Dynamic_Map :: struct #ordered {
|
||||||
hashes: [dynamic]int,
|
hashes: [...]int,
|
||||||
entries: Raw_Dynamic_Array,
|
entries: Raw_Dynamic_Array,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
|
_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
|
||||||
|
|
||||||
|
|
||||||
yield_thread :: proc() { win32._mm_pause(); }
|
yield_thread :: proc() { win32.mm_pause(); }
|
||||||
mfence :: proc() { win32.ReadWriteBarrier(); }
|
mfence :: proc() { win32.ReadWriteBarrier(); }
|
||||||
sfence :: proc() { win32.WriteBarrier(); }
|
sfence :: proc() { win32.WriteBarrier(); }
|
||||||
lfence :: proc() { win32.ReadBarrier(); }
|
lfence :: proc() { win32.ReadBarrier(); }
|
||||||
|
|||||||
+11
-11
@@ -3,7 +3,8 @@
|
|||||||
#import "utf8.odin";
|
#import "utf8.odin";
|
||||||
#import "types.odin";
|
#import "types.odin";
|
||||||
|
|
||||||
DEFAULT_BUFFER_SIZE :: 1<<12;
|
|
||||||
|
_BUFFER_SIZE :: 1<<12;
|
||||||
|
|
||||||
Buffer :: struct {
|
Buffer :: struct {
|
||||||
data: []byte,
|
data: []byte,
|
||||||
@@ -60,7 +61,7 @@ Fmt_Info :: struct {
|
|||||||
|
|
||||||
|
|
||||||
fprint :: proc(fd: os.Handle, args: ...any) -> int {
|
fprint :: proc(fd: os.Handle, args: ...any) -> int {
|
||||||
data: [DEFAULT_BUFFER_SIZE]byte;
|
data: [_BUFFER_SIZE]byte;
|
||||||
buf := Buffer{data[:], 0};
|
buf := Buffer{data[:], 0};
|
||||||
bprint(^buf, ...args);
|
bprint(^buf, ...args);
|
||||||
os.write(fd, buf.data[:buf.length]);
|
os.write(fd, buf.data[:buf.length]);
|
||||||
@@ -68,14 +69,14 @@ fprint :: proc(fd: os.Handle, args: ...any) -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fprintln :: proc(fd: os.Handle, args: ...any) -> int {
|
fprintln :: proc(fd: os.Handle, args: ...any) -> int {
|
||||||
data: [DEFAULT_BUFFER_SIZE]byte;
|
data: [_BUFFER_SIZE]byte;
|
||||||
buf := Buffer{data[:], 0};
|
buf := Buffer{data[:], 0};
|
||||||
bprintln(^buf, ...args);
|
bprintln(^buf, ...args);
|
||||||
os.write(fd, buf.data[:buf.length]);
|
os.write(fd, buf.data[:buf.length]);
|
||||||
return buf.length;
|
return buf.length;
|
||||||
}
|
}
|
||||||
fprintf :: proc(fd: os.Handle, fmt: string, args: ...any) -> int {
|
fprintf :: proc(fd: os.Handle, fmt: string, args: ...any) -> int {
|
||||||
data: [DEFAULT_BUFFER_SIZE]byte;
|
data: [_BUFFER_SIZE]byte;
|
||||||
buf := Buffer{data[:], 0};
|
buf := Buffer{data[:], 0};
|
||||||
bprintf(^buf, fmt, ...args);
|
bprintf(^buf, fmt, ...args);
|
||||||
os.write(fd, buf.data[:buf.length]);
|
os.write(fd, buf.data[:buf.length]);
|
||||||
@@ -95,7 +96,7 @@ printf :: proc(fmt: string, args: ...any) -> int {
|
|||||||
|
|
||||||
|
|
||||||
fprint_type :: proc(fd: os.Handle, info: ^Type_Info) {
|
fprint_type :: proc(fd: os.Handle, info: ^Type_Info) {
|
||||||
data: [DEFAULT_BUFFER_SIZE]byte;
|
data: [_BUFFER_SIZE]byte;
|
||||||
buf := Buffer{data[:], 0};
|
buf := Buffer{data[:], 0};
|
||||||
buffer_write_type(^buf, info);
|
buffer_write_type(^buf, info);
|
||||||
os.write(fd, buf.data[:buf.length]);
|
os.write(fd, buf.data[:buf.length]);
|
||||||
@@ -174,8 +175,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
|
|||||||
buffer_write_string(buf, "]");
|
buffer_write_string(buf, "]");
|
||||||
buffer_write_type(buf, info.elem);
|
buffer_write_type(buf, info.elem);
|
||||||
case Dynamic_Array:
|
case Dynamic_Array:
|
||||||
buffer_write_string(buf, "[dynamic");
|
buffer_write_string(buf, "[...]");
|
||||||
buffer_write_string(buf, "]");
|
|
||||||
buffer_write_type(buf, info.elem);
|
buffer_write_type(buf, info.elem);
|
||||||
case Slice:
|
case Slice:
|
||||||
buffer_write_string(buf, "[");
|
buffer_write_string(buf, "[");
|
||||||
@@ -316,7 +316,7 @@ parse_int :: proc(s: string, offset: int) -> (int, int, bool) {
|
|||||||
return result, offset+i, i != 0;
|
return result, offset+i, i != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset: int, arg_count: int) -> (int, int, bool) {
|
_arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset: int, arg_count: int) -> (int, int, bool) {
|
||||||
parse_arg_number :: proc(format: string) -> (int, int, bool) {
|
parse_arg_number :: proc(format: string) -> (int, int, bool) {
|
||||||
if format.count < 3 {
|
if format.count < 3 {
|
||||||
return 0, 1, false;
|
return 0, 1, false;
|
||||||
@@ -961,7 +961,7 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_index, i, was_prev_index = arg_number(^fi, arg_index, fmt, i, args.count);
|
arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, args.count);
|
||||||
|
|
||||||
// Width
|
// Width
|
||||||
if i < end && fmt[i] == '*' {
|
if i < end && fmt[i] == '*' {
|
||||||
@@ -991,7 +991,7 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int {
|
|||||||
fi.good_arg_index = false;
|
fi.good_arg_index = false;
|
||||||
}
|
}
|
||||||
if i < end && fmt[i] == '*' {
|
if i < end && fmt[i] == '*' {
|
||||||
arg_index, i, was_prev_index = arg_number(^fi, arg_index, fmt, i, args.count);
|
arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, args.count);
|
||||||
i += 1;
|
i += 1;
|
||||||
fi.prec, arg_index, fi.prec_set = int_from_arg(args, arg_index);
|
fi.prec, arg_index, fi.prec_set = int_from_arg(args, arg_index);
|
||||||
if fi.prec < 0 {
|
if fi.prec < 0 {
|
||||||
@@ -1012,7 +1012,7 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !was_prev_index {
|
if !was_prev_index {
|
||||||
arg_index, i, was_prev_index = arg_number(^fi, arg_index, fmt, i, args.count);
|
arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, args.count);
|
||||||
}
|
}
|
||||||
|
|
||||||
if i >= end {
|
if i >= end {
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
_ := compile_assert(ODIN_OS == "windows");
|
#foreign_system_library "kernel32.lib" when ODIN_OS == "windows";
|
||||||
#foreign_system_library "kernel32.lib";
|
#foreign_system_library "user32.lib" when ODIN_OS == "windows";
|
||||||
#foreign_system_library "user32.lib";
|
#foreign_system_library "gdi32.lib" when ODIN_OS == "windows";
|
||||||
#foreign_system_library "gdi32.lib";
|
#foreign_system_library "winmm.lib" when ODIN_OS == "windows";
|
||||||
#foreign_system_library "winmm.lib";
|
#foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
|
||||||
#foreign_system_library "opengl32.lib";
|
|
||||||
|
|
||||||
HANDLE :: rawptr;
|
HANDLE :: rawptr;
|
||||||
HWND :: HANDLE;
|
HWND :: HANDLE;
|
||||||
@@ -23,7 +22,7 @@ BOOL :: i32;
|
|||||||
WNDPROC :: #type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c;
|
WNDPROC :: #type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c;
|
||||||
|
|
||||||
|
|
||||||
INVALID_HANDLE_VALUE :: cast(HANDLE)(~cast(int)0);
|
INVALID_HANDLE_VALUE :: cast(HANDLE)~cast(int)0;
|
||||||
|
|
||||||
FALSE: BOOL : 0;
|
FALSE: BOOL : 0;
|
||||||
TRUE: BOOL : 1;
|
TRUE: BOOL : 1;
|
||||||
@@ -289,7 +288,7 @@ InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign ke
|
|||||||
InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
|
InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
|
||||||
InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
|
InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
|
||||||
|
|
||||||
_mm_pause :: proc() #foreign kernel32;
|
mm_pause :: proc() #foreign kernel32 "_mm_pause";
|
||||||
ReadWriteBarrier :: proc() #foreign kernel32;
|
ReadWriteBarrier :: proc() #foreign kernel32;
|
||||||
WriteBarrier :: proc() #foreign kernel32;
|
WriteBarrier :: proc() #foreign kernel32;
|
||||||
ReadBarrier :: proc() #foreign kernel32;
|
ReadBarrier :: proc() #foreign kernel32;
|
||||||
|
|||||||
+90
-30
@@ -360,6 +360,11 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
|||||||
|
|
||||||
Token name_token = name->Ident;
|
Token name_token = name->Ident;
|
||||||
|
|
||||||
|
if (str_eq(name_token.string, str_lit(""))) {
|
||||||
|
error(name_token, "`names` is a reserved identifier for unions");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Type *type = make_type_named(c->allocator, name_token.string, base_type, NULL);
|
Type *type = make_type_named(c->allocator, name_token.string, base_type, NULL);
|
||||||
Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, type);
|
Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, type);
|
||||||
type->Named.type_name = e;
|
type->Named.type_name = e;
|
||||||
@@ -521,6 +526,11 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) {
|
|||||||
struct_type->Record.fields_in_src_order = fields;
|
struct_type->Record.fields_in_src_order = fields;
|
||||||
struct_type->Record.field_count = field_count;
|
struct_type->Record.field_count = field_count;
|
||||||
|
|
||||||
|
// struct_type->Record.names = make_entity_field(c->allocator, c->context.scope,
|
||||||
|
// make_token_ident(str_lit("names")), t_string_slice, false, 0);
|
||||||
|
// struct_type->Record.names->Variable.is_immutable = true;
|
||||||
|
// struct_type->Record.names->flags |= EntityFlag_TypeField;
|
||||||
|
|
||||||
if (!st->is_packed && !st->is_ordered) {
|
if (!st->is_packed && !st->is_ordered) {
|
||||||
// NOTE(bill): Reorder fields for reduced size/performance
|
// NOTE(bill): Reorder fields for reduced size/performance
|
||||||
|
|
||||||
@@ -605,6 +615,11 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
|
|||||||
|
|
||||||
union_type->Record.fields = fields;
|
union_type->Record.fields = fields;
|
||||||
union_type->Record.field_count = field_count;
|
union_type->Record.field_count = field_count;
|
||||||
|
|
||||||
|
// union_type->Record.names = make_entity_field(c->allocator, c->context.scope,
|
||||||
|
// make_token_ident(str_lit("names")), t_string_slice, false, 0);
|
||||||
|
// union_type->Record.names->Variable.is_immutable = true;
|
||||||
|
// union_type->Record.names->flags |= EntityFlag_TypeField;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
|
void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
|
||||||
@@ -628,6 +643,11 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
|
|||||||
|
|
||||||
union_type->Record.fields = fields;
|
union_type->Record.fields = fields;
|
||||||
union_type->Record.field_count = field_count;
|
union_type->Record.field_count = field_count;
|
||||||
|
|
||||||
|
// union_type->Record.names = make_entity_field(c->allocator, c->context.scope,
|
||||||
|
// make_token_ident(str_lit("names")), t_string_slice, false, 0);
|
||||||
|
// union_type->Record.names->Variable.is_immutable = true;
|
||||||
|
// union_type->Record.names->flags |= EntityFlag_TypeField;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GB_COMPARE_PROC(cmp_enum_order) {
|
// GB_COMPARE_PROC(cmp_enum_order) {
|
||||||
@@ -664,6 +684,10 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
|||||||
error_node(node, "Base type for enumeration must be numeric");
|
error_node(node, "Base type for enumeration must be numeric");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (is_type_enum(base_type)) {
|
||||||
|
error_node(node, "Base type for enumeration cannot be another enumeration");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE(bill): Must be up here for the `check_init_constant` system
|
// NOTE(bill): Must be up here for the `check_init_constant` system
|
||||||
enum_type->Record.enum_base_type = base_type;
|
enum_type->Record.enum_base_type = base_type;
|
||||||
@@ -764,8 +788,9 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
|||||||
add_entity_use(c, field, e);
|
add_entity_use(c, field, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GB_ASSERT(field_count <= et->fields.count);
|
GB_ASSERT(field_count <= et->fields.count);
|
||||||
|
gb_temp_arena_memory_end(tmp);
|
||||||
|
|
||||||
|
|
||||||
enum_type->Record.fields = fields;
|
enum_type->Record.fields = fields;
|
||||||
enum_type->Record.field_count = field_count;
|
enum_type->Record.field_count = field_count;
|
||||||
@@ -777,12 +802,10 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
|||||||
enum_type->Record.enum_max_value = make_entity_constant(c->allocator, c->context.scope,
|
enum_type->Record.enum_max_value = make_entity_constant(c->allocator, c->context.scope,
|
||||||
make_token_ident(str_lit("max_value")), constant_type, max_value);
|
make_token_ident(str_lit("max_value")), constant_type, max_value);
|
||||||
|
|
||||||
enum_type->Record.enum_names = make_entity_field(c->allocator, c->context.scope,
|
enum_type->Record.names = make_entity_field(c->allocator, c->context.scope,
|
||||||
make_token_ident(str_lit("names")), t_string_slice, false, 0);
|
make_token_ident(str_lit("names")), t_string_slice, false, 0);
|
||||||
enum_type->Record.enum_names->Variable.is_immutable = true;
|
enum_type->Record.names->Variable.is_immutable = true;
|
||||||
enum_type->Record.enum_names->flags |= EntityFlag_EnumField;
|
enum_type->Record.names->flags |= EntityFlag_TypeField;
|
||||||
|
|
||||||
gb_temp_arena_memory_end(tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1058,6 +1081,11 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Operand o = {0};
|
Operand o = {0};
|
||||||
|
if (e->kind == AstNode_UnaryExpr &&
|
||||||
|
e->UnaryExpr.op.kind == Token_Question) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
check_expr(c, &o, e);
|
check_expr(c, &o, e);
|
||||||
if (o.mode != Addressing_Constant) {
|
if (o.mode != Addressing_Constant) {
|
||||||
if (o.mode != Addressing_Invalid) {
|
if (o.mode != Addressing_Invalid) {
|
||||||
@@ -1291,7 +1319,12 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
|
|||||||
case_ast_node(at, ArrayType, e);
|
case_ast_node(at, ArrayType, e);
|
||||||
if (at->count != NULL) {
|
if (at->count != NULL) {
|
||||||
Type *elem = check_type_extra(c, at->elem, NULL);
|
Type *elem = check_type_extra(c, at->elem, NULL);
|
||||||
type = make_type_array(c->allocator, elem, check_array_or_map_count(c, at->count, false));
|
i64 count = check_array_or_map_count(c, at->count, false);
|
||||||
|
if (count < 0) {
|
||||||
|
error_node(at->count, "? can only be used in conjuction with compound literals");
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
type = make_type_array(c->allocator, elem, count);
|
||||||
} else {
|
} else {
|
||||||
Type *elem = check_type(c, at->elem);
|
Type *elem = check_type(c, at->elem);
|
||||||
type = make_type_slice(c->allocator, elem);
|
type = make_type_slice(c->allocator, elem);
|
||||||
@@ -2506,19 +2539,23 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
|||||||
add_entity_use(c, op_expr, e);
|
add_entity_use(c, op_expr, e);
|
||||||
expr_entity = e;
|
expr_entity = e;
|
||||||
|
|
||||||
if (e != NULL && e->kind == Entity_ImportName &&
|
if (e != NULL && e->kind == Entity_ImportName && selector->kind == AstNode_Ident) {
|
||||||
selector->kind == AstNode_Ident) {
|
// IMPORTANT NOTE(bill): This is very sloppy code but it's also very fragile
|
||||||
|
// It pretty much needs to be in this order and this way
|
||||||
|
// If you can clean this up, please do but be really careful
|
||||||
|
|
||||||
String sel_name = selector->Ident.string;
|
String sel_name = selector->Ident.string;
|
||||||
|
|
||||||
check_op_expr = false;
|
check_op_expr = false;
|
||||||
entity = scope_lookup_entity(e->ImportName.scope, sel_name);
|
entity = scope_lookup_entity(e->ImportName.scope, sel_name);
|
||||||
bool is_declared = entity != NULL;
|
bool is_declared = entity != NULL;
|
||||||
|
if (is_declared) {
|
||||||
if (entity->kind == Entity_Builtin) {
|
if (entity->kind == Entity_Builtin) {
|
||||||
is_declared = false;
|
is_declared = false;
|
||||||
}
|
} else if (entity->scope->is_global && !e->ImportName.scope->is_global) {
|
||||||
if (entity->scope->is_global && !e->ImportName.scope->is_global) {
|
|
||||||
is_declared = false;
|
is_declared = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!is_declared) {
|
if (!is_declared) {
|
||||||
error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(sel_name), LIT(name));
|
error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(sel_name), LIT(name));
|
||||||
goto error;
|
goto error;
|
||||||
@@ -2539,6 +2576,17 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
is_not_exported = !is_entity_name_exported(entity);
|
||||||
|
|
||||||
|
if (is_not_exported) {
|
||||||
|
gbString sel_str = expr_to_string(selector);
|
||||||
|
error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(name));
|
||||||
|
gb_string_free(sel_str);
|
||||||
|
// NOTE(bill): We will have to cause an error his even though it exists
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_overloaded) {
|
if (is_overloaded) {
|
||||||
Scope *s = entity->scope;
|
Scope *s = entity->scope;
|
||||||
bool skip = false;
|
bool skip = false;
|
||||||
@@ -2583,7 +2631,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool *found = map_bool_get(&e->ImportName.scope->implicit, hash_pointer(entity));
|
bool *found = map_bool_get(&e->ImportName.scope->implicit, hash_pointer(entity));
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
is_not_exported = false;
|
is_not_exported = false;
|
||||||
} else {
|
} else {
|
||||||
@@ -2613,8 +2660,8 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
|||||||
sel = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type);
|
sel = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type);
|
||||||
entity = sel.entity;
|
entity = sel.entity;
|
||||||
|
|
||||||
// NOTE(bill): Add enum type info needed for fields like `names`
|
// NOTE(bill): Add type info needed for fields like `names`
|
||||||
if (entity != NULL && (entity->flags&EntityFlag_EnumField)) {
|
if (entity != NULL && (entity->flags&EntityFlag_TypeField)) {
|
||||||
add_type_info_type(c, operand->type);
|
add_type_info_type(c, operand->type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4454,16 +4501,18 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
|
|
||||||
case_ast_node(cl, CompoundLit, node);
|
case_ast_node(cl, CompoundLit, node);
|
||||||
Type *type = type_hint;
|
Type *type = type_hint;
|
||||||
bool ellipsis_array = false;
|
bool is_to_be_determined_array_count = false;
|
||||||
bool is_constant = true;
|
bool is_constant = true;
|
||||||
if (cl->type != NULL) {
|
if (cl->type != NULL) {
|
||||||
type = NULL;
|
type = NULL;
|
||||||
|
|
||||||
// [..]Type
|
// [..]Type
|
||||||
if (cl->type->kind == AstNode_ArrayType && cl->type->ArrayType.count != NULL) {
|
if (cl->type->kind == AstNode_ArrayType && cl->type->ArrayType.count != NULL) {
|
||||||
if (cl->type->ArrayType.count->kind == AstNode_Ellipsis) {
|
AstNode *count = cl->type->ArrayType.count;
|
||||||
|
if (count->kind == AstNode_UnaryExpr &&
|
||||||
|
count->UnaryExpr.op.kind == Token_Question) {
|
||||||
type = make_type_array(c->allocator, check_type(c, cl->type->ArrayType.elem), -1);
|
type = make_type_array(c->allocator, check_type(c, cl->type->ArrayType.elem), -1);
|
||||||
ellipsis_array = true;
|
is_to_be_determined_array_count = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4575,18 +4624,28 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
case Type_Slice:
|
case Type_Slice:
|
||||||
case Type_Array:
|
case Type_Array:
|
||||||
case Type_Vector:
|
case Type_Vector:
|
||||||
|
case Type_DynamicArray:
|
||||||
{
|
{
|
||||||
Type *elem_type = NULL;
|
Type *elem_type = NULL;
|
||||||
String context_name = {0};
|
String context_name = {0};
|
||||||
|
i64 max_type_count = -1;
|
||||||
if (t->kind == Type_Slice) {
|
if (t->kind == Type_Slice) {
|
||||||
elem_type = t->Slice.elem;
|
elem_type = t->Slice.elem;
|
||||||
context_name = str_lit("slice literal");
|
context_name = str_lit("slice literal");
|
||||||
} else if (t->kind == Type_Vector) {
|
} else if (t->kind == Type_Vector) {
|
||||||
elem_type = t->Vector.elem;
|
elem_type = t->Vector.elem;
|
||||||
context_name = str_lit("vector literal");
|
context_name = str_lit("vector literal");
|
||||||
} else {
|
max_type_count = t->Vector.count;
|
||||||
|
} else if (t->kind == Type_Array) {
|
||||||
elem_type = t->Array.elem;
|
elem_type = t->Array.elem;
|
||||||
context_name = str_lit("array literal");
|
context_name = str_lit("array literal");
|
||||||
|
max_type_count = t->Array.count;
|
||||||
|
} else if (t->kind == Type_DynamicArray) {
|
||||||
|
elem_type = t->DynamicArray.elem;
|
||||||
|
context_name = str_lit("dynamic array literal");
|
||||||
|
is_constant = false;
|
||||||
|
} else {
|
||||||
|
GB_PANIC("unreachable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4606,15 +4665,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->kind == Type_Array &&
|
if (0 <= max_type_count && max_type_count <= index) {
|
||||||
t->Array.count >= 0 &&
|
error_node(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name));
|
||||||
index >= t->Array.count) {
|
|
||||||
error_node(e, "Index %lld is out of bounds (>= %lld) for array literal", index, t->Array.count);
|
|
||||||
}
|
|
||||||
if (t->kind == Type_Vector &&
|
|
||||||
t->Vector.count >= 0 &&
|
|
||||||
index >= t->Vector.count) {
|
|
||||||
error_node(e, "Index %lld is out of bounds (>= %lld) for vector literal", index, t->Vector.count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Operand operand = {0};
|
Operand operand = {0};
|
||||||
@@ -4635,7 +4687,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->kind == Type_Array && ellipsis_array) {
|
if (t->kind == Type_Array && is_to_be_determined_array_count) {
|
||||||
t->Array.count = max;
|
t->Array.count = max;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@@ -5153,14 +5205,17 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case AstNode_HelperType:
|
||||||
case AstNode_ProcType:
|
case AstNode_ProcType:
|
||||||
case AstNode_PointerType:
|
case AstNode_PointerType:
|
||||||
case AstNode_ArrayType:
|
case AstNode_ArrayType:
|
||||||
|
case AstNode_DynamicArrayType:
|
||||||
case AstNode_VectorType:
|
case AstNode_VectorType:
|
||||||
case AstNode_StructType:
|
case AstNode_StructType:
|
||||||
case AstNode_UnionType:
|
case AstNode_UnionType:
|
||||||
case AstNode_RawUnionType:
|
case AstNode_RawUnionType:
|
||||||
case AstNode_EnumType:
|
case AstNode_EnumType:
|
||||||
|
case AstNode_MapType:
|
||||||
o->mode = Addressing_Type;
|
o->mode = Addressing_Type;
|
||||||
o->type = check_type(c, node);
|
o->type = check_type(c, node);
|
||||||
break;
|
break;
|
||||||
@@ -5388,7 +5443,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(e, Ellipsis, node);
|
case_ast_node(e, Ellipsis, node);
|
||||||
str = gb_string_appendc(str, "..");
|
str = gb_string_appendc(str, "...");
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(fv, FieldValue, node);
|
case_ast_node(fv, FieldValue, node);
|
||||||
@@ -5404,13 +5459,18 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
|||||||
|
|
||||||
case_ast_node(at, ArrayType, node);
|
case_ast_node(at, ArrayType, node);
|
||||||
str = gb_string_appendc(str, "[");
|
str = gb_string_appendc(str, "[");
|
||||||
|
if (at->count->kind == AstNode_UnaryExpr &&
|
||||||
|
at->count->UnaryExpr.op.kind == Token_Hash) {
|
||||||
|
str = gb_string_appendc(str, "#");
|
||||||
|
} else {
|
||||||
str = write_expr_to_string(str, at->count);
|
str = write_expr_to_string(str, at->count);
|
||||||
|
}
|
||||||
str = gb_string_appendc(str, "]");
|
str = gb_string_appendc(str, "]");
|
||||||
str = write_expr_to_string(str, at->elem);
|
str = write_expr_to_string(str, at->elem);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(at, DynamicArrayType, node);
|
case_ast_node(at, DynamicArrayType, node);
|
||||||
str = gb_string_appendc(str, "[dynamic]");
|
str = gb_string_appendc(str, "[...]");
|
||||||
str = write_expr_to_string(str, at->elem);
|
str = write_expr_to_string(str, at->elem);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
|||||||
+10
-2
@@ -999,7 +999,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (unparen_expr(lhs)->kind != AstNode_Ident) {
|
if (lhs->kind != AstNode_Ident) {
|
||||||
error_node(rhs, "Expected an identifier, got `%.*s`", LIT(ast_node_strings[rhs->kind]));
|
error_node(rhs, "Expected an identifier, got `%.*s`", LIT(ast_node_strings[rhs->kind]));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1067,9 +1067,17 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
check_open_scope(c, stmt);
|
check_open_scope(c, stmt);
|
||||||
if (case_type != NULL) {
|
if (case_type == NULL) {
|
||||||
|
if (is_union_ptr) {
|
||||||
|
case_type = type_deref(x.type);
|
||||||
|
} else {
|
||||||
|
case_type = x.type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
add_type_info_type(c, case_type);
|
add_type_info_type(c, case_type);
|
||||||
|
|
||||||
|
{
|
||||||
// NOTE(bill): Dummy type
|
// NOTE(bill): Dummy type
|
||||||
Type *tt = case_type;
|
Type *tt = case_type;
|
||||||
if (is_union_ptr) {
|
if (is_union_ptr) {
|
||||||
|
|||||||
+53
-1
@@ -208,6 +208,7 @@ typedef struct Scope {
|
|||||||
bool is_global;
|
bool is_global;
|
||||||
bool is_file;
|
bool is_file;
|
||||||
bool is_init;
|
bool is_init;
|
||||||
|
bool has_been_imported; // This is only applicable to file scopes
|
||||||
AstFile * file;
|
AstFile * file;
|
||||||
} Scope;
|
} Scope;
|
||||||
gb_global Scope *universal_scope = NULL;
|
gb_global Scope *universal_scope = NULL;
|
||||||
@@ -1542,6 +1543,12 @@ void check_all_global_entities(Checker *c) {
|
|||||||
}
|
}
|
||||||
add_curr_ast_file(c, d->scope->file);
|
add_curr_ast_file(c, d->scope->file);
|
||||||
|
|
||||||
|
if (!d->scope->has_been_imported) {
|
||||||
|
// NOTE(bill): All of these unchecked entities could mean a lot of unused allocations
|
||||||
|
// TODO(bill): Should this be worried about?
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (e->kind != Entity_Procedure && str_eq(e->token.string, str_lit("main"))) {
|
if (e->kind != Entity_Procedure && str_eq(e->token.string, str_lit("main"))) {
|
||||||
if (e->scope->is_init) {
|
if (e->scope->is_init) {
|
||||||
error(e->token, "`main` is reserved as the entry point procedure in the initial scope");
|
error(e->token, "`main` is reserved as the entry point procedure in the initial scope");
|
||||||
@@ -1575,6 +1582,30 @@ void check_all_global_entities(Checker *c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool is_string_an_identifier(String s) {
|
||||||
|
isize offset = 0;
|
||||||
|
if (s.len < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (offset < s.len) {
|
||||||
|
bool ok = false;
|
||||||
|
Rune r = -1;
|
||||||
|
isize size = gb_utf8_decode(s.text+offset, s.len-offset, &r);
|
||||||
|
if (offset == 0) {
|
||||||
|
ok = rune_is_letter(r);
|
||||||
|
} else {
|
||||||
|
ok = rune_is_letter(r) || rune_is_digit(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset == s.len;
|
||||||
|
}
|
||||||
|
|
||||||
String path_to_entity_name(String name, String fullpath) {
|
String path_to_entity_name(String name, String fullpath) {
|
||||||
if (name.len != 0) {
|
if (name.len != 0) {
|
||||||
return name;
|
return name;
|
||||||
@@ -1619,6 +1650,12 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
|
|||||||
ast_node(id, ImportDecl, decl);
|
ast_node(id, ImportDecl, decl);
|
||||||
Token token = id->relpath;
|
Token token = id->relpath;
|
||||||
|
|
||||||
|
GB_ASSERT(parent_scope->is_file);
|
||||||
|
|
||||||
|
if (!parent_scope->has_been_imported) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
HashKey key = hash_string(id->fullpath);
|
HashKey key = hash_string(id->fullpath);
|
||||||
Scope **found = map_scope_get(file_scopes, key);
|
Scope **found = map_scope_get(file_scopes, key);
|
||||||
if (found == NULL) {
|
if (found == NULL) {
|
||||||
@@ -1665,6 +1702,8 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
|
|||||||
warning(token, "Multiple #import of the same file within this scope");
|
warning(token, "Multiple #import of the same file within this scope");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope->has_been_imported = true;
|
||||||
|
|
||||||
if (str_eq(id->import_name.string, str_lit("."))) {
|
if (str_eq(id->import_name.string, str_lit("."))) {
|
||||||
// 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) {
|
||||||
@@ -1677,10 +1716,18 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
|
|||||||
case Entity_LibraryName:
|
case Entity_LibraryName:
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
|
|
||||||
|
if (id->is_import) {
|
||||||
|
if (is_entity_name_exported(e)) {
|
||||||
|
// TODO(bill): Should these entities be imported but cause an error when used?
|
||||||
bool ok = add_entity(c, parent_scope, NULL, e);
|
bool ok = add_entity(c, parent_scope, NULL, e);
|
||||||
if (ok && id->is_import) { // `#import`ed entities don't get exported
|
if (ok) {
|
||||||
map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
|
map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* bool ok = */add_entity(c, parent_scope, NULL, e);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1734,6 +1781,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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 (str_eq(library_name, str_lit("_"))) {
|
if (str_eq(library_name, str_lit("_"))) {
|
||||||
error(fl->token, "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));
|
||||||
@@ -1768,6 +1816,10 @@ void check_parsed_files(Checker *c) {
|
|||||||
array_add(&c->global_scope->shared, scope);
|
array_add(&c->global_scope->shared, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scope->is_init || scope->is_global) {
|
||||||
|
scope->has_been_imported = true;
|
||||||
|
}
|
||||||
|
|
||||||
f->scope = scope;
|
f->scope = scope;
|
||||||
f->decl_info = make_declaration_info(c->allocator, f->scope);
|
f->decl_info = make_declaration_info(c->allocator, f->scope);
|
||||||
HashKey key = hash_string(f->tokenizer.fullpath);
|
HashKey key = hash_string(f->tokenizer.fullpath);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ gbAllocator heap_allocator(void) {
|
|||||||
return gb_heap_allocator();
|
return gb_heap_allocator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "unicode.c"
|
||||||
#include "string.c"
|
#include "string.c"
|
||||||
#include "array.c"
|
#include "array.c"
|
||||||
|
|
||||||
|
|||||||
+10
-1
@@ -37,7 +37,7 @@ typedef enum EntityFlag {
|
|||||||
EntityFlag_VectorElem = 1<<5,
|
EntityFlag_VectorElem = 1<<5,
|
||||||
EntityFlag_Ellipsis = 1<<6,
|
EntityFlag_Ellipsis = 1<<6,
|
||||||
EntityFlag_NoAlias = 1<<7,
|
EntityFlag_NoAlias = 1<<7,
|
||||||
EntityFlag_EnumField = 1<<8,
|
EntityFlag_TypeField = 1<<8,
|
||||||
} EntityFlag;
|
} EntityFlag;
|
||||||
|
|
||||||
typedef enum OverloadKind {
|
typedef enum OverloadKind {
|
||||||
@@ -98,6 +98,15 @@ struct Entity {
|
|||||||
|
|
||||||
gb_global Entity *e_context = NULL;
|
gb_global Entity *e_context = NULL;
|
||||||
|
|
||||||
|
bool is_entity_name_exported(Entity *e) {
|
||||||
|
GB_ASSERT(e != NULL);
|
||||||
|
String name = e->token.string;
|
||||||
|
if (name.len == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return name.text[0] != '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
|
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
|
||||||
Entity *entity = gb_alloc_item(a, Entity);
|
Entity *entity = gb_alloc_item(a, Entity);
|
||||||
|
|||||||
@@ -1008,6 +1008,22 @@ irValue *ir_make_value_procedure(gbAllocator a, irModule *m, Entity *entity, Typ
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
irValue *ir_generate_array(irModule *m, Type *elem_type, i64 count, String prefix, i64 id) {
|
||||||
|
gbAllocator a = m->allocator;
|
||||||
|
Token token = {Token_Ident};
|
||||||
|
isize name_len = prefix.len + 10;
|
||||||
|
token.string.text = gb_alloc_array(a, u8, name_len);
|
||||||
|
token.string.len = gb_snprintf(cast(char *)token.string.text, name_len,
|
||||||
|
"%.*s-%llx", LIT(prefix), id)-1;
|
||||||
|
Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, elem_type, count), false);
|
||||||
|
irValue *value = ir_make_value_global(a, e, NULL);
|
||||||
|
value->Global.is_private = true;
|
||||||
|
ir_module_add_value(m, e, value);
|
||||||
|
map_ir_value_set(&m->members, hash_string(token.string), value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
irBlock *ir_new_block(irProcedure *proc, AstNode *node, char *label) {
|
irBlock *ir_new_block(irProcedure *proc, AstNode *node, char *label) {
|
||||||
Scope *scope = NULL;
|
Scope *scope = NULL;
|
||||||
if (node != NULL) {
|
if (node != NULL) {
|
||||||
@@ -3709,50 +3725,55 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
|||||||
AstNode *sel = unparen_expr(se->selector);
|
AstNode *sel = unparen_expr(se->selector);
|
||||||
if (sel->kind == AstNode_Ident) {
|
if (sel->kind == AstNode_Ident) {
|
||||||
String selector = sel->Ident.string;
|
String selector = sel->Ident.string;
|
||||||
Type *type = type_of_expr(proc->module->info, se->expr);
|
TypeAndValue *tav = type_and_value_of_expression(proc->module->info, se->expr);
|
||||||
|
|
||||||
if (is_type_enum(type)) {
|
if (tav == NULL) {
|
||||||
Selection sel = lookup_field(proc->module->allocator, type, selector, true);
|
|
||||||
Entity *e = sel.entity;
|
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
|
||||||
i32 index = e->Variable.field_index;
|
|
||||||
switch (index) {
|
|
||||||
case 0: {
|
|
||||||
irValue *ti_ptr = ir_type_info(proc, type);
|
|
||||||
{
|
|
||||||
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 1);
|
|
||||||
args[0] = ti_ptr;
|
|
||||||
ti_ptr = ir_emit_global_call(proc, "type_info_base", args, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
irValue *enum_info = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr);
|
|
||||||
irValue *names_ptr = ir_emit_struct_ep(proc, enum_info, 1);
|
|
||||||
return ir_make_addr(names_ptr);
|
|
||||||
} break;
|
|
||||||
default:
|
|
||||||
GB_PANIC("Unhandled enum index %d %.*s", index, LIT(selector));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type = base_type(type);
|
|
||||||
|
|
||||||
if (type == t_invalid) {
|
|
||||||
// NOTE(bill): Imports
|
// NOTE(bill): Imports
|
||||||
Entity *imp = entity_of_ident(proc->module->info, se->expr);
|
Entity *imp = entity_of_ident(proc->module->info, se->expr);
|
||||||
if (imp != NULL) {
|
if (imp != NULL) {
|
||||||
GB_ASSERT(imp->kind == Entity_ImportName);
|
GB_ASSERT(imp->kind == Entity_ImportName);
|
||||||
}
|
}
|
||||||
return ir_build_addr(proc, unparen_expr(se->selector));
|
return ir_build_addr(proc, unparen_expr(se->selector));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Type *type = base_type(tav->type);
|
||||||
|
if (tav->mode == Addressing_Type) { // Addressing_Type
|
||||||
|
Selection sel = lookup_field(proc->module->allocator, type, selector, true);
|
||||||
|
Entity *e = sel.entity;
|
||||||
|
GB_ASSERT(e->kind == Entity_Variable);
|
||||||
|
GB_ASSERT(e->flags & EntityFlag_TypeField);
|
||||||
|
String name = e->token.string;
|
||||||
|
if (str_eq(name, str_lit("names"))) {
|
||||||
|
irValue *ti_ptr = ir_type_info(proc, type);
|
||||||
|
// {
|
||||||
|
// irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 1);
|
||||||
|
// args[0] = ti_ptr;
|
||||||
|
// ti_ptr = ir_emit_global_call(proc, "type_info_base", args, 1);
|
||||||
|
// }
|
||||||
|
irValue *names_ptr = NULL;
|
||||||
|
|
||||||
|
if (is_type_enum(type)) {
|
||||||
|
irValue *enum_info = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr);
|
||||||
|
names_ptr = ir_emit_struct_ep(proc, enum_info, 1);
|
||||||
} else {
|
} else {
|
||||||
|
GB_PANIC("TODO(bill): `names` for records");
|
||||||
|
// irValue *record_info = ir_emit_conv(proc, ti_ptr, t_type_info_record_ptr);
|
||||||
|
// names_ptr = ir_emit_struct_ep(proc, record_info, 1);
|
||||||
|
}
|
||||||
|
return ir_make_addr(names_ptr);
|
||||||
|
} else {
|
||||||
|
GB_PANIC("Unhandled TypeField %.*s", LIT(name));
|
||||||
|
}
|
||||||
|
GB_PANIC("Unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
Selection sel = lookup_field(proc->module->allocator, type, selector, false);
|
Selection sel = lookup_field(proc->module->allocator, type, selector, false);
|
||||||
GB_ASSERT(sel.entity != NULL);
|
GB_ASSERT(sel.entity != NULL);
|
||||||
|
|
||||||
irValue *a = ir_build_addr(proc, se->expr).addr;
|
irValue *a = ir_build_addr(proc, se->expr).addr;
|
||||||
a = ir_emit_deep_field_gep(proc, type, a, sel);
|
a = ir_emit_deep_field_gep(proc, type, a, sel);
|
||||||
return ir_make_addr(a);
|
return ir_make_addr(a);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Type *type = base_type(type_of_expr(proc->module->info, se->expr));
|
Type *type = base_type(type_of_expr(proc->module->info, se->expr));
|
||||||
GB_ASSERT(is_type_integer(type));
|
GB_ASSERT(is_type_integer(type));
|
||||||
@@ -4117,33 +4138,6 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
|||||||
ir_emit_store(proc, gep, ev);
|
ir_emit_store(proc, gep, ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// irValue *result = ir_add_module_constant(proc->module, type, make_exact_value_compound(expr));
|
|
||||||
// for_array(index, cl->elems) {
|
|
||||||
// AstNode *elem = cl->elems.e[index];
|
|
||||||
// if (ir_is_elem_const(proc->module, elem, et)) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// irValue *field_elem = ir_build_expr(proc, elem);
|
|
||||||
// Type *t = ir_type(field_elem);
|
|
||||||
// GB_ASSERT(t->kind != Type_Tuple);
|
|
||||||
// irValue *ev = ir_emit_conv(proc, field_elem, et);
|
|
||||||
// irValue *i = ir_make_const_int(proc->module->allocator, index);
|
|
||||||
// result = ir_emit(proc, ir_make_instr_insert_element(proc, result, ev, i));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (cl->elems.count == 1 && bt->Vector.count > 1) {
|
|
||||||
// isize index_count = bt->Vector.count;
|
|
||||||
// i32 *indices = gb_alloc_array(proc->module->allocator, i32, index_count);
|
|
||||||
// for (isize i = 0; i < index_count; i++) {
|
|
||||||
// indices[i] = 0;
|
|
||||||
// }
|
|
||||||
// irValue *sv = ir_emit(proc, ir_make_instr_vector_shuffle(proc, result, indices, index_count));
|
|
||||||
// ir_emit_store(proc, v, sv);
|
|
||||||
// return ir_make_addr(v);
|
|
||||||
// }
|
|
||||||
// ir_emit_store(proc, v, result);
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Type_Record: {
|
case Type_Record: {
|
||||||
@@ -4186,13 +4180,51 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case Type_DynamicArray: {
|
||||||
|
if (cl->elems.count == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Type *elem = bt->DynamicArray.elem;
|
||||||
|
gbAllocator a = proc->module->allocator;
|
||||||
|
irValue *size = ir_make_const_int(a, type_size_of(proc->module->sizes, a, elem));
|
||||||
|
irValue *align = ir_make_const_int(a, type_align_of(proc->module->sizes, a, elem));
|
||||||
|
{
|
||||||
|
irValue **args = gb_alloc_array(a, irValue *, 4);
|
||||||
|
args[0] = ir_emit_conv(proc, v, t_rawptr);
|
||||||
|
args[1] = size;
|
||||||
|
args[2] = align;
|
||||||
|
args[3] = ir_make_const_int(a, 2*cl->elems.count);
|
||||||
|
ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
i64 item_count = cl->elems.count;
|
||||||
|
irValue *items = ir_generate_array(proc->module, elem, item_count, str_lit("__dacl$"), cast(i64)cast(intptr)expr);
|
||||||
|
|
||||||
|
for_array(field_index, cl->elems) {
|
||||||
|
AstNode *f = cl->elems.e[field_index];
|
||||||
|
irValue *value = ir_emit_conv(proc, ir_build_expr(proc, f), elem);
|
||||||
|
irValue *ep = ir_emit_array_epi(proc, items, field_index);
|
||||||
|
ir_emit_store(proc, ep, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
irValue **args = gb_alloc_array(a, irValue *, 5);
|
||||||
|
args[0] = ir_emit_conv(proc, v, t_rawptr);
|
||||||
|
args[1] = size;
|
||||||
|
args[2] = align;
|
||||||
|
args[3] = ir_emit_conv(proc, items, t_rawptr);
|
||||||
|
args[4] = ir_make_const_int(a, item_count);
|
||||||
|
ir_emit_global_call(proc, "__dynamic_array_append", args, 5);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
case Type_Map: {
|
case Type_Map: {
|
||||||
if (cl->elems.count == 0) {
|
if (cl->elems.count == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gbAllocator a = proc->module->allocator;
|
gbAllocator a = proc->module->allocator;
|
||||||
{
|
{
|
||||||
irValue **args = gb_alloc_array(a, irValue *, 4);
|
irValue **args = gb_alloc_array(a, irValue *, 2);
|
||||||
args[0] = ir_gen_map_header(proc, v, type);
|
args[0] = ir_gen_map_header(proc, v, type);
|
||||||
args[1] = ir_make_const_int(a, 2*cl->elems.count);
|
args[1] = ir_make_const_int(a, 2*cl->elems.count);
|
||||||
ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
|
ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
|
||||||
@@ -5294,17 +5326,6 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
|||||||
AstNode *clause = body->stmts.e[i];
|
AstNode *clause = body->stmts.e[i];
|
||||||
ast_node(cc, CaseClause, clause);
|
ast_node(cc, CaseClause, clause);
|
||||||
|
|
||||||
if (cc->list.count == 0) {
|
|
||||||
// default case
|
|
||||||
default_stmts = cc->stmts;
|
|
||||||
default_block = ir_new_block(proc, clause, "type-match.dflt.body");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
GB_ASSERT(cc->list.count == 1);
|
|
||||||
|
|
||||||
|
|
||||||
irBlock *body = ir_new_block(proc, clause, "type-match.case.body");
|
|
||||||
|
|
||||||
Entity *tag_var_entity = NULL;
|
Entity *tag_var_entity = NULL;
|
||||||
Type *tag_var_type = NULL;
|
Type *tag_var_type = NULL;
|
||||||
if (str_eq(tag_var_name, str_lit("_"))) {
|
if (str_eq(tag_var_name, str_lit("_"))) {
|
||||||
@@ -5324,6 +5345,26 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
|||||||
irBlock *next_cond = NULL;
|
irBlock *next_cond = NULL;
|
||||||
irValue *cond = NULL;
|
irValue *cond = NULL;
|
||||||
|
|
||||||
|
if (cc->list.count == 0) {
|
||||||
|
// default case
|
||||||
|
default_stmts = cc->stmts;
|
||||||
|
default_block = ir_new_block(proc, clause, "type-match.dflt.body");
|
||||||
|
|
||||||
|
|
||||||
|
irValue *tag_var = NULL;
|
||||||
|
if (tag_var_entity != NULL) {
|
||||||
|
tag_var = ir_add_local(proc, tag_var_entity);
|
||||||
|
} else {
|
||||||
|
tag_var = ir_add_local_generated(proc, tag_var_type);
|
||||||
|
}
|
||||||
|
ir_emit_store(proc, tag_var, parent);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
GB_ASSERT(cc->list.count == 1);
|
||||||
|
|
||||||
|
irBlock *body = ir_new_block(proc, clause, "type-match.case.body");
|
||||||
|
|
||||||
|
|
||||||
if (is_union_ptr) {
|
if (is_union_ptr) {
|
||||||
Type *bt = type_deref(tag_var_type);
|
Type *bt = type_deref(tag_var_type);
|
||||||
irValue *index = NULL;
|
irValue *index = NULL;
|
||||||
@@ -6409,38 +6450,10 @@ void ir_gen_tree(irGen *s) {
|
|||||||
if (t->Record.field_count > 0) {
|
if (t->Record.field_count > 0) {
|
||||||
Entity **fields = t->Record.fields;
|
Entity **fields = t->Record.fields;
|
||||||
isize count = t->Record.field_count;
|
isize count = t->Record.field_count;
|
||||||
irValue *name_array = NULL;
|
irValue *name_array = ir_generate_array(m, t_string, count,
|
||||||
irValue *value_array = NULL;
|
str_lit("__$enum_names"), cast(i64)entry_index);
|
||||||
|
irValue *value_array = ir_generate_array(m, t_type_info_enum_value, count,
|
||||||
{
|
str_lit("__$enum_values"), cast(i64)entry_index);
|
||||||
Token token = {Token_Ident};
|
|
||||||
i32 id = cast(i32)entry_index;
|
|
||||||
char name_base[] = "__$enum_names";
|
|
||||||
isize name_len = gb_size_of(name_base) + 10;
|
|
||||||
token.string.text = gb_alloc_array(a, u8, name_len);
|
|
||||||
token.string.len = gb_snprintf(cast(char *)token.string.text, name_len,
|
|
||||||
"%s-%d", name_base, id)-1;
|
|
||||||
Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, t_string, count), false);
|
|
||||||
name_array = ir_make_value_global(a, e, NULL);
|
|
||||||
name_array->Global.is_private = true;
|
|
||||||
ir_module_add_value(m, e, name_array);
|
|
||||||
map_ir_value_set(&m->members, hash_string(token.string), name_array);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Token token = {Token_Ident};
|
|
||||||
i32 id = cast(i32)entry_index;
|
|
||||||
char name_base[] = "__$enum_values";
|
|
||||||
isize name_len = gb_size_of(name_base) + 10;
|
|
||||||
token.string.text = gb_alloc_array(a, u8, name_len);
|
|
||||||
token.string.len = gb_snprintf(cast(char *)token.string.text, name_len,
|
|
||||||
"%s-%d", name_base, id)-1;
|
|
||||||
Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, t_type_info_enum_value, count), false);
|
|
||||||
value_array = ir_make_value_global(a, e, NULL);
|
|
||||||
value_array->Global.is_private = true;
|
|
||||||
ir_module_add_value(m, e, value_array);
|
|
||||||
map_ir_value_set(&m->members, hash_string(token.string), value_array);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_value_int = is_type_integer(t->Record.enum_base_type);
|
bool is_value_int = is_type_integer(t->Record.enum_base_type);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ extern "C" {
|
|||||||
|
|
||||||
#include "common.c"
|
#include "common.c"
|
||||||
#include "timings.c"
|
#include "timings.c"
|
||||||
#include "unicode.c"
|
|
||||||
#include "build.c"
|
#include "build.c"
|
||||||
#include "tokenizer.c"
|
#include "tokenizer.c"
|
||||||
#include "parser.c"
|
#include "parser.c"
|
||||||
|
|||||||
+76
-48
@@ -1832,6 +1832,7 @@ bool is_literal_type(AstNode *node) {
|
|||||||
case AstNode_ArrayType:
|
case AstNode_ArrayType:
|
||||||
case AstNode_VectorType:
|
case AstNode_VectorType:
|
||||||
case AstNode_StructType:
|
case AstNode_StructType:
|
||||||
|
case AstNode_DynamicArrayType:
|
||||||
case AstNode_MapType:
|
case AstNode_MapType:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2337,26 +2338,6 @@ bool parse_expect_separator(AstFile *f, TokenKind separator, AstNode *param) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNodeArray convert_to_ident_list(AstFile *f, AstNodeArray list) {
|
|
||||||
AstNodeArray idents = {0};
|
|
||||||
array_init_reserve(&idents, heap_allocator(), list.count);
|
|
||||||
// Convert to ident list
|
|
||||||
for_array(i, list) {
|
|
||||||
AstNode *ident = list.e[i];
|
|
||||||
switch (ident->kind) {
|
|
||||||
case AstNode_Ident:
|
|
||||||
case AstNode_BadExpr:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
error_node(ident, "Expected an identifier");
|
|
||||||
ident = ast_ident(f, blank_token);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
array_add(&idents, ident);
|
|
||||||
}
|
|
||||||
return idents;
|
|
||||||
}
|
|
||||||
|
|
||||||
AstNode *parse_var_type(AstFile *f, bool allow_ellipsis) {
|
AstNode *parse_var_type(AstFile *f, bool allow_ellipsis) {
|
||||||
if (allow_ellipsis && f->curr_token.kind == Token_Ellipsis) {
|
if (allow_ellipsis && f->curr_token.kind == Token_Ellipsis) {
|
||||||
Token tok = f->curr_token;
|
Token tok = f->curr_token;
|
||||||
@@ -2377,16 +2358,24 @@ AstNode *parse_var_type(AstFile *f, bool allow_ellipsis) {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_token_field_prefix(TokenKind kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case Token_using:
|
||||||
|
case Token_no_alias:
|
||||||
|
// case Token_immutable:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
u32 parse_field_prefixes(AstFile *f) {
|
u32 parse_field_prefixes(AstFile *f) {
|
||||||
i32 using_count = 0;
|
i32 using_count = 0;
|
||||||
i32 no_alias_count = 0;
|
i32 no_alias_count = 0;
|
||||||
i32 immutable_count = 0;
|
i32 immutable_count = 0;
|
||||||
|
|
||||||
bool loop = true;
|
while (is_token_field_prefix(f->curr_token.kind)) {
|
||||||
while (loop) {
|
|
||||||
switch (f->curr_token.kind) {
|
switch (f->curr_token.kind) {
|
||||||
default: loop = false; break;
|
|
||||||
case Token_using: using_count += 1; next_token(f); break;
|
case Token_using: using_count += 1; next_token(f); break;
|
||||||
case Token_no_alias: no_alias_count += 1; next_token(f); break;
|
case Token_no_alias: no_alias_count += 1; next_token(f); break;
|
||||||
// case Token_immutable: immutable_count += 1; next_token(f); break;
|
// case Token_immutable: immutable_count += 1; next_token(f); break;
|
||||||
@@ -2404,8 +2393,8 @@ u32 parse_field_prefixes(AstFile *f) {
|
|||||||
return field_flags;
|
return field_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 check_field_prefixes(AstFile *f, AstNodeArray names, u32 allowed_flags, u32 set_flags) {
|
u32 check_field_prefixes(AstFile *f, isize name_count, u32 allowed_flags, u32 set_flags) {
|
||||||
if (names.count > 1 && (set_flags&FieldFlag_using)) {
|
if (name_count > 1 && (set_flags&FieldFlag_using)) {
|
||||||
syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type");
|
syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type");
|
||||||
set_flags &= ~FieldFlag_using;
|
set_flags &= ~FieldFlag_using;
|
||||||
}
|
}
|
||||||
@@ -2425,19 +2414,54 @@ u32 check_field_prefixes(AstFile *f, AstNodeArray names, u32 allowed_flags, u32
|
|||||||
return set_flags;
|
return set_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct AstNodeAndFlags {
|
||||||
|
AstNode *node;
|
||||||
|
u32 flags;
|
||||||
|
} AstNodeAndFlags;
|
||||||
|
|
||||||
|
typedef Array(AstNodeAndFlags) AstNodeAndFlagsArray;
|
||||||
|
|
||||||
|
AstNodeArray convert_to_ident_list(AstFile *f, AstNodeAndFlagsArray list, bool ignore_flags) {
|
||||||
|
AstNodeArray idents = {0};
|
||||||
|
array_init_reserve(&idents, heap_allocator(), list.count);
|
||||||
|
// Convert to ident list
|
||||||
|
for_array(i, list) {
|
||||||
|
AstNode *ident = list.e[i].node;
|
||||||
|
|
||||||
|
if (!ignore_flags) {
|
||||||
|
if (i != 0) {
|
||||||
|
error_node(ident, "Illegal use of prefixes in parameter list");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ident->kind) {
|
||||||
|
case AstNode_Ident:
|
||||||
|
case AstNode_BadExpr:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_node(ident, "Expected an identifier");
|
||||||
|
ident = ast_ident(f, blank_token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
array_add(&idents, ident);
|
||||||
|
}
|
||||||
|
return idents;
|
||||||
|
}
|
||||||
|
|
||||||
AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
|
AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
|
||||||
TokenKind separator, TokenKind follow) {
|
TokenKind separator, TokenKind follow) {
|
||||||
AstNodeArray params = make_ast_node_array(f);
|
AstNodeArray params = make_ast_node_array(f);
|
||||||
AstNodeArray list = make_ast_node_array(f);
|
AstNodeAndFlagsArray list = {0}; array_init(&list, heap_allocator()); // LEAK(bill):
|
||||||
isize name_count = 0;
|
isize total_name_count = 0;
|
||||||
bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis;
|
bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis;
|
||||||
|
|
||||||
u32 set_flags = parse_field_prefixes(f);
|
|
||||||
while (f->curr_token.kind != follow &&
|
while (f->curr_token.kind != follow &&
|
||||||
f->curr_token.kind != Token_Colon &&
|
f->curr_token.kind != Token_Colon &&
|
||||||
f->curr_token.kind != Token_EOF) {
|
f->curr_token.kind != Token_EOF) {
|
||||||
|
u32 flags = parse_field_prefixes(f);
|
||||||
AstNode *param = parse_var_type(f, allow_ellipsis);
|
AstNode *param = parse_var_type(f, allow_ellipsis);
|
||||||
array_add(&list, param);
|
AstNodeAndFlags naf = {param, flags};
|
||||||
|
array_add(&list, naf);
|
||||||
if (f->curr_token.kind != Token_Comma) {
|
if (f->curr_token.kind != Token_Comma) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2445,12 +2469,16 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (f->curr_token.kind == Token_Colon) {
|
if (f->curr_token.kind == Token_Colon) {
|
||||||
AstNodeArray names = convert_to_ident_list(f, list); // Copy for semantic reasons
|
AstNodeArray names = convert_to_ident_list(f, list, true); // Copy for semantic reasons
|
||||||
if (names.count == 0) {
|
if (names.count == 0) {
|
||||||
syntax_error(f->curr_token, "Empty field declaration");
|
syntax_error(f->curr_token, "Empty field declaration");
|
||||||
}
|
}
|
||||||
set_flags = check_field_prefixes(f, names, allowed_flags, set_flags);
|
u32 set_flags = 0;
|
||||||
name_count += names.count;
|
if (list.count > 0) {
|
||||||
|
set_flags = list.e[0].flags;
|
||||||
|
}
|
||||||
|
set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags);
|
||||||
|
total_name_count += names.count;
|
||||||
|
|
||||||
expect_token_after(f, Token_Colon, "field list");
|
expect_token_after(f, Token_Colon, "field list");
|
||||||
AstNode *type = parse_var_type(f, allow_ellipsis);
|
AstNode *type = parse_var_type(f, allow_ellipsis);
|
||||||
@@ -2467,8 +2495,8 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
|
|||||||
syntax_error(f->curr_token, "Empty field declaration");
|
syntax_error(f->curr_token, "Empty field declaration");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
set_flags = check_field_prefixes(f, names, allowed_flags, set_flags);
|
set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags);
|
||||||
name_count += names.count;
|
total_name_count += names.count;
|
||||||
|
|
||||||
expect_token_after(f, Token_Colon, "field list");
|
expect_token_after(f, Token_Colon, "field list");
|
||||||
AstNode *type = parse_var_type(f, allow_ellipsis);
|
AstNode *type = parse_var_type(f, allow_ellipsis);
|
||||||
@@ -2480,25 +2508,25 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name_count_) *name_count_ = name_count;
|
if (name_count_) *name_count_ = total_name_count;
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_flags = check_field_prefixes(f, list, allowed_flags, set_flags);
|
|
||||||
for_array(i, list) {
|
for_array(i, list) {
|
||||||
AstNodeArray names = {0};
|
AstNodeArray names = {0};
|
||||||
AstNode *type = list.e[i];
|
AstNode *type = list.e[i].node;
|
||||||
Token token = blank_token;
|
Token token = blank_token;
|
||||||
|
|
||||||
array_init_count(&names, heap_allocator(), 1);
|
array_init_count(&names, heap_allocator(), 1);
|
||||||
token.pos = ast_node_token(type).pos;
|
token.pos = ast_node_token(type).pos;
|
||||||
names.e[0] = ast_ident(f, token);
|
names.e[0] = ast_ident(f, token);
|
||||||
|
u32 flags = check_field_prefixes(f, list.count, allowed_flags, list.e[i].flags);
|
||||||
|
|
||||||
AstNode *param = ast_field(f, names, list.e[i], set_flags);
|
AstNode *param = ast_field(f, names, list.e[i].node, flags);
|
||||||
array_add(¶ms, param);
|
array_add(¶ms, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name_count_) *name_count_ = name_count;
|
if (name_count_) *name_count_ = total_name_count;
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2548,8 +2576,8 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
|||||||
AstNode *count_expr = NULL;
|
AstNode *count_expr = NULL;
|
||||||
bool is_vector = false;
|
bool is_vector = false;
|
||||||
|
|
||||||
if (f->curr_token.kind == Token_Ellipsis) {
|
if (f->curr_token.kind == Token_Question) {
|
||||||
count_expr = ast_ellipsis(f, expect_token(f, Token_Ellipsis), NULL);
|
count_expr = ast_unary_expr(f, expect_token(f, Token_Question), NULL);
|
||||||
} else if (f->curr_token.kind == Token_vector) {
|
} else if (f->curr_token.kind == Token_vector) {
|
||||||
next_token(f);
|
next_token(f);
|
||||||
if (f->curr_token.kind != Token_CloseBracket) {
|
if (f->curr_token.kind != Token_CloseBracket) {
|
||||||
@@ -2560,7 +2588,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
|||||||
syntax_error(f->curr_token, "Vector type missing count");
|
syntax_error(f->curr_token, "Vector type missing count");
|
||||||
}
|
}
|
||||||
is_vector = true;
|
is_vector = true;
|
||||||
} else if (f->curr_token.kind == Token_dynamic) {
|
} else if (f->curr_token.kind == Token_Ellipsis) {
|
||||||
next_token(f);
|
next_token(f);
|
||||||
expect_token(f, Token_CloseBracket);
|
expect_token(f, Token_CloseBracket);
|
||||||
return ast_dynamic_array_type(f, token, parse_type(f));
|
return ast_dynamic_array_type(f, token, parse_type(f));
|
||||||
@@ -2627,12 +2655,10 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
|||||||
|
|
||||||
f->expr_level = prev_level;
|
f->expr_level = prev_level;
|
||||||
|
|
||||||
|
|
||||||
if (is_packed && is_ordered) {
|
if (is_packed && is_ordered) {
|
||||||
syntax_error(token, "`#ordered` is not needed with `#packed` which implies ordering");
|
syntax_error(token, "`#ordered` is not needed with `#packed` which implies ordering");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Token open = expect_token_after(f, Token_OpenBrace, "struct");
|
Token open = expect_token_after(f, Token_OpenBrace, "struct");
|
||||||
isize decl_count = 0;
|
isize decl_count = 0;
|
||||||
AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
|
AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
|
||||||
@@ -2685,12 +2711,10 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Token_OpenParen: {
|
case Token_OpenParen: {
|
||||||
// NOTE(bill): Skip the paren expression
|
|
||||||
Token open = expect_token(f, Token_OpenParen);
|
Token open = expect_token(f, Token_OpenParen);
|
||||||
AstNode *type = parse_type(f);
|
AstNode *type = parse_type(f);
|
||||||
Token close = expect_token(f, Token_CloseParen);
|
Token close = expect_token(f, Token_CloseParen);
|
||||||
return type;
|
return ast_paren_expr(f, type, open, close);
|
||||||
// return ast_paren_expr(f, type, open, close);
|
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3504,6 +3528,7 @@ AstNodeArray 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
|
||||||
if (!string_has_extension(fullpath, str_lit("odin"))) {
|
if (!string_has_extension(fullpath, str_lit("odin"))) {
|
||||||
return ParseFile_WrongExtension;
|
return ParseFile_WrongExtension;
|
||||||
}
|
}
|
||||||
@@ -3583,6 +3608,9 @@ void destroy_parser(Parser *p) {
|
|||||||
bool try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) {
|
bool try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) {
|
||||||
gb_mutex_lock(&p->mutex);
|
gb_mutex_lock(&p->mutex);
|
||||||
|
|
||||||
|
path = string_trim_whitespace(path);
|
||||||
|
rel_path = string_trim_whitespace(rel_path);
|
||||||
|
|
||||||
for_array(i, p->imports) {
|
for_array(i, p->imports) {
|
||||||
String import = p->imports.e[i].path;
|
String import = p->imports.e[i].path;
|
||||||
if (str_eq(import, path)) {
|
if (str_eq(import, path)) {
|
||||||
@@ -3763,7 +3791,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
|
|||||||
gb_printf_err("Invalid file extension: File must have the extension `.odin`");
|
gb_printf_err("Invalid file extension: File must have the extension `.odin`");
|
||||||
break;
|
break;
|
||||||
case ParseFile_InvalidFile:
|
case ParseFile_InvalidFile:
|
||||||
gb_printf_err("Invalid file");
|
gb_printf_err("Invalid file or cannot be found");
|
||||||
break;
|
break;
|
||||||
case ParseFile_Permission:
|
case ParseFile_Permission:
|
||||||
gb_printf_err("File permissions problem");
|
gb_printf_err("File permissions problem");
|
||||||
|
|||||||
+29
-8
@@ -145,16 +145,37 @@ gb_inline isize string_extension_position(String str) {
|
|||||||
return dot_pos;
|
return dot_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String string_trim_whitespace(String str) {
|
||||||
|
while (str.len > 0 && rune_is_whitespace(str.text[str.len-1])) {
|
||||||
|
str.len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (str.len > 0 && rune_is_whitespace(str.text[0])) {
|
||||||
|
str.text++;
|
||||||
|
str.len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
gb_inline bool string_has_extension(String str, String ext) {
|
gb_inline bool string_has_extension(String str, String ext) {
|
||||||
if (str.len > ext.len+1) {
|
str = string_trim_whitespace(str);
|
||||||
u8 *s = str.text+str.len - ext.len-1;
|
if (str.len <= ext.len+1) {
|
||||||
if (s[0] == '.') {
|
return false;
|
||||||
s++;
|
}
|
||||||
|
isize len = str.len;
|
||||||
|
for (isize i = len-1; i >= 0; i--) {
|
||||||
|
if (str.text[i] == '.') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
if (len == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *s = str.text + len;
|
||||||
return gb_memcompare(s, ext.text, ext.len) == 0;
|
return gb_memcompare(s, ext.text, ext.len) == 0;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool string_contains_char(String s, u8 c) {
|
bool string_contains_char(String s, u8 c) {
|
||||||
|
|||||||
+3
-3
@@ -107,12 +107,12 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
|||||||
TOKEN_KIND(Token_enum, "enum"), \
|
TOKEN_KIND(Token_enum, "enum"), \
|
||||||
TOKEN_KIND(Token_vector, "vector"), \
|
TOKEN_KIND(Token_vector, "vector"), \
|
||||||
TOKEN_KIND(Token_map, "map"), \
|
TOKEN_KIND(Token_map, "map"), \
|
||||||
TOKEN_KIND(Token_static, "static"), \
|
/* TOKEN_KIND(Token_static, "static"), */ \
|
||||||
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
/* TOKEN_KIND(Token_dynamic, "dynamic"), */ \
|
||||||
TOKEN_KIND(Token_using, "using"), \
|
TOKEN_KIND(Token_using, "using"), \
|
||||||
TOKEN_KIND(Token_no_alias, "no_alias"), \
|
TOKEN_KIND(Token_no_alias, "no_alias"), \
|
||||||
/* TOKEN_KIND(Token_mutable, "mutable"), */ \
|
/* TOKEN_KIND(Token_mutable, "mutable"), */ \
|
||||||
/* TOKEN_KIND(Token_immutable, "immutable"), */\
|
/* TOKEN_KIND(Token_immutable, "immutable"), */ \
|
||||||
TOKEN_KIND(Token_thread_local, "thread_local"), \
|
TOKEN_KIND(Token_thread_local, "thread_local"), \
|
||||||
TOKEN_KIND(Token_cast, "cast"), \
|
TOKEN_KIND(Token_cast, "cast"), \
|
||||||
TOKEN_KIND(Token_transmute, "transmute"), \
|
TOKEN_KIND(Token_transmute, "transmute"), \
|
||||||
|
|||||||
+9
-5
@@ -102,12 +102,12 @@ typedef struct TypeRecord {
|
|||||||
Entity **fields_in_src_order; // Entity_Variable
|
Entity **fields_in_src_order; // Entity_Variable
|
||||||
|
|
||||||
i64 custom_align; // NOTE(bill): Only used in structs at the moment
|
i64 custom_align; // NOTE(bill): Only used in structs at the moment
|
||||||
|
Entity * names;
|
||||||
|
|
||||||
Type * enum_base_type;
|
Type * enum_base_type;
|
||||||
Entity * enum_count;
|
Entity * enum_count;
|
||||||
Entity * enum_min_value;
|
Entity * enum_min_value;
|
||||||
Entity * enum_max_value;
|
Entity * enum_max_value;
|
||||||
Entity * enum_names;
|
|
||||||
} TypeRecord;
|
} TypeRecord;
|
||||||
|
|
||||||
#define TYPE_KINDS \
|
#define TYPE_KINDS \
|
||||||
@@ -1318,6 +1318,14 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
|||||||
return sel;
|
return sel;
|
||||||
}
|
}
|
||||||
if (is_type) {
|
if (is_type) {
|
||||||
|
if (type->kind == Type_Record) {
|
||||||
|
if (type->Record.names != NULL &&
|
||||||
|
str_eq(field_name, str_lit("names"))) {
|
||||||
|
sel.entity = type->Record.names;
|
||||||
|
return sel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (is_type_union(type)) {
|
if (is_type_union(type)) {
|
||||||
// NOTE(bill): The subtype for a union are stored in the fields
|
// NOTE(bill): The subtype for a union are stored in the fields
|
||||||
// as they are "kind of" like variables but not
|
// as they are "kind of" like variables but not
|
||||||
@@ -1347,10 +1355,6 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
|||||||
sel.entity = type->Record.enum_max_value;
|
sel.entity = type->Record.enum_max_value;
|
||||||
return sel;
|
return sel;
|
||||||
}
|
}
|
||||||
if (str_eq(field_name, str_lit("names"))) {
|
|
||||||
sel.entity = type->Record.enum_names;
|
|
||||||
return sel;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||||
|
|||||||
@@ -39,28 +39,3 @@ bool rune_is_whitespace(Rune r) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_string_an_identifier(String s) {
|
|
||||||
isize offset = 0;
|
|
||||||
if (s.len < 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
while (offset < s.len) {
|
|
||||||
bool ok = false;
|
|
||||||
Rune r = -1;
|
|
||||||
isize size = gb_utf8_decode(s.text+offset, s.len-offset, &r);
|
|
||||||
if (offset == 0) {
|
|
||||||
ok = rune_is_letter(r);
|
|
||||||
} else {
|
|
||||||
ok = rune_is_letter(r) || rune_is_digit(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ok) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
offset += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return offset == s.len;
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user