Browse Source

Merge branch 'master' into separate-int-word-sizes

gingerBill 2 years ago
parent
commit
e82146bf17
62 changed files with 1551 additions and 164 deletions
  1. 2 7
      .github/workflows/ci.yml
  2. 1 1
      README.md
  3. 1 1
      build_odin.sh
  4. 9 9
      core/bufio/lookahead_reader.odin
  5. 8 0
      core/bufio/writer.odin
  6. 137 78
      core/container/bit_array/bit_array.odin
  7. 2 2
      core/encoding/json/marshal.odin
  8. 35 5
      core/fmt/fmt_os.odin
  9. 6 6
      core/math/big/prime.odin
  10. 5 4
      core/math/linalg/extended.odin
  11. 5 3
      core/net/dns.odin
  12. 1 1
      core/reflect/types.odin
  13. 26 1
      core/strings/builder.odin
  14. 4 4
      core/strings/strings.odin
  15. 1 0
      core/sys/windows/user32.odin
  16. 2 2
      core/text/edit/text_edit.odin
  17. 7 3
      src/build_settings.cpp
  18. 2 0
      src/check_expr.cpp
  19. 15 8
      src/check_type.cpp
  20. 28 11
      src/common_memory.cpp
  21. 34 0
      src/error.cpp
  22. 4 1
      src/llvm_backend_expr.cpp
  23. 4 0
      src/main.cpp
  24. 47 3
      src/parser.cpp
  25. 3 1
      src/ptr_map.cpp
  26. 3 1
      src/string_map.cpp
  27. 30 0
      vendor/darwin/Foundation/NSNotification.odin
  28. 845 0
      vendor/darwin/Metal/MetalClasses.odin
  29. 86 6
      vendor/darwin/Metal/MetalEnums.odin
  30. 12 2
      vendor/darwin/Metal/MetalErrors.odin
  31. 7 0
      vendor/darwin/Metal/MetalProcedures.odin
  32. 2 0
      vendor/darwin/Metal/MetalTypes.odin
  33. 11 0
      vendor/darwin/QuartzCore/QuartzCore.odin
  34. 3 4
      vendor/sdl2/sdl2.odin
  35. 6 0
      vendor/sdl2/sdl_audio.odin
  36. 6 0
      vendor/sdl2/sdl_blendmode.odin
  37. 6 0
      vendor/sdl2/sdl_cpuinfo.odin
  38. 6 0
      vendor/sdl2/sdl_events.odin
  39. 6 0
      vendor/sdl2/sdl_gamecontroller.odin
  40. 6 0
      vendor/sdl2/sdl_gesture_haptic.odin
  41. 6 0
      vendor/sdl2/sdl_hints.odin
  42. 6 0
      vendor/sdl2/sdl_joystick.odin
  43. 6 0
      vendor/sdl2/sdl_keyboard.odin
  44. 1 0
      vendor/sdl2/sdl_keycode.odin
  45. 6 0
      vendor/sdl2/sdl_log.odin
  46. 6 0
      vendor/sdl2/sdl_messagebox.odin
  47. 6 0
      vendor/sdl2/sdl_metal.odin
  48. 6 0
      vendor/sdl2/sdl_mouse.odin
  49. 6 0
      vendor/sdl2/sdl_mutex.odin
  50. 6 0
      vendor/sdl2/sdl_pixels.odin
  51. 6 0
      vendor/sdl2/sdl_rect.odin
  52. 6 0
      vendor/sdl2/sdl_render.odin
  53. 6 0
      vendor/sdl2/sdl_rwops.odin
  54. 6 0
      vendor/sdl2/sdl_stdinc.odin
  55. 6 0
      vendor/sdl2/sdl_surface.odin
  56. 6 0
      vendor/sdl2/sdl_system.odin
  57. 6 0
      vendor/sdl2/sdl_syswm.odin
  58. 6 0
      vendor/sdl2/sdl_thread.odin
  59. 6 0
      vendor/sdl2/sdl_timer.odin
  60. 6 0
      vendor/sdl2/sdl_touch.odin
  61. 6 0
      vendor/sdl2/sdl_video.odin
  62. 6 0
      vendor/sdl2/sdl_vulkan.odin

+ 2 - 7
.github/workflows/ci.yml

@@ -56,9 +56,9 @@ jobs:
     runs-on: macos-latest
     steps:
       - uses: actions/checkout@v1
-      - name: Download LLVM, botan and setup PATH
+      - name: Download LLVM and setup PATH
         run: |
-          brew install llvm@11 botan
+          brew install llvm@11
           echo "/usr/local/opt/llvm@11/bin" >> $GITHUB_PATH
           TMP_PATH=$(xcrun --show-sdk-path)/user/include
           echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
@@ -87,11 +87,6 @@ jobs:
           cd tests/core
           make
         timeout-minutes: 10
-      - name: Vendor library tests
-        run: |
-          cd tests/vendor
-          make
-        timeout-minutes: 10
       - name: Odin internals tests
         run: |
           cd tests/internal

+ 1 - 1
README.md

@@ -11,7 +11,7 @@
         <img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
     </a>
     <br>
-    <a href="https://discord.gg/odinlang">
+    <a href="https://discord.com/invite/sVBPHEv">
         <img src="https://img.shields.io/discord/568138951836172421?logo=discord">
     </a>
     <a href="https://github.com/odin-lang/odin/actions">

+ 1 - 1
build_odin.sh

@@ -157,7 +157,7 @@ run_demo() {
 }
 
 have_which() {
-	if ! [ -x "$(command -v which)" ]; then
+	if ! command -v which > /dev/null 2>&1 ; then
 		panic "Could not find \`which\`"
 	fi
 }

+ 9 - 9
core/bufio/lookahead_reader.odin

@@ -2,25 +2,25 @@ package bufio
 
 import "core:io"
 
-// Loadahead_Reader provides io lookahead.
+// Lookahead_Reader provides io lookahead.
 // This is useful for tokenizers/parsers.
-// Loadahead_Reader is similar to bufio.Reader, but unlike bufio.Reader, Loadahead_Reader's buffer size
+// Lookahead_Reader is similar to bufio.Reader, but unlike bufio.Reader, Lookahead_Reader's buffer size
 // will EXACTLY match the specified size, whereas bufio.Reader's buffer size may differ from the specified size.
 // This makes sure that the buffer will not be accidentally read beyond the expected size.
