Explorar o código

Merge branch 'master' into windows-llvm-13.0.0

gingerBill %!s(int64=2) %!d(string=hai) anos
pai
achega
08ffbeebd5
Modificáronse 100 ficheiros con 5587 adicións e 5484 borrados
  1. 7 0
      .github/workflows/ci.yml
  2. 9 1
      core/builtin/builtin.odin
  3. 2 0
      core/crypto/util/util.odin
  4. 15 0
      core/dynlib/lib_js.odin
  5. 3 3
      core/encoding/json/types.odin
  6. 1 1
      core/fmt/doc.odin
  7. 543 92
      core/fmt/fmt.odin
  8. 43 19
      core/image/general.odin
  9. 10 0
      core/image/general_js.odin
  10. 0 61
      core/image/general_loader.odin
  11. 38 0
      core/image/general_os.odin
  12. 0 36
      core/image/netpbm/netpbm.odin
  13. 10 0
      core/image/netpbm/netpbm_js.odin
  14. 41 0
      core/image/netpbm/netpbm_os.odin
  15. 0 16
      core/image/png/png.odin
  16. 4 0
      core/image/png/png_js.odin
  17. 19 0
      core/image/png/png_os.odin
  18. 1 31
      core/image/qoi/qoi.odin
  19. 6 0
      core/image/qoi/qoi_js.odin
  20. 37 0
      core/image/qoi/qoi_os.odin
  21. 1 30
      core/image/tga/tga.odin
  22. 5 0
      core/image/tga/tga_js.odin
  23. 34 0
      core/image/tga/tga_os.odin
  24. 4 4
      core/math/linalg/extended.odin
  25. 1 1
      core/odin/parser/parser.odin
  26. 1 1
      core/os/os2/path_linux.odin
  27. 275 2
      core/os/os_js.odin
  28. 1 1
      core/os/os_linux.odin
  29. 8 1
      core/reflect/reflect.odin
  30. 3 1
      core/runtime/core.odin
  31. 7 3
      core/runtime/core_builtin.odin
  32. 7 7
      core/runtime/default_temporary_allocator.odin
  33. 24 3
      core/strings/ascii_set.odin
  34. 509 98
      core/strings/builder.odin
  35. 322 75
      core/strings/conversion.odin
  36. 61 11
      core/strings/intern.odin
  37. 139 22
      core/strings/reader.odin
  38. 699 136
      core/strings/strings.odin
  39. 2 0
      core/sys/windows/kernel32.odin
  40. 2 0
      core/sys/windows/shell32.odin
  41. 166 23
      core/sys/windows/types.odin
  42. 9 1
      core/sys/windows/user32.odin
  43. 161 0
      core/sys/windows/winmm.odin
  44. 100 0
      core/text/table/doc.odin
  45. 384 0
      core/text/table/table.odin
  46. 13 0
      core/text/table/utility.odin
  47. 55 0
      core/thread/thread_js.odin
  48. 0 337
      misc/old_demos/demo001.odin
  49. 0 879
      misc/old_demos/demo002.odin
  50. 0 66
      misc/old_demos/demo004.odin
  51. 0 283
      misc/old_demos/demo005.odin
  52. 0 310
      misc/old_demos/demo006.odin
  53. 0 570
      misc/old_demos/demo007.odin
  54. 0 778
      misc/old_demos/demo008.odin
  55. 0 412
      misc/old_demos/old_runtime.odin
  56. 0 430
      misc/old_stuff/demo_backup.odin
  57. 12 0
      src/checker.cpp
  58. 1 0
      src/checker.hpp
  59. 7 5
      src/docs_writer.cpp
  60. 1 0
      src/entity.cpp
  61. 83 58
      src/llvm_abi.cpp
  62. 16 3
      src/main.cpp
  63. 19 6
      src/parser.cpp
  64. 19 24
      tests/core/build.bat
  65. 7 0
      tests/core/compress/test_core_compress.odin
  66. 46 0
      tests/core/strings/test_core_strings.odin
  67. 13 0
      tests/documentation/build.bat
  68. 421 0
      tests/documentation/documentation_tester.odin
  69. 1 1
      tests/internal/build.bat
  70. 4 9
      tests/issues/run.bat
  71. 2 2
      tests/vendor/build.bat
  72. 44 44
      vendor/ENet/enet.odin
  73. 1 1
      vendor/raylib/LICENSE
  74. 55 21
      vendor/raylib/README.md
  75. BIN=BIN
      vendor/raylib/linux/libraylib.a
  76. BIN=BIN
      vendor/raylib/linux/libraylib.so
  77. BIN=BIN
      vendor/raylib/linux/libraylib.so.4.0.0
  78. BIN=BIN
      vendor/raylib/linux/libraylib.so.4.5.0
  79. BIN=BIN
      vendor/raylib/linux/libraylib.so.400
  80. BIN=BIN
      vendor/raylib/linux/libraylib.so.450
  81. BIN=BIN
      vendor/raylib/macos-arm64/libraylib.4.0.0.dylib
  82. BIN=BIN
      vendor/raylib/macos-arm64/libraylib.4.5.0.dylib
  83. BIN=BIN
      vendor/raylib/macos-arm64/libraylib.400.dylib
  84. BIN=BIN
      vendor/raylib/macos-arm64/libraylib.450.dylib
  85. BIN=BIN
      vendor/raylib/macos-arm64/libraylib.a
  86. BIN=BIN
      vendor/raylib/macos-arm64/libraylib.dylib
  87. BIN=BIN
      vendor/raylib/macos/libraylib.4.0.0.dylib
  88. BIN=BIN
      vendor/raylib/macos/libraylib.4.5.0.dylib
  89. BIN=BIN
      vendor/raylib/macos/libraylib.400.dylib
  90. BIN=BIN
      vendor/raylib/macos/libraylib.450.dylib
  91. BIN=BIN
      vendor/raylib/macos/libraylib.a
  92. BIN=BIN
      vendor/raylib/macos/libraylib.dylib
  93. BIN=BIN
      vendor/raylib/raylib.lib
  94. 408 412
      vendor/raylib/raylib.odin
  95. 321 153
      vendor/raylib/rlgl.odin
  96. BIN=BIN
      vendor/raylib/windows/raylib.dll
  97. BIN=BIN
      vendor/raylib/windows/raylib.lib
  98. BIN=BIN
      vendor/raylib/windows/raylibdll.lib
  99. 36 0
      vendor/wasm/js/dom_all_targets.odin
  100. 288 0
      vendor/wasm/js/events_all_targets.odin

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

@@ -163,6 +163,13 @@ jobs:
           cd tests\internal
           call build.bat
         timeout-minutes: 10
+      - name: Odin documentation tests
+        shell: cmd
+        run: |
+          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          cd tests\documentation
+          call build.bat
+        timeout-minutes: 10
       - name: core:math/big tests
         shell: cmd
         run: |

+ 9 - 1
core/builtin/builtin.odin

@@ -94,7 +94,15 @@ cap :: proc(array: Array_Type) -> int ---
 
 size_of      :: proc($T: typeid) -> int ---
 align_of     :: proc($T: typeid) -> int ---
-offset_of    :: proc($T: typeid) -> uintptr ---
+
+// e.g. offset_of(t.f), where t is an instance of the type T
+offset_of_selector :: proc(selector: $T) -> uintptr ---
+// e.g. offset_of(T, f), where T can be the type instead of a variable
+offset_of_member   :: proc($T: typeid, member: $M) -> uintptr ---
+offset_of :: proc{offset_of_selector, offset_of_member}
+// e.g. offset_of(T, "f"), where T can be the type instead of a variable
+offset_of_by_string :: proc($T: typeid, member: string) -> uintptr ---
+
 type_of      :: proc(x: expr) -> type ---
 type_info_of :: proc($T: typeid) -> ^runtime.Type_Info ---
 typeid_of    :: proc($T: typeid) -> typeid ---

+ 2 - 0
core/crypto/util/util.odin

@@ -11,6 +11,8 @@ package util
 */
 
 import "core:mem"
+// Keep vet happy
+_ :: mem
 
 // @note(bp): this can replace the other two
 cast_slice :: #force_inline proc "contextless" ($D: typeid/[]$DE, src: $S/[]$SE) -> D {

+ 15 - 0
core/dynlib/lib_js.odin

@@ -0,0 +1,15 @@
+//+build js
+//+private
+package dynlib
+
+_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
+	return
+}
+
+_unload_library :: proc(library: Library) -> bool {
+	return
+}
+
+_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
+	return
+}

+ 3 - 3
core/encoding/json/types.odin

@@ -87,7 +87,8 @@ Error :: enum {
 
 
 
-destroy_value :: proc(value: Value) {
+destroy_value :: proc(value: Value, allocator := context.allocator) {
+	context.allocator = allocator
 	#partial switch v in value {
 	case Object:
 		for key, elem in v {
@@ -103,5 +104,4 @@ destroy_value :: proc(value: Value) {
 	case String:
 		delete(v)
 	}
-}
-
+}

+ 1 - 1
core/fmt/doc.odin

@@ -68,7 +68,7 @@ A period with no following number specifies a precision of 0.
 Examples:
 	%f     default width, default precision
 	%8f    width 8, default precision
-	%.3f   default width, precision 2
+	%.2f   default width, precision 2
 	%8.3f  width 8, precision 3
 	%8.f   width 8, precision 0
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 543 - 92
core/fmt/fmt.odin


+ 43 - 19
core/image/which.odin → core/image/general.odin

@@ -1,6 +1,48 @@
 package image
 
-import "core:os"
+import "core:mem"
+import "core:bytes"
+
+Loader_Proc :: #type proc(data: []byte, options: Options, allocator: mem.Allocator) -> (img: ^Image, err: Error)
+Destroy_Proc :: #type proc(img: ^Image)
+
+@(private)
+_internal_loaders: [Which_File_Type]Loader_Proc
+_internal_destroyers: [Which_File_Type]Destroy_Proc
+
+register :: proc(kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) {
+	assert(loader != nil)
+	assert(destroyer != nil)
+	assert(_internal_loaders[kind] == nil)
+	_internal_loaders[kind] = loader
+
+	assert(_internal_destroyers[kind] == nil)
+	_internal_destroyers[kind] = destroyer
+}
+
+load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
+	loader := _internal_loaders[which(data)]
+	if loader == nil {
+		return nil, .Unsupported_Format
+	}
+	return loader(data, options, allocator)
+}
+
+
+destroy :: proc(img: ^Image, allocator := context.allocator) {
+	if img == nil {
+		return
+	}
+	context.allocator = allocator
+	destroyer := _internal_destroyers[img.which]
+	if destroyer != nil {
+		destroyer(img)
+	} else {
+		assert(img.metadata == nil)
+		bytes.buffer_destroy(&img.pixels)
+		free(img)
+	}
+}
 
 Which_File_Type :: enum {
 	Unknown,
@@ -28,11 +70,6 @@ Which_File_Type :: enum {
 	XBM, // X BitMap
 }
 
-which :: proc{
-	which_bytes,
-	which_file,
-}
-
 which_bytes :: proc(data: []byte) -> Which_File_Type {
 	test_tga :: proc(s: string) -> bool {
 		get8 :: #force_inline proc(s: ^string) -> u8 {
@@ -164,16 +201,3 @@ which_bytes :: proc(data: []byte) -> Which_File_Type {
 	}
 	return .Unknown
 }
-
-
-which_file :: proc(path: string) -> Which_File_Type {
-	f, err := os.open(path)
-	if err != 0 {
-		return .Unknown
-	}
-	header: [128]byte
-	os.read(f, header[:])
-	file_type := which_bytes(header[:])
-	os.close(f)
-	return file_type
-}

+ 10 - 0
core/image/general_js.odin

@@ -0,0 +1,10 @@
+//+build js
+package image
+
+load :: proc{
+	load_from_bytes,
+}
+
+which :: proc{
+	which_bytes,
+}

+ 0 - 61
core/image/general_loader.odin

@@ -1,61 +0,0 @@
-package image
-
-import "core:mem"
-import "core:os"
-import "core:bytes"
-
-Loader_Proc :: #type proc(data: []byte, options: Options, allocator: mem.Allocator) -> (img: ^Image, err: Error)
-Destroy_Proc :: #type proc(img: ^Image)
-
-@(private)
-_internal_loaders: [Which_File_Type]Loader_Proc
-_internal_destroyers: [Which_File_Type]Destroy_Proc
-
-register :: proc(kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) {
-	assert(loader != nil)
-	assert(destroyer != nil)
-	assert(_internal_loaders[kind] == nil)
-	_internal_loaders[kind] = loader
-
-	assert(_internal_destroyers[kind] == nil)
-	_internal_destroyers[kind] = destroyer
-}
-
-load :: proc{
-	load_from_bytes,
-	load_from_file,
-}
-
-load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
-	loader := _internal_loaders[which(data)]
-	if loader == nil {
-		return nil, .Unsupported_Format
-	}
-	return loader(data, options, allocator)
-}
-
-
-load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
-	data, ok := os.read_entire_file(filename, allocator)
-	defer delete(data, allocator)
-	if ok {
-		return load_from_bytes(data, options, allocator)
-	} else {
-		return nil, .Unable_To_Read_File
-	}
-}
-
-destroy :: proc(img: ^Image, allocator := context.allocator) {
-	if img == nil {
-		return
-	}
-	context.allocator = allocator
-	destroyer := _internal_destroyers[img.which]
-	if destroyer != nil {
-		destroyer(img)
-	} else {
-		assert(img.metadata == nil)
-		bytes.buffer_destroy(&img.pixels)
-		free(img)
-	}
-}

+ 38 - 0
core/image/general_os.odin

@@ -0,0 +1,38 @@
+//+build !js
+package image
+
+import "core:os"
+
+load :: proc{
+	load_from_bytes,
+	load_from_file,
+}
+
+
+load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
+	data, ok := os.read_entire_file(filename, allocator)
+	defer delete(data, allocator)
+	if ok {
+		return load_from_bytes(data, options, allocator)
+	} else {
+		return nil, .Unable_To_Read_File
+	}
+}
+
+
+which :: proc{
+	which_bytes,
+	which_file,
+}
+
+which_file :: proc(path: string) -> Which_File_Type {
+	f, err := os.open(path)
+	if err != 0 {
+		return .Unknown
+	}
+	header: [128]byte
+	os.read(f, header[:])
+	file_type := which_bytes(header[:])
+	os.close(f)
+	return file_type
+}

+ 0 - 36
core/image/netpbm/netpbm.odin

@@ -4,7 +4,6 @@ import "core:bytes"
 import "core:fmt"
 import "core:image"
 import "core:mem"
-import "core:os"
 import "core:strconv"
 import "core:strings"
 import "core:unicode"
@@ -27,23 +26,6 @@ PFM     :: Formats{.Pf, .PF}
 ASCII   :: Formats{.P1, .P2, .P3}
 BINARY  :: Formats{.P4, .P5, .P6} + PAM + PFM
 
-load :: proc {
-	load_from_file,
-	load_from_bytes,
-}
-
-load_from_file :: proc(filename: string, allocator := context.allocator) -> (img: ^Image, err: Error) {
-	context.allocator = allocator
-
-	data, ok := os.read_entire_file(filename); defer delete(data)
-	if !ok {
-		err = .Unable_To_Read_File
-		return
-	}
-
-	return load_from_bytes(data)
-}
-
 load_from_bytes :: proc(data: []byte, allocator := context.allocator) -> (img: ^Image, err: Error) {
 	context.allocator = allocator
 
@@ -67,24 +49,6 @@ load_from_bytes :: proc(data: []byte, allocator := context.allocator) -> (img: ^
 	return img, nil
 }
 
-save :: proc {
-	save_to_file,
-	save_to_buffer,
-}
-
-save_to_file :: proc(filename: string, img: ^Image, custom_info: Info = {}, allocator := context.allocator) -> (err: Error) {
-	context.allocator = allocator
-
-	data: []byte; defer delete(data)
-	data = save_to_buffer(img, custom_info) or_return
-
-	if ok := os.write_entire_file(filename, data); !ok {
-		return .Unable_To_Write_File
-	}
-
-	return Format_Error.None
-}
-
 save_to_buffer :: proc(img: ^Image, custom_info: Info = {}, allocator := context.allocator) -> (buffer: []byte, err: Error) {
 	context.allocator = allocator
 

+ 10 - 0
core/image/netpbm/netpbm_js.odin

@@ -0,0 +1,10 @@
+//+build js
+package netpbm
+
+load :: proc {
+	load_from_bytes,
+}
+
+save :: proc {
+	save_to_buffer,
+}

+ 41 - 0
core/image/netpbm/netpbm_os.odin

@@ -0,0 +1,41 @@
+//+build !js
+package netpbm
+
+import "core:os"
+
+load :: proc {
+	load_from_file,
+	load_from_bytes,
+}
+
+
+load_from_file :: proc(filename: string, allocator := context.allocator) -> (img: ^Image, err: Error) {
+	context.allocator = allocator
+
+	data, ok := os.read_entire_file(filename); defer delete(data)
+	if !ok {
+		err = .Unable_To_Read_File
+		return
+	}
+
+	return load_from_bytes(data)
+}
+
+
+save :: proc {
+	save_to_file,
+	save_to_buffer,
+}
+
+save_to_file :: proc(filename: string, img: ^Image, custom_info: Info = {}, allocator := context.allocator) -> (err: Error) {
+	context.allocator = allocator
+
+	data: []byte; defer delete(data)
+	data = save_to_buffer(img, custom_info) or_return
+
+	if ok := os.write_entire_file(filename, data); !ok {
+		return .Unable_To_Write_File
+	}
+
+	return Format_Error.None
+}

+ 0 - 16
core/image/png/png.odin

@@ -17,7 +17,6 @@ import "core:compress"
 import "core:compress/zlib"
 import "core:image"
 
-import "core:os"
 import "core:hash"
 import "core:bytes"
 import "core:io"
@@ -336,19 +335,6 @@ load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context
 	return img, err
 }
 
-load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
-	context.allocator = allocator
-
-	data, ok := os.read_entire_file(filename)
-	defer delete(data)
-
-	if ok {
-		return load_from_bytes(data, options)
-	} else {
-		return nil, .Unable_To_Read_File
-	}
-}
-
 load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
 	context.allocator = allocator
 	options := options
@@ -1641,8 +1627,6 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
 	return nil
 }
 
-load :: proc{load_from_file, load_from_bytes, load_from_context}
-
 
 @(init, private)
 _register :: proc() {

+ 4 - 0
core/image/png/png_js.odin

@@ -0,0 +1,4 @@
+//+build js
+package png
+
+load :: proc{load_from_bytes, load_from_context}

+ 19 - 0
core/image/png/png_os.odin

@@ -0,0 +1,19 @@
+//+build !js
+package png
+
+import "core:os"
+
+load :: proc{load_from_file, load_from_bytes, load_from_context}
+
+load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
+	context.allocator = allocator
+
+	data, ok := os.read_entire_file(filename)
+	defer delete(data)
+
+	if ok {
+		return load_from_bytes(data, options)
+	} else {
+		return nil, .Unable_To_Read_File
+	}
+}

+ 1 - 31
core/image/qoi/qoi.odin

@@ -15,7 +15,6 @@ package qoi
 import "core:image"
 import "core:compress"
 import "core:bytes"
-import "core:os"
 
 Error   :: image.Error
 Image   :: image.Image
@@ -24,7 +23,7 @@ Options :: image.Options
 RGB_Pixel  :: image.RGB_Pixel
 RGBA_Pixel :: image.RGBA_Pixel
 
-save_to_memory  :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) {
+save_to_buffer  :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) {
 	context.allocator = allocator
 
 	if img == nil {
@@ -166,20 +165,6 @@ save_to_memory  :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}
 	return nil
 }
 
-save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) {
-	context.allocator = allocator
-
-	out := &bytes.Buffer{}
-	defer bytes.buffer_destroy(out)
-
-	save_to_memory(out, img, options) or_return
-	write_ok := os.write_entire_file(output, out.buf[:])
-
-	return nil if write_ok else .Unable_To_Write_File
-}
-
-save :: proc{save_to_memory, save_to_file}
-
 load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
 	ctx := &compress.Context_Memory_Input{
 		input_data = data,
@@ -189,19 +174,6 @@ load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context
 	return img, err
 }
 
-load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
-	context.allocator = allocator
-
-	data, ok := os.read_entire_file(filename)
-	defer delete(data)
-
-	if ok {
-		return load_from_bytes(data, options)
-	} else {
-		return nil, .Unable_To_Read_File
-	}
-}
-
 @(optimization_mode="speed")
 load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
 	context.allocator = allocator
@@ -359,8 +331,6 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
 	return
 }
 
-load :: proc{load_from_file, load_from_bytes, load_from_context}
-
 /*
 	Cleanup of image-specific data.
 */

+ 6 - 0
core/image/qoi/qoi_js.odin

@@ -0,0 +1,6 @@
+//+build js
+package qoi
+
+save :: proc{save_to_buffer}
+
+load :: proc{load_from_bytes, load_from_context}

+ 37 - 0
core/image/qoi/qoi_os.odin

@@ -0,0 +1,37 @@
+//+build !js
+package qoi
+
+import "core:os"
+import "core:bytes"
+
+save :: proc{save_to_buffer, save_to_file}
+
+
+save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) {
+	context.allocator = allocator
+
+	out := &bytes.Buffer{}
+	defer bytes.buffer_destroy(out)
+
+	save_to_buffer(out, img, options) or_return
+	write_ok := os.write_entire_file(output, out.buf[:])
+
+	return nil if write_ok else .Unable_To_Write_File
+}
+
+
+load :: proc{load_from_file, load_from_bytes, load_from_context}
+
+
+load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
+	context.allocator = allocator
+
+	data, ok := os.read_entire_file(filename)
+	defer delete(data)
+
+	if ok {
+		return load_from_bytes(data, options)
+	} else {
+		return nil, .Unable_To_Read_File
+	}
+}

+ 1 - 30
core/image/tga/tga.odin

@@ -14,7 +14,6 @@ package tga
 import "core:mem"
 import "core:image"
 import "core:bytes"
-import "core:os"
 import "core:compress"
 import "core:strings"
 
@@ -28,7 +27,7 @@ GA_Pixel   :: image.GA_Pixel
 RGB_Pixel  :: image.RGB_Pixel
 RGBA_Pixel :: image.RGBA_Pixel
 
-save_to_memory  :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) {
+save_to_buffer  :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) {
 	context.allocator = allocator
 
 	if img == nil {
@@ -92,20 +91,6 @@ save_to_memory  :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}
 	return nil
 }
 
-save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) {
-	context.allocator = allocator
-
-	out := &bytes.Buffer{}
-	defer bytes.buffer_destroy(out)
-
-	save_to_memory(out, img, options) or_return
-	write_ok := os.write_entire_file(output, out.buf[:])
-
-	return nil if write_ok else .Unable_To_Write_File
-}
-
-save :: proc{save_to_memory, save_to_file}
-
 load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
 	context.allocator = allocator
 	options := options
@@ -398,20 +383,6 @@ load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context
 	return img, err
 }
 
-load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
-	context.allocator = allocator
-
-	data, ok := os.read_entire_file(filename)
-	defer delete(data)
-
-	if ok {
-		return load_from_bytes(data, options)
-	} else {
-		return nil, .Unable_To_Read_File
-	}
-}
-
-load :: proc{load_from_file, load_from_bytes, load_from_context}
 
 destroy :: proc(img: ^Image) {
 	if img == nil || img.width == 0 || img.height == 0 {

+ 5 - 0
core/image/tga/tga_js.odin

@@ -0,0 +1,5 @@
+//+build js
+package tga
+
+save :: proc{save_to_buffer}
+load :: proc{load_from_bytes, load_from_context}

+ 34 - 0
core/image/tga/tga_os.odin

@@ -0,0 +1,34 @@
+//+build !js
+package tga
+
+import "core:os"
+import "core:bytes"
+
+save :: proc{save_to_buffer, save_to_file}
+
+save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocator := context.allocator) -> (err: Error) {
+	context.allocator = allocator
+
+	out := &bytes.Buffer{}
+	defer bytes.buffer_destroy(out)
+
+	save_to_buffer(out, img, options) or_return
+	write_ok := os.write_entire_file(output, out.buf[:])
+
+	return nil if write_ok else .Unable_To_Write_File
+}
+
+load :: proc{load_from_file, load_from_bytes, load_from_context}
+
+load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
+	context.allocator = allocator
+
+	data, ok := os.read_entire_file(filename)
+	defer delete(data)
+
+	if ok {
+		return load_from_bytes(data, options)
+	} else {
+		return nil, .Unable_To_Read_File
+	}
+}

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

@@ -429,11 +429,11 @@ reflect :: proc(I, N: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T))
 	b := N * (2 * dot(N, I))
 	return I - b
 }
-refract :: proc(I, N: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
-	dv := dot(N, I)
-	k := 1 - eta*eta - (1 - dv*dv)
+refract :: proc(I, Normal: $V/[$N]$E, eta: E) -> (out: V) where IS_ARRAY(V), IS_FLOAT(ELEM_TYPE(V)) {
+	dv := dot(Normal, I)
+	k := 1 - eta*eta * (1 - dv*dv)
 	a := I * eta
-	b := N * eta*dv*math.sqrt(k)
+	b := Normal * (eta*dv+math.sqrt(k))
 	return (a - b) * E(int(k >= 0))
 }
 

+ 1 - 1
core/odin/parser/parser.odin

@@ -1425,7 +1425,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
 			return es
 
 		case "force_inline", "force_no_inline":
-			expr := parse_inlining_operand(p, true, tok)
+			expr := parse_inlining_operand(p, true, tag)
 			es := ast.new(ast.Expr_Stmt, expr.pos, expr.end)
 			es.expr = expr
 			return es

+ 1 - 1
core/os/os2/path_linux.odin

@@ -211,7 +211,7 @@ _getwd :: proc(allocator: runtime.Allocator) -> (string, Error) {
 		#no_bounds_check res := unix.sys_getcwd(&buf[0], uint(len(buf)))
 
 		if res >= 0 {
-			return strings.string_from_nul_terminated_ptr(&buf[0], len(buf)), nil
+			return strings.string_from_null_terminated_ptr(&buf[0], len(buf)), nil
 		}
 		if res != -ERANGE {
 			return "", _get_platform_error(res)

+ 275 - 2
core/os/os_js.odin

@@ -1,4 +1,277 @@
+//+build js
 package os
-// +build js
 
-#panic("package os does not support a js target")
+import "core:intrinsics"
+import "core:runtime"
+import "core:unicode/utf16"
+
+is_path_separator :: proc(c: byte) -> bool {
+	return c == '/' || c == '\\'
+}
+
+open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+close :: proc(fd: Handle) -> Errno {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+flush :: proc(fd: Handle) -> (err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+
+write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+@(private="file")
+read_console :: proc(handle: Handle, b: []byte) -> (n: int, err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+file_size :: proc(fd: Handle) -> (i64, Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+@(private)
+MAX_RW :: 1<<30
+
+@(private)
+pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+@(private)
+pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+
+// NOTE(bill): Uses startup to initialize it
+//stdin  := get_std_handle(uint(win32.STD_INPUT_HANDLE))
+//stdout := get_std_handle(uint(win32.STD_OUTPUT_HANDLE))
+//stderr := get_std_handle(uint(win32.STD_ERROR_HANDLE))
+
+
+get_std_handle :: proc "contextless" (h: uint) -> Handle {
+	context = runtime.default_context()
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+exists :: proc(path: string) -> bool {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+is_file :: proc(path: string) -> bool {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+is_dir :: proc(path: string) -> bool {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+// NOTE(tetra): GetCurrentDirectory is not thread safe with SetCurrentDirectory and GetFullPathName
+//@private cwd_lock := win32.SRWLOCK{} // zero is initialized
+
+get_current_directory :: proc(allocator := context.allocator) -> string {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+set_current_directory :: proc(path: string) -> (err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+
+change_directory :: proc(path: string) -> (err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+make_directory :: proc(path: string, mode: u32 = 0) -> (err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+remove_directory :: proc(path: string) -> (err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+
+@(private)
+is_abs :: proc(path: string) -> bool {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+@(private)
+fix_long_path :: proc(path: string) -> string {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+link :: proc(old_name, new_name: string) -> (err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+unlink :: proc(path: string) -> (err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+
+rename :: proc(old_path, new_path: string) -> (err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+ftruncate :: proc(fd: Handle, length: i64) -> (err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+truncate :: proc(path: string, length: i64) -> (err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+remove :: proc(name: string) -> Errno {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+pipe :: proc() -> (r, w: Handle, err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+Handle    :: distinct uintptr
+File_Time :: distinct u64
+Errno     :: distinct int
+
+
+INVALID_HANDLE :: ~Handle(0)
+
+
+
+O_RDONLY   :: 0x00000
+O_WRONLY   :: 0x00001
+O_RDWR     :: 0x00002
+O_CREATE   :: 0x00040
+O_EXCL     :: 0x00080
+O_NOCTTY   :: 0x00100
+O_TRUNC    :: 0x00200
+O_NONBLOCK :: 0x00800
+O_APPEND   :: 0x00400
+O_SYNC     :: 0x01000
+O_ASYNC    :: 0x02000
+O_CLOEXEC  :: 0x80000
+
+
+ERROR_NONE:                   Errno : 0
+ERROR_FILE_NOT_FOUND:         Errno : 2
+ERROR_PATH_NOT_FOUND:         Errno : 3
+ERROR_ACCESS_DENIED:          Errno : 5
+ERROR_INVALID_HANDLE:         Errno : 6
+ERROR_NOT_ENOUGH_MEMORY:      Errno : 8
+ERROR_NO_MORE_FILES:          Errno : 18
+ERROR_HANDLE_EOF:             Errno : 38
+ERROR_NETNAME_DELETED:        Errno : 64
+ERROR_FILE_EXISTS:            Errno : 80
+ERROR_INVALID_PARAMETER:      Errno : 87
+ERROR_BROKEN_PIPE:            Errno : 109
+ERROR_BUFFER_OVERFLOW:        Errno : 111
+ERROR_INSUFFICIENT_BUFFER:    Errno : 122
+ERROR_MOD_NOT_FOUND:          Errno : 126
+ERROR_PROC_NOT_FOUND:         Errno : 127
+ERROR_DIR_NOT_EMPTY:          Errno : 145
+ERROR_ALREADY_EXISTS:         Errno : 183
+ERROR_ENVVAR_NOT_FOUND:       Errno : 203
+ERROR_MORE_DATA:              Errno : 234
+ERROR_OPERATION_ABORTED:      Errno : 995
+ERROR_IO_PENDING:             Errno : 997
+ERROR_NOT_FOUND:              Errno : 1168
+ERROR_PRIVILEGE_NOT_HELD:     Errno : 1314
+WSAEACCES:                    Errno : 10013
+WSAECONNRESET:                Errno : 10054
+
+// Windows reserves errors >= 1<<29 for application use
+ERROR_FILE_IS_PIPE:           Errno : 1<<29 + 0
+ERROR_FILE_IS_NOT_DIR:        Errno : 1<<29 + 1
+ERROR_NEGATIVE_OFFSET:        Errno : 1<<29 + 2
+
+// "Argv" arguments converted to Odin strings
+args := _alloc_command_line_arguments()
+
+
+
+
+
+last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+
+heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
+	unimplemented("core:os procedure not supported on JS target")
+}
+heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
+	unimplemented("core:os procedure not supported on JS target")
+}
+heap_free :: proc(ptr: rawptr) {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+get_page_size :: proc() -> int {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+@(private)
+_processor_core_count :: proc() -> int {
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+exit :: proc "contextless" (code: int) -> ! {
+	context = runtime.default_context()
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+
+current_thread_id :: proc "contextless" () -> int {
+	context = runtime.default_context()
+	unimplemented("core:os procedure not supported on JS target")
+}
+
+
+
+_alloc_command_line_arguments :: proc() -> []string {
+	return nil
+}
+

+ 1 - 1
core/os/os_linux.odin

@@ -913,7 +913,7 @@ get_current_directory :: proc() -> string {
 		#no_bounds_check res := unix.sys_getcwd(&buf[0], uint(len(buf)))
 
 		if res >= 0 {
-			return strings.string_from_nul_terminated_ptr(&buf[0], len(buf))
+			return strings.string_from_null_terminated_ptr(&buf[0], len(buf))
 		}
 		if _get_errno(res) != ERANGE {
 			delete(buf)

+ 8 - 1
core/reflect/reflect.odin

@@ -449,7 +449,14 @@ struct_field_value_by_name :: proc(a: any, field: string, allow_using := false)
 	return nil
 }
 
-
+@(require_results)
+struct_field_value :: proc(a: any, field: Struct_Field) -> any {
+	if a == nil { return nil }
+	return any {
+		rawptr(uintptr(a.data) + field.offset),
+		field.type.id,
+	}
+}
 
 @(require_results)
 struct_field_names :: proc(T: typeid) -> []string {

+ 3 - 1
core/runtime/core.odin

@@ -621,7 +621,9 @@ __init_context :: proc "contextless" (c: ^Context) {
 	c.allocator.data = nil
 
 	c.temp_allocator.procedure = default_temp_allocator_proc
-	c.temp_allocator.data = &global_default_temp_allocator_data
+	when !NO_DEFAULT_TEMP_ALLOCATOR {
+		c.temp_allocator.data = &global_default_temp_allocator_data
+	}
 	
 	when !ODIN_DISABLE_ASSERT {
 		c.assertion_failure_proc = default_assertion_failure_proc

+ 7 - 3
core/runtime/core_builtin.odin

@@ -15,11 +15,15 @@ container_of :: #force_inline proc "contextless" (ptr: $P/^$Field_Type, $T: type
 }
 
 
-@thread_local global_default_temp_allocator_data: Default_Temp_Allocator
+when !NO_DEFAULT_TEMP_ALLOCATOR {
+	@thread_local global_default_temp_allocator_data: Default_Temp_Allocator
+}
 
-@builtin
+@(builtin, disabled=NO_DEFAULT_TEMP_ALLOCATOR)
 init_global_temporary_allocator :: proc(size: int, backup_allocator := context.allocator) {
-	default_temp_allocator_init(&global_default_temp_allocator_data, size, backup_allocator)
+	when !NO_DEFAULT_TEMP_ALLOCATOR {
+		default_temp_allocator_init(&global_default_temp_allocator_data, size, backup_allocator)
+	}
 }
 
 

+ 7 - 7
core/runtime/default_temporary_allocator.odin

@@ -1,9 +1,9 @@
 package runtime
 
 DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 4 * Megabyte)
+NO_DEFAULT_TEMP_ALLOCATOR: bool : ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR
 
-
-when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR {
+when NO_DEFAULT_TEMP_ALLOCATOR {
 	Default_Temp_Allocator :: struct {}
 	
 	default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {}
@@ -54,6 +54,11 @@ when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR
 	default_temp_allocator_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
 		arena_temp_end(temp, loc)
 	}
+
+	@(fini, private)
+	_destroy_temp_allocator_fini :: proc() {
+		default_temp_allocator_destroy(&global_default_temp_allocator_data)
+	}
 }
 
 @(deferred_out=default_temp_allocator_temp_end)
@@ -72,8 +77,3 @@ default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator
 		data      = allocator,
 	}
 }
-
-@(fini, private)
-_destroy_temp_allocator_fini :: proc() {
-	default_temp_allocator_destroy(&global_default_temp_allocator_data)
-}

+ 24 - 3
core/strings/ascii_set.odin

@@ -3,9 +3,22 @@ package strings
 
 import "core:unicode/utf8"
 
+/*
+Ascii_Set is designed to store ASCII characters efficiently as a bit-array
+Each bit in the array corresponds to a specific ASCII character, where the value of the bit (0 or 1) 
+indicates if the character is present in the set or not.
+*/
 Ascii_Set :: distinct [8]u32
+/*
+Creates an Ascii_Set with unique characters from the input string.
 
-// create an ascii set of all unique characters in the string
+Inputs:
+- chars: A string containing characters to include in the Ascii_Set.
+
+Returns:
+- as: An Ascii_Set with unique characters from the input string.
+- ok: false if any character in the input string is not a valid ASCII character.
+*/
 ascii_set_make :: proc(chars: string) -> (as: Ascii_Set, ok: bool) #no_bounds_check {
 	for i in 0..<len(chars) {
 		c := chars[i]
@@ -17,8 +30,16 @@ ascii_set_make :: proc(chars: string) -> (as: Ascii_Set, ok: bool) #no_bounds_ch
 	ok = true
 	return
 }
+/*
+Determines if a given char is contained within an Ascii_Set.
+
+Inputs:
+- as: The Ascii_Set to search.
+- c: The char to check for in the Ascii_Set.
 
-// returns true when the `c` byte is contained in the `as` ascii set
+Returns:
+A boolean indicating if the byte is contained in the Ascii_Set (true) or not (false).
+*/
 ascii_set_contains :: proc(as: Ascii_Set, c: byte) -> bool #no_bounds_check {
 	return as[c>>5] & (1<<(c&31)) != 0
-}
+}

+ 509 - 98
core/strings/builder.odin

@@ -4,68 +4,133 @@ import "core:runtime"
 import "core:unicode/utf8"
 import "core:strconv"
 import "core:io"
+/*
+Type definition for a procedure that flushes a Builder
 
-Builder_Flush_Proc :: #type proc(b: ^Builder) -> (do_reset: bool)
+Inputs:
+- b: A pointer to the Builder
 
+Returns:
+A boolean indicating whether the Builder should be reset
+*/
+Builder_Flush_Proc :: #type proc(b: ^Builder) -> (do_reset: bool)
 /*
-	dynamic byte buffer / string builder with helper procedures
-	the dynamic array is wrapped inside the struct to be more opaque
-	you can use `fmt.sbprint*` procedures with a `^strings.Builder` directly
+A dynamic byte buffer / string builder with helper procedures
+The dynamic array is wrapped inside the struct to be more opaque
+You can use `fmt.sbprint*` procedures with a `^strings.Builder` directly
 */
 Builder :: struct {
 	buf: [dynamic]byte,
 }
+/*
+Produces a Builder with a default length of 0 and cap of 16
+
+*Allocates Using Provided Allocator*
 
-// return a builder, default length 0 / cap 16 are done through make
+Inputs:
+- allocator: (default is context.allocator)
+
+Returns:
+A new Builder
+*/
 builder_make_none :: proc(allocator := context.allocator) -> Builder {
 	return Builder{buf=make([dynamic]byte, allocator)}
 }
+/*
+Produces a Builder with a specified length and cap of max(16,len) byte buffer
 
-// return a builder, with a set length `len` and cap 16 byte buffer
+*Allocates Using Provided Allocator*
+
+Inputs:
+- len: The desired length of the Builder's buffer
+- allocator: (default is context.allocator)
+
+Returns:
+A new Builder
+*/
 builder_make_len :: proc(len: int, allocator := context.allocator) -> Builder {
 	return Builder{buf=make([dynamic]byte, len, allocator)}
 }
+/*
+Produces a Builder with a specified length and cap
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- len: The desired length of the Builder's buffer
+- cap: The desired capacity of the Builder's buffer, cap is max(cap, len)
+- allocator: (default is context.allocator)
 
-// return a builder, with a set length `len` byte buffer and a custom `cap`
+Returns:
+A new Builder
+*/
 builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator) -> Builder {
 	return Builder{buf=make([dynamic]byte, len, cap, allocator)}
 }
-
 // overload simple `builder_make_*` with or without len / cap parameters
 builder_make :: proc{
 	builder_make_none,
 	builder_make_len,
 	builder_make_len_cap,
 }
+/*
+Initializes a Builder with a length of 0 and cap of 16
+It replaces the existing `buf`
 
-// initialize a builder, default length 0 / cap 16 are done through make
-// replaces the existing `buf`
+*Allocates Using Provided Allocator*
+
+Inputs:
+- b: A pointer to the Builder
+- allocator: (default is context.allocator)
+
+Returns:
+initialized ^Builder
+*/
 builder_init_none :: proc(b: ^Builder, allocator := context.allocator) -> ^Builder {
 	b.buf = make([dynamic]byte, allocator)
 	return b
 }
+/*
+Initializes a Builder with a specified length and cap, which is max(len,16)
+It replaces the existing `buf`
+
+*Allocates Using Provided Allocator*
 
-// initialize a builder, with a set length `len` and cap 16 byte buffer
-// replaces the existing `buf`
+Inputs:
+- b: A pointer to the Builder
+- len: The desired length of the Builder's buffer
+- allocator: (default is context.allocator)
+
+Returns:
+Initialized ^Builder
+*/
 builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator) -> ^Builder {
 	b.buf = make([dynamic]byte, len, allocator)
 	return b
 }
+/*
+Initializes a Builder with a specified length and cap
+It replaces the existing `buf`
 
-// initialize a builder, with a set length `len` byte buffer and a custom `cap`
-// replaces the existing `buf`
+Inputs:
+- b: A pointer to the Builder
+- len: The desired length of the Builder's buffer
+- cap: The desired capacity of the Builder's buffer, actual max(len,cap)
+- allocator: (default is context.allocator)
+
+Returns:
+A pointer to the initialized Builder
+*/
 builder_init_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) -> ^Builder {
 	b.buf = make([dynamic]byte, len, cap, allocator)
 	return b
 }
-
-// overload simple `builder_init_*` with or without len / ap parameters
+// Overload simple `builder_init_*` with or without len / ap parameters
 builder_init :: proc{
 	builder_init_none,
 	builder_init_len,
 	builder_init_len_cap,
 }
-
 @(private)
 _builder_stream_vtable_obj := io.Stream_VTable{
 	impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
@@ -90,50 +155,95 @@ _builder_stream_vtable_obj := io.Stream_VTable{
 	},
 	impl_destroy = proc(s: io.Stream) -> io.Error {
 		b := (^Builder)(s.stream_data)
-		delete(b.buf)
+		builder_destroy(b)
 		return .None
 	},
 }
-
 // NOTE(dweiler): Work around a miscompilation bug on Linux still.
 @(private)
 _builder_stream_vtable := &_builder_stream_vtable_obj
+/*
+Returns an io.Stream from a Builder
 
-// return an `io.Stream` from a builder
+Inputs:
+- b: A pointer to the Builder
+
+Returns:
+An io.Stream
+*/
 to_stream :: proc(b: ^Builder) -> io.Stream {
 	return io.Stream{stream_vtable=_builder_stream_vtable, stream_data=b}
 }
+/*
+Returns an io.Writer from a Builder
 
-// return an `io.Writer` from a builder
+Inputs:
+- b: A pointer to the Builder
+
+Returns: 
+An io.Writer
+*/
 to_writer :: proc(b: ^Builder) -> io.Writer {
 	return io.to_writer(to_stream(b))
 }
+/*
+Deletes the Builder byte buffer content
 
-// delete and clear the builder byte buffer content
+Inputs:
+- b: A pointer to the Builder
+*/
 builder_destroy :: proc(b: ^Builder) {
 	delete(b.buf)
-	clear(&b.buf)
+	b.buf = nil
 }
+/*
+Reserves the Builder byte buffer to a specific capacity, when it's higher than before
 
-// reserve the builfer byte buffer to a specific cap, when it's higher than before
+Inputs:
+- b: A pointer to the Builder
+- cap: The desired capacity for the Builder's buffer
+*/
 builder_grow :: proc(b: ^Builder, cap: int) {
 	reserve(&b.buf, cap)
 }
+/*
+Clears the Builder byte buffer content (sets len to zero)
 
-// clear the builder byte buffer content
+Inputs:
+- b: A pointer to the Builder
+*/
 builder_reset :: proc(b: ^Builder) {
 	clear(&b.buf)
 }
-
 /*
-	create an empty builder with the same slice length as its cap
-	uses the `mem.nil_allocator` to avoid allocation and keep a fixed length
-	used in `fmt.bprint*`
-	
-	bytes: [8]byte // <-- gets filled
-	builder := strings.builder_from_bytes(bytes[:])
-	strings.write_byte(&builder, 'a') -> "a"
-	strings.write_byte(&builder, 'b') -> "ab"
+Creates a Builder from a slice of bytes with the same slice length as its capacity. Used in fmt.bprint*
+
+*Uses Nil Allocator - Does NOT allocate*
+
+Inputs:
+- backing: A slice of bytes to be used as the backing buffer
+
+Returns:
+A new Builder
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+	builder_from_bytes_example :: proc() {
+		bytes: [8]byte // <-- gets filled
+		builder := strings.builder_from_bytes(bytes[:])
+		strings.write_byte(&builder, 'a')
+		fmt.println(strings.to_string(builder)) // -> "a"
+		strings.write_byte(&builder, 'b')
+		fmt.println(strings.to_string(builder)) // -> "ab"
+	}
+
+Output:
+
+	a
+	ab
+
 */
 builder_from_bytes :: proc(backing: []byte) -> Builder {
 	s := transmute(runtime.Raw_Slice)backing
@@ -147,36 +257,84 @@ builder_from_bytes :: proc(backing: []byte) -> Builder {
 		buf = transmute([dynamic]byte)d,
 	}
 }
+// Alias to `builder_from_bytes`
 builder_from_slice :: builder_from_bytes
+/*
+Casts the Builder byte buffer to a string and returns it
 
-// cast the builder byte buffer to a string and return it
+Inputs:
+- b: A Builder
+
+Returns:
+The contents of the Builder's buffer, as a string
+*/
 to_string :: proc(b: Builder) -> string {
 	return string(b.buf[:])
 }
+/*
+Returns the length of the Builder's buffer, in bytes
 
-// return the length of the builder byte buffer
+Inputs:
+- b: A Builder
+
+Returns:
+The length of the Builder's buffer
+*/
 builder_len :: proc(b: Builder) -> int {
 	return len(b.buf)
 }
+/*
+Returns the capacity of the Builder's buffer, in bytes
 
-// return the cap of the builder byte buffer
+Inputs:
+- b: A Builder
+
+Returns:
+The capacity of the Builder's buffer
+*/
 builder_cap :: proc(b: Builder) -> int {
 	return cap(b.buf)
 }
+/*
+The free space left in the Builder's buffer, in bytes
 
-// returns the space left in the builder byte buffer to use up
+Inputs:
+- b: A Builder
+
+Returns:
+The available space left in the Builder's buffer
+*/
 builder_space :: proc(b: Builder) -> int {
 	return cap(b.buf) - len(b.buf)
 }
-
 /*
-	appends a byte to the builder, returns the append diff
+Appends a byte to the Builder and returns the number of bytes appended
+
+Inputs:
+- b: A pointer to the Builder
+- x: The byte to be appended
+
+Returns:
+The number of bytes appended
+
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	write_byte_example :: proc() {
+		builder := strings.builder_make()
+		strings.write_byte(&builder, 'a')        // 1
+		strings.write_byte(&builder, 'b')        // 1
+		fmt.println(strings.to_string(builder))  // -> ab
+	}
+
+Output:
+
+	ab
 
-	builder := strings.builder_make()
-	strings.write_byte(&builder, 'a') // 1
-	strings.write_byte(&builder, 'b') // 1
-	strings.write_byte(&builder, 'c') // 1
-	fmt.println(strings.to_string(builder)) // -> abc
 */
 write_byte :: proc(b: ^Builder, x: byte) -> (n: int) {
 	n0 := len(b.buf)
@@ -184,14 +342,29 @@ write_byte :: proc(b: ^Builder, x: byte) -> (n: int) {
 	n1 := len(b.buf)
 	return n1-n0
 }
-
 /*
-	appends a slice of bytes to the builder, returns the append diff
+Appends a slice of bytes to the Builder and returns the number of bytes appended
+
+Inputs:
+- b: A pointer to the Builder
+- x: The slice of bytes to be appended
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
 
-	builder := strings.builder_make()
-	bytes := [?]byte { 'a', 'b', 'c' }
-	strings.write_bytes(&builder, bytes[:]) // 3
-	fmt.println(strings.to_string(builder)) // -> abc
+	write_bytes_example :: proc() {
+		builder := strings.builder_make()
+		bytes := [?]byte { 'a', 'b', 'c' }
+		strings.write_bytes(&builder, bytes[:]) // 3
+		fmt.println(strings.to_string(builder)) // -> abc
+	}
+
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
+
+Returns:
+The number of bytes appended
 */
 write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) {
 	n0 := len(b.buf)
@@ -199,42 +372,99 @@ write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) {
 	n1 := len(b.buf)
 	return n1-n0
 }
-
 /*
-	appends a single rune into the builder, returns written rune size and an `io.Error`
+Appends a single rune to the Builder and returns the number of bytes written and an `io.Error`
+
+Inputs:
+- b: A pointer to the Builder
+- r: The rune to be appended
+
+Returns:
+The number of bytes written and an io.Error (if any)
+
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	write_rune_example :: proc() {
+		builder := strings.builder_make()
+		strings.write_rune(&builder, 'ä')     // 2 None
+		strings.write_rune(&builder, 'b')       // 1 None
+		fmt.println(strings.to_string(builder)) // -> äb
+	}
+
+Output:
+
+	äb
 
-	builder := strings.builder_make()
-	strings.write_rune(&builder, 'ä') // 2 None
-	strings.write_rune(&builder, 'b') // 1 None
-	strings.write_rune(&builder, 'c') // 1 None
-	fmt.println(strings.to_string(builder)) // -> äbc
 */
 write_rune :: proc(b: ^Builder, r: rune) -> (int, io.Error) {
 	return io.write_rune(to_writer(b), r)
 }
-
 /*
-	appends a quoted rune into the builder, returns written size
+Appends a quoted rune to the Builder and returns the number of bytes written
+
+Inputs:
+- b: A pointer to the Builder
+- r: The rune to be appended
+
+Returns:
+The number of bytes written
+
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	write_quoted_rune_example :: proc() {
+		builder := strings.builder_make()
+		strings.write_string(&builder, "abc")      // 3
+		strings.write_quoted_rune(&builder, 'ä') // 4
+		strings.write_string(&builder, "abc")      // 3
+		fmt.println(strings.to_string(builder))    // -> abc'ä'abc
+	}
+
+Output:
+
+	abc'ä'abc
 
-	builder := strings.builder_make()
-	strings.write_string(&builder, "abc") // 3
-	strings.write_quoted_rune(&builder, 'ä') // 4
-	strings.write_string(&builder, "abc") // 3
-	fmt.println(strings.to_string(builder)) // -> abc'ä'abc
 */
 write_quoted_rune :: proc(b: ^Builder, r: rune) -> (n: int) {
 	return io.write_quoted_rune(to_writer(b), r)
 }
+/*
+Appends a string to the Builder and returns the number of bytes written
 
+Inputs:
+- b: A pointer to the Builder
+- s: The string to be appended
+
+Returns:
+The number of bytes written
+
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	write_string_example :: proc() {
+		builder := strings.builder_make()
+		strings.write_string(&builder, "a")     // 1
+		strings.write_string(&builder, "bc")    // 2
+		fmt.println(strings.to_string(builder)) // -> abc
+	}
+
+Output:
+
+	abc
 
-/*
-	appends a string to the builder, return the written byte size
-	
-	builder := strings.builder_make()
-	strings.write_string(&builder, "a") // 1
-	strings.write_string(&builder, "bc") // 2	
-	strings.write_string(&builder, "xyz") // 3
-	fmt.println(strings.to_string(builder)) // -> abcxyz
 */
 write_string :: proc(b: ^Builder, s: string) -> (n: int) {
 	n0 := len(b.buf)
@@ -242,10 +472,15 @@ write_string :: proc(b: ^Builder, s: string) -> (n: int) {
 	n1 := len(b.buf)
 	return n1-n0
 }
+/*
+Pops and returns the last byte in the Builder or 0 when the Builder is empty
 
+Inputs:
+- b: A pointer to the Builder
 
-// pops and returns the last byte in the builder
-// returns 0 when the builder is empty
+Returns:
+The last byte in the Builder or 0 if empty
+*/
 pop_byte :: proc(b: ^Builder) -> (r: byte) {
 	if len(b.buf) == 0 {
 		return 0
@@ -256,9 +491,15 @@ pop_byte :: proc(b: ^Builder) -> (r: byte) {
 	d.len = max(d.len-1, 0)
 	return
 }
+/*
+Pops the last rune in the Builder and returns the popped rune and its rune width or (0, 0) if empty
+
+Inputs:
+- b: A pointer to the Builder
 
-// pops the last rune in the builder and returns the popped rune and its rune width
-// returns 0, 0 when the builder is empty
+Returns:
+The popped rune and its rune width or (0, 0) if empty
+*/
 pop_rune :: proc(b: ^Builder) -> (r: rune, width: int) {
 	if len(b.buf) == 0 {
 		return 0, 0
@@ -269,41 +510,116 @@ pop_rune :: proc(b: ^Builder) -> (r: rune, width: int) {
 	d.len = max(d.len-width, 0)
 	return
 }
-
 @(private)
 DIGITS_LOWER := "0123456789abcdefx"
-
 /*
-	append a quoted string into the builder, return the written byte size
+Inputs:
+- b: A pointer to the Builder
+- str: The string to be quoted and appended
+- quote: The optional quote character (default is double quotes)
+
+Returns:
+The number of bytes written
+
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	write_quoted_string_example :: proc() {
+		builder := strings.builder_make()
+		strings.write_quoted_string(&builder, "a")        // 3
+		strings.write_quoted_string(&builder, "bc", '\'') // 4
+		strings.write_quoted_string(&builder, "xyz")      // 5
+		fmt.println(strings.to_string(builder))
+	}
+
+Output:
+
+	"a"'bc'"xyz"
 
-	builder := strings.builder_make()
-	strings.write_quoted_string(&builder, "a") // 3
-	strings.write_quoted_string(&builder, "bc", '\'') // 4	
-	strings.write_quoted_string(&builder, "xyz") // 5
-	fmt.println(strings.to_string(builder)) // -> "a"'bc'xyz"
 */
 write_quoted_string :: proc(b: ^Builder, str: string, quote: byte = '"') -> (n: int) {
 	n, _ = io.write_quoted_string(to_writer(b), str, quote)
 	return
 }
+/*
+Appends a rune to the Builder and returns the number of bytes written
+
+Inputs:
+- b: A pointer to the Builder
+- r: The rune to be appended
+- write_quote: Optional boolean flag to wrap in single-quotes (') (default is true)
+
+Returns:
+The number of bytes written
+
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	write_encoded_rune_example :: proc() {
+		builder := strings.builder_make()
+		strings.write_encoded_rune(&builder, 'a', false) // 1
+		strings.write_encoded_rune(&builder, '\"', true) // 3
+		strings.write_encoded_rune(&builder, 'x', false) // 1
+		fmt.println(strings.to_string(builder))
+	}
 
+Output:
 
-// appends a rune to the builder, optional `write_quote` boolean tag, returns the written rune size
+	a'"'x
+
+*/
 write_encoded_rune :: proc(b: ^Builder, r: rune, write_quote := true) -> (n: int) {
 	n, _ = io.write_encoded_rune(to_writer(b), r, write_quote)
 	return
 
 }
+/*
+Appends an escaped rune to the Builder and returns the number of bytes written
+
+Inputs:
+- b: A pointer to the Builder
+- r: The rune to be appended
+- quote: The quote character
+- html_safe: Optional boolean flag to encode '<', '>', '&' as digits (default is false)
+
+**Usage**
+- '\a' will be written as such
+- `r` and `quote` match and `quote` is `\\` - they will be written as two slashes
+- `html_safe` flag in case the runes '<', '>', '&' should be encoded as digits e.g. `\u0026`
+
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
 
-// appends a rune to the builder, fully written out in case of escaped runes e.g. '\a' will be written as such
-// when `r` and `quote` match and `quote` is `\\` - they will be written as two slashes
-// `html_safe` flag in case the runes '<', '>', '&' should be encoded as digits e.g. `\u0026`
+Returns:
+The number of bytes written
+*/
 write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) -> (n: int) {
 	n, _ = io.write_escaped_rune(to_writer(b), r, quote, html_safe)
 	return
 }
+/*
+Writes a f64 value to the Builder and returns the number of characters written
+
+Inputs:
+- b: A pointer to the Builder
+- f: The f64 value to be appended
+- fmt: The format byte
+- prec: The precision
+- bit_size: The bit size
+- always_signed: Optional boolean flag to always include the sign (default is false)
 
-// writes a f64 value into the builder, returns the written amount of characters
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
+
+Returns:
+The number of characters written
+*/
 write_float :: proc(b: ^Builder, f: f64, fmt: byte, prec, bit_size: int, always_signed := false) -> (n: int) {
 	buf: [384]byte
 	s := strconv.append_float(buf[:], f, fmt, prec, bit_size)
@@ -314,8 +630,20 @@ write_float :: proc(b: ^Builder, f: f64, fmt: byte, prec, bit_size: int, always_
 	}
 	return write_string(b, s)
 }
+/*
+Writes a f16 value to the Builder and returns the number of characters written
 
-// writes a f16 value into the builder, returns the written amount of characters
+Inputs:
+- b: A pointer to the Builder
+- f: The f16 value to be appended
+- fmt: The format byte
+- always_signed: Optional boolean flag to always include the sign
+
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
+
+Returns:
+The number of characters written
+*/
 write_f16 :: proc(b: ^Builder, f: f16, fmt: byte, always_signed := false) -> (n: int) {
 	buf: [384]byte
 	s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
@@ -324,8 +652,38 @@ write_f16 :: proc(b: ^Builder, f: f16, fmt: byte, always_signed := false) -> (n:
 	}
 	return write_string(b, s)
 }
+/*
+Writes a f32 value to the Builder and returns the number of characters written
+
+Inputs:
+- b: A pointer to the Builder
+- f: The f32 value to be appended
+- fmt: The format byte
+- always_signed: Optional boolean flag to always include the sign
+
+Returns:
+The number of characters written
+
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	write_f32_example :: proc() {
+		builder := strings.builder_make()
+		strings.write_f32(&builder, 3.14159, 'f') // 6
+		strings.write_string(&builder, " - ")     // 3
+		strings.write_f32(&builder, -0.123, 'e')  // 8
+		fmt.println(strings.to_string(builder))   // -> 3.14159012 - -1.23000003e-01
+	}
 
-// writes a f32 value into the builder, returns the written amount of characters
+Output:
+
+	3.14159012 - -1.23000003e-01
+
+*/
 write_f32 :: proc(b: ^Builder, f: f32, fmt: byte, always_signed := false) -> (n: int) {
 	buf: [384]byte
 	s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
@@ -334,8 +692,20 @@ write_f32 :: proc(b: ^Builder, f: f32, fmt: byte, always_signed := false) -> (n:
 	}
 	return write_string(b, s)
 }
+/*
+Writes a f32 value to the Builder and returns the number of characters written
+
+Inputs:
+- b: A pointer to the Builder
+- f: The f32 value to be appended
+- fmt: The format byte
+- always_signed: Optional boolean flag to always include the sign
+
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
 
-// writes a f64 value into the builder, returns the written amount of characters
+Returns:
+The number of characters written
+*/
 write_f64 :: proc(b: ^Builder, f: f64, fmt: byte, always_signed := false) -> (n: int) {
 	buf: [384]byte
 	s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
@@ -344,30 +714,71 @@ write_f64 :: proc(b: ^Builder, f: f64, fmt: byte, always_signed := false) -> (n:
 	}
 	return write_string(b, s)
 }
+/*
+Writes a u64 value to the Builder and returns the number of characters written
 
+Inputs:
+- b: A pointer to the Builder
+- i: The u64 value to be appended
+- base: The optional base for the numeric representation
 
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
 
-// writes a u64 value `i` in `base` = 10 into the builder, returns the written amount of characters
+Returns:
+The number of characters written
+*/
 write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) {
 	buf: [32]byte
 	s := strconv.append_bits(buf[:], i, base, false, 64, strconv.digits, nil)
 	return write_string(b, s)
 }
+/*
+Writes a i64 value to the Builder and returns the number of characters written
+
+Inputs:
+- b: A pointer to the Builder
+- i: The i64 value to be appended
+- base: The optional base for the numeric representation
 
-// writes a i64 value `i` in `base` = 10 into the builder, returns the written amount of characters
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
+
+Returns:
+The number of characters written
+*/
 write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) -> (n: int) {
 	buf: [32]byte
 	s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil)
 	return write_string(b, s)
 }
+/*
+Writes a uint value to the Builder and returns the number of characters written
 
-// writes a uint value `i` in `base` = 10 into the builder, returns the written amount of characters
+Inputs:
+- b: A pointer to the Builder
+- i: The uint value to be appended
+- base: The optional base for the numeric representation
+
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
+
+Returns:
+The number of characters written
+*/
 write_uint :: proc(b: ^Builder, i: uint, base: int = 10) -> (n: int) {
 	return write_u64(b, u64(i), base)
 }
+/*
+Writes a int value to the Builder and returns the number of characters written
+
+Inputs:
+- b: A pointer to the Builder
+- i: The int value to be appended
+- base: The optional base for the numeric representation
+
+NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` states the number actually written.
 
-// writes a int value `i` in `base` = 10 into the builder, returns the written amount of characters
+Returns:
+The number of characters written
+*/
 write_int :: proc(b: ^Builder, i: int, base: int = 10) -> (n: int) {
 	return write_i64(b, i64(i), base)
 }
-

+ 322 - 75
core/strings/conversion.odin

@@ -4,6 +4,21 @@ import "core:io"
 import "core:unicode"
 import "core:unicode/utf8"
 
+/*
+Converts invalid UTF-8 sequences in the input string `s` to the `replacement` string.
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- s: Input string that may contain invalid UTF-8 sequences.
+- replacement: String to replace invalid UTF-8 sequences with.
+- allocator: (default: context.allocator).
+
+WARNING: Allocation does not occur when len(s) == 0
+
+Returns:
+A valid UTF-8 string with invalid sequences replaced by `replacement`.
+*/
 to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) -> string {
 	if len(s) == 0 {
 		return ""
@@ -33,7 +48,7 @@ to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) ->
 
 	invalid := false
 
-	for i := 0; i < len(s); /**/ {
+	for i := 0; i < len(s);  /**/{
 		c := s[i]
 		if c < utf8.RUNE_SELF {
 			i += 1
@@ -57,13 +72,31 @@ to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) ->
 	}
 	return to_string(b)
 }
-
 /*
-	returns the input string `s` with all runes set to lowered case
-	always allocates using the `allocator`
+Converts the input string `s` to all lowercase characters.
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- s: Input string to be converted.
+- allocator: (default: context.allocator).
+
+Returns:
+A new string with all characters converted to lowercase.
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	to_lower_example :: proc() {
+		fmt.println(strings.to_lower("TeST"))
+	}
+
+Output:
+
+	test
 
-	strings.to_lower("test") -> test	
-	strings.to_lower("Test") -> test	
 */
 to_lower :: proc(s: string, allocator := context.allocator) -> string {
 	b: Builder
@@ -73,13 +106,31 @@ to_lower :: proc(s: string, allocator := context.allocator) -> string {
 	}
 	return to_string(b)
 }
-
 /*
-	returns the input string `s` with all runes set to upper case
-	always allocates using the `allocator`
+Converts the input string `s` to all uppercase characters.
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- s: Input string to be converted.
+- allocator: (default: context.allocator).
+
+Returns:
+A new string with all characters converted to uppercase.
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	to_upper_example :: proc() {
+		fmt.println(strings.to_upper("Test"))
+	}
+
+Output:
+
+	TEST
 
-	strings.to_upper("test") -> TEST
-	strings.to_upper("Test") -> TEST
 */
 to_upper :: proc(s: string, allocator := context.allocator) -> string {
 	b: Builder
@@ -89,21 +140,38 @@ to_upper :: proc(s: string, allocator := context.allocator) -> string {
 	}
 	return to_string(b)
 }
+/*
+Checks if the rune `r` is a delimiter (' ', '-', or '_').
+
+Inputs:
+- r: Rune to check for delimiter status.
 
-// returns true when the `c` rune is a space, '-' or '_' 
-// useful when treating strings like words in a text editor or html paths 
-is_delimiter :: proc(c: rune) -> bool {
-	return c == '-' || c == '_' || is_space(c)
+Returns:
+True if `r` is a delimiter, false otherwise.
+*/
+is_delimiter :: proc(r: rune) -> bool {
+	return r == '-' || r == '_' || is_space(r)
 }
+/*
+Checks if the rune `r` is a non-alphanumeric or space character.
+
+Inputs:
+- r: Rune to check for separator status.
 
-// returns true when the `r` rune is a non alpha or `unicode.is_space` rune
+Returns:
+True if `r` is a non-alpha or `unicode.is_space` rune.
+*/
 is_separator :: proc(r: rune) -> bool {
 	if r <= 0x7f {
 		switch r {
-		case '0'..='9': return false
-		case 'a'..='z': return false
-		case 'A'..='Z': return false
-		case '_': return false
+		case '0' ..= '9':
+			return false
+		case 'a' ..= 'z':
+			return false
+		case 'A' ..= 'Z':
+			return false
+		case '_':
+			return false
 		}
 		return true
 	}
@@ -115,12 +183,46 @@ is_separator :: proc(r: rune) -> bool {
 
 	return unicode.is_space(r)
 }
-
 /*
-	iterator that loops through the string and calls the callback with the `prev`, `curr` and `next` rune
-	on empty string `s` the callback gets called once with empty runes
+Iterates over a string, calling a callback for each rune with the previous, current, and next runes as arguments.
+
+Inputs:
+- w: An io.Writer to be used by the callback for writing output.
+- s: The input string to be iterated over.
+- callback: A procedure to be called for each rune in the string, with arguments (w: io.Writer, prev, curr, next: rune).
+The callback can utilize the provided io.Writer to write output during the iteration.
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+	import "core:io"
+
+	string_case_iterator_example :: proc() {
+		my_callback :: proc(w: io.Writer, prev, curr, next: rune) {
+			fmt.println("my_callback", curr) // <-- Custom logic here
+		}
+		s := "hello"
+		b: strings.Builder
+		strings.builder_init_len(&b, len(s))
+		w := strings.to_writer(&b)
+		strings.string_case_iterator(w, s, my_callback)
+	}
+
+Output:
+
+	my_callback h
+	my_callback e
+	my_callback l
+	my_callback l
+	my_callback o
+
 */
-string_case_iterator :: proc(w: io.Writer, s: string, callback: proc(w: io.Writer, prev, curr, next: rune)) {
+string_case_iterator :: proc(
+	w: io.Writer,
+	s: string,
+	callback: proc(w: io.Writer, prev, curr, next: rune),
+) {
 	prev, curr: rune
 	for next in s {
 		if curr == 0 {
@@ -139,10 +241,20 @@ string_case_iterator :: proc(w: io.Writer, s: string, callback: proc(w: io.Write
 		callback(w, prev, curr, 0)
 	}
 }
-
+// Alias to `to_camel_case`
 to_lower_camel_case :: to_camel_case
+/*
+Converts the input string `s` to "lowerCamelCase".
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- s: Input string to be converted.
+- allocator: (default: context.allocator).
 
-// converts the `s` string to "lowerCamelCase"
+Returns:
+A "lowerCamelCase" formatted string.
+*/
 to_camel_case :: proc(s: string, allocator := context.allocator) -> string {
 	s := s
 	s = trim_space(s)
@@ -164,10 +276,20 @@ to_camel_case :: proc(s: string, allocator := context.allocator) -> string {
 
 	return to_string(b)
 }
-
+// Alias to `to_pascal_case`
 to_upper_camel_case :: to_pascal_case
+/*
+Converts the input string `s` to "UpperCamelCase" (PascalCase).
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- s: Input string to be converted.
+- allocator: (default: context.allocator).
 
-// converts the `s` string to "PascalCase"
+Returns:
+A "PascalCase" formatted string.
+*/
 to_pascal_case :: proc(s: string, allocator := context.allocator) -> string {
 	s := s
 	s = trim_space(s)
@@ -189,17 +311,44 @@ to_pascal_case :: proc(s: string, allocator := context.allocator) -> string {
 
 	return to_string(b)
 }
+/*
+Returns a string converted to a delimiter-separated case with configurable casing
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- s: The input string to be converted
+- delimiter: The rune to be used as the delimiter between words
+- all_upper_case: A boolean indicating if the output should be all uppercased (true) or lowercased (false)
+- allocator: (default: context.allocator).
 
-/* 
-	returns the `s` string to words seperated by the given `delimiter` rune
-	all runes will be upper or lowercased based on the `all_uppercase` bool
+Returns:
+The converted string
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	to_delimiter_case_example :: proc() {
+		fmt.println(strings.to_delimiter_case("Hello World", '_', false))
+		fmt.println(strings.to_delimiter_case("Hello World", ' ', true))
+		fmt.println(strings.to_delimiter_case("aBC", '_', false))
+	}
+
+Output:
+
+	hello_world
+	HELLO WORLD
+	a_bc
 
-	strings.to_delimiter_case("Hello World", '_', false) -> hello_world
-	strings.to_delimiter_case("Hello World", ' ', true) -> HELLO WORLD
-	strings.to_delimiter_case("Hello World", ' ', true) -> HELLO WORLD
-	strings.to_delimiter_case("aBC", '_', false) -> a_b_c
 */
-to_delimiter_case :: proc(s: string, delimiter: rune, all_upper_case: bool, allocator := context.allocator) -> string {
+to_delimiter_case :: proc(
+	s: string,
+	delimiter: rune,
+	all_upper_case: bool,
+	allocator := context.allocator,
+) -> string {
 	s := s
 	s = trim_space(s)
 	b: Builder
@@ -237,73 +386,171 @@ to_delimiter_case :: proc(s: string, delimiter: rune, all_upper_case: bool, allo
 
 	return to_string(b)
 }
+/*
+Converts a string to "snake_case" with all runes lowercased
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- s: The input string to be converted
+- allocator: (default: context.allocator).
+
+Returns:
+The converted string
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	to_snake_case_example :: proc() {
+		fmt.println(strings.to_snake_case("HelloWorld"))
+		fmt.println(strings.to_snake_case("Hello World"))
+	}
+
+Output:
+
+	hello_world
+	hello_world
 
-/* 
-	converts the `s` string to "snake_case" with all runes lowercased
-	
-	strings.to_snake_case("HelloWorld") -> hello_world
-	strings.to_snake_case("Hello World") -> hello_world
 */
 to_snake_case :: proc(s: string, allocator := context.allocator) -> string {
 	return to_delimiter_case(s, '_', false, allocator)
 }
-
+// Alias for `to_upper_snake_case`
 to_screaming_snake_case :: to_upper_snake_case
+/*
+Converts a string to "SNAKE_CASE" with all runes uppercased
 
-// converts the `s` string to "SNAKE_CASE" with all runes uppercased
+*Allocates Using Provided Allocator*
+
+Inputs:
+- s: The input string to be converted
+- allocator: (default: context.allocator).
+
+Returns:
+The converted string
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	to_upper_snake_case_example :: proc() {
+		fmt.println(strings.to_upper_snake_case("HelloWorld"))
+	}
+
+Output:
+
+	HELLO_WORLD
+
+*/
 to_upper_snake_case :: proc(s: string, allocator := context.allocator) -> string {
 	return to_delimiter_case(s, '_', true, allocator)
 }
+/*
+Converts a string to "kebab-case" with all runes lowercased
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- s: The input string to be converted
+- allocator: (default: context.allocator).
+
+Returns:
+The converted string
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	to_kebab_case_example :: proc() {
+		fmt.println(strings.to_kebab_case("HelloWorld"))
+	}
 
-// converts the `s` string to "kebab-case" with all runes lowercased
+Output:
+
+	hello-world
+
+*/
 to_kebab_case :: proc(s: string, allocator := context.allocator) -> string {
 	return to_delimiter_case(s, '-', false, allocator)
 }
+/*
+Converts a string to "KEBAB-CASE" with all runes uppercased
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- s: The input string to be converted
+- allocator: (default: context.allocator).
+
+Returns:
+The converted string
+
+Example:
+
+	import "core:fmt"
+	import "core:strings"
 
-// converts the `s` string to "KEBAB-CASE" with all runes uppercased
+	to_upper_kebab_case_example :: proc() {
+		fmt.println(strings.to_upper_kebab_case("HelloWorld"))
+	}
+
+Output:
+
+	HELLO-WORLD
+
+*/
 to_upper_kebab_case :: proc(s: string, allocator := context.allocator) -> string {
 	return to_delimiter_case(s, '-', true, allocator)
 }
+/*
+Converts a string to "Ada_Case"
 
-// converts the `s` string to "Ada_case"
-to_ada_case :: proc(s: string, allocator := context.allocator) -> string {
-	delimiter :: '_'
+*Allocates Using Provided Allocator*
+
+Inputs:
+- s: The input string to be converted
+- allocator: (default: context.allocator).
+
+Returns:
+The converted string
 
+Example:
+
+	import "core:fmt"
+	import "core:strings"
+
+	to_ada_case_example :: proc() {
+		fmt.println(strings.to_ada_case("HelloWorld"))
+	}
+
+Output:
+
+	Hello_World
+
+*/
+to_ada_case :: proc(s: string, allocator := context.allocator) -> string {
 	s := s
 	s = trim_space(s)
 	b: Builder
 	builder_init(&b, 0, len(s), allocator)
 	w := to_writer(&b)
 
-	prev, curr: rune
-
-	for next in s {
-		if is_delimiter(curr) {
-			if !is_delimiter(prev) {
-				io.write_rune(w, delimiter)
-			}
-		} else if unicode.is_upper(curr) {
-			if unicode.is_lower(prev) || (unicode.is_upper(prev) && unicode.is_lower(next)) {
-				io.write_rune(w, delimiter)
+	string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) {
+		if !is_delimiter(curr) {
+			if is_delimiter(prev) || prev == 0 || (unicode.is_lower(prev) && unicode.is_upper(curr)) {
+				if prev != 0 {
+					io.write_rune(w, '_')
+				}
+				io.write_rune(w, unicode.to_upper(curr))
+			} else {
+				io.write_rune(w, unicode.to_lower(curr))
 			}
-			io.write_rune(w, unicode.to_upper(curr))
-		} else if curr != 0 {
-			io.write_rune(w, unicode.to_lower(curr))
-		}
-
-		prev = curr
-		curr = next
-	}
-
-	if len(s) > 0 {
-		if unicode.is_upper(curr) && unicode.is_lower(prev) && prev != 0 {
-			io.write_rune(w, delimiter)
-			io.write_rune(w, unicode.to_upper(curr))
-		} else {
-			io.write_rune(w, unicode.to_lower(curr))
 		}
-	}
+	})
 
 	return to_string(b)
 }
-

+ 61 - 11
core/strings/intern.odin

@@ -2,49 +2,99 @@ package strings
 
 import "core:runtime"
 
-// custom string entry struct
+// Custom string entry struct
 Intern_Entry :: struct {
 	len:  int,
 	str:  [1]byte, // string is allocated inline with the entry to keep allocations simple
 }
+/*
+Intern is a more memory efficient string map
 
-// "intern" is a more memory efficient string map
-// `allocator` is used to allocate the actual `Intern_Entry` strings
+Uses Specified Allocator for `Intern_Entry` strings
+
+Fields:
+- allocator: The allocator used for the Intern_Entry strings
+- entries: A map of strings to interned string entries
+*/
 Intern :: struct {
 	allocator: runtime.Allocator,
 	entries: map[string]^Intern_Entry,
 }
+/*
+Initializes the entries map and sets the allocator for the string entries
+
+*Allocates Using Provided Allocators*
 
-// initialize the entries map and set the allocator for the string entries
+Inputs:
+- m: A pointer to the Intern struct to be initialized
+- allocator: The allocator for the Intern_Entry strings (Default: context.allocator)
+- map_allocator: The allocator for the map of entries (Default: context.allocator)
+*/
 intern_init :: proc(m: ^Intern, allocator := context.allocator, map_allocator := context.allocator) {
 	m.allocator = allocator
 	m.entries = make(map[string]^Intern_Entry, 16, map_allocator)
 }
+/*
+Frees the map and all its content allocated using the `.allocator`.
 
-// free the map and all its content allocated using the `.allocator`
+Inputs:
+- m: A pointer to the Intern struct to be destroyed
+*/
 intern_destroy :: proc(m: ^Intern) {
 	for _, value in m.entries {
 		free(value, m.allocator)
 	}
 	delete(m.entries)
 }
+/*
+Returns an interned copy of the given text, adding it to the map if not already present.
+
+*Allocate using the Intern's Allocator (First time string is seen only)*
+
+Inputs:
+- m: A pointer to the Intern struct
+- text: The string to be interned
+
+NOTE: The returned string lives as long as the map entry lives.
 
-// returns the `text` string from the intern map - gets set if it didnt exist yet
-// the returned string lives as long as the map entry lives
+Returns:
+The interned string and an allocator error if any
+*/
 intern_get :: proc(m: ^Intern, text: string) -> (str: string, err: runtime.Allocator_Error) {
 	entry := _intern_get_entry(m, text) or_return
 	#no_bounds_check return string(entry.str[:entry.len]), nil
 }
+/*
+Returns an interned copy of the given text as a cstring, adding it to the map if not already present.
 
-// returns the `text` cstring from the intern map - gets set if it didnt exist yet
-// the returned cstring lives as long as the map entry lives
+*Allocate using the Intern's Allocator  (First time string is seen only)*
+
+Inputs:
+- m: A pointer to the Intern struct
+- text: The string to be interned
+
+NOTE: The returned cstring lives as long as the map entry lives
+
+Returns:
+The interned cstring and an allocator error if any
+*/
 intern_get_cstring :: proc(m: ^Intern, text: string) -> (str: cstring, err: runtime.Allocator_Error) {
 	entry := _intern_get_entry(m, text) or_return
 	return cstring(&entry.str[0]), nil
 }
+/*
+Internal function to lookup whether the text string exists in the map, returns the entry
+Sets and allocates the entry if it wasn't set yet
+
+*Allocate using the Intern's Allocator  (First time string is seen only)*
+
+Inputs:
+- m: A pointer to the Intern struct
+- text: The string to be looked up or interned
 
-// looks up wether the `text` string exists in the map, returns the entry
-// sets & allocates the entry if it wasnt set yet
+Returns:
+The new or existing interned entry and an allocator error if any
+*/
 _intern_get_entry :: proc(m: ^Intern, text: string) -> (new_entry: ^Intern_Entry, err: runtime.Allocator_Error) #no_bounds_check {
 	if prev, ok := m.entries[text]; ok {
 		return prev, nil

+ 139 - 22
core/strings/reader.odin

@@ -4,59 +4,109 @@ import "core:io"
 import "core:unicode/utf8"
 
 /*
-	io stream data for a string reader that can read based on bytes or runes
-	implements the vtable when using the io.Reader variants
-	"read" calls advance the current reading offset `i`
+io stream data for a string reader that can read based on bytes or runes
+implements the vtable when using the `io.Reader` variants
+"read" calls advance the current reading offset `i`
 */
 Reader :: struct {
 	s:         string, // read-only buffer
 	i:         i64,    // current reading index
 	prev_rune: int,    // previous reading index of rune or < 0
 }
+/*
+Initializes a string Reader with the provided string
 
-// init the reader to the string `s` 
+Inputs:
+- r: A pointer to a Reader struct
+- s: The input string to be read
+*/
 reader_init :: proc(r: ^Reader, s: string) {
 	r.s = s
 	r.i = 0
 	r.prev_rune = -1
 }
+/*
+Converts a Reader into an `io.Stream`
 
-// returns a stream from the reader data
+Inputs:
+- r: A pointer to a Reader struct
+
+Returns:
+An io.Stream for the given Reader
+*/
 reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) {
 	s.stream_data = r
 	s.stream_vtable = &_reader_vtable
 	return
 }
+/*
+Initializes a string Reader and returns an `io.Reader` for the given string
 
-// init a reader to the string `s` and return an io.Reader
+Inputs:
+- r: A pointer to a Reader struct
+- s: The input string to be read
+
+Returns:
+An io.Reader for the given string
+*/
 to_reader :: proc(r: ^Reader, s: string) -> io.Reader {
 	reader_init(r, s)
 	rr, _ := io.to_reader(reader_to_stream(r))
 	return rr
 }
+/*
+Initializes a string Reader and returns an `io.Reader_At` for the given string
 
-// init a reader to the string `s` and return an io.Reader_At
+Inputs:
+- r: A pointer to a Reader struct
+- s: The input string to be read
+
+Returns:
+An `io.Reader_At` for the given string
+*/
 to_reader_at :: proc(r: ^Reader, s: string) -> io.Reader_At {
 	reader_init(r, s)
 	rr, _ := io.to_reader_at(reader_to_stream(r))
 	return rr
 }
+/*
+Returns the remaining length of the Reader
 
-// remaining length of the reader 
+Inputs:
+- r: A pointer to a Reader struct
+
+Returns:
+The remaining length of the Reader
+*/
 reader_length :: proc(r: ^Reader) -> int {
 	if r.i >= i64(len(r.s)) {
 		return 0
 	}
 	return int(i64(len(r.s)) - r.i)
 }
+/*
+Returns the length of the string stored in the Reader
 
-// returns the string length stored by the reader
+Inputs:
+- r: A pointer to a Reader struct
+
+Returns:
+The length of the string stored in the Reader
+*/
 reader_size :: proc(r: ^Reader) -> i64 {
 	return i64(len(r.s))
 }
+/*
+Reads len(p) bytes from the Reader's string and copies into the provided slice.
 
-// reads len(p) bytes into the slice from the string in the reader
-// returns `n` amount of read bytes and an io.Error
+Inputs:
+- r: A pointer to a Reader struct
+- p: A byte slice to copy data into
+
+Returns:
+- n: The number of bytes read
+- err: An `io.Error` if an error occurs while reading, including `.EOF`, otherwise `nil` denotes success.
+*/
 reader_read :: proc(r: ^Reader, p: []byte) -> (n: int, err: io.Error) {
 	if r.i >= i64(len(r.s)) {
 		return 0, .EOF
@@ -66,9 +116,18 @@ reader_read :: proc(r: ^Reader, p: []byte) -> (n: int, err: io.Error) {
 	r.i += i64(n)
 	return
 }
+/*
+Reads len(p) bytes from the Reader's string and copies into the provided slice, at the specified offset from the current index.
 
-// reads len(p) bytes into the slice from the string in the reader at an offset
-// returns `n` amount of read bytes and an io.Error
+Inputs:
+- r: A pointer to a Reader struct
+- p: A byte slice to copy data into
+- off: The offset from which to read
+
+Returns:
+- n: The number of bytes read
+- err: An `io.Error` if an error occurs while reading, including `.EOF`, otherwise `nil` denotes success.
+*/
 reader_read_at :: proc(r: ^Reader, p: []byte, off: i64) -> (n: int, err: io.Error) {
 	if off < 0 {
 		return 0, .Invalid_Offset
@@ -82,8 +141,16 @@ reader_read_at :: proc(r: ^Reader, p: []byte, off: i64) -> (n: int, err: io.Erro
 	}
 	return
 }
+/*
+Reads and returns a single byte from the Reader's string
+
+Inputs:
+- r: A pointer to a Reader struct
 
-// reads and returns a single byte - error when out of bounds
+Returns:
+- The byte read from the Reader
+- err: An `io.Error` if an error occurs while reading, including `.EOF`, otherwise `nil` denotes success.
+*/
 reader_read_byte :: proc(r: ^Reader) -> (byte, io.Error) {
 	r.prev_rune = -1
 	if r.i >= i64(len(r.s)) {
@@ -93,8 +160,15 @@ reader_read_byte :: proc(r: ^Reader) -> (byte, io.Error) {
 	r.i += 1
 	return b, nil
 }
+/*
+Decrements the Reader's index (i) by 1
+
+Inputs:
+- r: A pointer to a Reader struct
 
-// decreases the reader offset - error when below 0
+Returns:
+An `io.Error` if `r.i <= 0` (`.Invalid_Unread`), otherwise `nil` denotes success.
+*/
 reader_unread_byte :: proc(r: ^Reader) -> io.Error {
 	if r.i <= 0 {
 		return .Invalid_Unread
@@ -103,9 +177,18 @@ reader_unread_byte :: proc(r: ^Reader) -> io.Error {
 	r.i -= 1
 	return nil
 }
+/*
+Reads and returns a single rune and its `size` from the Reader's string
+
+Inputs:
+- r: A pointer to a Reader struct
 
-// reads and returns a single rune and the rune size - error when out bounds
-reader_read_rune :: proc(r: ^Reader) -> (ch: rune, size: int, err: io.Error) {
+Returns:
+- rr: The rune read from the Reader
+- size: The size of the rune in bytes
+- err: An `io.Error` if an error occurs while reading
+*/
+reader_read_rune :: proc(r: ^Reader) -> (rr: rune, size: int, err: io.Error) {
 	if r.i >= i64(len(r.s)) {
 		r.prev_rune = -1
 		return 0, 0, .EOF
@@ -115,13 +198,21 @@ reader_read_rune :: proc(r: ^Reader) -> (ch: rune, size: int, err: io.Error) {
 		r.i += 1
 		return rune(c), 1, nil
 	}
-	ch, size = utf8.decode_rune_in_string(r.s[r.i:])
+	rr, size = utf8.decode_rune_in_string(r.s[r.i:])
 	r.i += i64(size)
 	return
 }
+/*
+Decrements the Reader's index (i) by the size of the last read rune
+
+Inputs:
+- r: A pointer to a Reader struct
 
-// decreases the reader offset by the last rune
-// can only be used once and after a valid read_rune call
+WARNING: May only be used once and after a valid `read_rune` call
+
+Returns:
+An `io.Error` if an error occurs while unreading (`.Invalid_Unread`), else `nil` denotes success.
+*/
 reader_unread_rune :: proc(r: ^Reader) -> io.Error {
 	if r.i <= 0 {
 		return .Invalid_Unread
@@ -133,8 +224,18 @@ reader_unread_rune :: proc(r: ^Reader) -> io.Error {
 	r.prev_rune = -1
 	return nil
 }
+/*
+Seeks the Reader's index to a new position
 
-// seeks the reader offset to a wanted offset 
+Inputs:
+- r: A pointer to a Reader struct
+- offset: The new offset position
+- whence: The reference point for the new position (`.Start`, `.Current`, or `.End`)
+
+Returns:
+- The absolute offset after seeking
+- err: An `io.Error` if an error occurs while seeking (`.Invalid_Whence`, `.Invalid_Offset`)
+*/
 reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.Error) {
 	r.prev_rune = -1
 	abs: i64
@@ -155,8 +256,19 @@ reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.E
 	r.i = abs
 	return abs, nil
 }
+/*
+Writes the remaining content of the Reader's string into the provided `io.Writer`
 
-// writes the string content left to read into the io.Writer `w`
+Inputs:
+- r: A pointer to a Reader struct
+- w: The io.Writer to write the remaining content into
+
+WARNING: Panics if writer writes more bytes than remainig length of string.
+
+Returns:
+- n: The number of bytes written
+- err: An io.Error if an error occurs while writing (`.Short_Write`)
+*/
 reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
 	r.prev_rune = -1
 	if r.i >= i64(len(r.s)) {
@@ -175,7 +287,12 @@ reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
 	}
 	return
 }
+/*
+VTable containing implementations for various `io.Stream` methods
 
+This VTable is used by the Reader struct to provide its functionality
+as an `io.Stream`.
+*/
 @(private)
 _reader_vtable := io.Stream_VTable{
 	impl_size = proc(s: io.Stream) -> i64 {

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 699 - 136
core/strings/strings.odin


+ 2 - 0
core/sys/windows/kernel32.odin

@@ -393,6 +393,8 @@ foreign kernel32 {
 	GetConsoleScreenBufferInfo :: proc(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: PCONSOLE_SCREEN_BUFFER_INFO) -> BOOL ---
 	SetConsoleScreenBufferSize :: proc(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL ---
 	SetConsoleWindowInfo :: proc(hConsoleOutput: HANDLE, bAbsolute : BOOL, lpConsoleWindow: ^SMALL_RECT) -> BOOL ---
+	GetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL ---
+	SetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL ---
 
 	GetDiskFreeSpaceExW :: proc(
 		lpDirectoryName: LPCWSTR,

+ 2 - 0
core/sys/windows/shell32.odin

@@ -23,6 +23,8 @@ foreign shell32 {
 	SHFileOperationW :: proc(lpFileOp: LPSHFILEOPSTRUCTW) -> c_int ---
 	SHGetFolderPathW :: proc(hwnd: HWND, csidl: c_int, hToken: HANDLE, dwFlags: DWORD, pszPath: LPWSTR) -> HRESULT ---
 	SHAppBarMessage :: proc(dwMessage: DWORD, pData: PAPPBARDATA) -> UINT_PTR --- 
+
+	Shell_NotifyIconW :: proc(dwMessage: DWORD, lpData: ^NOTIFYICONDATAW) -> BOOL ---
 }
 
 APPBARDATA :: struct {

+ 166 - 23
core/sys/windows/types.odin

@@ -145,8 +145,6 @@ PCONDITION_VARIABLE :: ^CONDITION_VARIABLE
 PLARGE_INTEGER :: ^LARGE_INTEGER
 PSRWLOCK :: ^SRWLOCK
 
-MMRESULT :: UINT
-
 CREATE_WAITABLE_TIMER_MANUAL_RESET    :: 0x00000001
 CREATE_WAITABLE_TIMER_HIGH_RESOLUTION :: 0x00000002
 
@@ -261,26 +259,6 @@ GET_FILEEX_INFO_LEVELS :: distinct i32
 GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0
 GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1
 
-// String resource number bases (internal use)
-
-MMSYSERR_BASE :: 0
-WAVERR_BASE   :: 32
-MIDIERR_BASE  :: 64
-TIMERR_BASE   :: 96
-JOYERR_BASE   :: 160
-MCIERR_BASE   :: 256
-MIXERR_BASE   :: 1024
-
-MCI_STRING_OFFSET :: 512
-MCI_VD_OFFSET     :: 1024
-MCI_CD_OFFSET     :: 1088
-MCI_WAVE_OFFSET   :: 1152
-MCI_SEQ_OFFSET    :: 1216
-
-// timer error return values
-TIMERR_NOERROR :: 0                // no error
-TIMERR_NOCANDO :: TIMERR_BASE + 1  // request not completed
-TIMERR_STRUCT  :: TIMERR_BASE + 33 // time struct size
 
 DIAGNOSTIC_REASON_VERSION :: 0
 
@@ -724,6 +702,14 @@ CWPRETSTRUCT :: struct {
 	hwnd: HWND,
 }
 
+MSLLHOOKSTRUCT :: struct {
+	pt: POINT,
+	mouseData: DWORD,
+	flags: DWORD,
+	time: DWORD,
+	dwExtraInfo: ULONG_PTR,
+}
+
 KBDLLHOOKSTRUCT :: struct {
 	vkCode: DWORD,
 	scanCode: DWORD,
@@ -732,6 +718,59 @@ KBDLLHOOKSTRUCT :: struct {
 	dwExtraInfo: ULONG_PTR,
 }
 
+MOUSEINPUT :: struct {
+	dx: LONG,
+	dy: LONG,
+	mouseData: DWORD,
+	dwFlags: DWORD,
+	time: DWORD,
+	dwExtraInfo: ULONG_PTR,
+}
+
+KEYBDINPUT :: struct {
+	wVk: WORD,
+	wScan: WORD,
+	dwFlags: DWORD,
+	time: DWORD,
+	dwExtraInfo: ULONG_PTR,
+}
+
+HARDWAREINPUT :: struct {
+	uMsg: DWORD,
+	wParamL: WORD,
+	wParamH: WORD,
+}
+
+INPUT_TYPE :: enum DWORD {
+	MOUSE = 0,
+	KEYBOARD = 1,
+	HARDWARE = 2,
+}
+
+INPUT :: struct {
+	type: INPUT_TYPE,
+	using _: struct #raw_union {
+		mi: MOUSEINPUT,
+		ki: KEYBDINPUT,
+		hi: HARDWAREINPUT,
+	},
+}
+
+MOUSEEVENTF_MOVE :: 0x0001
+MOUSEEVENTF_LEFTDOWN :: 0x0002
+MOUSEEVENTF_LEFTUP :: 0x0004
+MOUSEEVENTF_RIGHTDOWN :: 0x0008
+MOUSEEVENTF_RIGHTUP :: 0x0010
+MOUSEEVENTF_MIDDLEDOWN :: 0x0020
+MOUSEEVENTF_MIDDLEUP :: 0x0040
+MOUSEEVENTF_XDOWN :: 0x0080
+MOUSEEVENTF_XUP :: 0x0100
+MOUSEEVENTF_WHEEL :: 0x0800
+MOUSEEVENTF_HWHEEL :: 0x1000
+MOUSEEVENTF_MOVE_NOCOALESCE :: 0x2000
+MOUSEEVENTF_VIRTUALDESK :: 0x4000
+MOUSEEVENTF_ABSOLUTE :: 0x8000
+
 WNDCLASSA :: struct {
 	style: UINT,
 	lpfnWndProc: WNDPROC,
@@ -799,6 +838,104 @@ MSG :: struct {
 
 LPMSG :: ^MSG
 
+NOTIFYICONDATAW :: struct {
+	cbSize: DWORD,
+	hWnd: HWND,
+	uID: UINT,
+	uFlags: UINT,
+	uCallbackMessage: UINT,
+	hIcon: HICON,
+	szTip: [128]WCHAR,
+	dwState: DWORD,
+	dwStateMask: DWORD,
+	szInfo: [256]WCHAR,
+	using _: struct #raw_union {
+		uTimeout: UINT,
+		uVersion: UINT,
+	},
+	szInfoTitle: [64]WCHAR,
+	dwInfoFlags: DWORD,
+	guidItem: GUID,
+	hBalloonIcon: HICON,
+}
+
+NIF_MESSAGE :: 0x00000001
+NIF_ICON :: 0x00000002
+NIF_TIP :: 0x00000004
+NIF_STATE :: 0x00000008
+NIF_INFO :: 0x00000010
+NIF_GUID :: 0x00000020
+NIF_REALTIME :: 0x00000040
+NIF_SHOWTIP :: 0x00000080
+
+NIM_ADD :: 0x00000000
+NIM_MODIFY :: 0x00000001
+NIM_DELETE :: 0x00000002
+NIM_SETFOCUS :: 0x00000003
+NIM_SETVERSION :: 0x00000004
+
+// Menu flags for Add/Check/EnableMenuItem()
+MF_INSERT :: 0x00000000
+MF_CHANGE :: 0x00000080
+MF_APPEND :: 0x00000100
+MF_DELETE :: 0x00000200
+MF_REMOVE :: 0x00001000
+
+MF_BYCOMMAND :: 0x00000000
+MF_BYPOSITION :: 0x00000400
+
+MF_SEPARATOR :: 0x00000800
+
+MF_ENABLED :: 0x00000000
+MF_GRAYED :: 0x00000001
+MF_DISABLED :: 0x00000002
+
+MF_UNCHECKED :: 0x00000000
+MF_CHECKED :: 0x00000008
+MF_USECHECKBITMAPS :: 0x00000200
+
+MF_STRING :: 0x00000000
+MF_BITMAP :: 0x00000004
+MF_OWNERDRAW :: 0x00000100
+
+MF_POPUP :: 0x00000010
+MF_MENUBARBREAK :: 0x00000020
+MF_MENUBREAK :: 0x00000040
+
+MF_UNHILITE :: 0x00000000
+MF_HILITE :: 0x00000080
+
+MF_DEFAULT :: 0x00001000
+MF_SYSMENU :: 0x00002000
+MF_HELP :: 0x00004000
+MF_RIGHTJUSTIFY :: 0x00004000
+
+MF_MOUSESELECT :: 0x00008000
+MF_END :: 0x00000080  // Obsolete -- only used by old RES files
+
+// Flags for TrackPopupMenu
+TPM_LEFTBUTTON :: 0x0000
+TPM_RIGHTBUTTON :: 0x0002
+TPM_LEFTALIGN :: 0x0000
+TPM_CENTERALIGN :: 0x0004
+TPM_RIGHTALIGN :: 0x0008
+TPM_TOPALIGN :: 0x0000
+TPM_VCENTERALIGN :: 0x0010
+TPM_BOTTOMALIGN :: 0x0020
+
+TPM_HORIZONTAL :: 0x0000     /* Horz alignment matters more */
+TPM_VERTICAL :: 0x0040     /* Vert alignment matters more */
+TPM_NONOTIFY :: 0x0080     /* Don't send any notification msgs */
+TPM_RETURNCMD :: 0x0100
+TPM_RECURSE :: 0x0001
+TPM_HORPOSANIMATION :: 0x0400
+TPM_HORNEGANIMATION :: 0x0800
+TPM_VERPOSANIMATION :: 0x1000
+TPM_VERNEGANIMATION :: 0x2000
+TPM_NOANIMATION :: 0x4000
+TPM_LAYOUTRTL :: 0x8000
+TPM_WORKAREA :: 0x10000
+
 // WM_NCHITTEST and MOUSEHOOKSTRUCT Mouse Position Codes
 HTERROR       :: -2
 HTTRANSPARENT :: -1
@@ -3782,8 +3919,14 @@ CONSOLE_SCREEN_BUFFER_INFO :: struct {
 	dwMaximumWindowSize: COORD,
 }
 
+CONSOLE_CURSOR_INFO :: struct {
+	dwSize: DWORD,
+	bVisible: BOOL,
+}
+
 
 PCONSOLE_SCREEN_BUFFER_INFO :: ^CONSOLE_SCREEN_BUFFER_INFO
+PCONSOLE_CURSOR_INFO :: ^CONSOLE_CURSOR_INFO
 
 //
 // Networking
@@ -4018,4 +4161,4 @@ DNS_SRV_DATAA :: struct {
 SOCKADDR :: struct {
 	sa_family: ADDRESS_FAMILY,
 	sa_data:   [14]CHAR,
-}
+}

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

@@ -109,6 +109,12 @@ foreign user32 {
 	GetDlgCtrlID :: proc(hWnd: HWND) -> c_int ---
 	GetDlgItem :: proc(hDlg: HWND, nIDDlgItem: c_int) -> HWND ---
 
+	CreatePopupMenu :: proc() -> HMENU ---
+	DestroyMenu :: proc(hMenu: HMENU) -> BOOL ---
+	AppendMenuW :: proc(hMenu: HMENU, uFlags: UINT, uIDNewItem: UINT_PTR, lpNewItem: LPCWSTR) -> BOOL ---
+	TrackPopupMenu :: proc(hMenu: HMENU, uFlags: UINT, x: int, y: int, nReserved: int, hWnd: HWND, prcRect: ^RECT) -> i32 ---
+	RegisterWindowMessageW :: proc(lpString: LPCWSTR) -> UINT ---
+
 	GetUpdateRect :: proc(hWnd: HWND, lpRect: LPRECT, bErase: BOOL) -> BOOL ---
 	ValidateRect :: proc(hWnd: HWND, lpRect: ^RECT) -> BOOL ---
 	InvalidateRect :: proc(hWnd: HWND, lpRect: ^RECT, bErase: BOOL) -> BOOL ---
@@ -206,6 +212,8 @@ foreign user32 {
 	GetRegisteredRawInputDevices :: proc(pRawInputDevices: PRAWINPUTDEVICE, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
 	RegisterRawInputDevices :: proc(pRawInputDevices: PCRAWINPUTDEVICE, uiNumDevices: UINT, cbSize: UINT) -> BOOL ---
 
+	SendInput :: proc(cInputs: UINT, pInputs: [^]INPUT, cbSize: ^c_int) -> UINT ---
+
 	SetLayeredWindowAttributes  :: proc(hWnd: HWND, crKey: COLORREF, bAlpha: BYTE, dwFlags: DWORD) -> BOOL ---
 
 	FillRect :: proc(hDC: HDC, lprc: ^RECT, hbr: HBRUSH) -> int ---
@@ -469,4 +477,4 @@ WINDOWINFO :: struct {
 	atomWindowType: ATOM,
 	wCreatorVersion: WORD,
 }
-PWINDOWINFO :: ^WINDOWINFO
+PWINDOWINFO :: ^WINDOWINFO

+ 161 - 0
core/sys/windows/winmm.odin

@@ -3,9 +3,170 @@ package sys_windows
 
 foreign import winmm "system:Winmm.lib"
 
+MMRESULT :: UINT
+
 @(default_calling_convention="stdcall")
 foreign winmm {
+	timeGetDevCaps  :: proc(ptc: LPTIMECAPS, cbtc: UINT) -> MMRESULT ---
 	timeBeginPeriod :: proc(uPeriod: UINT) -> MMRESULT ---
 	timeEndPeriod   :: proc(uPeriod: UINT) -> MMRESULT ---
 	timeGetTime     :: proc() -> DWORD ---
 }
+
+LPTIMECAPS :: ^TIMECAPS
+TIMECAPS :: struct {
+	wPeriodMin: UINT,
+	wPeriodMax: UINT,
+}
+
+// String resource number bases (internal use)
+MMSYSERR_BASE :: 0
+WAVERR_BASE   :: 32
+MIDIERR_BASE  :: 64
+TIMERR_BASE   :: 96
+JOYERR_BASE   :: 160
+MCIERR_BASE   :: 256
+MIXERR_BASE   :: 1024
+
+MCI_STRING_OFFSET :: 512
+MCI_VD_OFFSET     :: 1024
+MCI_CD_OFFSET     :: 1088
+MCI_WAVE_OFFSET   :: 1152
+MCI_SEQ_OFFSET    :: 1216
+
+/* general error return values */
+MMSYSERR_NOERROR      :: 0                  /* no error */
+MMSYSERR_ERROR        :: MMSYSERR_BASE + 1  /* unspecified error */
+MMSYSERR_BADDEVICEID  :: MMSYSERR_BASE + 2  /* device ID out of range */
+MMSYSERR_NOTENABLED   :: MMSYSERR_BASE + 3  /* driver failed enable */
+MMSYSERR_ALLOCATED    :: MMSYSERR_BASE + 4  /* device already allocated */
+MMSYSERR_INVALHANDLE  :: MMSYSERR_BASE + 5  /* device handle is invalid */
+MMSYSERR_NODRIVER     :: MMSYSERR_BASE + 6  /* no device driver present */
+MMSYSERR_NOMEM        :: MMSYSERR_BASE + 7  /* memory allocation error */
+MMSYSERR_NOTSUPPORTED :: MMSYSERR_BASE + 8  /* function isn't supported */
+MMSYSERR_BADERRNUM    :: MMSYSERR_BASE + 9  /* error value out of range */
+MMSYSERR_INVALFLAG    :: MMSYSERR_BASE + 10 /* invalid flag passed */
+MMSYSERR_INVALPARAM   :: MMSYSERR_BASE + 11 /* invalid parameter passed */
+MMSYSERR_HANDLEBUSY   :: MMSYSERR_BASE + 12 /* handle being used simultaneously on another thread (eg callback) */
+MMSYSERR_INVALIDALIAS :: MMSYSERR_BASE + 13 /* specified alias not found */
+MMSYSERR_BADDB        :: MMSYSERR_BASE + 14 /* bad registry database */
+MMSYSERR_KEYNOTFOUND  :: MMSYSERR_BASE + 15 /* registry key not found */
+MMSYSERR_READERROR    :: MMSYSERR_BASE + 16 /* registry read error */
+MMSYSERR_WRITEERROR   :: MMSYSERR_BASE + 17 /* registry write error */
+MMSYSERR_DELETEERROR  :: MMSYSERR_BASE + 18 /* registry delete error */
+MMSYSERR_VALNOTFOUND  :: MMSYSERR_BASE + 19 /* registry value not found */
+MMSYSERR_NODRIVERCB   :: MMSYSERR_BASE + 20 /* driver does not call DriverCallback */
+MMSYSERR_MOREDATA     :: MMSYSERR_BASE + 21 /* more data to be returned */
+MMSYSERR_LASTERROR    :: MMSYSERR_BASE + 21 /* last error in range */
+
+/* waveform audio error return values */
+WAVERR_BADFORMAT    :: WAVERR_BASE + 0 /* unsupported wave format */
+WAVERR_STILLPLAYING :: WAVERR_BASE + 1 /* still something playing */
+WAVERR_UNPREPARED   :: WAVERR_BASE + 2 /* header not prepared */
+WAVERR_SYNC         :: WAVERR_BASE + 3 /* device is synchronous */
+WAVERR_LASTERROR    :: WAVERR_BASE + 3 /* last error in range */
+
+/* MIDI error return values */
+MIDIERR_UNPREPARED    :: MIDIERR_BASE + 0 /* header not prepared */
+MIDIERR_STILLPLAYING  :: MIDIERR_BASE + 1 /* still something playing */
+MIDIERR_NOMAP         :: MIDIERR_BASE + 2 /* no configured instruments */
+MIDIERR_NOTREADY      :: MIDIERR_BASE + 3 /* hardware is still busy */
+MIDIERR_NODEVICE      :: MIDIERR_BASE + 4 /* port no longer connected */
+MIDIERR_INVALIDSETUP  :: MIDIERR_BASE + 5 /* invalid MIF */
+MIDIERR_BADOPENMODE   :: MIDIERR_BASE + 6 /* operation unsupported w/ open mode */
+MIDIERR_DONT_CONTINUE :: MIDIERR_BASE + 7 /* thru device 'eating' a message */
+MIDIERR_LASTERROR     :: MIDIERR_BASE + 7 /* last error in range */
+
+/* timer error return values */
+TIMERR_NOERROR :: 0                /* no error */
+TIMERR_NOCANDO :: TIMERR_BASE + 1  /* request not completed */
+TIMERR_STRUCT  :: TIMERR_BASE + 33 /* time struct size */
+
+/* joystick error return values */
+JOYERR_NOERROR   :: 0               /* no error */
+JOYERR_PARMS     :: JOYERR_BASE + 5 /* bad parameters */
+JOYERR_NOCANDO   :: JOYERR_BASE + 6 /* request not completed */
+JOYERR_UNPLUGGED :: JOYERR_BASE + 7 /* joystick is unplugged */
+
+/* MCI error return values */
+MCIERR_INVALID_DEVICE_ID        :: MCIERR_BASE + 1
+MCIERR_UNRECOGNIZED_KEYWORD     :: MCIERR_BASE + 3
+MCIERR_UNRECOGNIZED_COMMAND     :: MCIERR_BASE + 5
+MCIERR_HARDWARE                 :: MCIERR_BASE + 6
+MCIERR_INVALID_DEVICE_NAME      :: MCIERR_BASE + 7
+MCIERR_OUT_OF_MEMORY            :: MCIERR_BASE + 8
+MCIERR_DEVICE_OPEN              :: MCIERR_BASE + 9
+MCIERR_CANNOT_LOAD_DRIVER       :: MCIERR_BASE + 10
+MCIERR_MISSING_COMMAND_STRING   :: MCIERR_BASE + 11
+MCIERR_PARAM_OVERFLOW           :: MCIERR_BASE + 12
+MCIERR_MISSING_STRING_ARGUMENT  :: MCIERR_BASE + 13
+MCIERR_BAD_INTEGER              :: MCIERR_BASE + 14
+MCIERR_PARSER_INTERNAL          :: MCIERR_BASE + 15
+MCIERR_DRIVER_INTERNAL          :: MCIERR_BASE + 16
+MCIERR_MISSING_PARAMETER        :: MCIERR_BASE + 17
+MCIERR_UNSUPPORTED_FUNCTION     :: MCIERR_BASE + 18
+MCIERR_FILE_NOT_FOUND           :: MCIERR_BASE + 19
+MCIERR_DEVICE_NOT_READY         :: MCIERR_BASE + 20
+MCIERR_INTERNAL                 :: MCIERR_BASE + 21
+MCIERR_DRIVER                   :: MCIERR_BASE + 22
+MCIERR_CANNOT_USE_ALL           :: MCIERR_BASE + 23
+MCIERR_MULTIPLE                 :: MCIERR_BASE + 24
+MCIERR_EXTENSION_NOT_FOUND      :: MCIERR_BASE + 25
+MCIERR_OUTOFRANGE               :: MCIERR_BASE + 26
+MCIERR_FLAGS_NOT_COMPATIBLE     :: MCIERR_BASE + 28
+MCIERR_FILE_NOT_SAVED           :: MCIERR_BASE + 30
+MCIERR_DEVICE_TYPE_REQUIRED     :: MCIERR_BASE + 31
+MCIERR_DEVICE_LOCKED            :: MCIERR_BASE + 32
+MCIERR_DUPLICATE_ALIAS          :: MCIERR_BASE + 33
+MCIERR_BAD_CONSTANT             :: MCIERR_BASE + 34
+MCIERR_MUST_USE_SHAREABLE       :: MCIERR_BASE + 35
+MCIERR_MISSING_DEVICE_NAME      :: MCIERR_BASE + 36
+MCIERR_BAD_TIME_FORMAT          :: MCIERR_BASE + 37
+MCIERR_NO_CLOSING_QUOTE         :: MCIERR_BASE + 38
+MCIERR_DUPLICATE_FLAGS          :: MCIERR_BASE + 39
+MCIERR_INVALID_FILE             :: MCIERR_BASE + 40
+MCIERR_NULL_PARAMETER_BLOCK     :: MCIERR_BASE + 41
+MCIERR_UNNAMED_RESOURCE         :: MCIERR_BASE + 42
+MCIERR_NEW_REQUIRES_ALIAS       :: MCIERR_BASE + 43
+MCIERR_NOTIFY_ON_AUTO_OPEN      :: MCIERR_BASE + 44
+MCIERR_NO_ELEMENT_ALLOWED       :: MCIERR_BASE + 45
+MCIERR_NONAPPLICABLE_FUNCTION   :: MCIERR_BASE + 46
+MCIERR_ILLEGAL_FOR_AUTO_OPEN    :: MCIERR_BASE + 47
+MCIERR_FILENAME_REQUIRED        :: MCIERR_BASE + 48
+MCIERR_EXTRA_CHARACTERS         :: MCIERR_BASE + 49
+MCIERR_DEVICE_NOT_INSTALLED     :: MCIERR_BASE + 50
+MCIERR_GET_CD                   :: MCIERR_BASE + 51
+MCIERR_SET_CD                   :: MCIERR_BASE + 52
+MCIERR_SET_DRIVE                :: MCIERR_BASE + 53
+MCIERR_DEVICE_LENGTH            :: MCIERR_BASE + 54
+MCIERR_DEVICE_ORD_LENGTH        :: MCIERR_BASE + 55
+MCIERR_NO_INTEGER               :: MCIERR_BASE + 56
+MCIERR_WAVE_OUTPUTSINUSE        :: MCIERR_BASE + 64
+MCIERR_WAVE_SETOUTPUTINUSE      :: MCIERR_BASE + 65
+MCIERR_WAVE_INPUTSINUSE         :: MCIERR_BASE + 66
+MCIERR_WAVE_SETINPUTINUSE       :: MCIERR_BASE + 67
+MCIERR_WAVE_OUTPUTUNSPECIFIED   :: MCIERR_BASE + 68
+MCIERR_WAVE_INPUTUNSPECIFIED    :: MCIERR_BASE + 69
+MCIERR_WAVE_OUTPUTSUNSUITABLE   :: MCIERR_BASE + 70
+MCIERR_WAVE_SETOUTPUTUNSUITABLE :: MCIERR_BASE + 71
+MCIERR_WAVE_INPUTSUNSUITABLE    :: MCIERR_BASE + 72
+MCIERR_WAVE_SETINPUTUNSUITABLE  :: MCIERR_BASE + 73
+MCIERR_SEQ_DIV_INCOMPATIBLE     :: MCIERR_BASE + 80
+MCIERR_SEQ_PORT_INUSE           :: MCIERR_BASE + 81
+MCIERR_SEQ_PORT_NONEXISTENT     :: MCIERR_BASE + 82
+MCIERR_SEQ_PORT_MAPNODEVICE     :: MCIERR_BASE + 83
+MCIERR_SEQ_PORT_MISCERROR       :: MCIERR_BASE + 84
+MCIERR_SEQ_TIMER                :: MCIERR_BASE + 85
+MCIERR_SEQ_PORTUNSPECIFIED      :: MCIERR_BASE + 86
+MCIERR_SEQ_NOMIDIPRESENT        :: MCIERR_BASE + 87
+MCIERR_NO_WINDOW                :: MCIERR_BASE + 90
+MCIERR_CREATEWINDOW             :: MCIERR_BASE + 91
+MCIERR_FILE_READ                :: MCIERR_BASE + 92
+MCIERR_FILE_WRITE               :: MCIERR_BASE + 93
+MCIERR_NO_IDENTITY              :: MCIERR_BASE + 94
+
+/*  MMRESULT error return values specific to the mixer API */
+MIXERR_INVALLINE    :: (MIXERR_BASE + 0)
+MIXERR_INVALCONTROL :: (MIXERR_BASE + 1)
+MIXERR_INVALVALUE   :: (MIXERR_BASE + 2)
+MIXERR_LASTERROR    :: (MIXERR_BASE + 2)

+ 100 - 0
core/text/table/doc.odin

@@ -0,0 +1,100 @@
+/*
+	package table implements ascii/markdown/html/custom rendering of tables.
+
+	---
+
+	Custom rendering example:
+
+	```odin
+	tbl := init(&Table{})
+	padding(tbl, 0, 1)
+	row(tbl, "A_LONG_ENUM", "= 54,", "// A comment about A_LONG_ENUM")
+	row(tbl, "AN_EVEN_LONGER_ENUM", "= 1,", "// A comment about AN_EVEN_LONGER_ENUM")
+	build(tbl)
+	for row in 0..<tbl.nr_rows {
+		for col in 0..<tbl.nr_cols {
+			write_table_cell(stdio_writer(), tbl, row, col)
+		}
+		io.write_byte(stdio_writer(), '\n')
+	}
+	```
+
+	This outputs:
+	```
+	A_LONG_ENUM         = 54, // A comment about A_LONG_ENUM
+	AN_EVEN_LONGER_ENUM = 1,  // A comment about AN_EVEN_LONGER_ENUM
+	```
+
+	---
+
+	ASCII rendering example:
+
+	```odin
+	tbl := init(&Table{})
+	defer destroy(tbl)
+
+	caption(tbl, "This is a table caption and it is very long")
+
+	padding(tbl, 1, 1) // Left/right padding of cells
+
+	header(tbl, "AAAAAAAAA", "B")
+	header(tbl, "C") // Appends to previous header row. Same as if done header("AAAAAAAAA", "B", "C") from start.
+
+	// Create a row with two values. Since there are three columns the third
+	// value will become the empty string.
+	//
+	// NOTE: header() is not allowed anymore after this.
+	row(tbl, 123, "foo")
+
+	// Use `format()` if you need custom formatting. This will allocate into
+	// the arena specified at init.
+	row(tbl,
+	    format(tbl, "%09d", 5),
+	    format(tbl, "%.6f", 6.28318530717958647692528676655900576))
+
+	// A row with zero values is allowed as long as a previous row or header
+	// exist. The value and alignment of each cell can then be set
+	// individually.
+	row(tbl)
+		set_cell_value_and_alignment(tbl, last_row(tbl), 0, "a", .Center)
+		set_cell_value(tbl, last_row(tbl), 1, "bbb")
+		set_cell_value(tbl, last_row(tbl), 2, "c")
+
+	// Headers are regular cells, too. Use header_row() as row index to modify
+	// header cells.
+	set_cell_alignment(tbl, header_row(tbl), 1, .Center) // Sets alignment of 'B' column to Center.
+	set_cell_alignment(tbl, header_row(tbl), 2, .Right) // Sets alignment of 'C' column to Right.
+
+	build(tbl)
+
+	write_ascii_table(stdio_writer(), tbl)
+	write_markdown_table(stdio_writer(), tbl)
+	```
+
+	This outputs:
+	```
+	+-----------------------------------------------+
+	|  This is a table caption and it is very long  |
+	+------------------+-----------------+----------+
+	| AAAAAAAAA        |        B        |        C |
+	+------------------+-----------------+----------+
+	| 123              | foo             |          |
+	| 000000005        | 6.283185        |          |
+	|        a         | bbb             | c        |
+	+------------------+-----------------+----------+
+	```
+
+	and
+
+	```
+	|    AAAAAAAAA     |        B        |    C     |
+	|:-----------------|:---------------:|---------:|
+	| 123              | foo             |          |
+	| 000000005        | 6.283185        |          |
+	| a                | bbb             | c        |
+	```
+
+	respectively.
+*/
+
+package text_table

+ 384 - 0
core/text/table/table.odin

@@ -0,0 +1,384 @@
+/*
+	Copyright 2023 oskarnp <[email protected]>
+	Made available under Odin's BSD-3 license.
+
+	List of contributors:
+		oskarnp: Initial implementation.
+*/
+
+package text_table
+
+import "core:io"
+import "core:os"
+import "core:fmt"
+import "core:mem"
+import "core:mem/virtual"
+import "core:runtime"
+import "core:strings"
+
+Cell :: struct {
+	text: string,
+	alignment: Cell_Alignment,
+}
+
+Cell_Alignment :: enum {
+	Left,
+	Center,
+	Right,
+}
+
+Table :: struct {
+	lpad, rpad: int, // Cell padding (left/right)
+	cells: [dynamic]Cell,
+	caption: string,
+	nr_rows, nr_cols: int,
+	has_header_row: bool,
+	table_allocator: runtime.Allocator,  // Used for allocating cells/colw
+	format_allocator: runtime.Allocator, // Used for allocating Cell.text when applicable
+
+	dirty: bool, // True if build() needs to be called before rendering
+
+	// The following are computed on build()
+	colw: [dynamic]int, // Width of each column (including padding, excluding borders)
+	tblw: int,          // Width of entire table (including padding, excluding borders)
+}
+
+init :: proc{init_with_allocator, init_with_virtual_arena, init_with_mem_arena}
+
+init_with_allocator :: proc(tbl: ^Table, format_allocator := context.temp_allocator, table_allocator := context.allocator) -> ^Table {
+	tbl.table_allocator = table_allocator
+	tbl.cells = make([dynamic]Cell, tbl.table_allocator)
+	tbl.colw = make([dynamic]int, tbl.table_allocator)
+	tbl.format_allocator = format_allocator
+	return tbl
+}
+init_with_virtual_arena :: proc(tbl: ^Table, format_arena: ^virtual.Arena, table_allocator := context.allocator) -> ^Table {
+	return init_with_allocator(tbl, virtual.arena_allocator(format_arena), table_allocator)
+}
+init_with_mem_arena :: proc(tbl: ^Table, format_arena: ^mem.Arena, table_allocator := context.allocator) -> ^Table {
+	return init_with_allocator(tbl, mem.arena_allocator(format_arena), table_allocator)
+}
+
+destroy :: proc(tbl: ^Table) {
+	free_all(tbl.format_allocator)
+	delete(tbl.cells)
+	delete(tbl.colw)
+}
+
+caption :: proc(tbl: ^Table, value: string) {
+	tbl.caption = value
+	tbl.dirty = true
+}
+
+padding :: proc(tbl: ^Table, lpad, rpad: int) {
+	tbl.lpad = lpad
+	tbl.rpad = rpad
+	tbl.dirty = true
+}
+
+get_cell :: proc(tbl: ^Table, row, col: int, loc := #caller_location) -> ^Cell {
+	assert(col >= 0 && col < tbl.nr_cols, "cell column out of range", loc)
+	assert(row >= 0 && row < tbl.nr_rows, "cell row out of range", loc)
+	resize(&tbl.cells, tbl.nr_cols * tbl.nr_rows)
+	return &tbl.cells[row*tbl.nr_cols + col]
+}
+
+set_cell_value_and_alignment :: proc(tbl: ^Table, row, col: int, value: string, alignment: Cell_Alignment) {
+	cell := get_cell(tbl, row, col)
+	cell.text = format(tbl, "%v", value)
+	cell.alignment = alignment
+	tbl.dirty = true
+}
+
+set_cell_value :: proc(tbl: ^Table, row, col: int, value: any, loc := #caller_location) {
+	cell := get_cell(tbl, row, col, loc)
+	switch val in value {
+	case nil:
+		cell.text = ""
+	case string:
+		cell.text = string(val)
+	case cstring:
+		cell.text = string(val)
+	case:
+		cell.text = format(tbl, "%v", val)
+		if cell.text == "" {
+			fmt.eprintf("{} text/table: format() resulted in empty string (arena out of memory?)\n", loc)
+		}
+	}
+	tbl.dirty = true
+}
+
+set_cell_alignment :: proc(tbl: ^Table, row, col: int, alignment: Cell_Alignment, loc := #caller_location) {
+	cell := get_cell(tbl, row, col, loc)
+	cell.alignment = alignment
+	tbl.dirty = true
+}
+
+format :: proc(tbl: ^Table, _fmt: string, args: ..any, loc := #caller_location) -> string {
+	context.allocator = tbl.format_allocator
+	return fmt.aprintf(fmt = _fmt, args = args)
+}
+
+header :: proc(tbl: ^Table, values: ..any, loc := #caller_location) {
+	if (tbl.has_header_row && tbl.nr_rows != 1) || (!tbl.has_header_row && tbl.nr_rows != 0) {
+		panic("Cannot add headers after rows have been added", loc)
+	}
+
+	if tbl.nr_rows == 0 {
+		tbl.nr_rows += 1
+		tbl.has_header_row = true
+	}
+
+	col := tbl.nr_cols
+	tbl.nr_cols += len(values)
+	for val in values {
+		set_cell_value(tbl, header_row(tbl), col, val, loc)
+		col += 1
+	}
+
+	tbl.dirty = true
+}
+
+row :: proc(tbl: ^Table, values: ..any, loc := #caller_location) {
+	if tbl.nr_cols == 0 {
+		if len(values) == 0 {
+			panic("Cannot create row without values unless knowing amount of columns in advance")
+		} else {
+			tbl.nr_cols = len(values)
+		}
+	}
+	tbl.nr_rows += 1
+	for col in 0..<tbl.nr_cols {
+		val := values[col] if col < len(values) else nil
+		set_cell_value(tbl, last_row(tbl), col, val)
+	}
+	tbl.dirty = true
+}
+
+last_row :: proc(tbl: ^Table) -> int {
+	return tbl.nr_rows - 1
+}
+
+header_row :: proc(tbl: ^Table) -> int {
+	return 0 if tbl.has_header_row else -1
+}
+
+first_row :: proc(tbl: ^Table) -> int {
+	return header_row(tbl)+1 if tbl.has_header_row else 0
+}
+
+build :: proc(tbl: ^Table) {
+	tbl.dirty = false
+
+	resize(&tbl.colw, tbl.nr_cols)
+	mem.zero_slice(tbl.colw[:])
+
+	for row in 0..<tbl.nr_rows {
+		for col in 0..<tbl.nr_cols {
+			cell := get_cell(tbl, row, col)
+			if w := len(cell.text) + tbl.lpad + tbl.rpad; w > tbl.colw[col] {
+				tbl.colw[col] = w
+			}
+		}
+	}
+
+	colw_sum := 0
+	for v in tbl.colw {
+		colw_sum += v
+	}
+
+	tbl.tblw = max(colw_sum, len(tbl.caption) + tbl.lpad + tbl.rpad)
+
+	// Resize columns to match total width of table
+	remain := tbl.tblw-colw_sum
+	for col := 0; remain > 0; col = (col + 1) % tbl.nr_cols {
+		tbl.colw[col] += 1
+		remain -= 1
+	}
+
+	return
+}
+
+write_html_table :: proc(w: io.Writer, tbl: ^Table) {
+	if tbl.dirty {
+		build(tbl)
+	}
+
+	io.write_string(w, "<table>\n")
+	if tbl.caption != "" {
+		io.write_string(w, "<caption>")
+		io.write_string(w, tbl.caption)
+		io.write_string(w, "</caption>\n")
+	}
+
+	align_attribute :: proc(cell: ^Cell) -> string {
+		switch cell.alignment {
+		case .Left:   return ` align="left"`
+		case .Center: return ` align="center"`
+		case .Right:  return ` align="right"`
+		}
+		unreachable()
+	}
+
+	if tbl.has_header_row {
+		io.write_string(w, "<thead>\n")
+		io.write_string(w, "  <tr>\n")
+		for col in 0..<tbl.nr_cols {
+			cell := get_cell(tbl, header_row(tbl), col)
+			io.write_string(w, "    <th")
+			io.write_string(w, align_attribute(cell))
+			io.write_string(w, ">")
+			io.write_string(w, cell.text)
+			io.write_string(w, "</th>\n")
+		}
+		io.write_string(w, "  </tr>\n")
+		io.write_string(w, "</thead>\n")
+	}
+
+	io.write_string(w, "<tbody>\n")
+	for row in 0..<tbl.nr_rows {
+		if tbl.has_header_row && row == header_row(tbl) {
+			continue
+		}
+		io.write_string(w, "  <tr>\n")
+		for col in 0..<tbl.nr_cols {
+			cell := get_cell(tbl, row, col)
+			io.write_string(w, "    <td")
+			io.write_string(w, align_attribute(cell))
+			io.write_string(w, ">")
+			io.write_string(w, cell.text)
+			io.write_string(w, "</td>\n")
+		}
+		io.write_string(w, "  </tr>\n")
+	}
+	io.write_string(w, "  </tbody>\n")
+
+	io.write_string(w, "</table>\n")
+}
+
+write_ascii_table :: proc(w: io.Writer, tbl: ^Table) {
+	if tbl.dirty {
+		build(tbl)
+	}
+
+	write_caption_separator :: proc(w: io.Writer, tbl: ^Table) {
+		io.write_byte(w, '+')
+		write_byte_repeat(w, tbl.tblw + tbl.nr_cols - 1, '-')
+		io.write_byte(w, '+')
+		io.write_byte(w, '\n')
+	}
+
+	write_table_separator :: proc(w: io.Writer, tbl: ^Table) {
+		for col in 0..<tbl.nr_cols {
+			if col == 0 {
+				io.write_byte(w, '+')
+			}
+			write_byte_repeat(w, tbl.colw[col], '-')
+			io.write_byte(w, '+')
+		}
+		io.write_byte(w, '\n')
+	}
+
+	if tbl.caption != "" {
+		write_caption_separator(w, tbl)
+		io.write_byte(w, '|')
+		write_text_align(w, tbl.tblw -  tbl.lpad - tbl.rpad + tbl.nr_cols - 1,
+		                 tbl.lpad, tbl.rpad, tbl.caption, .Center)
+		io.write_byte(w, '|')
+		io.write_byte(w, '\n')
+	}
+
+	write_table_separator(w, tbl)
+	for row in 0..<tbl.nr_rows {
+		for col in 0..<tbl.nr_cols {
+			if col == 0 {
+				io.write_byte(w, '|')
+			}
+			write_table_cell(w, tbl, row, col)
+			io.write_byte(w, '|')
+		}
+		io.write_byte(w, '\n')
+		if tbl.has_header_row && row == header_row(tbl) {
+			write_table_separator(w, tbl)
+		}
+	}
+	write_table_separator(w, tbl)
+}
+
+// Renders table according to GitHub Flavored Markdown (GFM) specification
+write_markdown_table :: proc(w: io.Writer, tbl: ^Table) {
+	// NOTE(oskar): Captions or colspans are not supported by GFM as far as I can tell.
+
+	if tbl.dirty {
+		build(tbl)
+	}
+
+	for row in 0..<tbl.nr_rows {
+		for col in 0..<tbl.nr_cols {
+			cell := get_cell(tbl, row, col)
+			if col == 0 {
+				io.write_byte(w, '|')
+			}
+			write_text_align(w, tbl.colw[col] - tbl.lpad - tbl.rpad, tbl.lpad, tbl.rpad, cell.text,
+			                 .Center if tbl.has_header_row && row == header_row(tbl) else .Left)
+			io.write_string(w, "|")
+		}
+		io.write_byte(w, '\n')
+
+		if tbl.has_header_row && row == header_row(tbl) {
+			for col in 0..<tbl.nr_cols {
+				cell := get_cell(tbl, row, col)
+				if col == 0 {
+					io.write_byte(w, '|')
+				}
+				switch cell.alignment {
+				case .Left:
+					io.write_byte(w, ':')
+					write_byte_repeat(w, max(1, tbl.colw[col]-1), '-')
+				case .Center:
+					io.write_byte(w, ':')
+					write_byte_repeat(w, max(1, tbl.colw[col]-2), '-')
+					io.write_byte(w, ':')
+				case .Right:
+					write_byte_repeat(w, max(1, tbl.colw[col]-1), '-')
+					io.write_byte(w, ':')
+				}
+				io.write_byte(w, '|')
+			}
+			io.write_byte(w, '\n')
+		}
+	}
+}
+
+write_byte_repeat :: proc(w: io.Writer, n: int, b: byte) {
+	for _ in 0..<n {
+		io.write_byte(w, b)
+	}
+}
+
+write_table_cell :: proc(w: io.Writer, tbl: ^Table, row, col: int) {
+	if tbl.dirty {
+		build(tbl)
+	}
+	cell := get_cell(tbl, row, col)
+	write_text_align(w, tbl.colw[col]-tbl.lpad-tbl.rpad, tbl.lpad, tbl.rpad, cell.text, cell.alignment)
+}
+
+write_text_align :: proc(w: io.Writer, colw, lpad, rpad: int, text: string, alignment: Cell_Alignment) {
+	write_byte_repeat(w, lpad, ' ')
+	switch alignment {
+	case .Left:
+		io.write_string(w, text)
+		write_byte_repeat(w, colw - len(text), ' ')
+	case .Center:
+		pad := colw - len(text)
+		odd := pad & 1 != 0
+		write_byte_repeat(w, pad/2, ' ')
+		io.write_string(w, text)
+		write_byte_repeat(w, pad/2 + 1 if odd else pad/2, ' ')
+	case .Right:
+		write_byte_repeat(w, colw - len(text), ' ')
+		io.write_string(w, text)
+	}
+	write_byte_repeat(w, rpad, ' ')
+}

+ 13 - 0
core/text/table/utility.odin

@@ -0,0 +1,13 @@
+package text_table
+
+import "core:io"
+import "core:os"
+import "core:strings"
+
+stdio_writer :: proc() -> io.Writer {
+	return io.to_writer(os.stream_from_handle(os.stdout))
+}
+
+strings_builder_writer :: proc(b: ^strings.Builder) -> io.Writer {
+	return strings.to_writer(b)
+}

+ 55 - 0
core/thread/thread_js.odin

@@ -0,0 +1,55 @@
+//+build js
+package thread
+
+import "core:intrinsics"
+import "core:sync"
+import "core:mem"
+
+Thread_State :: enum u8 {
+	Started,
+	Joined,
+	Done,
+}
+
+Thread_Os_Specific :: struct {
+	flags:       bit_set[Thread_State; u8],
+}
+
+_thread_priority_map := [Thread_Priority]i32{
+	.Normal = 0,
+	.Low = -2,
+	.High = +2,
+}
+
+_create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread {
+	unimplemented("core:thread procedure not supported on js target")
+}
+
+_start :: proc(t: ^Thread) {
+	unimplemented("core:thread procedure not supported on js target")
+}
+
+_is_done :: proc(t: ^Thread) -> bool {
+	unimplemented("core:thread procedure not supported on js target")
+}
+
+_join :: proc(t: ^Thread) {
+	unimplemented("core:thread procedure not supported on js target")
+}
+
+_join_multiple :: proc(threads: ..^Thread) {
+	unimplemented("core:thread procedure not supported on js target")
+}
+
+_destroy :: proc(thread: ^Thread) {
+	unimplemented("core:thread procedure not supported on js target")
+}
+
+_terminate :: proc(using thread : ^Thread, exit_code: int) {
+	unimplemented("core:thread procedure not supported on js target")
+}
+
+_yield :: proc() {
+	unimplemented("core:thread procedure not supported on js target")
+}
+

+ 0 - 337
misc/old_demos/demo001.odin

@@ -1,337 +0,0 @@
-import "core:fmt.odin";
-import "core:os.odin";
-import "core:mem.odin";
-// import "http_test.odin" as ht;
-// import "game.odin" as game;
-// import "punity.odin" as pn;
-
-main :: proc() {
-	struct_padding();
-	bounds_checking();
-	type_introspection();
-	any_type();
-	crazy_introspection();
-	namespaces_and_files();
-	miscellany();
-
-	/*
-	ht.run();
-	game.run();
-	{
-		init :: proc(c: ^pn.Core) {}
-		step :: proc(c: ^pn.Core) {}
-
-		pn.run(init, step);
-	}
-	*/
-}
-
-struct_padding :: proc() {
-	{
-		A :: struct {
-			a: u8,
-			b: u32,
-			c: u16,
-		}
-
-		B :: struct {
-			a: [7]u8,
-			b: [3]u16,
-			c: u8,
-			d: u16,
-		}
-
-		fmt.println("size_of(A):", size_of(A));
-		fmt.println("size_of(B):", size_of(B));
-
-		// n.b. http://cbloomrants.blogspot.co.uk/2012/07/07-23-12-structs-are-not-what-you-want.html
-	}
-	{
-		A :: struct #ordered {
-			a: u8,
-			b: u32,
-			c: u16,
-		}
-
-		B :: struct #ordered {
-			a: [7]u8,
-			b: [3]u16,
-			c: u8,
-			d: u16,
-		}
-
-		fmt.println("size_of(A):", size_of(A));
-		fmt.println("size_of(B):", size_of(B));
-
-		// C-style structure layout
-	}
-	{
-		A :: struct #packed {
-			a: u8,
-			b: u32,
-			c: u16,
-		}
-
-		B :: struct #packed {
-			a: [7]u8,
-			b: [3]u16,
-			c: u8,
-			d: u16,
-		}
-
-		fmt.println("size_of(A):", size_of(A));
-		fmt.println("size_of(B):", size_of(B));
-
-		// Useful for explicit layout
-	}
-
-	// Member sorting by priority
-	// Alignment desc.
-	// Size desc.
-	// source order asc.
-
-	/*
-		A :: struct {
-			a: u8
-			b: u32
-			c: u16
-		}
-
-		B :: struct {
-			a: [7]u8
-			b: [3]u16
-			c: u8
-			d: u16
-		}
-
-		Equivalent too
-
-		A :: struct #ordered {
-			b: u32
-			c: u16
-			a: u8
-		}
-
-		B :: struct #ordered {
-			b: [3]u16
-			d: u16
-			a: [7]u8
-			c: u8
-		}
-	*/
-}
-
-bounds_checking :: proc() {
-	x: [4]int;
-	// x[-1] = 0; // Compile Time
-	// x[4]  = 0; // Compile Time
-
-	{
-		a, b := -1, 4;
-		// x[a] = 0; // Runtime Time
-		// x[b] = 0; // Runtime Time
-	}
-
-	// Works for arrays, strings, slices, and related procedures & operations
-
-	{
-		base: [10]int;
-		s := base[2..6];
-		a, b := -1, 6;
-
-		#no_bounds_check {
-			s[a] = 0;
-			// #bounds_check s[b] = 0;
-		}
-
-	#no_bounds_check
-		if s[a] == 0 {
-			// Do whatever
-		}
-
-		// Bounds checking can be toggled explicit
-		// on a per statement basis.
-		// _any statement_
-	}
-}
-
-type_introspection :: proc() {
-	{
-		info: ^Type_Info;
-		x: int;
-
-		info = type_info_of(int); // by type
-		info = type_info_of(x);   // by value
-		// See: runtime.odin
-
-		match i in info.variant {
-		case Type_Info_Integer:
-			fmt.println("integer!");
-		case Type_Info_Float:
-			fmt.println("float!");
-		case:
-			fmt.println("potato!");
-		}
-
-		// Unsafe cast
-		integer_info := cast(^Type_Info_Integer)cast(rawptr)info;
-	}
-
-	{
-		Vector2 :: struct { x, y: f32 }
-		Vector3 :: struct { x, y, z: f32 }
-
-		v1: Vector2;
-		v2: Vector3;
-		v3: Vector3;
-
-		t1 := type_info_of(v1);
-		t2 := type_info_of(v2);
-		t3 := type_info_of(v3);
-
-		fmt.println();
-		fmt.print("Type of v1 is:\n\t", t1);
-
-		fmt.println();
-		fmt.print("Type of v2 is:\n\t", t2);
-
-		fmt.println("\n");
-		fmt.println("t1 == t2:", t1 == t2);
-		fmt.println("t2 == t3:", t2 == t3);
-	}
-}
-
-any_type :: proc() {
-	a: any;
-
-	x: int = 123;
-	y: f64 = 6.28;
-	z: string = "Yo-Yo Ma";
-	// All types can be implicit cast to `any`
-	a = x;
-	a = y;
-	a = z;
-	a = a; // This the "identity" type, it doesn't get converted
-
-	a = 123; // Literals are copied onto the stack first
-
-	// any has two members
-	// data      - rawptr to the data
-	// type_info - pointer to the type info
-
-	fmt.println(x, y, z);
-	// See: fmt.odin
-	// For variadic any procedures in action
-}
-
-crazy_introspection :: proc() {
-	{
-		Fruit :: enum {
-			APPLE,
-			BANANA,
-			GRAPE,
-			MELON,
-			PEACH,
-			TOMATO,
-		}
-
-		s: string;
-		// s = enum_to_string(Fruit.PEACH);
-		fmt.println(s);
-
-		f := Fruit.GRAPE;
-		// s = enum_to_string(f);
-		fmt.println(s);
-
-		fmt.println(f);
-		// See: runtime.odin
-	}
-
-
-	{
-		// NOTE(bill): This is not safe code and I would not recommend this at all
-		// I'd recommend you use `match type` to get the subtype rather than
-		// casting pointers
-
-		Fruit :: enum {
-			APPLE,
-			BANANA,
-			GRAPE,
-			MELON,
-			PEACH,
-			TOMATO,
-		}
-
-		fruit_ti := type_info_of(Fruit);
-		name := fruit_ti.variant.(Type_Info_Named).name;
-		info, _ := type_info_base(fruit_ti).variant.(Type_Info_Enum);
-
-		fmt.printf("%s :: enum %T {\n", name, info.base);
-		for _, i in info.values {
-			fmt.printf("\t%s\t= %v,\n", info.names[i], info.values[i]);
-		}
-		fmt.printf("}\n");
-
-		// NOTE(bill): look at that type-safe printf!
-	}
-
-	{
-		Vector3 :: struct {x, y, z: f32}
-
-		a := Vector3{x = 1, y = 4, z = 9};
-		fmt.println(a);
-		b := Vector3{x = 9, y = 3, z = 1};
-		fmt.println(b);
-
-		// NOTE(bill): See fmt.odin
-	}
-
-	// n.b. This pretty much "solves" serialization (to strings)
-}
-
-// #import "test.odin"
-
-namespaces_and_files :: proc() {
-
-	// test.thing()
-	// test.format.println()
-	// test.println()
-	/*
-		// Non-exporting import
-		#import "file.odin"
-		#import "file.odin" as file
-		#import "file.odin" as .
-		#import "file.odin" as _
-
-		// Exporting import
-		#include "file.odin"
-	*/
-
-	// Talk about scope rules and diagram
-}
-
-miscellany :: proc() {
-	/*
-		win32 `__imp__` prefix
-		#dll_import
-		#dll_export
-
-		Change exported name/symbol for linking
-		#link_name
-
-		Custom calling conventions
-		#stdcall
-		#fastcall
-
-		Runtime stuff
-		#shared_global_scope
-	*/
-
-	// assert(false)
-	// #assert(false)
-	// panic("Panic message goes here")
-}
-
-
-
-

+ 0 - 879
misc/old_demos/demo002.odin

@@ -1,879 +0,0 @@
-// Demo 002
-export "core:fmt.odin";
-export "core:math.odin";
-export "core:mem.odin";
-// export "game.odin"
-
-#thread_local tls_int: int;
-
-main :: proc() {
-	// Forenotes
-
-	// Semicolons are now optional
-	// Rule for when a semicolon is expected after a statement
-	// - If the next token is not on the same line
-	// - if the next token is a closing brace }
-	// - Otherwise, a semicolon is needed
-	//
-	// Expections:
-	// for, if, match
-	// if x := thing(); x < 123 {}
-	// for i := 0; i < 123; i++ {}
-
-	// Q: Should I use the new rule or go back to the old one without optional semicolons?
-
-
-	// #thread_local - see runtime.odin and above at `tls_int`
-	// #foreign_system_library - see win32.odin
-
-	// struct_compound_literals();
-	// enumerations();
-	// variadic_procedures();
-	// new_builtins();
-	// match_statement();
-	// namespacing();
-	// subtyping();
-	// tagged_unions();
-}
-
-struct_compound_literals :: proc() {
-	Thing :: struct {
-		id: int,
-		x: f32,
-		name: string,
-	};
-	{
-		t1: Thing;
-		t1.id = 1;
-
-		t3 := Thing{};
-		t4 := Thing{1, 2, "Fred"};
-		// t5 := Thing{1, 2};
-
-		t6 := Thing{
-			name = "Tom",
-			x    = 23,
-		};
-	}
-}
-
-enumerations :: proc() {
-	{
-		Fruit :: enum {
-			APPLE,  // 0
-			BANANA, // 1
-			PEAR,   // 2
-		};
-
-		f := Fruit.APPLE;
-		// g12: int = Fruit.BANANA
-		g: int = cast(int)Fruit.BANANA;
-		// However, you can use enums are index values as _any_ integer allowed
-	}
-	{
-		Fruit1 :: enum int {
-			APPLE,
-			BANANA,
-			PEAR,
-		}
-
-		Fruit2 :: enum u8 {
-			APPLE,
-			BANANA,
-			PEAR,
-		}
-
-		Fruit3 :: enum u8 {
-			APPLE = 1,
-			BANANA, // 2
-			PEAR  = 5,
-			TOMATO, // 6
-		}
-	}
-
-	// Q: remove the need for `type` if it's a record (struct/enum/raw_union/union)?
-}
-
-variadic_procedures :: proc() {
-	print_ints :: proc(args: ..int) {
-		for arg, i in args {
-			if i > 0 do print(", ");
-			print(arg);
-		}
-	}
-
-	print_ints(); // nl()
-	print_ints(1); nl();
-	print_ints(1, 2, 3); nl();
-
-	print_prefix_f32s :: proc(prefix: string, args: ..f32) {
-		print(prefix);
-		print(": ");
-		for arg, i in args {
-			if i > 0 do print(", ");
-			print(arg);
-		}
-	}
-
-	print_prefix_f32s("a"); nl();
-	print_prefix_f32s("b", 1); nl();
-	print_prefix_f32s("c", 1, 2, 3); nl();
-
-	// Internally, the variadic procedures get allocated to an array on the stack,
-	// and this array is passed a slice
-
-	// This is first step for a `print` procedure but I do not have an `any` type
-	// yet as this requires a few other things first - i.e. introspection
-
-	// NOTE(bill): I haven't yet added the feature of expanding a slice or array into
-	// a variadic a parameter but it's pretty trivial to add
-}
-
-new_builtins :: proc() {
-	{
-		a := new(int);
-		b := make([]int, 12);
-		c := make([]int, 12, 16);
-
-		defer free(a);
-		defer free(b);
-		defer free(c);
-
-		// NOTE(bill): These use the current context's allocator not the default allocator
-		// see runtime.odin
-
-		// Q: Should this be `free` rather than `free` and should I overload it for slices too?
-
-		push_allocator default_allocator() {
-			a := new(int);
-			defer free(a);
-
-			// Do whatever
-
-		}
-	}
-
-	{
-		a: int = 123;
-		b: type_of(a) = 321;
-
-		// NOTE(bill): This matches the current naming scheme
-		// size_of
-		// align_of
-		// offset_of
-		//
-		// size_of_val
-		// align_of_val
-		// offset_of_val
-		// type_of_val
-	}
-
-	{
-		// Compile time assert
-		COND :: true;
-		#assert(COND);
-		// #assert(!COND)
-
-		// Runtime assert
-		x := true;
-		assert(x);
-		// assert(!x);
-	}
-
-	{
-		x: ^u32 = nil;
-		y := x+100;
-		z := y-x;
-		w := slice_ptr(x, 12);
-		t := slice_ptr(x, 12, 16);
-
-		// NOTE(bill): These are here because I've removed:
-		// pointer arithmetic
-		// pointer indexing
-		// pointer slicing
-
-		// Reason
-
-		a: [16]int;
-		a[1] = 1;
-		b := &a;
-		// Auto pointer deref
-		// consistent with record members
-		assert(b[1] == 1);
-
-		// Q: Should I add them back in at the cost of inconsitency?
-	}
-
-	{
-		a, b := -1, 2;
-		print(min(a, b)); nl();
-		print(max(a, b)); nl();
-		print(abs(a)); nl();
-
-		// These work at compile time too
-		A :: -1;
-		B :: 2;
-		C :: min(A, B);
-		D :: max(A, B);
-		E :: abs(A);
-
-		print(C); nl();
-		print(D); nl();
-		print(E); nl();
-	}
-}
-
-
-match_statement :: proc() {
-	// NOTE(bill): `match` statements are similar to `switch` statements
-	// in other languages but there are few differences
-
-	{
-		match x := 5; x {
-		case 1: // cases must be constant expression
-			print("1!\n");
-			// break by default
-
-		case 2:
-			s := "2!\n"; // Each case has its own scope
-			print(s);
-			break; // explicit break
-
-		case 3, 4: // multiple cases
-			print("3 or 4!\n");
-
-		case 5:
-			print("5!\n");
-			fallthrough; // explicit fallthrough
-
-		case:
-			print("default!\n");
-		}
-
-
-
-		match x := 1.5; x {
-		case 1.5:
-			print("1.5!\n");
-			// break by default
-		case TAU:
-			print("τ!\n");
-		case:
-			print("default!\n");
-		}
-
-
-
-		match x := "Hello"; x {
-		case "Hello":
-			print("greeting\n");
-			// break by default
-		case "Goodbye":
-			print("farewell\n");
-		case:
-			print("???\n");
-		}
-
-
-
-
-
-
-		a := 53;
-		match {
-		case a == 1:
-			print("one\n");
-		case a == 2:
-			print("a couple\n");
-		case a < 7, a == 7:
-			print("a few\n");
-		case a < 12: // intentional bug
-			print("several\n");
-		case a >= 12 && a < 100:
-			print("dozens\n");
-		case a >= 100 && a < 1000:
-			print("hundreds\n");
-		case:
-			print("a fuck ton\n");
-		}
-
-		// Identical to this
-
-		b := 53;
-		if b == 1 {
-			print("one\n");
-		} else if b == 2 {
-			print("a couple\n");
-		} else if b < 7 || b == 7 {
-			print("a few\n");
-		} else if b < 12 { // intentional bug
-			print("several\n");
-		} else if b >= 12 && b < 100 {
-			print("dozens\n");
-		} else if b >= 100 && b < 1000 {
-			print("hundreds\n");
-		} else {
-			print("a fuck ton\n");
-		}
-
-		// However, match statements allow for `break` and `fallthrough` unlike
-		// an if statement
-	}
-}
-
-Vector3 :: struct {x, y, z: f32}
-
-print_floats :: proc(args: ..f32) {
-	for arg, i in args {
-		if i > 0 do print(", ");
-		print(arg);
-	}
-	println();
-}
-
-namespacing :: proc() {
-	{
-		Thing :: #type struct {
-			x: f32,
-			name: string,
-		};
-
-		a: Thing;
-		a.x = 3;
-		{
-			Thing :: #type struct {
-				y: int,
-				test: bool,
-			};
-
-			b: Thing; // Uses this scope's Thing
-			b.test = true;
-		}
-	}
-/*
-	{
-		Entity :: struct {
-			Guid :: int
-			Nested :: struct {
-				MyInt :: int
-				i: int
-			}
-
-			CONSTANT :: 123
-
-
-			guid:   Guid
-			name:   string
-			pos:    Vector3
-			vel:    Vector3
-			nested: Nested
-		}
-
-		guid: Entity.Guid = Entity.CONSTANT
-		i: Entity.Nested.MyInt
-
-
-
-		{
-			using Entity
-			guid: Guid = CONSTANT
-			using Nested
-			i: MyInt
-		}
-
-
-		{
-			using Entity.Nested
-			guid: Entity.Guid = Entity.CONSTANT
-			i: MyInt
-		}
-
-
-		{
-			e: Entity
-			using e
-			guid = 27832
-			name = "Bob"
-
-			print(e.guid as int); nl()
-			print(e.name); nl()
-		}
-
-		{
-			using e: Entity
-			guid = 78456
-			name = "Thing"
-
-			print(e.guid as int); nl()
-			print(e.name); nl()
-		}
-	}
-
-	{
-		Entity :: struct {
-			Guid :: int
-			Nested :: struct {
-				MyInt :: int
-				i: int
-			}
-
-			CONSTANT :: 123
-
-
-			guid:      Guid
-			name:      string
-			using pos: Vector3
-			vel:       Vector3
-			using nested: ^Nested
-		}
-
-		e := Entity{nested = new(Entity.Nested)}
-		e.x = 123
-		e.i = Entity.CONSTANT
-	}
-
-*/
-
-	{
-		Entity :: struct {
-			position: Vector3
-		}
-
-		print_pos_1 :: proc(entity: ^Entity) {
-			print("print_pos_1: ");
-			print_floats(entity.position.x, entity.position.y, entity.position.z);
-		}
-
-		print_pos_2 :: proc(entity: ^Entity) {
-			using entity;
-			print("print_pos_2: ");
-			print_floats(position.x, position.y, position.z);
-		}
-
-		print_pos_3 :: proc(using entity: ^Entity) {
-			print("print_pos_3: ");
-			print_floats(position.x, position.y, position.z);
-		}
-
-		print_pos_4 :: proc(using entity: ^Entity) {
-			using position;
-			print("print_pos_4: ");
-			print_floats(x, y, z);
-		}
-
-		e := Entity{position = Vector3{1, 2, 3}};
-		print_pos_1(&e);
-		print_pos_2(&e);
-		print_pos_3(&e);
-		print_pos_4(&e);
-
-		// This is similar to C++'s `this` pointer that is implicit and only available in methods
-	}
-}
-
-subtyping :: proc() {
-	{
-		// C way for subtyping/subclassing
-
-		Entity :: struct {
-			position: Vector3,
-		}
-
-		Frog :: struct {
-			entity: Entity,
-			jump_height: f32,
-		}
-
-		f: Frog;
-		f.entity.position = Vector3{1, 2, 3};
-
-		using f.entity;
-		position = Vector3{1, 2, 3};
-
-	}
-
-	{
-		// C++ way for subtyping/subclassing
-
-		Entity :: struct {
-			position: Vector3
-		}
-
-		Frog :: struct {
-			using entity: Entity,
-			jump_height: f32,
-		}
-
-		f: Frog;
-		f.position = Vector3{1, 2, 3};
-
-
-		print_pos :: proc(using entity: Entity) {
-			print("print_pos: ");
-			print_floats(position.x, position.y, position.z);
-		}
-
-		print_pos(f.entity);
-		// print_pos(f);
-
-		// Subtype Polymorphism
-	}
-
-	{
-		// More than C++ way for subtyping/subclassing
-
-		Entity :: struct {
-			position: Vector3,
-		}
-
-		Frog :: struct {
-			jump_height: f32,
-			using entity: ^Entity, // Doesn't have to be first member!
-		}
-
-		f: Frog;
-		f.entity = new(Entity);
-		f.position = Vector3{1, 2, 3};
-
-
-		print_pos :: proc(using entity: ^Entity) {
-			print("print_pos: ");
-			print_floats(position.x, position.y, position.z);
-		}
-
-		print_pos(f.entity);
-		// print_pos(^f);
-		// print_pos(f);
-	}
-
-	{
-		// More efficient subtyping
-
-		Entity :: struct {
-			position: Vector3,
-		}
-
-		Frog :: struct {
-			jump_height: f32,
-			using entity: ^Entity,
-		}
-
-		MAX_ENTITES :: 64;
-		entities: [MAX_ENTITES]Entity;
-		entity_count := 0;
-
-		next_entity :: proc(entities: []Entity, entity_count: ^int) -> ^Entity {
-			e := &entities[entity_count^];
-			entity_count^ += 1;
-			return e;
-		}
-
-		f: Frog;
-		f.entity = next_entity(entities[..], &entity_count);
-		f.position = Vector3{3, 4, 6};
-
-		using f.position;
-		print_floats(x, y, z);
-	}
-
-	/*{
-		// Down casting
-
-		Entity :: struct {
-			position: Vector3,
-		}
-
-		Frog :: struct {
-			jump_height: f32,
-			using entity: Entity,
-		}
-
-		f: Frog;
-		f.jump_height = 564;
-		e := ^f.entity;
-
-		frog := down_cast(^Frog)e;
-		print("down_cast: ");
-		print(frog.jump_height); nl();
-
-		// NOTE(bill): `down_cast` is unsafe and there are not check are compile time or run time
-		// Q: Should I completely remove `down_cast` as I added it in about 30 minutes
-	}*/
-
-	{
-		// Multiple "inheritance"/subclassing
-
-		Entity :: struct {
-			position: Vector3,
-		}
-		Climber :: struct {
-			speed: f32,
-		}
-
-		Frog :: struct {
-			using entity:  Entity,
-			using climber: Climber,
-		}
-	}
-}
-
-tagged_unions :: proc() {
-	{
-		Entity_Kind :: enum {
-			INVALID,
-			FROG,
-			GIRAFFE,
-			HELICOPTER,
-		}
-
-		Entity :: struct {
-			kind: Entity_Kind
-			using data: struct #raw_union {
-				frog: struct {
-					jump_height: f32,
-					colour: u32,
-				},
-				giraffe: struct {
-					neck_length: f32,
-					spot_count: int,
-				},
-				helicopter: struct {
-					blade_count: int,
-					weight: f32,
-					pilot_name: string,
-				},
-			}
-		}
-
-		e: Entity;
-		e.kind = Entity_Kind.FROG;
-		e.frog.jump_height = 12;
-
-		f: type_of(e.frog);
-
-		// But this is very unsafe and extremely cumbersome to write
-		// In C++, I use macros to alleviate this but it's not a solution
-	}
-
-	{
-		Frog :: struct {
-			jump_height: f32,
-			colour: u32,
-		}
-		Giraffe :: struct {
-			neck_length: f32,
-			spot_count: int,
-		}
-		Helicopter :: struct {
-			blade_count: int,
-			weight: f32,
-			pilot_name: string,
-		}
-		Entity :: union {Frog, Giraffe, Helicopter};
-
-		f1: Frog = Frog{12, 0xff9900};
-		f2: Entity = Frog{12, 0xff9900}; // Implicit cast
-		f3 := cast(Entity)Frog{12, 0xff9900}; // Explicit cast
-
-		// f3.Frog.jump_height = 12 // There are "members" of a union
-
-
-
-		e, f, g, h: Entity;
-		f = Frog{12, 0xff9900};
-		g = Giraffe{2.1, 23};
-		h = Helicopter{4, 1000, "Frank"};
-
-
-
-
-		// Requires a pointer to the union
-		// `x` will be a pointer to type of the case
-
-		match x in &f {
-		case Frog:
-			print("Frog!\n");
-			print(x.jump_height); nl();
-			// x.jump_height = 3;
-			print(x.jump_height); nl();
-		case Giraffe:
-			print("Giraffe!\n");
-		case Helicopter:
-			print("ROFLCOPTER!\n");
-		case:
-			print("invalid entity\n");
-		}
-
-
-		// Q: Allow for a non pointer version with takes a copy instead?
-		// Or it takes the pointer the data and not a copy
-
-
-		// fp := cast(^Frog)^f; // Unsafe
-		// print(fp.jump_height); nl();
-
-
-		// Internals of a tagged union
-		/*
-			struct {
-				data: [size_of_biggest_tag]u8,
-				tag_index: int,
-			}
-		*/
-		// This is to allow for pointer casting if needed
-
-
-		// Advantage over subtyping version
-		MAX_ENTITES :: 64;
-		entities: [MAX_ENTITES]Entity;
-
-		entities[0] = Frog{};
-		entities[1] = Helicopter{};
-		// etc.
-	}
-
-
-	{
-		// Transliteration of code from this actual compiler
-		// Some stuff is missing
-		Type       :: struct {};
-		Scope      :: struct {};
-		Token      :: struct {};
-		AstNode    :: struct {};
-		ExactValue :: struct {};
-
-		Entity_Kind :: enum {
-			Invalid,
-			Constant,
-			Variable,
-			Using_Variable,
-			TypeName,
-			Procedure,
-			Builtin,
-			Count,
-		}
-
-		Guid :: i64;
-		Entity :: struct {
-
-			kind: Entity_Kind,
-			guid: Guid,
-
-			scope: ^Scope,
-			token: Token,
-			type_: ^Type,
-
-			using data: struct #raw_union {
-				Constant: struct {
-					value: ExactValue,
-				},
-				Variable: struct {
-					visited:   bool, // Cycle detection
-					used:      bool, // Variable is used
-					is_field:  bool, // Is struct field
-					anonymous: bool, // Variable is an anonymous
-				},
-				Using_Variable: struct {
-				},
-				TypeName: struct {
-				},
-				Procedure: struct {
-					used: bool,
-				},
-				Builtin: struct {
-					id: int,
-				},
-			},
-		}
-
-		// Plus all the constructing procedures that go along with them!!!!
-		// It's a nightmare
-	}
-
-	{
-		Type       :: struct {};
-		Scope      :: struct {};
-		Token      :: struct {};
-		AstNode    :: struct {};
-		ExactValue :: struct {};
-
-
-		Guid :: i64;
-		Entity_Base :: struct {
-		}
-
-
-		Constant :: struct {
-			value: ExactValue,
-		}
-		Variable :: struct {
-			visited:   bool, // Cycle detection
-			used:      bool, // Variable is used
-			is_field:  bool, // Is struct field
-			anonymous: bool, // Variable is an anonymous
-		}
-		Using_Variable :: struct {
-		}
-		TypeName :: struct {
-		}
-		Procedure :: struct {
-			used: bool,
-		}
-		Builtin :: struct {
-			id: int,
-		}
-
-		Entity :: struct {
-			guid: Guid,
-
-			scope: ^Scope,
-			token: Token,
-			type_: ^Type,
-
-			variant: union {Constant, Variable, Using_Variable, TypeName, Procedure, Builtin},
-		}
-
-		e := Entity{
-			variant = Variable{
-				used = true,
-				anonymous = false,
-			},
-		};
-
-
-
-		// Q: Allow a "base" type to be added to a union?
-		// Or even `using` on union to get the same properties?
-	}
-
-
-	{
-		// `Raw` unions still have uses, especially for mathematic types
-
-		Vector2 :: struct #raw_union {
-			using xy_: struct { x, y: f32 },
-			e: [2]f32,
-			v: [vector 2]f32,
-		}
-
-		Vector3 :: struct #raw_union {
-			using xyz_: struct { x, y, z: f32 },
-			xy: Vector2,
-			e: [3]f32,
-			v: [vector 3]f32,
-		}
-
-		v2: Vector2;
-		v2.x = 1;
-		v2.e[0] = 1;
-		v2.v[0] = 1;
-
-		v3: Vector3;
-		v3.x = 1;
-		v3.e[0] = 1;
-		v3.v[0] = 1;
-		v3.xy.x = 1;
-	}
-}
-
-nl :: proc() { println(); }

+ 0 - 66
misc/old_demos/demo004.odin

@@ -1,66 +0,0 @@
-import "core:fmt.odin";
-import "core:utf8.odin";
-import "core:hash.odin";
-import "core:mem.odin";
-
-main :: proc() {
-	{ // New Standard Library stuff
-		s := "Hello";
-		fmt.println(s,
-		            utf8.valid_string(s),
-		            hash.murmur64(cast([]u8)s));
-
-		// utf8.odin
-		// hash.odin
-		//     - crc, fnv, fnva, murmur
-		// mem.odin
-		//     - Custom allocators
-		//     - Helpers
-	}
-
-	{
-		arena: mem.Arena;
-		mem.init_arena_from_context(&arena, mem.megabytes(16)); // Uses default allocator
-		defer mem.destroy_arena(&arena);
-
-		push_allocator mem.arena_allocator(&arena) {
-			x := new(int);
-			x^ = 1337;
-
-			fmt.println(x^);
-		}
-
-		/*
-			push_allocator x {
-				..
-			}
-
-			is equivalent to:
-
-			{
-				prev_allocator := __context.allocator
-				__context.allocator = x
-				defer __context.allocator = prev_allocator
-
-				..
-			}
-		*/
-
-		// You can also "push" a context
-
-		c := context; // Create copy of the allocator
-		c.allocator = mem.arena_allocator(&arena);
-
-		push_context c {
-			x := new(int);
-			x^ = 365;
-
-			fmt.println(x^);
-		}
-	}
-
-	// Backend improvements
-	// - Minimal dependency building (only build what is needed)
-	// - Numerous bugs fixed
-	// - Mild parsing recovery after bad syntax error
-}

+ 0 - 283
misc/old_demos/demo005.odin

@@ -1,283 +0,0 @@
-import "core:fmt.odin";
-import "core:utf8.odin";
-// import "core:atomic.odin";
-// import "core:hash.odin";
-// import "core:math.odin";
-// import "core:mem.odin";
-// import "core:opengl.odin";
-// import "core:os.odin";
-// import "core:sync.odin";
-// import win32 "core:sys/windows.odin";
-
-main :: proc() {
-	// syntax();
-	procedure_overloading();
-}
-
-syntax :: proc() {
-	// Cyclic type checking
-	// Uncomment to see the error
-	// A :: struct {b: B};
-	// B :: struct {a: A};
-
-	x: int;
-	y := cast(f32)x;
-	z := transmute(u32)y;
-	// down_cast, union_cast are similar too
-
-
-
-	// Basic directives
-	fmt.printf("Basic directives = %s(%d): %s\n", #file, #line, #procedure);
-	// NOTE: new and improved `printf`
-	// TODO: It does need accurate float printing
-
-
-
-	// record fields use the same syntax a procedure signatures
-	Thing1 :: struct {
-		x: f32,
-		y: int,
-		z: ^[]int,
-	};
-	Thing2 :: struct {x: f32, y: int, z: ^[]int};
-
-	// Slice interals are now just a `ptr+len+cap`
-	slice: []int; #assert(size_of(slice) == 3*size_of(int));
-
-	// Helper type - Help the reader understand what it is quicker
-	My_Int  :: #type int;
-	My_Proc :: #type proc(int) -> f32;
-
-
-	// All declarations with : are either variable or constant
-	// To make these declarations syntactically consistent
-	v_variable := 123;
-	c_constant :: 123;
-	c_type1    :: int;
-	c_type2    :: []int;
-	c_proc     :: proc() { /* code here */ };
-
-
-/*
-	x += 1;
-	x -= 1;
-	// ++ and -- have been removed
-	// x++;
-	// x--;
-	// Question: Should they be added again?
-	// They were removed as they are redundant and statements, not expressions
-	// like in C/C++
-*/
-
-	// You can now build files as a `.dll`
-	// `odin build_dll demo.odin`
-
-
-	// New vector syntax
-	u, v: [vector 3]f32;
-	v[0] = 123;
-	v.x  = 123; // valid for all vectors with count 1 to 4
-
-	// Next part
-	prefixes();
-}
-
-
-Prefix_Type :: struct {x: int, y: f32, z: rawptr};
-
-#thread_local my_tls: Prefix_Type;
-
-prefixes :: proc() {
-	using var: Prefix_Type;
-	var.x = 123;
-	x = 123;
-
-
-	foo :: proc(using pt: Prefix_Type) {
-	}
-
-
-
-	// Same as C99's `restrict`
-	bar :: proc(#no_alias a, b: ^int) {
-		// Assumes a never equals b so it can perform optimizations with that fact
-	}
-
-
-	when_statements();
-}
-
-
-
-
-
-when_statements :: proc() {
-	X :: 123 + 12;
-	Y :: X/5;
-	COND :: Y > 0;
-
-	when COND {
-		fmt.println("Y > 0");
-	} else {
-		fmt.println("Y <= 0");
-	}
-
-
-	when false {
-		this_code_does_not_exist(123, 321);
-		but_its_syntax_is_valid();
-		x :: ^^^^int;
-	}
-
-	foreign_procedures();
-}
-
-when ODIN_OS == "windows" {
-	foreign_system_library win32_user "user32.lib";
-}
-// NOTE: This is done on purpose for two reasons:
-// * Makes it clear where the platform specific stuff is
-// * Removes the need to solve the travelling salesman problem when importing files :P
-
-foreign_procedures :: proc() {
-	foreign win32_user {
-		ShowWindow  :: proc(hwnd: rawptr, cmd_show: i32) -> i32 ---;
-		show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #link_name "ShowWindow" ---;
-	}
-	// NOTE: If that library doesn't get used, it doesn't get linked with
-	// NOTE: There is not link checking yet to see if that procedure does come from that library
-
-	// See sys/windows.odin for more examples
-
-	special_expressions();
-}
-
-special_expressions :: proc() {
-/*
-	// Block expression
-	x := {
-		a: f32 = 123;
-		b := a-123;
-		c := b/a;
-		give c;
-	}; // semicolon is required as it's an expression
-
-	y := if x < 50 {
-		give x;
-	} else {
-		// TODO: Type cohesion is not yet finished
-		give 123;
-	}; // semicolon is required as it's an expression
-*/
-
-	// This is allows for inline blocks of code and will be a useful feature to have when
-	// macros will be implemented into the language
-
-	loops();
-}
-
-loops :: proc() {
-	// The C-style for loop
-	for i := 0; i < 123; i += 1 {
-		break;
-	}
-	for i := 0; i < 123; {
-		break;
-	}
-	for false {
-		break;
-	}
-	for {
-		break;
-	}
-
-	for i in 0..123 { // 123 exclusive
-	}
-
-	for i in 0..123-1 { // 122 inclusive
-	}
-
-	for val, idx in 12..16 {
-		fmt.println(val, idx);
-	}
-
-	primes := [?]int{2, 3, 5, 7, 11, 13, 17, 19};
-
-	for p in primes {
-		fmt.println(p);
-	}
-
-	// Pointers to arrays, slices, or strings are allowed
-	for _ in &primes {
-		// ignore the value and just iterate across it
-	}
-
-
-
-	name := "你好,世界";
-	fmt.println(name);
-	for r in name {
-		#assert(type_of(r) == rune);
-		fmt.printf("%r\n", r);
-	}
-
-	when false {
-		for i, size := 0; i < name.count; i += size {
-			r: rune;
-			r, size = utf8.decode_rune(name[i..]);
-			fmt.printf("%r\n", r);
-		}
-	}
-
-	procedure_overloading();
-}
-
-
-procedure_overloading :: proc() {
-	THINGF :: 14451.1;
-	THINGI :: 14451;
-
-	foo :: proc() {
-		fmt.printf("Zero args\n");
-	}
-	foo :: proc(i: int) {
-		fmt.printf("int arg, i=%d\n", i);
-	}
-	foo :: proc(f: f64) {
-		i := cast(int)f;
-		fmt.printf("f64 arg, f=%d\n", i);
-	}
-
-	foo();
-	foo(THINGF);
-	// foo(THINGI); // 14451 is just a number so it could go to either procedures
-	foo(cast(int)THINGI);
-
-
-
-
-	foo :: proc(x: ^i32) -> (int, int) {
-		fmt.println("^int");
-		return 123, cast(int)(x^);
-	}
-	foo :: proc(x: rawptr) {
-		fmt.println("rawptr");
-	}
-
-
-	a: i32 = 123;
-	b: f32;
-	c: rawptr;
-	fmt.println(foo(&a));
-	foo(&b);
-	foo(c);
-	// foo(nil); // nil could go to numerous types thus the ambiguity
-
-	f: proc();
-	f = foo; // The correct `foo` to chosen
-	f();
-
-
-	// See math.odin and atomic.odin for more examples
-}

+ 0 - 310
misc/old_demos/demo006.odin

@@ -1,310 +0,0 @@
-// import "core:atomic.odin";
-import "core:hash.odin";
-import "core:mem.odin";
-import "core:opengl.odin";
-import "core:strconv.odin";
-import "core:sync.odin";
-import win32 "core:sys/windows.odin";
-
-import "core:fmt.odin";
-import "core:os.odin";
-import "core:math.odin";
-
-
-main :: proc() {
-when true {
-/*
-	Added:
-		* Unexported entities and fields using an underscore prefix
-			- See `sync.odin` and explain
-
-	Removed:
-	 * Maybe/option types
-	 * Remove `type` keyword and other "reserved" keywords
-	 * ..< and .. removed and replace with .. (half-closed range)
-
-	Changed:
-	 * `#assert` and `assert` return the value of the condition for semantic reasons
-	 * thread_local -> #thread_local
-	 * #include -> #load
-	 * Files only get checked if they are actually used
-	 * match x in y {} // For type match statements
-	 * Version numbering now starts from 0.1.0 and uses the convention:
-	 	- major.minor.patch
-	 * Core library additions to Windows specific stuff
- */
-
-	{
-		Fruit :: enum {
-			APPLE,
-			BANANA,
-			COCONUT,
-		}
-		fmt.println(Fruit.names);
-	}
-
-	{
-		A :: struct           {x, y: f32};
-		B :: struct #align 16 {x, y: f32};
-		fmt.println("align_of(A) =", align_of(A));
-		fmt.println("align_of(B) =", align_of(B));
-	}
-
-	{
-		// Removal of ..< and ..
-		for i in 0..16 {
-		}
-		// Is similar to
-		for i := 0; i < 16; i += 1 {
-		}
-	}
-
-	{
-		thing: for i in 0..10 {
-			for j in i+1..10 {
-				if j == 2 {
-					fmt.println(i, j);
-					continue thing;
-				}
-				if j == 3 {
-					break thing;
-				}
-			}
-		}
-
-		// Works with, `for`, `for in`, `match`, `match in`
-		// NOTE(bill): This solves most of the problems I need `goto` for
-	}
-
-	{
-		t := type_info_of(int);
-		match i in t.variant {
-		case Type_Info_Integer, Type_Info_Float:
-			fmt.println("It's a number");
-		}
-
-
-		x: any = 123;
-		foo: match i in x {
-		case int, f32:
-			fmt.println("It's an int or f32");
-			break foo;
-		}
-	}
-
-	{
-		cond := true;
-		x: int;
-		if cond {
-			x = 3;
-		} else {
-			x = 4;
-		}
-
-
-		// Ternary operator
-		y := cond ? 3 : 4;
-
-		FOO :: true ? 123 : 432; // Constant ternary expression
-		fmt.println("Ternary values:", y, FOO);
-	}
-
-	{
-		// Slices now store a capacity
-		buf: [256]u8;
-		s: []u8;
-		s = buf[..0]; // == buf[0..0];
-		fmt.println("count =", len(s));
-		fmt.println("capacity =", cap(s));
-		append(&s, 1, 2, 3);
-		fmt.println(s);
-
-		s = buf[1..2..3];
-		fmt.println("count =", len(s));
-		fmt.println("capacity =", cap(s));
-		fmt.println(s);
-
-		clear(&s); // Sets count to zero
-	}
-
-	{
-		Foo :: struct {
-			x, y, z: f32,
-			ok:      bool,
-			flags:   u32,
-		}
-		foo_array: [256]Foo;
-		foo_as_bytes: []u8 = mem.slice_to_bytes(foo_array[..]);
-		// Useful for things like
-		// os.write(handle, foo_as_bytes);
-
-		foo_slice := mem.slice_ptr(cast(^Foo)&foo_as_bytes[0], len(foo_as_bytes)/size_of(Foo), cap(foo_as_bytes)/size_of(Foo));
-		// Question: Should there be a bytes_to_slice procedure or is it clearer to do this even if it is error prone?
-		// And if so what would the syntax be?
-		// slice_transmute([]Foo, foo_as_bytes);
-	}
-
-	{
-		Vec3 :: [vector 3]f32;
-
-		x := Vec3{1, 2, 3};
-		y := Vec3{4, 5, 6};
-		fmt.println(x < y);
-		fmt.println(x + y);
-		fmt.println(x - y);
-		fmt.println(x * y);
-		fmt.println(x / y);
-
-		for i in x {
-			fmt.println(i);
-		}
-
-		#assert(size_of([vector 7]bool) >= size_of([7]bool));
-		#assert(size_of([vector 7]i32) >= size_of([7]i32));
-		// align_of([vector 7]i32) != align_of([7]i32) // this may be the case
-	}
-
-	{
-		// fmt.* changes
-		// bprint* returns `string`
-
-		data: [256]u8;
-		str := fmt.bprintf(data[..], "Hellope %d %s %c", 123, "others", '!');
-		fmt.println(str);
-	}
-
-	{
-		x: [dynamic]f64;
-		reserve(&x, 16);
-		defer free(x); // `free` is overloaded for numerous types
-		// Number literals can have underscores in them for readability
-		append(&x, 2_000_000.500_000, 123, 5, 7); // variadic append
-
-		for p, i in x {
-			if i > 0 { fmt.print(", "); }
-			fmt.print(p);
-		}
-		fmt.println();
-	}
-
-	{
-		// Dynamic array "literals"
-		x := [dynamic]f64{2_000_000.500_000, 3, 5, 7};
-		defer free(x);
-		fmt.println(x); // fmt.print* supports printing of dynamic types
-		clear(&x);
-		fmt.println(x);
-	}
-
-	{
-		m: map[f32]int;
-		reserve(&m, 16);
-		defer free(m);
-
-		m[1.0] = 1278;
-		m[2.0] = 7643;
-		m[3.0] = 564;
-		_, ok := m[3.0];
-		c := m[3.0];
-		assert(ok && c == 564);
-
-		fmt.print("map[");
-		i := 0;
-		for val, key in m {
-			if i > 0 {
-				fmt.print(", ");
-			}
-			fmt.printf("%v=%v", key, val);
-			i += 1;
-		}
-		fmt.println("]");
-	}
-	{
-		m := map[string]u32{
-			"a" = 56,
-			"b" = 13453,
-			"c" = 7654,
-		};
-		defer free(m);
-
-		c := m["c"];
-		_, ok := m["c"];
-		assert(ok && c == 7654);
-		fmt.println(m);
-
-		delete(&m, "c"); // deletes entry with key "c"
-		_, found := m["c"];
-		assert(!found);
-
-		fmt.println(m);
-		clear(&m);
-		fmt.println(m);
-
-		// NOTE: Fixed size maps are planned but we have not yet implemented
-		// them as we have had no need for them as of yet
-	}
-
-	{
-		Vector3 :: struct{x, y, z: f32};
-		Quaternion :: struct{x, y, z, w: f32};
-
-		// Variants
-		Frog :: struct {
-			ribbit_volume: f32,
-			jump_height:   f32,
-		}
-		Door :: struct {
-			openness: f32,
-		}
-		Map :: struct {
-			width, height:   f32,
-			place_positions: []Vector3,
-			place_names:     []string,
-		}
-
-		Entity :: struct {
-			// Common Fields
-			id:             u64,
-			name:           string,
-			using position: Vector3,
-			orientation:    Quaternion,
-			flags:          u32,
-
-			variant: union { Frog, Door, Map },
-		}
-
-		entity: Entity;
-		entity.id = 1337;
-		// implicit conversion from variant to base type
-		entity.variant = Frog{
-			ribbit_volume = 0.5,
-			jump_height = 2.1,
-			/*other data */
-		};
-
-		entity.name = "Frank";
-		entity.position = Vector3{1, 4, 9};
-
-		match e in entity.variant {
-		case Frog:
-			fmt.println("Ribbit");
-		case Door:
-			fmt.println("Creak");
-		case Map:
-			fmt.println("Rustle");
-		case:
-			fmt.println("Just a normal entity");
-		}
-
-		if frog, ok := entity.variant.(Frog); ok {
-			fmt.printf("The frog jumps %f feet high at %v\n", frog.jump_height, entity.position);
-		}
-
-		// Panics if not the correct type
-		frog: Frog;
-		frog = entity.variant.(Frog);
-		frog, _ = entity.variant.(Frog); // ignore error and force cast
-	}
-}
-}
-

+ 0 - 570
misc/old_demos/demo007.odin

@@ -1,570 +0,0 @@
-import "core:fmt.odin"
-import "core:strconv.odin"
-import "core:mem.odin"
-import "core:bits.odin"
-import "core:hash.odin"
-import "core:math.odin"
-import "core:os.odin"
-import "core:raw.odin"
-import "core:sort.odin"
-import "core:strings.odin"
-import "core:types.odin"
-import "core:utf16.odin"
-import "core:utf8.odin"
-
-when ODIN_OS == "windows" {
-	import "core:atomics.odin"
-	import "core:opengl.odin"
-	import "core:thread.odin"
-	import win32 "core:sys/windows.odin"
-}
-
-general_stuff :: proc() {
-	{ // `do` for inline statmes rather than block
-		foo :: proc() do fmt.println("Foo!");
-		if   false do foo();
-		for  false do foo();
-		when false do foo();
-
-		if false do foo();
-		else     do foo();
-	}
-
-	{ // Removal of `++` and `--` (again)
-		x: int;
-		x += 1;
-		x -= 1;
-	}
-	{ // Casting syntaxes
-		i := i32(137);
-		ptr := &i;
-
-		fp1 := (^f32)(ptr);
-		// ^f32(ptr) == ^(f32(ptr))
-		fp2 := cast(^f32)ptr;
-
-		f1 := (^f32)(ptr)^;
-		f2 := (cast(^f32)ptr)^;
-
-		// Questions: Should there be two ways to do it?
-	}
-
-	/*
-	 * Remove *_val_of built-in procedures
-	 * size_of, align_of, offset_of
-	 * type_of, type_info_of
-	 */
-
-	{ // `expand_to_tuple` built-in procedure
-		Foo :: struct {
-			x: int,
-			b: bool,
-		}
-		f := Foo{137, true};
-		x, b := expand_to_tuple(f);
-		fmt.println(f);
-		fmt.println(x, b);
-		fmt.println(expand_to_tuple(f));
-	}
-
-	{
-		// ..  half-closed range
-		// .. open range
-
-		for in 0..2  {} // 0, 1
-		for in 0..2 {} // 0, 1, 2
-	}
-}
-
-default_struct_values :: proc() {
-	{
-		Vector3 :: struct {
-			x: f32,
-			y: f32,
-			z: f32,
-		}
-		v: Vector3;
-		fmt.println(v);
-	}
-	{
-		// Default values must be constants
-		Vector3 :: struct {
-			x: f32 = 1,
-			y: f32 = 4,
-			z: f32 = 9,
-		}
-		v: Vector3;
-		fmt.println(v);
-
-		v = Vector3{};
-		fmt.println(v);
-
-		// Uses the same semantics as a default values in a procedure
-		v = Vector3{137};
-		fmt.println(v);
-
-		v = Vector3{z = 137};
-		fmt.println(v);
-	}
-
-	{
-		Vector3 :: struct {
-			x := 1.0,
-			y := 4.0,
-			z := 9.0,
-		}
-		stack_default: Vector3;
-		stack_literal := Vector3{};
-		heap_one      := new(Vector3);         defer free(heap_one);
-		heap_two      := new_clone(Vector3{}); defer free(heap_two);
-
-		fmt.println("stack_default - ", stack_default);
-		fmt.println("stack_literal - ", stack_literal);
-		fmt.println("heap_one      - ", heap_one^);
-		fmt.println("heap_two      - ", heap_two^);
-
-
-		N :: 4;
-		stack_array: [N]Vector3;
-		heap_array := new([N]Vector3);    defer free(heap_array);
-		heap_slice := make([]Vector3, N); defer free(heap_slice);
-		fmt.println("stack_array[1] - ", stack_array[1]);
-		fmt.println("heap_array[1]  - ", heap_array[1]);
-		fmt.println("heap_slice[1]  - ", heap_slice[1]);
-	}
-}
-
-
-
-
-union_type :: proc() {
-	{
-		val: union{int, bool};
-		val = 137;
-		if i, ok := val.(int); ok {
-			fmt.println(i);
-		}
-		val = true;
-		fmt.println(val);
-
-		val = nil;
-
-		switch v in val {
-		case int:  fmt.println("int",  v);
-		case bool: fmt.println("bool", v);
-		case:      fmt.println("nil");
-		}
-	}
-	{
-		// There is a duality between `any` and `union`
-		// An `any` has a pointer to the data and allows for any type (open)
-		// A `union` has as binary blob to store the data and allows only certain types (closed)
-		// The following code is with `any` but has the same syntax
-		val: any;
-		val = 137;
-		if i, ok := val.(int); ok {
-			fmt.println(i);
-		}
-		val = true;
-		fmt.println(val);
-
-		val = nil;
-
-		switch v in val {
-		case int:  fmt.println("int",  v);
-		case bool: fmt.println("bool", v);
-		case:      fmt.println("nil");
-		}
-	}
-
-	Vector3 :: struct {x, y, z: f32};
-	Quaternion :: struct {x, y, z: f32, w: f32 = 1};
-
-	// More realistic examples
-	{
-		// NOTE(bill): For the above basic examples, you may not have any
-		// particular use for it. However, my main use for them is not for these
-		// simple cases. My main use is for hierarchical types. Many prefer
-		// subtyping, embedding the base data into the derived types. Below is
-		// an example of this for a basic game Entity.
-
-		Entity :: struct {
-			id:          u64,
-			name:        string,
-			position:    Vector3,
-			orientation: Quaternion,
-
-			derived: any,
-		}
-
-		Frog :: struct {
-			using entity: Entity,
-			jump_height:  f32,
-		}
-
-		Monster :: struct {
-			using entity: Entity,
-			is_robot:     bool,
-			is_zombie:    bool,
-		}
-
-		// See `parametric_polymorphism` procedure for details
-		new_entity :: proc(T: type) -> ^Entity {
-			t := new(T);
-			t.derived = t^;
-			return t;
-		}
-
-		entity := new_entity(Monster);
-
-		switch e in entity.derived {
-		case Frog:
-			fmt.println("Ribbit");
-		case Monster:
-			if e.is_robot  do fmt.println("Robotic");
-			if e.is_zombie do fmt.println("Grrrr!");
-		}
-	}
-
-	{
-		// NOTE(bill): A union can be used to achieve something similar. Instead
-		// of embedding the base data into the derived types, the derived data
-		// in embedded into the base type. Below is the same example of the
-		// basic game Entity but using an union.
-
-		Entity :: struct {
-			id:          u64,
-			name:        string,
-			position:    Vector3,
-			orientation: Quaternion,
-
-			derived: union {Frog, Monster},
-		}
-
-		Frog :: struct {
-			using entity: ^Entity,
-			jump_height:  f32,
-		}
-
-		Monster :: struct {
-			using entity: ^Entity,
-			is_robot:     bool,
-			is_zombie:    bool,
-		}
-
-		// See `parametric_polymorphism` procedure for details
-		new_entity :: proc(T: type) -> ^Entity {
-			t := new(Entity);
-			t.derived = T{entity = t};
-			return t;
-		}
-
-		entity := new_entity(Monster);
-
-		switch e in entity.derived {
-		case Frog:
-			fmt.println("Ribbit");
-		case Monster:
-			if e.is_robot  do fmt.println("Robotic");
-			if e.is_zombie do fmt.println("Grrrr!");
-		}
-
-		// NOTE(bill): As you can see, the usage code has not changed, only its
-		// memory layout. Both approaches have their own advantages but they can
-		// be used together to achieve different results. The subtyping approach
-		// can allow for a greater control of the memory layout and memory
-		// allocation, e.g. storing the derivatives together. However, this is
-		// also its disadvantage. You must either preallocate arrays for each
-		// derivative separation (which can be easily missed) or preallocate a
-		// bunch of "raw" memory; determining the maximum size of the derived
-		// types would require the aid of metaprogramming. Unions solve this
-		// particular problem as the data is stored with the base data.
-		// Therefore, it is possible to preallocate, e.g. [100]Entity.
-
-		// It should be noted that the union approach can have the same memory
-		// layout as the any and with the same type restrictions by using a
-		// pointer type for the derivatives.
-
-		/*
-			Entity :: struct {
-				..
-				derived: union{^Frog, ^Monster};
-			}
-
-			Frog :: struct {
-				using entity: Entity;
-				..
-			}
-			Monster :: struct {
-				using entity: Entity;
-				..
-
-			}
-			new_entity :: proc(T: type) -> ^Entity {
-				t := new(T);
-				t.derived = t;
-				return t;
-			}
-		*/
-	}
-}
-
-parametric_polymorphism :: proc() {
-	print_value :: proc(value: $T) {
-		fmt.printf("print_value: %T %v\n", value, value);
-	}
-
-	v1: int    = 1;
-	v2: f32    = 2.1;
-	v3: f64    = 3.14;
-	v4: string = "message";
-
-	print_value(v1);
-	print_value(v2);
-	print_value(v3);
-	print_value(v4);
-
-	fmt.println();
-
-	add :: proc(p, q: $T) -> T {
-		x: T = p + q;
-		return x;
-	}
-
-	a := add(3, 4);
-	fmt.printf("a: %T = %v\n", a, a);
-
-	b := add(3.2, 4.3);
-	fmt.printf("b: %T = %v\n", b, b);
-
-	// This is how `new` is implemented
-	alloc_type :: proc(T: type) -> ^T {
-		t := cast(^T)alloc(size_of(T), align_of(T));
-		t^ = T{}; // Use default initialization value
-		return t;
-	}
-
-	copy_slice :: proc(dst, src: []$T) -> int {
-		n := min(len(dst), len(src));
-		if n > 0 {
-			mem.copy(&dst[0], &src[0], n*size_of(T));
-		}
-		return n;
-	}
-
-	double_params :: proc(a: $A, b: $B) -> A {
-		return a + A(b);
-	}
-
-	fmt.println(double_params(12, 1.345));
-
-
-
-	{ // Polymorphic Types and Type Specialization
-		Table_Slot :: struct(Key, Value: type) {
-			occupied: bool,
-			hash:     u32,
-			key:      Key,
-			value:    Value,
-		}
-		TABLE_SIZE_MIN :: 32;
-		Table :: struct(Key, Value: type) {
-			count:     int,
-			allocator: Allocator,
-			slots:     []Table_Slot(Key, Value),
-		}
-
-		// Only allow types that are specializations of a (polymorphic) slice
-		make_slice :: proc(T: type/[]$E, len: int) -> T {
-			return make(T, len);
-		}
-
-
-		// Only allow types that are specializations of `Table`
-		allocate :: proc(table: ^$T/Table, capacity: int) {
-			c := context;
-			if table.allocator.procedure != nil do c.allocator = table.allocator;
-
-			push_context c {
-				table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN));
-			}
-		}
-
-		expand :: proc(table: ^$T/Table) {
-			c := context;
-			if table.allocator.procedure != nil do c.allocator = table.allocator;
-
-			push_context c {
-				old_slots := table.slots;
-
-				cap := max(2*cap(table.slots), TABLE_SIZE_MIN);
-				allocate(table, cap);
-
-				for s in old_slots do if s.occupied {
-					put(table, s.key, s.value);
-				}
-
-				free(old_slots);
-			}
-		}
-
-		// Polymorphic determination of a polymorphic struct
-		// put :: proc(table: ^$T/Table, key: T.Key, value: T.Value) {
-		put :: proc(table: ^Table($Key, $Value), key: Key, value: Value) {
-			hash := get_hash(key); // Ad-hoc method which would fail in a different scope
-			index := find_index(table, key, hash);
-			if index < 0 {
-				if f64(table.count) >= 0.75*f64(cap(table.slots)) {
-					expand(table);
-				}
-				assert(table.count <= cap(table.slots));
-
-				hash := get_hash(key);
-				index = int(hash % u32(cap(table.slots)));
-
-				for table.slots[index].occupied {
-					if index += 1; index >= cap(table.slots) {
-						index = 0;
-					}
-				}
-
-				table.count += 1;
-			}
-
-			slot := &table.slots[index];
-			slot.occupied = true;
-			slot.hash     = hash;
-			slot.key      = key;
-			slot.value    = value;
-		}
-
-
-		// find :: proc(table: ^$T/Table, key: T.Key) -> (T.Value, bool) {
-		find :: proc(table: ^Table($Key, $Value), key: Key) -> (Value, bool) {
-			hash := get_hash(key);
-			index := find_index(table, key, hash);
-			if index < 0 {
-				return Value{}, false;
-			}
-			return table.slots[index].value, true;
-		}
-
-		find_index :: proc(table: ^Table($Key, $Value), key: Key, hash: u32) -> int {
-			if cap(table.slots) <= 0 do return -1;
-
-			index := int(hash % u32(cap(table.slots)));
-			for table.slots[index].occupied {
-				if table.slots[index].hash == hash {
-					if table.slots[index].key == key {
-						return index;
-					}
-				}
-
-				if index += 1; index >= cap(table.slots) {
-					index = 0;
-				}
-			}
-
-			return -1;
-		}
-
-		get_hash :: proc(s: string) -> u32 { // fnv32a
-			h: u32 = 0x811c9dc5;
-			for i in 0..len(s) {
-				h = (h ~ u32(s[i])) * 0x01000193;
-			}
-			return h;
-		}
-
-
-		table: Table(string, int);
-
-		for i in 0..36 do put(&table, "Hellope", i);
-		for i in 0..42 do put(&table, "World!",  i);
-
-		found, _ := find(&table, "Hellope");
-		fmt.printf("`found` is %v\n", found);
-
-		found, _ = find(&table, "World!");
-		fmt.printf("`found` is %v\n", found);
-
-		// I would not personally design a hash table like this in production
-		// but this is a nice basic example
-		// A better approach would either use a `u64` or equivalent for the key
-		// and let the user specify the hashing function or make the user store
-		// the hashing procedure with the table
-	}
-}
-
-
-
-
-prefix_table := [?]string{
-	"White",
-	"Red",
-	"Green",
-	"Blue",
-	"Octarine",
-	"Black",
-};
-
-threading_example :: proc() {
-	when ODIN_OS == "windows" {
-		unordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) {
-			__bounds_check_error_loc(loc, index, len(array));
-			array[index] = array[len(array)-1];
-			pop(array);
-		}
-		ordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) {
-			__bounds_check_error_loc(loc, index, len(array));
-			copy(array[index..], array[index+1..]);
-			pop(array);
-		}
-
-		worker_proc :: proc(t: ^thread.Thread) -> int {
-			for iteration in 1..5 {
-				fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration);
-				fmt.printf("`%s`: iteration %d\n", prefix_table[t.user_index], iteration);
-				// win32.sleep(1);
-			}
-			return 0;
-		}
-
-		threads := make([]^thread.Thread, 0, len(prefix_table));
-		defer free(threads);
-
-		for i in 0..len(prefix_table) {
-			if t := thread.create(worker_proc); t != nil {
-				t.init_context = context;
-				t.use_init_context = true;
-				t.user_index = len(threads);
-				append(&threads, t);
-				thread.start(t);
-			}
-		}
-
-		for len(threads) > 0 {
-			for i := 0; i < len(threads); /**/ {
-				if t := threads[i]; thread.is_done(t) {
-					fmt.printf("Thread %d is done\n", t.user_index);
-					thread.destroy(t);
-
-					ordered_remove(&threads, i);
-				} else {
-					i += 1;
-				}
-			}
-		}
-	}
-}
-
-main :: proc() {
-	when false {
-		fmt.println("\n# general_stuff");              general_stuff();
-		fmt.println("\n# default_struct_values");      default_struct_values();
-		fmt.println("\n# union_type");                 union_type();
-		fmt.println("\n# parametric_polymorphism");    parametric_polymorphism();
-		fmt.println("\n# threading_example");          threading_example();
-	}
-}
-

+ 0 - 778
misc/old_demos/demo008.odin

@@ -1,778 +0,0 @@
-import "core:fmt.odin"
-import "core:strconv.odin"
-import "core:mem.odin"
-import "core:bits.odin"
-import "core:hash.odin"
-import "core:math.odin"
-import "core:math/rand.odin"
-import "core:os.odin"
-import "core:raw.odin"
-import "core:sort.odin"
-import "core:strings.odin"
-import "core:types.odin"
-import "core:utf16.odin"
-import "core:utf8.odin"
-
-// File scope `when` statements
-when ODIN_OS == "windows" {
-	import "core:atomics.odin"
-	import "core:thread.odin"
-	import win32 "core:sys/windows.odin"
-}
-
-@(link_name="general_stuff")
-general_stuff :: proc() {
-	fmt.println("# general_stuff");
-	{ // `do` for inline statements rather than block
-		foo :: proc() do fmt.println("Foo!");
-		if   false do foo();
-		for  false do foo();
-		when false do foo();
-
-		if false do foo();
-		else     do foo();
-	}
-
-	{ // Removal of `++` and `--` (again)
-		x: int;
-		x += 1;
-		x -= 1;
-	}
-	{ // Casting syntaxes
-		i := i32(137);
-		ptr := &i;
-
-		_ = (^f32)(ptr);
-		// ^f32(ptr) == ^(f32(ptr))
-		_ = cast(^f32)ptr;
-
-		_ = (^f32)(ptr)^;
-		_ = (cast(^f32)ptr)^;
-
-		// Questions: Should there be two ways to do it?
-	}
-
-	/*
-	 * Remove *_val_of built-in procedures
-	 * size_of, align_of, offset_of
-	 * type_of, type_info_of
-	 */
-
-	{ // `expand_to_tuple` built-in procedure
-		Foo :: struct {
-			x: int,
-			b: bool,
-		}
-		f := Foo{137, true};
-		x, b := expand_to_tuple(f);
-		fmt.println(f);
-		fmt.println(x, b);
-		fmt.println(expand_to_tuple(f));
-	}
-
-	{
-		// ..  half-closed range
-		// .. open range
-
-		for in 0..2  {} // 0, 1
-		for in 0..2 {} // 0, 1, 2
-	}
-
-	{ // Multiple sized booleans
-
-		x0: bool; // default
-		x1: b8  = true;
-		x2: b16 = false;
-		x3: b32 = true;
-		x4: b64 = false;
-
-		fmt.printf("x1: %T = %v;\n", x1, x1);
-		fmt.printf("x2: %T = %v;\n", x2, x2);
-		fmt.printf("x3: %T = %v;\n", x3, x3);
-		fmt.printf("x4: %T = %v;\n", x4, x4);
-
-		// Having specific sized booleans is very useful when dealing with foreign code
-		// and to enforce specific alignment for a boolean, especially within a struct
-	}
-
-	{ // `distinct` types
-		// Originally, all type declarations would create a distinct type unless #type_alias was present.
-		// Now the behaviour has been reversed. All type declarations create a type alias unless `distinct` is present.
-		// If the type expression is `struct`, `union`, `enum`, or `proc`, the types will always been distinct.
-
-		Int32 :: i32;
-		#assert(Int32 == i32);
-
-		My_Int32 :: distinct i32;
-		#assert(My_Int32 != i32);
-
-		My_Struct :: struct{x: int};
-		#assert(My_Struct != struct{x: int});
-	}
-}
-
-default_struct_values :: proc() {
-	fmt.println("# default_struct_values");
-	{
-		Vector3 :: struct {
-			x: f32,
-			y: f32,
-			z: f32,
-		}
-		v: Vector3;
-		fmt.println(v);
-	}
-	{
-		// Default values must be constants
-		Vector3 :: struct {
-			x: f32 = 1,
-			y: f32 = 4,
-			z: f32 = 9,
-		}
-		v: Vector3;
-		fmt.println(v);
-
-		v = Vector3{};
-		fmt.println(v);
-
-		// Uses the same semantics as a default values in a procedure
-		v = Vector3{137};
-		fmt.println(v);
-
-		v = Vector3{z = 137};
-		fmt.println(v);
-	}
-
-	{
-		Vector3 :: struct {
-			x := 1.0,
-			y := 4.0,
-			z := 9.0,
-		}
-		stack_default: Vector3;
-		stack_literal := Vector3{};
-		heap_one      := new(Vector3);         defer free(heap_one);
-		heap_two      := new_clone(Vector3{}); defer free(heap_two);
-
-		fmt.println("stack_default  - ", stack_default);
-		fmt.println("stack_literal  - ", stack_literal);
-		fmt.println("heap_one       - ", heap_one^);
-		fmt.println("heap_two       - ", heap_two^);
-
-
-		N :: 4;
-		stack_array: [N]Vector3;
-		heap_array := new([N]Vector3);    defer free(heap_array);
-		heap_slice := make([]Vector3, N); defer free(heap_slice);
-		fmt.println("stack_array[1] - ", stack_array[1]);
-		fmt.println("heap_array[1]  - ", heap_array[1]);
-		fmt.println("heap_slice[1]  - ", heap_slice[1]);
-	}
-}
-
-
-
-
-union_type :: proc() {
-	fmt.println("\n# union_type");
-	{
-		val: union{int, bool};
-		val = 137;
-		if i, ok := val.(int); ok {
-			fmt.println(i);
-		}
-		val = true;
-		fmt.println(val);
-
-		val = nil;
-
-		switch v in val {
-		case int:  fmt.println("int",  v);
-		case bool: fmt.println("bool", v);
-		case:      fmt.println("nil");
-		}
-	}
-	{
-		// There is a duality between `any` and `union`
-		// An `any` has a pointer to the data and allows for any type (open)
-		// A `union` has as binary blob to store the data and allows only certain types (closed)
-		// The following code is with `any` but has the same syntax
-		val: any;
-		val = 137;
-		if i, ok := val.(int); ok {
-			fmt.println(i);
-		}
-		val = true;
-		fmt.println(val);
-
-		val = nil;
-
-		switch v in val {
-		case int:  fmt.println("int",  v);
-		case bool: fmt.println("bool", v);
-		case:      fmt.println("nil");
-		}
-	}
-
-	Vector3 :: struct {x, y, z: f32};
-	Quaternion :: struct {x, y, z: f32, w: f32 = 1};
-
-	// More realistic examples
-	{
-		// NOTE(bill): For the above basic examples, you may not have any
-		// particular use for it. However, my main use for them is not for these
-		// simple cases. My main use is for hierarchical types. Many prefer
-		// subtyping, embedding the base data into the derived types. Below is
-		// an example of this for a basic game Entity.
-
-		Entity :: struct {
-			id:          u64,
-			name:        string,
-			position:    Vector3,
-			orientation: Quaternion,
-
-			derived: any,
-		}
-
-		Frog :: struct {
-			using entity: Entity,
-			jump_height:  f32,
-		}
-
-		Monster :: struct {
-			using entity: Entity,
-			is_robot:     bool,
-			is_zombie:    bool,
-		}
-
-		// See `parametric_polymorphism` procedure for details
-		new_entity :: proc(T: type) -> ^Entity {
-			t := new(T);
-			t.derived = t^;
-			return t;
-		}
-
-		entity := new_entity(Monster);
-
-		switch e in entity.derived {
-		case Frog:
-			fmt.println("Ribbit");
-		case Monster:
-			if e.is_robot  do fmt.println("Robotic");
-			if e.is_zombie do fmt.println("Grrrr!");
-		}
-	}
-
-	{
-		// NOTE(bill): A union can be used to achieve something similar. Instead
-		// of embedding the base data into the derived types, the derived data
-		// in embedded into the base type. Below is the same example of the
-		// basic game Entity but using an union.
-
-		Entity :: struct {
-			id:          u64,
-			name:        string,
-			position:    Vector3,
-			orientation: Quaternion,
-
-			derived: union {Frog, Monster},
-		}
-
-		Frog :: struct {
-			using entity: ^Entity,
-			jump_height:  f32,
-		}
-
-		Monster :: struct {
-			using entity: ^Entity,
-			is_robot:     bool,
-			is_zombie:    bool,
-		}
-
-		// See `parametric_polymorphism` procedure for details
-		new_entity :: proc(T: type) -> ^Entity {
-			t := new(Entity);
-			t.derived = T{entity = t};
-			return t;
-		}
-
-		entity := new_entity(Monster);
-
-		switch e in entity.derived {
-		case Frog:
-			fmt.println("Ribbit");
-		case Monster:
-			if e.is_robot  do fmt.println("Robotic");
-			if e.is_zombie do fmt.println("Grrrr!");
-		}
-
-		// NOTE(bill): As you can see, the usage code has not changed, only its
-		// memory layout. Both approaches have their own advantages but they can
-		// be used together to achieve different results. The subtyping approach
-		// can allow for a greater control of the memory layout and memory
-		// allocation, e.g. storing the derivatives together. However, this is
-		// also its disadvantage. You must either preallocate arrays for each
-		// derivative separation (which can be easily missed) or preallocate a
-		// bunch of "raw" memory; determining the maximum size of the derived
-		// types would require the aid of metaprogramming. Unions solve this
-		// particular problem as the data is stored with the base data.
-		// Therefore, it is possible to preallocate, e.g. [100]Entity.
-
-		// It should be noted that the union approach can have the same memory
-		// layout as the any and with the same type restrictions by using a
-		// pointer type for the derivatives.
-
-		/*
-			Entity :: struct {
-				..
-				derived: union{^Frog, ^Monster},
-			}
-
-			Frog :: struct {
-				using entity: Entity,
-				..
-			}
-			Monster :: struct {
-				using entity: Entity,
-				..
-
-			}
-			new_entity :: proc(T: type) -> ^Entity {
-				t := new(T);
-				t.derived = t;
-				return t;
-			}
-		*/
-	}
-}
-
-parametric_polymorphism :: proc() {
-	fmt.println("# parametric_polymorphism");
-
-	print_value :: proc(value: $T) {
-		fmt.printf("print_value: %T %v\n", value, value);
-	}
-
-	v1: int    = 1;
-	v2: f32    = 2.1;
-	v3: f64    = 3.14;
-	v4: string = "message";
-
-	print_value(v1);
-	print_value(v2);
-	print_value(v3);
-	print_value(v4);
-
-	fmt.println();
-
-	add :: proc(p, q: $T) -> T {
-		x: T = p + q;
-		return x;
-	}
-
-	a := add(3, 4);
-	fmt.printf("a: %T = %v\n", a, a);
-
-	b := add(3.2, 4.3);
-	fmt.printf("b: %T = %v\n", b, b);
-
-	// This is how `new` is implemented
-	alloc_type :: proc(T: type) -> ^T {
-		t := cast(^T)alloc(size_of(T), align_of(T));
-		t^ = T{}; // Use default initialization value
-		return t;
-	}
-
-	copy_slice :: proc(dst, src: []$T) -> int {
-		return mem.copy(&dst[0], &src[0], n*size_of(T));
-	}
-
-	double_params :: proc(a: $A, b: $B) -> A {
-		return a + A(b);
-	}
-
-	fmt.println(double_params(12, 1.345));
-
-
-
-	{ // Polymorphic Types and Type Specialization
-		Table_Slot :: struct(Key, Value: type) {
-			occupied: bool,
-			hash:     u32,
-			key:      Key,
-			value:    Value,
-		}
-		TABLE_SIZE_MIN :: 32;
-		Table :: struct(Key, Value: type) {
-			count:     int,
-			allocator: Allocator,
-			slots:     []Table_Slot(Key, Value),
-		}
-
-		// Only allow types that are specializations of a (polymorphic) slice
-		make_slice :: proc(T: type/[]$E, len: int) -> T {
-			return make(T, len);
-		}
-
-
-		// Only allow types that are specializations of `Table`
-		allocate :: proc(table: ^$T/Table, capacity: int) {
-			c := context;
-			if table.allocator.procedure != nil do c.allocator = table.allocator;
-
-			context <- c {
-				table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN));
-			}
-		}
-
-		expand :: proc(table: ^$T/Table) {
-			c := context;
-			if table.allocator.procedure != nil do c.allocator = table.allocator;
-
-			context <- c {
-				old_slots := table.slots;
-
-				cap := max(2*len(table.slots), TABLE_SIZE_MIN);
-				allocate(table, cap);
-
-				for s in old_slots do if s.occupied {
-					put(table, s.key, s.value);
-				}
-
-				free(old_slots);
-			}
-		}
-
-		// Polymorphic determination of a polymorphic struct
-		// put :: proc(table: ^$T/Table, key: T.Key, value: T.Value) {
-		put :: proc(table: ^Table($Key, $Value), key: Key, value: Value) {
-			hash := get_hash(key); // Ad-hoc method which would fail in a different scope
-			index := find_index(table, key, hash);
-			if index < 0 {
-				if f64(table.count) >= 0.75*f64(len(table.slots)) {
-					expand(table);
-				}
-				assert(table.count <= len(table.slots));
-
-				hash := get_hash(key);
-				index = int(hash % u32(len(table.slots)));
-
-				for table.slots[index].occupied {
-					if index += 1; index >= len(table.slots) {
-						index = 0;
-					}
-				}
-
-				table.count += 1;
-			}
-
-			slot := &table.slots[index];
-			slot.occupied = true;
-			slot.hash     = hash;
-			slot.key      = key;
-			slot.value    = value;
-		}
-
-
-		// find :: proc(table: ^$T/Table, key: T.Key) -> (T.Value, bool) {
-		find :: proc(table: ^Table($Key, $Value), key: Key) -> (Value, bool) {
-			hash := get_hash(key);
-			index := find_index(table, key, hash);
-			if index < 0 {
-				return Value{}, false;
-			}
-			return table.slots[index].value, true;
-		}
-
-		find_index :: proc(table: ^Table($Key, $Value), key: Key, hash: u32) -> int {
-			if len(table.slots) <= 0 do return -1;
-
-			index := int(hash % u32(len(table.slots)));
-			for table.slots[index].occupied {
-				if table.slots[index].hash == hash {
-					if table.slots[index].key == key {
-						return index;
-					}
-				}
-
-				if index += 1; index >= len(table.slots) {
-					index = 0;
-				}
-			}
-
-			return -1;
-		}
-
-		get_hash :: proc(s: string) -> u32 { // fnv32a
-			h: u32 = 0x811c9dc5;
-			for i in 0..len(s) {
-				h = (h ~ u32(s[i])) * 0x01000193;
-			}
-			return h;
-		}
-
-
-		table: Table(string, int);
-
-		for i in 0..36 do put(&table, "Hellope", i);
-		for i in 0..42 do put(&table, "World!",  i);
-
-		found, _ := find(&table, "Hellope");
-		fmt.printf("`found` is %v\n", found);
-
-		found, _ = find(&table, "World!");
-		fmt.printf("`found` is %v\n", found);
-
-		// I would not personally design a hash table like this in production
-		// but this is a nice basic example
-		// A better approach would either use a `u64` or equivalent for the key
-		// and let the user specify the hashing function or make the user store
-		// the hashing procedure with the table
-	}
-}
-
-
-
-
-prefix_table := [?]string{
-	"White",
-	"Red",
-	"Green",
-	"Blue",
-	"Octarine",
-	"Black",
-};
-
-threading_example :: proc() {
-	when ODIN_OS == "windows" {
-		fmt.println("# threading_example");
-
-		unordered_remove :: proc(array: ^[dynamic]$T, index: int, loc := #caller_location) {
-			__bounds_check_error_loc(loc, index, len(array));
-			array[index] = array[len(array)-1];
-			pop(array);
-		}
-		ordered_remove :: proc(array: ^[dynamic]$T, index: int, loc := #caller_location) {
-			__bounds_check_error_loc(loc, index, len(array));
-			copy(array[index..], array[index+1..]);
-			pop(array);
-		}
-
-		worker_proc :: proc(t: ^thread.Thread) -> int {
-			for iteration in 1..5 {
-				fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration);
-				fmt.printf("`%s`: iteration %d\n", prefix_table[t.user_index], iteration);
-				// win32.sleep(1);
-			}
-			return 0;
-		}
-
-		threads := make([dynamic]^thread.Thread, 0, len(prefix_table));
-		defer free(threads);
-
-		for in prefix_table {
-			if t := thread.create(worker_proc); t != nil {
-				t.init_context = context;
-				t.use_init_context = true;
-				t.user_index = len(threads);
-				append(&threads, t);
-				thread.start(t);
-			}
-		}
-
-		for len(threads) > 0 {
-			for i := 0; i < len(threads); /**/ {
-				if t := threads[i]; thread.is_done(t) {
-					fmt.printf("Thread %d is done\n", t.user_index);
-					thread.destroy(t);
-
-					ordered_remove(&threads, i);
-				} else {
-					i += 1;
-				}
-			}
-		}
-	}
-}
-
-array_programming :: proc() {
-	fmt.println("# array_programming");
-	{
-		a := [3]f32{1, 2, 3};
-		b := [3]f32{5, 6, 7};
-		c := a * b;
-		d := a + b;
-		e := 1 +  (c - d) / 2;
-		fmt.printf("%.1f\n", e); // [0.5, 3.0, 6.5]
-	}
-
-	{
-		a := [3]f32{1, 2, 3};
-		b := swizzle(a, 2, 1, 0);
-		assert(b == [3]f32{3, 2, 1});
-
-		c := swizzle(a, 0, 0);
-		assert(c == [2]f32{1, 1});
-		assert(c == 1);
-	}
-
-	{
-		Vector3 :: distinct [3]f32;
-		a := Vector3{1, 2, 3};
-		b := Vector3{5, 6, 7};
-		c := (a * b)/2 + 1;
-		d := c.x + c.y + c.z;
-		fmt.printf("%.1f\n", d); // 22.0
-
-		cross :: proc(a, b: Vector3) -> Vector3 {
-			i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1);
-			j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0);
-			return i - j;
-		}
-
-		blah :: proc(a: Vector3) -> f32 {
-			return a.x + a.y + a.z;
-		}
-
-		x := cross(a, b);
-		fmt.println(x);
-		fmt.println(blah(x));
-	}
-}
-
-
-using println in import "core:fmt.odin"
-
-using_in :: proc() {
-	fmt.println("# using in");
-	using print in fmt;
-
-	println("Hellope1");
-	print("Hellope2\n");
-
-	Foo :: struct {
-		x, y: int,
-		b: bool,
-	}
-	f: Foo;
-	f.x, f.y = 123, 321;
-	println(f);
-	using x, y in f;
-	x, y = 456, 654;
-	println(f);
-}
-
-named_proc_return_parameters :: proc() {
-	fmt.println("# named proc return parameters");
-
-	foo0 :: proc() -> int {
-		return 123;
-	}
-	foo1 :: proc() -> (a: int) {
-		a = 123;
-		return;
-	}
-	foo2 :: proc() -> (a, b: int) {
-		// Named return values act like variables within the scope
-		a = 321;
-		b = 567;
-		return b, a;
-	}
-	fmt.println("foo0 =", foo0()); // 123
-	fmt.println("foo1 =", foo1()); // 123
-	fmt.println("foo2 =", foo2()); // 567 321
-}
-
-
-enum_export :: proc() {
-	fmt.println("# enum #export");
-
-	Foo :: enum #export {A, B, C};
-
-	f0 := A;
-	f1 := B;
-	f2 := C;
-	fmt.println(f0, f1, f2);
-}
-
-explicit_procedure_overloading :: proc() {
-	fmt.println("# explicit procedure overloading");
-
-	add_ints :: proc(a, b: int) -> int {
-		x := a + b;
-		fmt.println("add_ints", x);
-		return x;
-	}
-	add_floats :: proc(a, b: f32) -> f32 {
-		x := a + b;
-		fmt.println("add_floats", x);
-		return x;
-	}
-	add_numbers :: proc(a: int, b: f32, c: u8) -> int {
-		x := int(a) + int(b) + int(c);
-		fmt.println("add_numbers", x);
-		return x;
-	}
-
-	add :: proc[add_ints, add_floats, add_numbers];
-
-	add(int(1), int(2));
-	add(f32(1), f32(2));
-	add(int(1), f32(2), u8(3));
-
-	add(1, 2);     // untyped ints coerce to int tighter than f32
-	add(1.0, 2.0); // untyped floats coerce to f32 tighter than int
-	add(1, 2, 3);  // three parameters
-
-	// Ambiguous answers
-	// add(1.0, 2);
-	// add(1, 2.0);
-}
-
-complete_switch :: proc() {
-	fmt.println("# complete_switch");
-	{ // enum
-		Foo :: enum #export {
-			A,
-			B,
-			C,
-			D,
-		}
-
-		b := Foo.B;
-		f := Foo.A;
-		#complete switch f {
-		case A: fmt.println("A");
-		case B: fmt.println("B");
-		case C: fmt.println("C");
-		case D: fmt.println("D");
-		case:   fmt.println("?");
-		}
-	}
-	{ // union
-		Foo :: union {int, bool};
-		f: Foo = 123;
-		#complete switch in f {
-		case int:  fmt.println("int");
-		case bool: fmt.println("bool");
-		case:
-		}
-	}
-}
-
-
-main :: proc() {
-	when true {
-		general_stuff();
-		default_struct_values();
-		union_type();
-		parametric_polymorphism();
-		threading_example();
-		array_programming();
-		using_in();
-		named_proc_return_parameters();
-		enum_export();
-		explicit_procedure_overloading();
-		complete_switch();
-	}
-}

+ 0 - 412
misc/old_demos/old_runtime.odin

@@ -1,412 +0,0 @@
-#include "win32.odin"
-
-assume :: proc(cond: bool) #foreign "llvm.assume"
-
-__debug_trap           :: proc()           #foreign "llvm.debugtrap"
-__trap                 :: proc()           #foreign "llvm.trap"
-read_cycle_counter     :: proc() -> u64    #foreign "llvm.readcyclecounter"
-
-bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
-bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
-bit_reverse64 :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
-
-byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
-byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
-byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
-
-fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
-fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
-
-// TODO(bill): make custom heap procedures
-heap_alloc   :: proc(len: int)   -> rawptr #foreign "malloc"
-heap_dealloc :: proc(ptr: rawptr)          #foreign "free"
-
-memory_zero :: proc(data: rawptr, len: int) {
-	d := slice_ptr(data as ^byte, len)
-	for i := 0; i < len; i++ {
-		d[i] = 0
-	}
-}
-
-memory_compare :: proc(dst, src: rawptr, len: int) -> int {
-	s1, s2: ^byte = dst, src
-	for i := 0; i < len; i++ {
-		a := ptr_offset(s1, i)^
-		b := ptr_offset(s2, i)^
-		if a != b {
-			return (a - b) as int
-		}
-	}
-	return 0
-}
-
-memory_copy :: proc(dst, src: rawptr, n: int) #inline {
-	if dst == src {
-		return
-	}
-
-	v128b :: type {4}u32
-	#assert(align_of(v128b) == 16)
-
-	d, s: ^byte = dst, src
-
-	for ; s as uint % 16 != 0 && n != 0; n-- {
-		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)^
-		}
-
-		if n&8 != 0 {
-			(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)
-		}
-		if n&2 != 0 {
-			(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)
-		}
-		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 }
-	/* 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
-
-	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
-
-		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)
-
-			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
-
-		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)
-
-			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
-
-		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)
-
-			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)
-	}
-	if n&8 != 0 {
-		(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)
-	}
-	if n&2 != 0 {
-		(d as ^u16)^ = (s as ^u16)^
-		d, s = ptr_offset(d, 2), ptr_offset(s, 2)
-	}
-	if n&1 != 0 {
-		d^  = s^
-	}
-}
-
-memory_move :: proc(dst, src: rawptr, n: int) #inline {
-	d, s: ^byte = dst, src
-	if d == s {
-		return
-	}
-	if d >= ptr_offset(s, n) || ptr_offset(d, n) <= s {
-		memory_copy(d, s, n)
-		return
-	}
-
-	// TODO(bill): Vectorize the shit out of this
-	if d < s {
-		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
-				}
-				n--
-				d^ = s^
-				d, s = ptr_offset(d, 1), ptr_offset(s, 1)
-			}
-			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)
-			}
-		}
-		for ; n > 0; n-- {
-			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
-				}
-				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^
-			}
-			for ; n > 0; n-- {
-				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^
-		}
-	}
-}
-
-__string_eq :: proc(a, b: string) -> bool {
-	if len(a) != len(b) {
-		return false
-	}
-	if ^a[0] == ^b[0] {
-		return true
-	}
-	return memory_compare(^a[0], ^b[0], len(a)) == 0
-}
-
-__string_cmp :: proc(a, b : string) -> int {
-	min_len := len(a)
-	if len(b) < min_len {
-		min_len = len(b)
-	}
-	for i := 0; i < min_len; i++ {
-		x := a[i]
-		y := b[i]
-		if x < y {
-			return -1
-		} else if x > y {
-			return +1
-		}
-	}
-
-	if len(a) < len(b) {
-		return -1
-	} else if len(a) > len(b) {
-		return +1
-	}
-	return 0
-}
-
-__string_ne :: proc(a, b : string) -> bool #inline { return !__string_eq(a, b) }
-__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 }
-
-
-
-
-Allocation_Mode :: type enum {
-	ALLOC,
-	DEALLOC,
-	DEALLOC_ALL,
-	RESIZE,
-}
-
-
-
-Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocation_Mode,
-                            size, alignment: int,
-                            old_memory: rawptr, old_size: int, flags: u64) -> rawptr
-
-Allocator :: type struct {
-	procedure: Allocator_Proc;
-	data:      rawptr
-}
-
-
-Context :: type struct {
-	thread_ptr: rawptr
-
-	user_data:  rawptr
-	user_index: int
-
-	allocator: Allocator
-}
-
-#thread_local context: Context
-
-DEFAULT_ALIGNMENT :: 2*size_of(int)
-
-
-__check_context :: proc() {
-	if context.allocator.procedure == null {
-		context.allocator = __default_allocator()
-	}
-	if context.thread_ptr == null {
-		// TODO(bill):
-		// context.thread_ptr = current_thread_pointer()
-	}
-}
-
-
-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, Allocation_Mode.ALLOC, size, alignment, null, 0, 0)
-}
-
-dealloc :: proc(ptr: rawptr) #inline {
-	__check_context()
-	a := context.allocator
-	_ = a.procedure(a.data, Allocation_Mode.DEALLOC, 0, 0, ptr, 0, 0)
-}
-dealloc_all :: proc(ptr: rawptr) #inline {
-	__check_context()
-	a := context.allocator
-	_ = a.procedure(a.data, Allocation_Mode.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_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
-	__check_context()
-	a := context.allocator
-	return a.procedure(a.data, Allocation_Mode.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)
-	}
-
-	if new_size == 0 {
-		dealloc(old_memory)
-		return null
-	}
-
-	if new_size == old_size {
-		return old_memory
-	}
-
-	new_memory := alloc_align(new_size, alignment)
-	if new_memory == null {
-		return null
-	}
-
-	memory_copy(new_memory, old_memory, min(old_size, new_size));
-	dealloc(old_memory)
-	return new_memory
-}
-
-
-__default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocation_Mode,
-                                 size, alignment: int,
-                                 old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
-	using Allocation_Mode
-	match mode {
-	case ALLOC:
-		return heap_alloc(size)
-	case RESIZE:
-		return default_resize_align(old_memory, old_size, size, alignment)
-	case DEALLOC:
-		heap_dealloc(old_memory)
-	case DEALLOC_ALL:
-		// NOTE(bill): Does nothing
-	}
-
-	return null
-}
-
-__default_allocator :: proc() -> Allocator {
-	return Allocator{
-		__default_allocator_proc,
-		null,
-	}
-}
-
-
-
-
-__assert :: proc(msg: string) {
-	file_write(file_get_standard(File_Standard.ERROR), msg as []byte)
-	// TODO(bill): Which is better?
-	// __trap()
-	__debug_trap()
-}

+ 0 - 430
misc/old_stuff/demo_backup.odin

@@ -1,430 +0,0 @@
-import (
-	"fmt.odin";
-	"atomics.odin";
-	"bits.odin";
-	"decimal.odin";
-	"hash.odin";
-	"math.odin";
-	"mem.odin";
-	"opengl.odin";
-	"os.odin";
-	"raw.odin";
-	"strconv.odin";
-	"strings.odin";
-	"sync.odin";
-	"sort.odin";
-	"types.odin";
-	"utf8.odin";
-	"utf16.odin";
-/*
-*/
-)
-
-
-general_stuff :: proc() {
-	// Complex numbers
-	a := 3 + 4i;
-	b: complex64 = 3 + 4i;
-	c: complex128 = 3 + 4i;
-	d := complex(2, 3);
-
-	e := a / conj(a);
-	fmt.println("(3+4i)/(3-4i) =", e);
-	fmt.println(real(e), "+", imag(e), "i");
-
-
-	// C-style variadic procedures
-	foreign __llvm_core {
-		// The variadic part allows for extra type checking too which C does not provide
-		c_printf :: proc(fmt: ^u8, #c_vararg args: ..any) -> i32 #link_name "printf" ---;
-	}
-	str := "%d\n\x00";
-	// c_printf(&str[0], i32(789456123));
-
-
-	Foo :: struct {
-		x: int;
-		y: f32;
-		z: string;
-	}
-	foo := Foo{123, 0.513, "A string"};
-	x, y, z := expand_to_tuple(foo);
-	fmt.println(x, y, z);
-	#assert(type_of(x) == int);
-	#assert(type_of(y) == f32);
-	#assert(type_of(z) == string);
-
-
-	// By default, all variables are zeroed
-	// This can be overridden with the "uninitialized value"
-	// This is similar to `nil` but applied to everything
-	undef_int: int = ---;
-
-
-	// Context system is now implemented using Implicit Parameter Passing (IPP)
-	// The previous implementation was Thread Local Storage (TLS)
-	// IPP has the advantage that it works on systems without TLS and that you can
-	// link the context to the stack frame and thus look at previous contexts
-	//
-	// It does mean that a pointer is implicitly passed procedures with the default
-	// Odin calling convention (#cc_odin)
-	// This can be overridden with something like #cc_contextless or #cc_c if performance
-	// is worried about
-
-}
-
-foreign_blocks :: proc() {
-	// See sys/windows.odin
-}
-
-default_arguments :: proc() {
-	hello :: proc(a: int = 9, b: int = 9) do fmt.printf("a is %d; b is %d\n", a, b);
-	fmt.println("\nTesting default arguments:");
-	hello(1, 2);
-	hello(1);
-	hello();
-}
-
-named_arguments :: proc() {
-	Colour :: enum {
-		Red,
-		Orange,
-		Yellow,
-		Green,
-		Blue,
-		Octarine,
-	};
-	using Colour;
-
-	make_character :: proc(name, catch_phrase: string, favourite_colour, least_favourite_colour: Colour) {
-		fmt.println();
-		fmt.printf("My name is %v and I like %v.  %v\n", name, favourite_colour, catch_phrase);
-	}
-
-	make_character("Frank", "¡Ay, caramba!", Blue, Green);
-
-
-	// As the procedures have more and more parameters, it is very easy
-	// to get many of the arguments in the wrong order especialy if the
-	// types are the same
-	make_character("¡Ay, caramba!", "Frank", Green, Blue);
-
-	// Named arguments help to disambiguate this problem
-	make_character(catch_phrase = "¡Ay, caramba!", name = "Frank",
-	               least_favourite_colour = Green, favourite_colour = Blue);
-
-
-	// The named arguments can be specifed in any order.
-	make_character(favourite_colour = Octarine, catch_phrase = "U wot m8!",
-	               least_favourite_colour = Green, name = "Dennis");
-
-
-	// NOTE: You cannot mix named arguments with normal values
-	/*
-	make_character("Dennis",
-	               favourite_colour = Octarine, catch_phrase = "U wot m8!",
-	               least_favourite_colour = Green);
-	*/
-
-
-	// Named arguments can also aid with default arguments
-	numerous_things :: proc(s: string, a := 1, b := 2, c := 3.14,
-	                        d := "The Best String!", e := false, f := 10.3/3.1, g := false) {
-		g_str := g ? "true" : "false";
-		fmt.printf("How many?! %s: %v\n", s, g_str);
-	}
-
-	numerous_things("First");
-	numerous_things(s = "Second", g = true);
-
-
-	// Default values can be placed anywhere, not just at the end like in other languages
-	weird :: proc(pre: string, mid: int = 0, post: string) {
-		fmt.println(pre, mid, post);
-	}
-
-	weird("How many things", 42, "huh?");
-	weird(pre = "Prefix", post = "Pat");
-
-}
-
-
-default_return_values :: proc() {
-	foo :: proc(x: int) -> (first: string = "Hellope", second := "world!") {
-		match x {
-		case 0: return;
-		case 1: return "Goodbye";
-		case 2: return "Goodbye", "cruel world..";
-		case 3: return second = "cruel world..", first = "Goodbye";
-		}
-
-		return second = "my old friend.";
-	}
-
-	fmt.printf("%s %s\n", foo(0));
-	fmt.printf("%s %s\n", foo(1));
-	fmt.printf("%s %s\n", foo(2));
-	fmt.printf("%s %s\n", foo(3));
-	fmt.printf("%s %s\n", foo(4));
-	fmt.println();
-
-
-	// A more "real" example
-	Error :: enum {
-		None,
-		WhyTheNumberThree,
-		TenIsTooBig,
-	};
-
-	Entity :: struct {
-		name: string;
-		id:   u32;
-	}
-
-	some_thing :: proc(input: int) -> (result: ^Entity = nil, err := Error.None) {
-		match {
-		case input == 3:  return err = Error.WhyTheNumberThree;
-		case input >= 10: return err = Error.TenIsTooBig;
-		}
-
-		e := new(Entity);
-		e.id = u32(input);
-
-		return result = e;
-	}
-}
-
-call_location :: proc() {
-	amazing :: proc(n: int, using loc := #caller_location) {
-		fmt.printf("%s(%d:%d) just asked to do something amazing.\n",
-				   fully_pathed_filename, line, column);
-		fmt.printf("Normal -> %d\n", n);
-		fmt.printf("Amazing -> %d\n", n+1);
-		fmt.println();
-	}
-
-	loc := #location(main);
-	fmt.println("`main` is located at", loc);
-
-	fmt.println("This line is located at", #location());
-	fmt.println();
-
-	amazing(3);
-	amazing(4, #location(call_location));
-
-	// See _preload.odin for the implementations of `assert` and `panic`
-
-}
-
-
-explicit_parametric_polymorphic_procedures :: proc() {
-	// This is how `new` is actually implemented, see _preload.odin
-	alloc_type :: proc(T: type) -> ^T do return cast(^T)alloc(size_of(T), align_of(T));
-
-	int_ptr := alloc_type(int);
-	defer free(int_ptr);
-	int_ptr^ = 137;
-	fmt.println(int_ptr, int_ptr^);
-
-	// Named arguments work too!
-	another_ptr := alloc_type(T = f32);
-	defer free(another_ptr);
-
-
-	add :: proc(T: type, args: ..T) -> T {
-		res: T;
-		for arg in args do res += arg;
-		return res;
-	}
-
-	fmt.println("add =", add(int, 1, 2, 3, 4, 5, 6));
-
-	swap :: proc(T: type, a, b: ^T) {
-		tmp := a^;
-		a^ = b^;
-		b^ = tmp;
-	}
-
-	a, b: int = 3, 4;
-	fmt.println("Pre-swap:", a, b);
-	swap(int, &a, &b);
-	fmt.println("Post-swap:", a, b);
-	a, b = b, a; // Or use this syntax for this silly example case
-
-
-	Vector2 :: struct {x, y: f32;};
-	{
-		// A more complicated example using subtyping
-		// Something like this could be used in a game
-
-		Entity :: struct {
-			using position: Vector2;
-			flags:          u64;
-			id:             u64;
-			derived:        any;
-		}
-
-		Rock :: struct {
-			using entity: Entity;
-			heavy: bool;
-		}
-		Door :: struct {
-			using entity: Entity;
-			open:         bool;
-		}
-		Monster :: struct {
-			using entity: Entity;
-			is_robot:     bool;
-			is_zombie:    bool;
-		}
-
-		new_entity :: proc(T: type, x, y: f32) -> ^T {
-			result := new(T);
-			result.derived = result^;
-			result.x = x;
-			result.y = y;
-
-			return result;
-		}
-
-		entities: [dynamic]^Entity;
-
-		rock := new_entity(Rock, 3, 5);
-
-		// Named arguments work too!
-		door := new_entity(T = Door, x = 3, y = 6);
-
-		// And named arguments can be any order
-		monster := new_entity(
-			y = 1,
-			x = 2,
-			T = Monster,
-		);
-
-		append(&entities, rock, door, monster);
-
-		fmt.println("Subtyping");
-		for entity in entities {
-			match e in entity.derived {
-			case Rock:    fmt.println("Rock",    e.x, e.y);
-			case Door:    fmt.println("Door",    e.x, e.y);
-			case Monster: fmt.println("Monster", e.x, e.y);
-			}
-		}
-	}
-	{
-		Entity :: struct {
-			using position: Vector2;
-			flags:          u64;
-			id:             u64;
-			variant: union { Rock, Door, Monster };
-		}
-
-		Rock :: struct {
-			using entity: ^Entity;
-			heavy: bool;
-		}
-		Door :: struct {
-			using entity: ^Entity;
-			open:         bool;
-		}
-		Monster :: struct {
-			using entity: ^Entity;
-			is_robot:     bool;
-			is_zombie:    bool;
-		}
-
-		new_entity :: proc(T: type, x, y: f32) -> ^T {
-			result := new(Entity);
-			result.variant = T{entity = result};
-			result.x = x;
-			result.y = y;
-
-			return cast(^T)&result.variant;
-		}
-
-		entities: [dynamic]^Entity;
-
-		rock := new_entity(Rock, 3, 5);
-
-		// Named arguments work too!
-		door := new_entity(T = Door, x = 3, y = 6);
-
-		// And named arguments can be any order
-		monster := new_entity(
-			y = 1,
-			x = 2,
-			T = Monster,
-		);
-
-		append(&entities, rock, door, monster);
-
-		fmt.println("Union");
-		for entity in entities {
-			match e in entity.variant {
-			case Rock:    fmt.println("Rock",    e.x, e.y);
-			case Door:    fmt.println("Door",    e.x, e.y);
-			case Monster: fmt.println("Monster", e.x, e.y);
-			}
-		}
-	}
-}
-
-
-implicit_polymorphic_assignment :: proc() {
-	yep :: proc(p: proc(x: int)) {
-		p(123);
-	}
-
-	frank :: proc(x: $T)    do fmt.println("frank ->", x);
-	tim   :: proc(x, y: $T) do fmt.println("tim ->", x, y);
-	yep(frank);
-	// yep(tim);
-}
-
-
-
-
-main :: proc() {
-/*
-	foo :: proc(x: i64,  y: f32) do fmt.println("#1", x, y);
-	foo :: proc(x: type, y: f32) do fmt.println("#2", type_info(x), y);
-	foo :: proc(x: type)         do fmt.println("#3", type_info(x));
-
-	f :: foo;
-
-	f(y = 3785.1546, x = 123);
-	f(x = int, y = 897.513);
-	f(x = f32);
-
-	general_stuff();
-	foreign_blocks();
-	default_arguments();
-	named_arguments();
-	default_return_values();
-	call_location();
-	explicit_parametric_polymorphic_procedures();
-	implicit_polymorphic_assignment();
-
-
-	// Command line argument(s)!
-	// -opt=0,1,2,3
-*/
-/*
-	program := "+ + * - /";
-	accumulator := 0;
-
-	for token in program {
-		match token {
-		case '+': accumulator += 1;
-		case '-': accumulator -= 1;
-		case '*': accumulator *= 2;
-		case '/': accumulator /= 2;
-		case: // Ignore everything else
-		}
-	}
-
-	fmt.printf("The program \"%s\" calculates the value %d\n",
-			   program, accumulator);
-*/
-}

+ 12 - 0
src/checker.cpp

@@ -4447,6 +4447,14 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
 			ac->foreign_import_priority_index = exact_value_to_i64(ev);
 		}
 		return true;
+	} else if (name == "extra_linker_flags") {
+		ExactValue ev = check_decl_attribute_value(c, value);
+		if (ev.kind != ExactValue_String) {
+			error(elem, "Expected a string value for '%.*s'", LIT(name));
+		} else {
+			ac->extra_linker_flags = ev.value_string;
+		}
+		return true;
 	}
 	return false;
 }
@@ -4506,6 +4514,10 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
 	if (ac.foreign_import_priority_index != 0) {
 		e->LibraryName.priority_index = ac.foreign_import_priority_index;
 	}
+	String extra_linker_flags = string_trim_whitespace(ac.extra_linker_flags);
+	if (extra_linker_flags.len != 0) {
+		e->LibraryName.extra_linker_flags = extra_linker_flags;
+	}
 
 	if (has_asm_extension(fullpath)) {
 		if (build_context.metrics.arch != TargetArch_amd64 ||

+ 1 - 0
src/checker.hpp

@@ -121,6 +121,7 @@ struct AttributeContext {
 	bool    set_cold            : 1;
 	u32 optimization_mode; // ProcedureOptimizationMode
 	i64 foreign_import_priority_index;
+	String extra_linker_flags;
 
 	String  objc_class;
 	String  objc_name;

+ 7 - 5
src/docs_writer.cpp

@@ -915,18 +915,20 @@ gb_internal void odin_doc_update_entities(OdinDocWriter *w) {
 		auto entities = array_make<Entity *>(heap_allocator(), 0, w->entity_cache.count);
 		defer (array_free(&entities));
 
-		for (auto const &entry : w->entity_cache) {
-			array_add(&entities, entry.key);
+		for (u32 i = 0; i < w->entity_cache.count; i++) {
+			Entity *e = w->entity_cache.entries[i].key;
+			array_add(&entities, e);
 		}
 		for (Entity *e : entities) {
+			GB_ASSERT(e != nullptr);
 			OdinDocTypeIndex type_index = odin_doc_type(w, e->type);
 			gb_unused(type_index);
 		}
 	}
 
-	for (auto const &entry : w->entity_cache) {
-		Entity *e = entry.key;
-		OdinDocEntityIndex entity_index = entry.value;
+	for (u32 i = 0; i < w->entity_cache.count; i++) {
+		Entity *e = w->entity_cache.entries[i].key;
+		OdinDocEntityIndex entity_index = w->entity_cache.entries[i].value;
 		OdinDocTypeIndex type_index = odin_doc_type(w, e->type);
 
 		OdinDocEntityIndex foreign_library = 0;

+ 1 - 0
src/entity.cpp

@@ -259,6 +259,7 @@ struct Entity {
 			Slice<String> paths;
 			String name;
 			i64 priority_index;
+			String extra_linker_flags;
 		} LibraryName;
 		i32 Nil;
 		struct {

+ 83 - 58
src/llvm_abi.cpp

@@ -563,7 +563,7 @@ namespace lbAbiAmd64SysV {
 	gb_internal void fixup(LLVMTypeRef t, Array<RegClass> *cls);
 	gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention);
 	gb_internal Array<RegClass> classify(LLVMTypeRef t);
-	gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const &reg_classes);
+	gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const &reg_classes, LLVMTypeRef type);
 
 	gb_internal LB_ABI_INFO(abi_info) {
 		lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
@@ -662,7 +662,7 @@ namespace lbAbiAmd64SysV {
 				// the ABI rules for SysV
 				reg_type = type;
 			} else {
-				reg_type = llreg(c, cls);
+				reg_type = llreg(c, cls, type);
 			}
 			return lb_arg_type_direct(type, reg_type, nullptr, nullptr);
 		}
@@ -785,67 +785,92 @@ namespace lbAbiAmd64SysV {
 	}
 
 
-	gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const &reg_classes) {
+	gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const &reg_classes, LLVMTypeRef type) {
 		auto types = array_make<LLVMTypeRef>(heap_allocator(), 0, reg_classes.count);
-		for (isize i = 0; i < reg_classes.count; /**/) {
-			RegClass reg_class = reg_classes[i];
-			switch (reg_class) {
-			case RegClass_Int:
-				array_add(&types, LLVMIntTypeInContext(c, 64));
+
+		bool all_ints = true;
+		for (RegClass reg_class : reg_classes) {
+			if (reg_class != RegClass_Int) {
+				all_ints = false;
 				break;
-			case RegClass_SSEFv:
-			case RegClass_SSEDv:
-			case RegClass_SSEInt8:
-			case RegClass_SSEInt16:
-			case RegClass_SSEInt32:
-			case RegClass_SSEInt64:
-				{
-					unsigned elems_per_word = 0;
-					LLVMTypeRef elem_type = nullptr;
-					switch (reg_class) {
-					case RegClass_SSEFv:
-						elems_per_word = 2;
-						elem_type = LLVMFloatTypeInContext(c);
-						break;
-					case RegClass_SSEDv:
-						elems_per_word = 1;
-						elem_type = LLVMDoubleTypeInContext(c);
-						break;
-					case RegClass_SSEInt8:
-						elems_per_word = 64/8;
-						elem_type = LLVMIntTypeInContext(c, 8);
-						break;
-					case RegClass_SSEInt16:
-						elems_per_word = 64/16;
-						elem_type = LLVMIntTypeInContext(c, 16);
-						break;
-					case RegClass_SSEInt32:
-						elems_per_word = 64/32;
-						elem_type = LLVMIntTypeInContext(c, 32);
-						break;
-					case RegClass_SSEInt64:
-						elems_per_word = 64/64;
-						elem_type = LLVMIntTypeInContext(c, 64);
-						break;
-					}
+			}
+		}
 
-					unsigned vec_len = llvec_len(reg_classes, i+1);
-					LLVMTypeRef vec_type = LLVMVectorType(elem_type, vec_len * elems_per_word);
-					array_add(&types, vec_type);
-					i += vec_len;
-					continue;
+		if (all_ints) {
+			i64 sz = lb_sizeof(type);
+			for_array(i, reg_classes) {
+				GB_ASSERT(sz != 0);
+				// TODO(bill): is this even correct? BECAUSE LLVM DOES NOT DOCUMENT ANY OF THIS!!!
+				if (sz >= 8) {
+					array_add(&types, LLVMIntTypeInContext(c, 64));
+					sz -= 8;
+				} else {
+					array_add(&types, LLVMIntTypeInContext(c, cast(unsigned)(sz*8)));
+					sz = 0;
 				}
-				break;
-			case RegClass_SSEFs:
-				array_add(&types, LLVMFloatTypeInContext(c));
-				break;
-			case RegClass_SSEDs:
-				array_add(&types, LLVMDoubleTypeInContext(c));
-				break;
-			default:
-				GB_PANIC("Unhandled RegClass");
 			}
-			i += 1;
+		} else {
+			for (isize i = 0; i < reg_classes.count; /**/) {
+				RegClass reg_class = reg_classes[i];
+				switch (reg_class) {
+				case RegClass_Int:
+					// TODO(bill): is this even correct? BECAUSE LLVM DOES NOT DOCUMENT ANY OF THIS!!!
+					array_add(&types, LLVMIntTypeInContext(c, 64));
+					break;
+				case RegClass_SSEFv:
+				case RegClass_SSEDv:
+				case RegClass_SSEInt8:
+				case RegClass_SSEInt16:
+				case RegClass_SSEInt32:
+				case RegClass_SSEInt64:
+					{
+						unsigned elems_per_word = 0;
+						LLVMTypeRef elem_type = nullptr;
+						switch (reg_class) {
+						case RegClass_SSEFv:
+							elems_per_word = 2;
+							elem_type = LLVMFloatTypeInContext(c);
+							break;
+						case RegClass_SSEDv:
+							elems_per_word = 1;
+							elem_type = LLVMDoubleTypeInContext(c);
+							break;
+						case RegClass_SSEInt8:
+							elems_per_word = 64/8;
+							elem_type = LLVMIntTypeInContext(c, 8);
+							break;
+						case RegClass_SSEInt16:
+							elems_per_word = 64/16;
+							elem_type = LLVMIntTypeInContext(c, 16);
+							break;
+						case RegClass_SSEInt32:
+							elems_per_word = 64/32;
+							elem_type = LLVMIntTypeInContext(c, 32);
+							break;
+						case RegClass_SSEInt64:
+							elems_per_word = 64/64;
+							elem_type = LLVMIntTypeInContext(c, 64);
+							break;
+						}
+
+						unsigned vec_len = llvec_len(reg_classes, i+1);
+						LLVMTypeRef vec_type = LLVMVectorType(elem_type, vec_len * elems_per_word);
+						array_add(&types, vec_type);
+						i += vec_len;
+						continue;
+					}
+					break;
+				case RegClass_SSEFs:
+					array_add(&types, LLVMFloatTypeInContext(c));
+					break;
+				case RegClass_SSEDs:
+					array_add(&types, LLVMDoubleTypeInContext(c));
+					break;
+				default:
+					GB_PANIC("Unhandled RegClass");
+				}
+				i += 1;
+			}
 		}
 
 		if (types.count == 1) {

+ 16 - 3
src/main.cpp

@@ -278,6 +278,13 @@ gb_internal i32 linker_stage(lbGenerator *gen) {
 				}
 			}
 
+			for (Entity *e : gen->foreign_libraries) {
+				GB_ASSERT(e->kind == Entity_LibraryName);
+				if (e->LibraryName.extra_linker_flags.len != 0) {
+					lib_str = gb_string_append_fmt(lib_str, " %.*s", LIT(e->LibraryName.extra_linker_flags));
+				}
+			}
+
 			if (build_context.build_mode == BuildMode_DynamicLibrary) {
 				link_settings = gb_string_append_fmt(link_settings, " /DLL");
 			} else {
@@ -449,6 +456,12 @@ gb_internal i32 linker_stage(lbGenerator *gen) {
 				}
 			}
 
+			for (Entity *e : gen->foreign_libraries) {
+				GB_ASSERT(e->kind == Entity_LibraryName);
+				if (e->LibraryName.extra_linker_flags.len != 0) {
+					lib_str = gb_string_append_fmt(lib_str, " %.*s", LIT(e->LibraryName.extra_linker_flags));
+				}
+			}
 
 			gbString object_files = gb_string_make(heap_allocator(), "");
 			defer (gb_string_free(object_files));
@@ -581,13 +594,13 @@ gb_internal Array<String> setup_args(int argc, char const **argv) {
 
 gb_internal void print_usage_line(i32 indent, char const *fmt, ...) {
 	while (indent --> 0) {
-		gb_printf_err("\t");
+		gb_printf("\t");
 	}
 	va_list va;
 	va_start(va, fmt);
-	gb_printf_err_va(fmt, va);
+	gb_printf_va(fmt, va);
 	va_end(va);
-	gb_printf_err("\n");
+	gb_printf("\n");
 }
 
 gb_internal void usage(String argv0) {

+ 19 - 6
src/parser.cpp

@@ -1411,7 +1411,7 @@ gb_internal Token expect_operator(AstFile *f) {
 		             LIT(p));
 	}
 	if (f->curr_token.kind == Token_Ellipsis) {
-		syntax_warning(f->curr_token, "'..' for ranges has now be deprecated, prefer '..='");
+		syntax_warning(f->curr_token, "'..' for ranges has now been deprecated, prefer '..='");
 		f->tokens[f->curr_token_index].flags |= TokenFlag_Replace;
 	}
 	
@@ -1434,7 +1434,7 @@ gb_internal Token expect_closing_brace_of_field_list(AstFile *f) {
 		return token;
 	}
 	bool ok = true;
-	if (!f->allow_newline) {
+	if (f->allow_newline) {
 		ok = !skip_possible_newline(f);
 	}
 	if (ok && allow_token(f, Token_Semicolon)) {
@@ -3191,6 +3191,15 @@ gb_internal Ast *parse_foreign_block(AstFile *f, Token token) {
 	return decl;
 }
 
+gb_internal void print_comment_group(CommentGroup *group) {
+	if (group) {
+		for (Token const &token : group->list) {
+			gb_printf_err("%.*s\n", LIT(token.string));
+		}
+		gb_printf_err("\n");
+	}
+}
+
 gb_internal Ast *parse_value_decl(AstFile *f, Array<Ast *> names, CommentGroup *docs) {
 	bool is_mutable = true;
 
@@ -3232,6 +3241,8 @@ gb_internal Ast *parse_value_decl(AstFile *f, Array<Ast *> names, CommentGroup *
 		values.allocator = heap_allocator();
 	}
 
+	CommentGroup *end_comment = f->lead_comment;
+
 	if (f->expr_level >= 0) {
 		if (f->curr_token.kind == Token_CloseBrace &&
 		    f->curr_token.pos.line == f->prev_token.pos.line) {
@@ -3252,7 +3263,7 @@ gb_internal Ast *parse_value_decl(AstFile *f, Array<Ast *> names, CommentGroup *
 		}
 	}
 
-	return ast_value_decl(f, names, type, values, is_mutable, docs, f->line_comment);
+	return ast_value_decl(f, names, type, values, is_mutable, docs, end_comment);
 }
 
 gb_internal Ast *parse_simple_stmt(AstFile *f, u32 flags) {
@@ -3682,9 +3693,11 @@ gb_internal bool allow_field_separator(AstFile *f) {
 	if (allow_token(f, Token_Comma)) {
 		return true;
 	}
-	if (ALLOW_NEWLINE && token.kind == Token_Semicolon && !token_is_newline(token)) {
-		String p = token_to_string(token);
-		syntax_error(token_end_of_line(f, f->prev_token), "Expected a comma, got a %.*s", LIT(p));
+	if (ALLOW_NEWLINE && token.kind == Token_Semicolon) {
+		if (!token_is_newline(token)) {
+			String p = token_to_string(token);
+			syntax_error(token_end_of_line(f, f->prev_token), "Expected a comma, got a %.*s", LIT(p));
+		}
 		advance_token(f);
 		return true;
 	}

+ 19 - 24
tests/core/build.bat

@@ -6,87 +6,82 @@ python3 download_assets.py
 echo ---
 echo Running core:image tests
 echo ---
-%PATH_TO_ODIN% run image    %COMMON% -out:test_core_image.exe
+%PATH_TO_ODIN% run image    %COMMON% -out:test_core_image.exe || exit /b
 
 echo ---
 echo Running core:compress tests
 echo ---
-%PATH_TO_ODIN% run compress %COMMON% -out:test_core_compress.exe
+%PATH_TO_ODIN% run compress %COMMON% -out:test_core_compress.exe || exit /b
 
 echo ---
 echo Running core:strings tests
 echo ---
-%PATH_TO_ODIN% run strings %COMMON% -out:test_core_strings.exe
+%PATH_TO_ODIN% run strings %COMMON% -out:test_core_strings.exe || exit /b
 
 echo ---
 echo Running core:hash tests
 echo ---
-%PATH_TO_ODIN% run hash %COMMON% -o:size -out:test_core_hash.exe
+%PATH_TO_ODIN% run hash %COMMON% -o:size -out:test_core_hash.exe || exit /b
 
 echo ---
 echo Running core:odin tests
 echo ---
-%PATH_TO_ODIN% run odin %COMMON% -o:size -out:test_core_odin.exe
+%PATH_TO_ODIN% run odin %COMMON% -o:size -out:test_core_odin.exe || exit /b
 
 echo ---
 echo Running core:crypto hash tests
 echo ---
-%PATH_TO_ODIN% run crypto %COMMON% -out:test_crypto_hash.exe
+%PATH_TO_ODIN% run crypto %COMMON% -out:test_crypto_hash.exe || exit /b
 
 echo ---
 echo Running core:encoding tests
 echo ---
-%PATH_TO_ODIN% run encoding/hxa    %COMMON% %COLLECTION% -out:test_hxa.exe
-%PATH_TO_ODIN% run encoding/json   %COMMON% -out:test_json.exe
-%PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe
-%PATH_TO_ODIN% run encoding/xml    %COMMON% -out:test_xml.exe
+%PATH_TO_ODIN% run encoding/hxa    %COMMON% %COLLECTION% -out:test_hxa.exe || exit /b
+%PATH_TO_ODIN% run encoding/json   %COMMON% -out:test_json.exe || exit /b
+%PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe || exit /b
+%PATH_TO_ODIN% run encoding/xml    %COMMON% -out:test_xml.exe || exit /b
 
 echo ---
 echo Running core:math/noise tests
 echo ---
-%PATH_TO_ODIN% run math/noise %COMMON% -out:test_noise.exe
+%PATH_TO_ODIN% run math/noise %COMMON% -out:test_noise.exe || exit /b
 
 echo ---
 echo Running core:math tests
 echo ---
-%PATH_TO_ODIN% run math %COMMON% %COLLECTION% -out:test_core_math.exe
+%PATH_TO_ODIN% run math %COMMON% %COLLECTION% -out:test_core_math.exe || exit /b
 
 echo ---
 echo Running core:math/linalg/glsl tests
 echo ---
-%PATH_TO_ODIN% run math/linalg/glsl %COMMON% %COLLECTION% -out:test_linalg_glsl.exe
+%PATH_TO_ODIN% run math/linalg/glsl %COMMON% %COLLECTION% -out:test_linalg_glsl.exe || exit /b
 
 echo ---
 echo Running core:path/filepath tests
 echo ---
-%PATH_TO_ODIN% run path/filepath %COMMON% %COLLECTION% -out:test_core_filepath.exe
+%PATH_TO_ODIN% run path/filepath %COMMON% %COLLECTION% -out:test_core_filepath.exe || exit /b
 
 echo ---
 echo Running core:reflect tests
 echo ---
-%PATH_TO_ODIN% run reflect %COMMON% %COLLECTION% -out:test_core_reflect.exe
+%PATH_TO_ODIN% run reflect %COMMON% %COLLECTION% -out:test_core_reflect.exe || exit /b
 
 echo ---
 echo Running core:text/i18n tests
 echo ---
-%PATH_TO_ODIN% run text\i18n %COMMON% -out:test_core_i18n.exe
+%PATH_TO_ODIN% run text\i18n %COMMON% -out:test_core_i18n.exe || exit /b
 
 echo ---
 echo Running core:net
 echo ---
-%PATH_TO_ODIN% run net %COMMON% -out:test_core_net.exe
-
-echo ---
-echo Running core:text/lua tests
-echo ---
-%PATH_TO_ODIN% run text\lua %COMMON% -out:test_core_lua_strlib.exe
+%PATH_TO_ODIN% run net %COMMON% -out:test_core_net.exe || exit /b
 
 echo ---
 echo Running core:slice tests
 echo ---
-%PATH_TO_ODIN% run slice %COMMON% -out:test_core_slice.exe
+%PATH_TO_ODIN% run slice %COMMON% -out:test_core_slice.exe || exit /b
 
 echo ---
 echo Running core:container tests
 echo ---
-%PATH_TO_ODIN% run container %COMMON% %COLLECTION% -out:test_core_container.exe
+%PATH_TO_ODIN% run container %COMMON% %COLLECTION% -out:test_core_container.exe || exit /b

+ 7 - 0
tests/core/compress/test_core_compress.odin

@@ -151,6 +151,13 @@ shoco_test :: proc(t: ^testing.T) {
 	}
 
 	for v in Shoco_Tests {
+		when ODIN_OS == .Windows {
+			v := v
+			// Compressed source files are not encoded with carriage returns but git replaces raw files lf with crlf on commit (on windows only)
+			// So replace crlf with lf on windows
+			v.raw, _ = bytes.replace_all(v.raw, { 0xD, 0xA }, { 0xA })
+		}
+
 		expected_raw        := len(v.raw)
 		expected_compressed := len(v.compressed)
 

+ 46 - 0
tests/core/strings/test_core_strings.odin

@@ -4,6 +4,7 @@ import "core:strings"
 import "core:testing"
 import "core:fmt"
 import "core:os"
+import "core:runtime"
 
 TEST_count := 0
 TEST_fail  := 0
@@ -33,6 +34,7 @@ main :: proc() {
 	test_index_any_small_string_found(&t)
 	test_index_any_larger_string_found(&t)
 	test_cut(&t)
+	test_case_conversion(&t)
 
 	fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
 	if TEST_fail > 0 {
@@ -89,4 +91,48 @@ test_cut :: proc(t: ^testing.T) {
 			test.input, test.offset, test.length, test.output, res)
 		expect(t, res == test.output, msg)
 	}
+}
+
+Case_Kind :: enum {
+	Lower_Space_Case,
+	Upper_Space_Case,
+	Lower_Snake_Case,
+	Upper_Snake_Case,
+	Lower_Kebab_Case,
+	Upper_Kebab_Case,
+	Camel_Case,
+	Pascal_Case,
+	Ada_Case,
+}
+
+test_cases := [Case_Kind]struct{s: string, p: proc(r: string, allocator: runtime.Allocator) -> string}{
+	.Lower_Space_Case = {"hellope world", to_lower_space_case},
+	.Upper_Space_Case = {"HELLOPE WORLD", to_upper_space_case},
+	.Lower_Snake_Case = {"hellope_world", strings.to_snake_case},
+	.Upper_Snake_Case = {"HELLOPE_WORLD", strings.to_upper_snake_case},
+	.Lower_Kebab_Case = {"hellope-world", strings.to_kebab_case},
+	.Upper_Kebab_Case = {"HELLOPE-WORLD", strings.to_upper_kebab_case},
+	.Camel_Case       = {"hellopeWorld",  strings.to_camel_case},
+	.Pascal_Case      = {"HellopeWorld",  strings.to_pascal_case},
+	.Ada_Case         = {"Hellope_World", strings.to_ada_case},
+}
+
+to_lower_space_case :: proc(r: string, allocator: runtime.Allocator) -> string {
+	return strings.to_delimiter_case(r, ' ', false, allocator)
+}
+to_upper_space_case :: proc(r: string, allocator: runtime.Allocator) -> string {
+	return strings.to_delimiter_case(r, ' ', true, allocator)
+}
+
+@test
+test_case_conversion :: proc(t: ^testing.T) {
+	for entry in test_cases {
+		for test_case, case_kind in test_cases {
+			result := entry.p(test_case.s, context.allocator)
+			defer delete(result)
+
+			msg := fmt.tprintf("ERROR: Input `{}` to converter {} does not match `{}`, got `{}`.\n", test_case.s, case_kind, entry.s, result)
+			expect(t, result == entry.s, msg)
+		}
+	}
 }

+ 13 - 0
tests/documentation/build.bat

@@ -0,0 +1,13 @@
+@echo off
+set PATH_TO_ODIN==..\..\odin
+
+echo ---
+echo Building Documentation File
+echo ---
+%PATH_TO_ODIN% doc ..\..\examples\all -all-packages -doc-format || exit /b
+
+
+echo ---
+echo Running Documentation Tester
+echo ---
+%PATH_TO_ODIN% run documentation_tester.odin -file -vet -strict-style -- %PATH_TO_ODIN% || exit /b

+ 421 - 0
tests/documentation/documentation_tester.odin

@@ -0,0 +1,421 @@
+package documentation_tester
+
+import "core:os"
+import "core:io"
+import "core:fmt"
+import "core:strings"
+import "core:odin/ast"
+import "core:odin/parser"
+import "core:c/libc"
+import doc "core:odin/doc-format"
+
+Example_Test :: struct {
+	entity_name: string,
+	package_name: string,
+	example_code: []string,
+	expected_output: []string,
+}
+
+g_header:   ^doc.Header
+g_bad_doc: bool
+g_examples_to_verify: [dynamic]Example_Test
+g_path_to_odin: string
+
+array :: proc(a: $A/doc.Array($T)) -> []T {
+	return doc.from_array(g_header, a)
+}
+
+str :: proc(s: $A/doc.String) -> string {
+	return doc.from_string(g_header, s)
+}
+
+common_prefix :: proc(strs: []string) -> string {
+	if len(strs) == 0 {
+		return ""
+	}
+	n := max(int)
+	for str in strs {
+		n = min(n, len(str))
+	}
+
+	prefix := strs[0][:n]
+	for str in strs[1:] {
+		for len(prefix) != 0 && str[:len(prefix)] != prefix {
+			prefix = prefix[:len(prefix)-1]
+		}
+		if len(prefix) == 0 {
+			break
+		}
+	}
+	return prefix
+}
+
+errorf :: proc(format: string, args: ..any) -> ! {
+	fmt.eprintf("%s ", os.args[0])
+	fmt.eprintf(format, ..args)
+	fmt.eprintln()
+	os.exit(1)
+}
+
+main :: proc() {
+	if len(os.args) != 2 {
+		errorf("expected path to odin executable")
+	}
+	g_path_to_odin = os.args[1]
+	data, ok := os.read_entire_file("all.odin-doc")
+	if !ok {
+		errorf("unable to read file: all.odin-doc")
+	}
+	err: doc.Reader_Error
+	g_header, err = doc.read_from_bytes(data)
+	switch err {
+	case .None:
+	case .Header_Too_Small:
+		errorf("file is too small for the file format")
+	case .Invalid_Magic:
+		errorf("invalid magic for the file format")
+	case .Data_Too_Small:
+		errorf("data is too small for the file format")
+	case .Invalid_Version:
+		errorf("invalid file format version")
+	}
+	pkgs     := array(g_header.pkgs)
+	entities := array(g_header.entities)
+
+	path_prefix: string
+	{
+		fullpaths: [dynamic]string
+		defer delete(fullpaths)
+
+		for pkg in pkgs[1:] {
+			append(&fullpaths, str(pkg.fullpath))
+		}
+		path_prefix = common_prefix(fullpaths[:])
+	}
+
+	for pkg in pkgs[1:] {
+		entries_array := array(pkg.entries)
+		fullpath := str(pkg.fullpath)
+		path := strings.trim_prefix(fullpath, path_prefix)
+		if ! strings.has_prefix(path, "core/") {
+			continue
+		}
+		trimmed_path := strings.trim_prefix(path, "core/")
+		if strings.has_prefix(trimmed_path, "sys") {
+			continue
+		}
+		if strings.contains(trimmed_path, "/_") {
+			continue
+		}
+		for entry in entries_array {
+			entity := entities[entry.entity]
+			find_and_add_examples(
+				docs = str(entity.docs),
+				package_name = str(pkg.name),
+				entity_name = str(entity.name),
+			)
+		}
+	}
+	write_test_suite(g_examples_to_verify[:])
+	if g_bad_doc {
+		errorf("We created bad documentation!")
+	}
+
+	if ! run_test_suite() {
+		errorf("Test suite failed!")
+	}
+	fmt.println("Examples verified")
+}
+
+// NOTE: this is a pretty close copy paste from the website pkg documentation on parsing the docs
+find_and_add_examples :: proc(docs: string, package_name: string, entity_name: string) {
+	if docs == "" {
+		return
+	}
+	Block_Kind :: enum {
+		Other,
+		Example,
+		Output,
+	}
+	Block :: struct {
+		kind: Block_Kind,
+		lines: []string,
+	}
+	lines := strings.split_lines(docs)
+	curr_block_kind := Block_Kind.Other
+	start := 0
+
+	example_block: Block // when set the kind should be Example
+	output_block: Block // when set the kind should be Output
+	// rely on zii that the kinds have not been set
+	assert(example_block.kind != .Example)
+	assert(output_block.kind != .Output)
+
+	insert_block :: proc(block: Block, example: ^Block, output: ^Block, name: string) {
+		switch block.kind {
+		case .Other:
+		case .Example:
+			if example.kind == .Example {
+				fmt.eprintf("The documentation for %q has multiple examples which is not allowed\n", name)
+				g_bad_doc = true
+			}
+			example^ = block
+		case .Output: output^ = block
+			if example.kind == .Output {
+				fmt.eprintf("The documentation for %q has multiple output which is not allowed\n", name)
+				g_bad_doc = true
+			}
+			output^ = block
+		}
+	}
+
+	for line, i in lines {
+		text := strings.trim_space(line)
+		next_block_kind := curr_block_kind
+
+		switch curr_block_kind {
+		case .Other:
+			switch {
+			case strings.has_prefix(line, "Example:"): next_block_kind = .Example
+			case strings.has_prefix(line, "Output:"): next_block_kind = .Output
+			}
+		case .Example:
+			switch {
+			case strings.has_prefix(line, "Output:"): next_block_kind = .Output
+			case ! (text == "" || strings.has_prefix(line, "\t")): next_block_kind = .Other
+			}
+		case .Output:
+			switch {
+			case strings.has_prefix(line, "Example:"): next_block_kind = .Example
+			case ! (text == "" || strings.has_prefix(line, "\t")): next_block_kind = .Other
+			}
+		}
+
+		if i-start > 0 && (curr_block_kind != next_block_kind) {
+			insert_block(Block{curr_block_kind, lines[start:i]}, &example_block, &output_block, entity_name)
+			curr_block_kind, start = next_block_kind, i
+		}
+	}
+
+	if start < len(lines) {
+		insert_block(Block{curr_block_kind, lines[start:]}, &example_block, &output_block, entity_name)
+	}
+
+	if output_block.kind == .Output && example_block.kind != .Example {
+		fmt.eprintf("The documentation for %q has an output block but no example\n", entity_name)
+		g_bad_doc = true
+	}
+
+	// Write example and output block if they're both present
+	if example_block.kind == .Example && output_block.kind == .Output {
+		{
+			// Example block starts with
+			// `Example:` and a number of white spaces,
+			lines := &example_block.lines
+			for len(lines) > 0 && (strings.trim_space(lines[0]) == "" || strings.has_prefix(lines[0], "Example:")) {
+				lines^ = lines[1:]
+			}
+		}
+		{
+			// Output block starts with
+			// `Output:` and a number of white spaces,
+			lines := &output_block.lines
+			for len(lines) > 0 && (strings.trim_space(lines[0]) == "" || strings.has_prefix(lines[0], "Output:")) {
+				lines^ = lines[1:]
+			}
+			// Additionally we need to strip all empty lines at the end of output to not include those in the expected output
+			for len(lines) > 0 && (strings.trim_space(lines[len(lines) - 1]) == "") {
+				lines^ = lines[:len(lines) - 1]
+			}
+		}
+		// Remove first layer of tabs which are always present
+		for line in &example_block.lines {
+			line = strings.trim_prefix(line, "\t")
+		}
+		for line in &output_block.lines {
+			line = strings.trim_prefix(line, "\t")
+		}
+		append(&g_examples_to_verify, Example_Test {
+			entity_name = entity_name,
+			package_name = package_name,
+			example_code = example_block.lines,
+			expected_output = output_block.lines,
+		})
+	}
+}
+
+
+write_test_suite :: proc(example_tests: []Example_Test) {
+	TEST_SUITE_DIRECTORY :: "verify"
+	os.remove_directory(TEST_SUITE_DIRECTORY)
+	os.make_directory(TEST_SUITE_DIRECTORY)
+
+	example_build := strings.builder_make()
+	test_runner := strings.builder_make()
+
+	strings.write_string(&test_runner,
+`//+private
+package documentation_verification
+
+import "core:os"
+import "core:mem"
+import "core:io"
+import "core:fmt"
+import "core:thread"
+import "core:sync"
+import "core:intrinsics"
+
+@(private="file")
+_read_pipe: os.Handle
+@(private="file")
+_write_pipe: os.Handle
+@(private="file")
+_pipe_reader_semaphore: sync.Sema
+@(private="file")
+_out_data: string
+@(private="file")
+_out_buffer: [mem.Megabyte]byte
+@(private="file")
+_bad_test_found: bool
+
+@(private="file")
+_spawn_pipe_reader :: proc() {
+	thread.create_and_start(proc(^thread.Thread) {
+		stream := os.stream_from_handle(_read_pipe)
+		reader := io.to_reader(stream)
+		sync.post(&_pipe_reader_semaphore) // notify thread is ready
+		for {
+			n_read := 0
+			read_to_null_byte := 0
+			finished_reading := false
+			for ! finished_reading {
+				just_read, err := io.read(reader, _out_buffer[n_read:], &n_read); if err != .None {
+					panic("We got an IO error!")
+				}
+				for b in _out_buffer[n_read - just_read: n_read] {
+					if b == 0 {
+						finished_reading = true
+						break
+					}
+				read_to_null_byte += 1
+				}
+			}
+			intrinsics.volatile_store(&_out_data, transmute(string)_out_buffer[:read_to_null_byte])
+			sync.post(&_pipe_reader_semaphore) // notify we read the null byte
+		}
+	})
+
+	sync.wait(&_pipe_reader_semaphore) // wait for thread to be ready
+}
+
+@(private="file")
+_check :: proc(test_name: string, expected: string) {
+	null_byte: [1]byte
+	os.write(_write_pipe, null_byte[:])
+	os.flush(_write_pipe)
+	sync.wait(&_pipe_reader_semaphore)
+	output := intrinsics.volatile_load(&_out_data) // wait for thread to read null byte
+	if expected != output {
+		fmt.eprintf("Test %q got unexpected output:\n%q\n", test_name, output)
+		fmt.eprintf("Expected:\n%q\n", expected)
+		_bad_test_found = true
+	}
+}
+
+main :: proc() {
+	_read_pipe, _write_pipe, _ = os.pipe()
+	os.stdout = _write_pipe
+	_spawn_pipe_reader()
+`)
+	for test in example_tests {
+		strings.builder_reset(&example_build)
+		strings.write_string(&example_build, "package documentation_verification\n\n")
+		for line in test.example_code {
+			strings.write_string(&example_build, line)
+			strings.write_byte(&example_build, '\n')
+		}
+
+		code_string := strings.to_string(example_build)
+
+		example_ast := ast.File { src = code_string }
+		odin_parser := parser.default_parser()
+
+		if ! parser.parse_file(&odin_parser, &example_ast) {
+			g_bad_doc = true
+			continue
+		}
+		if odin_parser.error_count > 0 {
+			fmt.eprintf("Errors on the following code generated for %q:\n%v\n", test.entity_name, code_string)
+			g_bad_doc = true
+			continue
+		}
+
+		enforced_name := fmt.tprintf("%v_example", test.entity_name)
+		index_of_proc_name: int
+		code_test_name: string
+
+		for d in example_ast.decls {
+			value_decl, is_value := d.derived.(^ast.Value_Decl); if ! is_value {
+				continue
+			}
+			if len(value_decl.values) != 1 {
+				continue
+			}
+			proc_lit, is_proc_lit := value_decl.values[0].derived_expr.(^ast.Proc_Lit); if ! is_proc_lit {
+				continue
+			}
+			if len(proc_lit.type.params.list) > 0 {
+				continue
+			}
+			this_procedure_name := code_string[value_decl.names[0].pos.offset:value_decl.names[0].end.offset]
+			if this_procedure_name != enforced_name {
+				continue
+			}
+			index_of_proc_name = value_decl.names[0].pos.offset
+			code_test_name = this_procedure_name
+			break
+		}
+
+		if code_test_name == "" {
+			fmt.eprintf("We could not any find procedure literals with no arguments with the identifier %q for the example for %q\n", enforced_name, test.entity_name)
+			g_bad_doc = true
+			continue
+		}
+
+		fmt.sbprintf(&test_runner, "\t%v_%v()\n", test.package_name, code_test_name)
+		fmt.sbprintf(&test_runner, "\t_check(%q, `", code_test_name)
+		for line in test.expected_output {
+			strings.write_string(&test_runner, line)
+			strings.write_string(&test_runner, "\n")
+		}
+		strings.write_string(&test_runner, "`)\n")
+		save_path := fmt.tprintf("verify/test_%v_%v.odin", test.package_name, code_test_name)
+
+		test_file_handle, err := os.open(save_path, os.O_WRONLY | os.O_CREATE); if err != 0 {
+			fmt.eprintf("We could not open the file to the path %q for writing\n", save_path)
+			g_bad_doc = true
+			continue
+		}
+		defer os.close(test_file_handle)
+		stream := os.stream_from_handle(test_file_handle)
+		writer, ok := io.to_writer(stream); if ! ok {
+			fmt.eprintf("We could not make the writer for the path %q\n", save_path)
+			g_bad_doc = true
+			continue
+		}
+		fmt.wprintf(writer, "%v%v_%v", code_string[:index_of_proc_name], test.package_name, code_string[index_of_proc_name:])
+	}
+
+	strings.write_string(&test_runner,
+`
+	if _bad_test_found {
+		fmt.eprintln("One or more tests failed")
+		os.exit(1)
+	}
+}`)
+	os.write_entire_file("verify/main.odin", transmute([]byte)strings.to_string(test_runner))
+}
+
+run_test_suite :: proc() -> bool {
+	return libc.system(fmt.caprintf("%v run verify", g_path_to_odin)) == 0
+}

+ 1 - 1
tests/internal/build.bat

@@ -1,4 +1,4 @@
 @echo off
 set PATH_TO_ODIN==..\..\odin
-%PATH_TO_ODIN% run test_map.odin -file -vet -strict-style -o:minimal
+%PATH_TO_ODIN% run test_map.odin -file -vet -strict-style -o:minimal || exit /b
 rem -define:SEED=42

+ 4 - 9
tests/issues/run.bat

@@ -5,19 +5,14 @@ pushd build
 
 set COMMON=-collection:tests=..\..
 
-set ERROR_DID_OCCUR=0
-
 @echo on
 
-..\..\..\odin test ..\test_issue_829.odin %COMMON% -file
-..\..\..\odin test ..\test_issue_1592.odin %COMMON% -file
-..\..\..\odin test ..\test_issue_2087.odin %COMMON% -file
-..\..\..\odin build ..\test_issue_2113.odin %COMMON% -file -debug
+..\..\..\odin test ..\test_issue_829.odin %COMMON% -file || exit /b
+..\..\..\odin test ..\test_issue_1592.odin %COMMON% -file || exit /b
+..\..\..\odin test ..\test_issue_2087.odin %COMMON% -file || exit /b
+..\..\..\odin build ..\test_issue_2113.odin %COMMON% -file -debug || exit /b
 
 @echo off
 
-if %ERRORLEVEL% NEQ 0 set ERROR_DID_OCCUR=1
-
 popd
 rmdir /S /Q build
-if %ERROR_DID_OCCUR% NEQ 0 EXIT /B 1

+ 2 - 2
tests/vendor/build.bat

@@ -5,9 +5,9 @@ set PATH_TO_ODIN==..\..\odin
 echo ---
 echo Running vendor:botan tests
 echo ---
-%PATH_TO_ODIN% run botan %COMMON% -out:vendor_botan.exe
+%PATH_TO_ODIN% run botan %COMMON% -out:vendor_botan.exe || exit /b
 
 echo ---
 echo Running vendor:glfw tests
 echo ---
-%PATH_TO_ODIN% run glfw %COMMON% -out:vendor_glfw.exe
+%PATH_TO_ODIN% run glfw %COMMON% -out:vendor_glfw.exe || exit /b

+ 44 - 44
vendor/ENet/enet.odin

@@ -343,58 +343,58 @@ foreign ENet {
 	deinitialize                   :: proc() ---
 	linked_version                 :: proc() -> Version ---
 	time_get                       :: proc() -> u32 ---
-	time_set                       :: proc(u32) ---
+	time_set                       :: proc(newTimeBase: u32) ---
 
 	socket_create                  :: proc(SocketType) -> Socket ---
-	socket_bind                    :: proc(Socket, ^Address) -> i32 ---
-	socket_get_address             :: proc(Socket, ^Address) -> i32 ---
-	socket_listen                  :: proc(Socket, i32) -> i32 ---
-	socket_accept                  :: proc(Socket, ^Address) -> Socket ---
-	socket_connect                 :: proc(Socket, ^Address) -> i32 ---
-	socket_send                    :: proc(Socket, ^Address, ^Buffer, uint) -> i32 ---
-	socket_receive                 :: proc(Socket, ^Address, ^Buffer, uint) -> i32 ---
-	socket_wait                    :: proc(Socket, ^u32, u32) -> i32 ---
-	socket_set_option              :: proc(Socket, SocketOption, i32) -> i32 ---
-	socket_get_option              :: proc(Socket, SocketOption, ^i32) -> i32 ---
-	socket_shutdown                :: proc(Socket, SocketShutdown) -> i32 ---
-	socket_destroy                 :: proc(Socket) ---
-	socketset_select               :: proc(Socket, ^SocketSet, ^SocketSet, u32) -> i32 ---
+	socket_bind                    :: proc(socket: Socket, address: ^Address) -> i32 ---
+	socket_get_address             :: proc(socket: Socket, address: ^Address) -> i32 ---
+	socket_listen                  :: proc(socket: Socket, backlog: i32) -> i32 ---
+	socket_accept                  :: proc(socket: Socket, address: ^Address) -> Socket ---
+	socket_connect                 :: proc(socket: Socket, address: ^Address) -> i32 ---
+	socket_send                    :: proc(socket: Socket, address: ^Address, buffers: [^]Buffer, bufferCount: uint) -> i32 ---
+	socket_receive                 :: proc(socket: Socket, address: ^Address, buffers: [^]Buffer, bufferCount: uint) -> i32 ---
+	socket_wait                    :: proc(socket: Socket, condition: ^u32, timeout: u32) -> i32 ---
+	socket_set_option              :: proc(socket: Socket, option: SocketOption, value: i32) -> i32 ---
+	socket_get_option              :: proc(socket: Socket, option: SocketOption, value: ^i32) -> i32 ---
+	socket_shutdown                :: proc(socket: Socket, how: SocketShutdown) -> i32 ---
+	socket_destroy                 :: proc(socket: Socket) ---
+	socketset_select               :: proc(socket: Socket, readSet: ^SocketSet, writeSet: ^SocketSet, timeout: u32) -> i32 ---
 
 	address_set_host_ip            :: proc(address: ^Address, hostName: cstring) -> i32 ---
 	address_set_host               :: proc(address: ^Address, hostName: cstring) -> i32 ---
 	address_get_host_ip            :: proc(address: ^Address, hostName: [^]u8, nameLength: uint) -> i32 ---
 	address_get_host               :: proc(address: ^Address, hostName: [^]u8, nameLength: uint) -> i32 ---
 
-	packet_create                  :: proc(rawptr, uint, u32) -> ^Packet ---
-	packet_destroy                 :: proc(^Packet) ---
-	packet_resize                  :: proc(^Packet, uint) -> i32 ---
-	crc32                          :: proc(^Buffer, uint) -> u32 ---
-
-	host_create                    :: proc(^Address, uint, uint, u32, u32) -> ^Host ---
-	host_destroy                   :: proc(^Host) ---
-	host_connect                   :: proc(^Host, ^Address, uint, u32) -> ^Peer ---
-	host_check_events              :: proc(^Host, ^Event) -> i32 ---
-	host_service                   :: proc(^Host, ^Event, u32) -> i32 ---
-	host_flush                     :: proc(^Host) ---
-	host_broadcast                 :: proc(^Host, u8, ^Packet) ---
-	host_compress                  :: proc(^Host, ^Compressor) ---
-	host_compress_with_range_coder :: proc(^Host) -> i32 ---
-	host_channel_limit             :: proc(^Host, uint) ---
-	host_bandwidth_limit           :: proc(^Host, u32, u32) ---
-
-	peer_send                      :: proc(^Peer, u8, ^Packet) -> i32 ---
-	peer_receive                   :: proc(^Peer, ^u8) -> ^Packet ---
-	peer_ping                      :: proc(^Peer) ---
-	peer_ping_interval             :: proc(^Peer, u32) ---
-	peer_timeout                   :: proc(^Peer, u32, u32, u32) ---
-	peer_reset                     :: proc(^Peer) ---
-	peer_disconnect                :: proc(^Peer, u32) ---
-	peer_disconnect_now            :: proc(^Peer, u32) ---
-	peer_disconnect_later          :: proc(^Peer, u32) ---
-	peer_throttle_configure        :: proc(^Peer, u32, u32, u32) ---
+	packet_create                  :: proc(data: rawptr, dataLength: uint, flags: PacketFlag) -> ^Packet ---
+	packet_destroy                 :: proc(packet: ^Packet) ---
+	packet_resize                  :: proc(packet: ^Packet, dataLength: uint) -> i32 ---
+	crc32                          :: proc(buffers: [^]Buffer, bufferCount: uint) -> u32 ---
+
+	host_create                    :: proc(address: ^Address, peerCount: uint, channelLimit: uint, incomingBandwidth: u32, outgoingBandwidth: u32) -> ^Host ---
+	host_destroy                   :: proc(host: ^Host) ---
+	host_connect                   :: proc(host: ^Host, address: ^Address, channelCount: uint, data: u32) -> ^Peer ---
+	host_check_events              :: proc(host: ^Host, event: ^Event) -> i32 ---
+	host_service                   :: proc(host: ^Host, event: ^Event, timeout: u32) -> i32 ---
+	host_flush                     :: proc(host: ^Host) ---
+	host_broadcast                 :: proc(host: ^Host, channelID: u8, packet: ^Packet) ---
+	host_compress                  :: proc(host: ^Host, compressor: ^Compressor) ---
+	host_compress_with_range_coder :: proc(host: ^Host) -> i32 ---
+	host_channel_limit             :: proc(host: ^Host, channelLimit: uint) ---
+	host_bandwidth_limit           :: proc(host: ^Host, incomingBandwidth: u32, outgoingBandwidth: u32) ---
+
+	peer_send                      :: proc(peer: ^Peer, channelID: u8, packet: ^Packet) -> i32 ---
+	peer_receive                   :: proc(peer: ^Peer, channelID: ^u8) -> ^Packet ---
+	peer_ping                      :: proc(peer: ^Peer) ---
+	peer_ping_interval             :: proc(peer: ^Peer, pingInterval: u32) ---
+	peer_timeout                   :: proc(peer: ^Peer, timoutLimit: u32, timeoutMinimum: u32, timeoutMaximum: u32) ---
+	peer_reset                     :: proc(peer: ^Peer) ---
+	peer_disconnect                :: proc(peer: ^Peer, data: u32) ---
+	peer_disconnect_now            :: proc(peer: ^Peer, data: u32) ---
+	peer_disconnect_later          :: proc(peer: ^Peer, data: u32) ---
+	peer_throttle_configure        :: proc(peer: ^Peer, interval: u32, acceleration: u32, deceleration: u32) ---
 
 	range_coder_create             :: proc() -> rawptr ---
-	range_coder_destroy            :: proc(rawptr) ---
-	range_coder_compress           :: proc(rawptr, [^]Buffer, uint, uint, [^]u8, uint) -> uint ---
-	range_coder_decompress         :: proc(rawptr, [^]u8, uint, [^]u8, uint) -> uint ---
+	range_coder_destroy            :: proc(ctx: rawptr) ---
+	range_coder_compress           :: proc(ctx: rawptr, inBuffers: [^]Buffer, inBufferCount: uint, inLimit: uint, outData: [^]u8, outLimit: uint) -> uint ---
+	range_coder_decompress         :: proc(ctx: rawptr, inData: [^]u8, inLimit: uint, outData: [^]u8, outLimit: uint) -> uint ---
 }

+ 1 - 1
vendor/raylib/LICENSE

@@ -1,4 +1,4 @@
-Copyright (c) 2013-2021 Ramon Santamaria (@raysan5)
+Copyright (c) 2013-2023 Ramon Santamaria (@raysan5)
 
 This software is provided "as-is", without any express or implied warranty. In no event 
 will the authors be held liable for any damages arising from the use of this software.

+ 55 - 21
vendor/raylib/README.md

@@ -12,15 +12,17 @@ Ready to learn? Jump to [code examples!](https://www.raylib.com/examples.html)
 
 <br>
 
-[![GitHub contributors](https://img.shields.io/github/contributors/raysan5/raylib)](https://github.com/raysan5/raylib/graphs/contributors)
-[![GitHub All Releases](https://img.shields.io/github/downloads/raysan5/raylib/total)](https://github.com/raysan5/raylib/releases)
-[![GitHub commits since tagged version](https://img.shields.io/github/commits-since/raysan5/raylib/4.0.0)](https://github.com/raysan5/raylib/commits/master)
+[![GitHub Releases Downloads](https://img.shields.io/github/downloads/raysan5/raylib/total)](https://github.com/raysan5/raylib/releases)
+[![GitHub Stars](https://img.shields.io/github/stars/raysan5/raylib?style=flat&label=stars)](https://github.com/raysan5/raylib/stargazers)
+[![GitHub commits since tagged version](https://img.shields.io/github/commits-since/raysan5/raylib/4.2.0)](https://github.com/raysan5/raylib/commits/master)
+[![GitHub Sponsors](https://img.shields.io/github/sponsors/raysan5?label=sponsors)](https://github.com/sponsors/raysan5)
+[![Packaging Status](https://repology.org/badge/tiny-repos/raylib.svg)](https://repology.org/project/raylib/versions)
 [![License](https://img.shields.io/badge/license-zlib%2Flibpng-blue.svg)](LICENSE)
 
-[![Chat on Discord](https://img.shields.io/discord/426912293134270465.svg?logo=discord)](https://discord.gg/raylib)
-[![GitHub stars](https://img.shields.io/github/stars/raysan5/raylib?style=social)](https://github.com/raysan5/raylib/stargazers)
-[![Twitter Follow](https://img.shields.io/twitter/follow/raysan5?style=social)](https://twitter.com/raysan5)
-[![Subreddit subscribers](https://img.shields.io/reddit/subreddit-subscribers/raylib?style=social)](https://www.reddit.com/r/raylib/)
+[![Discord Members](https://img.shields.io/discord/426912293134270465.svg?label=Discord&logo=discord)](https://discord.gg/raylib)
+[![Subreddit Subscribers](https://img.shields.io/reddit/subreddit-subscribers/raylib?label=reddit%20r%2Fraylib&logo=reddit)](https://www.reddit.com/r/raylib/)
+[![Youtube Subscribers](https://img.shields.io/youtube/channel/subscribers/UC8WIBkhYb5sBNqXO1mZ7WSQ?style=flat&label=Youtube&logo=youtube)](https://www.youtube.com/c/raylib)
+[![Twitch Status](https://img.shields.io/twitch/status/raysan5?style=flat&label=Twitch&logo=twitch)](https://www.twitch.tv/raysan5)
 
 [![Windows](https://github.com/raysan5/raylib/workflows/Windows/badge.svg)](https://github.com/raysan5/raylib/actions?query=workflow%3AWindows)
 [![Linux](https://github.com/raysan5/raylib/workflows/Linux/badge.svg)](https://github.com/raysan5/raylib/actions?query=workflow%3ALinux)
@@ -36,10 +38,10 @@ features
 --------
   - **NO external dependencies**, all required libraries are [bundled into raylib](https://github.com/raysan5/raylib/tree/master/src/external)
   - Multiple platforms supported: **Windows, Linux, MacOS, RPI, Android, HTML5... and more!**
-  - Written in plain C code (C99) in PascalCase/camelCase notation
+  - Written in plain C code (C99) using PascalCase/camelCase notation
   - Hardware accelerated with OpenGL (**1.1, 2.1, 3.3, 4.3 or ES 2.0**)
   - **Unique OpenGL abstraction layer** (usable as standalone module): [rlgl](https://github.com/raysan5/raylib/blob/master/src/rlgl.h)
-  - Multiple **Fonts** formats supported (TTF, XNA fonts, AngelCode fonts)
+  - Multiple **Fonts** formats supported (TTF, Image fonts, AngelCode fonts)
   - Multiple texture formats supported, including **compressed formats** (DXT, ETC, ASTC)
   - **Full 3D support**, including 3D Shapes, Models, Billboards, Heightmaps and more! 
   - Flexible Materials system, supporting classic maps and **PBR maps**
@@ -49,7 +51,7 @@ features
   - Audio loading and playing with streaming support (WAV, OGG, MP3, FLAC, XM, MOD)
   - **VR stereo rendering** support with configurable HMD device parameters
   - Huge examples collection with [+120 code examples](https://github.com/raysan5/raylib/tree/master/examples)!
-  - Bindings to [+50 programming languages](https://github.com/raysan5/raylib/blob/master/BINDINGS.md)!
+  - Bindings to [+60 programming languages](https://github.com/raysan5/raylib/blob/master/BINDINGS.md)!
   - **Free and open source**.
 
 basic example
@@ -61,25 +63,57 @@ package example
 import rl "vendor:raylib"
 
 main :: proc() {
-	rl.InitWindow(800, 450, "raylib [core] example - basic window")
+    rl.InitWindow(800, 450, "raylib [core] example - basic window")
 
-	for !rl.WindowShouldClose() {
-		rl.BeginDrawing()
-			rl.ClearBackground(rl.RAYWHITE)
-			rl.DrawText("Congrats! You created your first window!", 190, 200, 20, rl.LIGHTGRAY)
-		rl.EndDrawing()
-	}
+    for !rl.WindowShouldClose() {
+        rl.BeginDrawing()
+            rl.ClearBackground(rl.RAYWHITE)
+            rl.DrawText("Congrats! You created your first window!", 190, 200, 20, rl.LIGHTGRAY)
+        rl.EndDrawing()
+    }
 
-	rl.CloseWindow()
+    rl.CloseWindow()
 }
 ```
 
+
+build and installation
+----------------------
+
+raylib binary releases for Windows, Linux, macOS, Android and HTML5 are available at the [Github Releases page](https://github.com/raysan5/raylib/releases).
+
+raylib is also available via multiple [package managers](https://github.com/raysan5/raylib/issues/613) on multiple OS distributions.
+
+#### Installing and building raylib on multiple platforms
+
+[raylib Wiki](https://github.com/raysan5/raylib/wiki#development-platforms) contains detailed instructions on building and usage on multiple platforms.
+
+ - [Working on Windows](https://github.com/raysan5/raylib/wiki/Working-on-Windows)
+ - [Working on macOS](https://github.com/raysan5/raylib/wiki/Working-on-macOS)
+ - [Working on GNU Linux](https://github.com/raysan5/raylib/wiki/Working-on-GNU-Linux)
+ - [Working on Chrome OS](https://github.com/raysan5/raylib/wiki/Working-on-Chrome-OS)
+ - [Working on FreeBSD](https://github.com/raysan5/raylib/wiki/Working-on-FreeBSD)
+ - [Working on Raspberry Pi](https://github.com/raysan5/raylib/wiki/Working-on-Raspberry-Pi)
+ - [Working for Android](https://github.com/raysan5/raylib/wiki/Working-for-Android)
+ - [Working for Web (HTML5)](https://github.com/raysan5/raylib/wiki/Working-for-Web-(HTML5))
+ - [Working anywhere with CMake](https://github.com/raysan5/raylib/wiki/Working-with-CMake)
+
+*Note that the Wiki is open for edit, if you find some issues while building raylib for your target platform, feel free to edit the Wiki or open an issue related to it.*
+
+#### Setup raylib with multiple IDEs
+
+raylib has been developed on Windows platform using [Notepad++](https://notepad-plus-plus.org/) and [MinGW GCC](https://www.mingw-w64.org/) compiler but it can be used with other IDEs on multiple platforms.
+
+[Projects directory](https://github.com/raysan5/raylib/tree/master/projects) contains several ready-to-use **project templates** to build raylib and code examples with multiple IDEs.
+
+*Note that there are lots of IDEs supported, some of the provided templates could require some review, so please, if you find some issue with a template or you think they could be improved, feel free to send a PR or open a related issue.*
+
 learning and docs
 ------------------
 
-raylib is designed to be learned using [the examples](https://github.com/raysan5/raylib/tree/master/examples) as the main reference. There is no standard API documentation but there is a [**cheatsheet**](https://www.raylib.com/cheatsheet/cheatsheet.html) containing all the functions available on the library and a short description of each one of them, input parameters and result value names should be intuitive enough to understand how each function works. 
+raylib is designed to be learned using [the examples](https://github.com/raysan5/raylib/tree/master/examples) as the main reference. There is no standard API documentation but there is a [**cheatsheet**](https://www.raylib.com/cheatsheet/cheatsheet.html) containing all the functions available on the library a short description of each one of them, input parameters and result value names should be intuitive enough to understand how each function works.
 
-Some additional documentation about raylib design can be found in raylib GitHub Wiki. Here the more relevant links:
+Some additional documentation about raylib design can be found in raylib GitHub Wiki. Here are the relevant links:
 
  - [raylib cheatsheet](https://www.raylib.com/cheatsheet/cheatsheet.html)
  - [raylib architecture](https://github.com/raysan5/raylib/wiki/raylib-architecture)
@@ -106,4 +140,4 @@ license
 
 raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, BSD-like license that allows static linking with closed source software. Check [LICENSE](LICENSE) for further details.
 
-raylib uses internally some libraries for window/graphics/inputs management and also to support different fileformats loading, all those libraries are embedded with and are available in [src/external](https://github.com/raysan5/raylib/tree/master/src/external) directory. Check [raylib dependencies LICENSES](https://github.com/raysan5/raylib/wiki/raylib-dependencies) on raylib Wiki for details.
+raylib uses internally some libraries for window/graphics/inputs management and also to support different file formats loading, all those libraries are embedded with and are available in [src/external](https://github.com/raysan5/raylib/tree/master/src/external) directory. Check [raylib dependencies LICENSES](https://github.com/raysan5/raylib/wiki/raylib-dependencies) on raylib Wiki for details.

BIN=BIN
vendor/raylib/linux/libraylib.a


BIN=BIN
vendor/raylib/linux/libraylib.so


BIN=BIN
vendor/raylib/linux/libraylib.so.4.0.0


BIN=BIN
vendor/raylib/linux/libraylib.so.4.5.0


BIN=BIN
vendor/raylib/linux/libraylib.so.400


BIN=BIN
vendor/raylib/linux/libraylib.so.450


BIN=BIN
vendor/raylib/macos-arm64/libraylib.4.0.0.dylib


BIN=BIN
vendor/raylib/macos-arm64/libraylib.4.5.0.dylib


BIN=BIN
vendor/raylib/macos-arm64/libraylib.400.dylib


BIN=BIN
vendor/raylib/macos-arm64/libraylib.450.dylib


BIN=BIN
vendor/raylib/macos-arm64/libraylib.a


BIN=BIN
vendor/raylib/macos-arm64/libraylib.dylib


BIN=BIN
vendor/raylib/macos/libraylib.4.0.0.dylib


BIN=BIN
vendor/raylib/macos/libraylib.4.5.0.dylib


BIN=BIN
vendor/raylib/macos/libraylib.400.dylib


BIN=BIN
vendor/raylib/macos/libraylib.450.dylib


BIN=BIN
vendor/raylib/macos/libraylib.a


BIN=BIN
vendor/raylib/macos/libraylib.dylib


BIN=BIN
vendor/raylib/raylib.lib


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 408 - 412
vendor/raylib/raylib.odin


+ 321 - 153
vendor/raylib/rlgl.odin

@@ -1,10 +1,116 @@
+/**********************************************************************************************
+*
+*   rlgl v4.5 - A multi-OpenGL abstraction layer with an immediate-mode style API
+*
+*   An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0)
+*   that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...)
+*
+*   When choosing an OpenGL backend different than OpenGL 1.1, some internal buffer are
+*   initialized on rlglInit() to accumulate vertex data.
+*
+*   When an internal state change is required all the stored vertex data is renderer in batch,
+*   additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch.
+*
+*   Some additional resources are also loaded for convenience, here the complete list:
+*      - Default batch (RLGL.defaultBatch): RenderBatch system to accumulate vertex data
+*      - Default texture (RLGL.defaultTextureId): 1x1 white pixel R8G8B8A8
+*      - Default shader (RLGL.State.defaultShaderId, RLGL.State.defaultShaderLocs)
+*
+*   Internal buffer (and additional resources) must be manually unloaded calling rlglClose().
+*
+*
+*   CONFIGURATION:
+*
+*   #define GRAPHICS_API_OPENGL_11
+*   #define GRAPHICS_API_OPENGL_21
+*   #define GRAPHICS_API_OPENGL_33
+*   #define GRAPHICS_API_OPENGL_43
+*   #define GRAPHICS_API_OPENGL_ES2
+*       Use selected OpenGL graphics backend, should be supported by platform
+*       Those preprocessor defines are only used on rlgl module, if OpenGL version is
+*       required by any other module, use rlGetVersion() to check it
+*
+*   #define RLGL_IMPLEMENTATION
+*       Generates the implementation of the library into the included file.
+*       If not defined, the library is in header only mode and can be included in other headers
+*       or source files without problems. But only ONE file should hold the implementation.
+*
+*   #define RLGL_RENDER_TEXTURES_HINT
+*       Enable framebuffer objects (fbo) support (enabled by default)
+*       Some GPUs could not support them despite the OpenGL version
+*
+*   #define RLGL_SHOW_GL_DETAILS_INFO
+*       Show OpenGL extensions and capabilities detailed logs on init
+*
+*   #define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
+*       Enable debug context (only available on OpenGL 4.3)
+*
+*   rlgl capabilities could be customized just defining some internal
+*   values before library inclusion (default values listed):
+*
+*   #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS   8192    // Default internal render batch elements limits
+*   #define RL_DEFAULT_BATCH_BUFFERS              1    // Default number of batch buffers (multi-buffering)
+*   #define RL_DEFAULT_BATCH_DRAWCALLS          256    // Default number of batch draw calls (by state changes: mode, texture)
+*   #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS    4    // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture())
+*
+*   #define RL_MAX_MATRIX_STACK_SIZE             32    // Maximum size of internal Matrix stack
+*   #define RL_MAX_SHADER_LOCATIONS              32    // Maximum number of shader locations supported
+*   #define RL_CULL_DISTANCE_NEAR              0.01    // Default projection matrix near cull distance
+*   #define RL_CULL_DISTANCE_FAR             1000.0    // Default projection matrix far cull distance
+*
+*   When loading a shader, the following vertex attribute and uniform
+*   location names are tried to be set automatically:
+*
+*   #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION     "vertexPosition"    // Bound by default to shader location: 0
+*   #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD     "vertexTexCoord"    // Bound by default to shader location: 1
+*   #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL       "vertexNormal"      // Bound by default to shader location: 2
+*   #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR        "vertexColor"       // Bound by default to shader location: 3
+*   #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT      "vertexTangent"     // Bound by default to shader location: 4
+*   #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP         "mvp"               // model-view-projection matrix
+*   #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW        "matView"           // view matrix
+*   #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION  "matProjection"     // projection matrix
+*   #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL       "matModel"          // model matrix
+*   #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL      "matNormal"         // normal matrix (transpose(inverse(matModelView))
+*   #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR       "colDiffuse"        // color diffuse (base tint color, multiplied by texture color)
+*   #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0  "texture0"          // texture0 (texture slot active 0)
+*   #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1  "texture1"          // texture1 (texture slot active 1)
+*   #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2  "texture2"          // texture2 (texture slot active 2)
+*
+*   DEPENDENCIES:
+*
+*      - OpenGL libraries (depending on platform and OpenGL version selected)
+*      - GLAD OpenGL extensions loading library (only for OpenGL 3.3 Core, 4.3 Core)
+*
+*
+*   LICENSE: zlib/libpng
+*
+*   Copyright (c) 2014-2023 Ramon Santamaria (@raysan5)
+*
+*   This software is provided "as-is", without any express or implied warranty. In no event
+*   will the authors be held liable for any damages arising from the use of this software.
+*
+*   Permission is granted to anyone to use this software for any purpose, including commercial
+*   applications, and to alter it and redistribute it freely, subject to the following restrictions:
+*
+*     1. The origin of this software must not be misrepresented; you must not claim that you
+*     wrote the original software. If you use this software in a product, an acknowledgment
+*     in the product documentation would be appreciated but is not required.
+*
+*     2. Altered source versions must be plainly marked as such, and must not be misrepresented
+*     as being the original software.
+*
+*     3. This notice may not be removed or altered from any source distribution.
+*
+**********************************************************************************************/
+
+
 package raylib
 
 import "core:c"
 
 when ODIN_OS == .Windows {
 	foreign import lib {
-		"raylib.lib",
+		"windows/raylib.lib",
 		"system:Winmm.lib",
 		"system:Gdi32.lib",
 		"system:User32.lib",
@@ -13,37 +119,51 @@ when ODIN_OS == .Windows {
 } else when ODIN_OS == .Linux  {
 	foreign import lib "linux/libraylib.a"
 } else when ODIN_OS == .Darwin {
-	foreign import lib "macos/libraylib.a"
+	when ODIN_ARCH == .arm64 {
+		foreign import lib {
+			"macos-arm64/libraylib.a",
+			"system:Cocoa.framework",
+			"system:OpenGL.framework",
+			"system:IOKit.framework",
+		}
+	} else {
+		foreign import lib {
+			"macos/libraylib.a",
+			"system:Cocoa.framework",
+			"system:OpenGL.framework",
+			"system:IOKit.framework",
+		}
+	}
 } else {
 	foreign import lib "system:raylib"
 }
 
-GRAPHICS_API_OPENGL_11  :: false
-GRAPHICS_API_OPENGL_21  :: true
-GRAPHICS_API_OPENGL_33  :: GRAPHICS_API_OPENGL_21
-GRAPHICS_API_OPENGL_ES2 :: false
-GRAPHICS_API_OPENGL_43  :: false
+RL_GRAPHICS_API_OPENGL_11  :: false
+RL_GRAPHICS_API_OPENGL_21  :: true
+RL_GRAPHICS_API_OPENGL_33  :: RL_GRAPHICS_API_OPENGL_21 // default currently
+RL_GRAPHICS_API_OPENGL_ES2 :: false
+RL_GRAPHICS_API_OPENGL_43  :: false
 
-when !GRAPHICS_API_OPENGL_ES2 {
+when !RL_GRAPHICS_API_OPENGL_ES2 {
 	// This is the maximum amount of elements (quads) per batch
 	// NOTE: Be careful with text, every letter maps to a quad
-	DEFAULT_BATCH_BUFFER_ELEMENTS :: 8192
+	RL_DEFAULT_BATCH_BUFFER_ELEMENTS :: 8192
 } else {
 	// We reduce memory sizes for embedded systems (RPI and HTML5)
 	// NOTE: On HTML5 (emscripten) this is allocated on heap,
 	// by default it's only 16MB!...just take care...
-	DEFAULT_BATCH_BUFFER_ELEMENTS :: 2048
+	RL_DEFAULT_BATCH_BUFFER_ELEMENTS :: 2048
 }
 
-DEFAULT_BATCH_BUFFERS          :: 1                    // Default number of batch buffers (multi-buffering)
-DEFAULT_BATCH_DRAWCALLS        :: 256                  // Default number of batch draw calls (by state changes: mode, texture)
-MAX_BATCH_ACTIVE_TEXTURES      :: 4                    // Maximum number of additional textures that can be activated on batch drawing (SetShaderValueTexture())
+RL_DEFAULT_BATCH_BUFFERS            :: 1                    // Default number of batch buffers (multi-buffering)
+RL_DEFAULT_BATCH_DRAWCALLS          :: 256                  // Default number of batch draw calls (by state changes: mode, texture)
+RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS  :: 4                    // Maximum number of additional textures that can be activated on batch drawing (SetShaderValueTexture())
 
 // Internal Matrix stack
-MAX_MATRIX_STACK_SIZE          :: 32                   // Maximum size of Matrix stack
+RL_MAX_MATRIX_STACK_SIZE          :: 32                   // Maximum size of Matrix stack
 
 // Shader limits
-MAX_SHADER_LOCATIONS           :: 32                   // Maximum number of shader locations supported
+RL_MAX_SHADER_LOCATIONS           :: 32                   // Maximum number of shader locations supported
 
 // Projection matrix culling
 RL_CULL_DISTANCE_NEAR          :: 0.01                 // Default near cull distance
@@ -98,87 +218,129 @@ RL_FRAGMENT_SHADER                      :: 0x8B30      // GL_FRAGMENT_SHADER
 RL_VERTEX_SHADER                        :: 0x8B31      // GL_VERTEX_SHADER
 RL_COMPUTE_SHADER                       :: 0x91B9      // GL_COMPUTE_SHADER
 
+// GL blending factors
+RL_ZERO                                 :: 0           // GL_ZERO
+RL_ONE                                  :: 1           // GL_ONE
+RL_SRC_COLOR                            :: 0x0300      // GL_SRC_COLOR
+RL_ONE_MINUS_SRC_COLOR                  :: 0x0301      // GL_ONE_MINUS_SRC_COLOR
+RL_SRC_ALPHA                            :: 0x0302      // GL_SRC_ALPHA
+RL_ONE_MINUS_SRC_ALPHA                  :: 0x0303      // GL_ONE_MINUS_SRC_ALPHA
+RL_DST_ALPHA                            :: 0x0304      // GL_DST_ALPHA
+RL_ONE_MINUS_DST_ALPHA                  :: 0x0305      // GL_ONE_MINUS_DST_ALPHA
+RL_DST_COLOR                            :: 0x0306      // GL_DST_COLOR
+RL_ONE_MINUS_DST_COLOR                  :: 0x0307      // GL_ONE_MINUS_DST_COLOR
+RL_SRC_ALPHA_SATURATE                   :: 0x0308      // GL_SRC_ALPHA_SATURATE
+RL_CONSTANT_COLOR                       :: 0x8001      // GL_CONSTANT_COLOR
+RL_ONE_MINUS_CONSTANT_COLOR             :: 0x8002      // GL_ONE_MINUS_CONSTANT_COLOR
+RL_CONSTANT_ALPHA                       :: 0x8003      // GL_CONSTANT_ALPHA
+RL_ONE_MINUS_CONSTANT_ALPHA             :: 0x8004      // GL_ONE_MINUS_CONSTANT_ALPHA
+
+// GL blending functions/equations
+RL_FUNC_ADD                             :: 0x8006      // GL_FUNC_ADD
+RL_MIN                                  :: 0x8007      // GL_MIN
+RL_MAX                                  :: 0x8008      // GL_MAX
+RL_FUNC_SUBTRACT                        :: 0x800A      // GL_FUNC_SUBTRACT
+RL_FUNC_REVERSE_SUBTRACT                :: 0x800B      // GL_FUNC_REVERSE_SUBTRACT
+RL_BLEND_EQUATION                       :: 0x8009      // GL_BLEND_EQUATION
+RL_BLEND_EQUATION_RGB                   :: 0x8009      // GL_BLEND_EQUATION_RGB   // (Same as BLEND_EQUATION)
+RL_BLEND_EQUATION_ALPHA                 :: 0x883D      // GL_BLEND_EQUATION_ALPHA
+RL_BLEND_DST_RGB                        :: 0x80C8      // GL_BLEND_DST_RGB
+RL_BLEND_SRC_RGB                        :: 0x80C9      // GL_BLEND_SRC_RGB
+RL_BLEND_DST_ALPHA                      :: 0x80CA      // GL_BLEND_DST_ALPHA
+RL_BLEND_SRC_ALPHA                      :: 0x80CB      // GL_BLEND_SRC_ALPHA
+RL_BLEND_COLOR                          :: 0x8005      // GL_BLEND_COLOR
+
 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
-GlVersion :: enum c.int { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 }
-
-FramebufferAttachType :: enum c. int {
-	COLOR_CHANNEL0 = 0,
-	COLOR_CHANNEL1,
-	COLOR_CHANNEL2,
-	COLOR_CHANNEL3,
-	COLOR_CHANNEL4,
-	COLOR_CHANNEL5,
-	COLOR_CHANNEL6,
-	COLOR_CHANNEL7,
-	DEPTH = 100,
-	STENCIL = 200,
-}
 
-FramebufferAttachTextureType :: enum c.int {
-	CUBEMAP_POSITIVE_X = 0,
-	CUBEMAP_NEGATIVE_X,
-	CUBEMAP_POSITIVE_Y,
-	CUBEMAP_NEGATIVE_Y,
-	CUBEMAP_POSITIVE_Z,
-	CUBEMAP_NEGATIVE_Z,
-	TEXTURE2D = 100,
-	RENDERBUFFER = 200,
-}
 
-VertexBufferIndexType :: c.ushort when GRAPHICS_API_OPENGL_ES2 else c.uint
+VertexBufferIndexType :: c.ushort when RL_GRAPHICS_API_OPENGL_ES2 else c.uint
 
 // Dynamic vertex buffers (position + texcoords + colors + indices arrays)
 VertexBuffer :: struct {
-	elementsCount: c.int,                    // Number of elements in the buffer (QUADS)
-
-	vCounter:      c.int,                    // Vertex position counter to process (and draw) from full buffer
-	tcCounter:     c.int,                    // Vertex texcoord counter to process (and draw) from full buffer
-	cCounter:      c.int,                    // Vertex color counter to process (and draw) from full buffer
-
-	vertices:      [^]f32,                   // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
-	texcoords:     [^]f32,                   // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
-	colors:        [^]u8,                    // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
-	indices:       [^]VertexBufferIndexType, // Vertex indices (in case vertex data comes indexed) (6 indices per quad)
-	vaoId:         u32,                      // OpenGL Vertex Array Object id
-	vboId:         [4]u32,                   // OpenGL Vertex Buffer Objects id (4 types of vertex data)
-} 
+	elementCount: c.int,                 // Number of elements in the buffer (QUADS)
+
+	vertices:  [^]f32,                   // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
+	texcoords: [^]f32,                   // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
+	colors:    [^]u8,                    // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
+	indices:   [^]VertexBufferIndexType, // Vertex indices (in case vertex data comes indexed) (6 indices per quad)
+	vaoId:     c.uint,                   // OpenGL Vertex Array Object id
+	vboId:     [4]c.uint,                // OpenGL Vertex Buffer Objects id (4 types of vertex data)
+}
 
 // Draw call type
 // NOTE: Only texture changes register a new draw, other state-change-related elements are not
 // used at this moment (vaoId, shaderId, matrices), raylib just forces a batch draw call if any
 // of those state-change happens (this is done in core module)
 DrawCall :: struct {
-	mode:            c.int,       // Drawing mode: LINES, TRIANGLES, QUADS
-	vertexCount:     c.int,       // Number of vertex of the draw
-	vertexAlignment: c.int,       // Number of vertex required for index alignment (LINES, TRIANGLES)
-	//vaoId: u32,                 // Vertex array id to be used on the draw -> Using RLGL.currentBatch->vertexBuffer.vaoId
-	//shaderId: u32,              // Shader id to be used on the draw -> Using RLGL.currentShader.id
-	textureId: u32,               // Texture id to be used on the draw -> Use to create new draw call if changes
-
-	//projection: Matrix,         // Projection matrix for this draw -> Using RLGL.projection by default
-	//modelview:  Matrix,         // Modelview matrix for this draw -> Using RLGL.modelview by default
-} 
+	mode:            c.int,        // Drawing mode: LINES, TRIANGLES, QUADS
+	vertexCount:     c.int,        // Number of vertex of the draw
+	vertexAlignment: c.int,        // Number of vertex required for index alignment (LINES, TRIANGLES)
+	textureId:       c.uint,       // Texture id to be used on the draw -> Use to create new draw call if changes
+}
 
 // RenderBatch type
 RenderBatch :: struct {
-	buffersCount:  c.int,           // Number of vertex buffers (multi-buffering support)
+	bufferCount:   c.int,           // Number of vertex buffers (multi-buffering support)
 	currentBuffer: c.int,           // Current buffer tracking in case of multi-buffering
 	vertexBuffer:  [^]VertexBuffer, // Dynamic buffer(s) for vertex data
 
-	draws:        [^]DrawCall,      // Draw calls array, depends on textureId
-	drawsCounter: c.int,            // Draw calls counter
-	currentDepth: f32,              // Current depth value for next draw
+	draws:         [^]DrawCall,     // Draw calls array, depends on textureId
+	drawCounter:   c.int,           // Draw calls counter
+	currentDepth:  f32,             // Current depth value for next draw
 }
 
+
+// OpenGL version
+GlVersion :: enum c.int {
+	OPENGL_11 = 1,           // OpenGL 1.1
+	OPENGL_21,               // OpenGL 2.1 (GLSL 120)
+	OPENGL_33,               // OpenGL 3.3 (GLSL 330)
+	OPENGL_43,               // OpenGL 4.3 (using GLSL 330)
+	OPENGL_ES_20,            // OpenGL ES 2.0 (GLSL 100)
+}
+
+
 // Shader attribute data types
 ShaderAttributeDataType :: enum c.int {
-	FLOAT = 0,
-	VEC2,
-	VEC3,
-	VEC4,
+	FLOAT = 0,         // Shader attribute type: float
+	VEC2,              // Shader attribute type: vec2 (2 float)
+	VEC3,              // Shader attribute type: vec3 (3 float)
+	VEC4,              // Shader attribute type: vec4 (4 float)
+}
+
+// Framebuffer attachment type
+// NOTE: By default up to 8 color channels defined, but it can be more
+FramebufferAttachType :: enum c.int {
+	COLOR_CHANNEL0 = 0,   // Framebuffer attachment type: color 0
+	COLOR_CHANNEL1,       // Framebuffer attachment type: color 1
+	COLOR_CHANNEL2,       // Framebuffer attachment type: color 2
+	COLOR_CHANNEL3,       // Framebuffer attachment type: color 3
+	COLOR_CHANNEL4,       // Framebuffer attachment type: color 4
+	COLOR_CHANNEL5,       // Framebuffer attachment type: color 5
+	COLOR_CHANNEL6,       // Framebuffer attachment type: color 6
+	COLOR_CHANNEL7,       // Framebuffer attachment type: color 7
+	DEPTH = 100,          // Framebuffer attachment type: depth
+	STENCIL = 200,        // Framebuffer attachment type: stencil
+}
+
+// Framebuffer texture attachment type
+FramebufferAttachTextureType :: enum c.int {
+	CUBEMAP_POSITIVE_X = 0, // Framebuffer texture attachment type: cubemap, +X side
+	CUBEMAP_NEGATIVE_X,     // Framebuffer texture attachment type: cubemap, -X side
+	CUBEMAP_POSITIVE_Y,     // Framebuffer texture attachment type: cubemap, +Y side
+	CUBEMAP_NEGATIVE_Y,     // Framebuffer texture attachment type: cubemap, -Y side
+	CUBEMAP_POSITIVE_Z,     // Framebuffer texture attachment type: cubemap, +Z side
+	CUBEMAP_NEGATIVE_Z,     // Framebuffer texture attachment type: cubemap, -Z side
+	TEXTURE2D = 100,        // Framebuffer texture attachment type: texture2d
+	RENDERBUFFER = 200,     // Framebuffer texture attachment type: renderbuffer
+}
+
+CullMode :: enum c.int {
+	FRONT = 0,
+	BACK,
 }
 
 @(default_calling_convention="c")
@@ -219,38 +381,38 @@ foreign lib {
 	//------------------------------------------------------------------------------------
 
 	// Vertex buffers state
-	rlEnableVertexArray          :: proc(vaoId: u32) -> bool --- // Enable vertex array (VAO, if supported)
-	rlDisableVertexArray         :: proc() ---                   // Disable vertex array (VAO, if supported)
-	rlEnableVertexBuffer         :: proc(id: u32) ---            // Enable vertex buffer (VBO)
-	rlDisableVertexBuffer        :: proc() ---                   // Disable vertex buffer (VBO)
-	rlEnableVertexBufferElement  :: proc(id: u32) ---            // Enable vertex buffer element (VBO element)
-	rlDisableVertexBufferElement :: proc() ---                   // Disable vertex buffer element (VBO element)
-	rlEnableVertexAttribute      :: proc(index: u32) ---         // Enable vertex attribute index
-	rlDisableVertexAttribute     :: proc(index: u32) ---         // Disable vertex attribute index
-	when GRAPHICS_API_OPENGL_11 {
+	rlEnableVertexArray          :: proc(vaoId: c.uint) -> bool --- // Enable vertex array (VAO, if supported)
+	rlDisableVertexArray         :: proc() ---                      // Disable vertex array (VAO, if supported)
+	rlEnableVertexBuffer         :: proc(id: c.uint) ---            // Enable vertex buffer (VBO)
+	rlDisableVertexBuffer        :: proc() ---                      // Disable vertex buffer (VBO)
+	rlEnableVertexBufferElement  :: proc(id: c.uint) ---            // Enable vertex buffer element (VBO element)
+	rlDisableVertexBufferElement :: proc() ---                      // Disable vertex buffer element (VBO element)
+	rlEnableVertexAttribute      :: proc(index: c.uint) ---         // Enable vertex attribute index
+	rlDisableVertexAttribute     :: proc(index: c.uint) ---         // Disable vertex attribute index
+	when RL_GRAPHICS_API_OPENGL_11 {
 		rlEnableStatePointer :: proc(vertexAttribType: c.int, buffer: rawptr) ---
 		rlDisableStatePointer :: proc(vertexAttribType: c.int) ---
 	}
 
 	// Textures state
-	rlActiveTextureSlot     :: proc(slot: c.int) ---                         // Select and active a texture slot
-	rlEnableTexture         :: proc(id: u32) ---                             // Enable texture
-	rlDisableTexture        :: proc() ---                                    // Disable texture
-	rlEnableTextureCubemap  :: proc(id: u32) ---                             // Enable texture cubemap
-	rlDisableTextureCubemap :: proc() ---                                    // Disable texture cubemap
-	rlTextureParameters     :: proc(id: u32, param: c.int, value: c.int) --- // Set texture parameters (filter, wrap)
+	rlActiveTextureSlot     :: proc(slot: c.int) ---                            // Select and active a texture slot
+	rlEnableTexture         :: proc(id: c.uint) ---                             // Enable texture
+	rlDisableTexture        :: proc() ---                                       // Disable texture
+	rlEnableTextureCubemap  :: proc(id: c.uint) ---                             // Enable texture cubemap
+	rlDisableTextureCubemap :: proc() ---                                       // Disable texture cubemap
+	rlTextureParameters     :: proc(id: c.uint, param: c.int, value: c.int) --- // Set texture parameters (filter, wrap)
+	rlCubemapParameters     :: proc(id: i32, param: c.int, value: c.int) ---    // Set cubemap parameters (filter, wrap)
 
 	// Shader state
-	rlEnableShader  :: proc(id: u32) ---                                          // Enable shader program
+	rlEnableShader  :: proc(id: c.uint) ---                                       // Enable shader program
 	rlDisableShader :: proc() ---                                                 // Disable shader program
 
 	// Framebuffer state
-	rlEnableFramebuffer  :: proc(id: u32) ---                                     // Enable render texture (fbo)
+	rlEnableFramebuffer  :: proc(id: c.uint) ---                                  // Enable render texture (fbo)
 	rlDisableFramebuffer :: proc() ---                                            // Disable render texture (fbo), return to default framebuffer
 	rlActiveDrawBuffers  :: proc(count: c.int) ---                                // Activate multiple draw color buffers
 
 	// General render state
-	rlEnableColorBlend       :: proc() ---                           // Enable color blending
 	rlDisableColorBlend      :: proc() ---                           // Disable color blending
 	rlEnableDepthTest        :: proc() ---                           // Enable depth test
 	rlDisableDepthTest       :: proc() ---                           // Disable depth test
@@ -258,6 +420,7 @@ foreign lib {
 	rlDisableDepthMask       :: proc() ---                           // Disable depth write
 	rlEnableBackfaceCulling  :: proc() ---                           // Enable backface culling
 	rlDisableBackfaceCulling :: proc() ---                           // Disable backface culling
+	rlSetCullFace            :: proc(mode: CullMode) ---             // Set face culling mode
 	rlEnableScissorTest      :: proc() ---                           // Enable scissor test
 	rlDisableScissorTest     :: proc() ---                           // Disable scissor test
 	rlScissor                :: proc(x, y, width, height: c.int) --- // Scissor test
@@ -271,102 +434,107 @@ foreign lib {
 	rlDisableStereoRender    :: proc() ---                           // Disable stereo rendering
 	rlIsStereoRenderEnabled  :: proc() -> bool ---                   // Check if stereo render is enabled
 
-	rlClearColor         :: proc(r, g, b, a: u8) ---                              // Clear color buffer with color
-	rlClearScreenBuffers :: proc() ---                                            // Clear used screen buffers (color and depth)
-	rlCheckErrors        :: proc() ---                                            // Check and log OpenGL error codes
-	rlSetBlendMode       :: proc(mode: c.int) ---                                 // Set blending mode
-	rlSetBlendFactors    :: proc(glSrcFactor, glDstFactor, glEquation: c.int) --- // Set blending mode factor and equation (using OpenGL factors)
+
+	rlClearColor              :: proc(r, g, b, a: u8) ---                                                        // Clear color buffer with color
+	rlClearScreenBuffers      :: proc() ---                                                                      // Clear used screen buffers (color and depth)
+	rlCheckErrors             :: proc() ---                                                                      // Check and log OpenGL error codes
+	rlSetBlendMode            :: proc(mode: c.int) ---                                                           // Set blending mode
+	rlSetBlendFactors         :: proc(glSrcFactor, glDstFactor, glEquation: c.int) ---                           // Set blending mode factor and equation (using OpenGL factors)
+	rlSetBlendFactorsSeparate :: proc(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha, glEqRGB, glEqAlpha: c.int) --- // Set blending mode factors and equations separately (using OpenGL factors)
 
 	//------------------------------------------------------------------------------------
 	// Functions Declaration - rlgl functionality
 	//------------------------------------------------------------------------------------
 	// rlgl initialization functions
-	rlglInit               :: proc(width, height: c.int) ---                               // Initialize rlgl (buffers, shaders, textures, states)
-	rlglClose              :: proc() ---                                                   // De-inititialize rlgl (buffers, shaders, textures)
-	rlLoadExtensions       :: proc(loader: rawptr) ---                                     // Load OpenGL extensions (loader function pointer required)
-	rlGetVersion           :: proc() -> GlVersion ---                                      // Returns current OpenGL version
-	rlGetFramebufferWidth  :: proc() -> c.int ---                                          // Get default framebuffer width
-	rlGetFramebufferHeight :: proc() -> c.int ---                                          // Get default framebuffer height
+	rlglInit               :: proc(width, height: c.int) --- // Initialize rlgl (buffers, shaders, textures, states)
+	rlglClose              :: proc() ---                     // De-initialize rlgl (buffers, shaders, textures)
+	rlLoadExtensions       :: proc(loader: rawptr) ---       // Load OpenGL extensions (loader function required)
+	rlGetVersion           :: proc() -> GlVersion ---        // Get current OpenGL version
+	rlSetFramebufferWidth  :: proc(width: c.int) ---         // Set current framebuffer width
+	rlGetFramebufferWidth  :: proc() -> c.int ---            // Get default framebuffer width
+	rlSetFramebufferHeight :: proc(height: c.int) ---        // Set current framebuffer height
+	rlGetFramebufferHeight :: proc() -> c.int ---            // Get default framebuffer height
 
-	rlGetTextureIdDefault  :: proc() -> u32 ---                                            // Get default texture id
-	rlGetShaderIdDefault   :: proc() -> u32 ---                                            // Get default shader id
-	rlGetShaderLocsDefault :: proc() -> [^]i32 ---                                         // Get default shader locations
+
+	rlGetTextureIdDefault  :: proc() -> c.uint ---   // Get default texture id
+	rlGetShaderIdDefault   :: proc() -> c.uint ---   // Get default shader id
+	rlGetShaderLocsDefault :: proc() -> [^]c.int --- // Get default shader locations
 
 	// Render batch management
 	// NOTE: rlgl provides a default render batch to behave like OpenGL 1.1 immediate mode
 	// but this render batch API is exposed in case of custom batches are required
-	rlLoadRenderBatch       :: proc(numBuffers, bufferElements: c.int) -> RenderBatch ---  // Load a render batch system
-	rlUnloadRenderBatch     :: proc(batch: RenderBatch) ---                                // Unload render batch system
-	rlDrawRenderBatch       :: proc(batch: ^RenderBatch) ---                               // Draw render batch data (Update->Draw->Reset)
-	rlSetRenderBatchActive  :: proc(batch: ^RenderBatch) ---                               // Set the active render batch for rlgl (NULL for default internal)
-	rlDrawRenderBatchActive :: proc() ---                                                  // Update and draw internal render batch
-	rlCheckRenderBatchLimit :: proc(vCount: c.int) -> bool ---                             // Check internal buffer overflow for a given number of vertex
-	rlSetTexture            :: proc(id: u32) ---                                           // Set current texture for render batch and check buffers limits
+	rlLoadRenderBatch       :: proc(numBuffers, bufferElements: c.int) -> RenderBatch --- // Load a render batch system
+	rlUnloadRenderBatch     :: proc(batch: RenderBatch) ---                               // Unload render batch system
+	rlDrawRenderBatch       :: proc(batch: ^RenderBatch) ---                              // Draw render batch data (Update->Draw->Reset)
+	rlSetRenderBatchActive  :: proc(batch: ^RenderBatch) ---                              // Set the active render batch for rlgl (NULL for default internal)
+	rlDrawRenderBatchActive :: proc() ---                                                 // Update and draw internal render batch
+	rlCheckRenderBatchLimit :: proc(vCount: c.int) -> c.int ---                           // Check internal buffer overflow for a given number of vertex
+
+	rlSetTexture :: proc(id: c.uint) --- // Set current texture for render batch and check buffers limits
 
 	//------------------------------------------------------------------------------------------------------------------------
 
 	// Vertex buffers management
-	rlLoadVertexArray                  :: proc() -> u32 ---                                                                 // Load vertex array (vao) if supported
-	rlLoadVertexBuffer                 :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> u32 ---                    // Load a vertex buffer attribute
-	rlLoadVertexBufferElement          :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> u32 ---                    // Load a new attributes element buffer
-	rlUpdateVertexBuffer               :: proc(bufferId: c.int, data: rawptr, dataSize: c.int, offset: c.int) -> u32 ---    // Update GPU buffer with new data
-	rlUnloadVertexArray                :: proc(vaoId: u32) ---
-	rlUnloadVertexBuffer               :: proc(vboId: u32) ---
-	rlSetVertexAttribute               :: proc(index: u32, compSize: c.int, type: c.int, normalized: bool, stride: c.int, pointer: uintptr) ---
-	rlSetVertexAttributeDivisor        :: proc(index: u32, divisor: c.int) ---
-	rlSetVertexAttributeDefault        :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) ---         // Set vertex attribute default value
+	rlLoadVertexArray                  :: proc() -> c.uint ---                                                      // Load vertex array (vao) if supported
+	rlLoadVertexBuffer                 :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint ---         // Load a vertex buffer attribute
+	rlLoadVertexBufferElement          :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint ---         // Load a new attributes element buffer
+	rlUpdateVertexBuffer               :: proc(bufferId: c.uint, data: rawptr, dataSize: c.int, offset: c.int) ---  // Update GPU buffer with new data
+	rlUpdateVertexBufferElements       :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) ---        // Update vertex buffer elements with new data
+	rlUnloadVertexArray                :: proc(vaoId: c.uint) ---
+	rlUnloadVertexBuffer               :: proc(vboId: c.uint) ---
+	rlSetVertexAttribute               :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, pointer: rawptr) ---
+	rlSetVertexAttributeDivisor        :: proc(index: c.uint, divisor: c.int) ---
+	rlSetVertexAttributeDefault        :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value
 	rlDrawVertexArray                  :: proc(offset: c.int, count: c.int) ---
 	rlDrawVertexArrayElements          :: proc(offset: c.int, count: c.int, buffer: rawptr) ---
 	rlDrawVertexArrayInstanced         :: proc(offset: c.int, count: c.int, instances: c.int) ---
 	rlDrawVertexArrayElementsInstanced :: proc(offset: c.int, count: c.int, buffer: rawptr, instances: c.int) ---
 
 	// Textures management
-	rlLoadTexture          :: proc(data: rawptr, width, height: c.int, format: c.int, mipmapCount: c.int) -> u32 ---  // Load texture in GPU
-	rlLoadTextureDepth     :: proc(width, height: c.int, useRenderBuffer: bool) -> u32 ---                            // Load depth texture/renderbuffer (to be attached to fbo)
-	rlLoadTextureCubemap   :: proc(data: rawptr, size: c.int, format: c.int) -> u32 ---                               // Load texture cubemap
-	rlUpdateTexture        :: proc(id: u32, offsetX, offsetY, width, height: c.int, format: c.int, data: rawptr) ---  // Update GPU texture with new data
-	rlGetGlTextureFormats  :: proc(format: c.int, glInternalFormat: ^u32, glFormat: ^u32, glType: ^u32) ---           // Get OpenGL internal formats
-	rlGetPixelFormatName   :: proc(format: PixelFormat) -> cstring ---                                                // Get name string for pixel format
-	rlUnloadTexture        :: proc(id: u32) ---                                                                       // Unload texture from GPU memory
-	rlGenerateMipmaps      :: proc(texture: ^Texture2D) ---                                                           // Generate mipmap data for selected texture
-	rlReadTexturePixels    :: proc(texture: Texture2D) -> rawptr ---                                                  // Read texture pixel data
-	rlReadScreenPixels     :: proc(width, height: c.int) -> [^]u8 ---                                                 // Read screen pixel data (color buffer)
+	rlLoadTexture         :: proc(data: rawptr, width, height: c.int, format: c.int, mipmapCount: c.int) -> c.uint ---        // Load texture in GPU
+	rlLoadTextureDepth    :: proc(width, height: c.int, useRenderBuffer: bool) -> c.uint ---                                  // Load depth texture/renderbuffer (to be attached to fbo)
+	rlLoadTextureCubemap  :: proc(data: rawptr, size: c.int, format: c.int) -> c.uint ---                                     // Load texture cubemap
+	rlUpdateTexture       :: proc(id: c.uint, offsetX, offsetY: c.int, width, height: c.int, format: c.int, data: rawptr) --- // Update GPU texture with new data
+	rlGetGlTextureFormats :: proc(format: c.int, glInternalFormat, glFormat, glType: ^c.uint) ---                             // Get OpenGL internal formats
+	rlGetPixelFormatName  :: proc(format: c.uint) -> cstring ---                                                              // Get name string for pixel format
+	rlUnloadTexture       :: proc(id: c.uint) ---                                                                             // Unload texture from GPU memory
+	rlGenTextureMipmaps   :: proc(id: c.uint, width, height: c.int, format: c.int, mipmaps: ^c.int) ---                       // Generate mipmap data for selected texture
+	rlReadTexturePixels   :: proc(id: c.uint, width, height: c.int, format: c.int) -> rawptr ---                              // Read texture pixel data
+	rlReadScreenPixels    :: proc(width, height: c.int) -> [^]byte ---                                                        // Read screen pixel data (color buffer)
 
 	// Framebuffer management (fbo)
-	rlLoadFramebuffer     :: proc(width, height: c.int) -> u32 ---                                                // Load an empty framebuffer
-	rlFramebufferAttach   :: proc(fboId: u32, texId: u32, attachType: c.int, texType: c.int, mipLevel: c.int) --- // Attach texture/renderbuffer to a framebuffer
-	rlFramebufferComplete :: proc(id: u32) -> bool ---                                                            // Verify framebuffer is complete
-	rlUnloadFramebuffer   :: proc(id: u32) ---                                                                    // Delete framebuffer from GPU
+	rlLoadFramebuffer     :: proc(width, height: c.int) -> c.uint ---                                           // Load an empty framebuffer
+	rlFramebufferAttach   :: proc(fboId, texId: c.uint, attachType: c.int, texType: c.int, mipLevel: c.int) --- // Attach texture/renderbuffer to a framebuffer
+	rlFramebufferComplete :: proc(id: c.uint) -> bool ---                                                       // Verify framebuffer is complete
+	rlUnloadFramebuffer   :: proc(id: c.uint) ---                                                               // Delete framebuffer from GPU
 
 	// Shaders management
-	rlLoadShaderCode      :: proc(vsCode, fsCode: cstring) -> u32 ---                                   // Load shader from code strings
-	rlCompileShader       :: proc(shaderCode: cstring, type: c.int) -> u32 ---                          // Compile custom shader and return shader id (type: GL_VERTEX_SHADER, GL_FRAGMENT_SHADER)
-	rlLoadShaderProgram   :: proc(vShaderId, fShaderId: u32) -> u32 ---                                 // Load custom shader program
-	rlUnloadShaderProgram :: proc(id: u32) ---                                                          // Unload shader program
-	rlGetLocationUniform  :: proc(shaderId: u32, uniformName: cstring) -> c.int ---                     // Get shader location uniform
-	rlGetLocationAttrib   :: proc(shaderId: u32, attribName: cstring) -> c.int ---                      // Get shader location attribute
+	rlLoadShaderCode      :: proc(vsCode, fsCode: cstring) -> c.uint ---                                // Load shader from code strings
+	rlCompileShader       :: proc(shaderCode: cstring, type: c.int) -> c.uint ---                       // Compile custom shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER)
+	rlLoadShaderProgram   :: proc(vShaderId, fShaderId: c.uint) -> c.uint ---                           // Load custom shader program
+	rlUnloadShaderProgram :: proc(id: c.uint) ---                                                       // Unload shader program
+	rlGetLocationUniform  :: proc(shaderId: c.uint, uniformName: cstring) -> c.int ---                  // Get shader location uniform
+	rlGetLocationAttrib   :: proc(shaderId: c.uint, attribName: cstring) -> c.int ---                   // Get shader location attribute
 	rlSetUniform          :: proc(locIndex: c.int, value: rawptr, uniformType: c.int, count: c.int) --- // Set shader value uniform
 	rlSetUniformMatrix    :: proc(locIndex: c.int, mat: Matrix) ---                                     // Set shader value matrix
-	rlSetUniformSampler   :: proc(locIndex: c.int, textureId: u32) ---                                  // Set shader value sampler
-	rlSetShader           :: proc(shader: Shader) ---                                                   // Set shader currently active
+	rlSetUniformSampler   :: proc(locIndex: c.int, textureId: c.uint) ---                               // Set shader value sampler
+	rlSetShader           :: proc(id: c.uint, locs: [^]c.int) ---                                       // Set shader currently active (id and locations)
 
 	// Compute shader management
-	rlLoadComputeShaderProgram :: proc(shaderId: u32) -> u32 ---        // Load compute shader program
-	rlComputeShaderDispatch    :: proc(groupX, groupY, groupZ: u32) --- // Dispatch compute shader (equivalent to *draw* for graphics pilepine)
+	rlLoadComputeShaderProgram :: proc(shaderId: c.uint) -> c.uint ---     // Load compute shader program
+	rlComputeShaderDispatch    :: proc(groupX, groupY, groupZ: c.uint) --- // Dispatch compute shader (equivalent to *draw* for graphics pipeline)
 
-	
 	// Shader buffer storage object management (ssbo)
-	rlLoadShaderBuffer           :: proc(size: u64, data: rawptr, usageHint: c.int) -> u32 ---  // Load shader storage buffer object (SSBO)
-	rlUnloadShaderBuffer         :: proc(ssboId: u32) ---                                       // Unload shader storage buffer object (SSBO)
-	rlUpdateShaderBufferElements :: proc(id: u32, data: rawptr, dataSize: u64, offset: u64) --- // Update SSBO buffer data
-	rlGetShaderBufferSize        :: proc(id: u32) -> u64 ---                                    // Get SSBO buffer size
-	rlReadShaderBufferElements   :: proc(id: u32, dest: rawptr, count: u64, offset: u64) ---    // Bind SSBO buffer
-	rlBindShaderBuffer           :: proc(id: u32, index: u32) ---                               // Copy SSBO buffer data
+	rlLoadShaderBuffer    :: proc(size: c.uint, data: rawptr, usageHint: c.int) -> c.uint ---              // Load shader storage buffer object (SSBO)
+	rlUnloadShaderBuffer  :: proc(ssboId: c.uint) ---                                                      // Unload shader storage buffer object (SSBO)
+	rlUpdateShaderBuffer  :: proc(id: c.uint, data: rawptr, dataSize: c.uint, offset: c.uint) ---          // Update SSBO buffer data
+	rlBindShaderBuffer    :: proc(id: c.uint, index: c.uint) ---                                           // Bind SSBO buffer
+	rlReadShaderBuffer    :: proc(id: c.uint, dest: rawptr, count: c.uint, offset: c.uint) ---             // Read SSBO buffer data (GPU->CPU)
+	rlCopyShaderBuffer    :: proc(destId, srcId: c.uint, destOffset, srcOffset: c.uint, count: c.uint) --- // Copy SSBO data between buffers
+	rlGetShaderBufferSize :: proc(id: c.uint) -> c.uint ---                                                // Get SSBO buffer size
 
 	// Buffer management
-	rlCopyBuffersElements  :: proc(destId, srcId: u32, destOffset, srcOffset: u64, count: u64) --- // Copy SSBO buffer data
-	rlBindImageTexture     :: proc(id: u32, index: u32, format: u32, readonly: b32) ---            // Bind image texture
-
+	rlBindImageTexture :: proc(id: c.uint, index: c.uint, format: c.int, readonly: bool) ---  // Bind image texture
 
 	// Matrix state management
 	rlGetMatrixModelview        :: proc() -> Matrix ---           // Get internal modelview matrix

BIN=BIN
vendor/raylib/windows/raylib.dll


BIN=BIN
vendor/raylib/windows/raylib.lib


BIN=BIN
vendor/raylib/windows/raylibdll.lib


+ 36 - 0
vendor/wasm/js/dom_all_targets.odin

@@ -0,0 +1,36 @@
+//+build !js
+package wasm_js_interface
+
+import "core:runtime"
+
+
+get_element_value_string :: proc "contextless" (id: string, buf: []byte) -> string {
+	context = runtime.default_context()
+	panic("vendor:wasm/js not supported on non JS targets")
+}
+
+
+get_element_min_max :: proc "contextless" (id: string) -> (min, max: f64) {
+	context = runtime.default_context()
+	panic("vendor:wasm/js not supported on non JS targets")
+}
+
+
+Rect :: struct {
+	x, y, width, height: f64,
+}
+
+get_bounding_client_rect :: proc "contextless" (id: string) -> (rect: Rect) {
+	context = runtime.default_context()
+	panic("vendor:wasm/js not supported on non JS targets")
+}
+
+window_get_rect :: proc "contextless" () -> (rect: Rect) {
+	context = runtime.default_context()
+	panic("vendor:wasm/js not supported on non JS targets")
+}
+
+window_get_scroll :: proc "contextless" () -> (x, y: f64) {
+	context = runtime.default_context()
+	panic("vendor:wasm/js not supported on non JS targets")
+}

+ 288 - 0
vendor/wasm/js/events_all_targets.odin

@@ -0,0 +1,288 @@
+//+build !js
+package wasm_js_interface
+
+
+Event_Kind :: enum u32 {
+	Invalid,
+
+	Load,
+	Unload,
+	Error,
+	Resize,
+	Visibility_Change,
+	Fullscreen_Change,
+	Fullscreen_Error,
+
+	Click,
+	Double_Click,
+	Mouse_Move,
+	Mouse_Over,
+	Mouse_Out,
+	Mouse_Up,
+	Mouse_Down,
+
+	Key_Up,
+	Key_Down,
+	Key_Press,
+
+	Scroll,
+	Wheel,
+
+	Focus,
+	Submit,
+	Blur,
+	Change,
+	Select,
+
+	Animation_Start,
+	Animation_End,
+	Animation_Iteration,
+	Animation_Cancel,
+
+	Copy,
+	Cut,
+	Paste,
+
+	// Drag,
+	// Drag_Start,
+	// Drag_End,
+	// Drag_Enter,
+	// Drag_Leave,
+	// Drag_Over,
+	// Drop,
+
+	Pointer_Cancel,
+	Pointer_Down,
+	Pointer_Enter,
+	Pointer_Leave,
+	Pointer_Move,
+	Pointer_Over,
+	Pointer_Up,
+	Got_Pointer_Capture,
+	Lost_Pointer_Capture,
+	Pointer_Lock_Change,
+	Pointer_Lock_Error,
+
+	Selection_Change,
+	Selection_Start,
+
+	Touch_Cancel,
+	Touch_End,
+	Touch_Move,
+	Touch_Start,
+
+	Transition_Start,
+	Transition_End,
+	Transition_Run,
+	Transition_Cancel,
+
+	Context_Menu,
+
+	Custom,
+
+}
+event_kind_string := [Event_Kind]string{
+	.Invalid = "",
+
+	.Load         = "load",
+	.Unload       = "unload",
+	.Error        = "error",
+	.Resize       = "resize",
+	.Visibility_Change = "visibilitychange",
+	.Fullscreen_Change = "fullscreenchange",
+	.Fullscreen_Error  = "fullscreenerror",
+
+	.Click        = "click",
+	.Double_Click = "dblclick",
+	.Mouse_Move   = "mousemove",
+	.Mouse_Over   = "mouseover",
+	.Mouse_Out    = "mouseout",
+	.Mouse_Up     = "mouseup",
+	.Mouse_Down   = "mousedown",
+
+	.Key_Up       = "keyup",
+	.Key_Down     = "keydown",
+	.Key_Press    = "keypress",
+
+	.Scroll = "scroll",
+	.Wheel = "wheel",
+
+	.Focus        = "focus",
+	.Submit       = "submit",
+	.Blur         = "blur",
+	.Change       = "change",
+	.Select       = "select",
+
+	.Animation_Start     = "animationstart",
+	.Animation_End       = "animationend",
+	.Animation_Iteration = "animationiteration",
+	.Animation_Cancel    = "animationcancel",
+
+	.Copy   = "copy",
+	.Cut    = "cut",
+	.Paste  = "paste",
+
+	// .Drag,       = "drag",
+	// .Drag_Start, = "dragstart",
+	// .Drag_End,   = "dragend",
+	// .Drag_Enter, = "dragenter",
+	// .Drag_Leave, = "dragleave",
+	// .Drag_Over,  = "dragover",
+	// .Drop,       = "drop",
+
+	.Pointer_Cancel       = "pointercancel",
+	.Pointer_Down         = "pointerdown",
+	.Pointer_Enter        = "pointerenter",
+	.Pointer_Leave        = "pointerleave",
+	.Pointer_Move         = "pointermove",
+	.Pointer_Over         = "pointerover",
+	.Pointer_Up           = "pointerup",
+	.Got_Pointer_Capture  = "gotpointercapture",
+	.Lost_Pointer_Capture = "lostpointercapture",
+	.Pointer_Lock_Change  = "pointerlockchange",
+	.Pointer_Lock_Error   = "pointerlockerror",
+
+	.Selection_Change = "selectionchange",
+	.Selection_Start  = "selectionstart",
+
+	.Transition_Start  = "transitionstart",
+	.Transition_End    = "transitionend",
+	.Transition_Run    = "transitionrun",
+	.Transition_Cancel = "transitioncancel",
+
+	.Touch_Cancel = "touchcancel",
+	.Touch_End    = "touchend",
+	.Touch_Move   = "touchmove",
+	.Touch_Start  = "touchstart",
+
+	.Context_Menu = "contextmenu",
+
+	.Custom = "?custom?",
+}
+
+Delta_Mode :: enum u32 {
+	Pixel = 0,
+	Line  = 1,
+	Page  = 2,
+}
+
+Key_Location :: enum u8 {
+	Standard = 0,
+	Left     = 1,
+	Right    = 2,
+	Numpad   = 3,
+}
+
+KEYBOARD_MAX_KEY_SIZE :: 16
+KEYBOARD_MAX_CODE_SIZE :: 16
+
+Event_Target_Kind :: enum u32 {
+	Element  = 0,
+	Document = 1,
+	Window   = 2,
+}
+
+Event_Phase :: enum u8 {
+	None            = 0,
+	Capturing_Phase = 1,
+	At_Target       = 2,
+	Bubbling_Phase  = 3,
+}
+
+Event_Option :: enum u8 {
+	Bubbles    = 0,
+	Cancelable = 1,
+	Composed   = 2,
+}
+Event_Options :: distinct bit_set[Event_Option; u8]
+
+Event :: struct {
+	kind:                 Event_Kind,
+	target_kind:          Event_Target_Kind,
+	current_target_kind:  Event_Target_Kind,
+	id:           string,
+	timestamp:    f64,
+
+	phase:        Event_Phase,
+	options:      Event_Options,
+	is_composing: bool,
+	is_trusted:   bool,
+
+	using data: struct #raw_union #align 8 {
+		scroll: struct {
+			delta: [2]f64,
+		},
+		visibility_change: struct {
+			is_visible: bool,
+		},
+		wheel: struct {
+			delta: [3]f64,
+			delta_mode: Delta_Mode,
+		},
+
+		key: struct {
+			key:  string,
+			code: string,
+			location: Key_Location,
+
+			ctrl:   bool,
+			shift:  bool,
+			alt:    bool,
+			meta:   bool,
+
+			repeat: bool,
+
+			_key_buf:  [KEYBOARD_MAX_KEY_SIZE]byte,
+			_code_buf: [KEYBOARD_MAX_KEY_SIZE]byte,
+		},
+
+		mouse: struct {
+			screen:    [2]i64,
+			client:    [2]i64,
+			offset:    [2]i64,
+			page:      [2]i64,
+			movement:  [2]i64,
+
+			ctrl:   bool,
+			shift:  bool,
+			alt:    bool,
+			meta:   bool,
+
+			button:  i16,
+			buttons: bit_set[0..<16; u16],
+		},
+	},
+
+
+	user_data: rawptr,
+	callback:  proc(e: Event),
+}
+
+
+add_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
+	panic("vendor:wasm/js not supported on non JS targets")
+}
+
+remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool {
+	panic("vendor:wasm/js not supported on non JS targets")
+}
+
+add_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
+	panic("vendor:wasm/js not supported on non JS targets")
+}
+
+remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool {
+	panic("vendor:wasm/js not supported on non JS targets")
+}
+
+remove_event_listener_from_event :: proc(e: Event) -> bool {
+	panic("vendor:wasm/js not supported on non JS targets")
+}
+
+add_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
+	panic("vendor:wasm/js not supported on non JS targets")
+}
+remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event)) -> bool {
+	panic("vendor:wasm/js not supported on non JS targets")
+}
+

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio