This commit is contained in:
Zac Pierson
2017-02-15 10:21:38 -06:00
21 changed files with 643 additions and 793 deletions
+19 -12
View File
@@ -1,18 +1,22 @@
#import "fmt.odin"; #import "fmt.odin";
#import "atomic.odin";
#import "hash.odin";
#import "math.odin";
#import "mem.odin";
#import "opengl.odin";
#import "os.odin";
#import "utf8.odin";
main :: proc() { main :: proc() {
x: f32 = false ? 123 : 55;
{ fmt.println("Ternary:", x);
Vec2 :: [vector 2]f32;
i: f32 = 1;
b := Vec2{i, i};
}
/* /*
Version 0.1.0 /*
Version 0.1.1
Added: Added:
* Dynamic Arrays `[...]Type` * Dynamic Arrays [dynamic]Type`
* Dynamic Maps `map[Key]Value` * Dynamic Maps `map[Key]Value`
* Dynamic array and map literals * Dynamic array and map literals
* Custom struct alignemnt `struct #align 8 { bar: i8 }` * Custom struct alignemnt `struct #align 8 { bar: i8 }`
@@ -22,10 +26,12 @@ main :: proc() {
* Entities prefixes with an underscore do not get exported on imports * Entities prefixes with an underscore do not get exported on imports
* Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps * 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 * 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
Removed: Removed:
* Maybe/option types * Maybe/option types
* immutable variables
* Remove `type` keyword and other "reserved" keywords * Remove `type` keyword and other "reserved" keywords
* `compile_assert` and `assert`return the value of the condition for semantic reasons * `compile_assert` and `assert`return the value of the condition for semantic reasons
@@ -92,7 +98,7 @@ main :: proc() {
} }
{ {
x: [...]f64; x: [dynamic]f64;
reserve(x, 16); reserve(x, 16);
defer free(x); defer free(x);
append(x, 2_000_000.500_000, 3, 5, 7); append(x, 2_000_000.500_000, 3, 5, 7);
@@ -105,7 +111,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); defer free(x);
fmt.println(x); fmt.println(x);
} }
@@ -130,5 +136,6 @@ main :: proc() {
compile_assert(size_of([vector 7]i32) == size_of([7]i32)); compile_assert(size_of([vector 7]i32) == size_of([7]i32));
// align_of([vector 7]i32) != align_of([7]i32) // this may be the case // align_of([vector 7]i32) != align_of([7]i32) // this may be the case
} }
*/
} }
+15 -12
View File
@@ -315,7 +315,11 @@ __assert :: proc(file: string, line, column: int, msg: string) #inline {
file, line, column, msg); file, line, column, msg);
__debug_trap(); __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) { __bounds_check_error :: proc(file: string, line, column: int, index, count: int) {
if 0 <= index && index < count { if 0 <= index && index < count {
return; return;
@@ -341,6 +345,13 @@ __substring_expr_error :: proc(file: string, line, column: int, low, high: int)
file, line, column, low, high); file, line, column, low, high);
__debug_trap(); __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 { __string_decode_rune :: proc(s: string) -> (rune, int) #inline {
return utf8.decode_rune(s); return utf8.decode_rune(s);
@@ -370,7 +381,7 @@ Raw_Dynamic_Array :: struct #ordered {
}; };
Raw_Dynamic_Map :: struct #ordered { Raw_Dynamic_Map :: struct #ordered {
hashes: [...]int, hashes: [dynamic]int,
entries: Raw_Dynamic_Array, entries: Raw_Dynamic_Array,
}; };
@@ -449,6 +460,8 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
} }
// Map stuff
__default_hash :: proc(data: []byte) -> u64 { __default_hash :: proc(data: []byte) -> u64 {
return hash.fnv64a(data); return hash.fnv64a(data);
} }
@@ -650,13 +663,3 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
m.hashes[last.hash_index] = fr.entry_index; 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);
}
}
+15 -8
View File
@@ -116,7 +116,11 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
case ti == type_info(int): buffer_write_string(buf, "int"); case ti == type_info(int): buffer_write_string(buf, "int");
case ti == type_info(uint): buffer_write_string(buf, "uint"); case ti == type_info(uint): buffer_write_string(buf, "uint");
default: default:
buffer_write_string(buf, if info.signed { give "i" } else { give "u"}); if info.signed {
buffer_write_string(buf, "i");
} else {
buffer_write_string(buf, "u");
}
fi := Fmt_Info{buf = buf}; fi := Fmt_Info{buf = buf};
fmt_int(^fi, cast(u64)(8*info.size), false, 'd'); fmt_int(^fi, cast(u64)(8*info.size), false, 'd');
} }
@@ -140,7 +144,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
if info.params == nil { if info.params == nil {
buffer_write_string(buf, "()"); buffer_write_string(buf, "()");
} else { } else {
t := cast(^Tuple)info.params; t := union_cast(^Tuple)info.params;
buffer_write_string(buf, "("); buffer_write_string(buf, "(");
for type, i in t.types { for type, i in t.types {
if i > 0 { buffer_write_string(buf, ", "); } if i > 0 { buffer_write_string(buf, ", "); }
@@ -155,10 +159,9 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
case Tuple: case Tuple:
count := info.names.count; count := info.names.count;
if count != 1 { buffer_write_string(buf, "("); } 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, ", "); } if i > 0 { buffer_write_string(buf, ", "); }
name := info.names[i];
type := info.types[i]; type := info.types[i];
if name.count > 0 { if name.count > 0 {
@@ -393,7 +396,11 @@ fmt_bad_verb :: proc(using fi: ^Fmt_Info, verb: rune) {
fmt_bool :: proc(using fi: ^Fmt_Info, b: bool, verb: rune) { fmt_bool :: proc(using fi: ^Fmt_Info, b: bool, verb: rune) {
match verb { match verb {
case 't', 'v': case 't', 'v':
buffer_write_string(buf, if b { give "true" } else { give "false" }); if b {
buffer_write_string(buf, "true");
} else {
buffer_write_string(buf, "false");
}
default: default:
fmt_bad_verb(fi, verb); fmt_bad_verb(fi, verb);
} }
@@ -790,10 +797,10 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
buffer_write_string(fi.buf, "map["); buffer_write_string(fi.buf, "map[");
defer buffer_write_byte(fi.buf, ']'); defer buffer_write_byte(fi.buf, ']');
entries := ^(cast(^Raw_Dynamic_Map)v.data).entries; entries := ^(cast(^Raw_Dynamic_Map)v.data).entries;
gs, gs_ok := union_cast(^Struct)type_info_base(info.generated_struct); assert(gs_ok); gs := union_cast(^Struct)type_info_base(info.generated_struct);
ed, ed_ok := union_cast(^Dynamic_Array)type_info_base(gs.types[1]); assert(ed_ok); 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; entry_size := ed.elem_size;
for i in 0..<entries.count { for i in 0..<entries.count {
if i > 0 { if i > 0 {
+4 -4
View File
@@ -1,14 +1,14 @@
crc32 :: proc(data: []byte) -> u32 { crc32 :: proc(data: []byte) -> u32 {
result := ~cast(u32)0; result := ~cast(u32)0;
for b in data { 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; return ~result;
} }
crc64 :: proc(data: []byte) -> u64 { crc64 :: proc(data: []byte) -> u64 {
result := ~cast(u64)0; result := ~cast(u64)0;
for b in data { 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; return ~result;
} }
@@ -202,7 +202,7 @@ murmur64 :: proc(data: []byte) -> u64 {
} }
__CRC32_TABLE := [256]u32{ immutable _crc32_table := [256]u32{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -268,7 +268,7 @@ __CRC32_TABLE := [256]u32{
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
}; };
__CRC64_TABLE := [256]u64{ immutable _crc64_table := [256]u64{
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5, 0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a, 0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b, 0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
+87 -87
View File
@@ -20,13 +20,13 @@ Viewport :: proc(x, y, width, height: i32) #foreign lib "gl
Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign lib "glOrtho"; Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign lib "glOrtho";
Color3f :: proc(r, g, b: f32) #foreign lib "glColor3f"; Color3f :: proc(r, g, b: f32) #foreign lib "glColor3f";
Vertex3f :: proc(x, y, z: f32) #foreign lib "glVertex3f"; 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, TexImage2D :: proc(target, level, internal_format,
width, height, border, width, height, border,
format, _type: i32, pixels: rawptr) #foreign lib "glTexImage2D"; 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";
string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; } string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; }
@@ -42,114 +42,114 @@ GetProcAddress :: proc(name: string) -> proc() #cc_c {
return res; return res;
} }
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c; GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c; GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c; GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
BindBuffer: proc(target: i32, buffer: u32) #cc_c; BindBuffer: proc(target: i32, buffer: u32) #cc_c;
BindVertexArray: proc(buffer: u32) #cc_c; BindVertexArray: proc(buffer: u32) #cc_c;
BindSampler: proc(position: i32, sampler: u32) #cc_c; BindSampler: proc(position: i32, sampler: u32) #cc_c;
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32) #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; BufferSubData: proc(target: i32, offset, size: int, data: rawptr) #cc_c;
DrawArrays: proc(mode, first: i32, count: u32) #cc_c; DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c; DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
MapBuffer: proc(target, access: i32) -> rawptr #cc_c; MapBuffer: proc(target, access: i32) -> rawptr #cc_c;
UnmapBuffer: proc(target: i32) #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; EnableVertexAttribArray: proc(index: u32) #cc_c;
CreateShader: proc(shader_type: i32) -> u32 #cc_c; CreateShader: proc(shader_type: i32) -> u32 #cc_c;
ShaderSource: proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c; ShaderSource: proc(shader: u32, count: u32, str: ^^byte, length: ^i32) #cc_c;
CompileShader: proc(shader: u32) #cc_c; CompileShader: proc(shader: u32) #cc_c;
CreateProgram: proc() -> u32 #cc_c; CreateProgram: proc() -> u32 #cc_c;
AttachShader: proc(program, shader: u32) #cc_c; AttachShader: proc(program, shader: u32) #cc_c;
DetachShader: proc(program, shader: u32) #cc_c; DetachShader: proc(program, shader: u32) #cc_c;
DeleteShader: proc(shader: u32) #cc_c; DeleteShader: proc(shader: u32) #cc_c;
LinkProgram: proc(program: u32) #cc_c; LinkProgram: proc(program: u32) #cc_c;
UseProgram: proc(program: u32) #cc_c; UseProgram: proc(program: u32) #cc_c;
DeleteProgram: proc(program: u32) #cc_c; DeleteProgram: proc(program: u32) #cc_c;
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c; GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c;
GetProgramiv: proc(program: 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; 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; GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
ActiveTexture: proc(texture: i32) #cc_c; ActiveTexture: proc(texture: i32) #cc_c;
GenerateMipmap: proc(target: i32) #cc_c; GenerateMipmap: proc(target: i32) #cc_c;
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c; SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c;
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c; SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c;
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c; SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c; SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c; SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c; SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
Uniform1i: proc(loc: i32, v0: i32) #cc_c; Uniform1i: proc(loc: i32, v0: i32) #cc_c;
Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c; Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c;
Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c; Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c;
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c; Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
Uniform1f: proc(loc: i32, v0: f32) #cc_c; Uniform1f: proc(loc: i32, v0: f32) #cc_c;
Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c; Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c;
Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c; Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c;
Uniform4f: proc(loc: i32, v0, v1, v2, v3: 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; 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() { init :: proc() {
set_proc_address :: proc(p: rawptr, name: string) #inline { (cast(^(proc() #cc_c))p)^ = GetProcAddress(name); } 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(^GenBuffers, "glGenBuffers\x00");
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00"); set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
set_proc_address(^GenSamplers, "glGenSamplers\x00"); set_proc_address(^GenSamplers, "glGenSamplers\x00");
set_proc_address(^BindBuffer, "glBindBuffer\x00"); set_proc_address(^BindBuffer, "glBindBuffer\x00");
set_proc_address(^BindSampler, "glBindSampler\x00"); set_proc_address(^BindSampler, "glBindSampler\x00");
set_proc_address(^BindVertexArray, "glBindVertexArray\x00"); set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
set_proc_address(^BufferData, "glBufferData\x00"); set_proc_address(^BufferData, "glBufferData\x00");
set_proc_address(^BufferSubData, "glBufferSubData\x00"); set_proc_address(^BufferSubData, "glBufferSubData\x00");
set_proc_address(^DrawArrays, "glDrawArrays\x00"); set_proc_address(^DrawArrays, "glDrawArrays\x00");
set_proc_address(^DrawElements, "glDrawElements\x00"); set_proc_address(^DrawElements, "glDrawElements\x00");
set_proc_address(^MapBuffer, "glMapBuffer\x00"); set_proc_address(^MapBuffer, "glMapBuffer\x00");
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00"); set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");
set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00"); set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00");
set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00"); set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
set_proc_address(^CreateShader, "glCreateShader\x00"); set_proc_address(^CreateShader, "glCreateShader\x00");
set_proc_address(^ShaderSource, "glShaderSource\x00"); set_proc_address(^ShaderSource, "glShaderSource\x00");
set_proc_address(^CompileShader, "glCompileShader\x00"); set_proc_address(^CompileShader, "glCompileShader\x00");
set_proc_address(^CreateProgram, "glCreateProgram\x00"); set_proc_address(^CreateProgram, "glCreateProgram\x00");
set_proc_address(^AttachShader, "glAttachShader\x00"); set_proc_address(^AttachShader, "glAttachShader\x00");
set_proc_address(^DetachShader, "glDetachShader\x00"); set_proc_address(^DetachShader, "glDetachShader\x00");
set_proc_address(^DeleteShader, "glDeleteShader\x00"); set_proc_address(^DeleteShader, "glDeleteShader\x00");
set_proc_address(^LinkProgram, "glLinkProgram\x00"); set_proc_address(^LinkProgram, "glLinkProgram\x00");
set_proc_address(^UseProgram, "glUseProgram\x00"); set_proc_address(^UseProgram, "glUseProgram\x00");
set_proc_address(^DeleteProgram, "glDeleteProgram\x00"); set_proc_address(^DeleteProgram, "glDeleteProgram\x00");
set_proc_address(^GetShaderiv, "glGetShaderiv\x00"); set_proc_address(^GetShaderiv, "glGetShaderiv\x00");
set_proc_address(^GetProgramiv, "glGetProgramiv\x00"); set_proc_address(^GetProgramiv, "glGetProgramiv\x00");
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00"); set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00");
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00"); set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");
set_proc_address(^ActiveTexture, "glActiveTexture\x00"); set_proc_address(^ActiveTexture, "glActiveTexture\x00");
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00"); set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");
set_proc_address(^Uniform1i, "glUniform1i\x00"); set_proc_address(^Uniform1i, "glUniform1i\x00");
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\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(^SamplerParameteri, "glSamplerParameteri\x00");
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00"); set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00");
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00"); set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00");
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00"); set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00");
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00"); set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00");
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00"); set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
} }
+8 -5
View File
@@ -41,11 +41,14 @@ WS_CAPTION :: 0x00C00000;
WS_VISIBLE :: 0x10000000; WS_VISIBLE :: 0x10000000;
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX; WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
WM_DESTROY :: 0x0002; WM_DESTROY :: 0x0002;
WM_CLOSE :: 0x0010; WM_SIZE :: 0x0005;
WM_QUIT :: 0x0012; WM_CLOSE :: 0x0010;
WM_KEYDOWN :: 0x0100; WM_ACTIVATEAPP :: 0x001C;
WM_KEYUP :: 0x0101; WM_QUIT :: 0x0012;
WM_KEYDOWN :: 0x0100;
WM_KEYUP :: 0x0101;
WM_SIZING :: 0x0214;
PM_REMOVE :: 1; PM_REMOVE :: 1;
+1 -1
View File
@@ -1,6 +1,6 @@
is_signed :: proc(info: ^Type_Info) -> bool { is_signed :: proc(info: ^Type_Info) -> bool {
if is_integer(info) { if is_integer(info) {
i := cast(^Type_Info.Integer)info; i := union_cast(^Type_Info.Integer)info;
return i.signed; return i.signed;
} }
if is_float(info) { if is_float(info) {
+2 -2
View File
@@ -30,7 +30,7 @@ HICB :: 0b1011_1111;
Accept_Range :: struct { lo, hi: u8 } Accept_Range :: struct { lo, hi: u8 }
accept_ranges := [5]Accept_Range{ immutable accept_ranges := [5]Accept_Range{
{0x80, 0xbf}, {0x80, 0xbf},
{0xa0, 0xbf}, {0xa0, 0xbf},
{0x80, 0x9f}, {0x80, 0x9f},
@@ -38,7 +38,7 @@ accept_ranges := [5]Accept_Range{
{0x80, 0x8f}, {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, // 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, // 0x10-0x1f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
+6 -2
View File
@@ -1,4 +1,6 @@
// This stores the information for the specify architecture of this build
typedef struct BuildContext { typedef struct BuildContext {
// Constants
String ODIN_OS; // target operating system String ODIN_OS; // target operating system
String ODIN_ARCH; // target architecture String ODIN_ARCH; // target architecture
String ODIN_ENDIAN; // target endian String ODIN_ENDIAN; // target endian
@@ -6,8 +8,10 @@ typedef struct BuildContext {
String ODIN_VERSION; // compiler version String ODIN_VERSION; // compiler version
String ODIN_ROOT; // Odin ROOT String ODIN_ROOT; // Odin ROOT
i64 word_size; // In bytes
i64 max_align; 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 llc_flags;
String link_flags; String link_flags;
bool is_dll; bool is_dll;
-11
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); isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) { for (isize i = 0; i < max; i++) {
check_init_variable(c, lhs[i], &operands.e[i], context_name); check_init_variable(c, lhs[i], &operands.e[i], context_name);
} }
if (rhs_count > 0 && lhs_count != rhs_count) { if (rhs_count > 0 && lhs_count != rhs_count) {
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", 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); gb_temp_arena_memory_end(tmp);
} }
+163 -326
View File
@@ -265,8 +265,6 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
} }
if (type == NULL) { if (type == NULL) {
return; return;
} }
@@ -1030,7 +1028,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ
} }
o->mode = Addressing_Variable; o->mode = Addressing_Variable;
if (e->Variable.is_immutable) { if (e->Variable.is_immutable) {
o->mode = Addressing_Value; o->mode = Addressing_Immutable;
} }
break; break;
@@ -1073,7 +1071,7 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) {
} }
Operand o = {0}; Operand o = {0};
if (e->kind == AstNode_UnaryExpr && if (e->kind == AstNode_UnaryExpr &&
e->UnaryExpr.op.kind == Token_Question) { e->UnaryExpr.op.kind == Token_Ellipsis) {
return -1; return -1;
} }
@@ -1115,12 +1113,13 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) {
return 0; return 0;
} }
Type *make_map_tuple_type(gbAllocator a, Type *value) { Type *make_optional_ok_type(gbAllocator a, Type *value) {
bool typed = true;
Type *t = make_type_tuple(a); Type *t = make_type_tuple(a);
t->Tuple.variables = gb_alloc_array(a, Entity *, 2); t->Tuple.variables = gb_alloc_array(a, Entity *, 2);
t->Tuple.variable_count = 2; t->Tuple.variable_count = 2;
t->Tuple.variables[0] = make_entity_field(a, NULL, blank_token, value, false, 0); t->Tuple.variables[0] = make_entity_field(a, NULL, blank_token, value, false, 0);
t->Tuple.variables[1] = make_entity_field(a, NULL, blank_token, t_bool, false, 1); t->Tuple.variables[1] = make_entity_field(a, NULL, blank_token, typed ? t_bool : t_untyped_bool, false, 1);
return t; return t;
} }
@@ -1221,7 +1220,7 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
type->Map.generated_struct_type = generated_struct_type; type->Map.generated_struct_type = generated_struct_type;
} }
type->Map.lookup_result_type = make_map_tuple_type(a, value); type->Map.lookup_result_type = make_optional_ok_type(a, value);
// error_node(node, "`map` types are not yet implemented"); // error_node(node, "`map` types are not yet implemented");
} }
@@ -1929,82 +1928,6 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
x->mode = Addressing_Value; x->mode = Addressing_Value;
} }
bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
if (check_is_assignable_to(c, operand, y)) {
return true;
}
Type *x = operand->type;
Type *src = base_type(base_enum_type(x));
Type *dst = base_type(base_enum_type(y));
if (are_types_identical(src, dst)) {
return true;
}
if (dst->kind == Type_Array && src->kind == Type_Array) {
if (are_types_identical(dst->Array.elem, src->Array.elem)) {
return dst->Array.count == src->Array.count;
}
}
if (dst->kind == Type_Slice && src->kind == Type_Slice) {
return are_types_identical(dst->Slice.elem, src->Slice.elem);
}
// Cast between booleans and integers
if (is_type_boolean(src) || is_type_integer(src)) {
if (is_type_boolean(dst) || is_type_integer(dst)) {
return true;
}
}
// Cast between numbers
if (is_type_integer(src) || is_type_float(src)) {
if (is_type_integer(dst) || is_type_float(dst)) {
return true;
}
}
// Cast between pointers
if (is_type_pointer(src) && is_type_pointer(dst)) {
return true;
}
// (u)int <-> pointer
if (is_type_int_or_uint(src) && is_type_rawptr(dst)) {
return true;
}
if (is_type_rawptr(src) && is_type_int_or_uint(dst)) {
return true;
}
// []byte/[]u8 <-> string
if (is_type_u8_slice(src) && is_type_string(dst)) {
return true;
}
if (is_type_string(src) && is_type_u8_slice(dst)) {
if (is_type_typed(src)) {
return true;
}
}
// proc <-> proc
if (is_type_proc(src) && is_type_proc(dst)) {
return true;
}
// proc -> rawptr
if (is_type_proc(src) && is_type_rawptr(dst)) {
return true;
}
// rawptr -> proc
if (is_type_rawptr(src) && is_type_proc(dst)) {
return true;
}
return false;
}
String check_down_cast_name(Type *dst_, Type *src_) { String check_down_cast_name(Type *dst_, Type *src_) {
String result = {0}; String result = {0};
@@ -2074,7 +1997,96 @@ Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offs
} }
void check_conversion(Checker *c, Operand *x, Type *type) {
bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
if (check_is_assignable_to(c, operand, y)) {
return true;
}
Type *x = operand->type;
Type *src = base_type(base_enum_type(x));
Type *dst = base_type(base_enum_type(y));
if (are_types_identical(src, dst)) {
return true;
}
if (dst->kind == Type_Array && src->kind == Type_Array) {
if (are_types_identical(dst->Array.elem, src->Array.elem)) {
return dst->Array.count == src->Array.count;
}
}
if (dst->kind == Type_Slice && src->kind == Type_Slice) {
return are_types_identical(dst->Slice.elem, src->Slice.elem);
}
// Cast between booleans and integers
if (is_type_boolean(src) || is_type_integer(src)) {
if (is_type_boolean(dst) || is_type_integer(dst)) {
return true;
}
}
// Cast between numbers
if (is_type_integer(src) || is_type_float(src)) {
if (is_type_integer(dst) || is_type_float(dst)) {
return true;
}
}
// Cast between pointers
if (is_type_pointer(src) && is_type_pointer(dst)) {
Type *s = base_type(type_deref(src));
if (is_type_union(s)) {
// NOTE(bill): Should the error be here?!
// NOTE(bill): This error should suppress the next casting error as it's at the same position
gbString xs = type_to_string(x);
gbString ys = type_to_string(y);
error_node(operand->expr, "Cannot cast from a union pointer `%s` to `%s`, try using `union_cast` or cast to a `rawptr`", xs, ys);
gb_string_free(ys);
gb_string_free(xs);
return false;
}
return true;
}
// (u)int <-> rawptr
if (is_type_int_or_uint(src) && is_type_rawptr(dst)) {
return true;
}
if (is_type_rawptr(src) && is_type_int_or_uint(dst)) {
return true;
}
// []byte/[]u8 <-> string
if (is_type_u8_slice(src) && is_type_string(dst)) {
return true;
}
if (is_type_string(src) && is_type_u8_slice(dst)) {
if (is_type_typed(src)) {
return true;
}
}
// proc <-> proc
if (is_type_proc(src) && is_type_proc(dst)) {
return true;
}
// proc -> rawptr
if (is_type_proc(src) && is_type_rawptr(dst)) {
return true;
}
// rawptr -> proc
if (is_type_rawptr(src) && is_type_proc(dst)) {
return true;
}
return false;
}
void check_cast(Checker *c, Operand *x, Type *type) {
bool is_const_expr = x->mode == Addressing_Constant; bool is_const_expr = x->mode == Addressing_Constant;
bool can_convert = false; bool can_convert = false;
@@ -2714,7 +2726,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
break; break;
case Entity_Variable: case Entity_Variable:
// TODO(bill): This is the rule I need? // TODO(bill): This is the rule I need?
if (sel.indirect || operand->mode != Addressing_Value) { if (operand->mode == Addressing_Immutable) {
// Okay
} else if (sel.indirect || operand->mode != Addressing_Value) {
operand->mode = Addressing_Variable; operand->mode = Addressing_Variable;
} else { } else {
operand->mode = Addressing_Value; operand->mode = Addressing_Value;
@@ -3819,17 +3833,16 @@ int valid_proc_and_score_cmp(void const *a, void const *b) {
typedef Array(Operand) ArrayOperand; typedef Array(Operand) ArrayOperand;
void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray args, bool allow_map_ok) { bool check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray rhs, bool allow_ok) {
for_array(i, args) { bool optional_ok = false;
for_array(i, rhs) {
Operand o = {0}; Operand o = {0};
check_multi_expr(c, &o, args.e[i]); check_multi_expr(c, &o, rhs.e[i]);
if (o.type == NULL || o.type->kind != Type_Tuple) { if (o.type == NULL || o.type->kind != Type_Tuple) {
if (o.mode == Addressing_MapIndex && if (allow_ok && lhs_count == 2 && rhs.count == 1 &&
allow_map_ok && (o.mode == Addressing_MapIndex || o.mode == Addressing_OptionalOk)) {
lhs_count == 2 && Type *tuple = make_optional_ok_type(c->allocator, o.type);
args.count == 1) {
Type *tuple = make_map_tuple_type(c->allocator, o.type);
add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value); add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value);
Operand val = o; Operand val = o;
@@ -3839,9 +3852,11 @@ void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands,
ok.type = t_bool; ok.type = t_bool;
array_add(operands, val); array_add(operands, val);
array_add(operands, ok); array_add(operands, ok);
continue;
optional_ok = true;
} else {
array_add(operands, o);
} }
array_add(operands, o);
} else { } else {
TypeTuple *tuple = &o.type->Tuple; TypeTuple *tuple = &o.type->Tuple;
for (isize j = 0; j < tuple->variable_count; j++) { for (isize j = 0; j < tuple->variable_count; j++) {
@@ -3850,6 +3865,8 @@ void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands,
} }
} }
} }
return optional_ok;
} }
Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) { Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) {
@@ -3998,7 +4015,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
case 1: case 1:
check_expr(c, operand, ce->args.e[0]); check_expr(c, operand, ce->args.e[0]);
if (operand->mode != Addressing_Invalid) { if (operand->mode != Addressing_Invalid) {
check_conversion(c, operand, t); check_cast(c, operand, t);
} }
break; break;
} }
@@ -4097,8 +4114,19 @@ void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) {
} }
} }
bool check_set_index_data(Operand *o, Type *t, i64 *max_count) { void check_set_mode_with_indirection(Operand *o, bool indirection) {
t = base_type(type_deref(t)); if (o->mode != Addressing_Immutable) {
if (indirection) {
o->mode = Addressing_Variable;
} else if (o->mode != Addressing_Variable &&
o->mode != Addressing_Constant) {
o->mode = Addressing_Value;
}
}
}
bool check_set_index_data(Operand *o, Type *type, bool indirection, i64 *max_count) {
Type *t = base_type(type_deref(type));
switch (t->kind) { switch (t->kind) {
case Type_Basic: case Type_Basic:
@@ -4106,9 +4134,7 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) {
if (o->mode == Addressing_Constant) { if (o->mode == Addressing_Constant) {
*max_count = o->value.value_string.len; *max_count = o->value.value_string.len;
} }
if (o->mode != Addressing_Variable) { check_set_mode_with_indirection(o, indirection);
o->mode = Addressing_Value;
}
o->type = t_u8; o->type = t_u8;
return true; return true;
} }
@@ -4116,69 +4142,33 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) {
case Type_Array: case Type_Array:
*max_count = t->Array.count; *max_count = t->Array.count;
if (o->mode != Addressing_Variable) { check_set_mode_with_indirection(o, indirection);
o->mode = Addressing_Value;
}
o->type = t->Array.elem; o->type = t->Array.elem;
return true; return true;
case Type_Vector: case Type_Vector:
*max_count = t->Vector.count; *max_count = t->Vector.count;
if (o->mode != Addressing_Variable) { check_set_mode_with_indirection(o, indirection);
o->mode = Addressing_Value;
}
o->type = t->Vector.elem; o->type = t->Vector.elem;
return true; return true;
case Type_Slice: case Type_Slice:
o->type = t->Slice.elem; o->type = t->Slice.elem;
o->mode = Addressing_Variable; if (o->mode != Addressing_Immutable) {
o->mode = Addressing_Variable;
}
return true; return true;
case Type_DynamicArray: case Type_DynamicArray:
o->type = t->DynamicArray.elem; o->type = t->DynamicArray.elem;
o->mode = Addressing_Variable; check_set_mode_with_indirection(o, indirection);
return true; return true;
} }
return false; return false;
} }
bool check_is_giving(AstNode *node, AstNode **give_expr) {
switch (node->kind) {
case_ast_node(es, ExprStmt, node);
if (es->expr->kind == AstNode_GiveExpr) {
if (give_expr) *give_expr = es->expr;
return true;
}
case_end;
case_ast_node(ge, GiveExpr, node);
if (give_expr) *give_expr = node;
return true;
case_end;
case_ast_node(be, BlockExpr, node);
// Iterate backwards
for (isize n = be->stmts.count-1; n >= 0; n--) {
AstNode *stmt = be->stmts.e[n];
if (stmt->kind == AstNode_EmptyStmt) {
continue;
}
if (stmt->kind == AstNode_ExprStmt && stmt->ExprStmt.expr->kind == AstNode_GiveExpr) {
if (give_expr) *give_expr = stmt->ExprStmt.expr;
return true;
}
}
case_end;
}
if (give_expr) *give_expr = NULL;
return false;
}
ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) { ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) {
ExprKind kind = Expr_Stmt; ExprKind kind = Expr_Stmt;
@@ -4280,177 +4270,30 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
o->type = type; o->type = type;
case_end; case_end;
case_ast_node(ge, GiveExpr, node); case_ast_node(te, TernaryExpr, node);
if (c->proc_stack.count == 0) { if (c->proc_stack.count == 0) {
error_node(node, "A give expression is only allowed within a procedure"); error_node(node, "A ternary expression is only allowed within a procedure");
goto error; goto error;
} }
if (ge->results.count == 0) {
error_node(node, "`give` has no results");
goto error;
}
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
Array(Operand) operands;
array_init_reserve(&operands, c->tmp_allocator, 2*ge->results.count);
for_array(i, ge->results) {
AstNode *rhs = ge->results.e[i];
Operand o = {0};
check_multi_expr(c, &o, rhs);
if (!is_operand_value(o)) {
error_node(rhs, "Expected a value for a `give`");
continue;
}
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);
}
}
}
if (operands.count == 0) {
error_node(node, "`give` has no value");
gb_temp_arena_memory_end(tmp);
goto error;
} else if (operands.count == 1) {
Operand operand = operands.e[0];
Type *th = type_hint != NULL ? type_hint : c->context.type_hint;
if (th != NULL) {
convert_to_typed(c, &operand, th, 0);
}
// IMPORTANT NOTE(bill): This type could be untyped!!!
o->type = default_type(operand.type);
o->mode = Addressing_Value;
} else {
Type *tuple = make_type_tuple(c->allocator);
Entity **variables = gb_alloc_array(c->allocator, Entity *, operands.count);
isize variable_index = 0;
for_array(i, operands) {
Operand operand = operands.e[i];
// Type *type = default_type(operand.type);
Type *type = operand.type;
switch (operand.mode) {
case Addressing_Constant:
variables[variable_index++] = make_entity_constant(c->allocator, NULL, empty_token, type, operand.value);
break;
default:
variables[variable_index++] = make_entity_param(c->allocator, NULL, empty_token, type, false, true);
break;
}
}
tuple->Tuple.variables = variables;
tuple->Tuple.variable_count = operands.count;
o->type = tuple;
o->mode = Addressing_Value;
}
gb_temp_arena_memory_end(tmp);
case_end;
case_ast_node(be, BlockExpr, node);
if (c->proc_stack.count == 0) {
error_node(node, "A block expression is only allowed within a procedure");
goto error;
}
for (isize i = be->stmts.count-1; i >= 0; i--) {
if (be->stmts.e[i]->kind != AstNode_EmptyStmt) {
break;
}
be->stmts.count--;
}
if (be->stmts.count == 0) {
error_node(node, "Empty block expression");
goto error;
}
CheckerContext prev_context = c->context;
c->context.type_hint = type_hint;
check_open_scope(c, node);
check_stmt_list(c, be->stmts, Stmt_GiveAllowed);
check_close_scope(c);
c->context = prev_context;
AstNode *give_node = NULL;
if (!check_is_giving(node, &give_node) || give_node == NULL) {
error_node(node, "Missing give statement at end of block expression");
goto error;
}
GB_ASSERT(give_node != NULL && give_node->kind == AstNode_GiveExpr);
be->give_node = give_node;
Type *type = type_of_expr(&c->info, give_node);
if (type == NULL) {
goto error;
} else if (type == t_invalid) {
o->type = t_invalid;
o->mode = Addressing_Invalid;
} else {
o->type = type;
o->mode = Addressing_Value;
}
case_end;
case_ast_node(ie, IfExpr, node);
if (c->proc_stack.count == 0) {
error_node(node, "An if expression is only allowed within a procedure");
goto error;
}
check_open_scope(c, node);
if (ie->init != NULL) {
check_stmt(c, ie->init, 0);
}
Operand operand = {Addressing_Invalid}; Operand operand = {Addressing_Invalid};
check_expr(c, &operand, ie->cond); check_expr(c, &operand, te->cond);
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) { if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
error_node(ie->cond, "Non-boolean condition in if expression"); error_node(te->cond, "Non-boolean condition in if expression");
} }
Operand x = {Addressing_Invalid}; Operand x = {Addressing_Invalid};
Operand y = {Addressing_Invalid}; Operand y = {Addressing_Invalid};
Type *if_type = NULL; check_expr_with_type_hint(c, &x, te->x, type_hint);
Type *else_type = NULL;
if (type_hint) {
gb_printf_err("here\n");
}
check_expr_with_type_hint(c, &x, ie->body, type_hint);
if_type = x.type;
if (ie->else_expr != NULL) { if (te->y != NULL) {
switch (ie->else_expr->kind) { check_expr_with_type_hint(c, &y, te->y, type_hint);
case AstNode_IfExpr:
case AstNode_BlockExpr:
check_expr_with_type_hint(c, &y, ie->else_expr, if_type);
else_type = y.type;
break;
default:
error_node(ie->else_expr, "Invalid else expression in if expression");
break;
}
} else { } else {
error_node(ie->else_expr, "An if expression must have an else expression"); error_node(node, "A ternary expression must have an else clause");
check_close_scope(c);
goto error; goto error;
} }
check_close_scope(c); if (x.type == NULL || x.type == t_invalid ||
y.type == NULL || y.type == t_invalid) {
if (if_type == NULL || if_type == t_invalid ||
else_type == NULL || else_type == t_invalid) {
goto error; goto error;
} }
@@ -4465,16 +4308,16 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
} }
if (!are_types_identical(if_type, else_type)) { if (!are_types_identical(x.type, y.type)) {
gbString its = type_to_string(if_type); gbString its = type_to_string(x.type);
gbString ets = type_to_string(else_type); gbString ets = type_to_string(y.type);
error_node(node, "Mismatched types in if expression, %s vs %s", its, ets); error_node(node, "Mismatched types in ternary expression, %s vs %s", its, ets);
gb_string_free(ets); gb_string_free(ets);
gb_string_free(its); gb_string_free(its);
goto error; goto error;
} }
o->type = if_type; o->type = x.type;
o->mode = Addressing_Value; o->mode = Addressing_Value;
case_end; case_end;
@@ -4489,7 +4332,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
if (cl->type->kind == AstNode_ArrayType && cl->type->ArrayType.count != NULL) { if (cl->type->kind == AstNode_ArrayType && cl->type->ArrayType.count != NULL) {
AstNode *count = cl->type->ArrayType.count; AstNode *count = cl->type->ArrayType.count;
if (count->kind == AstNode_UnaryExpr && if (count->kind == AstNode_UnaryExpr &&
count->UnaryExpr.op.kind == Token_Question) { count->UnaryExpr.op.kind == Token_Ellipsis) {
type = make_type_array(c->allocator, check_type(c, cl->type->ArrayType.elem), -1); type = make_type_array(c->allocator, check_type(c, cl->type->ArrayType.elem), -1);
is_to_be_determined_array_count = true; is_to_be_determined_array_count = true;
} }
@@ -4820,7 +4663,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
} }
switch (ce->token.kind) { switch (ce->token.kind) {
case Token_cast: case Token_cast:
check_conversion(c, o, t); check_cast(c, o, t);
break; break;
case Token_transmute: { case Token_transmute: {
if (o->mode == Addressing_Constant) { if (o->mode == Addressing_Constant) {
@@ -4913,16 +4756,11 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
goto error; goto error;
} }
Entity **variables = gb_alloc_array(c->allocator, Entity *, 2); add_type_info_type(c, o->type);
variables[0] = make_entity_param(c->allocator, NULL, empty_token, t, false, true); add_type_info_type(c, t);
variables[1] = make_entity_param(c->allocator, NULL, empty_token, t_bool, false, true);
Type *tuple = make_type_tuple(c->allocator); o->type = t;
tuple->Tuple.variables = variables; o->mode = Addressing_OptionalOk;
tuple->Tuple.variable_count = 2;
o->type = tuple;
o->mode = Addressing_Value;
} break; } break;
case Token_down_cast: { case Token_down_cast: {
if (o->mode == Addressing_Constant) { if (o->mode == Addressing_Constant) {
@@ -5023,6 +4861,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
} }
Type *t = base_type(type_deref(o->type)); Type *t = base_type(type_deref(o->type));
bool is_ptr = is_type_pointer(o->type);
bool is_const = o->mode == Addressing_Constant; bool is_const = o->mode == Addressing_Constant;
if (is_type_map(t)) { if (is_type_map(t)) {
@@ -5039,7 +4878,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
} }
i64 max_count = -1; i64 max_count = -1;
bool valid = check_set_index_data(o, t, &max_count); bool valid = check_set_index_data(o, t, is_ptr, &max_count);
if (is_const) { if (is_const) {
valid = false; valid = false;
@@ -5048,7 +4887,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
if (!valid && (is_type_struct(t) || is_type_raw_union(t))) { if (!valid && (is_type_struct(t) || is_type_raw_union(t))) {
Entity *found = find_using_index_expr(t); Entity *found = find_using_index_expr(t);
if (found != NULL) { if (found != NULL) {
valid = check_set_index_data(o, found->type, &max_count); valid = check_set_index_data(o, found->type, is_type_pointer(found->type), &max_count);
} }
} }
@@ -5125,7 +4964,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
goto error; goto error;
} }
o->mode = Addressing_Value; if (o->mode != Addressing_Immutable) {
o->mode = Addressing_Value;
}
i64 indices[2] = {0}; i64 indices[2] = {0};
AstNode *nodes[2] = {se->low, se->high}; AstNode *nodes[2] = {se->low, se->high};
@@ -5173,7 +5014,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
} else { } else {
Type *t = base_type(o->type); Type *t = base_type(o->type);
if (t->kind == Type_Pointer) { if (t->kind == Type_Pointer) {
o->mode = Addressing_Variable; if (o->mode != Addressing_Immutable) {
o->mode = Addressing_Variable;
}
o->type = t->Pointer.elem; o->type = t->Pointer.elem;
} else { } else {
gbString str = expr_to_string(o->expr); gbString str = expr_to_string(o->expr);
@@ -5354,12 +5197,6 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
str = gb_string_appendc(str, "}"); str = gb_string_appendc(str, "}");
case_end; case_end;
case_ast_node(be, BlockExpr, node);
str = gb_string_appendc(str, "block expression");
case_end;
case_ast_node(ie, IfExpr, node);
str = gb_string_appendc(str, "if expression");
case_end;
case_ast_node(te, TagExpr, node); case_ast_node(te, TagExpr, node);
str = gb_string_appendc(str, "#"); str = gb_string_appendc(str, "#");
+67 -67
View File
@@ -30,11 +30,6 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
case AstNode_ReturnStmt: case AstNode_ReturnStmt:
error_node(n, "Statements after this `return` are never executed"); error_node(n, "Statements after this `return` are never executed");
break; 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; return false;
} }
Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
if (op_a->mode == Addressing_Invalid || if (rhs->mode == Addressing_Invalid ||
(op_a->type == t_invalid && op_a->mode != Addressing_Overload)) { (rhs->type == t_invalid && rhs->mode != Addressing_Overload)) {
return NULL; return NULL;
} }
AstNode *node = unparen_expr(lhs); AstNode *node = unparen_expr(lhs_node);
// NOTE(bill): Ignore assignments to `_` // NOTE(bill): Ignore assignments to `_`
if (node->kind == AstNode_Ident && if (node->kind == AstNode_Ident &&
str_eq(node->Ident.string, str_lit("_"))) { str_eq(node->Ident.string, str_lit("_"))) {
add_entity_definition(&c->info, node, NULL); add_entity_definition(&c->info, node, NULL);
check_assignment(c, op_a, NULL, str_lit("assignment to `_` identifier")); check_assignment(c, rhs, NULL, str_lit("assignment to `_` identifier"));
if (op_a->mode == Addressing_Invalid) { if (rhs->mode == Addressing_Invalid) {
return NULL; return NULL;
} }
return op_a->type; return rhs->type;
} }
Entity *e = NULL; Entity *e = NULL;
bool used = false; bool used = false;
Operand op_b = {Addressing_Invalid}; Operand lhs = {Addressing_Invalid};
check_expr(c, &op_b, lhs); check_expr(c, &lhs, lhs_node);
if (op_b.mode == Addressing_Invalid || if (lhs.mode == Addressing_Invalid ||
op_b.type == t_invalid) { lhs.type == t_invalid) {
return NULL; return NULL;
} }
if (op_a->mode == Addressing_Overload) { if (rhs->mode == Addressing_Overload) {
isize overload_count = op_a->overload_count; isize overload_count = rhs->overload_count;
Entity **procs = op_a->overload_entities; Entity **procs = rhs->overload_entities;
GB_ASSERT(procs != NULL && overload_count > 0); GB_ASSERT(procs != NULL && overload_count > 0);
// NOTE(bill): These should be done // NOTE(bill): These should be done
@@ -227,19 +222,19 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
Operand x = {0}; Operand x = {0};
x.mode = Addressing_Value; x.mode = Addressing_Value;
x.type = t; 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]; e = procs[i];
add_entity_use(c, op_a->expr, e); add_entity_use(c, rhs->expr, e);
break; break;
} }
} }
if (e != NULL) { if (e != NULL) {
// HACK TODO(bill): Should the entities be freed as it's technically a leak // HACK TODO(bill): Should the entities be freed as it's technically a leak
op_a->mode = Addressing_Value; rhs->mode = Addressing_Value;
op_a->type = e->type; rhs->type = e->type;
op_a->overload_count = 0; rhs->overload_count = 0;
op_a->overload_entities = NULL; rhs->overload_entities = NULL;
} }
} else { } else {
if (node->kind == AstNode_Ident) { if (node->kind == AstNode_Ident) {
@@ -256,43 +251,60 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
e->flags |= EntityFlag_Used; e->flags |= EntityFlag_Used;
} }
Type *assignment_type = op_b.type; Type *assignment_type = lhs.type;
switch (op_b.mode) { switch (lhs.mode) {
case Addressing_Invalid: case Addressing_Invalid:
return NULL; return NULL;
case Addressing_Variable: case Addressing_Variable:
case Addressing_MapIndex:
break; 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: { default: {
if (op_b.expr->kind == AstNode_SelectorExpr) { if (lhs.expr->kind == AstNode_SelectorExpr) {
// NOTE(bill): Extra error checks // NOTE(bill): Extra error checks
Operand op_c = {Addressing_Invalid}; 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); check_expr(c, &op_c, se->expr);
if (op_c.mode == Addressing_MapIndex) { if (op_c.mode == Addressing_MapIndex) {
gbString str = expr_to_string(op_b.expr); gbString str = expr_to_string(lhs.expr);
error_node(op_b.expr, "Cannot assign to record field `%s` in map", str); error_node(lhs.expr, "Cannot assign to record field `%s` in map", str);
gb_string_free(str); gb_string_free(str);
return NULL; return NULL;
} }
} }
gbString str = expr_to_string(op_b.expr); gbString str = expr_to_string(lhs.expr);
if (e != NULL && e->kind == Entity_Variable && e->Variable.is_immutable) { if (lhs.mode == Addressing_Immutable) {
error_node(op_b.expr, "Cannot assign to an immutable: `%s`", str); error_node(lhs.expr, "Cannot assign to an immutable: `%s`", str);
} else { } else {
error_node(op_b.expr, "Cannot assign to `%s`", str); error_node(lhs.expr, "Cannot assign to `%s`", str);
} }
gb_string_free(str); gb_string_free(str);
} break; } break;
} }
check_assignment(c, op_a, assignment_type, str_lit("assignment")); check_assignment(c, rhs, assignment_type, str_lit("assignment"));
if (op_a->mode == Addressing_Invalid) { if (rhs->mode == Addressing_Invalid) {
return NULL; return NULL;
} }
return op_a->type; return rhs->type;
} }
bool check_valid_type_match_type(Type *type, bool *is_union_ptr, bool *is_any) { 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) { if (operand.expr->kind == AstNode_CallExpr) {
return; 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); gbString expr_str = expr_to_string(operand.expr);
error_node(node, "Expression is not used: `%s`", expr_str); error_node(node, "Expression is not used: `%s`", expr_str);
gb_string_free(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) { switch (as->op.kind) {
case Token_Eq: { case Token_Eq: {
// a, b, c = 1, 2, 3; // Multisided // 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"); error(as->op, "Missing lhs in assignment statement");
return; 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); 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 // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation // an extra allocation
Array(Operand) operands; ArrayOperand operands = {0};
array_init_reserve(&operands, c->tmp_allocator, 2 * as->lhs.count); 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) { isize rhs_count = operands.count;
AstNode *rhs = as->rhs.e[i]; for_array(i, operands) {
Operand o = {0}; if (operands.e[i].mode == Addressing_Invalid) {
check_multi_expr(c, &o, rhs); rhs_count--;
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 lhs_count = as->lhs.count; isize max = gb_min(lhs_count, rhs_count);
isize rhs_count = operands.count; for (isize i = 0; i < max; i++) {
check_assignment_variable(c, &operands.e[i], as->lhs.e[i]);
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);
} }
if (lhs_count != rhs_count) { if (lhs_count != rhs_count) {
error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
+42 -33
View File
@@ -106,29 +106,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" #include "types.c"
#define MAP_TYPE Entity * typedef enum AddressingMode {
#define MAP_PROC map_entity_ Addressing_Invalid, // invalid addressing mode
#define MAP_NAME MapEntity Addressing_NoValue, // no value (void in C)
#include "map.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 { typedef struct Operand {
AddressingMode mode; AddressingMode mode;
Type * type; Type * type;
@@ -149,7 +149,9 @@ bool is_operand_value(Operand o) {
switch (o.mode) { switch (o.mode) {
case Addressing_Value: case Addressing_Value:
case Addressing_Variable: case Addressing_Variable:
case Addressing_Immutable:
case Addressing_Constant: case Addressing_Constant:
case Addressing_MapIndex:
return true; return true;
} }
return false; return false;
@@ -159,7 +161,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 { typedef struct DeclInfo {
Scope *scope; Scope *scope;
@@ -173,6 +175,17 @@ typedef struct DeclInfo {
MapBool deps; // Key: Entity * MapBool deps; // Key: Entity *
} DeclInfo; } 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 { typedef struct ExprInfo {
bool is_lhs; // Debug info bool is_lhs; // Debug info
AddressingMode mode; AddressingMode mode;
@@ -185,14 +198,12 @@ ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue
return ei; return ei;
} }
typedef struct ProcedureInfo {
AstFile * file;
Token token; #define MAP_TYPE Entity *
DeclInfo *decl; #define MAP_PROC map_entity_
Type * type; // Type_Procedure #define MAP_NAME MapEntity
AstNode * body; // AstNode_BlockStmt #include "map.c"
u32 tags;
} ProcedureInfo;
typedef struct Scope { typedef struct Scope {
Scope * parent; Scope * parent;
@@ -256,7 +267,7 @@ typedef struct CheckerContext {
Type * type_hint; Type * type_hint;
} CheckerContext; } CheckerContext;
// NOTE(bill): Symbol tables // CheckerInfo stores all the symbol information for a type-checked program
typedef struct CheckerInfo { typedef struct CheckerInfo {
MapTypeAndValue types; // Key: AstNode * | Expression -> Type (and value) MapTypeAndValue types; // Key: AstNode * | Expression -> Type (and value)
MapEntity definitions; // Key: AstNode * | Identifier -> Entity MapEntity definitions; // Key: AstNode * | Identifier -> Entity
@@ -389,9 +400,7 @@ void check_open_scope(Checker *c, AstNode *node) {
node = unparen_expr(node); node = unparen_expr(node);
GB_ASSERT(node->kind == AstNode_Invalid || GB_ASSERT(node->kind == AstNode_Invalid ||
is_ast_node_stmt(node) || is_ast_node_stmt(node) ||
is_ast_node_type(node) || is_ast_node_type(node));
node->kind == AstNode_BlockExpr ||
node->kind == AstNode_IfExpr );
Scope *scope = make_scope(c->context.scope, c->allocator); Scope *scope = make_scope(c->context.scope, c->allocator);
add_scope(c, node, scope); add_scope(c, node, scope);
if (node->kind == AstNode_ProcType) { if (node->kind == AstNode_ProcType) {
+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_TYPE String
#define MAP_PROC map_string_ #define MAP_PROC map_string_
+6 -3
View File
@@ -40,12 +40,15 @@ typedef enum EntityFlag {
EntityFlag_TypeField = 1<<8, EntityFlag_TypeField = 1<<8,
} EntityFlag; } EntityFlag;
// Zero value means the overloading process is not yet done
typedef enum OverloadKind { typedef enum OverloadKind {
Overload_No = -1, Overload_Unknown,
Overload_Unknown = 0, Overload_No,
Overload_Yes = +1, Overload_Yes,
} OverloadKind; } OverloadKind;
// An Entity is a named "thing" in the language
typedef struct Entity Entity; typedef struct Entity Entity;
struct Entity { struct Entity {
EntityKind kind; EntityKind kind;
+63 -66
View File
@@ -2462,13 +2462,19 @@ irValue *ir_emit_down_cast(irProcedure *proc, irValue *value, Type *t) {
return ir_emit_conv(proc, head, t); return ir_emit_conv(proc, head, t);
} }
irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *tuple) { irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, TokenPos pos) {
GB_ASSERT(tuple->kind == Type_Tuple);
gbAllocator a = proc->module->allocator; gbAllocator a = proc->module->allocator;
Type *src_type = ir_type(value); Type *src_type = ir_type(value);
bool is_ptr = is_type_pointer(src_type); bool is_ptr = is_type_pointer(src_type);
bool is_tuple = true;
Type *tuple = type;
if (type->kind != Type_Tuple) {
is_tuple = false;
tuple = make_optional_ok_type(a, type);
}
irValue *v = ir_add_local_generated(proc, tuple); irValue *v = ir_add_local_generated(proc, tuple);
if (is_ptr) { if (is_ptr) {
@@ -2541,6 +2547,25 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *tuple) {
ir_start_block(proc, end_block); ir_start_block(proc, end_block);
} }
if (!is_tuple) {
// NOTE(bill): Panic on invalid conversion
Type *dst_type = tuple->Tuple.variables[0]->type;
irValue *ok = ir_emit_load(proc, ir_emit_struct_ep(proc, v, 1));
irValue **args = gb_alloc_array(a, irValue *, 6);
args[0] = ok;
args[1] = ir_make_const_string(a, pos.file);
args[2] = ir_make_const_int(a, pos.line);
args[3] = ir_make_const_int(a, pos.column);
args[4] = ir_type_info(proc, src_type);
args[5] = ir_type_info(proc, dst_type);
ir_emit_global_call(proc, "__union_cast_check", args, 6);
return ir_emit_load(proc, ir_emit_struct_ep(proc, v, 0));
}
return ir_emit_load(proc, v); return ir_emit_load(proc, v);
} }
@@ -2826,25 +2851,40 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
return ir_addr_load(proc, ir_build_addr(proc, expr)); return ir_addr_load(proc, ir_build_addr(proc, expr));
case_end; case_end;
case_ast_node(be, BlockExpr, expr); case_ast_node(te, TernaryExpr, expr);
ir_emit_comment(proc, str_lit("BlockExpr")); ir_emit_comment(proc, str_lit("TernaryExpr"));
irValueArray edges = {0};
array_init_reserve(&edges, proc->module->allocator, 2);
GB_ASSERT(te->y != NULL);
irBlock *then = ir_new_block(proc, NULL, "if.then");
irBlock *done = ir_new_block(proc, NULL, "if.done"); // NOTE(bill): Append later
irBlock *else_ = ir_new_block(proc, NULL, "if.else");
irValue *cond = ir_build_cond(proc, te->cond, then, else_);
ir_start_block(proc, then);
ir_open_scope(proc); ir_open_scope(proc);
array_add(&edges, ir_build_expr(proc, te->x));
AstNodeArray stmts = be->stmts;
stmts.count--;
ir_build_stmt_list(proc, stmts);
AstNode *give_stmt = be->stmts.e[be->stmts.count-1];
GB_ASSERT(give_stmt->kind == AstNode_ExprStmt);
AstNode *give_expr = give_stmt->ExprStmt.expr;
GB_ASSERT(give_expr->kind == AstNode_GiveExpr);
irValue *value = ir_build_expr(proc, give_expr);
ir_close_scope(proc, irDeferExit_Default, NULL); ir_close_scope(proc, irDeferExit_Default, NULL);
return value; ir_emit_jump(proc, done);
ir_start_block(proc, else_);
ir_open_scope(proc);
array_add(&edges, ir_build_expr(proc, te->y));
ir_close_scope(proc, irDeferExit_Default, NULL);
ir_emit_jump(proc, done);
ir_start_block(proc, done);
Type *type = type_of_expr(proc->module->info, expr);
return ir_emit(proc, ir_make_instr_phi(proc, edges, type));
case_end; case_end;
#if 0
case_ast_node(ie, IfExpr, expr); case_ast_node(ie, IfExpr, expr);
ir_emit_comment(proc, str_lit("IfExpr")); ir_emit_comment(proc, str_lit("IfExpr"));
if (ie->init != NULL) { if (ie->init != NULL) {
@@ -2883,70 +2923,27 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
return ir_emit(proc, ir_make_instr_phi(proc, edges, type)); return ir_emit(proc, ir_make_instr_phi(proc, edges, type));
case_end; case_end;
#endif
case_ast_node(ge, GiveExpr, expr);
ir_emit_comment(proc, str_lit("GiveExpr"));
irValue *v = NULL;
Type *give_type = type_of_expr(proc->module->info, expr);
GB_ASSERT(give_type != NULL);
if (give_type->kind != Type_Tuple) {
v = ir_emit_conv(proc, ir_build_expr(proc, ge->results.e[0]), give_type);
} else {
TypeTuple *tuple = &give_type->Tuple;
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
irValueArray results;
array_init_reserve(&results, proc->module->tmp_allocator, tuple->variable_count);
for_array(res_index, ge->results) {
irValue *res = ir_build_expr(proc, ge->results.e[res_index]);
Type *t = ir_type(res);
if (t->kind == Type_Tuple) {
for (isize i = 0; i < t->Tuple.variable_count; i++) {
Entity *e = t->Tuple.variables[i];
irValue *v = ir_emit_struct_ev(proc, res, i);
array_add(&results, v);
}
} else {
array_add(&results, res);
}
}
v = ir_add_local_generated(proc, give_type);
for_array(i, results) {
Entity *e = tuple->variables[i];
irValue *res = ir_emit_conv(proc, results.e[i], e->type);
irValue *field = ir_emit_struct_ep(proc, v, i);
ir_emit_store(proc, field, res);
}
v = ir_emit_load(proc, v);
gb_temp_arena_memory_end(tmp);
}
return v;
case_end;
case_ast_node(ce, CastExpr, expr); case_ast_node(ce, CastExpr, expr);
Type *type = tv->type; Type *type = tv->type;
irValue *expr = ir_build_expr(proc, ce->expr); irValue *e = ir_build_expr(proc, ce->expr);
switch (ce->token.kind) { switch (ce->token.kind) {
case Token_cast: case Token_cast:
ir_emit_comment(proc, str_lit("cast - cast")); ir_emit_comment(proc, str_lit("cast - cast"));
return ir_emit_conv(proc, expr, type); return ir_emit_conv(proc, e, type);
case Token_transmute: case Token_transmute:
ir_emit_comment(proc, str_lit("cast - transmute")); ir_emit_comment(proc, str_lit("cast - transmute"));
return ir_emit_transmute(proc, expr, type); return ir_emit_transmute(proc, e, type);
case Token_down_cast: case Token_down_cast:
ir_emit_comment(proc, str_lit("cast - down_cast")); ir_emit_comment(proc, str_lit("cast - down_cast"));
return ir_emit_down_cast(proc, expr, type); return ir_emit_down_cast(proc, e, type);
case Token_union_cast: case Token_union_cast:
ir_emit_comment(proc, str_lit("cast - union_cast")); ir_emit_comment(proc, str_lit("cast - union_cast"));
return ir_emit_union_cast(proc, expr, type); return ir_emit_union_cast(proc, e, type, ast_node_token(expr).pos);
default: default:
GB_PANIC("Unknown cast expression"); GB_PANIC("Unknown cast expression");
@@ -3384,7 +3381,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
args[1] = ir_make_const_int(proc->module->allocator, pos.line); args[1] = ir_make_const_int(proc->module->allocator, pos.line);
args[2] = ir_make_const_int(proc->module->allocator, pos.column); args[2] = ir_make_const_int(proc->module->allocator, pos.column);
args[3] = msg; args[3] = msg;
ir_emit_global_call(proc, "__assert", args, 4); ir_emit_global_call(proc, "__panic", args, 4);
return NULL; return NULL;
} break; } break;
+3
View File
@@ -6,6 +6,9 @@
#define MAP_NAME MapString #define MAP_NAME MapString
#include "map.c" #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 #ifndef MAP_UTIL_STUFF
#define MAP_UTIL_STUFF #define MAP_UTIL_STUFF
+126 -146
View File
@@ -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 \ #define AST_NODE_KINDS \
AST_NODE_KIND(Ident, "identifier", Token) \ AST_NODE_KIND(Ident, "identifier", Token) \
AST_NODE_KIND(Implicit, "implicit", Token) \ AST_NODE_KIND(Implicit, "implicit", Token) \
@@ -166,24 +168,9 @@ AST_NODE_KIND(_ExprBegin, "", i32) \
Token open; \ Token open; \
Token close; \ Token close; \
}) \ }) \
AST_NODE_KIND(CastExpr, "cast expression", struct { Token token; AstNode *type, *expr; Token open, 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(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
AST_NODE_KIND(BlockExpr, "block expr", struct { \ AST_NODE_KIND(TernaryExpr, "ternary expression", struct { AstNode *cond, *x, *y; }) \
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(IntervalExpr, "interval expression", struct { Token op; AstNode *left, *right; }) \ AST_NODE_KIND(IntervalExpr, "interval expression", struct { Token op; AstNode *left, *right; }) \
AST_NODE_KIND(_ExprEnd, "", i32) \ AST_NODE_KIND(_ExprEnd, "", i32) \
AST_NODE_KIND(_StmtBegin, "", i32) \ AST_NODE_KIND(_StmtBegin, "", i32) \
@@ -463,9 +450,7 @@ Token ast_node_token(AstNode *node) {
case AstNode_CastExpr: return node->CastExpr.token; case AstNode_CastExpr: return node->CastExpr.token;
case AstNode_FieldValue: return node->FieldValue.eq; case AstNode_FieldValue: return node->FieldValue.eq;
case AstNode_DerefExpr: return node->DerefExpr.op; case AstNode_DerefExpr: return node->DerefExpr.op;
case AstNode_BlockExpr: return node->BlockExpr.open; case AstNode_TernaryExpr: return ast_node_token(node->TernaryExpr.cond);
case AstNode_GiveExpr: return node->GiveExpr.token;
case AstNode_IfExpr: return node->IfExpr.token;
case AstNode_IntervalExpr: return ast_node_token(node->IntervalExpr.left); case AstNode_IntervalExpr: return ast_node_token(node->IntervalExpr.left);
case AstNode_BadStmt: return node->BadStmt.begin; case AstNode_BadStmt: return node->BadStmt.begin;
@@ -766,29 +751,11 @@ AstNode *ast_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token o
return result; return result;
} }
AstNode *ast_ternary_expr(AstFile *f, AstNode *cond, AstNode *x, AstNode *y) {
AstNode *ast_block_expr(AstFile *f, AstNodeArray stmts, Token open, Token close) { AstNode *result = make_ast_node(f, AstNode_TernaryExpr);
AstNode *result = make_ast_node(f, AstNode_BlockExpr); result->TernaryExpr.cond = cond;
result->BlockExpr.stmts = stmts; result->TernaryExpr.x = x;
result->BlockExpr.open = open; result->TernaryExpr.y = y;
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;
return result; return result;
} }
@@ -1319,13 +1286,13 @@ void expect_semicolon(AstFile *f, AstNode *s) {
return; return;
} }
} else { } else {
switch (s->kind) { // switch (s->kind) {
case AstNode_GiveExpr: // case AstNode_GiveExpr:
if (f->curr_token.kind == Token_CloseBrace) { // if (f->curr_token.kind == Token_CloseBrace) {
return; // return;
} // }
break; // break;
} // }
} }
syntax_error(prev_token, "Expected `;` after %.*s, got %.*s", syntax_error(prev_token, "Expected `;` after %.*s, got %.*s",
LIT(ast_node_strings[s->kind]), LIT(token_strings[prev_token.kind])); LIT(ast_node_strings[s->kind]), LIT(token_strings[prev_token.kind]));
@@ -1610,72 +1577,72 @@ AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) {
AstNode *parse_block_expr(AstFile *f) { // AstNode *parse_block_expr(AstFile *f) {
AstNodeArray stmts = {0}; // AstNodeArray stmts = {0};
Token open, close; // Token open, close;
open = expect_token(f, Token_OpenBrace); // open = expect_token(f, Token_OpenBrace);
f->expr_level++; // f->expr_level++;
stmts = parse_stmt_list(f); // stmts = parse_stmt_list(f);
f->expr_level--; // f->expr_level--;
close = expect_token(f, Token_CloseBrace); // close = expect_token(f, Token_CloseBrace);
return ast_block_expr(f, stmts, open, close); // return ast_block_expr(f, stmts, open, close);
} // }
AstNode *parse_if_expr(AstFile *f) { // AstNode *parse_if_expr(AstFile *f) {
if (f->curr_proc == NULL) { // if (f->curr_proc == NULL) {
syntax_error(f->curr_token, "You cannot use an if expression in the file scope"); // 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); // return ast_bad_stmt(f, f->curr_token, f->curr_token);
} // }
Token token = expect_token(f, Token_if); // Token token = expect_token(f, Token_if);
AstNode *init = NULL; // AstNode *init = NULL;
AstNode *cond = NULL; // AstNode *cond = NULL;
AstNode *body = NULL; // AstNode *body = NULL;
AstNode *else_expr = NULL; // AstNode *else_expr = NULL;
isize prev_level = f->expr_level; // isize prev_level = f->expr_level;
f->expr_level = -1; // f->expr_level = -1;
if (allow_token(f, Token_Semicolon)) { // if (allow_token(f, Token_Semicolon)) {
cond = parse_expr(f, false); // cond = parse_expr(f, false);
} else { // } else {
init = parse_simple_stmt(f, false); // init = parse_simple_stmt(f, false);
if (allow_token(f, Token_Semicolon)) { // if (allow_token(f, Token_Semicolon)) {
cond = parse_expr(f, false); // cond = parse_expr(f, false);
} else { // } else {
cond = convert_stmt_to_expr(f, init, str_lit("boolean expression")); // cond = convert_stmt_to_expr(f, init, str_lit("boolean expression"));
init = NULL; // init = NULL;
} // }
} // }
f->expr_level = prev_level; // f->expr_level = prev_level;
if (cond == NULL) { // if (cond == NULL) {
syntax_error(f->curr_token, "Expected condition for if statement"); // 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)) { // if (allow_token(f, Token_else)) {
switch (f->curr_token.kind) { // switch (f->curr_token.kind) {
case Token_if: // case Token_if:
else_expr = parse_if_expr(f); // else_expr = parse_if_expr(f);
break; // break;
case Token_OpenBrace: // case Token_OpenBrace:
else_expr = parse_block_expr(f); // else_expr = parse_block_expr(f);
break; // break;
default: // default:
syntax_error(f->curr_token, "Expected if expression block statement"); // 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]); // else_expr = ast_bad_expr(f, f->curr_token, f->tokens.e[f->curr_token_index+1]);
break; // break;
} // }
} else { // } else {
syntax_error(f->curr_token, "An if expression must have an else clause"); // 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_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 *parse_operand(AstFile *f, bool lhs) {
AstNode *operand = NULL; // Operand AstNode *operand = NULL; // Operand
@@ -1789,16 +1756,16 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
return type; return type;
} }
case Token_if: // case Token_if:
if (!lhs && f->expr_level >= 0) { // if (!lhs && f->expr_level >= 0) {
return parse_if_expr(f); // return parse_if_expr(f);
} // }
break; // break;
case Token_OpenBrace: // case Token_OpenBrace:
if (!lhs && f->expr_level >= 0) { // if (!lhs && f->expr_level >= 0) {
return parse_block_expr(f); // return parse_block_expr(f);
} // }
break; // break;
default: { default: {
AstNode *type = parse_type_or_ident(f); AstNode *type = parse_type_or_ident(f);
@@ -1982,6 +1949,19 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
} }
break; break;
case Token_Question:
if (!lhs && operand != NULL && f->expr_level >= 0) {
AstNode *cond = operand;
Token token_q = expect_token(f, Token_Question);
AstNode *x = parse_expr(f, false);
Token token_c = expect_token(f, Token_Colon);
AstNode *y = parse_expr(f, false);
operand = ast_ternary_expr(f, cond, x, y);
} else {
loop = false;
}
break;
default: default:
loop = false; loop = false;
break; break;
@@ -2358,7 +2338,7 @@ bool is_token_field_prefix(TokenKind kind) {
switch (kind) { switch (kind) {
case Token_using: case Token_using:
case Token_no_alias: case Token_no_alias:
// case Token_immutable: case Token_immutable:
return true; return true;
} }
return false; return false;
@@ -2374,7 +2354,7 @@ u32 parse_field_prefixes(AstFile *f) {
switch (f->curr_token.kind) { switch (f->curr_token.kind) {
case Token_using: using_count += 1; next_token(f); break; case Token_using: using_count += 1; next_token(f); break;
case Token_no_alias: no_alias_count += 1; next_token(f); break; case Token_no_alias: no_alias_count += 1; next_token(f); break;
// case Token_immutable: immutable_count += 1; next_token(f); break; case Token_immutable: immutable_count += 1; next_token(f); break;
} }
} }
if (using_count > 1) syntax_error(f->curr_token, "Multiple `using` in this field list"); if (using_count > 1) syntax_error(f->curr_token, "Multiple `using` in this field list");
@@ -2572,8 +2552,8 @@ AstNode *parse_type_or_ident(AstFile *f) {
AstNode *count_expr = NULL; AstNode *count_expr = NULL;
bool is_vector = false; bool is_vector = false;
if (f->curr_token.kind == Token_Question) { if (f->curr_token.kind == Token_Ellipsis) {
count_expr = ast_unary_expr(f, expect_token(f, Token_Question), NULL); count_expr = ast_unary_expr(f, expect_token(f, Token_Ellipsis), NULL);
} else if (f->curr_token.kind == Token_vector) { } else if (f->curr_token.kind == Token_vector) {
next_token(f); next_token(f);
if (f->curr_token.kind != Token_CloseBracket) { if (f->curr_token.kind != Token_CloseBracket) {
@@ -2584,7 +2564,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
syntax_error(f->curr_token, "Vector type missing count"); syntax_error(f->curr_token, "Vector type missing count");
} }
is_vector = true; is_vector = true;
} else if (f->curr_token.kind == Token_Ellipsis) { } else if (f->curr_token.kind == Token_dynamic) {
next_token(f); next_token(f);
expect_token(f, Token_CloseBracket); expect_token(f, Token_CloseBracket);
return ast_dynamic_array_type(f, token, parse_type(f)); return ast_dynamic_array_type(f, token, parse_type(f));
@@ -2923,27 +2903,27 @@ AstNode *parse_return_stmt(AstFile *f) {
} }
AstNode *parse_give_stmt(AstFile *f) { // AstNode *parse_give_stmt(AstFile *f) {
if (f->curr_proc == NULL) { // if (f->curr_proc == NULL) {
syntax_error(f->curr_token, "You cannot use a give statement in the file scope"); // 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); // return ast_bad_stmt(f, f->curr_token, f->curr_token);
} // }
if (f->expr_level == 0) { // if (f->expr_level == 0) {
syntax_error(f->curr_token, "A give statement must be used within an expression"); // 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); // return ast_bad_stmt(f, f->curr_token, f->curr_token);
} // }
Token token = expect_token(f, Token_give); // Token token = expect_token(f, Token_give);
AstNodeArray results; // AstNodeArray results;
if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) { // if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) {
results = parse_rhs_expr_list(f); // results = parse_rhs_expr_list(f);
} else { // } else {
results = make_ast_node_array(f); // results = make_ast_node_array(f);
} // }
AstNode *ge = ast_give_expr(f, token, results); // AstNode *ge = ast_give_expr(f, token, results);
expect_semicolon(f, ge); // expect_semicolon(f, ge);
return ast_expr_stmt(f, ge); // return ast_expr_stmt(f, ge);
} // }
AstNode *parse_for_stmt(AstFile *f) { AstNode *parse_for_stmt(AstFile *f) {
if (f->curr_proc == NULL) { if (f->curr_proc == NULL) {
@@ -3225,7 +3205,7 @@ AstNode *parse_stmt(AstFile *f) {
case Token_defer: return parse_defer_stmt(f); case Token_defer: return parse_defer_stmt(f);
case Token_asm: return parse_asm_stmt(f); case Token_asm: return parse_asm_stmt(f);
case Token_return: return parse_return_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_break:
case Token_continue: case Token_continue:
@@ -3272,7 +3252,7 @@ AstNode *parse_stmt(AstFile *f) {
return ast_bad_stmt(f, token, f->curr_token); return ast_bad_stmt(f, token, f->curr_token);
} break; } break;
#if 0 #if 1
case Token_immutable: { case Token_immutable: {
Token token = expect_token(f, Token_immutable); Token token = expect_token(f, Token_immutable);
AstNode *node = parse_stmt(f); AstNode *node = parse_stmt(f);
+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} #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 { typedef struct String16 {
wchar_t *text; wchar_t *text;
isize len; isize len;
+3
View File
@@ -99,9 +99,12 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_raw_union, "raw_union"), \ TOKEN_KIND(Token_raw_union, "raw_union"), \
TOKEN_KIND(Token_enum, "enum"), \ TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_vector, "vector"), \ TOKEN_KIND(Token_vector, "vector"), \
TOKEN_KIND(Token_static, "static"), \
TOKEN_KIND(Token_dynamic, "dynamic"), \
TOKEN_KIND(Token_map, "map"), \ TOKEN_KIND(Token_map, "map"), \
TOKEN_KIND(Token_using, "using"), \ TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_no_alias, "no_alias"), \ TOKEN_KIND(Token_no_alias, "no_alias"), \
TOKEN_KIND(Token_immutable, "immutable"), \
TOKEN_KIND(Token_cast, "cast"), \ TOKEN_KIND(Token_cast, "cast"), \
TOKEN_KIND(Token_transmute, "transmute"), \ TOKEN_KIND(Token_transmute, "transmute"), \
TOKEN_KIND(Token_down_cast, "down_cast"), \ TOKEN_KIND(Token_down_cast, "down_cast"), \
+9 -8
View File
@@ -178,8 +178,9 @@ typedef struct Type {
bool failure; bool failure;
} Type; } Type;
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 { typedef struct Selection {
Entity * entity; Entity * entity;
Array_i32 index; Array_i32 index;
@@ -195,6 +196,7 @@ Selection make_selection(Entity *entity, Array_i32 index, bool indirect) {
void selection_add_index(Selection *s, isize index) { void selection_add_index(Selection *s, isize index) {
// IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form // IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form
// of heap allocation // 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) { if (s->index.e == NULL) {
array_init(&s->index, heap_allocator()); array_init(&s->index, heap_allocator());
} }
@@ -277,6 +279,7 @@ gb_global Type *t_byte_slice = NULL;
gb_global Type *t_string_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 = NULL;
gb_global Type *t_type_info_record = NULL; gb_global Type *t_type_info_record = NULL;
gb_global Type *t_type_info_enum_value = NULL; gb_global Type *t_type_info_enum_value = NULL;
@@ -303,7 +306,6 @@ gb_global Type *t_type_info_raw_union = NULL;
gb_global Type *t_type_info_enum = NULL; gb_global Type *t_type_info_enum = NULL;
gb_global Type *t_type_info_map = NULL; gb_global Type *t_type_info_map = NULL;
gb_global Type *t_type_info_named_ptr = 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_integer_ptr = NULL;
gb_global Type *t_type_info_float_ptr = NULL; gb_global Type *t_type_info_float_ptr = NULL;
@@ -323,8 +325,6 @@ gb_global Type *t_type_info_raw_union_ptr = NULL;
gb_global Type *t_type_info_enum_ptr = NULL; gb_global Type *t_type_info_enum_ptr = NULL;
gb_global Type *t_type_info_map_ptr = NULL; gb_global Type *t_type_info_map_ptr = NULL;
gb_global Type *t_allocator = NULL; gb_global Type *t_allocator = NULL;
gb_global Type *t_allocator_ptr = NULL; gb_global Type *t_allocator_ptr = NULL;
gb_global Type *t_context = NULL; gb_global Type *t_context = NULL;
@@ -337,14 +337,15 @@ 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);
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); gbString type_to_string(Type *type);
Type *base_type(Type *t) { Type *base_type(Type *t) {
for (;;) { for (;;) {
if (t == NULL) { if (t == NULL) {