-Loadahead_Reader :: struct {
+Lookahead_Reader :: struct {
 	r:   io.Reader,
 	buf: []byte,
 	n:   int,
 }
 
-lookahead_reader_init :: proc(lr: ^Loadahead_Reader, r: io.Reader, buf: []byte) -> ^Loadahead_Reader {
+lookahead_reader_init :: proc(lr: ^Lookahead_Reader, r: io.Reader, buf: []byte) -> ^Lookahead_Reader {
 	lr.r = r
 	lr.buf = buf
 	lr.n = 0
 	return lr
 }
 
-lookahead_reader_buffer :: proc(lr: ^Loadahead_Reader) -> []byte {
+lookahead_reader_buffer :: proc(lr: ^Lookahead_Reader) -> []byte {
 	return lr.buf[:lr.n]
 }
 
@@ -28,7 +28,7 @@ lookahead_reader_buffer :: proc(lr: ^Loadahead_Reader) -> []byte {
 // lookahead_reader_peek returns a slice of the Lookahead_Reader which holds n bytes
 // If the Lookahead_Reader cannot hold enough bytes, it will read from the underlying reader to populate the rest.
 // NOTE: The returned buffer is not a copy of the underlying buffer
-lookahead_reader_peek :: proc(lr: ^Loadahead_Reader, n: int) -> ([]byte, io.Error) {
+lookahead_reader_peek :: proc(lr: ^Lookahead_Reader, n: int) -> ([]byte, io.Error) {
 	switch {
 	case n < 0:
 		return nil, .Negative_Read
@@ -58,13 +58,13 @@ lookahead_reader_peek :: proc(lr: ^Loadahead_Reader, n: int) -> ([]byte, io.Erro
 // lookahead_reader_peek_all returns a slice of the Lookahead_Reader populating the full buffer
 // If the Lookahead_Reader cannot hold enough bytes, it will read from the underlying reader to populate the rest.
 // NOTE: The returned buffer is not a copy of the underlying buffer
-lookahead_reader_peek_all :: proc(lr: ^Loadahead_Reader) -> ([]byte, io.Error) {
+lookahead_reader_peek_all :: proc(lr: ^Lookahead_Reader) -> ([]byte, io.Error) {
 	return lookahead_reader_peek(lr, len(lr.buf))
 }
 
 
 // lookahead_reader_consume drops the first n populated bytes from the Lookahead_Reader.
-lookahead_reader_consume :: proc(lr: ^Loadahead_Reader, n: int) -> io.Error {
+lookahead_reader_consume :: proc(lr: ^Lookahead_Reader, n: int) -> io.Error {
 	switch {
 	case n == 0:
 		return nil
@@ -78,6 +78,6 @@ lookahead_reader_consume :: proc(lr: ^Loadahead_Reader, n: int) -> io.Error {
 	return nil
 }
 
-lookahead_reader_consume_all :: proc(lr: ^Loadahead_Reader) -> io.Error {
+lookahead_reader_consume_all :: proc(lr: ^Lookahead_Reader) -> io.Error {
 	return lookahead_reader_consume(lr, lr.n)
 }

+ 8 - 0
core/bufio/writer.odin

@@ -227,6 +227,14 @@ writer_to_stream :: proc(b: ^Writer) -> (s: io.Stream) {
 	return
 }
 
+// writer_to_stream converts a Writer into an io.Stream
+writer_to_writer :: proc(b: ^Writer) -> (s: io.Writer) {
+	s.stream_data = b
+	s.stream_vtable = &_writer_vtable
+	return
+}
+
+
 
 
 @(private)

+ 137 - 78
core/container/bit_array/bit_array.odin

@@ -27,27 +27,28 @@ Bit_Array_Iterator :: struct {
 	word_idx: int,
 	bit_idx:  uint,
 }
-
 /*
-	In:
-		- ba:   ^Bit_Array - the array to iterate over
+Wraps a `Bit_Array` into an Iterator
+
+Inputs:
+- ba: Pointer to the Bit_Array
 
-	Out:
-		- it:   ^Bit_Array_Iterator - the iterator that holds iteration state
+Returns:
+- it: Iterator struct
 */
 make_iterator :: proc (ba: ^Bit_Array) -> (it: Bit_Array_Iterator) {
 	return Bit_Array_Iterator { array = ba }
 }
-
 /*
-	In:
-		- it:    ^Bit_Array_Iterator - the iterator struct that holds the state.
-
-	Out:
-		- set:    bool - the state of the bit at `index`
-		- index:  int - the next bit of the Bit_Array referenced by `it`.
-		- ok:	  bool - `true` if the iterator returned a valid index,
-			  `false` if there were no more bits
+Returns the next bit, including its set-state. ok=false once exhausted
+
+Inputs:
+- it: The iterator that holds the state.
+
+Returns:
+- set: `true` if the bit at `index` is set.
+- index: The next bit of the Bit_Array referenced by `it`.
+- ok: `true` if the iterator can continue, `false` if the iterator is done
 */
 iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) {
 	index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
@@ -64,39 +65,51 @@ iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok:
 
 	return set, index, true
 }
-
 /*
-	In:
-		- it:     ^Bit_Array_Iterator - the iterator struct that holds the state.
+Returns the next Set Bit, for example if `0b1010`, then the iterator will return index={1, 3} over two calls.
+
+Inputs:
+- it: The iterator that holds the state.
 
-	Out:
-		- index:  int - the next set bit of the Bit_Array referenced by `it`.
-		- ok:	  bool - `true` if the iterator returned a valid index,
-			  `false` if there were no more bits set
+Returns:
+- index: The next *set* bit of the Bit_Array referenced by `it`.
+- ok: `true` if the iterator can continue, `false` if the iterator is done
 */
 iterate_by_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
 	return iterate_internal_(it, true)
 }
-
 /*
-	In:
-		- it:	  ^Bit_Array_Iterator - the iterator struct that holds the state.
+Returns the next Unset Bit, for example if `0b1010`, then the iterator will return index={0, 2} over two calls.
+
+Inputs:
+- it: The iterator that holds the state.
 
-	Out:
-		- index:  int - the next unset bit of the Bit_Array referenced by `it`.
-		- ok:	  bool - `true` if the iterator returned a valid index,
-			  `false` if there were no more unset bits
+Returns:
+- index: The next *unset* bit of the Bit_Array referenced by `it`.
+- ok: `true` if the iterator can continue, `false` if the iterator is done
 */
 iterate_by_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
 	return iterate_internal_(it, false)
 }
+/*
+Iterates through set/unset bits
 
+*Private*
+
+Inputs:
+- it: The iterator that holds the state.
+- ITERATE_SET_BITS: `true` for returning only set bits, false for returning only unset bits
+
+Returns:
+- index: The next *unset* bit of the Bit_Array referenced by `it`.
+- ok: `true` if the iterator can continue, `false` if the iterator is done
+*/
 @(private="file")
 iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) -> (index: int, ok: bool) {
 	word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
 	when ! ITERATE_SET_BITS { word = ~word }
 
-	// if the word is empty or we have already gone over all the bits in it,
+	// If the word is empty or we have already gone over all the bits in it,
 	// b.bit_idx is greater than the index of any set bit in the word,
 	// meaning that word >> b.bit_idx == 0.
 	for it.word_idx < len(it.array.bits) && word >> it.bit_idx == 0 {
@@ -106,14 +119,14 @@ iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) ->
 		when ! ITERATE_SET_BITS { word = ~word }
 	}
 
-	// if we are iterating the set bits, reaching the end of the array means we have no more bits to check
+	// If we are iterating the set bits, reaching the end of the array means we have no more bits to check
 	when ITERATE_SET_BITS {
 		if it.word_idx >= len(it.array.bits) {
 			return 0, false
 		}
 	}
 
-	// reaching here means that the word has some set bits
+	// Reaching here means that the word has some set bits
 	it.bit_idx += uint(intrinsics.count_trailing_zeros(word >> it.bit_idx))
 	index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
 
@@ -124,24 +137,21 @@ iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) ->
 	}
 	return index, index <= it.array.max_index
 }
-
-
 /*
-	In:
-		- ba:    ^Bit_Array - a pointer to the Bit Array
-		- index: The bit index. Can be an enum member.
+Gets the state of a bit in the bit-array
 
-	Out:
-		- res:   The bit you're interested in.
-		- ok:    Whether the index was valid. Returns `false` if the index is smaller than the bias.
+Inputs:
+- ba: Pointer to the Bit_Array
+- index: Which bit in the array
 
-	The `ok` return value may be ignored.
+Returns:
+- res: `true` if the bit at `index` is set.
+- ok: Whether the index was valid. Returns `false` if the index is smaller than the bias.
 */
-get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (res: bool, ok: bool) {
+get :: proc(ba: ^Bit_Array, #any_int index: uint) -> (res: bool, ok: bool) #optional_ok {
 	idx := int(index) - ba.bias
 
 	if ba == nil || int(index) < ba.bias { return false, false }
-	context.allocator = allocator
 
 	leg_index := idx >> INDEX_SHIFT
 	bit_index := idx &  INDEX_MASK
@@ -157,18 +167,36 @@ get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
 
 	return res, true
 }
+/*
+Gets the state of a bit in the bit-array
+
+*Bypasses all Checks*
+
+Inputs:
+- ba: Pointer to the Bit_Array
+- index: Which bit in the array
 
+Returns:
+- `true` if bit is set
+*/
+unsafe_get :: #force_inline proc(ba: ^Bit_Array, #any_int index: uint) -> bool #no_bounds_check {
+	return bool((ba.bits[index >> INDEX_SHIFT] >> uint(index & INDEX_MASK)) & 1)
+}
 /*
-	In:
-		- ba:    ^Bit_Array - a pointer to the Bit Array
-		- index: The bit index. Can be an enum member.
+Sets the state of a bit in the bit-array
+
+*Conditionally Allocates (Resizes backing data when `index > len(ba.bits)`)*
 
-	Out:
-		- ok:    Whether or not we managed to set requested bit.
+Inputs:
+- ba: Pointer to the Bit_Array
+- index: Which bit in the array
+- set_to: `true` sets the bit on, `false` to turn it off
+- allocator: (default is context.allocator)
 
-	`set` automatically resizes the Bit Array to accommodate the requested index if needed.
+Returns:
+- ok: Whether the set was successful, `false` on allocation failure or bad index
 */
-set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
+set :: proc(ba: ^Bit_Array, #any_int index: uint, set_to: bool = true, allocator := context.allocator) -> (ok: bool) {
 
 	idx := int(index) - ba.bias
 
@@ -181,65 +209,97 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
 	resize_if_needed(ba, leg_index) or_return
 
 	ba.max_index = max(idx, ba.max_index)
-	ba.bits[leg_index] |= 1 << uint(bit_index)
+
+	if set_to{ ba.bits[leg_index] |= 1 << uint(bit_index) }
+	else { ba.bits[leg_index] &= ~(1 << uint(bit_index)) }
+
 	return true
 }
-
 /*
-	In:
-		- ba:    ^Bit_Array - a pointer to the Bit Array
-		- index: The bit index. Can be an enum member.
+Sets the state of a bit in the bit-array
 
-	Out:
-		- ok:    Whether or not we managed to unset requested bit.
+*Bypasses all checks*
 
-	`unset` automatically resizes the Bit Array to accommodate the requested index if needed.
+Inputs:
+- ba: Pointer to the Bit_Array
+- index: Which bit in the array
 */
-unset :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
+unsafe_set :: proc(ba: ^Bit_Array, bit: int) #no_bounds_check {
+	ba.bits[bit >> INDEX_SHIFT] |= 1 << uint(bit & INDEX_MASK)
+}
+/*
+Unsets the state of a bit in the bit-array. (Convienence wrapper for `set`)
 
-	idx := int(index) - ba.bias
+*Conditionally Allocates (Resizes backing data when `index > len(ba.bits)`)*
 
-	if ba == nil || int(index) < ba.bias { return false }
-	context.allocator = allocator
+Inputs:
+- ba: Pointer to the Bit_Array
+- index: Which bit in the array
+- allocator: (default is context.allocator)
 
-	leg_index := idx >> INDEX_SHIFT
-	bit_index := idx &  INDEX_MASK
+Returns:
+- ok: Whether the unset was successful, `false` on allocation failure or bad index
+*/
+unset :: #force_inline proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) {
+	return set(ba, index, false, allocator)
+}
+/*
+Unsets the state of a bit in the bit-array
 
-	resize_if_needed(ba, leg_index) or_return
+*Bypasses all Checks*
 
-	ba.max_index = max(idx, ba.max_index)
-	ba.bits[leg_index] &= ~(1 << uint(bit_index))
-	return true
+Inputs:
+- ba: Pointer to the Bit_Array
+- index: Which bit in the array
+*/
+unsafe_unset :: proc(b: ^Bit_Array, bit: int) #no_bounds_check {
+	b.bits[bit >> INDEX_SHIFT] &= ~(1 << uint(bit & INDEX_MASK))
 }
-
 /*
-	A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
+A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
+
+*Allocates (`new(Bit_Array) & make(ba.bits)`)*
+
+Inputs:
+- max_index: maximum starting index
+- min_index: minimum starting index (used as a bias)
+- allocator: (default is context.allocator)
+
+Returns:
+- ba: Allocates a bit_Array, backing data is set to `max-min / 64` indices, rounded up (eg 65 - 0 allocates for [2]u64).
 */
-create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
+create :: proc(max_index: int, min_index: int = 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
 	context.allocator = allocator
 	size_in_bits := max_index - min_index
 
 	if size_in_bits < 1 { return {}, false }
 
 	legs := size_in_bits >> INDEX_SHIFT
-
+	if size_in_bits & INDEX_MASK > 0 {legs+=1}
+	bits, err := make([dynamic]u64, legs)
+	ok = err == mem.Allocator_Error.None
 	res = new(Bit_Array)
+	res.bits         = bits
 	res.bias         = min_index
 	res.max_index    = max_index
 	res.free_pointer = true
-	return res, resize_if_needed(res, legs)
+	return
 }
-
 /*
-	Sets all bits to `false`.
+Sets all values in the Bit_Array to zero.
+
+Inputs:
+- ba: The target Bit_Array
 */
 clear :: proc(ba: ^Bit_Array) {
 	if ba == nil { return }
 	mem.zero_slice(ba.bits[:])
 }
-
 /*
-	Releases the memory used by the Bit Array.
+Deallocates the Bit_Array and its backing storage
+
+Inputs:
+- ba: The target Bit_Array
 */
 destroy :: proc(ba: ^Bit_Array) {
 	if ba == nil { return }
@@ -248,9 +308,8 @@ destroy :: proc(ba: ^Bit_Array) {
 		free(ba)
 	}
 }
-
 /*
-	Resizes the Bit Array. For internal use.
+	Resizes the Bit Array. For internal use. Provisions needed capacity+1
 	If you want to reserve the memory for a given-sized Bit Array up front, you can use `create`.
 */
 @(private="file")

+ 2 - 2
core/encoding/json/marshal.odin

@@ -441,7 +441,7 @@ opt_write_start :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: i
 	return
 }
 
-// insert comma seperation and write indentations
+// insert comma separation and write indentations
 opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int) -> (err: io.Error) {
 	switch opt.spec {
 	case .JSON, .JSON5: 
@@ -461,7 +461,7 @@ opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int)
 			if opt.pretty {
 				io.write_byte(w, '\n') or_return
 			} else {
-				// comma seperation necessary for non pretty output!
+				// comma separation necessary for non pretty output!
 				io.write_string(w, ", ") or_return
 			}
 		}

+ 35 - 5
core/fmt/fmt_os.odin

@@ -4,29 +4,59 @@ package fmt
 import "core:runtime"
 import "core:os"
 import "core:io"
+import "core:bufio"
 
 // fprint formats using the default print settings and writes to fd
 fprint :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
-	w := io.to_writer(os.stream_from_handle(fd))
+	buf: [1024]byte
+	b: bufio.Writer
+	defer bufio.writer_flush(&b)
+
+	bufio.writer_init_with_buf(&b, {os.stream_from_handle(fd)}, buf[:])
+	w := bufio.writer_to_writer(&b)
 	return wprint(w=w, args=args, sep=sep)
 }
 
 // fprintln formats using the default print settings and writes to fd
 fprintln :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
-	w := io.to_writer(os.stream_from_handle(fd))
+	buf: [1024]byte
+	b: bufio.Writer
+	defer bufio.writer_flush(&b)
+
+	bufio.writer_init_with_buf(&b, {os.stream_from_handle(fd)}, buf[:])
+
+	w := bufio.writer_to_writer(&b)
 	return wprintln(w=w, args=args, sep=sep)
 }
 // fprintf formats according to the specified format string and writes to fd
 fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
-	w := io.to_writer(os.stream_from_handle(fd))
+	buf: [1024]byte
+	b: bufio.Writer
+	defer bufio.writer_flush(&b)
+
+	bufio.writer_init_with_buf(&b, {os.stream_from_handle(fd)}, buf[:])
+
+	w := bufio.writer_to_writer(&b)
 	return wprintf(w, fmt, ..args)
 }
 fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) -> (n: int, err: io.Error) {
-	w := io.to_writer(os.stream_from_handle(fd))
+	buf: [1024]byte
+	b: bufio.Writer
+	defer bufio.writer_flush(&b)
+
+	bufio.writer_init_with_buf(&b, {os.stream_from_handle(fd)}, buf[:])
+
+	w := bufio.writer_to_writer(&b)
 	return wprint_type(w, info)
 }
 fprint_typeid :: proc(fd: os.Handle, id: typeid) -> (n: int, err: io.Error) {
-	w := io.to_writer(os.stream_from_handle(fd))
+	buf: [1024]byte
+	b: bufio.Writer
+	defer bufio.writer_flush(&b)
+
+	bufio.writer_init_with_buf(&b, {os.stream_from_handle(fd)}, buf[:])
+
+	w := bufio.writer_to_writer(&b)
 	return wprint_typeid(w, id)
 }
 

+ 6 - 6
core/math/big/prime.odin

@@ -353,14 +353,14 @@ internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_ra
 
 	// Run the Miller-Rabin test with base 2 for the BPSW test.
 	internal_set(b, 2) or_return
-	if !internal_int_prime_miller_rabin(a, b) or_return { return }
+	if !(internal_int_prime_miller_rabin(a, b) or_return) { return }
 
 	// Rumours have it that Mathematica does a second M-R test with base 3.
 	// Other rumours have it that their strong L-S test is slightly different.
 	// It does not hurt, though, beside a bit of extra runtime.
 
 	b.digit[0] += 1
-	if !internal_int_prime_miller_rabin(a, b) or_return { return }
+	if !(internal_int_prime_miller_rabin(a, b) or_return) { return }
 
 	// Both, the Frobenius-Underwood test and the the Lucas-Selfridge test are quite
 	// slow so if speed is an issue, set `USE_MILLER_RABIN_ONLY` to use M-R tests with
@@ -369,9 +369,9 @@ internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_ra
 	if !miller_rabin_only {
 		if miller_rabin_trials >= 0 {
 			when MATH_BIG_USE_FROBENIUS_TEST {
-				if !internal_int_prime_frobenius_underwood(a) or_return { return }
+				if !(internal_int_prime_frobenius_underwood(a) or_return) { return }
 			} else {
-				if !internal_int_prime_strong_lucas_selfridge(a) or_return { return }
+				if !(internal_int_prime_strong_lucas_selfridge(a) or_return) { return }
 			}
 		}
 	}
@@ -410,7 +410,7 @@ internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_ra
 		// We did bases 2 and 3  already, skip them
 		for ix := 2; ix < p_max; ix += 1 {
 			internal_set(b, _private_prime_table[ix])
-			if !internal_int_prime_miller_rabin(a, b) or_return { return }
+			if !(internal_int_prime_miller_rabin(a, b) or_return) { return }
 		}
 	} else if miller_rabin_trials > 0 {
 		// Perform `miller_rabin_trials` M-R tests with random bases between 3 and "a".
@@ -490,7 +490,7 @@ internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_ra
 				ix -= 1
 				continue
 			}
-			if !internal_int_prime_miller_rabin(a, b) or_return { return }
+			if !(internal_int_prime_miller_rabin(a, b) or_return) { return }
 		}
 	}
 

+ 5 - 4
core/math/linalg/extended.odin

@@ -3,20 +3,21 @@ package linalg
 import "core:builtin"
 import "core:math"
 
-radians :: proc(degrees: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
+to_radians :: proc(degrees: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
-			out[i] = degrees * RAD_PER_DEG
+			out[i] = degrees[i] * RAD_PER_DEG
 		}
 	} else {
 		out = degrees * RAD_PER_DEG
 	}
 	return
 }
