Compare commits

...

22 Commits

Author SHA1 Message Date
Ginger Bill 9b2f5c359a v0.1.1 2017-02-24 19:48:18 +00:00
Ginger Bill a982c51c30 Fix minor bugs in IR for slices 2017-02-23 22:22:56 +00:00
Ginger Bill 047c0e4bcc A decent union type with common fields and variants 2017-02-21 21:21:54 +00:00
Ginger Bill a94dfdf21d Begin changing union syntax 2017-02-19 19:55:19 +00:00
Ginger Bill c0d5237b75 Unexported struct fields on selectors 2017-02-19 12:47:02 +00:00
Ginger Bill 6fdcbefe5d Unexported struct fields 2017-02-19 12:38:49 +00:00
Ginger Bill 3cec2550d9 delete for maps 2017-02-19 11:50:42 +00:00
Ginger Bill 758dd9ba16 Fix overloading bug due to #import .; Add sys/wgl.odin 2017-02-19 11:35:33 +00:00
Ginger Bill 0c37aa9ea0 Fix overloading bug due to comparison of named types 2017-02-18 22:19:35 +00:00
Ginger Bill 9ff474f387 Named return values but do not affect other declarations 2017-02-18 12:02:11 +00:00
Ginger Bill d2f9d20833 Change ternary expression precedence 2017-02-18 10:41:48 +00:00
Ginger Bill 71100ed427 Ternary expression (removed if and block expression) 2017-02-14 19:26:32 +00:00
Ginger Bill 3ecf3505fd Ignore previous silly commit :P I shouldn't have move it 2017-02-14 17:34:02 +00:00
Ginger Bill daa1cd55a1 Move error handling for casting 2017-02-14 17:33:11 +00:00
Ginger Bill 2722de65b7 Prevent cast on pointer to union types 2017-02-14 17:24:56 +00:00
Ginger Bill 8b5e3428a1 Optional ok for union_cast (similar to map indices) 2017-02-14 16:37:24 +00:00
Ginger Bill d1f65097c4 Fix immutable rules; add some general documentation
immutable is still a little weird and not completely what you'd expect. Maybe just not having it is better.
2017-02-14 15:19:29 +00:00
Ginger Bill 74d15ab84b Reimplement immutable with different rules. 2017-02-14 12:35:50 +00:00
Ginger Bill 763cd2649d Fix index assignment rules for indirection 2017-02-14 12:21:02 +00:00
Ginger Bill bd27c24fab Use a global to store the build context information 2017-02-12 21:27:13 +00:00
Ginger Bill 282f8bb06f Fix issue #23 2017-02-12 11:41:06 +00:00
Ginger Bill b9ed546ce0 Record type field names 2017-02-12 11:31:04 +00:00
26 changed files with 2406 additions and 1903 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
set exe_name=odin.exe
:: Debug = 0, Release = 1
set release_mode=1
set release_mode=0
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
if %release_mode% EQU 0 ( rem Debug
+26 -5
View File
@@ -1,11 +1,17 @@
#import "fmt.odin";
#import "atomic.odin";
#import "hash.odin";
#import "math.odin";
#import "mem.odin";
#import "opengl.odin";
#import "os.odin";
main :: proc() {
/*
Version 0.1.0
Version 0.1.1
Added:
* Dynamic Arrays `[...]Type`
* Dynamic Arrays `[dynamic]Type`
* Dynamic Maps `map[Key]Value`
* Dynamic array and map literals
* Custom struct alignemnt `struct #align 8 { bar: i8 }`
@@ -15,10 +21,20 @@ main :: proc() {
* Entities prefixes with an underscore do not get exported on imports
* Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps
* enum types have an implict `names` field, a []string of all the names in that enum
* immutable variables are "completely immutable" - rules need a full explanation
* `slice_to_bytes` - convert any slice to a slice of bytes
* `union_cast` allows for optional ok check
* Record type field `names` (struct/raw_union/enum)
* ?: ternary operator
* Unions with variants and common fields
* New built-in procedures
- `delete` to delete map entries `delete(m, key)`
- `clear` to clear dynamic maps and arrays `clear(map_or_array)`
- `reserve` to reserve space for the dynamic maps and arrays `reserve(map_or_array)`
* Unexported entities and fields using an underscore prefix
Removed:
* Maybe/option types
* immutable variables
* Remove `type` keyword and other "reserved" keywords
* `compile_assert` and `assert`return the value of the condition for semantic reasons
@@ -29,9 +45,14 @@ main :: proc() {
* match x in y {} // For type match statements
* Version numbering now starts from 0.1.0 and uses the convention:
- major.minor.patch
* Core library additions to Windows specific stuff
Fixes:
* Many fmt.* fixes
* Overloading bug due to comparison of named types
* Overloading bug due to `#import .` collision
* disallow a `cast` from pointers of unions
* Minor bugs in generated IR code for slices
To come very Soon:
* Linux and OS X builds (unofficial ones do exist already)
@@ -85,7 +106,7 @@ main :: proc() {
}
{
x: [...]f64;
x: [dynamic]f64;
reserve(x, 16);
defer free(x);
append(x, 2_000_000.500_000, 3, 5, 7);
@@ -98,7 +119,7 @@ main :: proc() {
}
{
x := [...]f64{2_000_000.500_000, 3, 5, 7};
x := [dynamic]f64{2_000_000.500_000, 3, 5, 7};
defer free(x);
fmt.println(x);
}
+59 -67
View File
@@ -14,25 +14,11 @@
// IMPORTANT NOTE(bill): Do not change the order of any of this data
// The compiler relies upon this _exact_ order
Type_Info_Member :: struct #ordered {
name: string, // can be empty if tuple
type_info: ^Type_Info,
offset: int, // offsets may not be used in tuples
}
Type_Info_Record :: struct #ordered {
fields: []Type_Info_Member,
size: int, // in bytes
align: int, // in bytes
packed: bool,
ordered: bool,
custom_align: bool,
}
Type_Info_Enum_Value :: raw_union {
f: f64,
i: i64,
}
// NOTE(bill): This much the same as the compiler's
// NOTE(bill): This must match the compiler's
Calling_Convention :: enum {
ODIN = 0,
C = 1,
@@ -40,59 +26,61 @@ Calling_Convention :: enum {
FAST = 3,
}
Type_Info_Record :: struct #ordered {
types: []^Type_Info,
names: []string,
offsets: []int, // offsets may not be used in tuples
size: int, // in bytes
align: int, // in bytes
packed: bool,
ordered: bool,
custom_align: bool,
}
Type_Info :: union {
Named: struct #ordered {
name: string,
base: ^Type_Info, // This will _not_ be a Type_Info.Named
},
Integer: struct #ordered {
size: int, // in bytes
signed: bool,
},
Float: struct #ordered {
size: int, // in bytes
},
String: struct #ordered {},
Boolean: struct #ordered {},
Any: struct #ordered {},
Pointer: struct #ordered {
Named{name: string, base: ^Type_Info},
Integer{size: int, signed: bool},
Float{size: int},
String{},
Boolean{},
Any{},
Pointer{
elem: ^Type_Info, // nil -> rawptr
},
Procedure: struct #ordered {
Procedure{
params: ^Type_Info, // Type_Info.Tuple
results: ^Type_Info, // Type_Info.Tuple
variadic: bool,
convention: Calling_Convention,
},
Array: struct #ordered {
Array{
elem: ^Type_Info,
elem_size: int,
count: int,
},
Dynamic_Array: struct #ordered {
elem: ^Type_Info,
elem_size: int,
Dynamic_Array{elem: ^Type_Info, elem_size: int},
Slice {elem: ^Type_Info, elem_size: int},
Vector {elem: ^Type_Info, elem_size, count, align: int},
Tuple {using record: Type_Info_Record}, // Only really used for procedures
Struct {using record: Type_Info_Record},
Raw_Union {using record: Type_Info_Record},
Union{
common_fields: struct {
types: []^Type_Info,
names: []string,
offsets: []int, // offsets may not be used in tuples
},
variant_names: []string,
variant_types: []^Type_Info,
size: int,
align: int,
},
Slice: struct #ordered {
elem: ^Type_Info,
elem_size: int,
},
Vector: struct #ordered {
elem: ^Type_Info,
elem_size: int,
count: int,
align: int,
},
Tuple: Type_Info_Record, // Only really used for procedures
Struct: Type_Info_Record,
Union: Type_Info_Record,
Raw_Union: Type_Info_Record,
Enum: struct #ordered {
Enum{
base: ^Type_Info,
names: []string,
values: []Type_Info_Enum_Value,
},
Map: struct #ordered {
Map{
key: ^Type_Info,
value: ^Type_Info,
generated_struct: ^Type_Info,
@@ -100,9 +88,10 @@ Type_Info :: union {
},
}
// // NOTE(bill): only the ones that are needed (not all types)
// // This will be set by the compiler
// immutable __type_infos: []Type_Info;
// NOTE(bill): only the ones that are needed (not all types)
// This will be set by the compiler
__type_table: []Type_Info;
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
if info == nil {
@@ -318,7 +307,11 @@ __assert :: proc(file: string, line, column: int, msg: string) #inline {
file, line, column, msg);
__debug_trap();
}
__panic :: proc(file: string, line, column: int, msg: string) #inline {
fmt.fprintf(os.stderr, "%s(%d:%d) Panic: %s\n",
file, line, column, msg);
__debug_trap();
}
__bounds_check_error :: proc(file: string, line, column: int, index, count: int) {
if 0 <= index && index < count {
return;
@@ -344,6 +337,13 @@ __substring_expr_error :: proc(file: string, line, column: int, low, high: int)
file, line, column, low, high);
__debug_trap();
}
__union_cast_check :: proc(ok: bool, file: string, line, column: int, from, to: ^Type_Info) {
if !ok {
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid `union_cast` from %T to %T\n",
file, line, column, from, to);
__debug_trap();
}
}
__string_decode_rune :: proc(s: string) -> (rune, int) #inline {
return utf8.decode_rune(s);
@@ -373,7 +373,7 @@ Raw_Dynamic_Array :: struct #ordered {
};
Raw_Dynamic_Map :: struct #ordered {
hashes: [...]int,
hashes: [dynamic]int,
entries: Raw_Dynamic_Array,
};
@@ -452,6 +452,8 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
}
// Map stuff
__default_hash :: proc(data: []byte) -> u64 {
return hash.fnv64a(data);
}
@@ -623,7 +625,7 @@ __dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int {
}
__dynamic_map_remove :: proc(using h: __Map_Header, key: __Map_Key) {
__dynamic_map_delete :: proc(using h: __Map_Header, key: __Map_Key) {
fr := __dynamic_map_find(h, key);
if fr.entry_index >= 0 {
__dynamic_map_erase(h, fr);
@@ -653,13 +655,3 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
m.hashes[last.hash_index] = fr.entry_index;
}
}
__print_ti_ptr :: proc(ti: ^Type_Info) {
fmt.println(ti);
match e in ti {
case Type_Info.Enum:
fmt.println(e.names);
}
}
+98 -43
View File
@@ -116,7 +116,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
case ti == type_info(int): buffer_write_string(buf, "int");
case ti == type_info(uint): buffer_write_string(buf, "uint");
default:
buffer_write_string(buf, if info.signed { give "i" } else { give "u"});
buffer_write_string(buf, info.signed ? "i" : "u");
fi := Fmt_Info{buf = buf};
fmt_int(^fi, cast(u64)(8*info.size), false, 'd');
}
@@ -140,11 +140,11 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
if info.params == nil {
buffer_write_string(buf, "()");
} else {
fields := (cast(^Tuple)info.params).fields;
t := union_cast(^Tuple)info.params;
buffer_write_string(buf, "(");
for f, i in fields {
for type, i in t.types {
if i > 0 { buffer_write_string(buf, ", "); }
buffer_write_type(buf, f.type_info);
buffer_write_type(buf, type);
}
buffer_write_string(buf, ")");
}
@@ -153,18 +153,18 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
buffer_write_type(buf, info.results);
}
case Tuple:
count := info.fields.count;
count := info.names.count;
if count != 1 { buffer_write_string(buf, "("); }
for i in 0..<count {
for name, i in info.names {
if i > 0 { buffer_write_string(buf, ", "); }
f := info.fields[i];
type := info.types[i];
if f.name.count > 0 {
buffer_write_string(buf, f.name);
if name.count > 0 {
buffer_write_string(buf, name);
buffer_write_string(buf, ": ");
}
buffer_write_type(buf, f.type_info);
buffer_write_type(buf, type);
}
if count != 1 { buffer_write_string(buf, ")"); }
@@ -205,38 +205,71 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
buffer_write_byte(buf, ' ');
}
buffer_write_byte(buf, '{');
for field, i in info.fields {
buffer_write_string(buf, field.name);
for name, i in info.names {
if i > 0 {
buffer_write_string(buf, ", ");
}
buffer_write_string(buf, name);
buffer_write_string(buf, ": ");
buffer_write_type(buf, field.type_info);
buffer_write_byte(buf, ',');
buffer_write_type(buf, info.types[i]);
}
buffer_write_byte(buf, '}');
case Union:
buffer_write_string(buf, "union {");
for field, i in info.fields {
buffer_write_string(buf, field.name);
cf := info.common_fields;
total_count := 0;
for name, i in cf.names {
if i > 0 {
buffer_write_string(buf, ", ");
}
buffer_write_string(buf, name);
buffer_write_string(buf, ": ");
buffer_write_type(buf, field.type_info);
buffer_write_byte(buf, ',');
buffer_write_type(buf, cf.types[i]);
total_count += 1;
}
for name, i in info.variant_names {
if total_count > 0 || i > 0 {
buffer_write_string(buf, ", ");
}
buffer_write_string(buf, name);
buffer_write_byte(buf, '{');
defer buffer_write_byte(buf, '}');
variant_type := type_info_base(info.variant_types[i]);
variant := union_cast(^Struct)variant_type;
vc := variant.names.count-cf.names.count;
for j in 0..<vc {
if j > 0 {
buffer_write_string(buf, ", ");
}
index := j + cf.names.count;
buffer_write_string(buf, variant.names[index]);
buffer_write_string(buf, ": ");
buffer_write_type(buf, variant.types[index]);
}
}
buffer_write_string(buf, "}");
case Raw_Union:
buffer_write_string(buf, "raw_union {");
for field, i in info.fields {
buffer_write_string(buf, field.name);
for name, i in info.names {
if i > 0 {
buffer_write_string(buf, ", ");
}
buffer_write_string(buf, name);
buffer_write_string(buf, ": ");
buffer_write_type(buf, field.type_info);
buffer_write_byte(buf, ',');
buffer_write_type(buf, info.types[i]);
}
buffer_write_string(buf, "}");
case Enum:
buffer_write_string(buf, "enum ");
buffer_write_type(buf, info.base);
buffer_write_string(buf, " {}");
buffer_write_string(buf, " {");
buffer_write_string(buf, "}");
}
}
@@ -293,7 +326,7 @@ sprintf :: proc(buf: []byte, fmt: string, args: ...any) -> string {
parse_int :: proc(s: string, offset: int) -> (int, int, bool) {
parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: bool) {
is_digit :: proc(r: rune) -> bool #inline {
return '0' <= r && r <= '9';
}
@@ -316,7 +349,12 @@ parse_int :: proc(s: string, offset: int) -> (int, int, bool) {
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,
) -> (index: int, offset: int, ok: bool) {
parse_arg_number :: proc(format: string) -> (int, int, bool) {
if format.count < 3 {
return 0, 1, false;
@@ -392,7 +430,7 @@ fmt_bad_verb :: proc(using fi: ^Fmt_Info, verb: rune) {
fmt_bool :: proc(using fi: ^Fmt_Info, b: bool, verb: rune) {
match verb {
case 't', 'v':
buffer_write_string(buf, if b { give "true" } else { give "false" });
buffer_write_string(buf, b ? "true" : "false");
default:
fmt_bad_verb(fi, verb);
}
@@ -417,9 +455,10 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) {
}
fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: string) {
s := cast(i64)u;
negative := signed && s < 0;
u = cast(u64)abs(s);
negative := signed && cast(i64)u < 0;
if signed {
u = cast(u64)abs(cast(i64)u);
}
buf: [256]byte;
if fi.width_set || fi.prec_set {
width := fi.width + fi.prec + 3;
@@ -681,6 +720,9 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
break;
}
}
} else if e.values.count == 0 {
buffer_write_string(fi.buf, "");
ok = true;
} else {
for it, idx in e.values {
if it.f == f {
@@ -719,14 +761,14 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
}
buffer_write_string(fi.buf, info.name);
buffer_write_byte(fi.buf, '{');
for f, i in b.fields {
for _, i in b.names {
if i > 0 {
buffer_write_string(fi.buf, ", ");
}
buffer_write_string(fi.buf, f.name);
buffer_write_string(fi.buf, b.names[i]);
buffer_write_string(fi.buf, " = ");
data := cast(^byte)v.data + f.offset;
fmt_arg(fi, any{f.type_info, cast(rawptr)data}, 'v');
data := cast(^byte)v.data + b.offsets[i];
fmt_arg(fi, any{b.types[i], cast(rawptr)data}, 'v');
}
buffer_write_byte(fi.buf, '}');
@@ -788,10 +830,10 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
buffer_write_string(fi.buf, "map[");
defer buffer_write_byte(fi.buf, ']');
entries := ^(cast(^Raw_Dynamic_Map)v.data).entries;
gs, gs_ok := union_cast(^Struct)type_info_base(info.generated_struct); assert(gs_ok);
ed, ed_ok := union_cast(^Dynamic_Array)type_info_base(gs.fields[1].type_info); assert(ed_ok);
gs := union_cast(^Struct)type_info_base(info.generated_struct);
ed := union_cast(^Dynamic_Array)type_info_base(gs.types[1]);
entry_type, et_ok := union_cast(^Struct)ed.elem; assert(et_ok);
entry_type := union_cast(^Struct)ed.elem;
entry_size := ed.elem_size;
for i in 0..<entries.count {
if i > 0 {
@@ -809,7 +851,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
buffer_write_string(fi.buf, "=");
value := data + entry_type.fields[2].offset;
value := data + entry_type.offsets[2];
fmt_arg(fi, any{info.value, cast(rawptr)value}, 'v');
}
@@ -847,19 +889,32 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
buffer_write_byte(fi.buf, '{');
defer buffer_write_byte(fi.buf, '}');
for f, i in info.fields {
for _, i in info.names {
if i > 0 {
buffer_write_string(fi.buf, ", ");
}
buffer_write_string(fi.buf, f.name);
buffer_write_string(fi.buf, info.names[i]);
buffer_write_string(fi.buf, " = ");
data := cast(^byte)v.data + f.offset;
ti := f.type_info;
fmt_value(fi, any{ti, cast(rawptr)data}, 'v');
data := cast(^byte)v.data + info.offsets[i];
fmt_value(fi, any{info.types[i], cast(rawptr)data}, 'v');
}
case Union:
buffer_write_string(fi.buf, "(union)");
buffer_write_byte(fi.buf, '{');
defer buffer_write_byte(fi.buf, '}');
cf := info.common_fields;
for _, i in cf.names {
if i > 0 {
buffer_write_string(fi.buf, ", ");
}
buffer_write_string(fi.buf, cf.names[i]);
buffer_write_string(fi.buf, " = ");
data := cast(^byte)v.data + cf.offsets[i];
fmt_value(fi, any{cf.types[i], cast(rawptr)data}, 'v');
}
case Raw_Union:
buffer_write_string(fi.buf, "(raw_union)");
+4 -4
View File
@@ -1,14 +1,14 @@
crc32 :: proc(data: []byte) -> u32 {
result := ~cast(u32)0;
for b in data {
result = result>>8 ~ __CRC32_TABLE[(result ~ cast(u32)b) & 0xff];
result = result>>8 ~ _crc32_table[(result ~ cast(u32)b) & 0xff];
}
return ~result;
}
crc64 :: proc(data: []byte) -> u64 {
result := ~cast(u64)0;
for b in data {
result = result>>8 ~ __CRC64_TABLE[(result ~ cast(u64)b) & 0xff];
result = result>>8 ~ _crc64_table[(result ~ cast(u64)b) & 0xff];
}
return ~result;
}
@@ -202,7 +202,7 @@ murmur64 :: proc(data: []byte) -> u64 {
}
__CRC32_TABLE := [256]u32{
immutable _crc32_table := [256]u32{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -268,7 +268,7 @@ __CRC32_TABLE := [256]u32{
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
__CRC64_TABLE := [256]u64{
immutable _crc64_table := [256]u64{
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
+89 -88
View File
@@ -1,5 +1,6 @@
#foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
#import "sys/wgl.odin" when ODIN_OS == "windows";
#load "opengl_constants.odin";
Clear :: proc(mask: u32) #foreign lib "glClear";
@@ -20,13 +21,13 @@ Viewport :: proc(x, y, width, height: i32) #foreign lib "gl
Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign lib "glOrtho";
Color3f :: proc(r, g, b: f32) #foreign lib "glColor3f";
Vertex3f :: proc(x, y, z: f32) #foreign lib "glVertex3f";
GetError :: proc() -> i32 #foreign lib "glGetError";
GetString :: proc(name: i32) -> ^byte #foreign lib "glGetString";
GetIntegerv :: proc(name: i32, v: ^i32) #foreign lib "glGetIntegerv";
TexCoord2f :: proc(x, y: f32) #foreign lib "glTexCoord2f";
TexImage2D :: proc(target, level, internal_format,
width, height, border,
format, _type: i32, pixels: rawptr) #foreign lib "glTexImage2D";
GetError :: proc() -> i32 #foreign lib "glGetError";
GetString :: proc(name: i32) -> ^byte #foreign lib "glGetString";
GetIntegerv :: proc(name: i32, v: ^i32) #foreign lib "glGetIntegerv";
format, type: i32, pixels: rawptr) #foreign lib "glTexImage2D";
string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; }
@@ -35,121 +36,121 @@ _libgl := win32.LoadLibraryA(string_data("opengl32.dll\x00"));
GetProcAddress :: proc(name: string) -> proc() #cc_c {
assert(name[name.count-1] == 0);
res := win32.wglGetProcAddress(name.data);
res := wgl.GetProcAddress(name.data);
if res == nil {
res = win32.GetProcAddress(_libgl, name.data);
}
return res;
}
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
BindBuffer: proc(target: i32, buffer: u32) #cc_c;
BindVertexArray: proc(buffer: u32) #cc_c;
BindSampler: proc(position: i32, sampler: u32) #cc_c;
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c;
BufferSubData: proc(target: i32, offset, size: int, data: rawptr) #cc_c;
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
BindBuffer: proc(target: i32, buffer: u32) #cc_c;
BindVertexArray: proc(buffer: u32) #cc_c;
BindSampler: proc(position: i32, sampler: u32) #cc_c;
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c;
BufferSubData: proc(target: i32, offset, size: int, data: rawptr) #cc_c;
DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
MapBuffer: proc(target, access: i32) -> rawptr #cc_c;
UnmapBuffer: proc(target: i32) #cc_c;
MapBuffer: proc(target, access: i32) -> rawptr #cc_c;
UnmapBuffer: proc(target: i32) #cc_c;
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c;
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c;
EnableVertexAttribArray: proc(index: u32) #cc_c;
CreateShader: proc(shader_type: i32) -> u32 #cc_c;
ShaderSource: proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c;
CompileShader: proc(shader: u32) #cc_c;
CreateProgram: proc() -> u32 #cc_c;
AttachShader: proc(program, shader: u32) #cc_c;
DetachShader: proc(program, shader: u32) #cc_c;
DeleteShader: proc(shader: u32) #cc_c;
LinkProgram: proc(program: u32) #cc_c;
UseProgram: proc(program: u32) #cc_c;
DeleteProgram: proc(program: u32) #cc_c;
CreateShader: proc(shader_type: i32) -> u32 #cc_c;
ShaderSource: proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c;
CompileShader: proc(shader: u32) #cc_c;
CreateProgram: proc() -> u32 #cc_c;
AttachShader: proc(program, shader: u32) #cc_c;
DetachShader: proc(program, shader: u32) #cc_c;
DeleteShader: proc(shader: u32) #cc_c;
LinkProgram: proc(program: u32) #cc_c;
UseProgram: proc(program: u32) #cc_c;
DeleteProgram: proc(program: u32) #cc_c;
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c;
GetProgramiv: proc(program: u32, pname: i32, params: ^i32) #cc_c;
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c;
GetProgramiv: proc(program: u32, pname: i32, params: ^i32) #cc_c;
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
ActiveTexture: proc(texture: i32) #cc_c;
GenerateMipmap: proc(target: i32) #cc_c;
ActiveTexture: proc(texture: i32) #cc_c;
GenerateMipmap: proc(target: i32) #cc_c;
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c;
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c;
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c;
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c;
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
Uniform1i: proc(loc: i32, v0: i32) #cc_c;
Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c;
Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c;
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
Uniform1f: proc(loc: i32, v0: f32) #cc_c;
Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c;
Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c;
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32) #cc_c;
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
Uniform1i: proc(loc: i32, v0: i32) #cc_c;
Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c;
Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c;
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
Uniform1f: proc(loc: i32, v0: f32) #cc_c;
Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c;
Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c;
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32) #cc_c;
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
init :: proc() {
set_proc_address :: proc(p: rawptr, name: string) #inline { (cast(^(proc() #cc_c))p)^ = GetProcAddress(name); }
set_proc_address(^GenBuffers, "glGenBuffers\x00");
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
set_proc_address(^GenSamplers, "glGenSamplers\x00");
set_proc_address(^BindBuffer, "glBindBuffer\x00");
set_proc_address(^BindSampler, "glBindSampler\x00");
set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
set_proc_address(^BufferData, "glBufferData\x00");
set_proc_address(^BufferSubData, "glBufferSubData\x00");
set_proc_address(^GenBuffers, "glGenBuffers\x00");
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
set_proc_address(^GenSamplers, "glGenSamplers\x00");
set_proc_address(^BindBuffer, "glBindBuffer\x00");
set_proc_address(^BindSampler, "glBindSampler\x00");
set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
set_proc_address(^BufferData, "glBufferData\x00");
set_proc_address(^BufferSubData, "glBufferSubData\x00");
set_proc_address(^DrawArrays, "glDrawArrays\x00");
set_proc_address(^DrawElements, "glDrawElements\x00");
set_proc_address(^DrawArrays, "glDrawArrays\x00");
set_proc_address(^DrawElements, "glDrawElements\x00");
set_proc_address(^MapBuffer, "glMapBuffer\x00");
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");
set_proc_address(^MapBuffer, "glMapBuffer\x00");
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");
set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00");
set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
set_proc_address(^CreateShader, "glCreateShader\x00");
set_proc_address(^ShaderSource, "glShaderSource\x00");
set_proc_address(^CompileShader, "glCompileShader\x00");
set_proc_address(^CreateProgram, "glCreateProgram\x00");
set_proc_address(^AttachShader, "glAttachShader\x00");
set_proc_address(^DetachShader, "glDetachShader\x00");
set_proc_address(^DeleteShader, "glDeleteShader\x00");
set_proc_address(^LinkProgram, "glLinkProgram\x00");
set_proc_address(^UseProgram, "glUseProgram\x00");
set_proc_address(^DeleteProgram, "glDeleteProgram\x00");
set_proc_address(^CreateShader, "glCreateShader\x00");
set_proc_address(^ShaderSource, "glShaderSource\x00");
set_proc_address(^CompileShader, "glCompileShader\x00");
set_proc_address(^CreateProgram, "glCreateProgram\x00");
set_proc_address(^AttachShader, "glAttachShader\x00");
set_proc_address(^DetachShader, "glDetachShader\x00");
set_proc_address(^DeleteShader, "glDeleteShader\x00");
set_proc_address(^LinkProgram, "glLinkProgram\x00");
set_proc_address(^UseProgram, "glUseProgram\x00");
set_proc_address(^DeleteProgram, "glDeleteProgram\x00");
set_proc_address(^GetShaderiv, "glGetShaderiv\x00");
set_proc_address(^GetProgramiv, "glGetProgramiv\x00");
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00");
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");
set_proc_address(^GetShaderiv, "glGetShaderiv\x00");
set_proc_address(^GetProgramiv, "glGetProgramiv\x00");
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00");
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");
set_proc_address(^ActiveTexture, "glActiveTexture\x00");
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");
set_proc_address(^ActiveTexture, "glActiveTexture\x00");
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");
set_proc_address(^Uniform1i, "glUniform1i\x00");
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00");
set_proc_address(^Uniform1i, "glUniform1i\x00");
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00");
set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00");
set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00");
set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00");
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00");
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00");
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00");
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00");
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00");
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00");
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00");
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00");
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00");
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
}
+72
View File
@@ -0,0 +1,72 @@
#foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
#import . "windows.odin";
CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
CONTEXT_MINOR_VERSION_ARB :: 0x2092;
CONTEXT_FLAGS_ARB :: 0x2094;
CONTEXT_PROFILE_MASK_ARB :: 0x9126;
CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002;
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001;
HGLRC :: HANDLE;
COLORREF :: u32;
LAYERPLANEDESCRIPTOR :: struct #ordered {
size: u16,
version: u16,
flags: u32,
pixel_type: byte,
color_bits: byte,
red_bits: byte,
red_shift: byte,
green_bits: byte,
green_shift: byte,
blue_bits: byte,
blue_shift: byte,
alpha_bits: byte,
alpha_shift: byte,
accum_bits: byte,
accum_red_bits: byte,
accum_green_bits: byte,
accum_blue_bits: byte,
accum_alpha_bits: byte,
depth_bits: byte,
stencil_bits: byte,
aux_buffers: byte,
layer_type: byte,
reserved: byte,
transparent: COLORREF,
}
POINTFLOAT :: struct #ordered {
x, y: f32,
}
GLYPHMETRICSFLOAT :: struct #ordered {
black_box_x: f32,
black_box_y: f32,
glyph_origin: POINTFLOAT,
cell_inc_x: f32,
cell_inc_y: f32,
}
CreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
ChoosePixelFormatARBType :: #type proc(hdc: HDC, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> BOOL #cc_c;
CreateContext :: proc(hdc: HDC) -> HGLRC #foreign opengl32 "wglCreateContext";
MakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32 "wglMakeCurrent";
GetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32 "wglGetProcAddress";
DeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32 "wglDeleteContext";
CopyContext :: proc(src, dst: HGLRC, mask: u32) -> BOOL #foreign opengl32 "wglCopyContext";
CreateLayerContext :: proc(hdc: HDC, layer_plane: i32) -> HGLRC #foreign opengl32 "wglCreateLayerContext";
DescribeLayerPlane :: proc(hdc: HDC, pixel_format, layer_plane: i32, bytes: u32, pd: ^LAYERPLANEDESCRIPTOR) -> BOOL #foreign opengl32 "wglDescribeLayerPlane";
GetCurrentContext :: proc() -> HGLRC #foreign opengl32 "wglGetCurrentContext";
GetCurrentDC :: proc() -> HDC #foreign opengl32 "wglGetCurrentDC";
GetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglGetLayerPaletteEntries";
RealizeLayerPalette :: proc(hdc: HDC, layer_plane: i32, realize: BOOL) -> BOOL #foreign opengl32 "wglRealizeLayerPalette";
SetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglSetLayerPaletteEntries";
ShareLists :: proc(hglrc1, hglrc2: HGLRC) -> BOOL #foreign opengl32 "wglShareLists";
SwapLayerBuffers :: proc(hdc: HDC, planes: u32) -> BOOL #foreign opengl32 "wglSwapLayerBuffers";
UseFontBitmaps :: proc(hdc: HDC, first, count, list_base: u32) -> BOOL #foreign opengl32 "wglUseFontBitmaps";
UseFontOutlines :: proc(hdc: HDC, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^GLYPHMETRICSFLOAT) -> BOOL #foreign opengl32 "wglUseFontOutlines";
+14 -22
View File
@@ -2,7 +2,6 @@
#foreign_system_library "user32.lib" when ODIN_OS == "windows";
#foreign_system_library "gdi32.lib" when ODIN_OS == "windows";
#foreign_system_library "winmm.lib" when ODIN_OS == "windows";
#foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
HANDLE :: rawptr;
HWND :: HANDLE;
@@ -41,11 +40,14 @@ WS_CAPTION :: 0x00C00000;
WS_VISIBLE :: 0x10000000;
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
WM_DESTROY :: 0x0002;
WM_CLOSE :: 0x0010;
WM_QUIT :: 0x0012;
WM_KEYDOWN :: 0x0100;
WM_KEYUP :: 0x0101;
WM_DESTROY :: 0x0002;
WM_SIZE :: 0x0005;
WM_CLOSE :: 0x0010;
WM_ACTIVATEAPP :: 0x001C;
WM_QUIT :: 0x0012;
WM_KEYDOWN :: 0x0100;
WM_KEYUP :: 0x0101;
WM_SIZING :: 0x0214;
PM_REMOVE :: 1;
@@ -165,6 +167,9 @@ DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) ->
AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign user32;
GetActiveWindow :: proc() -> HWND #foreign user32;
DestroyWindow :: proc(wnd: HWND) -> BOOL #foreign user32;
DescribePixelFormat :: proc(dc: HDC, pixel_format: i32, bytes : u32, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32;
GetQueryPerformanceFrequency :: proc() -> i64 {
r: i64;
@@ -357,10 +362,6 @@ PFD_DEPTH_DONTCARE :: 0x20000000;
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
PFD_STEREO_DONTCARE :: 0x80000000;
HGLRC :: HANDLE;
PROC :: #type proc() #cc_c;
wglCreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
PIXELFORMATDESCRIPTOR :: struct #ordered {
size,
@@ -393,23 +394,14 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
damage_mask: u32,
}
GetDC :: proc(h: HANDLE) -> HDC #foreign user32;
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign gdi32;
GetDC :: proc(h: HWND) -> HDC #foreign user32;
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR) -> BOOL #foreign gdi32;
ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32;
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign gdi32;
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign user32;
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092;
WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126;
WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001;
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002;
wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign opengl32;
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32;
wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32;
wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32;
PROC :: #type proc() #cc_c;
GetKeyState :: proc(v_key: i32) -> i16 #foreign user32;
+1 -1
View File
@@ -1,6 +1,6 @@
is_signed :: proc(info: ^Type_Info) -> bool {
if is_integer(info) {
i := cast(^Type_Info.Integer)info;
i := union_cast(^Type_Info.Integer)info;
return i.signed;
}
if is_float(info) {
+2 -2
View File
@@ -30,7 +30,7 @@ HICB :: 0b1011_1111;
Accept_Range :: struct { lo, hi: u8 }
accept_ranges := [5]Accept_Range{
immutable accept_ranges := [5]Accept_Range{
{0x80, 0xbf},
{0xa0, 0xbf},
{0x80, 0x9f},
@@ -38,7 +38,7 @@ accept_ranges := [5]Accept_Range{
{0x80, 0x8f},
};
accept_sizes := [256]byte{
immutable accept_sizes := [256]byte{
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
+14 -23
View File
@@ -1,4 +1,6 @@
// This stores the information for the specify architecture of this build
typedef struct BuildContext {
// Constants
String ODIN_OS; // target operating system
String ODIN_ARCH; // target architecture
String ODIN_ENDIAN; // target endian
@@ -6,13 +8,20 @@ typedef struct BuildContext {
String ODIN_VERSION; // compiler version
String ODIN_ROOT; // Odin ROOT
i64 word_size;
i64 max_align;
// In bytes
i64 word_size; // Size of a pointer, must be >= 4
i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
String llc_flags;
String link_flags;
bool is_dll;
} BuildContext;
gb_global BuildContext build_context = {0};
// TODO(bill): OS dependent versions for the BuildContext
// join_path
// is_dir
@@ -129,25 +138,6 @@ String odin_root_dir(void) {
#error Implement system
#endif
#if defined(GB_SYSTEM_WINDOWS)
String path_to_fullpath(gbAllocator a, String s) {
@@ -216,9 +206,10 @@ String get_fullpath_core(gbAllocator a, String path) {
void init_build_context(BuildContext *bc) {
void init_build_context(void) {
BuildContext *bc = &build_context;
bc->ODIN_VENDOR = str_lit("odin");
bc->ODIN_VERSION = str_lit("0.1.0");
bc->ODIN_VERSION = str_lit("0.1.1");
bc->ODIN_ROOT = odin_root_dir();
#if defined(GB_SYSTEM_WINDOWS)
+2 -13
View File
@@ -72,25 +72,14 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
}
}
isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) {
check_init_variable(c, lhs[i], &operands.e[i], context_name);
}
if (rhs_count > 0 && lhs_count != rhs_count) {
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
}
#if 0
if (lhs[0]->kind == Entity_Variable &&
lhs[0]->Variable.is_let) {
if (lhs_count != rhs_count) {
error(lhs[0]->token, "`let` variables must be initialized, `%td` = `%td`", lhs_count, rhs_count);
}
}
#endif
gb_temp_arena_memory_end(tmp);
}
@@ -300,7 +289,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
}
if (is_foreign) {
MapEntity *fp = &c->info.foreign_procs;
MapEntity *fp = &c->info.foreigns;
String name = e->token.string;
if (pd->foreign_name.len > 0) {
name = pd->foreign_name;
@@ -355,7 +344,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
}
if (is_link_name || is_export) {
MapEntity *fp = &c->info.foreign_procs;
MapEntity *fp = &c->info.foreigns;
e->Procedure.link_name = name;
+588 -561
View File
File diff suppressed because it is too large Load Diff
+72 -73
View File
@@ -30,11 +30,6 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
case AstNode_ReturnStmt:
error_node(n, "Statements after this `return` are never executed");
break;
case AstNode_ExprStmt:
if (n->ExprStmt.expr->kind == AstNode_GiveExpr) {
error_node(n, "A `give` must be the last statement in a block");
}
break;
}
}
@@ -182,40 +177,40 @@ bool check_is_terminating(AstNode *node) {
return false;
}
Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
if (op_a->mode == Addressing_Invalid ||
(op_a->type == t_invalid && op_a->mode != Addressing_Overload)) {
Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
if (rhs->mode == Addressing_Invalid ||
(rhs->type == t_invalid && rhs->mode != Addressing_Overload)) {
return NULL;
}
AstNode *node = unparen_expr(lhs);
AstNode *node = unparen_expr(lhs_node);
// NOTE(bill): Ignore assignments to `_`
if (node->kind == AstNode_Ident &&
str_eq(node->Ident.string, str_lit("_"))) {
add_entity_definition(&c->info, node, NULL);
check_assignment(c, op_a, NULL, str_lit("assignment to `_` identifier"));
if (op_a->mode == Addressing_Invalid) {
check_assignment(c, rhs, NULL, str_lit("assignment to `_` identifier"));
if (rhs->mode == Addressing_Invalid) {
return NULL;
}
return op_a->type;
return rhs->type;
}
Entity *e = NULL;
bool used = false;
Operand op_b = {Addressing_Invalid};
Operand lhs = {Addressing_Invalid};
check_expr(c, &op_b, lhs);
if (op_b.mode == Addressing_Invalid ||
op_b.type == t_invalid) {
check_expr(c, &lhs, lhs_node);
if (lhs.mode == Addressing_Invalid ||
lhs.type == t_invalid) {
return NULL;
}
if (op_a->mode == Addressing_Overload) {
isize overload_count = op_a->overload_count;
Entity **procs = op_a->overload_entities;
if (rhs->mode == Addressing_Overload) {
isize overload_count = rhs->overload_count;
Entity **procs = rhs->overload_entities;
GB_ASSERT(procs != NULL && overload_count > 0);
// NOTE(bill): These should be done
@@ -227,19 +222,19 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
Operand x = {0};
x.mode = Addressing_Value;
x.type = t;
if (check_is_assignable_to(c, &x, op_b.type)) {
if (check_is_assignable_to(c, &x, lhs.type)) {
e = procs[i];
add_entity_use(c, op_a->expr, e);
add_entity_use(c, rhs->expr, e);
break;
}
}
if (e != NULL) {
// HACK TODO(bill): Should the entities be freed as it's technically a leak
op_a->mode = Addressing_Value;
op_a->type = e->type;
op_a->overload_count = 0;
op_a->overload_entities = NULL;
rhs->mode = Addressing_Value;
rhs->type = e->type;
rhs->overload_count = 0;
rhs->overload_entities = NULL;
}
} else {
if (node->kind == AstNode_Ident) {
@@ -256,43 +251,60 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
e->flags |= EntityFlag_Used;
}
Type *assignment_type = op_b.type;
switch (op_b.mode) {
Type *assignment_type = lhs.type;
switch (lhs.mode) {
case Addressing_Invalid:
return NULL;
case Addressing_Variable:
case Addressing_MapIndex:
break;
case Addressing_MapIndex: {
AstNode *ln = unparen_expr(lhs_node);
if (ln->kind == AstNode_IndexExpr) {
AstNode *x = ln->IndexExpr.expr;
TypeAndValue *tav = type_and_value_of_expression(&c->info, x);
GB_ASSERT(tav != NULL);
if (tav->mode != Addressing_Variable) {
if (!is_type_pointer(tav->type)) {
gbString str = expr_to_string(lhs.expr);
error_node(lhs.expr, "Cannot assign to the value of a map `%s`", str);
gb_string_free(str);
return NULL;
}
}
}
} break;
default: {
if (op_b.expr->kind == AstNode_SelectorExpr) {
if (lhs.expr->kind == AstNode_SelectorExpr) {
// NOTE(bill): Extra error checks
Operand op_c = {Addressing_Invalid};
ast_node(se, SelectorExpr, op_b.expr);
ast_node(se, SelectorExpr, lhs.expr);
check_expr(c, &op_c, se->expr);
if (op_c.mode == Addressing_MapIndex) {
gbString str = expr_to_string(op_b.expr);
error_node(op_b.expr, "Cannot assign to record field `%s` in map", str);
gbString str = expr_to_string(lhs.expr);
error_node(lhs.expr, "Cannot assign to record field `%s` in map", str);
gb_string_free(str);
return NULL;
}
}
gbString str = expr_to_string(op_b.expr);
if (e != NULL && e->kind == Entity_Variable && e->Variable.is_immutable) {
error_node(op_b.expr, "Cannot assign to an immutable: `%s`", str);
gbString str = expr_to_string(lhs.expr);
if (lhs.mode == Addressing_Immutable) {
error_node(lhs.expr, "Cannot assign to an immutable: `%s`", str);
} else {
error_node(op_b.expr, "Cannot assign to `%s`", str);
error_node(lhs.expr, "Cannot assign to `%s`", str);
}
gb_string_free(str);
} break;
}
check_assignment(c, op_a, assignment_type, str_lit("assignment"));
if (op_a->mode == Addressing_Invalid) {
check_assignment(c, rhs, assignment_type, str_lit("assignment"));
if (rhs->mode == Addressing_Invalid) {
return NULL;
}
return op_a->type;
return rhs->type;
}
bool check_valid_type_match_type(Type *type, bool *is_union_ptr, bool *is_any) {
@@ -396,12 +408,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (operand.expr->kind == AstNode_CallExpr) {
return;
}
if (operand.expr->kind == AstNode_GiveExpr) {
if ((flags&Stmt_GiveAllowed) != 0) {
return;
}
error_node(node, "Illegal use of `give`");
}
gbString expr_str = expr_to_string(operand.expr);
error_node(node, "Expression is not used: `%s`", expr_str);
gb_string_free(expr_str);
@@ -419,40 +425,34 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
switch (as->op.kind) {
case Token_Eq: {
// a, b, c = 1, 2, 3; // Multisided
if (as->lhs.count == 0) {
isize lhs_count = as->lhs.count;
if (lhs_count == 0) {
error(as->op, "Missing lhs in assignment statement");
return;
}
// TODO(bill): This is a very similar to check_init_variables, should I merge the two some how or just
// leave it?
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation
Array(Operand) operands;
array_init_reserve(&operands, c->tmp_allocator, 2 * as->lhs.count);
ArrayOperand operands = {0};
array_init_reserve(&operands, c->tmp_allocator, 2 * lhs_count);
check_unpack_arguments(c, lhs_count, &operands, as->rhs, true);
for_array(i, as->rhs) {
AstNode *rhs = as->rhs.e[i];
Operand o = {0};
check_multi_expr(c, &o, rhs);
if (o.type->kind != Type_Tuple) {
array_add(&operands, o);
} else {
TypeTuple *tuple = &o.type->Tuple;
for (isize j = 0; j < tuple->variable_count; j++) {
o.type = tuple->variables[j]->type;
array_add(&operands, o);
}
isize rhs_count = operands.count;
for_array(i, operands) {
if (operands.e[i].mode == Addressing_Invalid) {
rhs_count--;
}
}
isize lhs_count = as->lhs.count;
isize rhs_count = operands.count;
isize operand_count = gb_min(as->lhs.count, operands.count);
for (isize i = 0; i < operand_count; i++) {
AstNode *lhs = as->lhs.e[i];
check_assignment_variable(c, &operands.e[i], lhs);
isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) {
check_assignment_variable(c, &operands.e[i], as->lhs.e[i]);
}
if (lhs_count != rhs_count) {
error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
@@ -1029,8 +1029,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (is_union_ptr) {
GB_ASSERT(is_type_union(bt));
bool tag_type_found = false;
for (isize i = 0; i < bt->Record.field_count; i++) {
Entity *f = bt->Record.fields[i];
for (isize i = 0; i < bt->Record.variant_count; i++) {
Entity *f = bt->Record.variants[i];
if (are_types_identical(f->type, y.type)) {
tag_type_found = true;
break;
@@ -1038,8 +1038,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
if (!tag_type_found) {
gbString type_str = type_to_string(y.type);
error_node(y.expr,
"Unknown tag type, got `%s`", type_str);
error_node(y.expr, "Unknown tag type, got `%s`", type_str);
gb_string_free(type_str);
continue;
}
@@ -1163,8 +1162,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case Entity_TypeName: {
Type *t = base_type(e->type);
if (is_type_union(t)) {
for (isize i = 0; i < t->Record.field_count; i++) {
Entity *f = t->Record.fields[i];
for (isize i = 0; i < t->Record.variant_count; i++) {
Entity *f = t->Record.variants[i];
Entity *found = scope_insert_entity(c->context.scope, f);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
+93 -70
View File
@@ -30,6 +30,7 @@ typedef enum BuiltinProcId {
BuiltinProc_reserve,
BuiltinProc_clear,
BuiltinProc_append,
BuiltinProc_delete,
BuiltinProc_size_of,
BuiltinProc_size_of_val,
@@ -73,6 +74,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
{STR_LIT("reserve"), 2, false, Expr_Stmt},
{STR_LIT("clear"), 1, false, Expr_Stmt},
{STR_LIT("append"), 1, true, Expr_Expr},
{STR_LIT("delete"), 2, false, Expr_Stmt},
{STR_LIT("size_of"), 1, false, Expr_Expr},
{STR_LIT("size_of_val"), 1, false, Expr_Expr},
@@ -106,29 +108,29 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
};
typedef enum AddressingMode {
Addressing_Invalid,
Addressing_NoValue,
Addressing_Value,
Addressing_Variable,
Addressing_Constant,
Addressing_Type,
Addressing_Builtin,
Addressing_Overload,
Addressing_MapIndex,
Addressing_Count,
} AddressingMode;
#include "types.c"
#define MAP_TYPE Entity *
#define MAP_PROC map_entity_
#define MAP_NAME MapEntity
#include "map.c"
typedef enum AddressingMode {
Addressing_Invalid, // invalid addressing mode
Addressing_NoValue, // no value (void in C)
Addressing_Value, // computed value (rvalue)
Addressing_Immutable, // immutable computed value (const rvalue)
Addressing_Variable, // addressable variable (lvalue)
Addressing_Constant, // constant & type will be a of Type_Basic (stripping Type_Named)
Addressing_Type, // type
Addressing_Builtin, // built in procedure
Addressing_Overload, // overloaded procedure
Addressing_MapIndex, // map index expression -
// lhs: acts like a Variable
// rhs: acts like OptionalOk
Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
} AddressingMode;
// Operand is used as an intermediate value whilst checking
// Operands store an addressing mode, the expression being evaluated,
// its type and node, and other specific information for certain
// addressing modes
// Its zero-value is a valid "invalid operand"
typedef struct Operand {
AddressingMode mode;
Type * type;
@@ -149,7 +151,9 @@ bool is_operand_value(Operand o) {
switch (o.mode) {
case Addressing_Value:
case Addressing_Variable:
case Addressing_Immutable:
case Addressing_Constant:
case Addressing_MapIndex:
return true;
}
return false;
@@ -159,7 +163,7 @@ bool is_operand_nil(Operand o) {
}
// DeclInfo is used to store information of certain declarations to allow for "any order" usage
typedef struct DeclInfo {
Scope *scope;
@@ -173,6 +177,17 @@ typedef struct DeclInfo {
MapBool deps; // Key: Entity *
} DeclInfo;
// ProcedureInfo stores the information needed for checking a procedure
typedef struct ProcedureInfo {
AstFile * file;
Token token;
DeclInfo *decl;
Type * type; // Type_Procedure
AstNode * body; // AstNode_BlockStmt
u32 tags;
} ProcedureInfo;
// ExprInfo stores information used for "untyped" expressions
typedef struct ExprInfo {
bool is_lhs; // Debug info
AddressingMode mode;
@@ -185,14 +200,12 @@ ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue
return ei;
}
typedef struct ProcedureInfo {
AstFile * file;
Token token;
DeclInfo *decl;
Type * type; // Type_Procedure
AstNode * body; // AstNode_BlockStmt
u32 tags;
} ProcedureInfo;
#define MAP_TYPE Entity *
#define MAP_PROC map_entity_
#define MAP_NAME MapEntity
#include "map.c"
typedef struct Scope {
Scope * parent;
@@ -248,6 +261,7 @@ typedef struct DelayedDecl {
} DelayedDecl;
typedef struct CheckerContext {
Scope * file_scope;
Scope * scope;
DeclInfo * decl;
u32 stmt_state_flags;
@@ -256,7 +270,7 @@ typedef struct CheckerContext {
Type * type_hint;
} CheckerContext;
// NOTE(bill): Symbol tables
// CheckerInfo stores all the symbol information for a type-checked program
typedef struct CheckerInfo {
MapTypeAndValue types; // Key: AstNode * | Expression -> Type (and value)
MapEntity definitions; // Key: AstNode * | Identifier -> Entity
@@ -264,7 +278,7 @@ typedef struct CheckerInfo {
MapScope scopes; // Key: AstNode * | Node -> Scope
MapExprInfo untyped; // Key: AstNode * | Expression -> ExprInfo
MapDeclInfo entities; // Key: Entity *
MapEntity foreign_procs; // Key: String
MapEntity foreigns; // Key: String
MapAstFile files; // Key: String (full path)
MapIsize type_info_map; // Key: Type *
isize type_info_count;
@@ -275,13 +289,11 @@ typedef struct Checker {
CheckerInfo info;
AstFile * curr_ast_file;
BaseTypeSizes sizes;
Scope * global_scope;
Array(ProcedureInfo) procs; // NOTE(bill): Procedures to check
Array(DelayedDecl) delayed_imports;
Array(DelayedDecl) delayed_foreign_libraries;
gbArena arena;
gbArena tmp_arena;
gbAllocator allocator;
@@ -391,9 +403,7 @@ void check_open_scope(Checker *c, AstNode *node) {
node = unparen_expr(node);
GB_ASSERT(node->kind == AstNode_Invalid ||
is_ast_node_stmt(node) ||
is_ast_node_type(node) ||
node->kind == AstNode_BlockExpr ||
node->kind == AstNode_IfExpr );
is_ast_node_type(node));
Scope *scope = make_scope(c->context.scope, c->allocator);
add_scope(c, node, scope);
if (node->kind == AstNode_ProcType) {
@@ -591,7 +601,8 @@ void add_global_string_constant(gbAllocator a, String name, String value) {
}
void init_universal_scope(BuildContext *bc) {
void init_universal_scope(void) {
BuildContext *bc = &build_context;
// NOTE(bill): No need to free these
gbAllocator a = heap_allocator();
universal_scope = make_scope(NULL, a);
@@ -650,7 +661,7 @@ void init_checker_info(CheckerInfo *i) {
map_scope_init(&i->scopes, a);
map_decl_info_init(&i->entities, a);
map_expr_info_init(&i->untyped, a);
map_entity_init(&i->foreign_procs, a);
map_entity_init(&i->foreigns, a);
map_isize_init(&i->type_info_map, a);
map_ast_file_init(&i->files, a);
i->type_info_count = 0;
@@ -664,7 +675,7 @@ void destroy_checker_info(CheckerInfo *i) {
map_scope_destroy(&i->scopes);
map_decl_info_destroy(&i->entities);
map_expr_info_destroy(&i->untyped);
map_entity_destroy(&i->foreign_procs);
map_entity_destroy(&i->foreigns);
map_isize_destroy(&i->type_info_map);
map_ast_file_destroy(&i->files);
}
@@ -675,8 +686,6 @@ void init_checker(Checker *c, Parser *parser, BuildContext *bc) {
c->parser = parser;
init_checker_info(&c->info);
c->sizes.word_size = bc->word_size;
c->sizes.max_align = bc->max_align;
array_init(&c->proc_stack, a);
array_init(&c->procs, a);
@@ -945,6 +954,10 @@ void add_type_info_type(Checker *c, Type *t) {
break;
case TypeRecord_Union:
add_type_info_type(c, t_int);
for (isize i = 0; i < bt->Record.variant_count; i++) {
Entity *f = bt->Record.variants[i];
add_type_info_type(c, f->type);
}
/* fallthrough */
default:
for (isize i = 0; i < bt->Record.field_count; i++) {
@@ -1010,6 +1023,7 @@ void add_curr_ast_file(Checker *c, AstFile *file) {
c->curr_ast_file = file;
c->context.decl = file->decl_info;
c->context.scope = file->scope;
c->context.file_scope = file->scope;
}
}
@@ -1079,44 +1093,41 @@ void init_preload(Checker *c) {
}
if (t_type_info == NULL) {
Entity *type_info_entity = find_core_entity(c, str_lit("Type_Info"));
Entity *type_info_member_entity = find_core_entity(c, str_lit("Type_Info_Member"));
Entity *type_info_enum_value_entity = find_core_entity(c, str_lit("Type_Info_Enum_Value"));
Entity *type_info_entity = find_core_entity(c, str_lit("Type_Info"));
t_type_info = type_info_entity->type;
t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
GB_ASSERT(is_type_union(type_info_entity->type));
TypeRecord *record = &base_type(type_info_entity->type)->Record;
t_type_info_member = type_info_member_entity->type;
t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member);
t_type_info_enum_value = type_info_enum_value_entity->type;
t_type_info_record = find_core_entity(c, str_lit("Type_Info_Record"))->type;
t_type_info_record_ptr = make_type_pointer(c->allocator, t_type_info_record);
t_type_info_enum_value = find_core_entity(c, str_lit("Type_Info_Enum_Value"))->type;
t_type_info_enum_value_ptr = make_type_pointer(c->allocator, t_type_info_enum_value);
if (record->field_count != 19) {
if (record->variant_count != 19) {
compiler_error("Invalid `Type_Info` layout");
}
t_type_info_named = record->fields[ 1]->type;
t_type_info_integer = record->fields[ 2]->type;
t_type_info_float = record->fields[ 3]->type;
t_type_info_string = record->fields[ 4]->type;
t_type_info_boolean = record->fields[ 5]->type;
t_type_info_any = record->fields[ 6]->type;
t_type_info_pointer = record->fields[ 7]->type;
t_type_info_procedure = record->fields[ 8]->type;
t_type_info_array = record->fields[ 9]->type;
t_type_info_dynamic_array = record->fields[10]->type;
t_type_info_slice = record->fields[11]->type;
t_type_info_vector = record->fields[12]->type;
t_type_info_tuple = record->fields[13]->type;
t_type_info_struct = record->fields[14]->type;
t_type_info_union = record->fields[15]->type;
t_type_info_raw_union = record->fields[16]->type;
t_type_info_enum = record->fields[17]->type;
t_type_info_map = record->fields[18]->type;
t_type_info_named = record->variants[ 1]->type;
t_type_info_integer = record->variants[ 2]->type;
t_type_info_float = record->variants[ 3]->type;
t_type_info_string = record->variants[ 4]->type;
t_type_info_boolean = record->variants[ 5]->type;
t_type_info_any = record->variants[ 6]->type;
t_type_info_pointer = record->variants[ 7]->type;
t_type_info_procedure = record->variants[ 8]->type;
t_type_info_array = record->variants[ 9]->type;
t_type_info_dynamic_array = record->variants[10]->type;
t_type_info_slice = record->variants[11]->type;
t_type_info_vector = record->variants[12]->type;
t_type_info_tuple = record->variants[13]->type;
t_type_info_struct = record->variants[14]->type;
t_type_info_raw_union = record->variants[15]->type;
t_type_info_union = record->variants[16]->type;
t_type_info_enum = record->variants[17]->type;
t_type_info_map = record->variants[18]->type;
t_type_info_named_ptr = make_type_pointer(c->allocator, t_type_info_named);
t_type_info_integer_ptr = make_type_pointer(c->allocator, t_type_info_integer);
@@ -1132,8 +1143,8 @@ void init_preload(Checker *c) {
t_type_info_vector_ptr = make_type_pointer(c->allocator, t_type_info_vector);
t_type_info_tuple_ptr = make_type_pointer(c->allocator, t_type_info_tuple);
t_type_info_struct_ptr = make_type_pointer(c->allocator, t_type_info_struct);
t_type_info_union_ptr = make_type_pointer(c->allocator, t_type_info_union);
t_type_info_raw_union_ptr = make_type_pointer(c->allocator, t_type_info_raw_union);
t_type_info_union_ptr = make_type_pointer(c->allocator, t_type_info_union);
t_type_info_enum_ptr = make_type_pointer(c->allocator, t_type_info_enum);
t_type_info_map_ptr = make_type_pointer(c->allocator, t_type_info_map);
}
@@ -1239,6 +1250,9 @@ void check_procedure_overloading(Checker *c, Entity *e) {
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
switch (kind) {
case ProcOverload_Identical:
error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name));
is_invalid = true;
break;
case ProcOverload_CallingConvention:
error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name));
is_invalid = true;
@@ -1387,8 +1401,14 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
di->entities = entities;
di->type_expr = vd->type;
di->init_expr = vd->values.e[0];
if (vd->flags & VarDeclFlag_thread_local) {
error_node(decl, "#thread_local variable declarations cannot have initialization values");
}
}
for_array(i, vd->names) {
AstNode *name = vd->names.e[i];
AstNode *value = NULL;
@@ -1400,8 +1420,9 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
continue;
}
Entity *e = make_entity_variable(c->allocator, c->context.scope, name->Ident, NULL, vd->flags & VarDeclFlag_immutable);
e->Variable.is_thread_local = vd->flags & VarDeclFlag_thread_local;
e->Variable.is_thread_local = (vd->flags & VarDeclFlag_thread_local) != 0;
e->identifier = name;
if (vd->flags & VarDeclFlag_using) {
vd->flags &= ~VarDeclFlag_using; // NOTE(bill): This error will be only caught once
error_node(name, "`using` is not allowed at the file scope");
@@ -1723,6 +1744,8 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid,
id->fullpath, id->import_name.string,
scope);
add_entity(c, parent_scope, NULL, e);
}
}
@@ -1886,7 +1909,7 @@ void check_parsed_files(Checker *c) {
if (e->kind == Entity_TypeName) {
if (e->type != NULL) {
// i64 size = type_size_of(c->sizes, c->allocator, e->type);
i64 align = type_align_of(c->sizes, c->allocator, e->type);
i64 align = type_align_of(c->allocator, e->type);
}
}
}
+3
View File
@@ -131,6 +131,9 @@ i16 f32_to_f16(f32 value) {
//
////////////////////////////////////////////////////////////////
typedef Array(i32) Array_i32;
typedef Array(isize) Array_isize;
#define MAP_TYPE String
#define MAP_PROC map_string_
+7 -3
View File
@@ -40,12 +40,15 @@ typedef enum EntityFlag {
EntityFlag_TypeField = 1<<8,
} EntityFlag;
// Zero value means the overloading process is not yet done
typedef enum OverloadKind {
Overload_No = -1,
Overload_Unknown = 0,
Overload_Yes = +1,
Overload_Unknown,
Overload_No,
Overload_Yes,
} OverloadKind;
// An Entity is a named "thing" in the language
typedef struct Entity Entity;
struct Entity {
EntityKind kind;
@@ -110,6 +113,7 @@ bool is_entity_kind_exported(EntityKind kind) {
}
bool is_entity_exported(Entity *e) {
// TODO(bill): Determine the actual exportation rules for imports of entities
GB_ASSERT(e != NULL);
if (!is_entity_kind_exported(e->kind)) {
return false;
+1 -1
View File
@@ -705,7 +705,7 @@ extern "C++" {
#endif
#ifndef gb_is_between
#define gb_is_between(x, lower, upper) (((x) >= (lower)) && ((x) <= (upper)))
#define gb_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
#endif
#ifndef gb_abs
+688 -458
View File
File diff suppressed because it is too large Load Diff
+74 -33
View File
@@ -137,8 +137,7 @@ void ir_print_encoded_global(irFileBuffer *f, String name, bool remove_prefix) {
void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
BaseTypeSizes s = m->sizes;
i64 word_bits = 8*s.word_size;
i64 word_bits = 8*build_context.word_size;
GB_ASSERT_NOT_NULL(t);
t = default_type(t);
GB_ASSERT(is_type_typed(t));
@@ -178,7 +177,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
ir_fprintf(f, "]");
return;
case Type_Vector: {
i64 align = type_align_of(s, heap_allocator(), t);
i64 align = type_align_of(heap_allocator(), t);
i64 count = t->Vector.count;
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x ", align, count);
ir_print_type(f, m, t->Vector.elem);
@@ -192,11 +191,11 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
case Type_Slice:
ir_fprintf(f, "{");
ir_print_type(f, m, t->Slice.elem);
ir_fprintf(f, "*, i%lld, i%lld}", word_bits, word_bits);
ir_fprintf(f, "*, i%lld}", word_bits);
return;
case Type_DynamicArray:
ir_fprintf(f, "{");
ir_print_type(f, m, t->Slice.elem);
ir_print_type(f, m, t->DynamicArray.elem);
ir_fprintf(f, "*, i%lld, i%lld,", word_bits, word_bits);
ir_print_type(f, m, t_allocator);
ir_fprintf(f, "}");
@@ -204,7 +203,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
case Type_Record: {
switch (t->Record.kind) {
case TypeRecord_Struct:
if (t->Record.struct_is_packed) {
if (t->Record.is_packed) {
ir_fprintf(f, "<");
}
ir_fprintf(f, "{");
@@ -221,22 +220,22 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
ir_print_type(f, m, t->Record.fields[i]->type);
}
ir_fprintf(f, "}");
if (t->Record.struct_is_packed) {
if (t->Record.is_packed) {
ir_fprintf(f, ">");
}
return;
case TypeRecord_Union: {
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
// LLVM takes the first element's alignment as the entire alignment (like C)
i64 size_of_union = type_size_of(s, heap_allocator(), t) - s.word_size;
i64 align_of_union = type_align_of(s, heap_allocator(), t);
i64 size_of_union = type_size_of(heap_allocator(), t) - build_context.word_size;
i64 align_of_union = type_align_of(heap_allocator(), t);
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align_of_union, size_of_union, word_bits);
} return;
case TypeRecord_RawUnion: {
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
// LLVM takes the first element's alignment as the entire alignment (like C)
i64 size_of_union = type_size_of(s, heap_allocator(), t);
i64 align_of_union = type_align_of(s, heap_allocator(), t);
i64 size_of_union = type_size_of(heap_allocator(), t);
i64 align_of_union = type_align_of(heap_allocator(), t);
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
} return;
case TypeRecord_Enum:
@@ -455,7 +454,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
break;
}
i64 align = type_align_of(m->sizes, m->allocator, type);
i64 align = type_align_of(m->allocator, type);
i64 count = type->Vector.count;
Type *elem_type = type->Vector.elem;
@@ -527,7 +526,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
if (type->Record.struct_is_packed) {
if (type->Record.is_packed) {
ir_fprintf(f, "<");
}
ir_fprintf(f, "{");
@@ -544,7 +543,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_fprintf(f, "}");
if (type->Record.struct_is_packed) {
if (type->Record.is_packed) {
ir_fprintf(f, ">");
}
@@ -617,8 +616,6 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
ir_print_type(f, m, t_int);
ir_fprintf(f, " 0, i32 0), ");
ir_print_type(f, m, t_int);
ir_fprintf(f, " %lld, ", cs->count);
ir_print_type(f, m, t_int);
ir_fprintf(f, " %lld}", cs->count);
}
} break;
@@ -681,7 +678,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
Type *type = instr->Local.entity->type;
ir_fprintf(f, "%%%d = alloca ", value->index);
ir_print_type(f, m, type);
ir_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type));
ir_fprintf(f, ", align %lld\n", type_align_of(m->allocator, type));
} break;
case irInstr_ZeroInit: {
@@ -714,7 +711,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_print_type(f, m, type);
ir_fprintf(f, "* ");
ir_print_value(f, m, instr->Load.address, type);
ir_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type));
ir_fprintf(f, ", align %lld\n", type_align_of(m->allocator, type));
} break;
case irInstr_ArrayElementPtr: {
@@ -842,6 +839,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, " 0, ");
ir_print_type(f, m, t_i32);
ir_fprintf(f, " %d", 2);
ir_fprintf(f, " ; UnionTagPtr");
ir_fprintf(f, "\n");
} break;
@@ -852,7 +850,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_print_type(f, m, et);
ir_fprintf(f, " ");
ir_print_value(f, m, instr->UnionTagValue.address, et);
ir_fprintf(f, ", %d\n", 2);
ir_fprintf(f, ", %d", 2);
ir_fprintf(f, " ; UnionTagValue");
ir_fprintf(f, "\n");
} break;
case irInstr_Jump: {;
@@ -1252,6 +1252,29 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, ")\n");
} break;
case irInstr_DebugDeclare: {
/* irInstrDebugDeclare *dd = &instr->DebugDeclare;
Type *vt = ir_type(dd->value);
irDebugInfo *di = dd->debug_info;
Entity *e = dd->entity;
String name = e->token.string;
TokenPos pos = e->token.pos;
// gb_printf("debug_declare %.*s\n", LIT(dd->entity->token.string));
ir_fprintf(f, "call void @llvm.dbg.declare(");
ir_fprintf(f, "metadata ");
ir_print_type(f, m, vt);
ir_fprintf(f, " ");
ir_print_value(f, m, dd->value, vt);
ir_fprintf(f, ", metadata !DILocalVariable(name: \"");
ir_print_escape_string(f, name, false);
ir_fprintf(f, "\", scope: !%d, line: %td)", di->id, pos.line);
ir_fprintf(f, ", metadata !DIExpression()");
ir_fprintf(f, ")");
ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, di->id);
ir_fprintf(f, "\n"); */
} break;
default: {
GB_PANIC("<unknown instr> %d\n", instr->kind);
@@ -1270,7 +1293,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
} else {
ir_fprintf(f, "\n");
ir_fprintf(f, "define ");
if (m->build_context->is_dll) {
if (build_context.is_dll) {
// if (proc->tags & (ProcTag_export|ProcTag_dll_export)) {
if (proc->tags & (ProcTag_export)) {
ir_fprintf(f, "dllexport ");
@@ -1324,11 +1347,14 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
}
if (proc->module->generate_debug_info && proc->entity != NULL) {
if (proc->entity != NULL) {
if (proc->body != NULL) {
irDebugInfo *di = *map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
GB_ASSERT(di->kind == irDebugInfo_Proc);
ir_fprintf(f, "!dbg !%d ", di->id);
irDebugInfo **di_ = map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
if (di_ != NULL) {
irDebugInfo *di = *di_;
GB_ASSERT(di->kind == irDebugInfo_Proc);
// ir_fprintf(f, "!dbg !%d ", di->id);
}
}
}
@@ -1394,6 +1420,8 @@ void print_llvm_ir(irGen *ir) {
ir_print_type(f, m, t_rawptr);
ir_fprintf(f, "} ; Basic_any\n");
ir_fprintf(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone \n");
for_array(member_index, m->members.entries) {
MapIrValueEntry *entry = &m->members.entries.e[member_index];
@@ -1446,6 +1474,9 @@ void print_llvm_ir(irGen *ir) {
}
ir_print_encoded_global(f, g->entity->token.string, in_global_scope);
ir_fprintf(f, " = ");
if (g->is_foreign) {
ir_fprintf(f, "external ");
}
if (g->is_thread_local) {
ir_fprintf(f, "thread_local ");
}
@@ -1465,19 +1496,30 @@ void print_llvm_ir(irGen *ir) {
ir_print_type(f, m, g->entity->type);
ir_fprintf(f, " ");
if (g->value != NULL) {
ir_print_value(f, m, g->value, g->entity->type);
} else {
ir_fprintf(f, "zeroinitializer");
if (!g->is_foreign) {
if (g->value != NULL) {
ir_print_value(f, m, g->value, g->entity->type);
} else {
ir_fprintf(f, "zeroinitializer");
}
}
ir_fprintf(f, "\n");
}
#if 0
if (m->generate_debug_info) {
// if (m->generate_debug_info) {
{
ir_fprintf(f, "\n");
i32 diec = m->debug_info.entries.count;
ir_fprintf(f, "!llvm.dbg.cu = !{!0}\n");
ir_fprintf(f, "!llvm.ident = !{!%d}\n", diec+3);
ir_fprintf(f, "!%d = !{i32 2, !\"Dwarf Version\", i32 4}\n", diec+0);
ir_fprintf(f, "!%d = !{i32 2, !\"Debug Info Version\", i32 3}\n", diec+1);
ir_fprintf(f, "!%d = !{i32 1, !\"PIC Level\", i32 2}\n", diec+2);
ir_fprintf(f, "!%d = !{!\"clang version 3.9.0 (branches/release_39)\"}\n", diec+3);
for_array(di_index, m->debug_info.entries) {
MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[di_index];
@@ -1486,19 +1528,18 @@ void print_llvm_ir(irGen *ir) {
switch (di->kind) {
case irDebugInfo_CompileUnit: {
auto *cu = &di->CompileUnit;
irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(cu->file));
irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
ir_fprintf(f,
"distinct !DICompileUnit("
"language: DW_LANG_Go, " // Is this good enough?
"file: !%d, "
"producer: \"%.*s\", "
"producer: \"clang version 3.9.0 (branches/release_39)\", "
"flags: \"\", "
"runtimeVersion: 0, "
"isOptimized: false, "
"emissionKind: FullDebug"
")",
file->id, LIT(cu->producer));
file->id);
} break;
case irDebugInfo_File:
+9 -9
View File
@@ -2,9 +2,10 @@
extern "C" {
#endif
#include "common.c"
#include "timings.c"
#include "build.c"
#include "build_settings.c"
#include "tokenizer.c"
#include "parser.c"
// #include "printer.c"
@@ -145,10 +146,9 @@ int main(int argc, char **argv) {
#if 1
BuildContext build_context = {0};
init_build_context(&build_context);
init_build_context();
init_universal_scope(&build_context);
init_universal_scope();
char *init_filename = NULL;
bool run_output = false;
@@ -217,12 +217,12 @@ int main(int argc, char **argv) {
return 1;
}
ssa_generate(&checker.info, &build_context);
#endif
#if 1
if (!ssa_generate(&checker.info)) {
return 1;
}
#else
irGen ir_gen = {0};
if (!ir_gen_init(&ir_gen, &checker, &build_context)) {
if (!ir_gen_init(&ir_gen, &checker)) {
return 1;
}
// defer (ssa_gen_destroy(&ir_gen));
+3
View File
@@ -6,6 +6,9 @@
#define MAP_NAME MapString
#include "map.c"
*/
// A `Map` is an unordered hash table which can allow for a key to point to multiple values
// with the use of the `multi_*` procedures.
// TODO(bill): I should probably allow the `multi_*` stuff to be #ifdefed out
#ifndef MAP_UTIL_STUFF
#define MAP_UTIL_STUFF
+282 -284
View File
@@ -84,9 +84,9 @@ typedef enum ProcCallingConvention {
} ProcCallingConvention;
typedef enum VarDeclFlag {
VarDeclFlag_thread_local = 1<<0,
VarDeclFlag_using = 1<<1,
VarDeclFlag_immutable = 1<<2,
VarDeclFlag_using = 1<<0,
VarDeclFlag_immutable = 1<<1,
VarDeclFlag_thread_local = 1<<2,
} VarDeclFlag;
typedef enum StmtStateFlag {
@@ -111,7 +111,9 @@ AstNodeArray make_ast_node_array(AstFile *f) {
}
// NOTE(bill): This massive define is so it is possible to create a discriminated union (and extra debug info)
// for the AstNode. I personally prefer discriminated unions over subtype polymorphism as I can preallocate
// all the nodes and even memcpy in a different kind of node
#define AST_NODE_KINDS \
AST_NODE_KIND(Ident, "identifier", Token) \
AST_NODE_KIND(Implicit, "implicit", Token) \
@@ -166,24 +168,9 @@ AST_NODE_KIND(_ExprBegin, "", i32) \
Token open; \
Token close; \
}) \
AST_NODE_KIND(CastExpr, "cast expression", struct { Token token; AstNode *type, *expr; Token open, close; }) \
AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
AST_NODE_KIND(BlockExpr, "block expr", struct { \
AstNodeArray stmts; \
Token open, close; \
AstNode *give_node; \
}) \
AST_NODE_KIND(GiveExpr, "give expression", struct { \
Token token; \
AstNodeArray results; \
}) \
AST_NODE_KIND(IfExpr, "if expression", struct { \
Token token; \
AstNode *init; \
AstNode *cond; \
AstNode *body; \
AstNode *else_expr; \
}) \
AST_NODE_KIND(CastExpr, "cast expression", struct { Token token; AstNode *type, *expr; Token open, close; }) \
AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
AST_NODE_KIND(TernaryExpr, "ternary expression", struct { AstNode *cond, *x, *y; }) \
AST_NODE_KIND(IntervalExpr, "interval expression", struct { Token op; AstNode *left, *right; }) \
AST_NODE_KIND(_ExprEnd, "", i32) \
AST_NODE_KIND(_StmtBegin, "", i32) \
@@ -315,16 +302,24 @@ AST_NODE_KIND(_DeclEnd, "", i32) \
AstNode * type; \
u32 flags; \
}) \
AST_NODE_KIND(FieldList, "field list", struct { \
Token token; \
AstNodeArray list; \
}) \
AST_NODE_KIND(UnionField, "union field", struct { \
AstNode *name; \
AstNode *list; \
}) \
AST_NODE_KIND(_TypeBegin, "", i32) \
AST_NODE_KIND(HelperType, "type", struct { \
Token token; \
AstNode *type; \
}) \
AST_NODE_KIND(ProcType, "procedure type", struct { \
Token token; \
AstNodeArray params; \
AstNodeArray results; \
u64 tags; \
Token token; \
AstNode *params; \
AstNode *results; \
u64 tags; \
ProcCallingConvention calling_convention; \
}) \
AST_NODE_KIND(PointerType, "pointer type", struct { \
@@ -354,9 +349,10 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
AstNode *align; \
}) \
AST_NODE_KIND(UnionType, "union type", struct { \
Token token; \
Token token; \
AstNodeArray fields; \
isize field_count; \
isize field_count; \
AstNodeArray variants; \
}) \
AST_NODE_KIND(RawUnionType, "raw union type", struct { \
Token token; \
@@ -463,9 +459,7 @@ Token ast_node_token(AstNode *node) {
case AstNode_CastExpr: return node->CastExpr.token;
case AstNode_FieldValue: return node->FieldValue.eq;
case AstNode_DerefExpr: return node->DerefExpr.op;
case AstNode_BlockExpr: return node->BlockExpr.open;
case AstNode_GiveExpr: return node->GiveExpr.token;
case AstNode_IfExpr: return node->IfExpr.token;
case AstNode_TernaryExpr: return ast_node_token(node->TernaryExpr.cond);
case AstNode_IntervalExpr: return ast_node_token(node->IntervalExpr.left);
case AstNode_BadStmt: return node->BadStmt.begin;
@@ -494,14 +488,15 @@ Token ast_node_token(AstNode *node) {
case AstNode_ForeignLibrary: return node->ForeignLibrary.token;
case AstNode_Field: {
case AstNode_Field:
if (node->Field.names.count > 0) {
return ast_node_token(node->Field.names.e[0]);
} else {
return ast_node_token(node->Field.type);
}
}
return ast_node_token(node->Field.type);
case AstNode_FieldList:
return node->FieldList.token;
case AstNode_UnionField:
return ast_node_token(node->UnionField.name);
case AstNode_HelperType: return node->HelperType.token;
case AstNode_ProcType: return node->ProcType.token;
@@ -770,29 +765,11 @@ AstNode *ast_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token o
return result;
}
AstNode *ast_block_expr(AstFile *f, AstNodeArray stmts, Token open, Token close) {
AstNode *result = make_ast_node(f, AstNode_BlockExpr);
result->BlockExpr.stmts = stmts;
result->BlockExpr.open = open;
result->BlockExpr.close = close;
return result;
}
AstNode *ast_give_expr(AstFile *f, Token token, AstNodeArray results) {
AstNode *result = make_ast_node(f, AstNode_GiveExpr);
result->GiveExpr.token = token;
result->GiveExpr.results = results;
return result;
}
AstNode *ast_if_expr(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *body, AstNode *else_expr) {
AstNode *result = make_ast_node(f, AstNode_IfExpr);
result->IfExpr.token = token;
result->IfExpr.init = init;
result->IfExpr.cond = cond;
result->IfExpr.body = body;
result->IfExpr.else_expr = else_expr;
AstNode *ast_ternary_expr(AstFile *f, AstNode *cond, AstNode *x, AstNode *y) {
AstNode *result = make_ast_node(f, AstNode_TernaryExpr);
result->TernaryExpr.cond = cond;
result->TernaryExpr.x = x;
result->TernaryExpr.y = y;
return result;
}
@@ -989,6 +966,19 @@ AstNode *ast_field(AstFile *f, AstNodeArray names, AstNode *type, u32 flags) {
return result;
}
AstNode *ast_field_list(AstFile *f, Token token, AstNodeArray list) {
AstNode *result = make_ast_node(f, AstNode_FieldList);
result->FieldList.token = token;
result->FieldList.list = list;
return result;
}
AstNode *ast_union_field(AstFile *f, AstNode *name, AstNode *list) {
AstNode *result = make_ast_node(f, AstNode_UnionField);
result->UnionField.name = name;
result->UnionField.list = list;
return result;
}
AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) {
AstNode *result = make_ast_node(f, AstNode_HelperType);
@@ -998,7 +988,7 @@ AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) {
}
AstNode *ast_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags, ProcCallingConvention calling_convention) {
AstNode *ast_proc_type(AstFile *f, Token token, AstNode *params, AstNode *results, u64 tags, ProcCallingConvention calling_convention) {
AstNode *result = make_ast_node(f, AstNode_ProcType);
result->ProcType.token = token;
result->ProcType.params = params;
@@ -1039,7 +1029,7 @@ AstNode *ast_vector_type(AstFile *f, Token token, AstNode *count, AstNode *elem)
}
AstNode *ast_struct_type(AstFile *f, Token token, AstNodeArray fields, isize field_count,
bool is_packed, bool is_ordered, AstNode *align) {
bool is_packed, bool is_ordered, AstNode *align) {
AstNode *result = make_ast_node(f, AstNode_StructType);
result->StructType.token = token;
result->StructType.fields = fields;
@@ -1051,11 +1041,12 @@ AstNode *ast_struct_type(AstFile *f, Token token, AstNodeArray fields, isize fie
}
AstNode *ast_union_type(AstFile *f, Token token, AstNodeArray fields, isize field_count) {
AstNode *ast_union_type(AstFile *f, Token token, AstNodeArray fields, isize field_count, AstNodeArray variants) {
AstNode *result = make_ast_node(f, AstNode_UnionType);
result->UnionType.token = token;
result->UnionType.fields = fields;
result->UnionType.field_count = field_count;
result->UnionType.variants = variants;
return result;
}
@@ -1323,13 +1314,13 @@ void expect_semicolon(AstFile *f, AstNode *s) {
return;
}
} else {
switch (s->kind) {
case AstNode_GiveExpr:
if (f->curr_token.kind == Token_CloseBrace) {
return;
}
break;
}
// switch (s->kind) {
// case AstNode_GiveExpr:
// if (f->curr_token.kind == Token_CloseBrace) {
// return;
// }
// break;
// }
}
syntax_error(prev_token, "Expected `;` after %.*s, got %.*s",
LIT(ast_node_strings[s->kind]), LIT(token_strings[prev_token.kind]));
@@ -1345,7 +1336,6 @@ AstNode * parse_proc_type(AstFile *f, AstNode **foreign_library, String *fore
AstNodeArray parse_stmt_list(AstFile *f);
AstNode * parse_stmt(AstFile *f);
AstNode * parse_body(AstFile *f);
void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results);
@@ -1614,72 +1604,72 @@ AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) {
AstNode *parse_block_expr(AstFile *f) {
AstNodeArray stmts = {0};
Token open, close;
open = expect_token(f, Token_OpenBrace);
f->expr_level++;
stmts = parse_stmt_list(f);
f->expr_level--;
close = expect_token(f, Token_CloseBrace);
return ast_block_expr(f, stmts, open, close);
}
// AstNode *parse_block_expr(AstFile *f) {
// AstNodeArray stmts = {0};
// Token open, close;
// open = expect_token(f, Token_OpenBrace);
// f->expr_level++;
// stmts = parse_stmt_list(f);
// f->expr_level--;
// close = expect_token(f, Token_CloseBrace);
// return ast_block_expr(f, stmts, open, close);
// }
AstNode *parse_if_expr(AstFile *f) {
if (f->curr_proc == NULL) {
syntax_error(f->curr_token, "You cannot use an if expression in the file scope");
return ast_bad_stmt(f, f->curr_token, f->curr_token);
}
// AstNode *parse_if_expr(AstFile *f) {
// if (f->curr_proc == NULL) {
// syntax_error(f->curr_token, "You cannot use an if expression in the file scope");
// return ast_bad_stmt(f, f->curr_token, f->curr_token);
// }
Token token = expect_token(f, Token_if);
AstNode *init = NULL;
AstNode *cond = NULL;
AstNode *body = NULL;
AstNode *else_expr = NULL;
// Token token = expect_token(f, Token_if);
// AstNode *init = NULL;
// AstNode *cond = NULL;
// AstNode *body = NULL;
// AstNode *else_expr = NULL;
isize prev_level = f->expr_level;
f->expr_level = -1;
// isize prev_level = f->expr_level;
// f->expr_level = -1;
if (allow_token(f, Token_Semicolon)) {
cond = parse_expr(f, false);
} else {
init = parse_simple_stmt(f, false);
if (allow_token(f, Token_Semicolon)) {
cond = parse_expr(f, false);
} else {
cond = convert_stmt_to_expr(f, init, str_lit("boolean expression"));
init = NULL;
}
}
// if (allow_token(f, Token_Semicolon)) {
// cond = parse_expr(f, false);
// } else {
// init = parse_simple_stmt(f, false);
// if (allow_token(f, Token_Semicolon)) {
// cond = parse_expr(f, false);
// } else {
// cond = convert_stmt_to_expr(f, init, str_lit("boolean expression"));
// init = NULL;
// }
// }
f->expr_level = prev_level;
// f->expr_level = prev_level;
if (cond == NULL) {
syntax_error(f->curr_token, "Expected condition for if statement");
}
// if (cond == NULL) {
// syntax_error(f->curr_token, "Expected condition for if statement");
// }
body = parse_block_expr(f);
// body = parse_block_expr(f);
if (allow_token(f, Token_else)) {
switch (f->curr_token.kind) {
case Token_if:
else_expr = parse_if_expr(f);
break;
case Token_OpenBrace:
else_expr = parse_block_expr(f);
break;
default:
syntax_error(f->curr_token, "Expected if expression block statement");
else_expr = ast_bad_expr(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
break;
}
} else {
syntax_error(f->curr_token, "An if expression must have an else clause");
return ast_bad_stmt(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
}
// if (allow_token(f, Token_else)) {
// switch (f->curr_token.kind) {
// case Token_if:
// else_expr = parse_if_expr(f);
// break;
// case Token_OpenBrace:
// else_expr = parse_block_expr(f);
// break;
// default:
// syntax_error(f->curr_token, "Expected if expression block statement");
// else_expr = ast_bad_expr(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
// break;
// }
// } else {
// syntax_error(f->curr_token, "An if expression must have an else clause");
// return ast_bad_stmt(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
// }
return ast_if_expr(f, token, init, cond, body, else_expr);
}
// return ast_if_expr(f, token, init, cond, body, else_expr);
// }
AstNode *parse_operand(AstFile *f, bool lhs) {
AstNode *operand = NULL; // Operand
@@ -1793,16 +1783,16 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
return type;
}
case Token_if:
if (!lhs && f->expr_level >= 0) {
return parse_if_expr(f);
}
break;
case Token_OpenBrace:
if (!lhs && f->expr_level >= 0) {
return parse_block_expr(f);
}
break;
// case Token_if:
// if (!lhs && f->expr_level >= 0) {
// return parse_if_expr(f);
// }
// break;
// case Token_OpenBrace:
// if (!lhs && f->expr_level >= 0) {
// return parse_block_expr(f);
// }
// break;
default: {
AstNode *type = parse_type_or_ident(f);
@@ -2040,22 +2030,24 @@ AstNode *parse_unary_expr(AstFile *f, bool lhs) {
// NOTE(bill): result == priority
i32 token_precedence(TokenKind t) {
switch (t) {
case Token_CmpOr:
case Token_Question:
return 1;
case Token_CmpAnd:
case Token_CmpOr:
return 2;
case Token_CmpAnd:
return 3;
case Token_CmpEq:
case Token_NotEq:
case Token_Lt:
case Token_Gt:
case Token_LtEq:
case Token_GtEq:
return 3;
return 4;
case Token_Add:
case Token_Sub:
case Token_Or:
case Token_Xor:
return 4;
return 5;
case Token_Mul:
case Token_Quo:
case Token_Mod:
@@ -2063,51 +2055,42 @@ i32 token_precedence(TokenKind t) {
case Token_AndNot:
case Token_Shl:
case Token_Shr:
return 5;
// case Token_as:
// case Token_transmute:
// case Token_down_cast:
// case Token_union_cast:
// return 6;
return 6;
}
return 0;
}
AstNode *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
AstNode *expression = parse_unary_expr(f, lhs);
AstNode *expr = parse_unary_expr(f, lhs);
for (i32 prec = token_precedence(f->curr_token.kind); prec >= prec_in; prec--) {
for (;;) {
AstNode *right;
Token op = f->curr_token;
i32 op_prec = token_precedence(op.kind);
if (op_prec != prec) {
// NOTE(bill): This will also catch operators that are not valid "binary" operators
break;
}
expect_operator(f); // NOTE(bill): error checks too
if (lhs) {
// TODO(bill): error checking
lhs = false;
}
switch (op.kind) {
/* case Token_as:
case Token_transmute:
case Token_down_cast:
case Token_union_cast:
right = parse_type(f);
break; */
default:
right = parse_binary_expr(f, false, prec+1);
if (op.kind == Token_Question) {
AstNode *cond = expr;
// Token_Question
AstNode *x = parse_expr(f, lhs);
Token token_c = expect_token(f, Token_Colon);
AstNode *y = parse_expr(f, lhs);
expr = ast_ternary_expr(f, cond, x, y);
} else {
AstNode *right = parse_binary_expr(f, false, prec+1);
if (!right) {
syntax_error(op, "Expected expression on the right hand side of the binary operator");
syntax_error(op, "Expected expression on the right-hand side of the binary operator");
}
break;
expr = ast_binary_expr(f, op, expr, right);
}
expression = ast_binary_expr(f, op, expression, right);
lhs = false;
}
}
return expression;
return expr;
}
AstNode *parse_expr(AstFile *f, bool lhs) {
@@ -2302,15 +2285,39 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) {
return parse_body(f);
}
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow);
AstNode *parse_results(AstFile *f) {
if (!allow_token(f, Token_ArrowRight)) {
return NULL;
}
if (f->curr_token.kind != Token_OpenParen) {
Token begin_token = f->curr_token;
AstNodeArray empty_names = {0};
AstNodeArray list = make_ast_node_array(f);
AstNode *type = parse_type(f);
array_add(&list, ast_field(f, empty_names, type, 0));
return ast_field_list(f, begin_token, list);
}
AstNode *list = NULL;
expect_token(f, Token_OpenParen);
list = parse_field_list(f, NULL, 0, Token_Comma, Token_CloseParen);
expect_token_after(f, Token_CloseParen, "parameter list");
return list;
}
AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign_name_, String *link_name_) {
AstNodeArray params = {0};
AstNodeArray results = {0};
AstNode *params = {0};
AstNode *results = {0};
Token proc_token = expect_token(f, Token_proc);
parse_proc_signature(f, &params, &results);
expect_token(f, Token_OpenParen);
params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen);
expect_token_after(f, Token_CloseParen, "parameter list");
results = parse_results(f);
u64 tags = 0;
String foreign_name = {0};
@@ -2362,7 +2369,7 @@ bool is_token_field_prefix(TokenKind kind) {
switch (kind) {
case Token_using:
case Token_no_alias:
// case Token_immutable:
case Token_immutable:
return true;
}
return false;
@@ -2378,7 +2385,7 @@ u32 parse_field_prefixes(AstFile *f) {
switch (f->curr_token.kind) {
case Token_using: using_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;
}
}
if (using_count > 1) syntax_error(f->curr_token, "Multiple `using` in this field list");
@@ -2448,8 +2455,9 @@ AstNodeArray convert_to_ident_list(AstFile *f, AstNodeAndFlagsArray list, bool i
return idents;
}
AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
TokenKind separator, TokenKind follow) {
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow) {
Token start_token = f->curr_token;
AstNodeArray params = make_ast_node_array(f);
AstNodeAndFlagsArray list = {0}; array_init(&list, heap_allocator()); // LEAK(bill):
isize total_name_count = 0;
@@ -2509,7 +2517,7 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
}
if (name_count_) *name_count_ = total_name_count;
return params;
return ast_field_list(f, start_token, params);
}
for_array(i, list) {
@@ -2527,11 +2535,11 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
}
if (name_count_) *name_count_ = total_name_count;
return params;
return ast_field_list(f, start_token, params);
}
AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
return parse_field_list(f, field_count_, flags, Token_Comma, Token_CloseBrace);
}
@@ -2576,8 +2584,8 @@ AstNode *parse_type_or_ident(AstFile *f) {
AstNode *count_expr = NULL;
bool is_vector = false;
if (f->curr_token.kind == Token_Question) {
count_expr = ast_unary_expr(f, expect_token(f, Token_Question), NULL);
if (f->curr_token.kind == Token_Ellipsis) {
count_expr = ast_unary_expr(f, expect_token(f, Token_Ellipsis), NULL);
} else if (f->curr_token.kind == Token_vector) {
next_token(f);
if (f->curr_token.kind != Token_CloseBracket) {
@@ -2588,7 +2596,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
syntax_error(f->curr_token, "Vector type missing count");
}
is_vector = true;
} else if (f->curr_token.kind == Token_Ellipsis) {
} else if (f->curr_token.kind == Token_dynamic) {
next_token(f);
expect_token(f, Token_CloseBracket);
return ast_dynamic_array_type(f, token, parse_type(f));
@@ -2661,29 +2669,84 @@ AstNode *parse_type_or_ident(AstFile *f) {
Token open = expect_token_after(f, Token_OpenBrace, "struct");
isize decl_count = 0;
AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
Token close = expect_token(f, Token_CloseBrace);
AstNodeArray decls = {0};
if (fields != NULL) {
GB_ASSERT(fields->kind == AstNode_FieldList);
decls = fields->FieldList.list;
}
return ast_struct_type(f, token, decls, decl_count, is_packed, is_ordered, align);
} break;
case Token_union: {
Token token = expect_token(f, Token_union);
Token open = expect_token_after(f, Token_OpenBrace, "union");
isize decl_count = 0;
AstNodeArray decls = parse_record_fields(f, &decl_count, 0, str_lit("union"));
AstNodeArray decls = make_ast_node_array(f);
AstNodeArray variants = make_ast_node_array(f);
isize total_decl_name_count = 0;
while (f->curr_token.kind != Token_CloseBrace &&
f->curr_token.kind != Token_EOF) {
u32 decl_flags = parse_field_prefixes(f);
if (decl_flags != 0) {
AstNodeArray names = parse_ident_list(f);
if (names.count == 0) {
syntax_error(f->curr_token, "Empty field declaration");
}
u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, decl_flags);
total_decl_name_count += names.count;
expect_token_after(f, Token_Colon, "field list");
AstNode *type = parse_var_type(f, false);
array_add(&decls, ast_field(f, names, type, set_flags));
} else {
AstNodeArray names = parse_ident_list(f);
if (names.count == 0) {
break;
}
if (names.count > 1 || f->curr_token.kind == Token_Colon) {
u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, decl_flags);
total_decl_name_count += names.count;
expect_token_after(f, Token_Colon, "field list");
AstNode *type = parse_var_type(f, false);
array_add(&decls, ast_field(f, names, type, set_flags));
} else {
AstNode *name = names.e[0];
Token open = expect_token(f, Token_OpenBrace);
isize decl_count = 0;
AstNode *list = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union"));
Token close = expect_token(f, Token_CloseBrace);
array_add(&variants, ast_union_field(f, name, list));
}
}
if (f->curr_token.kind != Token_Comma) {
break;
}
next_token(f);
}
Token close = expect_token(f, Token_CloseBrace);
return ast_union_type(f, token, decls, decl_count);
return ast_union_type(f, token, decls, total_decl_name_count, variants);
}
case Token_raw_union: {
Token token = expect_token(f, Token_raw_union);
Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
isize decl_count = 0;
AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union"));
AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union"));
Token close = expect_token(f, Token_CloseBrace);
AstNodeArray decls = {0};
if (fields != NULL) {
GB_ASSERT(fields->kind == AstNode_FieldList);
decls = fields->FieldList.list;
}
return ast_raw_union_type(f, token, decls, decl_count);
}
@@ -2723,39 +2786,6 @@ AstNode *parse_type_or_ident(AstFile *f) {
}
AstNodeArray parse_results(AstFile *f) {
AstNodeArray results = make_ast_node_array(f);
if (allow_token(f, Token_ArrowRight)) {
if (f->curr_token.kind == Token_OpenParen) {
expect_token(f, Token_OpenParen);
while (f->curr_token.kind != Token_CloseParen &&
f->curr_token.kind != Token_EOF) {
array_add(&results, parse_type(f));
if (f->curr_token.kind != Token_Comma) {
break;
}
next_token(f);
}
expect_token(f, Token_CloseParen);
return results;
}
array_add(&results, parse_type(f));
return results;
}
return results;
}
void parse_proc_signature(AstFile *f,
AstNodeArray *params,
AstNodeArray *results) {
expect_token(f, Token_OpenParen);
*params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen);
expect_token_after(f, Token_CloseParen, "parameter list");
*results = parse_results(f);
}
AstNode *parse_body(AstFile *f) {
AstNodeArray stmts = {0};
Token open, close;
@@ -2771,48 +2801,6 @@ AstNode *parse_body(AstFile *f) {
return ast_block_stmt(f, stmts, open, close);
}
/*
AstNode *parse_proc_decl(AstFile *f) {
if (look_ahead_token_kind(f, 1) == Token_OpenParen) {
// NOTE(bill): It's an anonymous procedure
// NOTE(bill): This look-ahead technically makes the grammar LALR(2)
// but is that a problem in practice?
return ast_expr_stmt(f, parse_expr(f, true));
}
AstNodeArray params = {0};
AstNodeArray results = {0};
Token proc_token = expect_token(f, Token_proc);
AstNode *name = parse_ident(f);
parse_proc_signature(f, &params, &results);
u64 tags = 0;
String foreign_name = {0};
String link_name = {0};
ProcCallingConvention cc = ProcCC_Odin;
parse_proc_tags(f, &tags, &foreign_name, &link_name, &cc);
AstNode *proc_type = ast_proc_type(f, proc_token, params, results, tags, cc);
AstNode *body = NULL;
if (f->curr_token.kind == Token_OpenBrace) {
if ((tags & ProcTag_foreign) != 0) {
syntax_error(proc_token, "A procedure tagged as `#foreign` cannot have a body");
}
AstNode *curr_proc = f->curr_proc;
f->curr_proc = proc_type;
body = parse_body(f);
f->curr_proc = curr_proc;
} else if ((tags & ProcTag_foreign) == 0) {
syntax_error(proc_token, "Only a procedure tagged as `#foreign` cannot have a body");
}
return ast_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name);
} */
AstNode *parse_if_stmt(AstFile *f) {
if (f->curr_proc == NULL) {
syntax_error(f->curr_token, "You cannot use an if statement in the file scope");
@@ -2927,27 +2915,27 @@ AstNode *parse_return_stmt(AstFile *f) {
}
AstNode *parse_give_stmt(AstFile *f) {
if (f->curr_proc == NULL) {
syntax_error(f->curr_token, "You cannot use a give statement in the file scope");
return ast_bad_stmt(f, f->curr_token, f->curr_token);
}
if (f->expr_level == 0) {
syntax_error(f->curr_token, "A give statement must be used within an expression");
return ast_bad_stmt(f, f->curr_token, f->curr_token);
}
// AstNode *parse_give_stmt(AstFile *f) {
// if (f->curr_proc == NULL) {
// syntax_error(f->curr_token, "You cannot use a give statement in the file scope");
// return ast_bad_stmt(f, f->curr_token, f->curr_token);
// }
// if (f->expr_level == 0) {
// syntax_error(f->curr_token, "A give statement must be used within an expression");
// return ast_bad_stmt(f, f->curr_token, f->curr_token);
// }
Token token = expect_token(f, Token_give);
AstNodeArray results;
if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) {
results = parse_rhs_expr_list(f);
} else {
results = make_ast_node_array(f);
}
AstNode *ge = ast_give_expr(f, token, results);
expect_semicolon(f, ge);
return ast_expr_stmt(f, ge);
}
// Token token = expect_token(f, Token_give);
// AstNodeArray results;
// if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) {
// results = parse_rhs_expr_list(f);
// } else {
// results = make_ast_node_array(f);
// }
// AstNode *ge = ast_give_expr(f, token, results);
// expect_semicolon(f, ge);
// return ast_expr_stmt(f, ge);
// }
AstNode *parse_for_stmt(AstFile *f) {
if (f->curr_proc == NULL) {
@@ -3229,7 +3217,7 @@ AstNode *parse_stmt(AstFile *f) {
case Token_defer: return parse_defer_stmt(f);
case Token_asm: return parse_asm_stmt(f);
case Token_return: return parse_return_stmt(f);
case Token_give: return parse_give_stmt(f);
// case Token_give: return parse_give_stmt(f);
case Token_break:
case Token_continue:
@@ -3276,7 +3264,7 @@ AstNode *parse_stmt(AstFile *f) {
return ast_bad_stmt(f, token, f->curr_token);
} break;
#if 0
#if 1
case Token_immutable: {
Token token = expect_token(f, Token_immutable);
AstNode *node = parse_stmt(f);
@@ -3482,8 +3470,18 @@ AstNode *parse_stmt(AstFile *f) {
return s;
}
expect_semicolon(f, s);
return ast_tag_stmt(f, hash_token, name, parse_stmt(f));
if (str_eq(tag, str_lit("include"))) {
syntax_error(token, "#include is not a valid import declaration kind. Use #load instead");
s = ast_bad_stmt(f, token, f->curr_token);
} else {
syntax_error(token, "Unknown tag directive used: `%.*s`", LIT(tag));
s = ast_bad_stmt(f, token, f->curr_token);
}
fix_advance_to_next_stmt(f);
return s;
} break;
case Token_OpenBrace:
+1
View File
@@ -19,6 +19,7 @@ typedef struct String {
#define str_lit(c_str) (String){cast(u8 *)c_str, gb_size_of(c_str)-1}
// NOTE(bill): String16 is only used for Windows due to its file directories
typedef struct String16 {
wchar_t *text;
isize len;
+3
View File
@@ -99,9 +99,12 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_raw_union, "raw_union"), \
TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_vector, "vector"), \
TOKEN_KIND(Token_static, "static"), \
TOKEN_KIND(Token_dynamic, "dynamic"), \
TOKEN_KIND(Token_map, "map"), \
TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_no_alias, "no_alias"), \
TOKEN_KIND(Token_immutable, "immutable"), \
TOKEN_KIND(Token_cast, "cast"), \
TOKEN_KIND(Token_transmute, "transmute"), \
TOKEN_KIND(Token_down_cast, "down_cast"), \
+200 -142
View File
@@ -88,18 +88,21 @@ typedef struct TypeRecord {
// All record types
// Theses are arrays
// Entity_Variable - struct/raw_union
// Entity_TypeName - union
// Entity_Variable - struct/raw_union/union (for common fields)
// Entity_Constant - enum
Entity **fields;
i32 field_count; // == struct_offsets count
Entity **fields_in_src_order; // Entity_Variable
AstNode *node;
i64 * struct_offsets;
bool struct_are_offsets_set;
bool struct_is_packed;
bool struct_is_ordered;
Entity **fields_in_src_order; // Entity_Variable
// Entity_TypeName - union
Entity **variants;
i32 variant_count;
i64 * offsets;
bool are_offsets_set;
bool is_packed;
bool is_ordered;
i64 custom_align; // NOTE(bill): Only used in structs at the moment
Entity * names;
@@ -178,21 +181,9 @@ typedef struct Type {
bool failure;
} Type;
// NOTE(bill): Internal sizes of certain types
// string: 2*word_size (ptr+len)
// slice: 3*word_size (ptr+len+cap)
// array: count*size_of(elem) aligned
// NOTE(bill): Alignment of structures and other types are to be compatible with C
typedef struct BaseTypeSizes {
i64 word_size;
i64 max_align;
} BaseTypeSizes;
typedef Array(i32) Array_i32;
// TODO(bill): Should I add extra information here specifying the kind of selection?
// e.g. field, constant, vector field, type field, etc.
typedef struct Selection {
Entity * entity;
Array_i32 index;
@@ -208,6 +199,7 @@ Selection make_selection(Entity *entity, Array_i32 index, bool indirect) {
void selection_add_index(Selection *s, isize index) {
// IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form
// of heap allocation
// TODO(bill): Find a way to use a backing buffer for initial use as the general case is probably .count<3
if (s->index.e == NULL) {
array_init(&s->index, heap_allocator());
}
@@ -290,11 +282,12 @@ gb_global Type *t_byte_slice = NULL;
gb_global Type *t_string_slice = NULL;
// Type generated for the "preload" file
gb_global Type *t_type_info = NULL;
gb_global Type *t_type_info_member = NULL;
gb_global Type *t_type_info_record = NULL;
gb_global Type *t_type_info_enum_value = NULL;
gb_global Type *t_type_info_ptr = NULL;
gb_global Type *t_type_info_member_ptr = NULL;
gb_global Type *t_type_info_record_ptr = NULL;
gb_global Type *t_type_info_enum_value_ptr = NULL;
gb_global Type *t_type_info_named = NULL;
@@ -311,12 +304,11 @@ gb_global Type *t_type_info_slice = NULL;
gb_global Type *t_type_info_vector = NULL;
gb_global Type *t_type_info_tuple = NULL;
gb_global Type *t_type_info_struct = NULL;
gb_global Type *t_type_info_union = NULL;
gb_global Type *t_type_info_raw_union = NULL;
gb_global Type *t_type_info_union = NULL;
gb_global Type *t_type_info_enum = NULL;
gb_global Type *t_type_info_map = NULL;
gb_global Type *t_type_info_named_ptr = NULL;
gb_global Type *t_type_info_integer_ptr = NULL;
gb_global Type *t_type_info_float_ptr = NULL;
@@ -331,13 +323,11 @@ gb_global Type *t_type_info_slice_ptr = NULL;
gb_global Type *t_type_info_vector_ptr = NULL;
gb_global Type *t_type_info_tuple_ptr = NULL;
gb_global Type *t_type_info_struct_ptr = NULL;
gb_global Type *t_type_info_union_ptr = NULL;
gb_global Type *t_type_info_raw_union_ptr = NULL;
gb_global Type *t_type_info_union_ptr = NULL;
gb_global Type *t_type_info_enum_ptr = NULL;
gb_global Type *t_type_info_map_ptr = NULL;
gb_global Type *t_allocator = NULL;
gb_global Type *t_allocator_ptr = NULL;
gb_global Type *t_context = NULL;
@@ -352,8 +342,13 @@ gb_global Type *t_map_header = NULL;
i64 type_size_of (gbAllocator allocator, Type *t);
i64 type_align_of (gbAllocator allocator, Type *t);
i64 type_offset_of (gbAllocator allocator, Type *t, i32 index);
gbString type_to_string(Type *type);
Type *base_type(Type *t) {
for (;;) {
if (t == NULL) {
@@ -866,8 +861,11 @@ bool are_types_identical(Type *x, Type *y) {
case TypeRecord_RawUnion:
case TypeRecord_Union:
if (x->Record.field_count == y->Record.field_count &&
x->Record.struct_is_packed == y->Record.struct_is_packed &&
x->Record.struct_is_ordered == y->Record.struct_is_ordered) {
x->Record.variant_count == y->Record.variant_count &&
x->Record.is_packed == y->Record.is_packed &&
x->Record.is_ordered == y->Record.is_ordered &&
x->Record.custom_align == y->Record.custom_align) {
// TODO(bill); Fix the custom alignment rule
for (isize i = 0; i < x->Record.field_count; i++) {
if (!are_types_identical(x->Record.fields[i]->type, y->Record.fields[i]->type)) {
return false;
@@ -876,9 +874,18 @@ bool are_types_identical(Type *x, Type *y) {
return false;
}
}
for (isize i = 1; i < x->Record.variant_count; i++) {
if (!are_types_identical(x->Record.variants[i]->type, y->Record.variants[i]->type)) {
return false;
}
if (str_ne(x->Record.variants[i]->token.string, y->Record.variants[i]->token.string)) {
return false;
}
}
return true;
}
break;
case TypeRecord_Enum:
return x == y; // NOTE(bill): All enums are unique
}
@@ -894,7 +901,7 @@ bool are_types_identical(Type *x, Type *y) {
case Type_Named:
if (y->kind == Type_Named) {
return x->Named.base == y->Named.base;
return x->Named.type_name == y->Named.type_name;
}
break;
@@ -929,7 +936,6 @@ bool are_types_identical(Type *x, Type *y) {
break;
}
return false;
}
@@ -970,6 +976,8 @@ bool is_type_cte_safe(Type *type) {
case Type_DynamicArray:
return false;
case Type_Map:
return false;
case Type_Vector: // NOTE(bill): This should always to be true but this is for sanity reasons
return is_type_cte_safe(type->Vector.elem);
@@ -1027,41 +1035,50 @@ typedef enum ProcTypeOverloadKind {
ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
if (!is_type_proc(x)) return ProcOverload_NotProcedure;
if (!is_type_proc(y)) return ProcOverload_NotProcedure;
TypeProc *px = &base_type(x)->Proc;
TypeProc *py = &base_type(y)->Proc;
TypeProc px = base_type(x)->Proc;
TypeProc py = base_type(y)->Proc;
if (px->calling_convention != py->calling_convention) {
if (px.calling_convention != py.calling_convention) {
return ProcOverload_CallingConvention;
}
if (px->param_count != py->param_count) {
if (px.param_count != py.param_count) {
return ProcOverload_ParamCount;
}
for (isize i = 0; i < px->param_count; i++) {
Entity *ex = px->params->Tuple.variables[i];
Entity *ey = py->params->Tuple.variables[i];
for (isize i = 0; i < px.param_count; i++) {
Entity *ex = px.params->Tuple.variables[i];
Entity *ey = py.params->Tuple.variables[i];
if (!are_types_identical(ex->type, ey->type)) {
return ProcOverload_ParamTypes;
}
}
// IMPORTANT TODO(bill): Determine the rules for overloading procedures with variadic parameters
if (px->variadic != py->variadic) {
if (px.variadic != py.variadic) {
return ProcOverload_ParamVariadic;
}
if (px->result_count != py->result_count) {
if (px.result_count != py.result_count) {
return ProcOverload_ResultCount;
}
for (isize i = 0; i < px->result_count; i++) {
Entity *ex = px->results->Tuple.variables[i];
Entity *ey = py->results->Tuple.variables[i];
for (isize i = 0; i < px.result_count; i++) {
Entity *ex = px.results->Tuple.variables[i];
Entity *ey = py.results->Tuple.variables[i];
if (!are_types_identical(ex->type, ey->type)) {
return ProcOverload_ResultTypes;
}
}
{
Entity *ex = px.params->Tuple.variables[0];
Entity *ey = py.params->Tuple.variables[0];
bool ok = are_types_identical(ex->type, ey->type);
if (ok) {
gb_printf_err("Here\n");
}
}
return ProcOverload_Identical;
}
@@ -1327,14 +1344,12 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
}
if (is_type_union(type)) {
// NOTE(bill): The subtype for a union are stored in the fields
// as they are "kind of" like variables but not
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
for (isize i = 1; i < type->Record.variant_count; i++) {
Entity *f = type->Record.variants[i];
GB_ASSERT(f->kind == Entity_TypeName);
String str = f->token.string;
if (str_eq(field_name, str)) {
if (str_eq(str, field_name)) {
sel.entity = f;
// selection_add_index(&sel, i);
return sel;
@@ -1369,7 +1384,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
}
}
}
} else if (!is_type_union(type)) {
} else {
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) {
@@ -1461,12 +1476,8 @@ void type_path_pop(TypePath *tp) {
#define FAILURE_ALIGNMENT 0
i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t);
i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t);
i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, i32 index);
i64 type_size_of_internal (BaseTypeSizes s, gbAllocator allocator, Type *t, TypePath *path);
i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypePath *path);
i64 type_size_of_internal (gbAllocator allocator, Type *t, TypePath *path);
i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path);
i64 align_formula(i64 size, i64 align) {
if (align > 0) {
@@ -1476,32 +1487,32 @@ i64 align_formula(i64 size, i64 align) {
return size;
}
i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
i64 type_size_of(gbAllocator allocator, Type *t) {
if (t == NULL) {
return 0;
}
i64 size;
TypePath path = {0};
type_path_init(&path);
size = type_size_of_internal(s, allocator, t, &path);
size = type_size_of_internal(allocator, t, &path);
type_path_free(&path);
return size;
}
i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
i64 type_align_of(gbAllocator allocator, Type *t) {
if (t == NULL) {
return 1;
}
i64 align;
TypePath path = {0};
type_path_init(&path);
align = type_align_of_internal(s, allocator, t, &path);
align = type_align_of_internal(allocator, t, &path);
type_path_free(&path);
return align;
}
i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypePath *path) {
i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
if (t->failure) {
return FAILURE_ALIGNMENT;
}
@@ -1511,11 +1522,11 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
case Type_Basic: {
GB_ASSERT(is_type_typed(t));
switch (t->kind) {
case Basic_string: return s.word_size;
case Basic_any: return s.word_size;
case Basic_string: return build_context.word_size;
case Basic_any: return build_context.word_size;
case Basic_int: case Basic_uint: case Basic_rawptr:
return s.word_size;
return build_context.word_size;
}
} break;
@@ -1525,17 +1536,17 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
if (path->failure) {
return FAILURE_ALIGNMENT;
}
i64 align = type_align_of_internal(s, allocator, t->Array.elem, path);
i64 align = type_align_of_internal(allocator, t->Array.elem, path);
type_path_pop(path);
return align;
}
case Type_DynamicArray:
// data, count, capacity, allocator
return s.word_size;
return build_context.word_size;
case Type_Slice:
return s.word_size;
return build_context.word_size;
case Type_Vector: {
Type *elem = t->Vector.elem;
@@ -1543,17 +1554,17 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
if (path->failure) {
return FAILURE_ALIGNMENT;
}
i64 size = type_size_of_internal(s, allocator, t->Vector.elem, path);
i64 size = type_size_of_internal(allocator, t->Vector.elem, path);
type_path_pop(path);
i64 count = gb_max(prev_pow2(t->Vector.count), 1);
i64 total = size * count;
return gb_clamp(total, 1, s.max_align);
return gb_clamp(total, 1, build_context.max_align);
} break;
case Type_Tuple: {
i64 max = 1;
for (isize i = 0; i < t->Tuple.variable_count; i++) {
i64 align = type_align_of_internal(s, allocator, t->Tuple.variables[i]->type, path);
i64 align = type_align_of_internal(allocator, t->Tuple.variables[i]->type, path);
if (max < align) {
max = align;
}
@@ -1563,7 +1574,7 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
case Type_Map: {
if (t->Map.count == 0) { // Dynamic
return type_align_of_internal(s, allocator, t->Map.generated_struct_type, path);
return type_align_of_internal(allocator, t->Map.generated_struct_type, path);
}
GB_PANIC("TODO(bill): Fixed map alignment");
} break;
@@ -1572,19 +1583,19 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
switch (t->Record.kind) {
case TypeRecord_Struct:
if (t->Record.custom_align > 0) {
return gb_clamp(t->Record.custom_align, 1, s.max_align);
return gb_clamp(t->Record.custom_align, 1, build_context.max_align);
}
if (t->Record.field_count > 0) {
// TODO(bill): What is this supposed to be?
if (t->Record.struct_is_packed) {
i64 max = s.word_size;
if (t->Record.is_packed) {
i64 max = build_context.word_size;
for (isize i = 0; i < t->Record.field_count; i++) {
Type *field_type = t->Record.fields[i]->type;
type_path_push(path, field_type);
if (path->failure) {
return FAILURE_ALIGNMENT;
}
i64 align = type_align_of_internal(s, allocator, field_type, path);
i64 align = type_align_of_internal(allocator, field_type, path);
type_path_pop(path);
if (max < align) {
max = align;
@@ -1597,7 +1608,7 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
if (path->failure) {
return FAILURE_ALIGNMENT;
}
i64 align = type_align_of_internal(s, allocator, field_type, path);
i64 align = type_align_of_internal(allocator, field_type, path);
type_path_pop(path);
return align;
}
@@ -1605,13 +1616,13 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
case TypeRecord_Union: {
i64 max = 1;
// NOTE(bill): field zero is null
for (isize i = 1; i < t->Record.field_count; i++) {
Type *field_type = t->Record.fields[i]->type;
type_path_push(path, field_type);
for (isize i = 1; i < t->Record.variant_count; i++) {
Type *variant = t->Record.variants[i]->type;
type_path_push(path, variant);
if (path->failure) {
return FAILURE_ALIGNMENT;
}
i64 align = type_align_of_internal(s, allocator, field_type, path);
i64 align = type_align_of_internal(allocator, variant, path);
type_path_pop(path);
if (max < align) {
max = align;
@@ -1620,14 +1631,14 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
return max;
} break;
case TypeRecord_RawUnion: {
i64 max = 1;
i64 max = build_context.word_size;
for (isize i = 0; i < t->Record.field_count; i++) {
Type *field_type = t->Record.fields[i]->type;
type_path_push(path, field_type);
if (path->failure) {
return FAILURE_ALIGNMENT;
}
i64 align = type_align_of_internal(s, allocator, field_type, path);
i64 align = type_align_of_internal(allocator, field_type, path);
type_path_pop(path);
if (max < align) {
max = align;
@@ -1639,43 +1650,48 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
} break;
}
// return gb_clamp(next_pow2(type_size_of(s, allocator, t)), 1, s.max_align);
// NOTE(bill): Things that are bigger than s.word_size, are actually comprised of smaller types
// return gb_clamp(next_pow2(type_size_of(allocator, t)), 1, build_context.max_align);
// NOTE(bill): Things that are bigger than build_context.word_size, are actually comprised of smaller types
// TODO(bill): Is this correct for 128-bit types (integers)?
return gb_clamp(next_pow2(type_size_of_internal(s, allocator, t, path)), 1, s.word_size);
return gb_clamp(next_pow2(type_size_of_internal(allocator, t, path)), 1, build_context.word_size);
}
i64 *type_set_offsets_of(BaseTypeSizes s, gbAllocator allocator, Entity **fields, isize field_count, bool is_packed) {
i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_count, bool is_packed) {
i64 *offsets = gb_alloc_array(allocator, i64, field_count);
i64 curr_offset = 0;
if (is_packed) {
for (isize i = 0; i < field_count; i++) {
offsets[i] = curr_offset;
curr_offset += type_size_of(s, allocator, fields[i]->type);
curr_offset += type_size_of(allocator, fields[i]->type);
}
} else {
for (isize i = 0; i < field_count; i++) {
i64 align = type_align_of(s, allocator, fields[i]->type);
i64 align = type_align_of(allocator, fields[i]->type);
curr_offset = align_formula(curr_offset, align);
offsets[i] = curr_offset;
curr_offset += type_size_of(s, allocator, fields[i]->type);
curr_offset += type_size_of(allocator, fields[i]->type);
}
}
return offsets;
}
bool type_set_offsets(BaseTypeSizes s, gbAllocator allocator, Type *t) {
bool type_set_offsets(gbAllocator allocator, Type *t) {
t = base_type(t);
if (is_type_struct(t)) {
if (!t->Record.struct_are_offsets_set) {
t->Record.struct_offsets = type_set_offsets_of(s, allocator, t->Record.fields, t->Record.field_count, t->Record.struct_is_packed);
t->Record.struct_are_offsets_set = true;
if (!t->Record.are_offsets_set) {
t->Record.offsets = type_set_offsets_of(allocator, t->Record.fields, t->Record.field_count, t->Record.is_packed);
t->Record.are_offsets_set = true;
return true;
}
} else if (is_type_tuple(t)) {
} else if (is_type_union(t)) {
if (!t->Record.are_offsets_set) {
t->Record.offsets = type_set_offsets_of(allocator, t->Record.fields, t->Record.field_count, false);
t->Record.are_offsets_set = true;
return true;
}
} else if (is_type_tuple(t)) {
if (!t->Tuple.are_offsets_set) {
t->Tuple.offsets = type_set_offsets_of(s, allocator, t->Tuple.variables, t->Tuple.variable_count, false);
t->Tuple.offsets = type_set_offsets_of(allocator, t->Tuple.variables, t->Tuple.variable_count, false);
t->Tuple.are_offsets_set = true;
return true;
}
@@ -1685,7 +1701,7 @@ bool type_set_offsets(BaseTypeSizes s, gbAllocator allocator, Type *t) {
return false;
}
i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypePath *path) {
i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
if (t->failure) {
return FAILURE_SIZE;
}
@@ -1699,11 +1715,11 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
return size;
}
switch (kind) {
case Basic_string: return 2*s.word_size;
case Basic_any: return 2*s.word_size;
case Basic_string: return 2*build_context.word_size;
case Basic_any: return 2*build_context.word_size;
case Basic_int: case Basic_uint: case Basic_rawptr:
return s.word_size;
return build_context.word_size;
}
} break;
@@ -1713,17 +1729,17 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
if (count == 0) {
return 0;
}
align = type_align_of_internal(s, allocator, t->Array.elem, path);
align = type_align_of_internal(allocator, t->Array.elem, path);
if (path->failure) {
return FAILURE_SIZE;
}
size = type_size_of_internal(s, allocator, t->Array.elem, path);
size = type_size_of_internal( allocator, t->Array.elem, path);
alignment = align_formula(size, align);
return alignment*(count-1) + size;
} break;
case Type_DynamicArray:
return 3*s.word_size + type_size_of(s, allocator, t_allocator);
return 3*build_context.word_size + type_size_of(allocator, t_allocator);
case Type_Vector: {
#if 0
@@ -1736,7 +1752,7 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
if (path->failure) {
return FAILURE_SIZE;
}
bit_size = 8*type_size_of_internal(s, allocator, t->Vector.elem, path);
bit_size = 8*type_size_of_internal(allocator, t->Vector.elem, path);
type_path_pop(path);
if (is_type_boolean(t->Vector.elem)) {
bit_size = 1; // NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
@@ -1751,11 +1767,11 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
if (count == 0) {
return 0;
}
align = type_align_of_internal(s, allocator, t->Vector.elem, path);
align = type_align_of_internal(allocator, t->Vector.elem, path);
if (path->failure) {
return FAILURE_SIZE;
}
size = type_size_of_internal(s, allocator, t->Vector.elem, path);
size = type_size_of_internal( allocator, t->Vector.elem, path);
alignment = align_formula(size, align);
return alignment*(count-1) + size;
#endif
@@ -1763,11 +1779,11 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
case Type_Slice: // ptr + count
return 2 * s.word_size;
return 2 * build_context.word_size;
case Type_Map: {
if (t->Map.count == 0) { // Dynamic
return type_size_of_internal(s, allocator, t->Map.generated_struct_type, path);
return type_size_of_internal(allocator, t->Map.generated_struct_type, path);
}
GB_PANIC("TODO(bill): Fixed map size");
}
@@ -1778,9 +1794,9 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
if (count == 0) {
return 0;
}
align = type_align_of_internal(s, allocator, t, path);
type_set_offsets(s, allocator, t);
size = t->Tuple.offsets[count-1] + type_size_of_internal(s, allocator, t->Tuple.variables[count-1]->type, path);
align = type_align_of_internal(allocator, t, path);
type_set_offsets(allocator, t);
size = t->Tuple.offsets[count-1] + type_size_of_internal(allocator, t->Tuple.variables[count-1]->type, path);
return align_formula(size, align);
} break;
@@ -1791,44 +1807,44 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
if (count == 0) {
return 0;
}
i64 align = type_align_of_internal(s, allocator, t, path);
i64 align = type_align_of_internal(allocator, t, path);
if (path->failure) {
return FAILURE_SIZE;
}
type_set_offsets(s, allocator, t);
i64 size = t->Record.struct_offsets[count-1] + type_size_of_internal(s, allocator, t->Record.fields[count-1]->type, path);
type_set_offsets(allocator, t);
i64 size = t->Record.offsets[count-1] + type_size_of_internal(allocator, t->Record.fields[count-1]->type, path);
return align_formula(size, align);
} break;
case TypeRecord_Union: {
i64 count = t->Record.field_count;
i64 align = type_align_of_internal(s, allocator, t, path);
i64 count = t->Record.variant_count;
i64 align = type_align_of_internal(allocator, t, path);
if (path->failure) {
return FAILURE_SIZE;
}
i64 max = 0;
// NOTE(bill): Zeroth field is invalid
for (isize i = 1; i < count; i++) {
i64 size = type_size_of_internal(s, allocator, t->Record.fields[i]->type, path);
i64 size = type_size_of_internal(allocator, t->Record.variants[i]->type, path);
if (max < size) {
max = size;
}
}
// NOTE(bill): Align to int
isize size = align_formula(max, s.word_size);
size += type_size_of_internal(s, allocator, t_int, path);
i64 size = align_formula(max, build_context.word_size);
size += type_size_of_internal(allocator, t_int, path);
return align_formula(size, align);
} break;
case TypeRecord_RawUnion: {
i64 count = t->Record.field_count;
i64 align = type_align_of_internal(s, allocator, t, path);
i64 align = type_align_of_internal(allocator, t, path);
if (path->failure) {
return FAILURE_SIZE;
}
i64 max = 0;
for (isize i = 0; i < count; i++) {
i64 size = type_size_of_internal(s, allocator, t->Record.fields[i]->type, path);
i64 size = type_size_of_internal(allocator, t->Record.fields[i]->type, path);
if (max < size) {
max = size;
}
@@ -1841,18 +1857,18 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
}
// Catch all
return s.word_size;
return build_context.word_size;
}
i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, i32 index) {
i64 type_offset_of(gbAllocator allocator, Type *t, i32 index) {
t = base_type(t);
if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) {
type_set_offsets(s, allocator, t);
type_set_offsets(allocator, t);
if (gb_is_between(index, 0, t->Record.field_count-1)) {
return t->Record.struct_offsets[index];
return t->Record.offsets[index];
}
} else if (t->kind == Type_Tuple) {
type_set_offsets(s, allocator, t);
type_set_offsets(allocator, t);
if (gb_is_between(index, 0, t->Tuple.variable_count-1)) {
return t->Tuple.offsets[index];
}
@@ -1860,32 +1876,32 @@ i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, i32 index) {
if (t->Basic.kind == Basic_string) {
switch (index) {
case 0: return 0; // data
case 1: return s.word_size; // count
case 1: return build_context.word_size; // count
}
} else if (t->Basic.kind == Basic_any) {
switch (index) {
case 0: return 0; // type_info
case 1: return s.word_size; // data
case 1: return build_context.word_size; // data
}
}
} else if (t->kind == Type_Slice) {
switch (index) {
case 0: return 0; // data
case 1: return 1*s.word_size; // count
case 1: return 1*build_context.word_size; // count
}
} else if (t->kind == Type_DynamicArray) {
switch (index) {
case 0: return 0; // data
case 1: return 1*s.word_size; // count
case 2: return 2*s.word_size; // capacity
case 3: return 3*s.word_size; // allocator
case 1: return 1*build_context.word_size; // count
case 2: return 2*build_context.word_size; // capacity
case 3: return 3*build_context.word_size; // allocator
}
}
return 0;
}
i64 type_offset_of_from_selection(BaseTypeSizes s, gbAllocator allocator, Type *type, Selection sel) {
i64 type_offset_of_from_selection(gbAllocator allocator, Type *type, Selection sel) {
GB_ASSERT(sel.indirect == false);
Type *t = type;
@@ -1893,7 +1909,7 @@ i64 type_offset_of_from_selection(BaseTypeSizes s, gbAllocator allocator, Type *
for_array(i, sel.index) {
isize index = sel.index.e[i];
t = base_type(t);
offset += type_offset_of(s, allocator, t, index);
offset += type_offset_of(allocator, t, index);
if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) {
t = t->Record.fields[index]->type;
} else {
@@ -1973,18 +1989,19 @@ gbString write_type_to_string(gbString str, Type *type) {
switch (type->Record.kind) {
case TypeRecord_Struct:
str = gb_string_appendc(str, "struct");
if (type->Record.struct_is_packed) {
if (type->Record.is_packed) {
str = gb_string_appendc(str, " #packed");
}
if (type->Record.struct_is_ordered) {
if (type->Record.is_ordered) {
str = gb_string_appendc(str, " #ordered");
}
str = gb_string_appendc(str, " {");
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
GB_ASSERT(f->kind == Entity_Variable);
if (i > 0)
str = gb_string_appendc(str, "; ");
if (i > 0) {
str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, f->type);
@@ -1994,16 +2011,38 @@ gbString write_type_to_string(gbString str, Type *type) {
case TypeRecord_Union:
str = gb_string_appendc(str, "union{");
for (isize i = 1; i < type->Record.field_count; i++) {
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
GB_ASSERT(f->kind == Entity_TypeName);
if (i > 1) {
str = gb_string_appendc(str, "; ");
GB_ASSERT(f->kind == Entity_Variable);
if (i > 0) {
str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, base_type(f->type));
}
for (isize i = 1; i < type->Record.variant_count; i++) {
Entity *f = type->Record.variants[i];
GB_ASSERT(f->kind == Entity_TypeName);
if (i > 1 || type->Record.field_count > 1) {
str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, "{");
Type *variant = base_type(f->type);
for (isize i = 0; i < variant->Record.field_count; i++) {
Entity *f = variant->Record.fields[i];
GB_ASSERT(f->kind == Entity_Variable);
if (i > 0) {
str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, f->type);
}
str = gb_string_appendc(str, "{");
}
str = gb_string_appendc(str, "}");
break;
@@ -2021,6 +2060,25 @@ gbString write_type_to_string(gbString str, Type *type) {
}
str = gb_string_appendc(str, "}");
break;
case TypeRecord_Enum:
str = gb_string_appendc(str, "enum");
if (type->Record.enum_base_type != NULL) {
str = gb_string_appendc(str, " ");
str = write_type_to_string(str, type->Record.enum_base_type);
}
str = gb_string_appendc(str, " {");
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
GB_ASSERT(f->kind == Entity_Constant);
if (i > 0) {
str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
// str = gb_string_appendc(str, " = ");
}
str = gb_string_appendc(str, "}");
break;
}
} break;