diff --git a/examples/basic.odin b/examples/basic.odin index c9a54d15a..96282ccd8 100644 --- a/examples/basic.odin +++ b/examples/basic.odin @@ -3,166 +3,166 @@ #load "file.odin" print_string :: proc(s: string) { - file_write(file_get_standard(FileStandard.OUTPUT), s as []byte); + file_write(file_get_standard(FileStandard.OUTPUT), s as []byte) } byte_reverse :: proc(b: []byte) { - n := len(b); + n := len(b) for i := 0; i < n/2; i++ { - b[i], b[n-1-i] = b[n-1-i], b[i]; + b[i], b[n-1-i] = b[n-1-i], b[i] } } encode_rune :: proc(r: rune) -> ([4]byte, int) { - buf: [4]byte; - i := r as u32; - mask: byte : 0x3f; + buf: [4]byte + i := r as u32 + mask: byte : 0x3f if i <= 1<<7-1 { - buf[0] = r as byte; - return buf, 1; + buf[0] = r as byte + return buf, 1 } if i <= 1<<11-1 { - buf[0] = 0xc0 | (r>>6) as byte; - buf[1] = 0x80 | (r) as byte & mask; - return buf, 2; + buf[0] = 0xc0 | (r>>6) as byte + buf[1] = 0x80 | (r) as byte & mask + return buf, 2 } // Invalid or Surrogate range if i > 0x0010ffff || (i >= 0xd800 && i <= 0xdfff) { - r = 0xfffd; + r = 0xfffd } if i <= 1<<16-1 { - buf[0] = 0xe0 | (r>>12) as byte; - buf[1] = 0x80 | (r>>6) as byte & mask; - buf[2] = 0x80 | (r) as byte & mask; - return buf, 3; + buf[0] = 0xe0 | (r>>12) as byte + buf[1] = 0x80 | (r>>6) as byte & mask + buf[2] = 0x80 | (r) as byte & mask + return buf, 3 } - buf[0] = 0xf0 | (r>>18) as byte; - buf[1] = 0x80 | (r>>12) as byte & mask; - buf[2] = 0x80 | (r>>6) as byte & mask; - buf[3] = 0x80 | (r) as byte & mask; - return buf, 4; + buf[0] = 0xf0 | (r>>18) as byte + buf[1] = 0x80 | (r>>12) as byte & mask + buf[2] = 0x80 | (r>>6) as byte & mask + buf[3] = 0x80 | (r) as byte & mask + return buf, 4 } print_rune :: proc(r: rune) { - buf, n := encode_rune(r); - str := buf[:n] as string; - print_string(str); + buf, n := encode_rune(r) + str := buf[:n] as string + print_string(str) } -print_space :: proc() { print_rune(#rune " "); } -print_nl :: proc() { print_rune(#rune "\n"); } +print_space :: proc() { print_rune(#rune " ") } +print_nl :: proc() { print_rune(#rune "\n") } print_int :: proc(i: int) { print_int_base(i, 10); } print_int_base :: proc(i, base: int) { - NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"; + NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$" - buf: [65]byte; - len := 0; - negative := false; + buf: [65]byte + len := 0 + negative := false if i < 0 { - negative = true; - i = -i; + negative = true + i = -i } if i == 0 { - buf[len] = #rune "0"; - len++; + buf[len] = #rune "0" + len++ } for i > 0 { - buf[len] = NUM_TO_CHAR_TABLE[i % base]; + buf[len] = NUM_TO_CHAR_TABLE[i % base] len++; - i /= base; + i /= base } if negative { - buf[len] = #rune "-"; - len++; + buf[len] = #rune "-" + len++ } - byte_reverse(buf[:len]); - print_string(buf[:len] as string); + byte_reverse(buf[:len]) + print_string(buf[:len] as string) } print_uint :: proc(i: uint) { - print__uint(i, 10, 0, #rune " "); + print__uint(i, 10, 0, #rune " ") } print__uint :: proc(i, base: uint, min_width: int, pad_char: byte) { - NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"; + NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$" - buf: [65]byte; - len := 0; + buf: [65]byte + len := 0 if i == 0 { - buf[len] = #rune "0"; - len++; + buf[len] = #rune "0" + len++ } for i > 0 { - buf[len] = NUM_TO_CHAR_TABLE[i % base]; - len++; - i /= base; + buf[len] = NUM_TO_CHAR_TABLE[i % base] + len++ + i /= base } for len < min_width { - buf[len] = pad_char; - len++; + buf[len] = pad_char + len++ } - byte_reverse(buf[:len]); - print_string(buf[:len] as string); + byte_reverse(buf[:len]) + print_string(buf[:len] as string) } print_bool :: proc(b : bool) { - if b { print_string("true"); } - else { print_string("false"); } + if b { print_string("true") } + else { print_string("false") } } -print_pointer :: proc(p: rawptr) #inline { print__uint(p as uint, 16, 0, #rune " "); } +print_pointer :: proc(p: rawptr) #inline { print__uint(p as uint, 16, 0, #rune " ") } -print_f32 :: proc(f: f32) #inline { print__f64(f as f64, 7); } -print_f64 :: proc(f: f64) #inline { print__f64(f, 10); } +print_f32 :: proc(f: f32) #inline { print__f64(f as f64, 7) } +print_f64 :: proc(f: f64) #inline { print__f64(f, 10) } print__f64 :: proc(f: f64, decimal_places: int) { if f == 0 { - print_rune(#rune "0"); - return; + print_rune(#rune "0") + return } if f < 0 { - print_rune(#rune "-"); - f = -f; + print_rune(#rune "-") + f = -f } print_u64 :: proc(i: u64) { - NUM_TO_CHAR_TABLE :: "0123456789"; + NUM_TO_CHAR_TABLE :: "0123456789" - buf: [22]byte; - len := 0; + buf: [22]byte + len := 0 if i == 0 { - buf[len] = #rune "0"; - len++; + buf[len] = #rune "0" + len++ } for i > 0 { - buf[len] = NUM_TO_CHAR_TABLE[i % 10]; - len++; - i /= 10; + buf[len] = NUM_TO_CHAR_TABLE[i % 10] + len++ + i /= 10 } - byte_reverse(buf[:len]); - print_string(buf[:len] as string); + byte_reverse(buf[:len]) + print_string(buf[:len] as string) } - i := f as u64; - print_u64(i); - f -= i as f64; + i := f as u64 + print_u64(i) + f -= i as f64 - print_rune(#rune "."); + print_rune(#rune ".") - mult := 10.0; + mult := 10.0 for decimal_places := 6; decimal_places >= 0; decimal_places-- { - i = (f * mult) as u64; - print_u64(i as u64); - f -= i as f64 / mult; - mult *= 10; + i = (f * mult) as u64 + print_u64(i as u64) + f -= i as f64 / mult + mult *= 10 } } diff --git a/examples/demo.odin b/examples/demo.odin index 07fa7b1d5..84845a3e0 100644 --- a/examples/demo.odin +++ b/examples/demo.odin @@ -3,760 +3,28 @@ #load "game.odin" main :: proc() { - // _ = hellope(); - // variables(); - // procedures(); - // constants(); - // types(); - // data_control(); - // using_fields(); - - Entity :: type struct { - guid: u64; - name: string; - } - - Frog :: type struct { - using entity: Entity; - jump_height: f32; - } - - - e: Entity; - frog : Frog; - frog.name = "Ribbit"; - - a: [16]u32; - x := ^a[1]; - y := ^a[5]; - d := ptr_sub(y, ptr_offset(x, 1)); - print_int(d); nl(); Thing :: type struct { - CONSTANT :: 123; - Thing :: type struct { - y: f32; - - z: int; - w: int; - } - - x: Thing; - } - - test :: proc() -> int { - t_outer: Thing; - t_outer.x = Thing.Thing{}; - using Thing; - t_inner: Thing; - t_inner.y = 1; - print_int(CONSTANT); nl(); - return CONSTANT; - } - - test__ := test(); - - - - // run_game(); -} - - -hellope :: proc() -> int { - print_string("Hellope, 世界\n"); - return 1; -} - - -// Line comment -/* - Block Comment -*/ -/* - Nested /* - Block /* - Comment - */ - */ -*/ - -apple, banana, carrot: bool; -box, carboard: bool = true, false; -hellope_value: int = hellope(); // The procedure is ran just before `main` - -variables :: proc() { - i: int; // initialized with zero value - j: int = 1; - x, y: int = 1, 2; - - // Type inference - apple, banana, 世界 := true, 123, "world"; - - - // Basic Types of the Language - // - // bool - // - // i8 i16 i32 i64 i128 - // u8 u16 u32 u64 u128 - // - // f32 f64 - // - // int uint (size_of(int) == size_of(uint) == size_of(rawptr)) - // - // rawptr (equivalent to void * in C/C++) - // - // string - // - // byte - alias for u8 - // rune - alias for i32 // Unicode Codepoint - // - // "untyped" types can implicitly convert to any of the "typed" types - // Default Type - // untyped bool - bool - // untyped integer - int - // untyped float - f64 - // untyped pointer - rawptr - // untyped string - string - // untyped rune - rune/i32 - - - // Zero values - zero_numeric := 0; - zero_boolean := false; - zero_pointer := null; - zero_string1 := ""; // Escaped string - zero_string2 := ``; // Raw string - // Compound types have a different kind of zero value - - // Unary operators - // +a - // -a - // ~a - // !a - - // Binary operators - // a + b add - // a - b sub - // a ~ b xor - // a | b or - - // a * b mul - // a / b quo - // a % b mod - // a & b and - // a &~ b bitclear == a & (~b) - // a << b shl - // a >> b shr - - // a as Type // Type cast - // a transmute Type // Bit cast - - // a == b eq - // a != b ne - // a < b lt - // a > b gt - // a <= b le - // a >= b ge - -} - -procedures :: proc() { - add :: proc(x: int, y: int) -> int { - return x + y; - } - print_int(add(3, 4)); // 7 - print_nl(); - - add_v2 :: proc(x, y: int) -> int { - return x + y; - } - - fibonacci :: proc(n: int) -> int { - if n < 2 { - return n; - } - return fibonacci(n-1) + fibonacci(n-2); - } - print_int(fibonacci(12)); nl(); - - - swap_strings :: proc(x, y: string) -> (string, string) { - return y, x; - } - a, b := swap_strings("Hellope\n", "World\n"); - print_string(a); - print_string(b); - - a, b = b, a; // Quirk of grammar the of multiple assignments - // Swap variables - print_string(a); - print_string(b); - - // Not a hint like C/C++, it's mandatory (unless it cannot do it but it will warn) - proc1 :: proc(a, b: int) #inline { - print_int(a + b); - } - proc2 :: proc(a, b: int) #no_inline { - print_int(a + b); - } - - print_int(3 ''add 4); // Infix style - print_nl(); - print_int(12 'fibonacci); // Postfix style - print_nl(); -} - - -TAU :: 6.28318530718; - -constants :: proc() { - TAU :: 6.28318530718; // untyped float - WORLD_JAPANESE :: "世界"; // untyped string - - TAU_32 : f32 : 6.28318530718; - TAU_AS_32 :: 6.28318530718 as f32; - - PI :: TAU / 2; - - CLOSE_TO_PI :: 3; - - DIFF :: (PI - CLOSE_TO_PI) / PI; // Evaluated at compile time - - a := TAU; // the constant's value becomes typed as f64 - b := CLOSE_TO_PI; // the constant's value becomes typed as int - c := DIFF; -} - -nl :: proc() { print_nl(); } - -types :: proc() { - - x: int = 123; - y := x; // y: int = x; - // z: f32 = x; // invalid - z: f32 = x as f32; - - - ptr_z := ^z; // Pascal notation - ptr_z^ = 123; // Derefence Notation - w: f32 = ptr_z^; // 123 - print_f32(z); nl(); - - // ^z - pointer to z - // z^ - z from pointer - - // Implicit conversion to and from rawptr - r_ptr: rawptr = ptr_z; - ptr_z = r_ptr; - - - - f32_array: [12]f32; // Array of 12 f32 - f32_array[0] = 2; - f32_array[1] = 3; - // f32_array[-1] = 2; // Error - compile time check - // f32_array[13] = 2; // Error - compile time check - f32_array_len := len(f32_array); // builtin procedure - f32_array_cap := cap(f32_array); // == len(f32_array) - - - mda: [2][3][4]int; // Column-major - // mda[x][y][z] - - - api: [2]^f32; - papi: ^[2]^f32; - - - - - f32_slice: []f32; // Slice / Array reference - f32_slice = f32_array[0:5]; - f32_slice = f32_array[:5]; - f32_slice = f32_array[:]; // f32_array[0:len(f32_array)-1]; - - f32_slice = f32_array[1:5:7]; // low:1, high:5, max:7 - // len: 5-1 == 4 - // cap: 7-1 == 6 - - - - append_success := append(^f32_slice, 1); - _ = append(^f32_slice, 2); - - _ = copy(f32_array[0:2], f32_array[2:4]); // You can use memcpy/memmove if you want - - - - - - s := "Hellope World"; - sub_string: string = s[5:10]; - - - - - - v0: {4}f32; // Vector of 4 f32 - v0[0] = 1; - v0[1] = 3; - v0[2] = 6; - v0[3] = 10; - - v1 := v0 + v0; // Simd Arithmetic - v1 = v1 - v0; - v1 *= v0; // i.e. hadamard product - v1 /= v0; - - // builtin procedure - v2 := swizzle(v0, 3, 2, 1, 0); // {10, 6, 3, 1} - - v3: {4}bool = v0 == v2; - // LLVM rant? - - - - - - - - Vec4 :: type {4}f32; - Array3Int :: type [3]int; - - Vec3 :: type struct { - x, y, z: f32; - } - - BinaryNode :: type struct { - left, right: ^BinaryNode; // same format as procedure argument - data: rawptr; - } - - AddProc :: type proc(a, b: int) -> int - - Packed :: type struct #packed { - a: u8; - b: u16; - c: u32; - } - static_assert(size_of(Packed) == 7); // builtin procedure - - - { - MyInt :: type int; - x: int = 1; - y: MyInt = 2; - // z := x + y; // Failure - types cannot implicit convert* - z := x as MyInt + y; // Type cast using `as` - } - - - { - // From: Quake III Arena - Q_rsqrt :: proc(number: f32) -> f32 { - i: i32; - x2, y: f32; - THREE_HALFS :: 1.5; - - x2 = number * 0.5; - y = number; - i = (^y as ^i32)^; // evil floating point bit level hacking - i = 0x5f3759df - i>>1; // what the fuck? - y = (^i as ^f32)^; - y = y * (THREE_HALFS - (x2 * y *y)); // 1st iteration - // y = y * (THREE_HALFS - (x2 * y *y)); // 2nd iteration, this can be removed - return y; - } - - Q_rsqrt_v2 :: proc(number: f32) -> f32 { - THREE_HALFS :: 1.5; - - x2 := number * 0.5; - y := number; - i := y transmute i32; // evil floating point bit level hacking - i = 0x5f3759df - i>>1; // what the fuck? - y = i transmute f32; - y = y * (THREE_HALFS - (x2 * y *y)); // 1st iteration - // y = y * (THREE_HALFS - (x2 * y *y)); // 2nd iteration, this can be removed - return y; - } - - // NOTE(bill): transmute only works if the size of the types are equal - - /* - // in C - union { - i32 i; - f32 y; - }; - */ - } - - { // Enumeration - Thing :: type enum { - APPLE, - FROG, - TREE, - TOMB, - } - a := Thing.APPLE; - - Sized :: type enum u64 { - APPLE, - FROG, - TREE, - TOMB, - } - static_assert(size_of(Sized) == size_of(u64)); - - Certain :: type enum { - APPLE = 3, - FROG, - TREE = 7, - TOMB, - } - static_assert(Certain.TOMB == 8); - } - - { // Untagged union - BitHack :: type union { - i: i32; - f: f32; - } - b: BitHack; - b.f = 123; - print_int_base(b.i as int, 16); print_nl(); - - - - // Manually tagged union - - EntityKind :: type enum { - Invalid, - Constant, - Variable, - TypeName, - Procedure, - Builtin, - Count, - } - - Entity :: type struct { - kind: EntityKind; - guid: u64; - - // Other data - - /*using*/ - data: union { - constant: struct{}; - variable: struct{ - visited, is_field, used, anonymous: bool; - }; - procedure: struct { used: bool; }; - buitlin: struct { id: i32; }; - }; - } - - - // NOTE(bill): Tagged unions are not added yet but are planned - } - - - - { // Compound Literals - a := [3]int{1, 2, 3}; - b := [3]int{}; - c := [..]int{1, 2, 3}; - - d := []int{1, 2, 3}; // slice - - e := {4}f32{1, 2, 3, 4}; - f := {4}f32{1}; // broadcasts to all - // g := {4}f32{1, 2}; // require either 1 or 4 elements - - Vec2 :: type {2}f32; - - h := Vec2{1, 2}; - - i := Vec2{5} * h; // For strong type safety - // FORENOTE: 5 * h was originally allowed but it was an edge case in the - // compiler I didn't think it was enough to justify have it it. - - print_f32(i[0]); print_rune(#rune ","); - print_f32(i[1]); print_nl(); - } - - - - { // First class procedures - - do_thing :: proc(p: proc(a, b: int) -> int) { - print_int(p(3, 4)); nl(); - } - - add :: proc(a, b: int) -> int { - return a + b; - } - - - add_lambda := proc(a, b: int) -> int { - return a - b; - }; // note semicolon - - do_thing(add); - do_thing(add_lambda); - do_thing(proc(a, b: int) -> int { // Anonymous - return a * b; - }); - } - - - - { // strings and runes - escaped := "Hellope World\n"; - raw := `Hellope World\n`; - print_string(escaped); - print_string(raw); nl(); - - // Crap shader example - shader_string := -`#version 410 - -layout (location = 0) in vec3 a_position; -layout (location = 1) in vec3 a_normal; -layout (location = 2) in vec2 a_tex_coord; - -out vec3 v_position; -out vec3 v_normal; -out vec2 v_tex_coord; - -uniform mat4 u_model_view; -uniform mat3 u_normal; -uniform mat4 u_proj; -uniform mat4 u_mvp; - -void main() { - v_tex_coord = a_tex_coord; - v_normal = normalize(u_normal * a_normal); - v_position = vec3(u_model_view * vec4(a_position, 1.0)); - - gl_Position = u_mvp * vec4(a_position, 1.0); -}`; - - - hearts1 := #rune "💕"; - hearts2 := #rune "\U0001f495"; // 32 bit - hearts3 := #rune "\xf0\x9f\x92\x95"; - - 㐒 := #rune "㐒"; - 㐒16 := #rune "\u4db5"; // 16 bit but will be `rune` - // String ideas "nicked" from Go, so far. I think I might change how some of it works later. - } - - - { // size, align, offset - Thing :: type struct { - a: u8; - b: u16; - c, d, e: u32; - } - - s := size_of(Thing); - a := align_of(Thing); - o := offset_of(Thing, b); - - t: Thing; - - sv := size_of_val(t); - av := align_of_val(t); - ov := offset_of_val(t.b); - } -} - -data_control :: proc() { - sum := 0; - for i := 0; i < 12; i++ { - sum += 1; - } - print_string("sum = "); print_int(sum); nl(); - - sum = 1; - for ; sum < 1000000; { - sum += sum; - } - print_string("sum = "); print_int(sum); nl(); - - sum = 1; - for sum < 1000000 { - sum += sum; - } - print_string("sum = "); print_int(sum); nl(); - - // loop - // for { } == for true {} - - // Question: Should I separate all these concepts and rename it? - // - // range - iterable - // for - c style - // while - // loop - while true - - // Notes: - // conditions _must_ a boolean expression - // i++ and i-- are statements, not expressions - - - x := 2; - if x < 3 { - print_string("x < 2\n"); - } - - // Unified initializer syntax - same as for statements - if x := 2; x < 3 { - print_string("x < 2\n"); - } - - if x := 4; x < 3 { - print_string("Never called\n"); - } else { - print_string("This is called\n"); - } - - { // String comparison - a := "Hellope"; - b := "World"; - if a < b { - print_string("a < b\n"); - } - if a != b { - print_string("a != b\n"); - } - - } - - - - - { // Defer statement - defer print_string("日本語\n"); - print_string("Japanese\n"); + using x: struct { a, b: int } } { - defer print_string("1\n"); - defer print_string("2\n"); - defer print_string("3\n"); + using t := new(Thing) + defer delete(t) + a = 321 + print_int(a); nl() } - { - prev_allocator := context.allocator; - context.allocator = __default_allocator(); - defer context.allocator = prev_allocator; + // { + // using t := new(Thing) + // defer delete(t) + // a = 1337 + // print_int(a); nl() + // } - File :: type struct { filename: string; }; - FileError :: type int; - open_file :: proc(filename: string) -> (File, FileError) { - return File{}, 0; - } - close_file :: proc(f: ^File) {} - f, err := open_file("Test"); - if err != 0 { - // handle error - } - defer close_file(^f); - - // Rest of code!!! - } - - for i := 0; i < 100; i++ { - blah := new(int); - defer { - defer print_string("!"); - defer print_int(i); - defer print_string("dealloc"); - delete(blah); - } - - if i == 3 { - // defers called - continue; - } - - if i == 5 { - // defers called - return; // End of procedure - } - - if i == 8 { - // defers called - break; // never happens - } - } - - defer print_string("It'll never happen, mate 1"); - print_string("It'll never happen, mate 2"); - print_string("It'll never happen, mate 3"); + // run_game() } -using_fields :: proc() { - { // Everyday stuff - Vec3 :: type struct { x, y, z: f32; } - - Entity :: type struct { - name: string; - using pos: Vec3; - vel: Vec3; - } - t: Entity; - t.y = 456; - print_f32(t.y); print_nl(); - print_f32(t.pos.y); print_nl(); - print_f32(t.vel.y); print_nl(); - - - Frog :: type struct { // Subtype (kind of) - using entity: Entity; - colour: u32; - jump_height: f32; - } - - f: Frog; - f.y = 1337; - print_f32(f.y); print_nl(); - print_f32(f.pos.y); print_nl(); - print_f32(f.vel.y); print_nl(); - - - Buffalo :: type struct { - using entity: Entity; - speed: f32; - noise_level: f32; - } - } - - - { // Crazy Shit - Vec2 :: type union { - using _xy: struct { x, y: f32; }; - e: [2]f32; - v: {2}f32; - } - - Entity :: type struct { - using pos: ^Vec2; - name: string; - } - t: Entity; - t.pos = new(Vec2); - defer delete(t.pos); - t.x = 123; - print_f32(t._xy.x); print_nl(); - print_f32(t.pos.x); print_nl(); - print_f32(t.pos._xy.x); print_nl(); - } -} +nl :: proc() #inline { print_nl() } diff --git a/examples/file.odin b/examples/file.odin index a4011520a..5b3aa9f8c 100644 --- a/examples/file.odin +++ b/examples/file.odin @@ -1,37 +1,37 @@ #load "win32.odin" File :: type struct { - Handle :: type HANDLE; - handle: Handle; + Handle :: type HANDLE + handle: Handle } file_open :: proc(name: string) -> (File, bool) { - buf: [300]byte; - _ = copy(buf[:], name as []byte); - f := File{CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null)}; - success := f.handle != INVALID_HANDLE_VALUE as File.Handle; + buf: [300]byte + _ = copy(buf[:], name as []byte) + f := File{CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null)} + success := f.handle != INVALID_HANDLE_VALUE as File.Handle - return f, success; + return f, success } file_create :: proc(name: string) -> (File, bool) { - buf: [300]byte; - _ = copy(buf[:], name as []byte); + buf: [300]byte + _ = copy(buf[:], name as []byte) f := File{ handle = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, 0, null), - }; - success := f.handle != INVALID_HANDLE_VALUE as File.Handle; - return f, success; + } + success := f.handle != INVALID_HANDLE_VALUE as File.Handle + return f, success } file_close :: proc(f: ^File) { - CloseHandle(f.handle); + CloseHandle(f.handle) } file_write :: proc(f: ^File, buf: []byte) -> bool { - bytes_written: i32; - return WriteFile(f.handle, ^buf[0], len(buf) as i32, ^bytes_written, null) != 0; + bytes_written: i32 + return WriteFile(f.handle, ^buf[0], len(buf) as i32, ^bytes_written, null) != 0 } FileStandard :: type enum { @@ -47,60 +47,60 @@ __std_files: [FileStandard.COUNT as int]File; file_get_standard :: proc(std: FileStandard) -> ^File { // using FileStandard; if (!__std_file_set) { - using FileStandard; - __std_files[INPUT] .handle = GetStdHandle(STD_INPUT_HANDLE); - __std_files[OUTPUT].handle = GetStdHandle(STD_OUTPUT_HANDLE); - __std_files[ERROR] .handle = GetStdHandle(STD_ERROR_HANDLE); - __std_file_set = true; + using FileStandard + __std_files[INPUT] .handle = GetStdHandle(STD_INPUT_HANDLE) + __std_files[OUTPUT].handle = GetStdHandle(STD_OUTPUT_HANDLE) + __std_files[ERROR] .handle = GetStdHandle(STD_ERROR_HANDLE) + __std_file_set = true } - return ^__std_files[std]; + return ^__std_files[std] } read_entire_file :: proc(name: string) -> (string, bool) { - buf: [300]byte; - _ = copy(buf[:], name as []byte); - c_string := ^buf[0]; + buf: [300]byte + _ = copy(buf[:], name as []byte) + c_string := ^buf[0] - f, file_ok := file_open(name); + f, file_ok := file_open(name) if !file_ok { - return "", false; + return "", false } - defer file_close(^f); + defer file_close(^f) - length: i64; - file_size_ok := GetFileSizeEx(f.handle as HANDLE, ^length) != 0; + length: i64 + file_size_ok := GetFileSizeEx(f.handle as HANDLE, ^length) != 0 if !file_size_ok { - return "", false; + return "", false } - data := new_slice(u8, length); + data := new_slice(u8, length) if ^data[0] == null { - return "", false; + return "", false } - single_read_length: i32; - total_read: i64; + single_read_length: i32 + total_read: i64 for total_read < length { - remaining := length - total_read; - to_read: u32; - MAX :: 0x7fffffff; + remaining := length - total_read + to_read: u32 + MAX :: 0x7fffffff if remaining <= MAX { - to_read = remaining as u32; + to_read = remaining as u32 } else { - to_read = MAX; + to_read = MAX } - ReadFile(f.handle as HANDLE, ^data[total_read], to_read, ^single_read_length, null); + ReadFile(f.handle as HANDLE, ^data[total_read], to_read, ^single_read_length, null) if single_read_length <= 0 { - delete(data); - return "", false; + delete(data) + return "", false } - total_read += single_read_length as i64; + total_read += single_read_length as i64 } - return data as string, true; + return data as string, true } diff --git a/examples/game.odin b/examples/game.odin index 6451bb8aa..4420ce448 100644 --- a/examples/game.odin +++ b/examples/game.odin @@ -2,55 +2,55 @@ #load "opengl.odin" #load "math.odin" -TWO_HEARTS :: #rune "💕"; +TWO_HEARTS :: #rune "💕" -win32_perf_count_freq := GetQueryPerformanceFrequency(); +win32_perf_count_freq := GetQueryPerformanceFrequency() time_now :: proc() -> f64 { if win32_perf_count_freq == 0 { - debug_trap(); + debug_trap() } - counter: i64; - _ = QueryPerformanceCounter(^counter); - result := counter as f64 / win32_perf_count_freq as f64; - return result; + counter: i64 + _ = QueryPerformanceCounter(^counter) + result := counter as f64 / win32_perf_count_freq as f64 + return result } win32_print_last_error :: proc() { - err_code := GetLastError() as int; + err_code := GetLastError() as int if err_code != 0 { - print_string("GetLastError: "); - print_int(err_code); - print_string("\n"); + print_string("GetLastError: ") + print_int(err_code) + print_string("\n") } } // Yuk! to_c_string :: proc(s: string) -> ^u8 { - c_str: ^u8 = alloc(len(s)+1); - memory_copy(c_str, ^s[0], len(s)); - ptr_offset(c_str, len(s))^ = 0; - return c_str; + c_str: ^u8 = alloc(len(s)+1) + memory_copy(c_str, ^s[0], len(s)) + ptr_offset(c_str, len(s))^ = 0 + return c_str } Window :: type struct { - width, height: int; - wc: WNDCLASSEXA; - dc: HDC; - hwnd: HWND; - opengl_context, rc: HGLRC; - c_title: ^u8; + width, height: int + wc: WNDCLASSEXA + dc: HDC + hwnd: HWND + opengl_context, rc: HGLRC + c_title: ^u8 } make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (Window, bool) { - w: Window; - w.width, w.height = msg, height; + w: Window + w.width, w.height = msg, height - class_name := "Win32-Odin-Window\x00"; - c_class_name := ^class_name[0]; - w.c_title = to_c_string(title); + class_name := "Win32-Odin-Window\x00" + c_class_name := ^class_name[0] + w.c_title = to_c_string(title) - instance := GetModuleHandleA(null); + instance := GetModuleHandleA(null) w.wc = WNDCLASSEXA{ size = size_of(WNDCLASSEXA) as u32, @@ -61,7 +61,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W }; if RegisterClassExA(^w.wc) == 0 { - return w, false; + return w, false } w.hwnd = CreateWindowExA(0, @@ -69,14 +69,14 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, w.width as i32, w.height as i32, - null, null, instance, null); + null, null, instance, null) if w.hwnd == null { - win32_print_last_error(); - return w, false; + win32_print_last_error() + return w, false } - w.dc = GetDC(w.hwnd); + w.dc = GetDC(w.hwnd) { pfd := PIXELFORMATDESCRIPTOR{ @@ -89,126 +89,126 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W depth_bits = 24, stencil_bits = 8, layer_type = PFD_MAIN_PLANE, - }; + } - SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), null); - w.opengl_context = wglCreateContext(w.dc); - wglMakeCurrent(w.dc, w.opengl_context); + SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), null) + w.opengl_context = wglCreateContext(w.dc) + wglMakeCurrent(w.dc, w.opengl_context) attribs := [8]i32{ WGL_CONTEXT_MAJOR_VERSION_ARB, 2, WGL_CONTEXT_MINOR_VERSION_ARB, 1, WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 0, // NOTE(bill): tells the proc that this is the end of attribs - }; + } - wgl_string := "wglCreateContextAttribsARB\x00"; - c_wgl_string := ^wgl_string[0]; - wglCreateContextAttribsARB := wglGetProcAddress(c_wgl_string) as wglCreateContextAttribsARBType; - w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0]); - wglMakeCurrent(w.dc, w.rc); - SwapBuffers(w.dc); + wgl_string := "wglCreateContextAttribsARB\x00" + c_wgl_string := ^wgl_string[0] + wglCreateContextAttribsARB := wglGetProcAddress(c_wgl_string) as wglCreateContextAttribsARBType + w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0]) + wglMakeCurrent(w.dc, w.rc) + SwapBuffers(w.dc) } - return w, true; + return w, true } destroy_window :: proc(w: ^Window) { - heap_free(w.c_title); + heap_free(w.c_title) } display_window :: proc(w: ^Window) { - SwapBuffers(w.dc); + SwapBuffers(w.dc) } Entity :: type struct { - pos: Vec2; - dim: Vec2; + pos: Vec2 + dim: Vec2 } run_game :: proc() { win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline { if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT { - ExitProcess(0); - return 0; + ExitProcess(0) + return 0 } - return DefWindowProcA(hwnd, msg, wparam, lparam); + return DefWindowProcA(hwnd, msg, wparam, lparam) } - window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc); + window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc) if !window_success { - return; + return } - defer destroy_window(^window); + defer destroy_window(^window) - prev_time := time_now(); - running := true; + prev_time := time_now() + running := true - pos := Vec2{100, 100}; + pos := Vec2{100, 100} for running { - curr_time := time_now(); - dt := (curr_time - prev_time) as f32; - prev_time = curr_time; + curr_time := time_now() + dt := (curr_time - prev_time) as f32 + prev_time = curr_time - msg: MSG; + msg: MSG for PeekMessageA(^msg, null, 0, 0, PM_REMOVE) > 0 { if msg.message == WM_QUIT { - running = false; + running = false } - _ = TranslateMessage(^msg); - _ = DispatchMessageA(^msg); + _ = TranslateMessage(^msg) + _ = DispatchMessageA(^msg) } if is_key_down(VK_ESCAPE) { - running = false; + running = false } { - SPEED :: 500; - v: Vec2; + SPEED :: 500 + v: Vec2 - if is_key_down(VK_RIGHT) { v[0] += 1; } - if is_key_down(VK_LEFT) { v[0] -= 1; } - if is_key_down(VK_UP) { v[1] += 1; } - if is_key_down(VK_DOWN) { v[1] -= 1; } + if is_key_down(VK_RIGHT) { v[0] += 1 } + if is_key_down(VK_LEFT) { v[0] -= 1 } + if is_key_down(VK_UP) { v[1] += 1 } + if is_key_down(VK_DOWN) { v[1] -= 1 } - v = vec2_norm0(v); + v = vec2_norm0(v) - pos += v * Vec2{SPEED * dt}; + pos += v * Vec2{SPEED * dt} } - glClearColor(0.5, 0.7, 1.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); + glClearColor(0.5, 0.7, 1.0, 1.0) + glClear(GL_COLOR_BUFFER_BIT) - glLoadIdentity(); + glLoadIdentity() glOrtho(0, window.width as f64, - 0, window.height as f64, 0, 1); + 0, window.height as f64, 0, 1) draw_rect :: proc(x, y, w, h: f32) { - glBegin(GL_TRIANGLES); + glBegin(GL_TRIANGLES) - glColor3f(1, 0, 0); glVertex3f(x, y, 0); - glColor3f(0, 1, 0); glVertex3f(x+w, y, 0); - glColor3f(0, 0, 1); glVertex3f(x+w, y+h, 0); + glColor3f(1, 0, 0); glVertex3f(x, y, 0) + glColor3f(0, 1, 0); glVertex3f(x+w, y, 0) + glColor3f(0, 0, 1); glVertex3f(x+w, y+h, 0) - glColor3f(0, 0, 1); glVertex3f(x+w, y+h, 0); - glColor3f(1, 1, 0); glVertex3f(x, y+h, 0); - glColor3f(1, 0, 0); glVertex3f(x, y, 0); + glColor3f(0, 0, 1); glVertex3f(x+w, y+h, 0) + glColor3f(1, 1, 0); glVertex3f(x, y+h, 0) + glColor3f(1, 0, 0); glVertex3f(x, y, 0) - glEnd(); + glEnd() } - draw_rect(pos[0], pos[1], 50, 50); + draw_rect(pos[0], pos[1], 50, 50) - display_window(^window); - ms_to_sleep := (16 - 1000*dt) as i32; + display_window(^window) + ms_to_sleep := (16 - 1000*dt) as i32 if ms_to_sleep > 0 { - sleep_ms(ms_to_sleep); + sleep_ms(ms_to_sleep) } } } diff --git a/examples/math.odin b/examples/math.odin index c961e891a..ee0245d4b 100644 --- a/examples/math.odin +++ b/examples/math.odin @@ -1,162 +1,162 @@ -MATH_TAU :: 6.28318530717958647692528676655900576; -MATH_PI :: 3.14159265358979323846264338327950288; -MATH_ONE_OVER_TAU :: 0.636619772367581343075535053490057448; -MATH_ONE_OVER_PI :: 0.159154943091895335768883763372514362; +MATH_TAU :: 6.28318530717958647692528676655900576 +MATH_PI :: 3.14159265358979323846264338327950288 +MATH_ONE_OVER_TAU :: 0.636619772367581343075535053490057448 +MATH_ONE_OVER_PI :: 0.159154943091895335768883763372514362 -MATH_E :: 2.71828182845904523536; -MATH_SQRT_TWO :: 1.41421356237309504880168872420969808; -MATH_SQRT_THREE :: 1.73205080756887729352744634150587236; -MATH_SQRT_FIVE :: 2.23606797749978969640917366873127623; +MATH_E :: 2.71828182845904523536 +MATH_SQRT_TWO :: 1.41421356237309504880168872420969808 +MATH_SQRT_THREE :: 1.73205080756887729352744634150587236 +MATH_SQRT_FIVE :: 2.23606797749978969640917366873127623 -MATH_LOG_TWO :: 0.693147180559945309417232121458176568; -MATH_LOG_TEN :: 2.30258509299404568401799145468436421; +MATH_LOG_TWO :: 0.693147180559945309417232121458176568 +MATH_LOG_TEN :: 2.30258509299404568401799145468436421 -MATH_EPSILON :: 1.19209290e-7; +MATH_EPSILON :: 1.19209290e-7 -τ :: MATH_TAU; -π :: MATH_PI; +τ :: MATH_TAU +π :: MATH_PI -Vec2 :: type {2}f32; -Vec3 :: type {3}f32; -Vec4 :: type {4}f32; +Vec2 :: type {2}f32 +Vec3 :: type {3}f32 +Vec4 :: type {4}f32 -Mat2 :: type {4}f32; -Mat3 :: type {9}f32; -Mat4 :: type {16}f32; +Mat2 :: type {4}f32 +Mat3 :: type {9}f32 +Mat4 :: type {16}f32 fsqrt :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32" fsin :: proc(x: f32) -> f32 #foreign "llvm.sin.f32" fcos :: proc(x: f32) -> f32 #foreign "llvm.cos.f32" -flerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; } -fclamp :: proc(x, lower, upper: f32) -> f32 { return fmin(fmax(x, lower), upper); } -fclamp01 :: proc(x: f32) -> f32 { return fclamp(x, 0, 1); } -fabs :: proc(x: f32) -> f32 { if x < 0 { x = -x; } return x; } -fsign :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; } +flerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t } +fclamp :: proc(x, lower, upper: f32) -> f32 { return fmin(fmax(x, lower), upper) } +fclamp01 :: proc(x: f32) -> f32 { return fclamp(x, 0, 1) } +fabs :: proc(x: f32) -> f32 { if x < 0 { x = -x } return x } +fsign :: proc(x: f32) -> f32 { if x >= 0 { return +1 } return -1 } -fmin :: proc(a, b: f32) -> f32 { if a < b { return a; } return b; } -fmax :: proc(a, b: f32) -> f32 { if a > b { return a; } return b; } -fmin3 :: proc(a, b, c: f32) -> f32 { return fmin(fmin(a, b), c); } -fmax3 :: proc(a, b, c: f32) -> f32 { return fmax(fmax(a, b), c); } +fmin :: proc(a, b: f32) -> f32 { if a < b { return a } return b } +fmax :: proc(a, b: f32) -> f32 { if a > b { return a } return b } +fmin3 :: proc(a, b, c: f32) -> f32 { return fmin(fmin(a, b), c) } +fmax3 :: proc(a, b, c: f32) -> f32 { return fmax(fmax(a, b), c) } copy_sign :: proc(x, y: f32) -> f32 { - ix := x transmute u32; - iy := y transmute u32; - ix &= 0x7fffffff; - ix |= iy & 0x80000000; - return ix transmute f32; + ix := x transmute u32 + iy := y transmute u32 + ix &= 0x7fffffff + ix |= iy & 0x80000000 + return ix transmute f32 } round :: proc(x: f32) -> f32 { if x >= 0 { - return floor(x + 0.5); + return floor(x + 0.5) } - return ceil(x - 0.5); + return ceil(x - 0.5) } floor :: proc(x: f32) -> f32 { if x >= 0 { - return x as int as f32; + return x as int as f32 } - return (x-0.5) as int as f32; + return (x-0.5) as int as f32 } ceil :: proc(x: f32) -> f32 { if x < 0 { - return x as int as f32; + return x as int as f32 } - return ((x as int)+1) as f32; + return ((x as int)+1) as f32 } remainder :: proc(x, y: f32) -> f32 { - return x - round(x/y) * y; + return x - round(x/y) * y } fmod :: proc(x, y: f32) -> f32 { - y = fabs(y); - result := remainder(fabs(x), y); + y = fabs(y) + result := remainder(fabs(x), y) if fsign(result) < 0 { - result += y; + result += y } - return copy_sign(result, x); + return copy_sign(result, x) } -to_radians :: proc(degrees: f32) -> f32 { return degrees * MATH_TAU / 360; } -to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / MATH_TAU; } +to_radians :: proc(degrees: f32) -> f32 { return degrees * MATH_TAU / 360 } +to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / MATH_TAU } -dot2 :: proc(a, b: Vec2) -> f32 { c := a*b; return c[0] + c[1]; } -dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c[0] + c[1] + c[2]; } -dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c[0] + c[1] + c[2] + c[3]; } +dot2 :: proc(a, b: Vec2) -> f32 { c := a*b; return c[0] + c[1] } +dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c[0] + c[1] + c[2] } +dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c[0] + c[1] + c[2] + c[3] } cross :: proc(x, y: Vec3) -> Vec3 { - a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1); - b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0); - return a - b; + a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1) + b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0) + return a - b } -vec2_mag :: proc(v: Vec2) -> f32 { return fsqrt(v ''dot2 v); } -vec3_mag :: proc(v: Vec3) -> f32 { return fsqrt(v ''dot3 v); } -vec4_mag :: proc(v: Vec4) -> f32 { return fsqrt(v ''dot4 v); } +vec2_mag :: proc(v: Vec2) -> f32 { return fsqrt(v ''dot2 v) } +vec3_mag :: proc(v: Vec3) -> f32 { return fsqrt(v ''dot3 v) } +vec4_mag :: proc(v: Vec4) -> f32 { return fsqrt(v ''dot4 v) } -vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; } -vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; } -vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; } +vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)} } +vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)} } +vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)} } vec2_norm0 :: proc(v: Vec2) -> Vec2 { - m := vec2_mag(v); + m := vec2_mag(v) if m == 0 { - return Vec2{0}; + return Vec2{0} } - return v / Vec2{m}; + return v / Vec2{m} } vec3_norm0 :: proc(v: Vec3) -> Vec3 { - m := vec3_mag(v); + m := vec3_mag(v) if m == 0 { - return Vec3{0}; + return Vec3{0} } - return v / Vec3{m}; + return v / Vec3{m} } vec4_norm0 :: proc(v: Vec4) -> Vec4 { - m := vec4_mag(v); + m := vec4_mag(v) if m == 0 { - return Vec4{0}; + return Vec4{0} } - return v / Vec4{m}; + return v / Vec4{m} } -F32_DIG :: 6; -F32_EPSILON :: 1.192092896e-07; -F32_GUARD :: 0; -F32_MANT_DIG :: 24; -F32_MAX :: 3.402823466e+38; -F32_MAX_10_EXP :: 38; -F32_MAX_EXP :: 128; -F32_MIN :: 1.175494351e-38; -F32_MIN_10_EXP :: -37; -F32_MIN_EXP :: -125; -F32_NORMALIZE :: 0; -F32_RADIX :: 2; -F32_ROUNDS :: 1; +F32_DIG :: 6 +F32_EPSILON :: 1.192092896e-07 +F32_GUARD :: 0 +F32_MANT_DIG :: 24 +F32_MAX :: 3.402823466e+38 +F32_MAX_10_EXP :: 38 +F32_MAX_EXP :: 128 +F32_MIN :: 1.175494351e-38 +F32_MIN_10_EXP :: -37 +F32_MIN_EXP :: -125 +F32_NORMALIZE :: 0 +F32_RADIX :: 2 +F32_ROUNDS :: 1 -F64_DIG :: 15; // # of decimal digits of precision -F64_EPSILON :: 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0 -F64_MANT_DIG :: 53; // # of bits in mantissa -F64_MAX :: 1.7976931348623158e+308; // max value -F64_MAX_10_EXP :: 308; // max decimal exponent -F64_MAX_EXP :: 1024; // max binary exponent -F64_MIN :: 2.2250738585072014e-308; // min positive value -F64_MIN_10_EXP :: -307; // min decimal exponent -F64_MIN_EXP :: -1021; // min binary exponent -F64_RADIX :: 2; // exponent radix -F64_ROUNDS :: 1; // addition rounding: near +F64_DIG :: 15 // # of decimal digits of precision +F64_EPSILON :: 2.2204460492503131e-016 // smallest such that 1.0+F64_EPSILON != 1.0 +F64_MANT_DIG :: 53 // # of bits in mantissa +F64_MAX :: 1.7976931348623158e+308 // max value +F64_MAX_10_EXP :: 308 // max decimal exponent +F64_MAX_EXP :: 1024 // max binary exponent +F64_MIN :: 2.2250738585072014e-308 // min positive value +F64_MIN_10_EXP :: -307 // min decimal exponent +F64_MIN_EXP :: -1021 // min binary exponent +F64_RADIX :: 2 // exponent radix +F64_ROUNDS :: 1 // addition rounding: near diff --git a/examples/opengl.odin b/examples/opengl.odin index edc7cb083..79668dd00 100644 --- a/examples/opengl.odin +++ b/examples/opengl.odin @@ -1,29 +1,31 @@ -GL_ZERO :: 0x0000; -GL_ONE :: 0x0001; -GL_TRIANGLES :: 0x0004; -GL_BLEND :: 0x0BE2; -GL_SRC_ALPHA :: 0x0302; -GL_ONE_MINUS_SRC_ALPHA :: 0x0303; -GL_TEXTURE_2D :: 0x0DE1; -GL_RGBA8 :: 0x8058; -GL_UNSIGNED_BYTE :: 0x1401; -GL_BGRA_EXT :: 0x80E1; -GL_TEXTURE_MAX_LEVEL :: 0x813D; -GL_RGBA :: 0x1908; +#foreign_system_library "opengl32" -GL_NEAREST :: 0x2600; -GL_LINEAR :: 0x2601; +GL_ZERO :: 0x0000 +GL_ONE :: 0x0001 +GL_TRIANGLES :: 0x0004 +GL_BLEND :: 0x0be2 +GL_SRC_ALPHA :: 0x0302 +GL_ONE_MINUS_SRC_ALPHA :: 0x0303 +GL_TEXTURE_2D :: 0x0de1 +GL_RGBA8 :: 0x8058 +GL_UNSIGNED_BYTE :: 0x1401 +GL_BGRA_EXT :: 0x80e1 +GL_TEXTURE_MAX_LEVEL :: 0x813d +GL_RGBA :: 0x1908 -GL_DEPTH_BUFFER_BIT :: 0x00000100; -GL_STENCIL_BUFFER_BIT :: 0x00000400; -GL_COLOR_BUFFER_BIT :: 0x00004000; +GL_NEAREST :: 0x2600 +GL_LINEAR :: 0x2601 -GL_TEXTURE_MAX_ANISOTROPY_EXT :: 0x84FE; +GL_DEPTH_BUFFER_BIT :: 0x00000100 +GL_STENCIL_BUFFER_BIT :: 0x00000400 +GL_COLOR_BUFFER_BIT :: 0x00004000 -GL_TEXTURE_MAG_FILTER :: 0x2800; -GL_TEXTURE_MIN_FILTER :: 0x2801; -GL_TEXTURE_WRAP_S :: 0x2802; -GL_TEXTURE_WRAP_T :: 0x2803; +GL_TEXTURE_MAX_ANISOTROPY_EXT :: 0x84fe + +GL_TEXTURE_MAG_FILTER :: 0x2800 +GL_TEXTURE_MIN_FILTER :: 0x2801 +GL_TEXTURE_WRAP_S :: 0x2802 +GL_TEXTURE_WRAP_T :: 0x2803 glClear :: proc(mask: u32) #foreign glClearColor :: proc(r, g, b, a: f32) #foreign diff --git a/examples/runtime.odin b/examples/runtime.odin index 5f39bc306..e203aaca1 100644 --- a/examples/runtime.odin +++ b/examples/runtime.odin @@ -4,167 +4,167 @@ debug_trap :: proc() #foreign "llvm.debugtrap" // TODO(bill): make custom heap procedures heap_alloc :: proc(len: int) -> rawptr { - return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); + return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len) } heap_free :: proc(ptr: rawptr) { - _ = HeapFree(GetProcessHeap(), 0, ptr); + _ = HeapFree(GetProcessHeap(), 0, ptr) } memory_compare :: proc(dst, src: rawptr, len: int) -> int { - s1, s2: ^u8 = dst, src; + s1, s2: ^u8 = dst, src for i := 0; i < len; i++ { - a := ptr_offset(s1, i)^; - b := ptr_offset(s2, i)^; + a := ptr_offset(s1, i)^ + b := ptr_offset(s2, i)^ if a != b { - return (a - b) as int; + return (a - b) as int } } - return 0; + return 0 } memory_copy :: proc(dst, src: rawptr, n: int) #inline { if dst == src { - return; + return } - v128b :: type {4}u32; - static_assert(align_of(v128b) == 16); + v128b :: type {4}u32 + static_assert(align_of(v128b) == 16) - d, s: ^u8 = dst, src; + d, s: ^u8 = dst, src for ; s as uint % 16 != 0 && n != 0; n-- { - d^ = s^; - d, s = ptr_offset(d, 1), ptr_offset(s, 1); + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) } if d as uint % 16 == 0 { for ; n >= 16; d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 { - (d as ^v128b)^ = (s as ^v128b)^; + (d as ^v128b)^ = (s as ^v128b)^ } if n&8 != 0 { - (d as ^u64)^ = (s as ^u64)^; - d, s = ptr_offset(d, 8), ptr_offset(s, 8); + (d as ^u64)^ = (s as ^u64)^ + d, s = ptr_offset(d, 8), ptr_offset(s, 8) } if n&4 != 0 { (d as ^u32)^ = (s as ^u32)^; - d, s = ptr_offset(d, 4), ptr_offset(s, 4); + d, s = ptr_offset(d, 4), ptr_offset(s, 4) } if n&2 != 0 { - (d as ^u16)^ = (s as ^u16)^; - d, s = ptr_offset(d, 2), ptr_offset(s, 2); + (d as ^u16)^ = (s as ^u16)^ + d, s = ptr_offset(d, 2), ptr_offset(s, 2) } if n&1 != 0 { - d^ = s^; - d, s = ptr_offset(d, 1), ptr_offset(s, 1); + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) } return; } // IMPORTANT NOTE(bill): Little endian only - LS :: proc(a, b: u32) -> u32 #inline { return a << b; } - RS :: proc(a, b: u32) -> u32 #inline { return a >> b; } + LS :: proc(a, b: u32) -> u32 #inline { return a << b } + RS :: proc(a, b: u32) -> u32 #inline { return a >> b } /* NOTE(bill): Big endian version LS :: proc(a, b: u32) -> u32 #inline { return a >> b; } RS :: proc(a, b: u32) -> u32 #inline { return a << b; } */ - w, x: u32; + w, x: u32 if d as uint % 4 == 1 { - w = (s as ^u32)^; - d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1); - d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1); - d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1); - n -= 3; + w = (s as ^u32)^ + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + n -= 3 for n > 16 { - d32 := d as ^u32; - s32 := ptr_offset(s, 1) as ^u32; - x = s32^; d32^ = LS(w, 24) | RS(x, 8); - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); - w = s32^; d32^ = LS(x, 24) | RS(w, 8); - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); - x = s32^; d32^ = LS(w, 24) | RS(x, 8); - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); - w = s32^; d32^ = LS(x, 24) | RS(w, 8); - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); + d32 := d as ^u32 + s32 := ptr_offset(s, 1) as ^u32 + x = s32^; d32^ = LS(w, 24) | RS(x, 8) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 24) | RS(w, 8) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + x = s32^; d32^ = LS(w, 24) | RS(x, 8) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 24) | RS(w, 8) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16; + d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 } } else if d as uint % 4 == 2 { - w = (s as ^u32)^; - d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1); - d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1); - n -= 2; + w = (s as ^u32)^ + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + n -= 2 for n > 17 { - d32 := d as ^u32; - s32 := ptr_offset(s, 2) as ^u32; - x = s32^; d32^ = LS(w, 16) | RS(x, 16); - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); - w = s32^; d32^ = LS(x, 16) | RS(w, 16); - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); - x = s32^; d32^ = LS(w, 16) | RS(x, 16); - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); - w = s32^; d32^ = LS(x, 16) | RS(w, 16); - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); + d32 := d as ^u32 + s32 := ptr_offset(s, 2) as ^u32 + x = s32^; d32^ = LS(w, 16) | RS(x, 16) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 16) | RS(w, 16) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + x = s32^; d32^ = LS(w, 16) | RS(x, 16) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 16) | RS(w, 16) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16; + d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 } } else if d as uint % 4 == 3 { - w = (s as ^u32)^; - d^ = s^; - n -= 1; + w = (s as ^u32)^ + d^ = s^ + n -= 1 for n > 18 { - d32 := d as ^u32; - s32 := ptr_offset(s, 3) as ^u32; - x = s32^; d32^ = LS(w, 8) | RS(x, 24); - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); - w = s32^; d32^ = LS(x, 8) | RS(w, 24); - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); - x = s32^; d32^ = LS(w, 8) | RS(x, 24); - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); - w = s32^; d32^ = LS(x, 8) | RS(w, 24); - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1); + d32 := d as ^u32 + s32 := ptr_offset(s, 3) as ^u32 + x = s32^; d32^ = LS(w, 8) | RS(x, 24) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 8) | RS(w, 24) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + x = s32^; d32^ = LS(w, 8) | RS(x, 24) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 8) | RS(w, 24) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16; + d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 } } if n&16 != 0 { - (d as ^v128b)^ = (s as ^v128b)^; - d, s = ptr_offset(d, 16), ptr_offset(s, 16); + (d as ^v128b)^ = (s as ^v128b)^ + d, s = ptr_offset(d, 16), ptr_offset(s, 16) } if n&8 != 0 { - (d as ^u64)^ = (s as ^u64)^; - d, s = ptr_offset(d, 8), ptr_offset(s, 8); + (d as ^u64)^ = (s as ^u64)^ + d, s = ptr_offset(d, 8), ptr_offset(s, 8) } if n&4 != 0 { (d as ^u32)^ = (s as ^u32)^; - d, s = ptr_offset(d, 4), ptr_offset(s, 4); + d, s = ptr_offset(d, 4), ptr_offset(s, 4) } if n&2 != 0 { - (d as ^u16)^ = (s as ^u16)^; - d, s = ptr_offset(d, 2), ptr_offset(s, 2); + (d as ^u16)^ = (s as ^u16)^ + d, s = ptr_offset(d, 2), ptr_offset(s, 2) } if n&1 != 0 { - d^ = s^; + d^ = s^ } } memory_move :: proc(dst, src: rawptr, n: int) #inline { - d, s: ^u8 = dst, src; + d, s: ^u8 = dst, src if d == s { - return; + return } if d >= ptr_offset(s, n) || ptr_offset(d, n) <= s { - memory_copy(d, s, n); - return; + memory_copy(d, s, n) + return } // TODO(bill): Vectorize the shit out of this @@ -172,94 +172,94 @@ memory_move :: proc(dst, src: rawptr, n: int) #inline { if s as int % size_of(int) == d as int % size_of(int) { for d as int % size_of(int) != 0 { if n == 0 { - return; + return } - n--; - d^ = s^; - d, s = ptr_offset(d, 1), ptr_offset(s, 1); + n-- + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) } - di, si := d as ^int, s as ^int; + di, si := d as ^int, s as ^int for n >= size_of(int) { - di^ = si^; - di, si = ptr_offset(di, 1), ptr_offset(si, 1); - n -= size_of(int); + di^ = si^ + di, si = ptr_offset(di, 1), ptr_offset(si, 1) + n -= size_of(int) } } for ; n > 0; n-- { - d^ = s^; - d, s = ptr_offset(d, 1), ptr_offset(s, 1); + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) } } else { if s as int % size_of(int) == d as int % size_of(int) { for ptr_offset(d, n) as int % size_of(int) != 0 { if n == 0 { - return; + return } - n--; - d^ = s^; - d, s = ptr_offset(d, 1), ptr_offset(s, 1); + n-- + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) } for n >= size_of(int) { - n -= size_of(int); - di := ptr_offset(d, n) as ^int; - si := ptr_offset(s, n) as ^int; - di^ = si^; + n -= size_of(int) + di := ptr_offset(d, n) as ^int + si := ptr_offset(s, n) as ^int + di^ = si^ } for ; n > 0; n-- { - d^ = s^; - d, s = ptr_offset(d, 1), ptr_offset(s, 1); + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) } } for n > 0 { - n--; - dn := ptr_offset(d, n); - sn := ptr_offset(s, n); - dn^ = sn^; + n-- + dn := ptr_offset(d, n) + sn := ptr_offset(s, n) + dn^ = sn^ } } } -__string_eq :: proc(a, b : string) -> bool { +__string_eq :: proc(a, b: string) -> bool { if len(a) != len(b) { - return false; + return false } if ^a[0] == ^b[0] { - return true; + return true } - return memory_compare(^a[0], ^b[0], len(a)) == 0; + return memory_compare(^a[0], ^b[0], len(a)) == 0 } __string_ne :: proc(a, b : string) -> bool #inline { - return !__string_eq(a, b); + return !__string_eq(a, b) } __string_cmp :: proc(a, b : string) -> int { - min_len := len(a); + min_len := len(a) if len(b) < min_len { - min_len = len(b); + min_len = len(b) } for i := 0; i < min_len; i++ { - x := a[i]; - y := b[i]; + x := a[i] + y := b[i] if x < y { - return -1; + return -1 } else if x > y { - return +1; + return +1 } } if len(a) < len(b) { - return -1; + return -1 } else if len(a) > len(b) { - return +1; + return +1 } - return 0; + return 0 } -__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0; } -__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0; } -__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0; } -__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0; } +__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0 } +__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0 } +__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 } +__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 } @@ -275,117 +275,113 @@ AllocationMode :: type enum { AllocatorProc :: type proc(allocator_data: rawptr, mode: AllocationMode, size, alignment: int, - old_memory: rawptr, old_size: int, flags: u64) -> rawptr; + old_memory: rawptr, old_size: int, flags: u64) -> rawptr Allocator :: type struct { procedure: AllocatorProc; - data: rawptr; + data: rawptr } Context :: type struct { - thread_id: i32; + thread_id: i32 - user_index: i32; - user_data: rawptr; + user_index: i32 + user_data: rawptr - allocator: Allocator; + allocator: Allocator } -#thread_local context: Context; +#thread_local context: Context -DEFAULT_ALIGNMENT :: 2*size_of(int); +DEFAULT_ALIGNMENT :: 2*size_of(int) __check_context :: proc() { - static_assert(AllocationMode.ALLOC == 0); - static_assert(AllocationMode.DEALLOC == 1); - static_assert(AllocationMode.DEALLOC_ALL == 2); - static_assert(AllocationMode.RESIZE == 3); - if context.allocator.procedure == null { - context.allocator = __default_allocator(); + context.allocator = __default_allocator() } } -alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT); } +alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) } alloc_align :: proc(size, alignment: int) -> rawptr #inline { - __check_context(); - a := context.allocator; - return a.procedure(a.data, AllocationMode.ALLOC, size, alignment, null, 0, 0); + __check_context() + a := context.allocator + return a.procedure(a.data, AllocationMode.ALLOC, size, alignment, null, 0, 0) } dealloc :: proc(ptr: rawptr) #inline { - __check_context(); - a := context.allocator; - _ = a.procedure(a.data, AllocationMode.DEALLOC, 0, 0, ptr, 0, 0); + __check_context() + a := context.allocator + _ = a.procedure(a.data, AllocationMode.DEALLOC, 0, 0, ptr, 0, 0) } dealloc_all :: proc(ptr: rawptr) #inline { - __check_context(); - a := context.allocator; - _ = a.procedure(a.data, AllocationMode.DEALLOC_ALL, 0, 0, ptr, 0, 0); + __check_context() + a := context.allocator + _ = a.procedure(a.data, AllocationMode.DEALLOC_ALL, 0, 0, ptr, 0, 0) } -resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT); } +resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) } resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline { - __check_context(); - a := context.allocator; - return a.procedure(a.data, AllocationMode.RESIZE, new_size, alignment, ptr, old_size, 0); + __check_context() + a := context.allocator + return a.procedure(a.data, AllocationMode.RESIZE, new_size, alignment, ptr, old_size, 0) } default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr { if old_memory == null { - return alloc_align(new_size, alignment); + return alloc_align(new_size, alignment) } if new_size == 0 { - dealloc(old_memory); - return null; + dealloc(old_memory) + return null } if new_size < old_size { - new_size = old_size; + new_size = old_size } if old_size == new_size { - return old_memory; + return old_memory } - new_memory := alloc_align(new_size, alignment); + new_memory := alloc_align(new_size, alignment) if new_memory == null { - return null; + return null } - _ = copy(slice_ptr(new_memory as ^u8, new_size), slice_ptr(old_memory as ^u8, old_size)); - dealloc(old_memory); - return new_memory; + _ = copy(slice_ptr(new_memory as ^u8, new_size), slice_ptr(old_memory as ^u8, old_size)) + dealloc(old_memory) + return new_memory } __default_allocator_proc :: proc(allocator_data: rawptr, mode: AllocationMode, size, alignment: int, old_memory: rawptr, old_size: int, flags: u64) -> rawptr { - if mode == AllocationMode.ALLOC { - return heap_alloc(size); - } else if mode == AllocationMode.RESIZE { - return default_resize_align(old_memory, old_size, size, alignment); - } else if mode == AllocationMode.DEALLOC { - heap_free(old_memory); - } else if mode == AllocationMode.DEALLOC_ALL { + using AllocationMode + if mode == ALLOC { + return heap_alloc(size) + } else if mode == RESIZE { + return default_resize_align(old_memory, old_size, size, alignment) + } else if mode == DEALLOC { + heap_free(old_memory) + } else if mode == DEALLOC_ALL { // NOTE(bill): Does nothing } - return null; + return null } __default_allocator :: proc() -> Allocator { return Allocator{ __default_allocator_proc, null, - }; + } } diff --git a/examples/stb_image.odin b/examples/stb_image.odin index 286fb39c8..2da840838 100644 --- a/examples/stb_image.odin +++ b/examples/stb_image.odin @@ -7,24 +7,24 @@ type Bitmap: struct { make_bitmap :: proc(filename: string) -> Bitmap { stbi_load :: proc(filename: ^u8, x, y, comp: ^i32, req_comp: i32) -> ^u8 #foreign - c_buf: [1024]u8; - bytes := filename as []byte; - str_len := copy(c_buf[:], bytes); + c_buf: [1024]u8 + bytes := filename as []byte + str_len := copy(c_buf[:], bytes) - b: Bitmap; - pixels := stbi_load(^c_buf[0], ^b.width, ^b.height, ^b.comp, 4); - len := (b.width*b.height*b.comp) as int; - b.data = pixels[:len]; + b: Bitmap + pixels := stbi_load(^c_buf[0], ^b.width, ^b.height, ^b.comp, 4) + len := (b.width*b.height*b.comp) as int + b.data = slice_ptr(pixels, len) - return b; + return b } destroy_bitmap :: proc(b: ^Bitmap) { stbi_image_free :: proc(retval_from_stbi_load: rawptr) #foreign - stbi_image_free(^b.data[0]); - b.data = b.data[:0]; - b.width = 0; - b.height = 0; - b.comp = 0; + stbi_image_free(^b.data[0]) + b.data = b.data[:0] + b.width = 0 + b.height = 0 + b.comp = 0 } diff --git a/examples/win32.odin b/examples/win32.odin index 4807cf2a2..ec543565b 100644 --- a/examples/win32.odin +++ b/examples/win32.odin @@ -1,63 +1,66 @@ -CS_VREDRAW :: 1; -CS_HREDRAW :: 2; -CW_USEDEFAULT :: 0x80000000; +#foreign_system_library "user32" +#foreign_system_library "gdi32" -WS_OVERLAPPED :: 0; -WS_MAXIMIZEBOX :: 0x00010000; -WS_MINIMIZEBOX :: 0x00020000; -WS_THICKFRAME :: 0x00040000; -WS_SYSMENU :: 0x00080000; -WS_CAPTION :: 0x00C00000; -WS_VISIBLE :: 0x10000000; -WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX; +CS_VREDRAW :: 1 +CS_HREDRAW :: 2 +CW_USEDEFAULT :: 0x80000000 -WM_DESTROY :: 0x02; -WM_CLOSE :: 0x10; -WM_QUIT :: 0x12; +WS_OVERLAPPED :: 0 +WS_MAXIMIZEBOX :: 0x00010000 +WS_MINIMIZEBOX :: 0x00020000 +WS_THICKFRAME :: 0x00040000 +WS_SYSMENU :: 0x00080000 +WS_CAPTION :: 0x00C00000 +WS_VISIBLE :: 0x10000000 +WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX -PM_REMOVE :: 1; +WM_DESTROY :: 0x02 +WM_CLOSE :: 0x10 +WM_QUIT :: 0x12 -COLOR_BACKGROUND :: 1 as HBRUSH; +PM_REMOVE :: 1 + +COLOR_BACKGROUND :: 1 as HBRUSH -HANDLE :: type rawptr; -HWND :: type HANDLE; -HDC :: type HANDLE; -HINSTANCE :: type HANDLE; -HICON :: type HANDLE; -HCURSOR :: type HANDLE; -HMENU :: type HANDLE; -HBRUSH :: type HANDLE; -WPARAM :: type uint; -LPARAM :: type int; -LRESULT :: type int; -ATOM :: type i16; -BOOL :: type i32; -POINT :: type struct { x, y: i32; }; +HANDLE :: type rawptr +HWND :: type HANDLE +HDC :: type HANDLE +HINSTANCE :: type HANDLE +HICON :: type HANDLE +HCURSOR :: type HANDLE +HMENU :: type HANDLE +HBRUSH :: type HANDLE +WPARAM :: type uint +LPARAM :: type int +LRESULT :: type int +ATOM :: type i16 +BOOL :: type i32 +POINT :: type struct { x, y: i32 } -INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE; +INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT WNDCLASSEXA :: type struct { - size, style: u32; - wnd_proc: WNDPROC; - cls_extra, wnd_extra: i32; - instance: HINSTANCE; - icon: HICON; - cursor: HCURSOR; - background: HBRUSH; - menu_name, class_name: ^u8; - sm: HICON; + size, style: u32 + wnd_proc: WNDPROC + cls_extra, wnd_extra: i32 + instance: HINSTANCE + icon: HICON + cursor: HCURSOR + background: HBRUSH + menu_name, class_name: ^u8 + sm: HICON } MSG :: type struct { - hwnd: HWND; - message: u32; - wparam: WPARAM; - lparam: LPARAM; - time: u32; - pt: POINT; + hwnd: HWND + message: u32 + wparam: WPARAM + lparam: LPARAM + time: u32 + pt: POINT } @@ -75,7 +78,7 @@ QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign sleep_ms :: proc(ms: i32) { Sleep :: proc(ms: i32) -> i32 #foreign - Sleep(ms); + Sleep(ms) } OutputDebugStringA :: proc(c_str: ^u8) #foreign @@ -102,9 +105,9 @@ DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) - GetQueryPerformanceFrequency :: proc() -> i64 { - r: i64; - _ = QueryPerformanceFrequency(^r); - return r; + r: i64 + _ = QueryPerformanceFrequency(^r) + return r } @@ -121,30 +124,30 @@ WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, ove GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign -FILE_SHARE_READ :: 0x00000001; -FILE_SHARE_WRITE :: 0x00000002; -FILE_SHARE_DELETE :: 0x00000004; -FILE_GENERIC_ALL :: 0x10000000; -FILE_GENERIC_EXECUTE :: 0x20000000; -FILE_GENERIC_WRITE :: 0x40000000; -FILE_GENERIC_READ :: 0x80000000; +FILE_SHARE_READ :: 0x00000001 +FILE_SHARE_WRITE :: 0x00000002 +FILE_SHARE_DELETE :: 0x00000004 +FILE_GENERIC_ALL :: 0x10000000 +FILE_GENERIC_EXECUTE :: 0x20000000 +FILE_GENERIC_WRITE :: 0x40000000 +FILE_GENERIC_READ :: 0x80000000 -STD_INPUT_HANDLE :: -10; -STD_OUTPUT_HANDLE :: -11; -STD_ERROR_HANDLE :: -12; +STD_INPUT_HANDLE :: -10 +STD_OUTPUT_HANDLE :: -11 +STD_ERROR_HANDLE :: -12 -CREATE_NEW :: 1; -CREATE_ALWAYS :: 2; -OPEN_EXISTING :: 3; -OPEN_ALWAYS :: 4; -TRUNCATE_EXISTING :: 5; +CREATE_NEW :: 1 +CREATE_ALWAYS :: 2 +OPEN_EXISTING :: 3 +OPEN_ALWAYS :: 4 +TRUNCATE_EXISTING :: 5 HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign HeapFree :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign GetProcessHeap :: proc() -> HANDLE #foreign -HEAP_ZERO_MEMORY :: 0x00000008; +HEAP_ZERO_MEMORY :: 0x00000008 @@ -159,37 +162,37 @@ HEAP_ZERO_MEMORY :: 0x00000008; // Windows OpenGL -PFD_TYPE_RGBA :: 0; -PFD_TYPE_COLORINDEX :: 1; -PFD_MAIN_PLANE :: 0; -PFD_OVERLAY_PLANE :: 1; -PFD_UNDERLAY_PLANE :: -1; -PFD_DOUBLEBUFFER :: 1; -PFD_STEREO :: 2; -PFD_DRAW_TO_WINDOW :: 4; -PFD_DRAW_TO_BITMAP :: 8; -PFD_SUPPORT_GDI :: 16; -PFD_SUPPORT_OPENGL :: 32; -PFD_GENERIC_FORMAT :: 64; -PFD_NEED_PALETTE :: 128; -PFD_NEED_SYSTEM_PALETTE :: 0x00000100; -PFD_SWAP_EXCHANGE :: 0x00000200; -PFD_SWAP_COPY :: 0x00000400; -PFD_SWAP_LAYER_BUFFERS :: 0x00000800; -PFD_GENERIC_ACCELERATED :: 0x00001000; -PFD_DEPTH_DONTCARE :: 0x20000000; -PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000; -PFD_STEREO_DONTCARE :: 0x80000000; +PFD_TYPE_RGBA :: 0 +PFD_TYPE_COLORINDEX :: 1 +PFD_MAIN_PLANE :: 0 +PFD_OVERLAY_PLANE :: 1 +PFD_UNDERLAY_PLANE :: -1 +PFD_DOUBLEBUFFER :: 1 +PFD_STEREO :: 2 +PFD_DRAW_TO_WINDOW :: 4 +PFD_DRAW_TO_BITMAP :: 8 +PFD_SUPPORT_GDI :: 16 +PFD_SUPPORT_OPENGL :: 32 +PFD_GENERIC_FORMAT :: 64 +PFD_NEED_PALETTE :: 128 +PFD_NEED_SYSTEM_PALETTE :: 0x00000100 +PFD_SWAP_EXCHANGE :: 0x00000200 +PFD_SWAP_COPY :: 0x00000400 +PFD_SWAP_LAYER_BUFFERS :: 0x00000800 +PFD_GENERIC_ACCELERATED :: 0x00001000 +PFD_DEPTH_DONTCARE :: 0x20000000 +PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000 +PFD_STEREO_DONTCARE :: 0x80000000 -HGLRC :: type HANDLE; -PROC :: type proc(); -wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC; +HGLRC :: type HANDLE +PROC :: type proc() +wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC PIXELFORMATDESCRIPTOR :: type struct { size, version, - flags: u32; + flags: u32 pixel_type, color_bits, @@ -210,11 +213,11 @@ PIXELFORMATDESCRIPTOR :: type struct { stencil_bits, aux_buffers, layer_type, - reserved: byte; + reserved: byte layer_mask, visible_mask, - damage_mask: u32; + damage_mask: u32 } GetDC :: proc(h: HANDLE) -> HDC #foreign @@ -223,10 +226,10 @@ ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign -WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091; -WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092; -WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126; -WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002; +WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091 +WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092 +WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126 +WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002 wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign @@ -238,159 +241,159 @@ wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign is_key_down :: proc(key: int) -> bool { - return GetAsyncKeyState(key as i32) < 0; + return GetAsyncKeyState(key as i32) < 0 } -VK_LBUTTON :: 0x01; -VK_RBUTTON :: 0x02; -VK_CANCEL :: 0x03; -VK_MBUTTON :: 0x04; +VK_LBUTTON :: 0x01 +VK_RBUTTON :: 0x02 +VK_CANCEL :: 0x03 +VK_MBUTTON :: 0x04 -VK_BACK :: 0x08; -VK_TAB :: 0x09; +VK_BACK :: 0x08 +VK_TAB :: 0x09 -VK_CLEAR :: 0x0C; -VK_RETURN :: 0x0D; +VK_CLEAR :: 0x0C +VK_RETURN :: 0x0D -VK_SHIFT :: 0x10; -VK_CONTROL :: 0x11; -VK_MENU :: 0x12; -VK_PAUSE :: 0x13; -VK_CAPITAL :: 0x14; +VK_SHIFT :: 0x10 +VK_CONTROL :: 0x11 +VK_MENU :: 0x12 +VK_PAUSE :: 0x13 +VK_CAPITAL :: 0x14 -VK_KANA :: 0x15; -VK_HANGEUL :: 0x15; -VK_HANGUL :: 0x15; -VK_JUNJA :: 0x17; -VK_FINAL :: 0x18; -VK_HANJA :: 0x19; -VK_KANJI :: 0x19; +VK_KANA :: 0x15 +VK_HANGEUL :: 0x15 +VK_HANGUL :: 0x15 +VK_JUNJA :: 0x17 +VK_FINAL :: 0x18 +VK_HANJA :: 0x19 +VK_KANJI :: 0x19 -VK_ESCAPE :: 0x1B; +VK_ESCAPE :: 0x1B -VK_CONVERT :: 0x1C; -VK_NONCONVERT :: 0x1D; -VK_ACCEPT :: 0x1E; -VK_MODECHANGE :: 0x1F; +VK_CONVERT :: 0x1C +VK_NONCONVERT :: 0x1D +VK_ACCEPT :: 0x1E +VK_MODECHANGE :: 0x1F -VK_SPACE :: 0x20; -VK_PRIOR :: 0x21; -VK_NEXT :: 0x22; -VK_END :: 0x23; -VK_HOME :: 0x24; -VK_LEFT :: 0x25; -VK_UP :: 0x26; -VK_RIGHT :: 0x27; -VK_DOWN :: 0x28; -VK_SELECT :: 0x29; -VK_PRINT :: 0x2A; -VK_EXECUTE :: 0x2B; -VK_SNAPSHOT :: 0x2C; -VK_INSERT :: 0x2D; -VK_DELETE :: 0x2E; -VK_HELP :: 0x2F; +VK_SPACE :: 0x20 +VK_PRIOR :: 0x21 +VK_NEXT :: 0x22 +VK_END :: 0x23 +VK_HOME :: 0x24 +VK_LEFT :: 0x25 +VK_UP :: 0x26 +VK_RIGHT :: 0x27 +VK_DOWN :: 0x28 +VK_SELECT :: 0x29 +VK_PRINT :: 0x2A +VK_EXECUTE :: 0x2B +VK_SNAPSHOT :: 0x2C +VK_INSERT :: 0x2D +VK_DELETE :: 0x2E +VK_HELP :: 0x2F -VK_0 :: #rune "0"; -VK_1 :: #rune "1"; -VK_2 :: #rune "2"; -VK_3 :: #rune "3"; -VK_4 :: #rune "4"; -VK_5 :: #rune "5"; -VK_6 :: #rune "6"; -VK_7 :: #rune "7"; -VK_8 :: #rune "8"; -VK_9 :: #rune "9"; +VK_0 :: #rune "0" +VK_1 :: #rune "1" +VK_2 :: #rune "2" +VK_3 :: #rune "3" +VK_4 :: #rune "4" +VK_5 :: #rune "5" +VK_6 :: #rune "6" +VK_7 :: #rune "7" +VK_8 :: #rune "8" +VK_9 :: #rune "9" -VK_A :: #rune "A"; -VK_B :: #rune "B"; -VK_C :: #rune "C"; -VK_D :: #rune "D"; -VK_E :: #rune "E"; -VK_F :: #rune "F"; -VK_G :: #rune "G"; -VK_H :: #rune "H"; -VK_I :: #rune "I"; -VK_J :: #rune "J"; -VK_K :: #rune "K"; -VK_L :: #rune "L"; -VK_M :: #rune "M"; -VK_N :: #rune "N"; -VK_O :: #rune "O"; -VK_P :: #rune "P"; -VK_Q :: #rune "Q"; -VK_R :: #rune "R"; -VK_S :: #rune "S"; -VK_T :: #rune "T"; -VK_U :: #rune "U"; -VK_V :: #rune "V"; -VK_W :: #rune "W"; -VK_X :: #rune "X"; -VK_Y :: #rune "Y"; -VK_Z :: #rune "Z"; +VK_A :: #rune "A" +VK_B :: #rune "B" +VK_C :: #rune "C" +VK_D :: #rune "D" +VK_E :: #rune "E" +VK_F :: #rune "F" +VK_G :: #rune "G" +VK_H :: #rune "H" +VK_I :: #rune "I" +VK_J :: #rune "J" +VK_K :: #rune "K" +VK_L :: #rune "L" +VK_M :: #rune "M" +VK_N :: #rune "N" +VK_O :: #rune "O" +VK_P :: #rune "P" +VK_Q :: #rune "Q" +VK_R :: #rune "R" +VK_S :: #rune "S" +VK_T :: #rune "T" +VK_U :: #rune "U" +VK_V :: #rune "V" +VK_W :: #rune "W" +VK_X :: #rune "X" +VK_Y :: #rune "Y" +VK_Z :: #rune "Z" -VK_LWIN :: 0x5B; -VK_RWIN :: 0x5C; -VK_APPS :: 0x5D; +VK_LWIN :: 0x5B +VK_RWIN :: 0x5C +VK_APPS :: 0x5D -VK_NUMPAD0 :: 0x60; -VK_NUMPAD1 :: 0x61; -VK_NUMPAD2 :: 0x62; -VK_NUMPAD3 :: 0x63; -VK_NUMPAD4 :: 0x64; -VK_NUMPAD5 :: 0x65; -VK_NUMPAD6 :: 0x66; -VK_NUMPAD7 :: 0x67; -VK_NUMPAD8 :: 0x68; -VK_NUMPAD9 :: 0x69; -VK_MULTIPLY :: 0x6A; -VK_ADD :: 0x6B; -VK_SEPARATOR :: 0x6C; -VK_SUBTRACT :: 0x6D; -VK_DECIMAL :: 0x6E; -VK_DIVIDE :: 0x6F; -VK_F1 :: 0x70; -VK_F2 :: 0x71; -VK_F3 :: 0x72; -VK_F4 :: 0x73; -VK_F5 :: 0x74; -VK_F6 :: 0x75; -VK_F7 :: 0x76; -VK_F8 :: 0x77; -VK_F9 :: 0x78; -VK_F10 :: 0x79; -VK_F11 :: 0x7A; -VK_F12 :: 0x7B; -VK_F13 :: 0x7C; -VK_F14 :: 0x7D; -VK_F15 :: 0x7E; -VK_F16 :: 0x7F; -VK_F17 :: 0x80; -VK_F18 :: 0x81; -VK_F19 :: 0x82; -VK_F20 :: 0x83; -VK_F21 :: 0x84; -VK_F22 :: 0x85; -VK_F23 :: 0x86; -VK_F24 :: 0x87; +VK_NUMPAD0 :: 0x60 +VK_NUMPAD1 :: 0x61 +VK_NUMPAD2 :: 0x62 +VK_NUMPAD3 :: 0x63 +VK_NUMPAD4 :: 0x64 +VK_NUMPAD5 :: 0x65 +VK_NUMPAD6 :: 0x66 +VK_NUMPAD7 :: 0x67 +VK_NUMPAD8 :: 0x68 +VK_NUMPAD9 :: 0x69 +VK_MULTIPLY :: 0x6A +VK_ADD :: 0x6B +VK_SEPARATOR :: 0x6C +VK_SUBTRACT :: 0x6D +VK_DECIMAL :: 0x6E +VK_DIVIDE :: 0x6F +VK_F1 :: 0x70 +VK_F2 :: 0x71 +VK_F3 :: 0x72 +VK_F4 :: 0x73 +VK_F5 :: 0x74 +VK_F6 :: 0x75 +VK_F7 :: 0x76 +VK_F8 :: 0x77 +VK_F9 :: 0x78 +VK_F10 :: 0x79 +VK_F11 :: 0x7A +VK_F12 :: 0x7B +VK_F13 :: 0x7C +VK_F14 :: 0x7D +VK_F15 :: 0x7E +VK_F16 :: 0x7F +VK_F17 :: 0x80 +VK_F18 :: 0x81 +VK_F19 :: 0x82 +VK_F20 :: 0x83 +VK_F21 :: 0x84 +VK_F22 :: 0x85 +VK_F23 :: 0x86 +VK_F24 :: 0x87 -VK_NUMLOCK :: 0x90; -VK_SCROLL :: 0x91; +VK_NUMLOCK :: 0x90 +VK_SCROLL :: 0x91 -VK_LSHIFT :: 0xA0; -VK_RSHIFT :: 0xA1; -VK_LCONTROL :: 0xA2; -VK_RCONTROL :: 0xA3; -VK_LMENU :: 0xA4; -VK_RMENU :: 0xA5; -VK_PROCESSKEY :: 0xE5; -VK_ATTN :: 0xF6; -VK_CRSEL :: 0xF7; -VK_EXSEL :: 0xF8; -VK_EREOF :: 0xF9; -VK_PLAY :: 0xFA; -VK_ZOOM :: 0xFB; -VK_NONAME :: 0xFC; -VK_PA1 :: 0xFD; -VK_OEM_CLEAR :: 0xFE; +VK_LSHIFT :: 0xA0 +VK_RSHIFT :: 0xA1 +VK_LCONTROL :: 0xA2 +VK_RCONTROL :: 0xA3 +VK_LMENU :: 0xA4 +VK_RMENU :: 0xA5 +VK_PROCESSKEY :: 0xE5 +VK_ATTN :: 0xF6 +VK_CRSEL :: 0xF7 +VK_EXSEL :: 0xF8 +VK_EREOF :: 0xF9 +VK_PLAY :: 0xFA +VK_ZOOM :: 0xFB +VK_NONAME :: 0xFC +VK_PA1 :: 0xFD +VK_OEM_CLEAR :: 0xFE diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 717c70b57..d239d0995 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -530,7 +530,7 @@ void add_entity_definition(CheckerInfo *i, AstNode *identifier, Entity *entity) map_set(&i->definitions, key, entity); } -void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) { +b32 add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) { if (!are_strings_equal(entity->token.string, make_string("_"))) { Entity *insert_entity = scope_insert_entity(scope, entity); if (insert_entity) { @@ -541,18 +541,20 @@ void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) { "\tat %.*s(%td:%td)", LIT(entity->token.string), LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column); + return false; } else { error(&c->error_collector, entity->token, "Redeclararation of `%.*s` in this scope\n" "\tat %.*s(%td:%td)", LIT(entity->token.string), LIT(entity->token.pos.file), entity->token.pos.line, entity->token.pos.column); + return false; } - return; } } if (identifier != NULL) add_entity_definition(&c->info, identifier, entity); + return true; } void add_entity_use(CheckerInfo *i, AstNode *identifier, Entity *entity) { @@ -733,6 +735,10 @@ void check_parsed_files(Checker *c) { case_ast_node(ld, LoadDecl, decl); // NOTE(bill): ignore case_end; + case_ast_node(fsl, ForeignSystemLibrary, decl); + // NOTE(bill): ignore + case_end; + default: error(&c->error_collector, ast_node_token(decl), "Only declarations are allowed at file scope"); diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp index de4095766..8667aa0c7 100644 --- a/src/checker/entity.cpp +++ b/src/checker/entity.cpp @@ -6,6 +6,7 @@ enum BuiltinProcId; ENTITY_KIND(Invalid), \ ENTITY_KIND(Constant), \ ENTITY_KIND(Variable), \ + ENTITY_KIND(UsingVariable), \ ENTITY_KIND(TypeName), \ ENTITY_KIND(Procedure), \ ENTITY_KIND(Builtin), \ @@ -35,6 +36,7 @@ struct Entity { Token token; Type *type; Entity *using_parent; + AstNode *using_expr; union { struct { ExactValue value; } Constant; @@ -44,9 +46,9 @@ struct Entity { b8 is_field; // Is struct field b8 anonymous; // Variable is an anonymous } Variable; - struct { - b8 used; - } Procedure; + struct {} UsingVariable; + struct {} TypeName; + struct { b8 used; } Procedure; struct { BuiltinProcId id; } Builtin; }; }; @@ -72,6 +74,14 @@ Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *typ return entity; } +Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) { + GB_ASSERT(parent != NULL); + Entity *entity = alloc_entity(a, Entity_UsingVariable, parent->scope, token, type); + entity->using_parent = parent; + return entity; +} + + Entity *make_entity_constant(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value) { Entity *entity = alloc_entity(a, Entity_Constant, scope, token, type); entity->Constant.value = value; diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index c252871a8..b0ec95805 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -4,7 +4,7 @@ void check_expr_or_type (Checker *c, Operand *operand, AstNode *expre ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL); Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL, CycleChecker *cycle_checker = NULL); void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker); -void check_selector (Checker *c, Operand *operand, AstNode *node); +Entity * check_selector (Checker *c, Operand *operand, AstNode *node); void check_not_tuple (Checker *c, Operand *operand); b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value); void convert_to_typed (Checker *c, Operand *operand, Type *target_type); @@ -143,6 +143,7 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map error(&c->error_collector, e->token, "`%.*s` is already declared in `%s`", LIT(name), str); } else { map_set(entity_map, key, f); + add_entity(c, c->context.scope, NULL, f); if (f->Variable.anonymous) { populate_using_entity_map(c, node, f->type, entity_map); } @@ -338,6 +339,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecke } else { map_set(&entity_map, key, e); fields[field_index++] = e; + add_entity(c, c->context.scope, name, e); } add_entity_use(&c->info, name, e); } @@ -610,6 +612,11 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl o->mode = Addressing_Builtin; break; + case Entity_UsingVariable: + // TODO(bill): Entity_UsingVariable: is this correct? + o->mode = Addressing_Variable; + break; + default: GB_PANIC("Compiler error: Unknown EntityKind"); break; @@ -727,6 +734,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c check_open_scope(c, e); check_struct_type(c, type, e, cycle_checker); check_close_scope(c); + type->Struct.node = e; goto end; case_end; @@ -736,6 +744,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c check_open_scope(c, e); check_union_type(c, type, e, cycle_checker); check_close_scope(c); + type->Union.node = e; goto end; case_end; @@ -1746,7 +1755,7 @@ Selection lookup_field(Type *type_, String field_name, AddressingMode mode, Sele return sel; } -void check_selector(Checker *c, Operand *operand, AstNode *node) { +Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { GB_ASSERT(node->kind == AstNode_SelectorExpr); ast_node(se, SelectorExpr, node); @@ -1764,7 +1773,7 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) { error(&c->error_collector, ast_node_token(op_expr), "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str); operand->mode = Addressing_Invalid; operand->expr = node; - return; + return NULL; } add_entity_use(&c->info, selector, entity); @@ -1779,11 +1788,12 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) { if (operand->mode != Addressing_Variable) operand->mode = Addressing_Value; } + return entity; } else { operand->mode = Addressing_Invalid; operand->expr = node; } - + return NULL; } b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) { @@ -1886,7 +1896,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) return false; } - operand->mode = Addressing_Value; + operand->mode = Addressing_NoValue; operand->type = NULL; } break; @@ -2967,6 +2977,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case AstNode_ArrayType: case AstNode_VectorType: case AstNode_StructType: + case AstNode_UnionType: o->mode = Addressing_Type; o->type = check_type(c, node); break; @@ -3240,6 +3251,13 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, "}"); case_end; + case_ast_node(st, UnionType, node); + str = gb_string_appendc(str, "union{"); + // str = write_field_list_to_string(str, st->decl_list, ", "); + str = gb_string_appendc(str, "}"); + case_end; + + case_ast_node(et, EnumType, node); str = gb_string_appendc(str, "enum "); if (et->base_type != NULL) { diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index a0d1838a8..1bbaf1040 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -436,6 +436,107 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc +void check_var_decl(Checker *c, AstNode *node) { + ast_node(vd, VarDecl, node); + isize entity_count = vd->name_count; + isize entity_index = 0; + Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); + switch (vd->kind) { + case Declaration_Mutable: { + Entity **new_entities = gb_alloc_array(c->allocator, Entity *, entity_count); + isize new_entity_count = 0; + + for (AstNode *name = vd->name_list; name != NULL; name = name->next) { + Entity *entity = NULL; + Token token = name->Ident.token; + if (name->kind == AstNode_Ident) { + String str = token.string; + Entity *found = NULL; + // NOTE(bill): Ignore assignments to `_` + b32 can_be_ignored = are_strings_equal(str, make_string("_")); + if (!can_be_ignored) { + found = current_scope_lookup_entity(c->context.scope, str); + } + if (found == NULL) { + entity = make_entity_variable(c->allocator, c->context.scope, token, NULL); + if (!can_be_ignored) { + new_entities[new_entity_count++] = entity; + } + add_entity_definition(&c->info, name, entity); + } else { + entity = found; + } + } else { + error(&c->error_collector, token, "A variable declaration must be an identifier"); + } + if (entity == NULL) + entity = make_entity_dummy_variable(c->allocator, c->global_scope, token); + entities[entity_index++] = entity; + } + + Type *init_type = NULL; + if (vd->type) { + init_type = check_type(c, vd->type, NULL); + if (init_type == NULL) + init_type = t_invalid; + } + + for (isize i = 0; i < entity_count; i++) { + Entity *e = entities[i]; + GB_ASSERT(e != NULL); + if (e->Variable.visited) { + e->type = t_invalid; + continue; + } + e->Variable.visited = true; + + if (e->type == NULL) + e->type = init_type; + } + + check_init_variables(c, entities, entity_count, vd->value_list, vd->value_count, make_string("variable declaration")); + + AstNode *name = vd->name_list; + for (isize i = 0; i < new_entity_count; i++, name = name->next) { + add_entity(c, c->context.scope, name, new_entities[i]); + } + + } break; + + case Declaration_Immutable: { + for (AstNode *name = vd->name_list, *value = vd->value_list; + name != NULL && value != NULL; + name = name->next, value = value->next) { + GB_ASSERT(name->kind == AstNode_Ident); + ExactValue v = {ExactValue_Invalid}; + ast_node(i, Ident, name); + Entity *e = make_entity_constant(c->allocator, c->context.scope, i->token, NULL, v); + entities[entity_index++] = e; + check_const_decl(c, e, vd->type, value); + } + + isize lhs_count = vd->name_count; + isize rhs_count = vd->value_count; + + // TODO(bill): Better error messages or is this good enough? + if (rhs_count == 0 && vd->type == NULL) { + error(&c->error_collector, ast_node_token(node), "Missing type or initial expression"); + } else if (lhs_count < rhs_count) { + error(&c->error_collector, ast_node_token(node), "Extra initial expression"); + } + + AstNode *name = vd->name_list; + for (isize i = 0; i < entity_count; i++, name = name->next) { + add_entity(c, c->context.scope, name, entities[i]); + } + } break; + + default: + error(&c->error_collector, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST."); + return; + } +} + void check_stmt(Checker *c, AstNode *node, u32 flags) { switch (node->kind) { @@ -688,16 +789,28 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_ast_node(us, UsingStmt, node); switch (us->node->kind) { case_ast_node(es, ExprStmt, us->node); - AstNode *ident = es->expr; - GB_ASSERT(ident->kind == AstNode_Ident); - String name = ident->Ident.token.string; + Entity *e = NULL; + + b32 is_selector = false; + AstNode *expr = unparen_expr(es->expr); + if (expr->kind == AstNode_Ident) { + String name = expr->Ident.token.string; + e = scope_lookup_entity(c, c->context.scope, name); + } else if (expr->kind == AstNode_SelectorExpr) { + Operand o = {}; + check_expr_base(c, &o, expr->SelectorExpr.expr); + e = check_selector(c, &o, expr); + is_selector = true; + } - Entity *e = scope_lookup_entity(c, c->context.scope, name); if (e == NULL) { error(&c->error_collector, us->token, "`using` applied to an unknown entity"); return; } + gbString expr_str = expr_to_string(expr); + defer (gb_string_free(expr_str)); + switch (e->kind) { case Entity_TypeName: { Type *t = get_base_type(e->type); @@ -706,20 +819,34 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { Entity *f = t->Enum.fields[i]; Entity *found = scope_insert_entity(c->context.scope, f); if (found != NULL) { - error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of the constant: %.*s", LIT(name), LIT(found->token.string)); + error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of the constant: %.*s", expr_str, LIT(found->token.string)); return; } f->using_parent = e; } } else if (t->kind == Type_Struct) { - for (isize i = 0; i < t->Struct.other_field_count; i++) { - Entity *f = t->Struct.other_fields[i]; - Entity *found = scope_insert_entity(c->context.scope, f); - if (found != NULL) { - error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(found->token.string)); - return; + Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node)); + if (found != NULL) { + gb_for_array(i, (*found)->elements.entries) { + Entity *f = (*found)->elements.entries[i].value; + Entity *found = scope_insert_entity(c->context.scope, f); + if (found != NULL) { + error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); + return; + } + f->using_parent = e; + } + } else { + for (isize i = 0; i < t->Struct.other_field_count; i++) { + // TODO(bill): using field types too + Entity *f = t->Struct.other_fields[i]; + Entity *found = scope_insert_entity(c->context.scope, f); + if (found != NULL) { + error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); + return; + } + f->using_parent = e; } - f->using_parent = e; } } } break; @@ -733,13 +860,70 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { error(&c->error_collector, us->token, "`using` cannot be applied to a procedure"); break; + case Entity_Variable: + case Entity_UsingVariable: { + Type *t = get_base_type(type_deref(e->type)); + if (t->kind == Type_Struct || t->kind == Type_Union) { + // IMPORTANT HACK(bill): Entity_(Struct|Union) overlap in some memory allowing + // for some variables to accessed to same + Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node)); + GB_ASSERT(found != NULL); + gb_for_array(i, (*found)->elements.entries) { + Entity *f = (*found)->elements.entries[i].value; + if (f->kind == Entity_Variable) { + Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type); + if (is_selector) { + uvar->using_expr = expr; + } + Entity *prev = scope_insert_entity(c->context.scope, uvar); + if (prev != NULL) { + error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string)); + return; + } + } + } + } else { + error(&c->error_collector, us->token, "`using` can only be applied to variables of type struct or union"); + return; + } + } break; + default: GB_PANIC("TODO(bill): using Ident"); } case_end; case_ast_node(vd, VarDecl, us->node); - GB_PANIC("TODO(bill): using VarDecl"); + if (vd->name_count > 1) { + error(&c->error_collector, us->token, "`using` can only be applied to one variable of the same type"); + } + check_var_decl(c, us->node); + ast_node(i, Ident, vd->name_list); + + String name = i->token.string; + Entity *e = scope_lookup_entity(c, c->context.scope, name); + + Type *t = get_base_type(type_deref(e->type)); + if (t->kind == Type_Struct || t->kind == Type_Union) { + // IMPORTANT HACK(bill): Entity_(Struct|Union) overlap in some memory allowing + // for some variables to accessed to same + Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node)); + GB_ASSERT(found != NULL); + gb_for_array(i, (*found)->elements.entries) { + Entity *f = (*found)->elements.entries[i].value; + if (f->kind == Entity_Variable) { + Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type); + Entity *prev = scope_insert_entity(c->context.scope, uvar); + if (prev != NULL) { + error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string)); + return; + } + } + } + } else { + error(&c->error_collector, us->token, "`using` can only be applied to variables of type struct or union"); + return; + } case_end; @@ -755,103 +939,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_ast_node(vd, VarDecl, node); - isize entity_count = vd->name_count; - isize entity_index = 0; - Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); - switch (vd->kind) { - case Declaration_Mutable: { - Entity **new_entities = gb_alloc_array(c->allocator, Entity *, entity_count); - isize new_entity_count = 0; - - for (AstNode *name = vd->name_list; name != NULL; name = name->next) { - Entity *entity = NULL; - Token token = name->Ident.token; - if (name->kind == AstNode_Ident) { - String str = token.string; - Entity *found = NULL; - // NOTE(bill): Ignore assignments to `_` - b32 can_be_ignored = are_strings_equal(str, make_string("_")); - if (!can_be_ignored) { - found = current_scope_lookup_entity(c->context.scope, str); - } - if (found == NULL) { - entity = make_entity_variable(c->allocator, c->context.scope, token, NULL); - if (!can_be_ignored) { - new_entities[new_entity_count++] = entity; - } - add_entity_definition(&c->info, name, entity); - } else { - entity = found; - } - } else { - error(&c->error_collector, token, "A variable declaration must be an identifier"); - } - if (entity == NULL) - entity = make_entity_dummy_variable(c->allocator, c->global_scope, token); - entities[entity_index++] = entity; - } - - Type *init_type = NULL; - if (vd->type) { - init_type = check_type(c, vd->type, NULL); - if (init_type == NULL) - init_type = t_invalid; - } - - for (isize i = 0; i < entity_count; i++) { - Entity *e = entities[i]; - GB_ASSERT(e != NULL); - if (e->Variable.visited) { - e->type = t_invalid; - continue; - } - e->Variable.visited = true; - - if (e->type == NULL) - e->type = init_type; - } - - check_init_variables(c, entities, entity_count, vd->value_list, vd->value_count, make_string("variable declaration")); - - AstNode *name = vd->name_list; - for (isize i = 0; i < new_entity_count; i++, name = name->next) { - add_entity(c, c->context.scope, name, new_entities[i]); - } - - } break; - - case Declaration_Immutable: { - for (AstNode *name = vd->name_list, *value = vd->value_list; - name != NULL && value != NULL; - name = name->next, value = value->next) { - GB_ASSERT(name->kind == AstNode_Ident); - ExactValue v = {ExactValue_Invalid}; - ast_node(i, Ident, name); - Entity *e = make_entity_constant(c->allocator, c->context.scope, i->token, NULL, v); - entities[entity_index++] = e; - check_const_decl(c, e, vd->type, value); - } - - isize lhs_count = vd->name_count; - isize rhs_count = vd->value_count; - - // TODO(bill): Better error messages or is this good enough? - if (rhs_count == 0 && vd->type == NULL) { - error(&c->error_collector, ast_node_token(node), "Missing type or initial expression"); - } else if (lhs_count < rhs_count) { - error(&c->error_collector, ast_node_token(node), "Extra initial expression"); - } - - AstNode *name = vd->name_list; - for (isize i = 0; i < entity_count; i++, name = name->next) { - add_entity(c, c->context.scope, name, entities[i]); - } - } break; - - default: - error(&c->error_collector, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST."); - return; - } + check_var_decl(c, node); case_end; case_ast_node(pd, ProcDecl, node); diff --git a/src/checker/type.cpp b/src/checker/type.cpp index bd1ff223e..d5cef4b07 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -107,18 +107,22 @@ struct Type { // Theses are arrays Entity **fields; // Entity_Variable isize field_count; // == offset_count + AstNode *node; + i64 * offsets; b32 are_offsets_set; b32 is_packed; Entity **other_fields; // Entity_Constant or Entity_TypeName isize other_field_count; + } Struct; struct { - // IMPORTANT HACK(bill): The positions of fields and field_count + // IMPORTANT HACK(bill): The positions of fields, field_count, and node // must be same for Struct and Union Entity **fields; // Entity_Variable isize field_count; + AstNode *node; } Union; struct { Type *elem; } Pointer; struct { diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index bf2470a28..b01a50d33 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -2034,6 +2034,30 @@ ssaValue *ssa_emit_deep_field_gep(ssaProcedure *proc, Type *type, ssaValue *e, S } +ssaValue *ssa_add_using_variable(ssaProcedure *proc, Entity *e) { + GB_ASSERT(e->kind == Entity_UsingVariable); + String name = e->token.string; + Entity *parent = e->using_parent; + ssaValue *p = NULL; + if (parent->kind == Entity_UsingVariable) { + p = ssa_add_using_variable(proc, parent); + } + + Selection sel = lookup_field(parent->type, name, Addressing_Variable); + GB_ASSERT(sel.entity != NULL); + ssaValue **pv = map_get(&proc->module->values, hash_pointer(parent)); + ssaValue *v = NULL; + if (pv != NULL) { + v = *pv; + } else { + v = ssa_build_addr(proc, e->using_expr).addr; + } + GB_ASSERT(v != NULL); + ssaValue *var = ssa_emit_deep_field_gep(proc, parent->type, v, sel); + map_set(&proc->module->values, hash_pointer(e), var); + return var; +} + ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { switch (expr->kind) { case_ast_node(i, Ident, expr); @@ -2047,9 +2071,13 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { ssaValue **found = map_get(&proc->module->values, hash_pointer(e)); if (found) { v = *found; - } else { + } else if (e->kind == Entity_UsingVariable) { + v = ssa_add_using_variable(proc, e); + } + if (v == NULL) { GB_PANIC("Unknown value: %s, entity: %p\n", expr_to_string(expr), e); } + return ssa_make_addr(v, expr); case_end; @@ -2286,6 +2314,13 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { case_ast_node(bs, EmptyStmt, node); case_end; + case_ast_node(us, UsingStmt, node); + AstNode *decl = unparen_expr(us->node); + if (decl->kind == AstNode_VarDecl) { + ssa_build_stmt(proc, decl); + } + case_end; + case_ast_node(vd, VarDecl, node); if (vd->kind == Declaration_Mutable) { if (vd->name_count == vd->value_count) { // 1:1 assigment diff --git a/src/main.cpp b/src/main.cpp index 26ef255ce..b37ffad48 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -93,14 +93,26 @@ int main(int argc, char **argv) { #if 1 #endif + gbString lib_str = gb_string_make(gb_heap_allocator(), "-lKernel32.lib"); + char lib_str_buf[1024] = {}; + gb_for_array(i, parser.system_libraries) { + String lib = parser.system_libraries[i]; + isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), + " -l%.*s.lib", LIT(lib)); + lib_str = gb_string_appendc(lib_str, lib_str_buf); + } + + exit_code = win32_exec_command_line_app( "clang -o %.*s.exe %.*s.bc " "-Wno-override-module " // "-nostartfiles " - "-lKernel32.lib -lUser32.lib -lGdi32.lib -lOpengl32.lib " + "%s " , cast(int)base_name_len, output_name, - cast(int)base_name_len, output_name); + cast(int)base_name_len, output_name, + lib_str); + gb_string_free(lib_str); if (exit_code != 0) return exit_code; diff --git a/src/parser.cpp b/src/parser.cpp index e3be11940..e4544dae9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -32,6 +32,7 @@ struct AstFile { AstScope *file_scope; AstScope *curr_scope; + AstNode *curr_proc; isize scope_level; ErrorCollector error_collector; @@ -60,6 +61,8 @@ struct Parser { String init_fullpath; gbArray(AstFile) files; gbArray(String) loads; + gbArray(String) libraries; + gbArray(String) system_libraries; isize load_index; isize total_token_count; }; @@ -193,6 +196,7 @@ AST_NODE_KIND(_DeclBegin, struct{}) \ }) \ AST_NODE_KIND(TypeDecl, struct { Token token; AstNode *name, *type; }) \ AST_NODE_KIND(LoadDecl, struct { Token token, filepath; }) \ + AST_NODE_KIND(ForeignSystemLibrary, struct { Token token, filepath; }) \ AST_NODE_KIND(_DeclEnd, struct{}) \ AST_NODE_KIND(_TypeBegin, struct{}) \ AST_NODE_KIND(Field, struct { \ @@ -368,6 +372,8 @@ Token ast_node_token(AstNode *node) { return node->TypeDecl.token; case AstNode_LoadDecl: return node->LoadDecl.token; + case AstNode_ForeignSystemLibrary: + return node->ForeignSystemLibrary.token; case AstNode_Field: { if (node->Field.name_list) return ast_node_token(node->Field.name_list); @@ -831,6 +837,12 @@ gb_inline AstNode *make_load_decl(AstFile *f, Token token, Token filepath) { return result; } +gb_inline AstNode *make_foreign_system_library(AstFile *f, Token token, Token filepath) { + AstNode *result = make_node(f, AstNode_ForeignSystemLibrary); + result->ForeignSystemLibrary.token = token; + result->ForeignSystemLibrary.filepath = filepath; + return result; +} gb_inline b32 next_token(AstFile *f) { if (f->cursor+1 < f->tokens + gb_array_count(f->tokens)) { @@ -967,11 +979,15 @@ b32 expect_semicolon_after_stmt(AstFile *f, AstNode *s) { } if (!allow_token(f, Token_Semicolon)) { - // CLEANUP(bill): Semicolon handling in parser - ast_file_err(f, f->cursor[0], - "Expected `;` after %.*s, got `%.*s`", - LIT(ast_node_strings[s->kind]), LIT(token_strings[f->cursor[0].kind])); - return false; + if (f->cursor[0].pos.line == f->cursor[-1].pos.line) { + if (f->cursor[0].kind != Token_CloseBrace) { + // CLEANUP(bill): Semicolon handling in parser + ast_file_err(f, f->cursor[0], + "Expected `;` after %.*s, got `%.*s`", + LIT(ast_node_strings[s->kind]), LIT(token_strings[f->cursor[0].kind])); + return false; + } + } } return true; } @@ -1203,7 +1219,10 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { // Parse Procedure Type or Literal case Token_proc: { AstScope *scope = NULL; + AstNode *curr_proc = f->curr_proc; AstNode *type = parse_proc_type(f, &scope); + f->curr_proc = type; + defer (f->curr_proc = curr_proc); u64 tags = 0; String foreign_name = {}; @@ -1862,8 +1881,13 @@ AstNode *parse_identifier_or_type(AstFile *f) { return make_enum_type(f, token, base_type, root, field_count); } - case Token_proc: - return parse_proc_type(f, NULL); + case Token_proc: { + AstNode *curr_proc = f->curr_proc; + AstNode *type = parse_proc_type(f, NULL); + f->curr_proc = type; + f->curr_proc = curr_proc; + return type; + } case Token_OpenParen: { @@ -2126,10 +2150,14 @@ AstNode *parse_return_stmt(AstFile *f) { Token token = expect_token(f, Token_return); AstNode *result = NULL; isize result_count = 0; - if (f->cursor[0].kind != Token_Semicolon) + + if (f->cursor[0].kind != Token_Semicolon && f->cursor[0].kind != Token_CloseBrace && + f->cursor[0].pos.line == token.pos.line) { result = parse_rhs_expr_list(f, &result_count); - if (f->cursor[0].kind != Token_CloseBrace) - expect_token(f, Token_Semicolon); + } + if (f->cursor[0].kind != Token_CloseBrace) { + expect_semicolon_after_stmt(f, result); + } return make_return_stmt(f, token, result, result_count); } @@ -2248,11 +2276,15 @@ AstNode *parse_stmt(AstFile *f) { b32 valid = false; switch (node->kind) { - case AstNode_ExprStmt: - if (node->ExprStmt.expr->kind == AstNode_Ident) { + case AstNode_ExprStmt: { + AstNode *e = unparen_expr(node->ExprStmt.expr); + while (e->kind == AstNode_SelectorExpr) { + e = unparen_expr(e->SelectorExpr.selector); + } + if (e->kind == AstNode_Ident) { valid = true; } - break; + } break; case AstNode_VarDecl: if (node->VarDecl.kind == Declaration_Mutable) { valid = true; @@ -2279,6 +2311,13 @@ AstNode *parse_stmt(AstFile *f) { } ast_file_err(f, token, "You cannot `load` within a procedure. This must be done at the file scope."); return make_bad_decl(f, token, file_path); + } else if (are_strings_equal(s->TagStmt.name.string, make_string("foreign_system_library"))) { + Token file_path = expect_token(f, Token_String); + if (f->curr_scope == f->file_scope) { + return make_foreign_system_library(f, s->TagStmt.token, file_path); + } + ast_file_err(f, token, "You cannot using `foreign_system_library` within a procedure. This must be done at the file scope."); + return make_bad_decl(f, token, file_path); } else if (are_strings_equal(s->TagStmt.name.string, make_string("thread_local"))) { AstNode *var_decl = parse_simple_stmt(f); if (var_decl->kind != AstNode_VarDecl || @@ -2387,6 +2426,8 @@ void destroy_ast_file(AstFile *f) { b32 init_parser(Parser *p) { gb_array_init(p->files, gb_heap_allocator()); gb_array_init(p->loads, gb_heap_allocator()); + gb_array_init(p->libraries, gb_heap_allocator()); + gb_array_init(p->system_libraries, gb_heap_allocator()); return true; } @@ -2402,6 +2443,8 @@ void destroy_parser(Parser *p) { #endif gb_array_free(p->files); gb_array_free(p->loads); + gb_array_free(p->libraries); + gb_array_free(p->system_libraries); } // NOTE(bill): Returns true if it's added @@ -2417,6 +2460,18 @@ b32 try_add_load_path(Parser *p, String import_file) { return true; } +// NOTE(bill): Returns true if it's added +b32 try_add_foreign_system_library_path(Parser *p, String import_file) { + gb_for_array(i, p->system_libraries) { + String import = p->system_libraries[i]; + if (are_strings_equal(import, import_file)) { + return false; + } + } + gb_array_append(p->system_libraries, import_file); + return true; +} + gb_global Rune illegal_import_runes[] = { '"', '\'', '`', ' ', '\\', // NOTE(bill): Disallow windows style filepaths @@ -2480,7 +2535,7 @@ void parse_file(Parser *p, AstFile *f) { String file_str = id->filepath.string; if (!is_load_path_valid(file_str)) { - ast_file_err(f, ast_node_token(node), "Invalid import path"); + ast_file_err(f, ast_node_token(node), "Invalid `load` path"); continue; } @@ -2498,6 +2553,16 @@ void parse_file(Parser *p, AstFile *f) { if (!try_add_load_path(p, import_file)) { gb_free(gb_heap_allocator(), import_file.text); } + } else if (node->kind == AstNode_ForeignSystemLibrary) { + auto *id = &node->ForeignSystemLibrary; + String file_str = id->filepath.string; + + if (!is_load_path_valid(file_str)) { + ast_file_err(f, ast_node_token(node), "Invalid `foreign_system_library` path"); + continue; + } + + try_add_foreign_system_library_path(p, file_str); } } }