-degrees :: proc(radians: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
+
+to_degrees :: proc(radians: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
 	when IS_ARRAY(T) {
 		for i in 0..<len(T) {
-			out[i] = radians * DEG_PER_RAD
+			out[i] = radians[i] * DEG_PER_RAD
 		}
 	} else {
 		out = radians * DEG_PER_RAD

+ 5 - 3
core/net/dns.odin

@@ -373,18 +373,20 @@ load_resolv_conf :: proc(resolv_conf_path: string, allocator := context.allocato
 	defer delete(res)
 	resolv_str := string(res)
 
+	id_str := "nameserver"
+	id_len := len(id_str)
+
 	_name_servers := make([dynamic]Endpoint, 0, allocator)
 	for line in strings.split_lines_iterator(&resolv_str) {
 		if len(line) == 0 || line[0] == '#' {
 			continue
 		}
 
-		id_str := "nameserver"
-		if strings.compare(line[:len(id_str)], id_str) != 0 {
+		if len(line) < id_len || strings.compare(line[:id_len], id_str) != 0 {
 			continue
 		}
 
-		server_ip_str := strings.trim_left_space(line[len(id_str):])
+		server_ip_str := strings.trim_left_space(line[id_len:])
 		if len(server_ip_str) == 0 {
 			continue
 		}

+ 1 - 1
core/reflect/types.odin

@@ -563,7 +563,7 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
 		case .None: // Ignore
 		case .Fixed:
 			io.write_string(w, "#soa[",           &n) or_return
-			io.write_i64(w, i64(info.soa_len), 10 &n) or_return
+			io.write_i64(w, i64(info.soa_len),    10) or_return
 			io.write_byte(w, ']',                 &n) or_return
 			write_type(w, info.soa_base_type,     &n) or_return
 			return

+ 26 - 1
core/strings/builder.odin

@@ -71,7 +71,32 @@ Returns:
 builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
 	return Builder{buf=make([dynamic]byte, len, cap, allocator) or_return }, nil
 }
-// overload simple `builder_make_*` with or without len / cap parameters
+/*
+Produces a String Builder
+
+*Allocates Using Provided Allocator*
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+	builder_make_example :: proc() {
+		sb := strings.builder_make()
+		strings.write_byte(&sb, 'a')
+		strings.write_string(&sb, " slice of ")
+		strings.write_f64(&sb, 3.14,'g',true) // See `fmt.fmt_float` byte codes
+		strings.write_string(&sb, " is ")
+		strings.write_int(&sb, 180)
+		strings.write_rune(&sb,'°')
+		the_string :=strings.to_string(sb)
+		fmt.println(the_string)
+	}
+
+Output:
+
+	a slice of +3.14 is 180°
+
+*/
 builder_make :: proc{
 	builder_make_none,
 	builder_make_len,

+ 4 - 4
core/strings/strings.odin

@@ -41,7 +41,7 @@ Returns:
 */
 @(deprecated="Prefer clone. It now returns an optional allocator error")
 clone_safe :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) {
-    return clone(s, allocator, loc)
+	return clone(s, allocator, loc)
 }
 /*
 Clones a string and appends a null-byte to make it a cstring
@@ -263,7 +263,7 @@ compare :: proc(lhs, rhs: string) -> (result: int) {
 	return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs)
 }
 /*
-Returns the byte offset of the rune `r` in the string `s`, -1 when not found
+Checks if rune `r` in the string `s`
 
 Inputs:
 - s: The input string
@@ -629,7 +629,7 @@ Returns:
 */
 @(deprecated="Prefer join. It now returns an optional allocator error")
 join_safe :: proc(a: []string, sep: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) {
-    return join(a, sep, allocator)
+	return join(a, sep, allocator)
 }
 /*
 Returns a combined string from the slice of strings `a` without a separator
@@ -689,7 +689,7 @@ The concatenated string, and an error if allocation fails
 */
 @(deprecated="Prefer concatenate. It now returns an optional allocator error")
 concatenate_safe :: proc(a: []string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) {
-    return concatenate(a, allocator)
+	return concatenate(a, allocator)
 }
 /*
 Returns a substring of the input string `s` with the specified rune offset and length

+ 1 - 0
core/sys/windows/user32.odin

@@ -38,6 +38,7 @@ foreign user32 {
 	DestroyWindow :: proc(hWnd: HWND) -> BOOL ---
 
 	ShowWindow :: proc(hWnd: HWND, nCmdShow: c_int) -> BOOL ---
+	IsWindow :: proc(hWnd: HWND) -> BOOL ---
 	BringWindowToTop :: proc(hWnd: HWND) -> BOOL ---
 	GetTopWindow :: proc(hWnd: HWND) -> HWND ---
 	SetForegroundWindow :: proc(hWnd: HWND) -> BOOL ---

+ 2 - 2
core/text/edit/text_edit.odin

@@ -219,7 +219,7 @@ selection_delete :: proc(s: ^State) {
 
 translate_position :: proc(s: ^State, pos: int, t: Translation) -> int {
 	is_continuation_byte :: proc(b: byte) -> bool {
-		return b <= 0x80 && b < 0xc0
+		return b >= 0x80 && b < 0xc0
 	}
 	is_space :: proc(b: byte) -> bool {
 		return b == ' ' || b == '\t' || b == '\n'
@@ -410,4 +410,4 @@ perform_command :: proc(s: ^State, cmd: Command) {
 	case .Select_Line_Start: select_to(s, .Soft_Line_Start)
 	case .Select_Line_End:   select_to(s, .Soft_Line_End)
 	}
-}
+}

+ 7 - 3
src/build_settings.cpp

@@ -264,6 +264,7 @@ struct BuildContext {
 	String microarch;
 	BuildModeKind build_mode;
 	bool   generate_docs;
+	bool   custom_optimization_level;
 	i32    optimization_level;
 	bool   show_timings;
 	TimingsExportFormat export_timings_format;
@@ -1309,6 +1310,12 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
 		gb_exit(1);
 	}
 
+	if (bc->ODIN_DEBUG && !bc->custom_optimization_level) {
+		// NOTE(bill): when building with `-debug` but not specifying an optimization level
+		// default to `-o:none` to improve the debug symbol generation by default
+		bc->optimization_level = -1; // -o:none
+	}
+
 	bc->optimization_level = gb_clamp(bc->optimization_level, -1, 2);
 
 	// ENFORCE DYNAMIC MAP CALLS
@@ -1322,9 +1329,6 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
 			break;
 		}
 	}
-
-	#undef LINK_FLAG_X64
-	#undef LINK_FLAG_386
 }
 
 #if defined(GB_SYSTEM_WINDOWS)

+ 2 - 0
src/check_expr.cpp

@@ -1688,6 +1688,8 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) {
 			if (is_type_integer(type)) {
 				error_line("\tSuggestion: Did you mean to use the bitwise not operator '~'?\n");
 			}
+		} else {
+			o->type = t_untyped_bool;
 		}
 		break;
 

+ 15 - 8
src/check_type.cpp

@@ -378,6 +378,17 @@ gb_internal void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, T
 	rw_mutex_unlock(&ctx->info->gen_types_mutex);
 }
 
+
+bool check_constant_parameter_value(Type *type, Ast *expr) {
+	if (!is_type_constant_type(type)) {
+		gbString str = type_to_string(type);
+		defer (gb_string_free(str));
+		error(expr, "A parameter must be a valid constant type, got %s", str);
+		return true;
+	}
+	return false;
+}
+
 gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_params,
                                                   bool *is_polymorphic_,
                                                   Ast *node, Array<Operand> *poly_operands) {
@@ -477,10 +488,8 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly
 				type = t_invalid;
 			}
 
-			if (!is_type_param && !is_type_constant_type(type)) {
-				gbString str = type_to_string(type);
-				error(params[i], "A parameter must be a valid constant type, got %s", str);
-				gb_string_free(str);
+			if (!is_type_param && check_constant_parameter_value(type, params[i])) {
+				// failed
 			}
 
 			Scope *scope = ctx->scope;
@@ -1757,10 +1766,8 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
 						p->flags &= ~FieldFlag_by_ptr;
 					}
 
-					if (!is_type_constant_type(type) && !is_type_polymorphic(type)) {
-						gbString str = type_to_string(type);
-						error(params[i], "A parameter must be a valid constant type, got %s", str);
-						gb_string_free(str);
+					if (!is_type_polymorphic(type) && check_constant_parameter_value(type, params[i])) {
+						// failed
 					}
 
 					param = alloc_entity_const_param(scope, name->Ident.token, type, poly_const, is_type_polymorphic(type));

+ 28 - 11
src/common_memory.cpp

@@ -1,3 +1,6 @@
+#if defined(GB_SYSTEM_LINUX)
+#include <malloc.h>
+#endif
 
 gb_internal gb_inline void zero_size(void *ptr, isize len) {
 	memset(ptr, 0, len);
@@ -121,7 +124,6 @@ struct PlatformMemoryBlock {
 	PlatformMemoryBlock *prev, *next;
 };
 
-
 gb_global std::atomic<isize> global_platform_memory_total_usage;
 gb_global PlatformMemoryBlock global_platform_memory_block_sentinel;
 
@@ -177,12 +179,12 @@ gb_internal void platform_virtual_memory_protect(void *memory, isize size);
 			gb_printf_err("Total Usage: %lld bytes\n", cast(long long)global_platform_memory_total_usage);
 			GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no...");
 		}
-		global_platform_memory_total_usage += total_size;
+		global_platform_memory_total_usage.fetch_add(total_size);
 		return pmblock;
 	}
 	gb_internal void platform_virtual_memory_free(PlatformMemoryBlock *block) {
 		isize size = block->total_size;
-		global_platform_memory_total_usage -= size;
+		global_platform_memory_total_usage.fetch_sub(size);
 		munmap(block, size);
 	}
 	gb_internal void platform_virtual_memory_protect(void *memory, isize size) {
@@ -396,6 +398,8 @@ gb_internal gbAllocator heap_allocator(void) {
 	return a;
 }
 
+gb_internal std::atomic<isize> total_heap_memory_allocated;
+
 
 gb_internal GB_ALLOCATOR_PROC(heap_allocator_proc) {
 	void *ptr = nullptr;
@@ -403,7 +407,6 @@ gb_internal GB_ALLOCATOR_PROC(heap_allocator_proc) {
 	gb_unused(old_size);
 
 
-
 // TODO(bill): Throughly test!
 	switch (type) {
 #if defined(GB_COMPILER_MSVC)
@@ -436,28 +439,34 @@ gb_internal GB_ALLOCATOR_PROC(heap_allocator_proc) {
 #elif defined(GB_SYSTEM_LINUX)
 	// TODO(bill): *nix version that's decent
 	case gbAllocation_Alloc: {
-		ptr = aligned_alloc(alignment, (size + alignment - 1) & ~(alignment - 1));
+		isize total_size = (size + alignment - 1) & ~(alignment - 1);
+		total_heap_memory_allocated.fetch_add(total_size);
+		ptr = aligned_alloc(alignment, total_size);
 		gb_zero_size(ptr, size);
 	} break;
 
 	case gbAllocation_Free:
 		if (old_memory != nullptr) {
+			total_heap_memory_allocated.fetch_sub(malloc_usable_size(old_memory));
 			free(old_memory);
 		}
 		break;
 
-	case gbAllocation_Resize:
+	case gbAllocation_Resize: {
 		if (size == 0) {
 			if (old_memory != nullptr) {
+				total_heap_memory_allocated.fetch_sub(malloc_usable_size(old_memory));
 				free(old_memory);
 			}
 			break;
 		}
-		
+
 		alignment = gb_max(alignment, gb_align_of(max_align_t));
-		
+
 		if (old_memory == nullptr) {
-			ptr = aligned_alloc(alignment, (size + alignment - 1) & ~(alignment - 1));
+			isize total_size = (size + alignment - 1) & ~(alignment - 1);
+			total_heap_memory_allocated.fetch_add(total_size);
+			ptr = aligned_alloc(alignment, total_size);
 			gb_zero_size(ptr, size);
 			break;
 		}
@@ -466,11 +475,19 @@ gb_internal GB_ALLOCATOR_PROC(heap_allocator_proc) {
 			break;
 		}
 
-		ptr = aligned_alloc(alignment, (size + alignment - 1) & ~(alignment - 1));
+		size_t actual_old_size = malloc_usable_size(old_memory);
+		if (size <= actual_old_size) {
+			ptr = old_memory;
+			break;
+		}
+
+		isize total_size = (size + alignment - 1) & ~(alignment - 1);
+		total_heap_memory_allocated.fetch_add(total_size);
+		ptr = aligned_alloc(alignment, total_size);
 		gb_memmove(ptr, old_memory, old_size);
 		free(old_memory);
 		gb_zero_size(cast(u8 *)ptr + old_size, gb_max(size-old_size, 0));
-		break;
+	} break;
 #else
 	// TODO(bill): *nix version that's decent
 	case gbAllocation_Alloc: {

+ 34 - 0
src/error.cpp

@@ -436,6 +436,32 @@ gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const *
 	}
 }
 
+gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
+	global_error_collector.count.fetch_add(1);
+
+	mutex_lock(&global_error_collector.mutex);
+	// NOTE(bill): Duplicate error, skip it
+	if (pos.line == 0) {
+		error_out_coloured("Syntax_Error: ", TerminalStyle_Normal, TerminalColour_Red);
+		error_out_va(fmt, va);
+		error_out("\n");
+	} else if (global_error_collector.prev != pos) {
+		global_error_collector.prev = pos;
+		error_out_pos(pos);
+		if (has_ansi_terminal_colours()) {
+			error_out_coloured("Syntax_Error: ", TerminalStyle_Normal, TerminalColour_Red);
+		}
+		error_out_va(fmt, va);
+		error_out("\n");
+		show_error_on_line(pos, end);
+	}
+	mutex_unlock(&global_error_collector.mutex);
+	if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
+		gb_exit(1);
+	}
+}
+
+
 gb_internal void syntax_warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
 	if (global_warnings_as_errors()) {
 		syntax_error_va(pos, end, fmt, va);
@@ -515,6 +541,14 @@ gb_internal void syntax_warning(Token const &token, char const *fmt, ...) {
 	va_end(va);
 }
 
+gb_internal void syntax_error_with_verbose(TokenPos pos, TokenPos end, char const *fmt, ...) {
+	va_list va;
+	va_start(va, fmt);
+	syntax_error_with_verbose_va(pos, end, fmt, va);
+	va_end(va);
+}
+
+
 
 gb_internal void compiler_error(char const *fmt, ...) {
 	va_list va;

+ 4 - 1
src/llvm_backend_expr.cpp

@@ -514,6 +514,9 @@ gb_internal bool lb_is_matrix_simdable(Type *t) {
 		// it's not aligned well enough to use the vector instructions
 		return false;
 	}
+	if ((mt->Matrix.row_count & 1) ^ (mt->Matrix.column_count & 1)) {
+		return false;
+	}
 	
 	if (elem->kind == Type_Basic) {
 		switch (elem->Basic.kind) {
@@ -2833,7 +2836,7 @@ gb_internal lbValue lb_make_soa_pointer(lbProcedure *p, Type *type, lbValue cons
 	lbValue ptr = lb_emit_struct_ep(p, v.addr, 0);
 	lbValue idx = lb_emit_struct_ep(p, v.addr, 1);
 	lb_emit_store(p, ptr, addr);
-	lb_emit_store(p, idx, index);
+	lb_emit_store(p, idx, lb_emit_conv(p, index, t_int));
 
 	return lb_addr_load(p, v);
 }

+ 4 - 0
src/main.cpp

@@ -1035,12 +1035,16 @@ gb_internal bool parse_build_flags(Array<String> args) {
 						case BuildFlag_OptimizationMode: {
 							GB_ASSERT(value.kind == ExactValue_String);
 							if (value.value_string == "none") {
+								build_context.custom_optimization_level = true;
 								build_context.optimization_level = -1;
 							} else if (value.value_string == "minimal") {
+								build_context.custom_optimization_level = true;
 								build_context.optimization_level = 0;
 							} else if (value.value_string == "size") {
+								build_context.custom_optimization_level = true;
 								build_context.optimization_level = 1;
 							} else if (value.value_string == "speed") {
+								build_context.custom_optimization_level = true;
 								build_context.optimization_level = 2;
 							} else {
 								gb_printf_err("Invalid optimization mode for -o:<string>, got %.*s\n", LIT(value.value_string));

+ 47 - 3
src/parser.cpp

@@ -418,6 +418,25 @@ gb_internal void error(Ast *node, char const *fmt, ...) {
 	}
 }
 
+gb_internal void syntax_error_with_verbose(Ast *node, char const *fmt, ...) {
+	Token token = {};
+	TokenPos end_pos = {};
+	if (node != nullptr) {
+		token = ast_token(node);
+		end_pos = ast_end_pos(node);
+	}
+
+	va_list va;
+	va_start(va, fmt);
+	syntax_error_with_verbose_va(token.pos, end_pos, fmt, va);
+	va_end(va);
+	if (node != nullptr && node->file_id != 0) {
+		AstFile *f = node->thread_safe_file();
+		f->error_count += 1;
+	}
+}
+
+
 gb_internal void error_no_newline(Ast *node, char const *fmt, ...) {
 	Token token = {};
 	if (node != nullptr) {
@@ -496,11 +515,17 @@ gb_internal Ast *ast_tag_expr(AstFile *f, Token token, Token name, Ast *expr) {
 
 gb_internal Ast *ast_unary_expr(AstFile *f, Token op, Ast *expr) {
 	Ast *result = alloc_ast_node(f, Ast_UnaryExpr);
+
+	if (expr && expr->kind == Ast_OrReturnExpr) {
+		syntax_error_with_verbose(expr, "'or_return' within an unary expression not wrapped in parentheses (...)");
+	}
+
 	result->UnaryExpr.op = op;
 	result->UnaryExpr.expr = expr;
 	return result;
 }
 
+
 gb_internal Ast *ast_binary_expr(AstFile *f, Token op, Ast *left, Ast *right) {
 	Ast *result = alloc_ast_node(f, Ast_BinaryExpr);
 
@@ -513,6 +538,13 @@ gb_internal Ast *ast_binary_expr(AstFile *f, Token op, Ast *left, Ast *right) {
 		right = ast_bad_expr(f, op, op);
 	}
 
+	if (left->kind == Ast_OrReturnExpr) {
+		syntax_error_with_verbose(left, "'or_return' within a binary expression not wrapped in parentheses (...)");
+	}
+	if (right->kind == Ast_OrReturnExpr) {
+		syntax_error_with_verbose(right, "'or_return' within a binary expression not wrapped in parentheses (...)");
+	}
+
 	result->BinaryExpr.op = op;
 	result->BinaryExpr.left = left;
 	result->BinaryExpr.right = right;
@@ -2765,6 +2797,12 @@ gb_internal Ast *parse_call_expr(AstFile *f, Ast *operand) {
 	return call;
 }
 
+gb_internal void parse_check_or_return(Ast *operand, char const *msg) {
+	if (operand && operand->kind == Ast_OrReturnExpr) {
+		syntax_error_with_verbose(operand, "'or_return' use within %s is not wrapped in parentheses (...)", msg);
+	}
+}
+
 gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
 	if (operand == nullptr) {
 		if (f->allow_type) return nullptr;
@@ -2778,6 +2816,7 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
 	while (loop) {
 		switch (f->curr_token.kind) {
 		case Token_OpenParen:
+			parse_check_or_return(operand, "call expression");
 			operand = parse_call_expr(f, operand);
 			break;
 
@@ -2785,12 +2824,11 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
 			Token token = advance_token(f);
 			switch (f->curr_token.kind) {
 			case Token_Ident:
+				parse_check_or_return(operand, "selector expression");
 				operand = ast_selector_expr(f, token, operand, parse_ident(f));
 				break;
-			// case Token_Integer:
-				// operand = ast_selector_expr(f, token, operand, parse_expr(f, lhs));
-				// break;
 			case Token_OpenParen: {
+				parse_check_or_return(operand, "type assertion");
 				Token open = expect_token(f, Token_OpenParen);
 				Ast *type = parse_type(f);
 				Token close = expect_token(f, Token_CloseParen);
@@ -2798,6 +2836,7 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
 			} break;
 
 			case Token_Question: {
+				parse_check_or_return(operand, ".? based type assertion");
 				Token question = expect_token(f, Token_Question);
 				Ast *type = ast_unary_expr(f, question, nullptr);
 				operand = ast_type_assertion(f, operand, token, type);
@@ -2813,6 +2852,7 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
 		} break;
 
 		case Token_ArrowRight: {
+			parse_check_or_return(operand, "-> based call expression");
 			Token token = advance_token(f);
 
 			operand = ast_selector_expr(f, token, operand, parse_ident(f));
@@ -2870,11 +2910,14 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
 					if (indices[0] == nullptr || indices[1] == nullptr) {
 						syntax_error(open, "Matrix index expressions require both row and column indices");
 					}
+					parse_check_or_return(operand, "matrix index expression");
 					operand = ast_matrix_index_expr(f, operand, open, close, interval, indices[0], indices[1]);
 				} else {
+					parse_check_or_return(operand, "slice expression");
 					operand = ast_slice_expr(f, operand, open, close, interval, indices[0], indices[1]);
 				}
 			} else {
+				parse_check_or_return(operand, "index expression");
 				operand = ast_index_expr(f, operand, indices[0], open, close);
 			}
 
@@ -2882,6 +2925,7 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
 		} break;
 
 		case Token_Pointer: // Deference
+			parse_check_or_return(operand, "dereference");
 			operand = ast_deref_expr(f, operand, expect_token(f, Token_Pointer));
 			break;
 

+ 3 - 1
src/ptr_map.cpp

@@ -114,7 +114,9 @@ gb_internal MapIndex map__add_entry(PtrMap<K, V> *h, K key) {
 	PtrMapEntry<K, V> e = {};
 	e.key = key;
 	e.next = MAP_SENTINEL;
-	map__reserve_entries(h, h->count+1);
+	if (h->count+1 >= h->entries_capacity) {
+		map__reserve_entries(h, gb_max(h->entries_capacity*2, 4));
+	}
 	h->entries[h->count++] = e;
 	return cast(MapIndex)(h->count-1);
 }

+ 3 - 1
src/string_map.cpp

@@ -96,7 +96,9 @@ gb_internal MapIndex string_map__add_entry(StringMap<T> *h, u32 hash, String con
 	e.key = key;
 	e.hash = hash;
 	e.next = MAP_SENTINEL;
-	string_map__reserve_entries(h, h->count+1);
+	if (h->count+1 >= h->entries_capacity) {
+		string_map__reserve_entries(h, gb_max(h->entries_capacity*2, 4));
+	}
 	h->entries[h->count++] = e;
 	return cast(MapIndex)(h->count-1);
 }

+ 30 - 0
vendor/darwin/Foundation/NSNotification.odin

@@ -27,4 +27,34 @@ Notification_object :: proc(self: ^Notification) -> ^Object {
 @(objc_type=Notification, objc_name="userInfo")
 Notification_userInfo :: proc(self: ^Notification) -> ^Dictionary {
 	return msgSend(^Dictionary, self, "userInfo")
+}
+
+NotificationName :: ^String
+
+@(objc_class="NSNotificationCenter")
+NotificationCenter :: struct{using _: Object}
+
+
+@(objc_type=NotificationCenter, objc_name="alloc", objc_is_class_method=true)
+NotificationCenter_alloc :: proc() -> ^NotificationCenter {
+	return msgSend(^NotificationCenter, NotificationCenter, "alloc")
+}
+
+@(objc_type=NotificationCenter, objc_name="init")
+NotificationCenter_init :: proc(self: ^NotificationCenter) -> ^NotificationCenter {
+	return msgSend(^NotificationCenter, self, "init")
+}
+
+@(objc_type=NotificationCenter, objc_name="defaultCenter", objc_is_class_method=true)
+NotificationCenter_defaultCenter :: proc() -> ^NotificationCenter {
+	return msgSend(^NotificationCenter, NotificationCenter, "defaultCenter")
+}
+
+@(objc_type=NotificationCenter, objc_name="addObserver")
+NotificationCenter_addObserverName :: proc(self: ^NotificationCenter, name: NotificationName, pObj: ^Object, pQueue: rawptr, block: ^Block) -> ^Object {
+	return msgSend(^Object, self, "addObserverName:object:queue:block:", name, pObj, pQueue, block)
+}
+@(objc_type=NotificationCenter, objc_name="removeObserver")
+NotificationCenter_removeObserver :: proc(self: ^NotificationCenter, pObserver: ^Object) {
+	msgSend(nil, self, "removeObserver:", pObserver)
 }

File diff suppressed because it is too large
+ 845 - 0
vendor/darwin/Metal/MetalClasses.odin


+ 86 - 6
vendor/darwin/Metal/MetalEnums.odin

@@ -17,6 +17,14 @@ AccelerationStructureInstanceOption :: enum u32 {
 	NonOpaque                                  = 3,
 }
 
+
+AccelerationStructureRefitOptions :: distinct bit_set[AccelerationStructureRefitOption; NS.UInteger]
+AccelerationStructureRefitOption :: enum NS.UInteger {
+	VertexData       = 0,
+	PerPrimitiveData = 1,
+}
+
+
 MotionBorderMode :: enum u32 {
 	Clamp  = 0,
 	Vanish = 1,
@@ -148,6 +156,21 @@ BinaryArchiveError :: enum NS.UInteger {
 	InvalidFile        = 1,
 	UnexpectedElement  = 2,
 	CompilationFailure = 3,
+	InternalError      = 4,
+}
+
+BindingType :: enum NS.Integer {
+	Buffer                         = 0,
+	ThreadgroupMemory              = 1,
+	Texture                        = 2,
+	Sampler                        = 3,
+	ImageblockData                 = 16,
+	Imageblock                     = 17,
+	VisibleFunctionTable           = 24,
+	PrimitiveAccelerationStructure = 25,
+	InstanceAccelerationStructure  = 26,
+	IntersectionFunctionTable      = 27,
+	ObjectPayload                  = 34,
 }
 
 BlitOptionFlag :: enum NS.UInteger {
@@ -171,15 +194,16 @@ CaptureDestination :: enum NS.Integer {
 
 CommandBufferStatus :: enum NS.UInteger {
 	NotEnqueued = 0,
-	Enqueued = 1,
-	Committed = 2,
-	Scheduled = 3,
-	Completed = 4,
-	Error = 5,
+	Enqueued    = 1,
+	Committed   = 2,
+	Scheduled   = 3,
+	Completed   = 4,
+	Error       = 5,
 }
 
 CommandBufferError :: enum NS.UInteger {
 	None            = 0,
+	Internal        = 1,
 	Timeout         = 2,
 	PageFault       = 3,
 	AccessRevoked   = 4,
@@ -232,6 +256,7 @@ BarrierScope :: distinct bit_set[BarrierScopeFlag; NS.UInteger]
 CounterSampleBufferError :: enum NS.Integer {
 	OutOfMemory = 0,
 	Invalid     = 1,
+	Internal    = 2,
 }
 
 CompareFunction :: enum NS.UInteger {
@@ -312,6 +337,13 @@ GPUFamily :: enum NS.Integer {
 	Common3      = 3003,
 	MacCatalyst1 = 4001,
 	MacCatalyst2 = 4002,
+	Metal3       = 5001,
+}
+
+SparsePageSize :: enum NS.Integer {
+	Size16  = 101,
+	Size64  = 102,
+	Size256 = 103,
 }
 
 DeviceLocation :: enum NS.UInteger {
@@ -409,6 +441,9 @@ FunctionType :: enum NS.UInteger {
 	Kernel       = 3,
 	Visible      = 5,
 	Intersection = 6,
+	Mesh         = 7,
+	Object       = 8,
+
 }
 
 
@@ -421,15 +456,22 @@ LanguageVersion :: enum NS.UInteger {
 	Version2_2 = 131074,
 	Version2_3 = 131075,
 	Version2_4 = 131076,
+	Version3_0 = 196608,
 }
 
 LibraryType :: enum NS.Integer {
 	Executable = 0,
-	Dynamic = 1,
+	Dynamic    = 1,
+}
+
+LibraryOptimizationLevel :: enum NS.Integer {
+	Default = 0,
+	Size    = 1,
 }
 
 LibraryError :: enum NS.UInteger {
 	Unsupported      = 1,
+	Internal         = 2,
 	CompileFailure   = 3,
 	CompileWarning   = 4,
 	FunctionNotFound = 5,
@@ -624,6 +666,8 @@ RenderStage :: enum NS.UInteger {
 	Vertex   = 0,
 	Fragment = 1,
 	Tile     = 2,
+	Object   = 3,
+	Mesh     = 4,
 }
 RenderStages :: distinct bit_set[RenderStage; NS.UInteger]
 
@@ -861,6 +905,42 @@ IndexType :: enum NS.UInteger {
 	UInt32 = 1,
 }
 
+IOPriority :: enum NS.Integer {
+	High   = 0,
+	Normal = 1,
+	Low    = 2,
+}
+
+IOCommandQueueType :: enum NS.Integer {
+	Concurrent = 0,
+	Serial     = 1,
+}
+
+IOError :: enum NS.Integer {
+	URLInvalid = 1,
+	Internal   = 2,
+}
+
+IOStatus :: enum NS.Integer {
+	Pending   = 0,
+	Cancelled = 1,
+	Error     = 2,
+	Complete  = 3,
+}
+
+IOCompressionMethod :: enum NS.Integer {
+	Zlib     = 0,
+	LZFSE    = 1,
+	LZ4      = 2,
+	LZMA     = 3,
+	LZBitmap = 4,
+}
+
+IOCompressionStatus :: enum NS.Integer {
+	Complete = 0,
+	Error    = 1,
+}
+
 StepFunction :: enum NS.UInteger {
 	Constant                     = 0,
 	PerVertex                    = 1,

+ 12 - 2
vendor/darwin/Metal/MetalErrors.odin

@@ -4,9 +4,11 @@ import NS "vendor:darwin/Foundation"
 
 foreign import "system:Metal.framework"
 
-CommonCounter :: ^NS.String
-CommonCounterSet :: ^NS.String
+CommonCounter          :: ^NS.String
+CommonCounterSet       :: ^NS.String
 DeviceNotificationName :: ^NS.String
+ErrorUserInfoKey       :: ^NS.ErrorUserInfoKey
+ErrorDomain            :: ^NS.ErrorDomain
 
 foreign Metal {
 	@(linkage="weak") CommonCounterTimestamp:                         CommonCounter
@@ -36,4 +38,12 @@ foreign Metal {
 	@(linkage="weak") DeviceWasAddedNotification:         DeviceNotificationName
 	@(linkage="weak") DeviceRemovalRequestedNotification: DeviceNotificationName
 	@(linkage="weak") DeviceWasRemovedNotification:       DeviceNotificationName
+}
+
+foreign Metal {
+	@(linkage="weak") CommandBufferEncoderInfoErrorKey: ErrorUserInfoKey
+}
+
+foreign Metal {
+	@(linkage="weak") IOErrorDomain: ErrorDomain
 }

+ 7 - 0
vendor/darwin/Metal/MetalProcedures.odin

@@ -1,6 +1,7 @@
 package objc_Metal
 
 import NS "vendor:darwin/Foundation"
+import "core:c"
 
 @(require)
 foreign import "system:Metal.framework"
@@ -11,6 +12,12 @@ foreign Metal {
 	CopyAllDevicesWithObserver :: proc(observer: ^id, handler: DeviceNotificationHandler) -> ^NS.Array ---
 	CreateSystemDefaultDevice  :: proc() -> ^Device ---
 	RemoveDeviceObserver       :: proc(observer: id) ---
+
+
+	IOCompressionContextDefaultChunkSize :: proc() -> c.size_t ---
+	IOCreateCompressionContext           :: proc(path: cstring, type: IOCompressionMethod, chuckSize: c.size_t) -> rawptr ---
+	IOCompressionContextAppendData       :: proc(ctx: rawptr, data: rawptr, size: c.size_t) ---
+	IOFlushAndDestroyCompressionContext  :: proc(ctx: rawptr) -> IOCompressionStatus ---
 }
 
 

+ 2 - 0
vendor/darwin/Metal/MetalTypes.odin

@@ -133,6 +133,8 @@ Region :: struct {
 
 SamplePosition :: distinct [2]f32
 
+ResourceID :: distinct u64
+
 ScissorRect :: struct {
 	x:      NS.Integer,
 	y:      NS.Integer,

+ 11 - 0
vendor/darwin/QuartzCore/QuartzCore.odin

@@ -56,6 +56,17 @@ MetalLayer_setFramebufferOnly :: proc(self: ^MetalLayer, ok: NS.BOOL) {
 	msgSend(nil, self, "setFramebufferOnly:", ok)
 }
 
+
+@(objc_type=MetalLayer, objc_name="drawableSize")
+MetalLayer_drawableSize :: proc(self: ^MetalLayer) -> NS.Size {
+	return msgSend(NS.Size, self, "drawableSize")
+}
+@(objc_type=MetalLayer, objc_name="setDrawableSize")
+MetalLayer_setDrawableSize :: proc(self: ^MetalLayer, drawableSize: NS.Size) {
+	msgSend(nil, self, "setDrawableSize:", drawableSize)
+}
+
+
 @(objc_type=MetalLayer, objc_name="frame")
 MetalLayer_frame :: proc(self: ^MetalLayer) -> NS.Rect {
 	return msgSend(NS.Rect, self, "frame")

+ 3 - 4
vendor/sdl2/sdl2.odin

@@ -26,13 +26,11 @@ import "core:c"
 import "core:intrinsics"
 
 when ODIN_OS == .Windows {
-	foreign import _lib "SDL2.lib"
+	foreign import lib "SDL2.lib"
 } else {
-	foreign import _lib "system:SDL2"
+	foreign import lib "system:SDL2"
 }
 
-lib :: _lib
-
 version :: struct {
 	major: u8,        /**< major version */
 	minor: u8,        /**< minor version */
@@ -47,6 +45,7 @@ PATCHLEVEL      :: 16
 foreign lib {
 	GetVersion  :: proc(ver: ^version) ---
 	GetRevision :: proc() -> cstring ---
+
 }
 
 InitFlag :: enum u32 {

+ 6 - 0
vendor/sdl2/sdl_audio.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 /**
  *  \brief Audio format flags.
  *

+ 6 - 0
vendor/sdl2/sdl_blendmode.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 /**
  *  \brief The blend mode used in SDL_RenderCopy() and drawing operations.
  */

+ 6 - 0
vendor/sdl2/sdl_cpuinfo.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 /* This is a guess for the cacheline size used for padding.
  * Most x86 processors have a 64 byte cache line.
  * The 64-bit PowerPC processors have a 128 byte cache line.

+ 6 - 0
vendor/sdl2/sdl_events.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 RELEASED :: 0
 PRESSED  :: 1
 

+ 6 - 0
vendor/sdl2/sdl_gamecontroller.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 GameController :: struct {}
 
 GameControllerType :: enum c.int {

+ 6 - 0
vendor/sdl2/sdl_gesture_haptic.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 // Gesture
 
 GestureID :: distinct i64

+ 6 - 0
vendor/sdl2/sdl_hints.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 HINT_ACCELEROMETER_AS_JOYSTICK                :: "SDL_ACCELEROMETER_AS_JOYSTICK"
 HINT_ALLOW_ALT_TAB_WHILE_GRABBED              :: "SDL_ALLOW_ALT_TAB_WHILE_GRABBED"
 HINT_ALLOW_TOPMOST                            :: "SDL_ALLOW_TOPMOST"

+ 6 - 0
vendor/sdl2/sdl_joystick.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 Joystick :: struct {}
 
 JoystickGUID :: struct {

+ 6 - 0
vendor/sdl2/sdl_keyboard.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 Keysym :: struct {
 	scancode: Scancode, /**< SDL physical key code - see ::SDL_Scancode for details */
 	sym:      Keycode,  /**< SDL virtual key code - see ::SDL_Keycode for details */

+ 1 - 0
vendor/sdl2/sdl_keycode.odin

@@ -1,5 +1,6 @@
 package sdl2
 
+
 SCANCODE_MASK :: 1<<30
 SCANCODE_TO_KEYCODE :: #force_inline proc "c" (X: Scancode) -> Keycode {
 	return Keycode(i32(X) | SCANCODE_MASK)

+ 6 - 0
vendor/sdl2/sdl_log.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 MAX_LOG_MESSAGE :: 4096
 
 LogCategory :: enum c.int {

+ 6 - 0
vendor/sdl2/sdl_messagebox.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 MessageBoxFlag :: enum u32 {
 	_ = 0,
 	ERROR                 = 4,   /**< error dialog */

+ 6 - 0
vendor/sdl2/sdl_metal.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 MetalView :: distinct rawptr
 
 @(default_calling_convention="c", link_prefix="SDL_")

+ 6 - 0
vendor/sdl2/sdl_mouse.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 Cursor :: struct {}
 
 BUTTON :: #force_inline proc "c" (X: c.int) -> c.int { return 1 << u32(X-1) }

+ 6 - 0
vendor/sdl2/sdl_mutex.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 MUTEX_TIMEDOUT :: 1
 MUTEX_MAXWAIT  :: ~u32(0)
 

+ 6 - 0
vendor/sdl2/sdl_pixels.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 ALPHA_OPAQUE      :: 255
 ALPHA_TRANSPARENT ::   0
 

+ 6 - 0
vendor/sdl2/sdl_rect.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 Point :: struct {
 	x: c.int,
 	y: c.int,

+ 6 - 0
vendor/sdl2/sdl_render.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 RendererFlag :: enum u32 {
 	SOFTWARE      = 0, /**< The renderer is a software fallback */
 	ACCELERATED   = 1, /**< The renderer uses hardware acceleration */

+ 6 - 0
vendor/sdl2/sdl_rwops.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 /* RWops Types */
 RWOPS_UNKNOWN   :: 0 /**< Unknown stream type */
 RWOPS_WINFILE   :: 1 /**< Win32 file */

+ 6 - 0
vendor/sdl2/sdl_stdinc.odin

@@ -5,6 +5,12 @@ import "core:intrinsics"
 import "core:runtime"
 _, _ :: intrinsics, runtime
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 bool :: distinct b32
 #assert(size_of(bool) == size_of(c.int))
 

+ 6 - 0
vendor/sdl2/sdl_surface.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 SWSURFACE       :: 0           /**< Just here for compatibility */
 PREALLOC        :: 0x00000001  /**< Surface uses preallocated memory */
 RLEACCEL        :: 0x00000002  /**< Surface is RLE encoded */

+ 6 - 0
vendor/sdl2/sdl_system.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 // General
 @(default_calling_convention="c", link_prefix="SDL_")
 foreign lib {

+ 6 - 0
vendor/sdl2/sdl_syswm.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 SYSWM_TYPE :: enum c.int {
 	UNKNOWN,
 	WINDOWS,

+ 6 - 0
vendor/sdl2/sdl_thread.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 Thread :: struct {}
 
 threadID :: distinct c.ulong

+ 6 - 0
vendor/sdl2/sdl_timer.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 TimerCallback :: proc "c" (interval: u32, param: rawptr) -> u32
 TimerID :: distinct c.int
 

+ 6 - 0
vendor/sdl2/sdl_touch.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 TouchID  :: distinct i64
 FingerID :: distinct i64
 

+ 6 - 0
vendor/sdl2/sdl_video.odin

@@ -2,6 +2,12 @@ package sdl2
 
 import "core:c"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 DisplayMode :: struct {
 	format:       u32,    /**< pixel format */
 	w:            c.int,  /**< width, in screen coordinates */

+ 6 - 0
vendor/sdl2/sdl_vulkan.odin

@@ -3,6 +3,12 @@ package sdl2
 import "core:c"
 import vk "vendor:vulkan"
 
+when ODIN_OS == .Windows {
+	foreign import lib "SDL2.lib"
+} else {
+	foreign import lib "system:SDL2"
+}
+
 VkInstance   :: vk.Instance
 VkSurfaceKHR :: vk.SurfaceKHR
 

Some files were not shown because too many files changed in this diff