Compare commits

...

332 Commits

Author SHA1 Message Date
gingerBill 2cca005056 Merge branch 'master' of https://github.com/odin-lang/Odin 2023-10-02 20:59:49 +01:00
gingerBill d27109640e Partial pseudo-revert 2023-10-02 20:59:43 +01:00
Jeroen van Rijn 1287e8c734 Merge pull request #2839 from Tetralux/aprintf-ally
[fmt] Add allocator parameter to `fmt.aprintf`
2023-10-02 11:23:26 +02:00
Tetralux 7a6ac3ea92 [fmt] Add allocator parameter to fmt.aprintf
This allows you to do `fmt.aprintf("Hello, %v!", name, allocator = ally)`.
2023-10-02 02:46:26 +00:00
Jeroen van Rijn 81fe93127d Make core:net test os.exit(1) on failure. 2023-09-30 22:47:49 +02:00
Jeroen van Rijn aa5716d3f9 Allow any order of query strings in net.join_url tests. 2023-09-30 22:36:50 +02:00
gingerBill f9c6f6856b Fix #2261 2023-09-30 20:32:24 +01:00
gingerBill b9cc2606f2 Remove default value 2023-09-30 20:26:52 +01:00
gingerBill 5023313c03 Minor cleanups to the core library 2023-09-30 20:26:04 +01:00
gingerBill 3e0fd63682 Fix or_break code generation issue 2023-09-30 18:58:28 +01:00
gingerBill 1f643b5816 Remove -vet-extra 2023-09-30 18:29:18 +01:00
gingerBill 14adcb9db8 Use or_break and or_continue where appropriate in the core library 2023-09-30 15:34:39 +01:00
gingerBill 41a22bd83d or_break and or_continue to core:odin packages 2023-09-30 15:09:59 +01:00
gingerBill 648b83d6ea Add or_break and or_continue constructs 2023-09-30 15:04:17 +01:00
Jeroen van Rijn 4e97b83312 Merge pull request #2832 from Kelimion/big_int_literal_hex
Change large math/big test literals to hex.
2023-09-30 11:30:31 +02:00
Jeroen van Rijn 07cd6cd670 Change large math/big test literals to hex.
In September 2022, the Python team addressed a possible DoS issue converting big integers to and from base 10 strings: https://github.com/python/cpython/issues/95778

Converting to/from base 10 is a quadratic operation, so they limited it to 4300 digits: https://discuss.python.org/t/int-str-conversions-broken-in-latest-python-bugfix-releases/18889/83

Github CI still uses an old Python version which parsed our test suite just fine. This patch converts them to hex literals to ensure our test doesn't break when Github does update to a non-vulnerable Python version released after September 2022.
2023-09-30 11:16:36 +02:00
gingerBill 3fae38a2f8 Correct get_file_line_as_string to fix #2829 2023-09-29 12:17:15 +01:00
gingerBill 23054138c2 Remove debug message 2023-09-29 12:12:14 +01:00
gingerBill 63f755554b Rename simd bitwise operations from intrinsics.simd_and to intrinsics.simd_bit_and etc 2023-09-28 16:42:08 +01:00
gingerBill 2ac463f003 Rename bitwise operations to bit_or etc 2023-09-28 16:40:01 +01:00
gingerBill 77227c2ff5 Merge pull request #2805 from odin-lang/llvm-17
Support LLVM 17.0.1
2023-09-28 16:01:26 +01:00
gingerBill 2afccd7fbd Revert llvm@17 to llvm@13 on macOS 2023-09-27 14:09:08 +01:00
gingerBill 991181104b Update CI macOS to use llvm@17 2023-09-27 14:06:51 +01:00
gingerBill 70aff9fbb2 Update src/build_settings.cpp
Co-authored-by: Laytan Laats <laytanlaats@hotmail.com>
2023-09-27 14:01:45 +01:00
gingerBill 2370884722 Merge pull request #2827 from Lperlind/fixup-bad-rand-merge
Fixed up missing output for rand
2023-09-27 11:45:00 +01:00
gingerBill c529b1b73a Generate the global type info member values even if the count is 0 2023-09-27 11:44:29 +01:00
gingerBill acc29fbceb Merge branch 'master' into llvm-17 2023-09-27 11:38:11 +01:00
Lucas Perlind 7cc5177078 Fixed up missing output for rand examples 2023-09-27 16:34:19 +10:00
gingerBill fc93ea7aa3 Fix #2820 2023-09-26 15:15:31 +01:00
gingerBill 4c22982732 Rename files to not start with _ 2023-09-26 13:15:21 +01:00
gingerBill fb935541c9 Fix #2809 - disallow files to start with _ 2023-09-26 13:10:18 +01:00
gingerBill 47023b2e6c Fix #2812 2023-09-26 13:04:47 +01:00
gingerBill f4a390201c Fix #2819 2023-09-26 13:02:40 +01:00
gingerBill d358ebd7e6 Potentially fix race condition #2463 #2814 2023-09-26 12:57:26 +01:00
gingerBill 9711dd1381 Fix #2816 2023-09-26 12:41:33 +01:00
gingerBill 4c328d83ba Fix #2817 2023-09-26 12:40:35 +01:00
gingerBill 9911b132d2 Fix #2818 (enforce #partial label: switch) 2023-09-26 12:35:24 +01:00
gingerBill 534e5978d8 Merge branch 'master' of https://github.com/odin-lang/Odin 2023-09-26 12:21:49 +01:00
gingerBill c08bf1204f Add cstring specific comparison procedures to fix comparisons like cstring("") != cstring(nil) 2023-09-26 12:21:43 +01:00
gingerBill 94d68c1f22 Fix ptr != ptr type cast problem in LLVM 17 2023-09-26 11:58:12 +01:00
gingerBill 0ca379ed03 Fix typo 2023-09-25 17:06:00 +01:00
gingerBill 0ed2d8b127 Merge pull request #2813 from mtarik34b/fix-mismatches-with-max-error-count-flag
Fix various mismatches with the specified -max-error-count flag
2023-09-25 16:44:05 +01:00
gingerBill 3bee571e1f Use giant struct only in 17 2023-09-25 16:43:28 +01:00
Tarık B 0b78544796 Fix various mismatches with the specified -max-error-count flag 2023-09-22 17:12:16 +02:00
gingerBill 361f71deed Use llvm_const_array wrapper 2023-09-22 15:35:24 +01:00
gingerBill 61f39ae0a0 Use a giant packed struct working for type info table 2023-09-22 15:32:32 +01:00
gingerBill 082324d7b9 Begin work on making the type info table be constantly initialized 2023-09-22 14:39:51 +01:00
gingerBill 5e99289d7a Minor clean up 2023-09-22 12:11:39 +01:00
gingerBill e14a4e79ae Merge pull request #2808 from karl-zylinski/write-128-bit-int-buf-size
Fix for crash when using io.write_u128/io.write_i128 due to buffer being too small
2023-09-22 11:38:07 +01:00
Karl Zylinski 39c85cafa2 Fix for crash when using io.write_u128/io.write_i128 due to buffer being too small 2023-09-22 08:26:41 +02:00
gingerBill fa6be4ec58 Revert build.bat 2023-09-21 17:27:17 +01:00
gingerBill 25b8461bfb Update LLVM-C.dll 2023-09-21 17:09:00 +01:00
gingerBill ac43dd0777 Remove debug text 2023-09-21 17:08:45 +01:00
gingerBill 963559676e Fix build times for -o:<string> in LLVM-17 2023-09-21 16:48:00 +01:00
gingerBill 20ce8c4c51 Allow for zero passes 2023-09-21 12:45:11 +01:00
gingerBill 098c09835b Add ODIN_SANITIZER_FLAGS global constant 2023-09-21 11:34:40 +01:00
gingerBill 4aa9d34b3d Add attributes for sanitize_memory and sanitize_thread 2023-09-21 11:20:13 +01:00
gingerBill 38d2a0ddb9 Add sanitize_address attribute to all normal packages 2023-09-21 11:13:26 +01:00
gingerBill 735bb147e2 Add asan lib for Windows 2023-09-21 11:03:25 +01:00
gingerBill 7a511308ef Re-configure the new pass system 2023-09-21 10:54:02 +01:00
gingerBill bc401fa392 Fix wrong import due to grep-replace 2023-09-21 10:41:42 +01:00
gingerBill 96fbafe359 Update ABI breaking changes for f16 types (due to LLVM 15+) 2023-09-21 10:38:44 +01:00
gingerBill e82b0ea4cd Add -o:aggressive for LLVM 17 2023-09-21 09:48:53 +01:00
gingerBill 2160484b62 Support -sanitize:<string> for address, memory, thread for LLVM 17 2023-09-21 09:40:33 +01:00
gingerBill f0ab58dfbb Begin work with adding the new pass system 2023-09-20 10:39:48 +01:00
gingerBill c23b5825bb Merge pull request #2804 from bytesiz3d/fix-unquote-string
Fix bug with index increment in `core:encoding/json.unquote_string`
2023-09-20 10:16:51 +01:00
Abdelrahman Farid f1872f495a Fix bug with index increment in unquote_string 2023-09-19 22:19:05 +03:00
Abdelrahman Farid 9ed36445b9 Add test for utf8 multibyte strings 2023-09-19 22:18:23 +03:00
gingerBill 5043c10d70 Check for LLVM versions 2023-09-19 16:21:34 +01:00
gingerBill e748d2f2af Update to LLVM-17 2023-09-19 16:15:26 +01:00
gingerBill ecde06e3a3 Merge branch 'master' of https://github.com/odin-lang/Odin 2023-09-19 15:12:50 +01:00
gingerBill 3505c1d790 Fix constant literals using the wrong type 2023-09-19 15:12:44 +01:00
gingerBill 150a72f75e Merge pull request #2769 from RLGingerBiscuit/json-marshal-stuff
json.marshal: Don't output spaces if pretty=false
2023-09-18 10:47:02 +01:00
gingerBill f96579824b Merge pull request #2791 from ftphikari/master
[core:sys/windows] Added couple of procedures
2023-09-15 11:22:30 +01:00
gingerBill 2aa3cabd85 Merge pull request #2782 from AbdelHameed-Hamed/dxc-unix-bindings
Add unix bindings for DXC.
2023-09-14 20:08:49 +01:00
AbdelHameed-Hamed 06d26df046 Move API into one file and use "system" calling convention, and move data definitions into platform specific files. 2023-09-14 19:24:44 +02:00
gingerBill 6e49b1cad7 Merge pull request #2784 from laytan/fmt-memory-sizes
Add formatting of bytes into the best unit of measurement
2023-09-14 11:00:48 +01:00
gingerBill d928f425ec Merge pull request #2789 from fabiansperber/fix-odin-parser
Fix issues with core:odin parser
2023-09-14 11:00:11 +01:00
gingerBill ed3a9aed12 Merge pull request #2790 from Lperlind/master
Further improve on NSBlock
2023-09-14 10:59:48 +01:00
hikari aaccaa19bf [vendor:directx/d3d11] Added CalcSubresource helper macro 2023-09-13 23:47:18 +03:00
gingerBill 35857d3103 Fix wrong type 2023-09-12 23:01:49 +01:00
Laytan Laats d47b0eeee7 update doc 2023-09-12 16:51:21 +02:00
Laytan Laats 287beaff35 use KiB etc. instead of KB 2023-09-12 16:49:42 +02:00
gingerBill 8e9d1c7ebf Make procedures contextless where possible 2023-09-12 11:52:05 +01:00
gingerBill 53380632a1 Swap order of prev and next 2023-09-12 11:44:54 +01:00
gingerBill 984a95b8c7 Update Tilde 2023-09-11 23:36:39 +01:00
gingerBill 72118fcc6a Fix #2794 (Fix typo for IsWindowState) 2023-09-11 16:14:28 +01:00
hikari 1b06f809de [core:sys/windows] Added SuspendThread 2023-09-08 00:02:27 +03:00
hikari 19fe508fb2 [core:sys/windows] Added couple of procedures 2023-09-07 23:58:19 +03:00
gingerBill aaaff9b66c Fix bug: Disallow non-specialized polymorphic in typeid assignment 2023-09-06 17:33:38 +01:00
gingerBill c660b43105 Merge branch 'master' of https://github.com/odin-lang/Odin 2023-09-06 16:55:50 +01:00
Lucas Perlind 92b24fd02d Further improve on NSBlock
* Correct setting the isa of the NSBlock
* Make global blocks managed by the odin runtime
* Make local blocks copy to a malloc block that is managed by the objc runtime
* Add method to create blocks that take a paramater
2023-09-06 15:03:17 +10:00
Fabian Sperber 886d0de040 Remove auto_cast from field_flags
- auto_cast is parsed as its own expression
2023-09-05 23:14:55 +02:00
Fabian Sperber 16d797cb01 Add #const field flag 2023-09-05 22:57:40 +02:00
Fabian Sperber bbf9678756 Fix parsing #force_inline call expression with or_return 2023-09-05 22:35:30 +02:00
gingerBill d60c619c44 Merge pull request #2785 from DanielGavin/odin-core-reverse
Add #reverse to `odin/parser`.
2023-09-05 18:57:08 +01:00
gingerBill e7abc05931 Merge pull request #2787 from laytan/fix-commonmark
fix commonmark import
2023-09-05 18:56:58 +01:00
Laytan Laats 12dd912ce9 fix commonmark import 2023-09-04 20:48:03 +02:00
DanielGavin 64a63b3879 Add #reverse to odin/parser. 2023-09-03 16:15:03 +02:00
Laytan Laats 93caf5b311 use memory formatting in tracking allocator doc 2023-09-01 22:05:04 +02:00
Laytan Laats aab2fa1af9 fix test case 2023-09-01 19:53:24 +02:00
Laytan Laats 4cf176de0b actually run the test 2023-09-01 19:51:53 +02:00
Laytan Laats 735cfcd290 Add formatting of bytes into the best unit of measurement 2023-09-01 19:17:07 +02:00
gingerBill 4aa4317c28 Merge pull request #2780 from laytan/fix-ternary-with-union-of-enum
fix #2779 ternary with a union of enum
2023-08-31 15:19:27 +01:00
AbdelHameed-Hamed d0ef6d2a9b Add unix bindings for DXC. 2023-08-31 11:50:29 +02:00
Jeroen van Rijn 434c84043d Merge pull request #2781 from Lperlind/master
Add more darwin bindings
2023-08-31 10:08:02 +02:00
Lucas Perlind 747116aeb0 Add more darwin bindings 2023-08-31 17:37:32 +10:00
Laytan Laats a182dc78f4 fix #2779 ternary with a union of enum 2023-08-31 02:31:11 +02:00
gingerBill 1a316c8a18 Merge pull request #2776 from Lperlind/master
Add more NS bindings and correctly link NS block
2023-08-30 01:48:06 +01:00
Lucas Perlind 46e7fa52b3 Add more NS bindings and correctly link NS block 2023-08-30 10:18:17 +10:00
Jeroen van Rijn 52ea3748b4 Merge pull request #2775 from laytan/fix-overlapped-entry-type
Fix the OVERLAPPED_ENTRY type definition
2023-08-29 10:56:01 +02:00
Laytan Laats 0a2678973b Fix the OVERLAPPED_ENTRY type definition 2023-08-29 10:44:21 +02:00
gingerBill 04129c5bd5 Update Tilde 2023-08-27 23:45:39 +01:00
Jeroen van Rijn 6f363dcae3 Merge pull request #2774 from Pix-xiP/master
Updating to be the correct function name in documentation.
2023-08-27 16:47:45 +02:00
Pix 8c4bd76280 Updating to be the correct function name in documentation. 2023-08-27 21:03:49 +08:00
Jeroen van Rijn 92f385e7b5 Merge pull request #2773 from Tetralux/minor-net-cleanup
[net] Assorted cleanup
2023-08-27 13:37:56 +02:00
Jeroen van Rijn ac4e259e29 Merge pull request #2771 from laytan/fix-queue-reserve
fix queue reserve always doubling in size when there is enough space
2023-08-26 19:23:17 +02:00
Laytan Laats 076b20a9a5 fix queue reserve always doubling in size when there is enough space 2023-08-26 19:09:04 +02:00
gingerBill 0b0230adce Update Tilde 2023-08-26 13:14:49 +01:00
Tetralux e51915a529 [net] Assorted cleanup
- Remove some old comments

- Fix some doc comments

- Improve some doc comments

- Unify name of the errors related to UDP packet sizes
   (i.e: recv buffer too small, and message too big to send)
2023-08-26 11:47:03 +00:00
RLGingerBiscuit 187a475b84 json.marshal: Don't output spaces if pretty=false 2023-08-25 17:33:41 +01:00
gingerBill 39c0a619eb Merge pull request #2767 from Lperlind/master
Correct run loop linking
2023-08-25 11:20:07 +01:00
Lucas Perlind 29f7eaad78 Correct run loop linking 2023-08-25 13:46:03 +10:00
gingerBill 8f086a6957 Add NSSet 2023-08-24 23:31:21 +01:00
gingerBill 8f512001b6 Shut up the type checker 2023-08-24 16:49:56 +01:00
gingerBill 1d25522a3b Update vendor:darwin/Foundation to implement Event, Color, Screen, and other fixes 2023-08-24 16:43:13 +01:00
Jeroen van Rijn fdb538538a Merge pull request #2765 from Despacito696969/master
Commit `a040be9` but for `core:sort`
2023-08-23 16:24:59 +02:00
Despacito696969 2feb1bf847 Commit a040be9 but for core:sort 2023-08-23 15:46:32 +02:00
Jeroen van Rijn 74bbb1167f Fix #2763
Fixes #2763
2023-08-22 20:18:54 +02:00
gingerBill 515163864f Add optional flush := true to many of the core:fmt procedures 2023-08-22 17:24:12 +01:00
gingerBill 1cdb975c91 Add attribute @(require) import "foo" to replace/supplement _ :: foo 2023-08-22 12:05:25 +01:00
gingerBill cd42d26eb3 Fix variadic parapoly bug 2023-08-21 12:19:38 +01:00
gingerBill 8bc96652cd Merge branch 'master' of https://github.com/odin-lang/Odin 2023-08-21 11:15:22 +01:00
gingerBill 1631a2bac1 Update Tilde 2023-08-21 11:15:16 +01:00
Jeroen van Rijn 501635ca26 Merge pull request #2760 from Lperlind/cocoa-import
Always include Cocoa for NSFoundation
2023-08-21 07:20:35 +02:00
Lucas Perlind edcd335b90 Always include Cocoa for NSFoundation 2023-08-21 11:36:39 +10:00
gingerBill 0cb9908f27 Update Tilde 2023-08-19 12:26:59 +01:00
gingerBill 61858f5899 Merge pull request #2755 from Lperlind/improve-float-rand
Better guarantee boundaries of floating point rand
2023-08-19 11:07:28 +01:00
Jeroen van Rijn c5911679d1 Merge pull request #2757 from Kelimion/fix_2756
`_buffer_grow`: Preserve allocator if already set via init_buffer_allocator
2023-08-18 22:27:03 +02:00
Jeroen van Rijn 99d6a077fe _buffer_grow: Preserve allocator if already set via init_buffer_allocator
Fixes #2756
2023-08-18 22:16:59 +02:00
Lucas Perlind 8b680254ee Better guarantee boundaries of floating point rand 2023-08-18 11:19:01 +10:00
gingerBill b873651da7 Merge pull request #2748 from Caedo/js-events-fix
Fix issues with js events not being initialized properly
2023-08-17 16:40:54 +01:00
Caedo b185d9e701 Remove pointer magic when creating strings 2023-08-16 20:33:17 +02:00
Jeroen van Rijn b635622cac Merge pull request #2751 from Lperlind/rand-doc-float
Update rand documentation about floats
2023-08-16 13:48:01 +02:00
Lucas Perlind b31d8b1ad0 Update rand documentation about floats 2023-08-16 21:13:56 +10:00
gingerBill 2153cb7e0a Merge pull request #2721 from Kartoffelsaft/dynamic-pool-alloc
Return .Invalid_Argument in pool allocator to avoid potential segfaults
2023-08-16 12:02:21 +01:00
gingerBill 15033eab28 Fix comparison of two nil unions against each other 2023-08-16 11:52:40 +01:00
gingerBill 8b4c530062 Disable HAS_VALGRIND logic for BlockingMutex (fixes #2703) 2023-08-16 11:02:09 +01:00
gingerBill 9ff9587b7b Remove unused code in gb.h; Minimize use of heap_allocator() in parser 2023-08-16 00:41:49 +01:00
gingerBill d8acbda548 Update to llvm@13 for Mac
Brew has broke llvm@11
2023-08-15 21:25:14 +01:00
Benjamin Findley 7e4a65114a fix whitespace 2023-08-15 08:49:27 -07:00
gingerBill d9a2d29d00 Update demo.odin to #align(N) style 2023-08-15 15:59:38 +01:00
gingerBill 27931249ce Scale by 3/2 rather than 5/4 2023-08-15 15:45:12 +01:00
gingerBill 52318d0e0e Improve heuristic for committing memory with virtual.alloc_from_memory_block 2023-08-15 15:42:28 +01:00
gingerBill 8d673789be Align committed to a page size 2023-08-15 15:20:23 +01:00
gingerBill 646c4c7458 alloc_from_memory_block to commit amounts equal to multiples of the DEFAULT_PAGE_SIZE 2023-08-15 15:12:12 +01:00
gingerBill 2cc22d118d Require parentheses for #align(N) 2023-08-15 14:55:02 +01:00
Caedo 1182f41f99 Fix issues with js events not being initialized properly 2023-08-15 14:56:04 +02:00
gingerBill 098d1d2b5e Merge pull request #2716 from laytan/add-libraygui-macos-arm64
add libraygui.a for macos-arm64
2023-08-15 11:19:20 +01:00
gingerBill 31c85f0ec5 Merge pull request #2719 from laytan/add-waitgroup-to-wait-proc-group
add wait group to wait proc group
2023-08-15 11:19:09 +01:00
gingerBill 091d1f8c75 Merge pull request #2747 from Pix-xiP/loc-into-strings
#caller_location into the strings package
2023-08-15 11:16:12 +01:00
gingerBill 6c50e6ef34 Use or_return on resize/reserve 2023-08-15 11:13:43 +01:00
gingerBill 67f48aca96 Fix _random_u64 2023-08-15 11:06:12 +01:00
gingerBill fc64e787a3 Change to LLVM@13 for ci.yml on Mac 2023-08-15 10:55:37 +01:00
gingerBill d13bed9a0a Change algorithm to work on 64-bit integers rather than 32-bit integers internally 2023-08-15 10:53:59 +01:00
gingerBill 904c48b11a Fix range comment from (0, n] to [0, n) 2023-08-15 10:36:00 +01:00
Pix 2ab5eb7213 Strings makes added caller function 2023-08-15 12:31:06 +08:00
Pix 5ce541e9ef Intern add location to init. 2023-08-15 12:30:50 +08:00
Pix 0cf9c22033 Builder makes added caller location 2023-08-15 12:30:40 +08:00
Benjamin Findley 38e06f13d6 prevent potential segfaults when using large allocations from dynamic pool 2023-08-11 11:49:31 -07:00
Laytan Laats ccc94f6832 add wait group to wait proc group 2023-08-11 20:21:42 +02:00
gingerBill 589820639c Correct lb_run_function_pass_manager behaviour 2023-08-10 14:35:09 +01:00
Laytan Laats 68b9260c9b add libraygui.a for macos-arm64 2023-08-09 00:36:21 +02:00
gingerBill 49b2447113 Merge pull request #2710 from guifes/raygui
raygui bindings
2023-08-08 16:13:51 +01:00
gingerBill 89c50bbd82 Adhere to -vet-style 2023-08-08 16:01:22 +01:00
gingerBill 2b3f3e11d3 Make trailing commas followed by a closing token on the same an error with -vet-style 2023-08-08 16:01:08 +01:00
gingerBill 4100cfec86 Fix typo 2023-08-08 15:31:17 +01:00
gingerBill cad3a50e4e Add ODIN_PLATFORM_SUBTARGET 2023-08-08 15:28:21 +01:00
gingerBill 4d9ee55468 Fix add_constant_switch_case 2023-08-08 15:23:01 +01:00
gingerBill b72f009d87 Disallow aliasing of any and typeid 2023-08-08 15:10:57 +01:00
gingerBill 2181e0fc27 Make for init; ; {} an error without an explicit cond or post 2023-08-08 15:07:00 +01:00
gingerBill cd74cdfdaf Remove switch in in favour of switch _ in 2023-08-08 14:57:25 +01:00
gingerBill 49ab935ae9 Disallow for in in favour of for _ in 2023-08-08 14:56:12 +01:00
Guilherme Fernandes 6879c9d8df Tabs for identation and spaces for aligment 2023-08-08 13:22:26 +01:00
gingerBill 939bf4bb5d Add experimental -subtarget:ios 2023-08-08 11:35:51 +01:00
gingerBill 7861dfd667 Fix tilde extension when trying to build as assembly (unsupported currently) 2023-08-08 11:16:14 +01:00
gingerBill c5fc28de7d Merge pull request #2714 from wjlroe/fix-cycle-count-intrinsic-on-darwin
Fix read_cycle_counter intrinsic on arm64
2023-08-07 23:18:55 +01:00
Guilherme Fernandes 535d290293 Removing contextual comment 2023-08-07 22:35:30 +01:00
Guilherme Fernandes a0dd975686 Adjusting identation 2023-08-07 22:35:30 +01:00
Guilherme Fernandes f48531efaf Removing unecessary line
Not sure what the context is for it, grabbed it from raylib's bindings. Tested without it, everything works fine.
2023-08-07 22:35:30 +01:00
Guilherme Fernandes c6a4116082 Fixing return value missing 2023-08-07 22:35:30 +01:00
Guilherme Fernandes aecd6b85e6 Improving style
minValue: c.int, maxValue: c.int
minValue, maxValue: c.int
2023-08-07 22:35:30 +01:00
Guilherme Fernandes 55439ef293 Fixing minor typo: minValu -> minValue 2023-08-07 22:35:17 +01:00
Guilherme Fernandes d4cf103676 Adding whitespaces to detach procedure declaration from category comments 2023-08-07 22:26:19 +01:00
Guilherme Fernandes 489fb087a4 Fixing identation to use tabs 2023-08-07 22:26:18 +01:00
Guilherme Fernandes ff904ae174 Fixing Error: Redeclaration of 'VERSION' in this scope 2023-08-07 22:26:18 +01:00
Guilherme Fernandes d8db5ec7b6 Moving raygui to vendor/raylib
Removing raylib import and raylib package references
2023-08-07 22:25:04 +01:00
William Roe 5d8b78cb88 Fix read_cycle_counter intrinsic on arm64
Running this code with the hard-coded x9 register results in not 
returning the cycle count, but some other value.

This code (using $0 as the register), works on arm64 Linux and Darwin.
2023-08-07 21:18:56 +01:00
gingerBill 9736402dfd Fix docs typo 2023-08-07 15:34:28 +01:00
gingerBill 0600054ad4 Remove temporary assert 2023-08-07 15:21:18 +01:00
gingerBill b782fca75b Fix using bug 2023-08-07 15:18:45 +01:00
gingerBill 0230b88078 Tilde: #soa pointers 2023-08-07 15:11:15 +01:00
gingerBill 55c9fb7c5c Tilde: Begin work on #soa 2023-08-07 15:04:03 +01:00
gingerBill 8201a9ce6e Tilde: for in for enum types 2023-08-07 14:53:31 +01:00
gingerBill 561a94cc50 Tilde: Fix type info for enums 2023-08-07 14:50:06 +01:00
gingerBill 0636887931 Tilde: Add in/not_in for maps 2023-08-07 14:43:11 +01:00
gingerBill 0c1b39d881 Mock out map get/set functionality 2023-08-07 14:40:42 +01:00
gingerBill 67ffae7e32 Merge pull request #2655 from hchac/stdlib-parser-fixes
Match C++ parser allowing named arguments after variadic
2023-08-07 11:45:14 +01:00
gingerBill 488a38a96d Merge pull request #2649 from hchac/allow-newline-field-list-separator
Match C++ parser behavior in allowing newlines before a closing brace.
2023-08-07 11:45:08 +01:00
gingerBill 77e5854a16 Merge branch 'master' into stdlib-parser-fixes 2023-08-07 11:02:01 +01:00
gingerBill 2a42dab108 Merge pull request #2661 from Beefster09/fixed-f64-conversion
Fix conversions between fixed point numbers and f64
2023-08-07 11:00:42 +01:00
Guilherme Fernandes 092d103d24 Adding raygui bindings
Including binaries for Windows only at the moment.
2023-08-07 09:44:55 +01:00
gingerBill 12b7df550f Merge pull request #2701 from Alkamist/nanovg-leak-fix
Fix small memory leak in nanovg.
2023-08-05 17:07:35 +01:00
gingerBill 006bd2fe17 Merge pull request #2696 from hwchen/hwchen/fix-parse-call-expr-ellipses
core:odin/parser allow args after varargs in parse_call_expr
2023-08-05 17:07:28 +01:00
gingerBill d252768ac5 Merge pull request #2652 from ftphikari/master
[vendor:directx/d3d_compiler] Added default include file handler
2023-08-05 16:59:43 +01:00
gingerBill dd7c2c0574 Update demo for #relative multi-pointers 2023-08-05 16:09:19 +01:00
gingerBill c91898a888 Remove #relative slices; Replace with #relative multi-pointers 2023-08-05 16:05:39 +01:00
gingerBill afa8eb2d6f Fix #2699 2023-08-05 15:04:14 +01:00
gingerBill 1481015dc4 Fix #2690 2023-08-05 15:01:21 +01:00
gingerBill 8cdedd4cd2 Add raw_data(^matrix[R, C]T) -> [^]T 2023-08-05 12:35:27 +01:00
gingerBill 985e4eed60 Fix #2697 2023-08-04 16:00:10 +01:00
gingerBill 9d0583e0d2 Add missing import 2023-08-04 15:57:50 +01:00
gingerBill 9aed26a234 Remove the use of import within when 2023-08-04 15:54:44 +01:00
gingerBill 3323d5c76c Disallow import declarations within a when statement 2023-08-04 15:45:25 +01:00
Walther Chen 4b9afd787c core:odin/parser allow args after varargs in parse_call_expr 2023-08-03 22:45:21 -04:00
Alkamist cedf01d094 Fix small memory leak in nanovg. 2023-08-03 18:36:12 -04:00
gingerBill 4a71603a77 Add hasher proc generation 2023-08-03 14:46:22 +01:00
gingerBill aadc8477b9 Generate equal proc for unions 2023-08-03 13:42:14 +01:00
gingerBill 9bf111bd3d Add comments for tilde building 2023-08-03 13:26:42 +01:00
gingerBill 8060da2132 Toggle tilde backend in the build script 2023-08-03 13:16:23 +01:00
gingerBill b495a302b0 Merge branch 'master' into tilde 2023-08-03 13:14:09 +01:00
gingerBill c39a360372 Update Tilde for the new TB_Passes approach 2023-07-28 14:57:04 +01:00
gingerBill f6d1724835 BODGE for finding procedure symbols
Related to a dependency graph race condition bug (THIS NEEDS TO BE FIXED)
2023-07-28 12:12:06 +01:00
gingerBill 0f217c715e Fix dependency issue; Allow polymorphic procedures in tilde 2023-07-25 15:15:35 +01:00
gingerBill c4033c215e Support non-constant global slices 2023-07-25 14:37:19 +01:00
gingerBill e914d551e7 Basic support for global variables 2023-07-25 13:56:28 +01:00
gingerBill c6e4b8ed5c Move mutable value decl stuff to a separate procedure 2023-07-25 13:49:19 +01:00
gingerBill ab398f3704 Implement @(static) local variables 2023-07-25 13:46:40 +01:00
ftphikari 699aec331d Merge branch 'odin-lang:master' into master 2023-07-25 15:32:18 +03:00
gingerBill baea6a1da8 Generate anonymous procedure literals 2023-07-25 13:31:22 +01:00
hikari d2375a79f2 [vendor:directx/d3d11] Added missing UUIDs for shader reflection 2023-07-25 14:42:08 +03:00
gingerBill ba48093666 Fill out type information data 2023-07-25 12:19:59 +01:00
gingerBill d4b87f1672 Continue filling in the global type info data 2023-07-25 11:46:53 +01:00
gingerBill e4006eb583 Update tilde 2023-07-25 01:11:57 +01:00
gingerBill b934e4b564 Implement basic runtime type information
This allows for `runtime.println_any` to work!
2023-07-25 00:33:43 +01:00
gingerBill 28c97a9467 Begin work on setting up type information table 2023-07-24 17:12:23 +01:00
gingerBill 28fca190ee Fix transmute(uintptr)ptr etc 2023-07-24 16:09:01 +01:00
gingerBill 78116e0ea2 Implement for in statements for array-like values 2023-07-24 15:46:54 +01:00
gingerBill 5a50afa1fd Implement for in interval statements 2023-07-24 15:28:51 +01:00
gingerBill cf77a0e2b4 Update Tilde to fix reg alloc bug 2023-07-24 15:18:20 +01:00
gingerBill e2593a6883 Update Tilde for testing reg spill stuff 2023-07-24 14:01:10 +01:00
gingerBill 00a44d1ddb Mock out type info initialize stuff 2023-07-24 13:06:01 +01:00
gingerBill d8445fd9df Multithread tilde backend 2023-07-24 12:53:16 +01:00
gingerBill 304db907f5 Generate object name for them module 2023-07-24 12:19:22 +01:00
gingerBill b09cdc0f25 Hook up Tilde to the linker code 2023-07-24 12:01:23 +01:00
gingerBill bd81c6f5b4 Move linker code into separate file 2023-07-24 11:53:18 +01:00
gingerBill 4051dd9522 Update Tilde to get basic "Hello World" working with runtime.print_string 2023-07-24 11:30:07 +01:00
gingerBill 360cb9eb9a Add tb.lib to build.bat 2023-07-24 10:28:56 +01:00
gingerBill 241a939c29 Update Tilde 2023-07-24 10:27:55 +01:00
gingerBill 2f9c5d2d0b Minor clean up to builtin procs 2023-07-23 22:07:21 +01:00
gingerBill 99c812b02d Begin working on a minimum build 2023-07-23 21:44:50 +01:00
gingerBill d82c2ce50f Update Tilde; Add min and max 2023-07-22 12:21:29 +01:00
gingerBill 6c12156b1a Simplify procedure argument handling 2023-07-22 11:16:29 +01:00
gingerBill eec3b3009f Begin work on builtin procedures 2023-07-22 10:16:28 +01:00
gingerBill 4654b41c3e Implement call expressions 2023-07-22 09:06:44 +01:00
gingerBill b09ea17f0e Support multiple return values for non-odin calling conventions 2023-07-22 08:48:13 +01:00
gingerBill 99ebfc337e Support multiple return values 2023-07-22 08:33:30 +01:00
gingerBill e5f9458905 Update Tilde to get procedure passing rules 2023-07-22 07:56:13 +01:00
gingerBill ec0a9a5f8a Copy lvalues on multi-valued assignments to allow for a, b = b, a on large types (minor bodge) 2023-07-21 13:05:39 +01:00
gingerBill 47b924990f Count extra stuff 2023-07-20 02:04:59 +01:00
gingerBill 215bebb01a Remove dead code 2023-07-20 02:00:20 +01:00
gingerBill 9fffa19c51 Mock out more global stuff 2023-07-20 01:58:46 +01:00
gingerBill b54f3d4ee9 Mock out more global value stuff 2023-07-20 01:54:36 +01:00
gingerBill bcdcad5847 Add global string constants 2023-07-20 01:24:19 +01:00
gingerBill 737b8e42e4 Global constants for arrays 2023-07-20 00:48:52 +01:00
gingerBill c61e7c05da Begin working on global constants 2023-07-20 00:34:24 +01:00
gingerBill a919828003 Add complex and quaternion global stuff 2023-07-19 23:27:06 +01:00
gingerBill 0bd33882b6 Basic constant compound literal support 2023-07-19 21:43:42 +01:00
gingerBill e0e55a649c Rename tilde_backend* files to tilde* 2023-07-19 20:50:15 +01:00
gingerBill f32d71eca0 Mock out any type switch statement 2023-07-19 20:44:37 +01:00
gingerBill 5fb98609cd Implement type switch statement for unions 2023-07-19 18:03:42 +01:00
gingerBill 19633ece80 Simplification of the ValueDecl code 2023-07-19 15:51:56 +01:00
gingerBill fb04103352 Add defer statements; add implicit context pointer to context stack 2023-07-19 15:37:33 +01:00
gingerBill 9abf43b0d2 Mock out defer handling logic (before handling defer statements) 2023-07-19 15:24:07 +01:00
gingerBill 7f97274ecc Wrap Tilde's goto pseudo-instruction 2023-07-19 14:31:32 +01:00
gingerBill b2edab193f Support branch statements break/continue/fallthrough 2023-07-19 14:19:01 +01:00
gingerBill 184563bbe1 Add trivial switch statement check to use a jump table 2023-07-19 13:58:56 +01:00
gingerBill 73f25ed182 Add basic switch statement
Implement as naive if-else chain
2023-07-19 13:37:56 +01:00
gingerBill 533f6a552c Add for and += assignments 2023-07-19 13:15:13 +01:00
gingerBill 32ac319525 Implement if statements 2023-07-19 12:55:44 +01:00
gingerBill 569397bd7e Update TB 2023-07-19 11:39:37 +01:00
gingerBill 3535d16c3a Implement Ternary If Expression 2023-07-18 18:58:56 +01:00
gingerBill 7f4efa90c8 Mock out cg_emit_comp 2023-07-18 16:51:37 +01:00
gingerBill bab3cd988e Mock out cg_emit_unary_arith 2023-07-18 13:42:37 +01:00
gingerBill feda213c0c Mock out cg_append_tuple_values 2023-07-18 13:30:59 +01:00
gingerBill c6593e8cde Mock out binary expressions and variable declarations 2023-07-18 13:27:47 +01:00
gingerBill 4d8d3919c0 Update tilde; procedure type determination from debug types 2023-07-18 13:16:35 +01:00
hikari 20dc8b222d [vendor:directx/dxgi] Removed GetDebugInterface
Since Windows 8.1 `DXGIGetDebugInterface1` is present, which eliminates the need for `GetDebugInterface`. Odin does not support Windows versions that Microsoft doesn't support, so anything Windows 7 and earlier is basically useless anyway.
2023-07-18 02:35:05 +03:00
gingerBill 55733171c1 Planning for multi-valued expressions in the tilde backend 2023-07-17 23:16:50 +01:00
gingerBill 988926b59d Flesh out debug procedure type 2023-07-17 22:51:18 +01:00
gingerBill d72f8da6d7 Move debug type code its own file 2023-07-17 22:37:40 +01:00
gingerBill 0b697b24bd Implement debug type for procs 2023-07-17 22:33:13 +01:00
gingerBill b2c75dc3a2 Mostly fill in cg_debug_type 2023-07-17 22:18:15 +01:00
gingerBill b5b3f1fb42 Mock out struct_ep calls 2023-07-17 17:28:12 +01:00
gingerBill bd73834e19 Update Tilde; mock out cg_build_return_stmt
128-bit types are broken
2023-07-17 16:56:10 +01:00
gingerBill 7f43c24297 Merge branch 'master' into tilde 2023-07-17 16:23:01 +01:00
hikari 6ac2c5c6dc [core:sys/windows] Added a couple of procedures 2023-07-17 02:40:49 +03:00
gingerBill 45b3ae31af Mock out more of the ep procedures 2023-07-17 00:31:44 +01:00
gingerBill 66a20264ab Mock out cg_emit_arith 2023-07-17 00:06:03 +01:00
gingerBill d2d243cca8 Mock out cg_emit_conv 2023-07-16 23:41:51 +01:00
Justin Snyder d4194962b0 Update fixed.odin 2023-07-15 23:43:14 -06:00
gingerBill ee8372145d Begin working on proper expressions 2023-07-15 14:26:47 +01:00
gingerBill ccb736411b Basic context creation 2023-07-15 13:30:31 +01:00
gingerBill e2e5641a45 Update TB; Fix calling nullptr TB_Node* problems 2023-07-15 13:15:50 +01:00
ftphikari 7ca0b256eb [core:sys/windows] Added missing MONITORINFOEXW type 2023-07-14 23:02:56 +03:00
gingerBill ca442defbb Mocking out call related stuff 2023-07-14 17:34:00 +01:00
gingerBill b17ebeb6f6 Mock out more of the addr related stuff 2023-07-14 17:03:28 +01:00
gingerBill a8afcf1ca9 cg_emit_load/cg_emit_store 2023-07-14 16:03:21 +01:00
gingerBill 6545cc2d48 Stub out expr and const files 2023-07-14 14:54:49 +01:00
gingerBill 2a10c8fe5c Begin work on building statements 2023-07-14 13:01:17 +01:00
gingerBill 7cd2d14b64 Very start of working on Tilde Backend for Odin 2023-07-14 11:58:18 +01:00
gingerBill fc5abfd68b Update Tilde 2023-07-14 11:56:13 +01:00
hchac cb5c821989 Matching C++ parser changes from commit 67ca9166d3.
Without these changes the core library parser fails to parse:

 - core/fmt/fmt.odin:

     Line 126 (and others):
       sbprint(&str, ..args, sep=sep)

 - core/fmt/fmt_os.odin:

     Line 17 (and others):
       return wprint(w, ..args, sep=sep)

 - core/log/log.odin:

     Line 79 (and others):
       logf(.Debug,   fmt_str, ..args, location=location)

 - core/runtime/core_builtin.odin:

     Line 475 (and others):
       return append_elems(array, ..args, loc=loc)
2023-07-13 15:38:10 -04:00
ftphikari ab7652010b [vendor:directx/dxgi] Rename debug_interface_init to InitDebugInterface 2023-07-13 17:41:21 +03:00
ftphikari 7990566f6b Code review fixes 2023-07-13 17:16:32 +03:00
ftphikari b6baee5f77 [vendor:directx/dxgi] Added GetDebugInterface 2023-07-13 02:11:46 +03:00
ftphikari 24c3ec235a [vendor:directx/d3d_compiler] Added default include file handler 2023-07-12 00:56:01 +03:00
hchac 4c0e9f1f89 Match CPP parser behavior in allowing newlines before a closing brace. 2023-07-11 16:15:06 -04:00
gingerBill 8ebb84ad1e Basic global struct example 2023-07-08 13:02:17 +01:00
gingerBill f0e77a309d Hellope World! with Tilde 2023-07-08 12:43:20 +01:00
gingerBill 7ab531bd21 Add -tilde for working on the new compiler 2023-07-08 12:07:11 +01:00
gingerBill d7af6de9b9 Add tilde 2023-07-08 11:54:44 +01:00
219 changed files with 22907 additions and 4292 deletions
+2 -2
View File
@@ -58,8 +58,8 @@ jobs:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: Download LLVM, botan and setup PATH - name: Download LLVM, botan and setup PATH
run: | run: |
brew install llvm@11 botan brew install llvm@13 botan
echo "/usr/local/opt/llvm@11/bin" >> $GITHUB_PATH echo "/usr/local/opt/llvm@13/bin" >> $GITHUB_PATH
TMP_PATH=$(xcrun --show-sdk-path)/user/include TMP_PATH=$(xcrun --show-sdk-path)/user/include
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
- name: build odin - name: build odin
+2 -2
View File
@@ -69,8 +69,8 @@ jobs:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: Download LLVM and setup PATH - name: Download LLVM and setup PATH
run: | run: |
brew install llvm@11 brew install llvm@13
echo "/usr/local/opt/llvm@11/bin" >> $GITHUB_PATH echo "/usr/local/opt/llvm@13/bin" >> $GITHUB_PATH
TMP_PATH=$(xcrun --show-sdk-path)/user/include TMP_PATH=$(xcrun --show-sdk-path)/user/include
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
- name: build odin - name: build odin
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
+11 -1
View File
@@ -80,6 +80,16 @@ set libs= ^
Synchronization.lib ^ Synchronization.lib ^
bin\llvm\windows\LLVM-C.lib bin\llvm\windows\LLVM-C.lib
rem DO NOT TOUCH!
rem THIS TILDE STUFF IS FOR DEVELOPMENT ONLY!
set tilde_backend=0
if %tilde_backend% EQU 1 (
set libs=%libs% src\tilde\tb.lib
set compiler_defines=%compiler_defines% -DODIN_TILDE_BACKEND
)
rem DO NOT TOUCH!
set linker_flags= -incremental:no -opt:ref -subsystem:console set linker_flags= -incremental:no -opt:ref -subsystem:console
if %release_mode% EQU 0 ( rem Debug if %release_mode% EQU 0 ( rem Debug
@@ -104,4 +114,4 @@ if %release_mode% EQU 0 odin run examples/demo
del *.obj > NUL 2> NUL del *.obj > NUL 2> NUL
:end_of_build :end_of_build
+13 -31
View File
@@ -118,9 +118,7 @@ reader_peek :: proc(b: ^Reader, n: int) -> (data: []byte, err: io.Error) {
b.last_rune_size = -1 b.last_rune_size = -1
for b.w-b.r < n && b.w-b.r < len(b.buf) && b.err == nil { for b.w-b.r < n && b.w-b.r < len(b.buf) && b.err == nil {
if fill_err := _reader_read_new_chunk(b); fill_err != nil { _reader_read_new_chunk(b) or_return
return nil, fill_err
}
} }
if n > len(b.buf) { if n > len(b.buf) {
@@ -156,9 +154,7 @@ reader_discard :: proc(b: ^Reader, n: int) -> (discarded: int, err: io.Error) {
for { for {
skip := reader_buffered(b) skip := reader_buffered(b)
if skip == 0 { if skip == 0 {
if fill_err := _reader_read_new_chunk(b); fill_err != nil { _reader_read_new_chunk(b) or_return
return 0, fill_err
}
skip = reader_buffered(b) skip = reader_buffered(b)
} }
skip = min(skip, remaining) skip = min(skip, remaining)
@@ -223,20 +219,18 @@ reader_read :: proc(b: ^Reader, p: []byte) -> (n: int, err: io.Error) {
// reader_read_byte reads and returns a single byte // reader_read_byte reads and returns a single byte
// If no byte is available, it return an error // If no byte is available, it return an error
reader_read_byte :: proc(b: ^Reader) -> (byte, io.Error) { reader_read_byte :: proc(b: ^Reader) -> (c: byte, err: io.Error) {
b.last_rune_size = -1 b.last_rune_size = -1
for b.r == b.w { for b.r == b.w {
if b.err != nil { if b.err != nil {
return 0, _reader_consume_err(b) return 0, _reader_consume_err(b)
} }
if err := _reader_read_new_chunk(b); err != nil { _reader_read_new_chunk(b) or_return
return 0, err
}
} }
c := b.buf[b.r] c = b.buf[b.r]
b.r += 1 b.r += 1
b.last_byte = int(c) b.last_byte = int(c)
return c, nil return
} }
// reader_unread_byte unreads the last byte. Only the most recently read byte can be unread // reader_unread_byte unreads the last byte. Only the most recently read byte can be unread
@@ -264,15 +258,12 @@ reader_read_rune :: proc(b: ^Reader) -> (r: rune, size: int, err: io.Error) {
!utf8.full_rune(b.buf[b.r:b.w]) && !utf8.full_rune(b.buf[b.r:b.w]) &&
b.err == nil && b.err == nil &&
b.w-b.w < len(b.buf) { b.w-b.w < len(b.buf) {
if err = _reader_read_new_chunk(b); err != nil { _reader_read_new_chunk(b) or_return
return
}
} }
b.last_rune_size = -1 b.last_rune_size = -1
if b.r == b.w { if b.r == b.w {
err = _reader_consume_err(b) return 0, 0, _reader_consume_err(b)
return
} }
r, size = rune(b.buf[b.r]), 1 r, size = rune(b.buf[b.r]), 1
if r >= utf8.RUNE_SELF { if r >= utf8.RUNE_SELF {
@@ -305,27 +296,20 @@ reader_write_to :: proc(b: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
return i64(n), err return i64(n), err
} }
n, err = write_buf(b, w) n = write_buf(b, w) or_return
if err != nil {
return
}
m: i64 m: i64
if b.w-b.r < len(b.buf) { if b.w-b.r < len(b.buf) {
if err = _reader_read_new_chunk(b); err != nil { _reader_read_new_chunk(b) or_return
return
}
} }
for b.r < b.w { for b.r < b.w {
m, err = write_buf(b, w) m, err = write_buf(b, w)
n += m n += m // this needs to be done before returning
if err != nil { if err != nil {
return return
} }
if err = _reader_read_new_chunk(b); err != nil { _reader_read_new_chunk(b) or_return
return
}
} }
if b.err == .EOF { if b.err == .EOF {
@@ -403,9 +387,7 @@ reader_read_slice :: proc(b: ^Reader, delim: byte) -> (line: []byte, err: io.Err
s = b.w - b.r s = b.w - b.r
if err = _reader_read_new_chunk(b); err != nil { _reader_read_new_chunk(b) or_break
break
}
} }
if i := len(line)-1; i >= 0 { if i := len(line)-1; i >= 0 {
+1 -1
View File
@@ -159,7 +159,7 @@ writer_write_rune :: proc(b: ^Writer, r: rune) -> (size: int, err: io.Error) {
return return
} }
// writer_write writes a string into the buffer // writer_write_string writes a string into the buffer
// It returns the number of bytes written // It returns the number of bytes written
// If n < len(p), it will return an error explaining why the write is short // If n < len(p), it will return an error explaining why the write is short
writer_write_string :: proc(b: ^Writer, s: string) -> (int, io.Error) { writer_write_string :: proc(b: ^Writer, s: string) -> (int, io.Error) {
+4 -1
View File
@@ -113,8 +113,11 @@ _buffer_grow :: proc(b: ^Buffer, n: int) -> int {
if i, ok := _buffer_try_grow(b, n); ok { if i, ok := _buffer_try_grow(b, n); ok {
return i return i
} }
if b.buf == nil && n <= SMALL_BUFFER_SIZE { if b.buf == nil && n <= SMALL_BUFFER_SIZE {
b.buf = make([dynamic]byte, n, SMALL_BUFFER_SIZE) // Fixes #2756 by preserving allocator if already set on Buffer via init_buffer_allocator
reserve(&b.buf, SMALL_BUFFER_SIZE)
resize(&b.buf, n)
return 0 return 0
} }
+1 -1
View File
@@ -127,7 +127,7 @@ advance_rune :: proc(t: ^Tokenizer) {
} }
advance_rune_n :: proc(t: ^Tokenizer, n: int) { advance_rune_n :: proc(t: ^Tokenizer, n: int) {
for in 0..<n { for _ in 0..<n {
advance_rune(t) advance_rune(t)
} }
} }
+1 -1
View File
@@ -63,4 +63,4 @@ foreign libc {
// strictly conformant C implementation is 16 on the platforms we care about. // strictly conformant C implementation is 16 on the platforms we care about.
// The choice of 4096 bytes for storage of this type is more than enough on all // The choice of 4096 bytes for storage of this type is more than enough on all
// relevant platforms. // relevant platforms.
jmp_buf :: struct #align 16 { _: [4096]char, } jmp_buf :: struct #align(16) { _: [4096]char, }
+1 -1
View File
@@ -18,7 +18,7 @@ foreign _ {
// strictly conformant C implementation is 16 on the platforms we care about. // strictly conformant C implementation is 16 on the platforms we care about.
// The choice of 4096 bytes for storage of this type is more than enough on all // The choice of 4096 bytes for storage of this type is more than enough on all
// relevant platforms. // relevant platforms.
va_list :: struct #align 16 { va_list :: struct #align(16) {
_: [4096]u8, _: [4096]u8,
} }
+2 -2
View File
@@ -35,12 +35,12 @@ when ODIN_OS == .Windows {
clock_t :: distinct long clock_t :: distinct long
time_t :: distinct i64 time_t :: distinct i64
timespec :: struct #align 8 { timespec :: struct #align(8) {
tv_sec: time_t, tv_sec: time_t,
tv_nsec: long, tv_nsec: long,
} }
tm :: struct #align 8 { tm :: struct #align(8) {
tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday, tm_isdst: int, tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday, tm_isdst: int,
} }
} }
+1 -1
View File
@@ -98,7 +98,7 @@ foreign libc {
} }
// Large enough and aligned enough for any wide-spread in-use libc. // Large enough and aligned enough for any wide-spread in-use libc.
mbstate_t :: struct #align 16 { _: [32]char, } mbstate_t :: struct #align(16) { _: [32]char, }
// Odin does not have default argument promotion so the need for a separate type // Odin does not have default argument promotion so the need for a separate type
// here isn't necessary, though make it distinct just to be safe. // here isn't necessary, though make it distinct just to be safe.
+17 -39
View File
@@ -216,24 +216,16 @@ read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int
// TODO: REMOVE ALL USE OF context.temp_allocator here // TODO: REMOVE ALL USE OF context.temp_allocator here
// the is literally no need for it // the is literally no need for it
b := make([]u8, size, context.temp_allocator) b := make([]u8, size, context.temp_allocator)
_, e := io.read(z.input, b[:]) _ = io.read(z.input, b[:]) or_return
if e == .None { return b, nil
return b, .None
}
return []u8{}, e
} }
read_slice :: proc{read_slice_from_memory, read_slice_from_stream} read_slice :: proc{read_slice_from_memory, read_slice_from_stream}
@(optimization_mode="speed") @(optimization_mode="speed")
read_data :: #force_inline proc(z: ^$C, $T: typeid) -> (res: T, err: io.Error) { read_data :: #force_inline proc(z: ^$C, $T: typeid) -> (res: T, err: io.Error) {
b, e := read_slice(z, size_of(T)) b := read_slice(z, size_of(T)) or_return
if e == .None { return (^T)(&b[0])^, nil
return (^T)(&b[0])^, .None
}
return T{}, e
} }
@(optimization_mode="speed") @(optimization_mode="speed")
@@ -250,12 +242,8 @@ read_u8_from_memory :: #force_inline proc(z: ^Context_Memory_Input) -> (res: u8,
@(optimization_mode="speed") @(optimization_mode="speed")
read_u8_from_stream :: #force_inline proc(z: ^Context_Stream_Input) -> (res: u8, err: io.Error) { read_u8_from_stream :: #force_inline proc(z: ^Context_Stream_Input) -> (res: u8, err: io.Error) {
b, e := read_slice_from_stream(z, 1) b := read_slice_from_stream(z, 1) or_return
if e == .None { return b[0], nil
return b[0], .None
}
return 0, e
} }
read_u8 :: proc{read_u8_from_memory, read_u8_from_stream} read_u8 :: proc{read_u8_from_memory, read_u8_from_stream}
@@ -320,12 +308,9 @@ peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid
size :: size_of(T) size :: size_of(T)
// Get current position to read from. // Get current position to read from.
curr, e1 := z.input->impl_seek(0, .Current) curr := z.input->impl_seek(0, .Current) or_return
if e1 != .None { r, e1 := io.to_reader_at(z.input)
return T{}, e1 if !e1 {
}
r, e2 := io.to_reader_at(z.input)
if !e2 {
return T{}, .Empty return T{}, .Empty
} }
when size <= 128 { when size <= 128 {
@@ -333,8 +318,8 @@ peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid
} else { } else {
b := make([]u8, size, context.temp_allocator) b := make([]u8, size, context.temp_allocator)
} }
_, e3 := io.read_at(r, b[:], curr) _, e2 := io.read_at(r, b[:], curr)
if e3 != .None { if e2 != .None {
return T{}, .Empty return T{}, .Empty
} }
@@ -347,16 +332,9 @@ peek_data_at_offset_from_stream :: #force_inline proc(z: ^Context_Stream_Input,
size :: size_of(T) size :: size_of(T)
// Get current position to return to. // Get current position to return to.
cur_pos, e1 := z.input->impl_seek(0, .Current) cur_pos := z.input->impl_seek(0, .Current) or_return
if e1 != .None {
return T{}, e1
}
// Seek to offset. // Seek to offset.
pos, e2 := z.input->impl_seek(offset, .Start) pos := z.input->impl_seek(offset, .Start) or_return
if e2 != .None {
return T{}, e2
}
r, e3 := io.to_reader_at(z.input) r, e3 := io.to_reader_at(z.input)
if !e3 { if !e3 {
@@ -465,7 +443,7 @@ peek_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width:
if z.num_bits < u64(width) { if z.num_bits < u64(width) {
refill_lsb(z) refill_lsb(z)
} }
return u32(z.code_buffer & ~(~u64(0) << width)) return u32(z.code_buffer &~ (~u64(0) << width))
} }
@(optimization_mode="speed") @(optimization_mode="speed")
@@ -473,7 +451,7 @@ peek_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width:
if z.num_bits < u64(width) { if z.num_bits < u64(width) {
refill_lsb(z) refill_lsb(z)
} }
return u32(z.code_buffer & ~(~u64(0) << width)) return u32(z.code_buffer &~ (~u64(0) << width))
} }
peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream} peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream}
@@ -481,13 +459,13 @@ peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream}
@(optimization_mode="speed") @(optimization_mode="speed")
peek_bits_no_refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 { peek_bits_no_refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
assert(z.num_bits >= u64(width)) assert(z.num_bits >= u64(width))
return u32(z.code_buffer & ~(~u64(0) << width)) return u32(z.code_buffer &~ (~u64(0) << width))
} }
@(optimization_mode="speed") @(optimization_mode="speed")
peek_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 { peek_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
assert(z.num_bits >= u64(width)) assert(z.num_bits >= u64(width))
return u32(z.code_buffer & ~(~u64(0) << width)) return u32(z.code_buffer &~ (~u64(0) << width))
} }
peek_bits_no_refill_lsb :: proc{peek_bits_no_refill_lsb_from_memory, peek_bits_no_refill_lsb_from_stream} peek_bits_no_refill_lsb :: proc{peek_bits_no_refill_lsb_from_memory, peek_bits_no_refill_lsb_from_stream}
+2 -4
View File
@@ -335,10 +335,8 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp
// fmt.printf("GZIP: Expected Payload Size: %v\n", expected_output_size); // fmt.printf("GZIP: Expected Payload Size: %v\n", expected_output_size);
zlib_error := zlib.inflate_raw(z, expected_output_size=expected_output_size) zlib.inflate_raw(z, expected_output_size=expected_output_size) or_return
if zlib_error != nil {
return zlib_error
}
/* /*
Read CRC32 using the ctx bit reader because zlib may leave bytes in there. Read CRC32 using the ctx bit reader because zlib may leave bytes in there.
*/ */
+8 -16
View File
@@ -147,15 +147,7 @@ grow_buffer :: proc(buf: ^[dynamic]u8) -> (err: compress.Error) {
Double until we reach the maximum allowed. Double until we reach the maximum allowed.
*/ */
new_size := min(len(buf) << 1, compress.COMPRESS_OUTPUT_ALLOCATE_MAX) new_size := min(len(buf) << 1, compress.COMPRESS_OUTPUT_ALLOCATE_MAX)
resize(buf, new_size) return resize(buf, new_size)
if len(buf) != new_size {
/*
Resize failed.
*/
return .Resize_Failed
}
return nil
} }
/* /*
@@ -182,7 +174,7 @@ write_byte :: #force_inline proc(z: ^$C, c: u8) -> (err: io.Error) #no_bounds_ch
} }
@(optimization_mode="speed") @(optimization_mode="speed")
repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_check { repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_check {
/* /*
TODO(Jeroen): Once we have a magic ring buffer, we can just peek/write into it TODO(Jeroen): Once we have a magic ring buffer, we can just peek/write into it
without having to worry about wrapping, so no need for a temp allocation to give to without having to worry about wrapping, so no need for a temp allocation to give to
@@ -306,10 +298,10 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro
code := u16(compress.peek_bits_lsb(z,16)) code := u16(compress.peek_bits_lsb(z,16))
k := int(z_bit_reverse(code, 16)) k := int(z_bit_reverse(code, 16))
s: u8
#no_bounds_check for s = HUFFMAN_FAST_BITS+1; ; { s: u8 = HUFFMAN_FAST_BITS+1
if k < t.maxcode[s] { for {
#no_bounds_check if k < t.maxcode[s] {
break break
} }
s += 1 s += 1
@@ -510,8 +502,8 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
/* /*
Try to pre-allocate the output buffer. Try to pre-allocate the output buffer.
*/ */
reserve(&z.output.buf, expected_output_size) reserve(&z.output.buf, expected_output_size) or_return
resize (&z.output.buf, expected_output_size) resize (&z.output.buf, expected_output_size) or_return
} }
if len(z.output.buf) != expected_output_size { if len(z.output.buf) != expected_output_size {
@@ -654,7 +646,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
} }
if int(z.bytes_written) != len(z.output.buf) { if int(z.bytes_written) != len(z.output.buf) {
resize(&z.output.buf, int(z.bytes_written)) resize(&z.output.buf, int(z.bytes_written)) or_return
} }
return nil return nil
@@ -20,10 +20,10 @@ List :: struct {
Node :: struct { Node :: struct {
next, prev: ^Node, prev, next: ^Node,
} }
push_front :: proc(list: ^List, node: ^Node) { push_front :: proc "contextless" (list: ^List, node: ^Node) {
if list.head != nil { if list.head != nil {
list.head.prev = node list.head.prev = node
node.prev, node.next = nil, list.head node.prev, node.next = nil, list.head
@@ -34,7 +34,7 @@ push_front :: proc(list: ^List, node: ^Node) {
} }
} }
push_back :: proc(list: ^List, node: ^Node) { push_back :: proc "contextless" (list: ^List, node: ^Node) {
if list.tail != nil { if list.tail != nil {
list.tail.next = node list.tail.next = node
node.prev, node.next = list.tail, nil node.prev, node.next = list.tail, nil
@@ -45,7 +45,7 @@ push_back :: proc(list: ^List, node: ^Node) {
} }
} }
remove :: proc(list: ^List, node: ^Node) { remove :: proc "contextless" (list: ^List, node: ^Node) {
if node != nil { if node != nil {
if node.next != nil { if node.next != nil {
node.next.prev = node.prev node.next.prev = node.prev
@@ -83,12 +83,34 @@ remove_by_proc :: proc(list: ^List, to_erase: proc(^Node) -> bool) {
} }
} }
remove_by_proc_contextless :: proc(list: ^List, to_erase: proc "contextless" (^Node) -> bool) {
for node := list.head; node != nil; {
next := node.next
if to_erase(node) {
if node.next != nil {
node.next.prev = node.prev
}
if node.prev != nil {
node.prev.next = node.next
}
if list.head == node {
list.head = node.next
}
if list.tail == node {
list.tail = node.prev
}
}
node = next
}
}
is_empty :: proc(list: ^List) -> bool {
is_empty :: proc "contextless" (list: ^List) -> bool {
return list.head == nil return list.head == nil
} }
pop_front :: proc(list: ^List) -> ^Node { pop_front :: proc "contextless" (list: ^List) -> ^Node {
link := list.head link := list.head
if link == nil { if link == nil {
return nil return nil
@@ -108,7 +130,7 @@ pop_front :: proc(list: ^List) -> ^Node {
return link return link
} }
pop_back :: proc(list: ^List) -> ^Node { pop_back :: proc "contextless" (list: ^List) -> ^Node {
link := list.tail link := list.tail
if link == nil { if link == nil {
return nil return nil
@@ -134,25 +156,25 @@ Iterator :: struct($T: typeid) {
offset: uintptr, offset: uintptr,
} }
iterator_head :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T) iterator_head :: proc "contextless" (list: List, $T: typeid, $field_name: string) -> Iterator(T)
where intrinsics.type_has_field(T, field_name), where intrinsics.type_has_field(T, field_name),
intrinsics.type_field_type(T, field_name) == Node { intrinsics.type_field_type(T, field_name) == Node {
return {list.head, offset_of_by_string(T, field_name)} return {list.head, offset_of_by_string(T, field_name)}
} }
iterator_tail :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T) iterator_tail :: proc "contextless" (list: List, $T: typeid, $field_name: string) -> Iterator(T)
where intrinsics.type_has_field(T, field_name), where intrinsics.type_has_field(T, field_name),
intrinsics.type_field_type(T, field_name) == Node { intrinsics.type_field_type(T, field_name) == Node {
return {list.tail, offset_of_by_string(T, field_name)} return {list.tail, offset_of_by_string(T, field_name)}
} }
iterator_from_node :: proc(node: ^Node, $T: typeid, $field_name: string) -> Iterator(T) iterator_from_node :: proc "contextless" (node: ^Node, $T: typeid, $field_name: string) -> Iterator(T)
where intrinsics.type_has_field(T, field_name), where intrinsics.type_has_field(T, field_name),
intrinsics.type_field_type(T, field_name) == Node { intrinsics.type_field_type(T, field_name) == Node {
return {node, offset_of_by_string(T, field_name)} return {node, offset_of_by_string(T, field_name)}
} }
iterate_next :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) { iterate_next :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
node := it.curr node := it.curr
if node == nil { if node == nil {
return nil, false return nil, false
@@ -162,7 +184,7 @@ iterate_next :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
return (^T)(uintptr(node) - it.offset), true return (^T)(uintptr(node) - it.offset), true
} }
iterate_prev :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) { iterate_prev :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
node := it.curr node := it.curr
if node == nil { if node == nil {
return nil, false return nil, false
+1 -1
View File
@@ -56,7 +56,7 @@ space :: proc(q: $Q/Queue($T)) -> int {
// Reserve enough space for at least the specified capacity // Reserve enough space for at least the specified capacity
reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> runtime.Allocator_Error { reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> runtime.Allocator_Error {
if uint(capacity) > q.len { if capacity > space(q^) {
return _grow(q, uint(capacity)) return _grow(q, uint(capacity))
} }
return nil return nil
+1 -1
View File
@@ -248,7 +248,7 @@ _read_record :: proc(r: ^Reader, dst: ^[dynamic]string, allocator := context.all
field_length += 1 field_length += 1
case '\n', '\r': case '\n', '\r':
if !is_quoted { break read_loop } is_quoted or_break read_loop
case r.comma: case r.comma:
field_length = 0 field_length = 0
+11 -12
View File
@@ -207,7 +207,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
case runtime.Type_Info_Relative_Pointer: case runtime.Type_Info_Relative_Pointer:
return .Unsupported_Type return .Unsupported_Type
case runtime.Type_Info_Relative_Slice: case runtime.Type_Info_Relative_Multi_Pointer:
return .Unsupported_Type return .Unsupported_Type
case runtime.Type_Info_Matrix: case runtime.Type_Info_Matrix:
@@ -265,9 +265,8 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
i := 0 i := 0
for bucket_index in 0..<map_cap { for bucket_index in 0..<map_cap {
if !runtime.map_hash_is_valid(hs[bucket_index]) { runtime.map_hash_is_valid(hs[bucket_index]) or_continue
continue
}
opt_write_iteration(w, opt, i) or_return opt_write_iteration(w, opt, i) or_return
i += 1 i += 1
@@ -284,8 +283,8 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
#partial switch info in ti.variant { #partial switch info in ti.variant {
case runtime.Type_Info_String: case runtime.Type_Info_String:
switch s in a { switch s in a {
case string: name = s case string: name = s
case cstring: name = string(s) case cstring: name = string(s)
} }
opt_write_key(w, opt, name) or_return opt_write_key(w, opt, name) or_return
@@ -404,7 +403,7 @@ opt_write_key :: proc(w: io.Writer, opt: ^Marshal_Options, name: string) -> (err
switch opt.spec { switch opt.spec {
case .JSON, .JSON5: case .JSON, .JSON5:
io.write_quoted_string(w, name) or_return io.write_quoted_string(w, name) or_return
io.write_string(w, ": ") or_return io.write_string(w, ": " if opt.pretty else ":") or_return
case .MJSON: case .MJSON:
if opt.mjson_keys_use_quotes { if opt.mjson_keys_use_quotes {
@@ -412,11 +411,11 @@ opt_write_key :: proc(w: io.Writer, opt: ^Marshal_Options, name: string) -> (err
} else { } else {
io.write_string(w, name) or_return io.write_string(w, name) or_return
} }
if opt.mjson_keys_use_equal_sign { if opt.mjson_keys_use_equal_sign {
io.write_string(w, " = ") or_return io.write_string(w, " = " if opt.pretty else "=") or_return
} else { } else {
io.write_string(w, ": ") or_return io.write_string(w, ": " if opt.pretty else ":") or_return
} }
} }
@@ -446,7 +445,7 @@ opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int)
switch opt.spec { switch opt.spec {
case .JSON, .JSON5: case .JSON, .JSON5:
if iteration > 0 { if iteration > 0 {
io.write_string(w, ", ") or_return io.write_byte(w, ',') or_return
if opt.pretty { if opt.pretty {
io.write_byte(w, '\n') or_return io.write_byte(w, '\n') or_return
@@ -462,7 +461,7 @@ opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int)
io.write_byte(w, '\n') or_return io.write_byte(w, '\n') or_return
} else { } else {
// comma separation necessary for non pretty output! // comma separation necessary for non pretty output!
io.write_string(w, ", ") or_return io.write_byte(w, ',') or_return
} }
} }
+1 -1
View File
@@ -343,7 +343,7 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
i += 1 i += 1
continue continue
} }
r, w := utf8.decode_rune_in_string(s) r, w := utf8.decode_rune_in_string(s[i:])
if r == utf8.RUNE_ERROR && w == 1 { if r == utf8.RUNE_ERROR && w == 1 {
break break
} }
+2 -2
View File
@@ -21,13 +21,13 @@ find_child_by_ident :: proc(doc: ^Document, parent_id: Element_ID, ident: string
/* /*
Skip commments. They have no name. Skip commments. They have no name.
*/ */
if child.kind != .Element { continue } if child.kind != .Element { continue }
/* /*
If the ident matches and it's the nth such child, return it. If the ident matches and it's the nth such child, return it.
*/ */
if child.ident == ident { if child.ident == ident {
if count == nth { return child_id, true } if count == nth { return child_id, true }
count += 1 count += 1
} }
} }
+3
View File
@@ -35,6 +35,8 @@ Floating-point, complex numbers, and quaternions:
%F synonym for %f %F synonym for %f
%h hexadecimal (lower-case) representation with 0h prefix (0h01234abcd) %h hexadecimal (lower-case) representation with 0h prefix (0h01234abcd)
%H hexadecimal (upper-case) representation with 0H prefix (0h01234ABCD) %H hexadecimal (upper-case) representation with 0H prefix (0h01234ABCD)
%m number of bytes in the best unit of measurement, e.g. 123.45mib
%M number of bytes in the best unit of measurement, e.g. 123.45MiB
String and slice of bytes String and slice of bytes
%s the uninterpreted bytes of the string or slice %s the uninterpreted bytes of the string or slice
%q a double-quoted string safely escaped with Odin syntax %q a double-quoted string safely escaped with Odin syntax
@@ -85,6 +87,7 @@ Other flags:
add leading 0z for dozenal (%#z) add leading 0z for dozenal (%#z)
add leading 0x or 0X for hexadecimal (%#x or %#X) add leading 0x or 0X for hexadecimal (%#x or %#X)
remove leading 0x for %p (%#p) remove leading 0x for %p (%#p)
add a space between bytes and the unit of measurement (%#m or %#M)
' ' (space) leave a space for elided sign in numbers (% d) ' ' (space) leave a space for elided sign in numbers (% d)
0 pad with leading zeros rather than spaces 0 pad with leading zeros rather than spaces
+96 -50
View File
@@ -152,9 +152,9 @@ aprintln :: proc(args: ..any, sep := " ") -> string {
// //
// Returns: A formatted string. The returned string must be freed accordingly. // Returns: A formatted string. The returned string must be freed accordingly.
// //
aprintf :: proc(fmt: string, args: ..any) -> string { aprintf :: proc(fmt: string, args: ..any, allocator := context.allocator) -> string {
str: strings.Builder str: strings.Builder
strings.builder_init(&str) strings.builder_init(&str, allocator)
sbprintf(&str, fmt, ..args) sbprintf(&str, fmt, ..args)
return strings.to_string(str) return strings.to_string(str)
} }
@@ -327,7 +327,7 @@ ctprintf :: proc(format: string, args: ..any) -> cstring {
// Returns: A formatted string // Returns: A formatted string
// //
sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
wprint(strings.to_writer(buf), ..args, sep=sep) wprint(strings.to_writer(buf), ..args, sep=sep, flush=true)
return strings.to_string(buf^) return strings.to_string(buf^)
} }
// Formats and writes to a strings.Builder buffer using the default print settings // Formats and writes to a strings.Builder buffer using the default print settings
@@ -340,7 +340,7 @@ sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
// Returns: The resulting formatted string // Returns: The resulting formatted string
// //
sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
wprintln(strings.to_writer(buf), ..args, sep=sep) wprintln(strings.to_writer(buf), ..args, sep=sep, flush=true)
return strings.to_string(buf^) return strings.to_string(buf^)
} }
// Formats and writes to a strings.Builder buffer according to the specified format string // Formats and writes to a strings.Builder buffer according to the specified format string
@@ -353,7 +353,7 @@ sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
// Returns: The resulting formatted string // Returns: The resulting formatted string
// //
sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any) -> string { sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any) -> string {
wprintf(strings.to_writer(buf), fmt, ..args) wprintf(strings.to_writer(buf), fmt, ..args, flush=true)
return strings.to_string(buf^) return strings.to_string(buf^)
} }
// Formats and writes to an io.Writer using the default print settings // Formats and writes to an io.Writer using the default print settings
@@ -365,7 +365,7 @@ sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any) -> string {
// //
// Returns: The number of bytes written // Returns: The number of bytes written
// //
wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int { wprint :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int {
fi: Info fi: Info
fi.writer = w fi.writer = w
@@ -391,7 +391,9 @@ wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
fmt_value(&fi, args[i], 'v') fmt_value(&fi, args[i], 'v')
} }
io.flush(auto_cast w) if flush {
io.flush(w)
}
return fi.n return fi.n
} }
@@ -404,7 +406,7 @@ wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
// //
// Returns: The number of bytes written // Returns: The number of bytes written
// //
wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int { wprintln :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int {
fi: Info fi: Info
fi.writer = w fi.writer = w
@@ -416,7 +418,9 @@ wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
fmt_value(&fi, args[i], 'v') fmt_value(&fi, args[i], 'v')
} }
io.write_byte(fi.writer, '\n', &fi.n) io.write_byte(fi.writer, '\n', &fi.n)
io.flush(auto_cast w) if flush {
io.flush(w)
}
return fi.n return fi.n
} }
// Formats and writes to an io.Writer according to the specified format string // Formats and writes to an io.Writer according to the specified format string
@@ -428,7 +432,7 @@ wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
// //
// Returns: The number of bytes written // Returns: The number of bytes written
// //
wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int { wprintf :: proc(w: io.Writer, fmt: string, args: ..any, flush := true) -> int {
fi: Info fi: Info
arg_index: int = 0 arg_index: int = 0
end := len(fmt) end := len(fmt)
@@ -698,8 +702,9 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int {
} }
io.write_string(fi.writer, ")", &fi.n) io.write_string(fi.writer, ")", &fi.n)
} }
if flush {
io.flush(auto_cast w) io.flush(w)
}
return fi.n return fi.n
} }
@@ -711,9 +716,11 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int {
// //
// Returns: The number of bytes written and an io.Error if encountered // Returns: The number of bytes written and an io.Error if encountered
// //
wprint_type :: proc(w: io.Writer, info: ^runtime.Type_Info) -> (int, io.Error) { wprint_type :: proc(w: io.Writer, info: ^runtime.Type_Info, flush := true) -> (int, io.Error) {
n, err := reflect.write_type(w, info) n, err := reflect.write_type(w, info)
io.flush(auto_cast w) if flush {
io.flush(w)
}
return n, err return n, err
} }
// Writes a typeid value to an io.Writer // Writes a typeid value to an io.Writer
@@ -724,9 +731,11 @@ wprint_type :: proc(w: io.Writer, info: ^runtime.Type_Info) -> (int, io.Error) {
// //
// Returns: The number of bytes written and an io.Error if encountered // Returns: The number of bytes written and an io.Error if encountered
// //
wprint_typeid :: proc(w: io.Writer, id: typeid) -> (int, io.Error) { wprint_typeid :: proc(w: io.Writer, id: typeid, flush := true) -> (int, io.Error) {
n, err := reflect.write_type(w, type_info_of(id)) n, err := reflect.write_type(w, type_info_of(id))
io.flush(auto_cast w) if flush {
io.flush(w)
}
return n, err return n, err
} }
// Parses an integer from a given string starting at a specified offset // Parses an integer from a given string starting at a specified offset
@@ -746,9 +755,8 @@ _parse_int :: proc(s: string, offset: int) -> (result: int, new_offset: int, ok:
new_offset = offset new_offset = offset
for new_offset < len(s) { for new_offset < len(s) {
c := s[new_offset] c := s[new_offset]
if !is_digit(c) { is_digit(c) or_break
break
}
new_offset += 1 new_offset += 1
result *= 10 result *= 10
@@ -1039,6 +1047,65 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i
fi.zero = false fi.zero = false
_pad(fi, s) _pad(fi, s)
} }
// Units of measurements:
__MEMORY_LOWER := " b kib mib gib tib pib eib"
__MEMORY_UPPER := " B KiB MiB GiB TiB PiB EiB"
// Formats an integer value as bytes with the best representation.
//
// Inputs:
// - fi: A pointer to an Info structure
// - u: The integer value to format
// - is_signed: A boolean indicating if the integer is signed
// - bit_size: The bit size of the integer
// - digits: A string containing the digits for formatting
//
_fmt_memory :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, units: string) {
abs, neg := strconv.is_integer_negative(u, is_signed, bit_size)
// Default to a precision of 2, but if less than a kb, 0
prec := fi.prec if (fi.prec_set || abs < mem.Kilobyte) else 2
div, off, unit_len := 1, 0, 1
for n := abs; n >= mem.Kilobyte; n /= mem.Kilobyte {
div *= mem.Kilobyte
off += 4
// First iteration is slightly different because you go from
// units of length 1 to units of length 2.
if unit_len == 1 {
off = 2
unit_len = 3
}
}
// If hash, we add a space between the value and the suffix.
if fi.hash {
unit_len += 1
} else {
off += 1
}
amt := f64(abs) / f64(div)
if neg {
amt = -amt
}
buf: [256]byte
str := strconv.append_float(buf[:], amt, 'f', prec, 64)
// Add the unit at the end.
copy(buf[len(str):], units[off:off+unit_len])
str = string(buf[:len(str)+unit_len])
if !fi.plus {
// Strip sign from "+<value>" but not "+Inf".
if str[0] == '+' && str[1] != 'I' {
str = str[1:]
}
}
_pad(fi, str)
}
// Hex Values: // Hex Values:
__DIGITS_LOWER := "0123456789abcdefx" __DIGITS_LOWER := "0123456789abcdefx"
__DIGITS_UPPER := "0123456789ABCDEFX" __DIGITS_UPPER := "0123456789ABCDEFX"
@@ -1087,6 +1154,8 @@ fmt_int :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, verb: rune) {
io.write_string(fi.writer, "U+", &fi.n) io.write_string(fi.writer, "U+", &fi.n)
_fmt_int(fi, u, 16, false, bit_size, __DIGITS_UPPER) _fmt_int(fi, u, 16, false, bit_size, __DIGITS_UPPER)
} }
case 'm': _fmt_memory(fi, u, is_signed, bit_size, __MEMORY_LOWER)
case 'M': _fmt_memory(fi, u, is_signed, bit_size, __MEMORY_UPPER)
case: case:
fmt_bad_verb(fi, verb) fmt_bad_verb(fi, verb)
@@ -1565,7 +1634,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
// - fi: A pointer to the Info structure where the indents will be written. // - fi: A pointer to the Info structure where the indents will be written.
// //
fmt_write_indent :: proc(fi: ^Info) { fmt_write_indent :: proc(fi: ^Info) {
for in 0..<fi.indent { for _ in 0..<fi.indent {
io.write_byte(fi.writer, '\t', &fi.n) io.write_byte(fi.writer, '\t', &fi.n)
} }
} }
@@ -1720,7 +1789,7 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St
} }
defer { defer {
if hash { if hash {
for in 0..<indent { io.write_byte(fi.writer, '\t', &fi.n) } for _ in 0..<indent { io.write_byte(fi.writer, '\t', &fi.n) }
} }
io.write_byte(fi.writer, ']' if is_soa else '}', &fi.n) io.write_byte(fi.writer, ']' if is_soa else '}', &fi.n)
} }
@@ -1956,7 +2025,7 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named)
for x := i; x >= 10; x /= 10 { for x := i; x >= 10; x /= 10 {
n -= 1 n -= 1
} }
for in 0..<n { for _ in 0..<n {
io.write_byte(fi.writer, '0', &fi.n) io.write_byte(fi.writer, '0', &fi.n)
} }
io.write_i64(fi.writer, i, 10, &fi.n) io.write_i64(fi.writer, i, 10, &fi.n)
@@ -1989,7 +2058,7 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named)
v := v v := v
w := len(buf) w := len(buf)
print := false print := false
for in 0..<prec { for _ in 0..<prec {
digit := v % 10 digit := v % 10
print = print || digit != 0 print = print || digit != 0
if print { if print {
@@ -2485,9 +2554,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info) ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info)
j := 0 j := 0
for bucket_index in 0..<map_cap { for bucket_index in 0..<map_cap {
if !runtime.map_hash_is_valid(hs[bucket_index]) { runtime.map_hash_is_valid(hs[bucket_index]) or_continue
continue
}
if j > 0 { if j > 0 {
io.write_string(fi.writer, ", ", &fi.n) io.write_string(fi.writer, ", ", &fi.n)
@@ -2535,32 +2602,11 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
fmt_value(fi, absolute_ptr, verb) fmt_value(fi, absolute_ptr, verb)
case runtime.Type_Info_Relative_Slice: case runtime.Type_Info_Relative_Multi_Pointer:
ptr := reflect.relative_pointer_to_absolute_raw(v.data, info.base_integer.id) ptr := reflect.relative_pointer_to_absolute_raw(v.data, info.base_integer.id)
absolute_ptr := any{ptr, info.pointer.id}
if verb == 'p' { fmt_value(fi, absolute_ptr, verb)
fmt_pointer(fi, ptr, 'p')
} else if ptr == nil {
io.write_string(fi.writer, "[]", &fi.n)
} else {
len_ptr := uintptr(v.data) + uintptr(info.base_integer.size)
len_any := any{rawptr(len_ptr), info.base_integer.id}
len, _ := reflect.as_int(len_any)
slice_type := reflect.type_info_base(info.slice).variant.(runtime.Type_Info_Slice)
fi.record_level += 1
defer fi.record_level -= 1
io.write_byte(fi.writer, '[', &fi.n)
defer io.write_byte(fi.writer, ']', &fi.n)
for i in 0..<len {
if i > 0 { io.write_string(fi.writer, ", ", &fi.n) }
data := uintptr(ptr) + uintptr(i*slice_type.elem_size)
fmt_arg(fi, any{rawptr(data), slice_type.elem.id}, verb)
}
}
case runtime.Type_Info_Matrix: case runtime.Type_Info_Matrix:
fmt_matrix(fi, v, verb, info) fmt_matrix(fi, v, verb, info)
+6 -6
View File
@@ -32,15 +32,15 @@ stderr := io.Writer{
} }
// print formats using the default print settings and writes to stdout // print formats using the default print settings and writes to stdout
print :: proc(args: ..any, sep := " ") -> int { return wprint(w=stdout, args=args, sep=sep) } print :: proc(args: ..any, sep := " ", flush := true) -> int { return wprint(w=stdout, args=args, sep=sep, flush=flush) }
// println formats using the default print settings and writes to stdout // println formats using the default print settings and writes to stdout
println :: proc(args: ..any, sep := " ") -> int { return wprintln(w=stdout, args=args, sep=sep) } println :: proc(args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stdout, args=args, sep=sep, flush=flush) }
// printf formats according to the specififed format string and writes to stdout // printf formats according to the specififed format string and writes to stdout
printf :: proc(fmt: string, args: ..any) -> int { return wprintf(stdout, fmt, ..args) } printf :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush) }
// eprint formats using the default print settings and writes to stderr // eprint formats using the default print settings and writes to stderr
eprint :: proc(args: ..any, sep := " ") -> int { return wprint(w=stderr, args=args, sep=sep) } eprint :: proc(args: ..any, sep := " ", flush := true) -> int { return wprint(w=stderr, args=args, sep=sep, flush=flush) }
// eprintln formats using the default print settings and writes to stderr // eprintln formats using the default print settings and writes to stderr
eprintln :: proc(args: ..any, sep := " ") -> int { return wprintln(w=stderr, args=args, sep=sep) } eprintln :: proc(args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stderr, args=args, sep=sep, flush=flush) }
// eprintf formats according to the specififed format string and writes to stderr // eprintf formats according to the specififed format string and writes to stderr
eprintf :: proc(fmt: string, args: ..any) -> int { return wprintf(stderr, fmt, ..args) } eprintf :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stderr, fmt, ..args, flush=flush) }
+16 -16
View File
@@ -7,18 +7,18 @@ import "core:io"
import "core:bufio" import "core:bufio"
// fprint formats using the default print settings and writes to fd // fprint formats using the default print settings and writes to fd
fprint :: proc(fd: os.Handle, args: ..any, sep := " ") -> int { fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int {
buf: [1024]byte buf: [1024]byte
b: bufio.Writer b: bufio.Writer
defer bufio.writer_flush(&b) defer bufio.writer_flush(&b)
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
w := bufio.writer_to_writer(&b) w := bufio.writer_to_writer(&b)
return wprint(w, ..args, sep=sep) return wprint(w, ..args, sep=sep, flush=flush)
} }
// fprintln formats using the default print settings and writes to fd // fprintln formats using the default print settings and writes to fd
fprintln :: proc(fd: os.Handle, args: ..any, sep := " ") -> int { fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int {
buf: [1024]byte buf: [1024]byte
b: bufio.Writer b: bufio.Writer
defer bufio.writer_flush(&b) defer bufio.writer_flush(&b)
@@ -26,10 +26,10 @@ fprintln :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
w := bufio.writer_to_writer(&b) w := bufio.writer_to_writer(&b)
return wprintln(w, ..args, sep=sep) return wprintln(w, ..args, sep=sep, flush=flush)
} }
// fprintf formats according to the specified format string and writes to fd // fprintf formats according to the specified format string and writes to fd
fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int { fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true) -> int {
buf: [1024]byte buf: [1024]byte
b: bufio.Writer b: bufio.Writer
defer bufio.writer_flush(&b) defer bufio.writer_flush(&b)
@@ -37,9 +37,9 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
w := bufio.writer_to_writer(&b) w := bufio.writer_to_writer(&b)
return wprintf(w, fmt, ..args) return wprintf(w, fmt, ..args, flush=flush)
} }
fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) -> (n: int, err: io.Error) { fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info, flush := true) -> (n: int, err: io.Error) {
buf: [1024]byte buf: [1024]byte
b: bufio.Writer b: bufio.Writer
defer bufio.writer_flush(&b) defer bufio.writer_flush(&b)
@@ -47,9 +47,9 @@ fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) -> (n: int, err: io
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
w := bufio.writer_to_writer(&b) w := bufio.writer_to_writer(&b)
return wprint_type(w, info) return wprint_type(w, info, flush=flush)
} }
fprint_typeid :: proc(fd: os.Handle, id: typeid) -> (n: int, err: io.Error) { fprint_typeid :: proc(fd: os.Handle, id: typeid, flush := true) -> (n: int, err: io.Error) {
buf: [1024]byte buf: [1024]byte
b: bufio.Writer b: bufio.Writer
defer bufio.writer_flush(&b) defer bufio.writer_flush(&b)
@@ -57,19 +57,19 @@ fprint_typeid :: proc(fd: os.Handle, id: typeid) -> (n: int, err: io.Error) {
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
w := bufio.writer_to_writer(&b) w := bufio.writer_to_writer(&b)
return wprint_typeid(w, id) return wprint_typeid(w, id, flush=flush)
} }
// print formats using the default print settings and writes to os.stdout // print formats using the default print settings and writes to os.stdout
print :: proc(args: ..any, sep := " ") -> int { return fprint(os.stdout, ..args, sep=sep) } print :: proc(args: ..any, sep := " ", flush := true) -> int { return fprint(os.stdout, ..args, sep=sep, flush=flush) }
// println formats using the default print settings and writes to os.stdout // println formats using the default print settings and writes to os.stdout
println :: proc(args: ..any, sep := " ") -> int { return fprintln(os.stdout, ..args, sep=sep) } println :: proc(args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stdout, ..args, sep=sep, flush=flush) }
// printf formats according to the specified format string and writes to os.stdout // printf formats according to the specified format string and writes to os.stdout
printf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stdout, fmt, ..args) } printf :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush) }
// eprint formats using the default print settings and writes to os.stderr // eprint formats using the default print settings and writes to os.stderr
eprint :: proc(args: ..any, sep := " ") -> int { return fprint(os.stderr, ..args, sep=sep) } eprint :: proc(args: ..any, sep := " ", flush := true) -> int { return fprint(os.stderr, ..args, sep=sep, flush=flush) }
// eprintln formats using the default print settings and writes to os.stderr // eprintln formats using the default print settings and writes to os.stderr
eprintln :: proc(args: ..any, sep := " ") -> int { return fprintln(os.stderr, ..args, sep=sep) } eprintln :: proc(args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stderr, ..args, sep=sep, flush=flush) }
// eprintf formats according to the specified format string and writes to os.stderr // eprintf formats according to the specified format string and writes to os.stderr
eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stderr, fmt, ..args) } eprintf :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush) }
+1 -1
View File
@@ -299,7 +299,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
if length := int(data & 63) + 1; (length * img.channels) > len(pixels) { if length := int(data & 63) + 1; (length * img.channels) > len(pixels) {
return img, .Corrupt return img, .Corrupt
} else { } else {
#no_bounds_check for in 0..<length { #no_bounds_check for _ in 0..<length {
copy(pixels, pix[:img.channels]) copy(pixels, pix[:img.channels])
pixels = pixels[img.channels:] pixels = pixels[img.channels:]
} }
+4 -4
View File
@@ -215,10 +215,10 @@ simd_shr_masked :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T
simd_add_sat :: proc(a, b: #simd[N]T) -> #simd[N]T --- simd_add_sat :: proc(a, b: #simd[N]T) -> #simd[N]T ---
simd_sub_sat :: proc(a, b: #simd[N]T) -> #simd[N]T --- simd_sub_sat :: proc(a, b: #simd[N]T) -> #simd[N]T ---
simd_and :: proc(a, b: #simd[N]T) -> #simd[N]T --- simd_bit_and :: proc(a, b: #simd[N]T) -> #simd[N]T ---
simd_or :: proc(a, b: #simd[N]T) -> #simd[N]T --- simd_bit_or :: proc(a, b: #simd[N]T) -> #simd[N]T ---
simd_xor :: proc(a, b: #simd[N]T) -> #simd[N]T --- simd_bit_xor :: proc(a, b: #simd[N]T) -> #simd[N]T ---
simd_and_not :: proc(a, b: #simd[N]T) -> #simd[N]T --- simd_bit_and_not :: proc(a, b: #simd[N]T) -> #simd[N]T ---
simd_neg :: proc(a: #simd[N]T) -> #simd[N]T --- simd_neg :: proc(a: #simd[N]T) -> #simd[N]T ---
+2 -2
View File
@@ -39,12 +39,12 @@ write_int :: proc(w: Writer, i: int, base: int = 10, n_written: ^int = nil) -> (
} }
write_u128 :: proc(w: Writer, i: u128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { write_u128 :: proc(w: Writer, i: u128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
buf: [32]byte buf: [39]byte
s := strconv.append_bits_128(buf[:], i, base, false, 128, strconv.digits, nil) s := strconv.append_bits_128(buf[:], i, base, false, 128, strconv.digits, nil)
return write_string(w, s, n_written) return write_string(w, s, n_written)
} }
write_i128 :: proc(w: Writer, i: i128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { write_i128 :: proc(w: Writer, i: i128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
buf: [32]byte buf: [40]byte
s := strconv.append_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil) s := strconv.append_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil)
return write_string(w, s, n_written) return write_string(w, s, n_written)
} }
+8 -8
View File
@@ -22,43 +22,43 @@ package math_big
/* /*
2's complement `and`, returns `dest = a & b;` 2's complement `and`, returns `dest = a & b;`
*/ */
int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) { int_bit_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dest, a, b) assert_if_nil(dest, a, b)
context.allocator = allocator context.allocator = allocator
internal_clear_if_uninitialized(a, b) or_return internal_clear_if_uninitialized(a, b) or_return
return #force_inline internal_int_and(dest, a, b) return #force_inline internal_int_and(dest, a, b)
} }
and :: proc { int_and, } bit_and :: proc { int_bit_and, }
/* /*
2's complement `or`, returns `dest = a | b;` 2's complement `or`, returns `dest = a | b;`
*/ */
int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) { int_bit_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dest, a, b) assert_if_nil(dest, a, b)
context.allocator = allocator context.allocator = allocator
internal_clear_if_uninitialized(a, b) or_return internal_clear_if_uninitialized(a, b) or_return
return #force_inline internal_int_or(dest, a, b) return #force_inline internal_int_or(dest, a, b)
} }
or :: proc { int_or, } bit_or :: proc { int_bit_or, }
/* /*
2's complement `xor`, returns `dest = a ^ b;` 2's complement `xor`, returns `dest = a ^ b;`
*/ */
int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) { int_bit_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dest, a, b) assert_if_nil(dest, a, b)
context.allocator = allocator context.allocator = allocator
internal_clear_if_uninitialized(a, b) or_return internal_clear_if_uninitialized(a, b) or_return
return #force_inline internal_int_xor(dest, a, b) return #force_inline internal_int_xor(dest, a, b)
} }
xor :: proc { int_xor, } bit_xor :: proc { int_bit_xor, }
/* /*
dest = ~src dest = ~src
*/ */
int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) { int_bit_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
/* /*
Check that `src` and `dest` are usable. Check that `src` and `dest` are usable.
*/ */
@@ -68,7 +68,7 @@ int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err:
internal_clear_if_uninitialized(dest, src) or_return internal_clear_if_uninitialized(dest, src) or_return
return #force_inline internal_int_complement(dest, src) return #force_inline internal_int_complement(dest, src)
} }
complement :: proc { int_complement, } bit_complement :: proc { int_bit_complement, }
/* /*
quotient, remainder := numerator >> bits; quotient, remainder := numerator >> bits;
+7 -7
View File
@@ -1163,7 +1163,7 @@ internal_int_prime_next_prime :: proc(a: ^Int, trials: int, bbs_style: bool, all
/* /*
If we didn't pass the sieve and step == MP_MAX then skip test */ If we didn't pass the sieve and step == MP_MAX then skip test */
if (y && (step >= ((1 << _DIGIT_BITS) - kstep))) { continue } if y && (step >= ((1 << _DIGIT_BITS) - kstep)) { continue }
if internal_int_is_prime(a, trials) or_return { break } if internal_int_is_prime(a, trials) or_return { break }
} }
@@ -1214,7 +1214,6 @@ internal_random_prime :: proc(a: ^Int, size_in_bits: int, trials: int, flags :=
trials = number_of_rabin_miller_trials(size_in_bits) trials = number_of_rabin_miller_trials(size_in_bits)
} }
res: bool
RANDOM_PRIME_ITERATIONS_USED = 0 RANDOM_PRIME_ITERATIONS_USED = 0
for { for {
@@ -1251,9 +1250,8 @@ internal_random_prime :: proc(a: ^Int, size_in_bits: int, trials: int, flags :=
/* /*
Is it prime? Is it prime?
*/ */
res = internal_int_is_prime(a, trials) or_return res := internal_int_is_prime(a, trials) or_return
if !res {
if (!res) {
continue continue
} }
@@ -1267,9 +1265,11 @@ internal_random_prime :: proc(a: ^Int, size_in_bits: int, trials: int, flags :=
/* /*
Is it prime? Is it prime?
*/ */
res = internal_int_is_prime(a, trials) or_return res = internal_int_is_prime(a, trials) or_return
}
if res {
break
} }
if res { break }
} }
if .Safe in flags { if .Safe in flags {
+1 -1
View File
@@ -1089,7 +1089,7 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In
Step 3. for i from n down to (t + 1). Step 3. for i from n down to (t + 1).
*/ */
#no_bounds_check for i := n; i >= (t + 1); i -= 1 { #no_bounds_check for i := n; i >= (t + 1); i -= 1 {
if (i > x.used) { continue } if i > x.used { continue }
/* /*
step 3.1 if xi == yt then set q{i-t-1} to b-1, otherwise set q{i-t-1} to (xi*b + x{i-1})/yt step 3.1 if xi == yt then set q{i-t-1} to b-1, otherwise set q{i-t-1} to (xi*b + x{i-1})/yt
+7 -5
View File
@@ -29,13 +29,13 @@ Fixed52_12 :: distinct Fixed(i64, 12)
init_from_f64 :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), val: f64) { init_from_f64 :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), val: f64) {
i, f := math.modf(val) i, f := math.modf(math.abs(val))
x.i = Backing(f * (1<<Fraction_Width)) x.i = Backing(f * (1<<Fraction_Width))
x.i &= 1<<Fraction_Width - 1 x.i &= 1<<Fraction_Width - 1
x.i |= Backing(i) << Fraction_Width x.i |= Backing(i) << Fraction_Width
if val < 0 do x.i *= -1
} }
init_from_parts :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), integer, fraction: Backing) { init_from_parts :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), integer, fraction: Backing) {
i, f := math.modf(val) i, f := math.modf(val)
x.i = fraction x.i = fraction
@@ -44,9 +44,11 @@ init_from_parts :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), integer, fracti
} }
to_f64 :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> f64 { to_f64 :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> f64 {
res := f64(x.i >> Fraction_Width) sign := -1.0 if x.i < 0 else 1.0
res += f64(x.i & (1<<Fraction_Width-1)) / f64(1<<Fraction_Width) num := math.abs(x.i)
return res res := f64(num >> Fraction_Width)
res += f64(num & (1<<Fraction_Width-1)) / f64(1<<Fraction_Width)
return res * sign
} }
+60 -40
View File
@@ -1,9 +1,11 @@
/* /*
Package core:math/rand implements various random number generators Package core:math/rand implements various random number generators
*/ */
package rand package rand
import "core:intrinsics" import "core:intrinsics"
import "core:math"
import "core:mem" import "core:mem"
Rand :: struct { Rand :: struct {
@@ -70,6 +72,7 @@ create :: proc(seed: u64) -> (res: Rand) {
return r return r
} }
/* /*
Initialises a random number generator. Initialises a random number generator.
@@ -95,9 +98,9 @@ Possible Output:
init :: proc(r: ^Rand, seed: u64) { init :: proc(r: ^Rand, seed: u64) {
r.state = 0 r.state = 0
r.inc = (seed << 1) | 1 r.inc = (seed << 1) | 1
_random(r) _random_u64(r)
r.state += seed r.state += seed
_random(r) _random_u64(r)
} }
/* /*
@@ -107,7 +110,7 @@ On `linux` refer to the `getrandom` syscall.
On `darwin` refer to `getentropy`. On `darwin` refer to `getentropy`.
On `windows` refer to `BCryptGenRandom`. On `windows` refer to `BCryptGenRandom`.
All other platforms wi All other platforms are not supported
Inputs: Inputs:
- r: The random number generator to use the system random number generator - r: The random number generator to use the system random number generator
@@ -139,11 +142,9 @@ init_as_system :: proc(r: ^Rand) {
} }
@(private) @(private)
_random :: proc(r: ^Rand) -> u32 { _random_u64 :: proc(r: ^Rand) -> u64 {
r := r r := r
if r == nil { if r == nil {
// NOTE(bill, 2020-09-07): Do this so that people can
// enforce the global random state if necessary with `nil`
r = &global_rand r = &global_rand
} }
when #defined(_system_random) { when #defined(_system_random) {
@@ -152,11 +153,12 @@ _random :: proc(r: ^Rand) -> u32 {
} }
} }
old_state := r.state old_state := r.state
r.state = old_state * 6364136223846793005 + (r.inc|1) r.state = old_state * 6364136223846793005 + (r.inc|1)
xor_shifted := u32(((old_state>>18) ~ old_state) >> 27) xor_shifted := (((old_state >> 59) + 5) ~ old_state) * 12605985483714917081
rot := u32(old_state >> 59) rot := (old_state >> 59)
return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31)) return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 63))
} }
/* /*
@@ -187,7 +189,7 @@ Possible Output:
*/ */
@(require_results) @(require_results)
uint32 :: proc(r: ^Rand = nil) -> (val: u32) { return _random(r) } uint32 :: proc(r: ^Rand = nil) -> (val: u32) { return u32(_random_u64(r)) }
/* /*
Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
@@ -217,11 +219,7 @@ Possible Output:
*/ */
@(require_results) @(require_results)
uint64 :: proc(r: ^Rand = nil) -> (val: u64) { uint64 :: proc(r: ^Rand = nil) -> (val: u64) { return _random_u64(r) }
a := u64(_random(r))
b := u64(_random(r))
return (a<<32) | b
}
/* /*
Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
@@ -252,11 +250,9 @@ Possible Output:
*/ */
@(require_results) @(require_results)
uint128 :: proc(r: ^Rand = nil) -> (val: u128) { uint128 :: proc(r: ^Rand = nil) -> (val: u128) {
a := u128(_random(r)) a := u128(_random_u64(r))
b := u128(_random(r)) b := u128(_random_u64(r))
c := u128(_random(r)) return (a<<64) | b
d := u128(_random(r))
return (a<<96) | (b<<64) | (c<<32) | d
} }
/* /*
@@ -288,6 +284,7 @@ Possible Output:
*/ */
@(require_results) int31 :: proc(r: ^Rand = nil) -> (val: i32) { return i32(uint32(r) << 1 >> 1) } @(require_results) int31 :: proc(r: ^Rand = nil) -> (val: i32) { return i32(uint32(r) << 1 >> 1) }
/* /*
Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
The sign bit will always be set to 0, thus all generated numbers will be positive. The sign bit will always be set to 0, thus all generated numbers will be positive.
@@ -317,6 +314,7 @@ Possible Output:
*/ */
@(require_results) int63 :: proc(r: ^Rand = nil) -> (val: i64) { return i64(uint64(r) << 1 >> 1) } @(require_results) int63 :: proc(r: ^Rand = nil) -> (val: i64) { return i64(uint64(r) << 1 >> 1) }
/* /*
Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
The sign bit will always be set to 0, thus all generated numbers will be positive. The sign bit will always be set to 0, thus all generated numbers will be positive.
@@ -348,14 +346,14 @@ Possible Output:
@(require_results) int127 :: proc(r: ^Rand = nil) -> (val: i128) { return i128(uint128(r) << 1 >> 1) } @(require_results) int127 :: proc(r: ^Rand = nil) -> (val: i128) { return i128(uint128(r) << 1 >> 1) }
/* /*
Generates a random 31 bit value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random 31 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs: Inputs:
- n: The upper bound of the generated number, this value is exclusive - n: The upper bound of the generated number, this value is exclusive
- r: The random number generator to use, or nil for the global generator - r: The random number generator to use, or nil for the global generator
Returns: Returns:
- val: A random 31 bit value in the range `(0, n]` - val: A random 31 bit value in the range `[0, n)`
WARNING: Panics if n is less than 0 WARNING: Panics if n is less than 0
@@ -392,15 +390,16 @@ int31_max :: proc(n: i32, r: ^Rand = nil) -> (val: i32) {
} }
return v % n return v % n
} }
/* /*
Generates a random 63 bit value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random 63 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs: Inputs:
- n: The upper bound of the generated number, this value is exclusive - n: The upper bound of the generated number, this value is exclusive
- r: The random number generator to use, or nil for the global generator - r: The random number generator to use, or nil for the global generator
Returns: Returns:
- val: A random 63 bit value in the range `(0, n]` - val: A random 63 bit value in the range `[0, n)`
WARNING: Panics if n is less than 0 WARNING: Panics if n is less than 0
@@ -437,15 +436,16 @@ int63_max :: proc(n: i64, r: ^Rand = nil) -> (val: i64) {
} }
return v % n return v % n
} }
/* /*
Generates a random 127 bit value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random 127 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs: Inputs:
- n: The upper bound of the generated number, this value is exclusive - n: The upper bound of the generated number, this value is exclusive
- r: The random number generator to use, or nil for the global generator - r: The random number generator to use, or nil for the global generator
Returns: Returns:
- val: A random 127 bit value in the range `(0, n]` - val: A random 127 bit value in the range `[0, n)`
WARNING: Panics if n is less than 0 WARNING: Panics if n is less than 0
@@ -482,15 +482,16 @@ int127_max :: proc(n: i128, r: ^Rand = nil) -> (val: i128) {
} }
return v % n return v % n
} }
/* /*
Generates a random integer value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random integer value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs: Inputs:
- n: The upper bound of the generated number, this value is exclusive - n: The upper bound of the generated number, this value is exclusive
- r: The random number generator to use, or nil for the global generator - r: The random number generator to use, or nil for the global generator
Returns: Returns:
- val: A random integer value in the range `(0, n]` - val: A random integer value in the range `[0, n)`
WARNING: Panics if n is less than 0 WARNING: Panics if n is less than 0
@@ -525,13 +526,13 @@ int_max :: proc(n: int, r: ^Rand = nil) -> (val: int) {
} }
/* /*
Generates a random double floating point value in the range `(0, 1]` using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random double floating point value in the range `[0, 1)` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs: Inputs:
- r: The random number generator to use, or nil for the global generator - r: The random number generator to use, or nil for the global generator
Returns: Returns:
- val: A random double floating point value in the range `(0, 1]` - val: A random double floating point value in the range `[0, 1)`
Example: Example:
import "core:math/rand" import "core:math/rand"
@@ -554,13 +555,13 @@ Possible Output:
@(require_results) float64 :: proc(r: ^Rand = nil) -> (val: f64) { return f64(int63_max(1<<53, r)) / (1 << 53) } @(require_results) float64 :: proc(r: ^Rand = nil) -> (val: f64) { return f64(int63_max(1<<53, r)) / (1 << 53) }
/* /*
Generates a random single floating point value in the range `(0, 1]` using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random single floating point value in the range `[0, 1)` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs: Inputs:
- r: The random number generator to use, or nil for the global generator - r: The random number generator to use, or nil for the global generator
Returns: Returns:
- val: A random single floating point value in the range `(0, 1]` - val: A random single floating point value in the range `[0, 1)`
Example: Example:
import "core:math/rand" import "core:math/rand"
@@ -580,10 +581,12 @@ Possible Output:
0.511 0.511
*/ */
@(require_results) float32 :: proc(r: ^Rand = nil) -> (val: f32) { return f32(float64(r)) } @(require_results) float32 :: proc(r: ^Rand = nil) -> (val: f32) { return f32(int31_max(1<<24, r)) / (1 << 24) }
/* /*
Generates a random double floating point value in the range `(low, high]` using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random double floating point value in the range `[low, high)` using the provided random number generator. If no generator is provided the global random number generator will be used.
WARNING: Panics if `high < low`
Inputs: Inputs:
- low: The lower bounds of the value, this value is inclusive - low: The lower bounds of the value, this value is inclusive
@@ -591,7 +594,7 @@ Inputs:
- r: The random number generator to use, or nil for the global generator - r: The random number generator to use, or nil for the global generator
Returns: Returns:
- val: A random double floating point value in the range `(low, high]` - val: A random double floating point value in the range [low, high)
Example: Example:
import "core:math/rand" import "core:math/rand"
@@ -611,9 +614,17 @@ Possible Output:
673.130 673.130
*/ */
@(require_results) float64_range :: proc(low, high: f64, r: ^Rand = nil) -> (val: f64) { return (high-low)*float64(r) + low } @(require_results) float64_range :: proc(low, high: f64, r: ^Rand = nil) -> (val: f64) {
assert(low <= high, "low must be lower than or equal to high")
val = (high-low)*float64(r) + low
if val >= high {
val = max(low, high * (1 - math.F64_EPSILON))
}
return
}
/* /*
Generates a random single floating point value in the range `(low, high]` using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random single floating point value in the range `[low, high)` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs: Inputs:
- low: The lower bounds of the value, this value is inclusive - low: The lower bounds of the value, this value is inclusive
@@ -621,7 +632,9 @@ Inputs:
- r: The random number generator to use, or nil for the global generator - r: The random number generator to use, or nil for the global generator
Returns: Returns:
- val: A random single floating point value in the range `(low, high]` - val: A random single floating point value in the range [low, high)
WARNING: Panics if `high < low`
Example: Example:
import "core:math/rand" import "core:math/rand"
@@ -641,10 +654,18 @@ Possible Output:
673.130 673.130
*/ */
@(require_results) float32_range :: proc(low, high: f32, r: ^Rand = nil) -> (val: f32) { return (high-low)*float32(r) + low } @(require_results) float32_range :: proc(low, high: f32, r: ^Rand = nil) -> (val: f32) {
assert(low <= high, "low must be lower than or equal to high")
val = (high-low)*float32(r) + low
if val >= high {
val = max(low, high * (1 - math.F32_EPSILON))
}
return
}
/* /*
Fills a byte slice with random values using the provided random number generator. If no generator is provided the global random number generator will be used. Fills a byte slice with random values using the provided random number generator. If no generator is provided the global random number generator will be used.
Due to floating point precision there is no guarantee if the upper and lower bounds are inclusive/exclusive with the exact floating point value.
Inputs: Inputs:
- p: The byte slice to fill - p: The byte slice to fill
@@ -797,7 +818,6 @@ Example:
fmt.println(rand.choice(data[:])) fmt.println(rand.choice(data[:]))
} }
Possible Output: Possible Output:
3 3
+3 -3
View File
@@ -3,10 +3,10 @@ package rand
import "core:sys/darwin" import "core:sys/darwin"
@(require_results) @(require_results)
_system_random :: proc() -> u32 { _system_random :: proc() -> u64 {
for { for {
value: u32 value: u64
ret := darwin.syscall_getentropy(([^]u8)(&value), 4) ret := darwin.syscall_getentropy(([^]u8)(&value), size_of(value))
if ret < 0 { if ret < 0 {
switch ret { switch ret {
case -4: // EINTR case -4: // EINTR
+3 -3
View File
@@ -3,10 +3,10 @@ package rand
import "core:sys/unix" import "core:sys/unix"
@(require_results) @(require_results)
_system_random :: proc() -> u32 { _system_random :: proc() -> u64 {
for { for {
value: u32 value: u64
ret := unix.sys_getrandom(([^]u8)(&value), 4, 0) ret := unix.sys_getrandom(([^]u8)(&value), size_of(value), 0)
if ret < 0 { if ret < 0 {
switch ret { switch ret {
case -4: // EINTR case -4: // EINTR
+3 -3
View File
@@ -3,9 +3,9 @@ package rand
import win32 "core:sys/windows" import win32 "core:sys/windows"
@(require_results) @(require_results)
_system_random :: proc() -> u32 { _system_random :: proc() -> u64 {
value: u32 value: u64
status := win32.BCryptGenRandom(nil, ([^]u8)(&value), 4, win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG) status := win32.BCryptGenRandom(nil, ([^]u8)(&value), size_of(value), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)
if status < 0 { if status < 0 {
panic("BCryptGenRandom failed") panic("BCryptGenRandom failed")
} }
+1
View File
@@ -749,6 +749,7 @@ dynamic_pool_alloc_bytes :: proc(p: ^Dynamic_Pool, bytes: int) -> ([]byte, Alloc
n := bytes n := bytes
extra := p.alignment - (n % p.alignment) extra := p.alignment - (n % p.alignment)
n += extra n += extra
if n > p.block_size do return nil, .Invalid_Argument
if n >= p.out_band_size { if n >= p.out_band_size {
assert(p.block_allocator.procedure != nil) assert(p.block_allocator.procedure != nil)
memory, err := p.block_allocator.procedure(p.block_allocator.data, Allocator_Mode.Alloc, memory, err := p.block_allocator.procedure(p.block_allocator.data, Allocator_Mode.Alloc,
+1 -1
View File
@@ -24,7 +24,7 @@ main :: proc() {
_main() _main()
for _, leak in track.allocation_map { for _, leak in track.allocation_map {
fmt.printf("%v leaked %v bytes\n", leak.location, leak.size) fmt.printf("%v leaked %m\n", leak.location, leak.size)
} }
for bad_free in track.bad_free_array { for bad_free in track.bad_free_array {
fmt.printf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory) fmt.printf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory)
+2
View File
@@ -8,6 +8,8 @@ Kilobyte :: runtime.Kilobyte
Megabyte :: runtime.Megabyte Megabyte :: runtime.Megabyte
Gigabyte :: runtime.Gigabyte Gigabyte :: runtime.Gigabyte
Terabyte :: runtime.Terabyte Terabyte :: runtime.Terabyte
Petabyte :: runtime.Petabyte
Exabyte :: runtime.Exabyte
set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr { set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr {
return runtime.memset(data, i32(value), len) return runtime.memset(data, i32(value), len)
+1 -1
View File
@@ -133,7 +133,7 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
return return
} }
// Resets the memory of a Static or Buffer arena to a specific `pos`ition (offset) and zeroes the previously used memory. // Resets the memory of a Static or Buffer arena to a specific `position` (offset) and zeroes the previously used memory.
arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool { arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool {
sync.mutex_guard(&arena.mutex) sync.mutex_guard(&arena.mutex)
+25 -10
View File
@@ -2,6 +2,8 @@ package mem_virtual
import "core:mem" import "core:mem"
import "core:intrinsics" import "core:intrinsics"
import "core:runtime"
_ :: runtime
DEFAULT_PAGE_SIZE := uint(4096) DEFAULT_PAGE_SIZE := uint(4096)
@@ -59,16 +61,22 @@ Memory_Block_Flag :: enum u32 {
Memory_Block_Flags :: distinct bit_set[Memory_Block_Flag; u32] Memory_Block_Flags :: distinct bit_set[Memory_Block_Flag; u32]
@(private="file", require_results)
align_formula :: #force_inline proc "contextless" (size, align: uint) -> uint {
result := size + align-1
return result - result%align
}
@(require_results) @(require_results)
memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags) -> (block: ^Memory_Block, err: Allocator_Error) { memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags) -> (block: ^Memory_Block, err: Allocator_Error) {
align_formula :: proc "contextless" (size, align: uint) -> uint {
result := size + align-1
return result - result%align
}
page_size := DEFAULT_PAGE_SIZE page_size := DEFAULT_PAGE_SIZE
assert(mem.is_power_of_two(uintptr(page_size))) assert(mem.is_power_of_two(uintptr(page_size)))
committed := committed committed := committed
reserved := reserved
committed = align_formula(committed, page_size)
reserved = align_formula(reserved, page_size)
committed = clamp(committed, 0, reserved) committed = clamp(committed, 0, reserved)
total_size := uint(reserved + size_of(Platform_Memory_Block)) total_size := uint(reserved + size_of(Platform_Memory_Block))
@@ -77,7 +85,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
do_protection := false do_protection := false
if .Overflow_Protection in flags { // overflow protection if .Overflow_Protection in flags { // overflow protection
rounded_size := align_formula(uint(reserved), page_size) rounded_size := reserved
total_size = uint(rounded_size + 2*page_size) total_size = uint(rounded_size + 2*page_size)
base_offset = uintptr(page_size + rounded_size - uint(reserved)) base_offset = uintptr(page_size + rounded_size - uint(reserved))
protect_offset = uintptr(page_size + rounded_size) protect_offset = uintptr(page_size + rounded_size)
@@ -86,14 +94,14 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
pmblock := platform_memory_alloc(0, total_size) or_return pmblock := platform_memory_alloc(0, total_size) or_return
pmblock.block.base = ([^]byte)(uintptr(pmblock) + base_offset) pmblock.block.base = ([^]byte)(pmblock)[base_offset:]
platform_memory_commit(pmblock, uint(base_offset) + committed) or_return platform_memory_commit(pmblock, uint(base_offset) + committed) or_return
// Should be zeroed // Should be zeroed
assert(pmblock.block.used == 0) assert(pmblock.block.used == 0)
assert(pmblock.block.prev == nil) assert(pmblock.block.prev == nil)
if do_protection { if do_protection {
protect(rawptr(uintptr(pmblock) + protect_offset), page_size, Protect_No_Access) protect(([^]byte)(pmblock)[protect_offset:], page_size, Protect_No_Access)
} }
pmblock.block.committed = committed pmblock.block.committed = committed
@@ -119,7 +127,13 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint)
if block.committed - block.used < size { if block.committed - block.used < size {
pmblock := (^Platform_Memory_Block)(block) pmblock := (^Platform_Memory_Block)(block)
base_offset := uint(uintptr(pmblock.block.base) - uintptr(pmblock)) base_offset := uint(uintptr(pmblock.block.base) - uintptr(pmblock))
platform_total_commit := base_offset + block.used + size
// NOTE(bill): [Heuristic] grow the commit size larger than needed
// TODO(bill): determine a better heuristic for this behaviour
extra_size := max(size, block.committed>>1)
platform_total_commit := base_offset + block.used + extra_size
platform_total_commit = align_formula(platform_total_commit, DEFAULT_PAGE_SIZE)
platform_total_commit = min(platform_total_commit, pmblock.reserved)
assert(pmblock.committed <= pmblock.reserved) assert(pmblock.committed <= pmblock.reserved)
assert(pmblock.committed < platform_total_commit) assert(pmblock.committed < platform_total_commit)
@@ -128,8 +142,9 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint)
pmblock.committed = platform_total_commit pmblock.committed = platform_total_commit
block.committed = pmblock.committed - base_offset block.committed = pmblock.committed - base_offset
} }
return nil return
} }
if block == nil { if block == nil {
+3 -3
View File
@@ -471,7 +471,7 @@ join_port :: proc(address_or_host: string, port: int, allocator := context.alloc
// hostname // hostname
fmt.sbprintf(&b, "%v:%v", addr_or_host, port) fmt.sbprintf(&b, "%v:%v", addr_or_host, port)
} else { } else {
switch in addr { switch _ in addr {
case IP4_Address: case IP4_Address:
fmt.sbprintf(&b, "%v:%v", address_to_string(addr), port) fmt.sbprintf(&b, "%v:%v", address_to_string(addr), port)
case IP6_Address: case IP6_Address:
@@ -587,7 +587,7 @@ address_to_string :: proc(addr: Address, allocator := context.temp_allocator) ->
} }
// Returns a temporarily-allocated string representation of the endpoint. // Returns a temporarily-allocated string representation of the endpoint.
// If there's a port, uses the `[address]:port` format. // If there's a port, uses the `ip4address:port` or `[ip6address]:port` format, respectively.
endpoint_to_string :: proc(ep: Endpoint, allocator := context.temp_allocator) -> string { endpoint_to_string :: proc(ep: Endpoint, allocator := context.temp_allocator) -> string {
if ep.port == 0 { if ep.port == 0 {
return address_to_string(ep.address, allocator) return address_to_string(ep.address, allocator)
@@ -606,7 +606,7 @@ to_string :: proc{address_to_string, endpoint_to_string}
family_from_address :: proc(addr: Address) -> Address_Family { family_from_address :: proc(addr: Address) -> Address_Family {
switch in addr { switch _ in addr {
case IP4_Address: return .IP4 case IP4_Address: return .IP4
case IP6_Address: return .IP6 case IP6_Address: return .IP6
case: case:
+20 -32
View File
@@ -96,7 +96,7 @@ resolve :: proc(hostname_and_maybe_port: string) -> (ep4, ep6: Endpoint, err: Ne
switch t in target { switch t in target {
case Endpoint: case Endpoint:
// NOTE(tetra): The hostname was actually an IP address; nothing to resolve, so just return it. // NOTE(tetra): The hostname was actually an IP address; nothing to resolve, so just return it.
switch in t.address { switch _ in t.address {
case IP4_Address: ep4 = t case IP4_Address: ep4 = t
case IP6_Address: ep6 = t case IP6_Address: ep6 = t
case: unreachable() case: unreachable()
@@ -122,7 +122,7 @@ resolve_ip4 :: proc(hostname_and_maybe_port: string) -> (ep4: Endpoint, err: Net
switch t in target { switch t in target {
case Endpoint: case Endpoint:
// NOTE(tetra): The hostname was actually an IP address; nothing to resolve, so just return it. // NOTE(tetra): The hostname was actually an IP address; nothing to resolve, so just return it.
switch in t.address { switch _ in t.address {
case IP4_Address: case IP4_Address:
return t, nil return t, nil
case IP6_Address: case IP6_Address:
@@ -149,7 +149,7 @@ resolve_ip6 :: proc(hostname_and_maybe_port: string) -> (ep6: Endpoint, err: Net
switch t in target { switch t in target {
case Endpoint: case Endpoint:
// NOTE(tetra): The hostname was actually an IP address; nothing to resolve, so just return it. // NOTE(tetra): The hostname was actually an IP address; nothing to resolve, so just return it.
switch in t.address { switch _ in t.address {
case IP4_Address: case IP4_Address:
err = .Unable_To_Resolve err = .Unable_To_Resolve
return return
@@ -247,23 +247,19 @@ get_dns_records_from_nameservers :: proc(hostname: string, type: DNS_Record_Type
} }
defer close(conn) defer close(conn)
_, send_err := send(conn, dns_packet[:], name_server) _ = send(conn, dns_packet[:], name_server) or_continue
if send_err != nil {
continue
}
set_err := set_option(conn, .Receive_Timeout, time.Second * 1) if set_option(conn, .Receive_Timeout, time.Second * 1) != nil {
if set_err != nil {
return nil, .Connection_Error return nil, .Connection_Error
} }
recv_sz, _, recv_err := recv_udp(conn, dns_response_buf[:]) // recv_sz, _, recv_err := recv_udp(conn, dns_response_buf[:])
if recv_err == UDP_Recv_Error.Timeout { // if recv_err == UDP_Recv_Error.Timeout {
continue // continue
} else if recv_err != nil { // } else if recv_err != nil {
continue // continue
} // }
recv_sz, _ := recv_udp(conn, dns_response_buf[:]) or_continue
if recv_sz == 0 { if recv_sz == 0 {
continue continue
} }
@@ -429,11 +425,9 @@ load_hosts :: proc(hosts_file_path: string, allocator := context.allocator) -> (
} }
for hostname in splits[1:] { for hostname in splits[1:] {
if len(hostname) == 0 { if len(hostname) != 0 {
continue append(&_hosts, DNS_Host_Entry{hostname, addr})
} }
append(&_hosts, DNS_Host_Entry{hostname, addr})
} }
} }
@@ -833,11 +827,9 @@ parse_response :: proc(response: []u8, filter: DNS_Record_Type = nil, allocator
} }
rec := parse_record(response, &cur_idx, filter) or_return rec := parse_record(response, &cur_idx, filter) or_return
if rec == nil { if rec != nil {
continue append(&_records, rec)
} }
append(&_records, rec)
} }
for _ in 0..<authority_count { for _ in 0..<authority_count {
@@ -846,11 +838,9 @@ parse_response :: proc(response: []u8, filter: DNS_Record_Type = nil, allocator
} }
rec := parse_record(response, &cur_idx, filter) or_return rec := parse_record(response, &cur_idx, filter) or_return
if rec == nil { if rec != nil {
continue append(&_records, rec)
} }
append(&_records, rec)
} }
for _ in 0..<additional_count { for _ in 0..<additional_count {
@@ -859,11 +849,9 @@ parse_response :: proc(response: []u8, filter: DNS_Record_Type = nil, allocator
} }
rec := parse_record(response, &cur_idx, filter) or_return rec := parse_record(response, &cur_idx, filter) or_return
if rec == nil { if rec != nil {
continue append(&_records, rec)
} }
append(&_records, rec)
} }
return _records[:], true return _records[:], true
+10 -3
View File
@@ -45,15 +45,22 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator :
count := 0 count := 0
for r := rec; r != nil; r = r.pNext { for r := rec; r != nil; r = r.pNext {
if r.wType != u16(type) do continue // NOTE(tetra): Should never happen, but... if r.wType != u16(type) {
// NOTE(tetra): Should never happen, but...
continue
}
count += 1 count += 1
} }
recs := make([dynamic]DNS_Record, 0, count) recs := make([dynamic]DNS_Record, 0, count)
if recs == nil do return nil, .System_Error // return no results if OOM. if recs == nil {
return nil, .System_Error // return no results if OOM.
}
for r := rec; r != nil; r = r.pNext { for r := rec; r != nil; r = r.pNext {
if r.wType != u16(type) do continue // NOTE(tetra): Should never happen, but... if r.wType != u16(type) {
continue // NOTE(tetra): Should never happen, but...
}
base_record := DNS_Record_Base{ base_record := DNS_Record_Base{
record_name = strings.clone(string(r.pName)), record_name = strings.clone(string(r.pName)),
+7 -9
View File
@@ -109,12 +109,12 @@ TCP_Recv_Error :: enum c.int {
} }
UDP_Recv_Error :: enum c.int { UDP_Recv_Error :: enum c.int {
None = 0, None = 0,
Truncated = c.int(os.EMSGSIZE), // The buffer is too small to fit the entire message, and the message was truncated. Buffer_Too_Small = c.int(os.EMSGSIZE), // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost.
Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket. Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket.
Not_Descriptor = c.int(os.EBADF), // The so-called socket is, in fact, not even a valid descriptor. Not_Descriptor = c.int(os.EBADF), // The so-called socket is, in fact, not even a valid descriptor.
Bad_Buffer = c.int(os.EFAULT), // The buffer did not point to a valid location in memory. Bad_Buffer = c.int(os.EFAULT), // The buffer did not point to a valid location in memory.
Interrupted = c.int(os.EINTR), // A signal occurred before any data was transmitted. See signal(7). Interrupted = c.int(os.EINTR), // A signal occurred before any data was transmitted. See signal(7).
// The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout. // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout.
// NOTE: No, really. Presumably this means something different for nonblocking sockets... // NOTE: No, really. Presumably this means something different for nonblocking sockets...
@@ -122,11 +122,9 @@ UDP_Recv_Error :: enum c.int {
Socket_Not_Bound = c.int(os.EINVAL), // The socket must be bound for this operation, but isn't. Socket_Not_Bound = c.int(os.EINVAL), // The socket must be bound for this operation, but isn't.
} }
// TODO
TCP_Send_Error :: enum c.int { TCP_Send_Error :: enum c.int {
None = 0, None = 0,
// TODO: merge with other errors?
Aborted = c.int(os.ECONNABORTED), Aborted = c.int(os.ECONNABORTED),
Connection_Closed = c.int(os.ECONNRESET), Connection_Closed = c.int(os.ECONNRESET),
Not_Connected = c.int(os.ENOTCONN), Not_Connected = c.int(os.ENOTCONN),
@@ -151,7 +149,7 @@ TCP_Send_Error :: enum c.int {
// TODO // TODO
UDP_Send_Error :: enum c.int { UDP_Send_Error :: enum c.int {
None = 0, None = 0,
Truncated = c.int(os.EMSGSIZE), // The message is too big. No data was sent. Message_Too_Long = c.int(os.EMSGSIZE), // The message is larger than the maximum UDP packet size. No data was sent.
// TODO: not sure what the exact circumstances for this is yet // TODO: not sure what the exact circumstances for this is yet
Network_Unreachable = c.int(os.ENETUNREACH), Network_Unreachable = c.int(os.ENETUNREACH),
+5 -9
View File
@@ -105,9 +105,7 @@ TCP_Recv_Error :: enum c.int {
UDP_Recv_Error :: enum c.int { UDP_Recv_Error :: enum c.int {
None = 0, None = 0,
// The buffer is too small to fit the entire message, and the message was truncated. Buffer_Too_Small = c.int(os.EMSGSIZE), // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost.
// When this happens, the rest of message is lost.
Buffer_Too_Small = c.int(os.EMSGSIZE),
Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket. Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket.
Not_Descriptor = c.int(os.EBADF), // The so-called socket is, in fact, not even a valid descriptor. Not_Descriptor = c.int(os.EBADF), // The so-called socket is, in fact, not even a valid descriptor.
Bad_Buffer = c.int(os.EFAULT), // The buffer did not point to a valid location in memory. Bad_Buffer = c.int(os.EFAULT), // The buffer did not point to a valid location in memory.
@@ -119,10 +117,8 @@ UDP_Recv_Error :: enum c.int {
Socket_Not_Bound = c.int(os.EINVAL), // The socket must be bound for this operation, but isn't. Socket_Not_Bound = c.int(os.EINVAL), // The socket must be bound for this operation, but isn't.
} }
// TODO
TCP_Send_Error :: enum c.int { TCP_Send_Error :: enum c.int {
None = 0, None = 0,
// TODO(tetra): merge with other errors?
Aborted = c.int(os.ECONNABORTED), Aborted = c.int(os.ECONNABORTED),
Connection_Closed = c.int(os.ECONNRESET), Connection_Closed = c.int(os.ECONNRESET),
Not_Connected = c.int(os.ENOTCONN), Not_Connected = c.int(os.ENOTCONN),
@@ -135,16 +131,16 @@ TCP_Send_Error :: enum c.int {
// doesn't fit in the send queue. // doesn't fit in the send queue.
No_Buffer_Space_Available = c.int(os.ENOBUFS), No_Buffer_Space_Available = c.int(os.ENOBUFS),
Offline = c.int(os.ENETDOWN), Offline = c.int(os.ENETDOWN),
Host_Unreachable = c.int(os.EHOSTUNREACH), // A signal occurred before any data was transmitted. See signal(7). Host_Unreachable = c.int(os.EHOSTUNREACH),
Interrupted = c.int(os.EINTR), // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout. Interrupted = c.int(os.EINTR), // A signal occurred before any data was transmitted. See signal(7).
Timeout = c.int(os.EWOULDBLOCK), // NOTE: No, really. Presumably this means something different for nonblocking sockets... Timeout = c.int(os.EWOULDBLOCK), // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout.
Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket. Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket.
} }
// TODO // TODO
UDP_Send_Error :: enum c.int { UDP_Send_Error :: enum c.int {
None = 0, None = 0,
Message_Too_Long = c.int(os.EMSGSIZE), // The message is too big. No data was sent. Message_Too_Long = c.int(os.EMSGSIZE), // The message is larger than the maximum UDP packet size. No data was sent.
// TODO: not sure what the exact circumstances for this is yet // TODO: not sure what the exact circumstances for this is yet
Network_Unreachable = c.int(os.ENETUNREACH), Network_Unreachable = c.int(os.ENETUNREACH),
+5 -12
View File
@@ -92,8 +92,6 @@ TCP_Recv_Error :: enum c.int {
Not_Socket = win.WSAENOTSOCK, Not_Socket = win.WSAENOTSOCK,
Shutdown = win.WSAESHUTDOWN, Shutdown = win.WSAESHUTDOWN,
Would_Block = win.WSAEWOULDBLOCK, Would_Block = win.WSAEWOULDBLOCK,
// TODO: not functionally different from Reset; merge?
Aborted = win.WSAECONNABORTED, Aborted = win.WSAECONNABORTED,
Timeout = win.WSAETIMEDOUT, Timeout = win.WSAETIMEDOUT,
@@ -107,11 +105,8 @@ TCP_Recv_Error :: enum c.int {
UDP_Recv_Error :: enum c.int { UDP_Recv_Error :: enum c.int {
None = 0, None = 0,
Network_Subsystem_Failure = win.WSAENETDOWN, Network_Subsystem_Failure = win.WSAENETDOWN,
Aborted = win.WSAECONNABORTED,
// TODO: not functionally different from Reset; merge? Buffer_Too_Small = win.WSAEMSGSIZE, // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost.
// UDP packets are limited in size, and the length of the incoming message exceeded it.
Aborted = win.WSAECONNABORTED,
Truncated = win.WSAEMSGSIZE,
Remote_Not_Listening = win.WSAECONNRESET, // The machine at the remote endpoint doesn't have the given port open to receiving UDP data. Remote_Not_Listening = win.WSAECONNRESET, // The machine at the remote endpoint doesn't have the given port open to receiving UDP data.
Shutdown = win.WSAESHUTDOWN, Shutdown = win.WSAESHUTDOWN,
Broadcast_Disabled = win.WSAEACCES, // A broadcast address was specified, but the .Broadcast socket option isn't set. Broadcast_Disabled = win.WSAEACCES, // A broadcast address was specified, but the .Broadcast socket option isn't set.
@@ -133,7 +128,6 @@ UDP_Recv_Error :: enum c.int {
TCP_Send_Error :: enum c.int { TCP_Send_Error :: enum c.int {
None = 0, None = 0,
// TODO: not functionally different from Reset; merge?
Aborted = win.WSAECONNABORTED, Aborted = win.WSAECONNABORTED,
Not_Connected = win.WSAENOTCONN, Not_Connected = win.WSAENOTCONN,
Shutdown = win.WSAESHUTDOWN, Shutdown = win.WSAESHUTDOWN,
@@ -159,10 +153,9 @@ UDP_Send_Error :: enum c.int {
None = 0, None = 0,
Network_Subsystem_Failure = win.WSAENETDOWN, Network_Subsystem_Failure = win.WSAENETDOWN,
// TODO: not functionally different from Reset; merge? Aborted = win.WSAECONNABORTED,
Aborted = win.WSAECONNABORTED, // UDP packets are limited in size, and len(buf) exceeded it. Message_Too_Long = win.WSAEMSGSIZE, // The message is larger than the maximum UDP packet size.
Message_Too_Long = win.WSAEMSGSIZE, // The machine at the remote endpoint doesn't have the given port open to receiving UDP data. Remote_Not_Listening = win.WSAECONNRESET, // The machine at the remote endpoint doesn't have the given port open to receiving UDP data.
Remote_Not_Listening = win.WSAECONNRESET,
Shutdown = win.WSAESHUTDOWN, // A broadcast address was specified, but the .Broadcast socket option isn't set. Shutdown = win.WSAESHUTDOWN, // A broadcast address was specified, but the .Broadcast socket option isn't set.
Broadcast_Disabled = win.WSAEACCES, Broadcast_Disabled = win.WSAEACCES,
Bad_Buffer = win.WSAEFAULT, // Connection is broken due to keepalive activity detecting a failure during the operation. Bad_Buffer = win.WSAEFAULT, // Connection is broken due to keepalive activity detecting a failure during the operation.
+39 -5
View File
@@ -284,6 +284,13 @@ Or_Return_Expr :: struct {
token: tokenizer.Token, token: tokenizer.Token,
} }
Or_Branch_Expr :: struct {
using node: Expr,
expr: ^Expr,
token: tokenizer.Token,
label: ^Expr,
}
Type_Assertion :: struct { Type_Assertion :: struct {
using node: Expr, using node: Expr,
expr: ^Expr, expr: ^Expr,
@@ -419,6 +426,7 @@ Range_Stmt :: struct {
in_pos: tokenizer.Pos, in_pos: tokenizer.Pos,
expr: ^Expr, expr: ^Expr,
body: ^Stmt, body: ^Stmt,
reverse: bool,
} }
Inline_Range_Stmt :: struct { Inline_Range_Stmt :: struct {
@@ -543,8 +551,8 @@ unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
return return
} }
for { for {
e, ok := val.derived.(^Paren_Expr) e := val.derived.(^Paren_Expr) or_break
if !ok || e.expr == nil { if e.expr == nil {
break break
} }
val = e.expr val = e.expr
@@ -552,6 +560,29 @@ unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
return return
} }
strip_or_return_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
val = expr
if expr == nil {
return
}
for {
inner: ^Expr
#partial switch e in val.derived {
case ^Or_Return_Expr:
inner = e.expr
case ^Or_Branch_Expr:
inner = e.expr
case ^Paren_Expr:
inner = e.expr
}
if inner == nil {
break
}
val = inner
}
return
}
Field_Flags :: distinct bit_set[Field_Flag] Field_Flags :: distinct bit_set[Field_Flag]
Field_Flag :: enum { Field_Flag :: enum {
@@ -562,7 +593,7 @@ Field_Flag :: enum {
Using, Using,
No_Alias, No_Alias,
C_Vararg, C_Vararg,
Auto_Cast, Const,
Any_Int, Any_Int,
Subtype, Subtype,
By_Ptr, By_Ptr,
@@ -581,7 +612,7 @@ field_flag_strings := [Field_Flag]string{
.Using = "using", .Using = "using",
.No_Alias = "#no_alias", .No_Alias = "#no_alias",
.C_Vararg = "#c_vararg", .C_Vararg = "#c_vararg",
.Auto_Cast = "auto_cast", .Const = "#const",
.Any_Int = "#any_int", .Any_Int = "#any_int",
.Subtype = "#subtype", .Subtype = "#subtype",
.By_Ptr = "#by_ptr", .By_Ptr = "#by_ptr",
@@ -595,6 +626,7 @@ field_flag_strings := [Field_Flag]string{
field_hash_flag_strings := []struct{key: string, flag: Field_Flag}{ field_hash_flag_strings := []struct{key: string, flag: Field_Flag}{
{"no_alias", .No_Alias}, {"no_alias", .No_Alias},
{"c_vararg", .C_Vararg}, {"c_vararg", .C_Vararg},
{"const", .Const},
{"any_int", .Any_Int}, {"any_int", .Any_Int},
{"subtype", .Subtype}, {"subtype", .Subtype},
{"by_ptr", .By_Ptr}, {"by_ptr", .By_Ptr},
@@ -615,7 +647,7 @@ Field_Flags_Signature :: Field_Flags{
.Using, .Using,
.No_Alias, .No_Alias,
.C_Vararg, .C_Vararg,
.Auto_Cast, .Const,
.Any_Int, .Any_Int,
.By_Ptr, .By_Ptr,
.Default_Parameters, .Default_Parameters,
@@ -837,6 +869,7 @@ Any_Node :: union {
^Ternary_When_Expr, ^Ternary_When_Expr,
^Or_Else_Expr, ^Or_Else_Expr,
^Or_Return_Expr, ^Or_Return_Expr,
^Or_Branch_Expr,
^Type_Assertion, ^Type_Assertion,
^Type_Cast, ^Type_Cast,
^Auto_Cast, ^Auto_Cast,
@@ -920,6 +953,7 @@ Any_Expr :: union {
^Ternary_When_Expr, ^Ternary_When_Expr,
^Or_Else_Expr, ^Or_Else_Expr,
^Or_Return_Expr, ^Or_Return_Expr,
^Or_Branch_Expr,
^Type_Assertion, ^Type_Assertion,
^Type_Cast, ^Type_Cast,
^Auto_Cast, ^Auto_Cast,
+6 -3
View File
@@ -77,7 +77,7 @@ clone_node :: proc(node: ^Node) -> ^Node {
align = elem.align align = elem.align
} }
#partial switch in node.derived { #partial switch _ in node.derived {
case ^Package, ^File: case ^Package, ^File:
panic("Cannot clone this node type") panic("Cannot clone this node type")
} }
@@ -147,8 +147,8 @@ clone_node :: proc(node: ^Node) -> ^Node {
r.expr = clone(r.expr) r.expr = clone(r.expr)
r.index = clone(r.index) r.index = clone(r.index)
case ^Matrix_Index_Expr: case ^Matrix_Index_Expr:
r.expr = clone(r.expr) r.expr = clone(r.expr)
r.row_index = clone(r.row_index) r.row_index = clone(r.row_index)
r.column_index = clone(r.column_index) r.column_index = clone(r.column_index)
case ^Deref_Expr: case ^Deref_Expr:
r.expr = clone(r.expr) r.expr = clone(r.expr)
@@ -175,6 +175,9 @@ clone_node :: proc(node: ^Node) -> ^Node {
r.y = clone(r.y) r.y = clone(r.y)
case ^Or_Return_Expr: case ^Or_Return_Expr:
r.expr = clone(r.expr) r.expr = clone(r.expr)
case ^Or_Branch_Expr:
r.expr = clone(r.expr)
r.label = clone(r.label)
case ^Type_Assertion: case ^Type_Assertion:
r.expr = clone(r.expr) r.expr = clone(r.expr)
r.type = clone(r.type) r.type = clone(r.type)
+5
View File
@@ -146,6 +146,11 @@ walk :: proc(v: ^Visitor, node: ^Node) {
walk(v, n.y) walk(v, n.y)
case ^Or_Return_Expr: case ^Or_Return_Expr:
walk(v, n.expr) walk(v, n.expr)
case ^Or_Branch_Expr:
walk(v, n.expr)
if n.label != nil {
walk(v, n.label)
}
case ^Type_Assertion: case ^Type_Assertion:
walk(v, n.expr) walk(v, n.expr)
if n.type != nil { if n.type != nil {
+25 -25
View File
@@ -162,31 +162,31 @@ Attribute :: struct {
} }
Type_Kind :: enum u32le { Type_Kind :: enum u32le {
Invalid = 0, Invalid = 0,
Basic = 1, Basic = 1,
Named = 2, Named = 2,
Generic = 3, Generic = 3,
Pointer = 4, Pointer = 4,
Array = 5, Array = 5,
Enumerated_Array = 6, Enumerated_Array = 6,
Slice = 7, Slice = 7,
Dynamic_Array = 8, Dynamic_Array = 8,
Map = 9, Map = 9,
Struct = 10, Struct = 10,
Union = 11, Union = 11,
Enum = 12, Enum = 12,
Tuple = 13, Tuple = 13,
Proc = 14, Proc = 14,
Bit_Set = 15, Bit_Set = 15,
Simd_Vector = 16, Simd_Vector = 16,
SOA_Struct_Fixed = 17, SOA_Struct_Fixed = 17,
SOA_Struct_Slice = 18, SOA_Struct_Slice = 18,
SOA_Struct_Dynamic = 19, SOA_Struct_Dynamic = 19,
Relative_Pointer = 20, Relative_Pointer = 20,
Relative_Slice = 21, Relative_Multi_Pointer = 21,
Multi_Pointer = 22, Multi_Pointer = 22,
Matrix = 23, Matrix = 23,
Soa_Pointer = 24, Soa_Pointer = 24,
} }
Type_Elems_Cap :: 4 Type_Elems_Cap :: 4
+50 -33
View File
@@ -420,7 +420,7 @@ expect_closing_brace_of_field_list :: proc(p: ^Parser) -> tokenizer.Token {
if allow_token(p, .Close_Brace) { if allow_token(p, .Close_Brace) {
return token return token
} }
if allow_token(p, .Semicolon) { if allow_token(p, .Semicolon) && !tokenizer.is_newline(token) {
str := tokenizer.token_to_string(token) str := tokenizer.token_to_string(token)
error(p, end_of_line_pos(p, p.prev_tok), "expected a comma, got %s", str) error(p, end_of_line_pos(p, p.prev_tok), "expected a comma, got %s", str)
} }
@@ -1053,9 +1053,7 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind:
} }
append(&elems, elem) append(&elems, elem)
if !allow_token(p, .Comma) { allow_token(p, .Comma) or_break
break
}
} }
p.expr_level -= 1 p.expr_level -= 1
close = expect_token_after(p, close_kind, "attribute") close = expect_token_after(p, close_kind, "attribute")
@@ -1091,7 +1089,7 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind:
parse_foreign_block_decl :: proc(p: ^Parser) -> ^ast.Stmt { parse_foreign_block_decl :: proc(p: ^Parser) -> ^ast.Stmt {
decl := parse_stmt(p) decl := parse_stmt(p)
#partial switch in decl.derived_stmt { #partial switch _ in decl.derived_stmt {
case ^ast.Empty_Stmt, ^ast.Bad_Stmt, ^ast.Bad_Decl: case ^ast.Empty_Stmt, ^ast.Bad_Stmt, ^ast.Bad_Decl:
// Ignore // Ignore
return nil return nil
@@ -1174,9 +1172,7 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl {
path := expect_token(p, .String) path := expect_token(p, .String)
append(&fullpaths, path.text) append(&fullpaths, path.text)
if !allow_token(p, .Comma) { allow_token(p, .Comma) or_break
break
}
} }
expect_token(p, .Close_Brace) expect_token(p, .Close_Brace)
} else { } else {
@@ -1431,6 +1427,18 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
return es return es
case "unroll": case "unroll":
return parse_unrolled_for_loop(p, tag) return parse_unrolled_for_loop(p, tag)
case "reverse":
stmt := parse_for_stmt(p)
if range, is_range := stmt.derived.(^ast.Range_Stmt); is_range {
if range.reverse {
error(p, range.pos, "#reverse already applied to a 'for in' statement")
}
range.reverse = true
} else {
error(p, range.pos, "#reverse can only be applied to a 'for in' statement")
}
return stmt
case "include": case "include":
error(p, tag.pos, "#include is not a valid import declaration kind. Did you meant 'import'?") error(p, tag.pos, "#include is not a valid import declaration kind. Did you meant 'import'?")
return ast.new(ast.Bad_Stmt, tok.pos, end_pos(tag)) return ast.new(ast.Bad_Stmt, tok.pos, end_pos(tag))
@@ -1654,9 +1662,6 @@ is_token_field_prefix :: proc(p: ^Parser) -> ast.Field_Flag {
case .Using: case .Using:
advance_token(p) advance_token(p)
return .Using return .Using
case .Auto_Cast:
advance_token(p)
return .Auto_Cast
case .Hash: case .Hash:
tok: tokenizer.Token tok: tokenizer.Token
advance_token(p) advance_token(p)
@@ -1836,7 +1841,9 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
return true return true
} }
if allow_token(p, .Semicolon) { if allow_token(p, .Semicolon) {
error(p, tok.pos, "expected a comma, got a semicolon") if !tokenizer.is_newline(tok) {
error(p, tok.pos, "expected a comma, got a semicolon")
}
return true return true
} }
return false return false
@@ -1950,9 +1957,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
eaf := Expr_And_Flags{param, prefix_flags} eaf := Expr_And_Flags{param, prefix_flags}
append(&list, eaf) append(&list, eaf)
if !allow_token(p, .Comma) { allow_token(p, .Comma) or_break
break
}
} }
if p.curr_tok.kind != .Colon { if p.curr_tok.kind != .Colon {
@@ -2000,10 +2005,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
names = parse_ident_list(p, allow_poly_names) names = parse_ident_list(p, allow_poly_names)
total_name_count += len(names) total_name_count += len(names)
ok := handle_field(p, &seen_ellipsis, &fields, docs, names, allowed_flags, set_flags) handle_field(p, &seen_ellipsis, &fields, docs, names, allowed_flags, set_flags) or_break
if !ok {
break
}
} }
} }
@@ -2139,7 +2141,7 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^
} }
} }
#partial switch e in ast.unparen_expr(expr).derived_expr { #partial switch e in ast.strip_or_return_expr(expr).derived_expr {
case ^ast.Proc_Lit: case ^ast.Proc_Lit:
if e.inlining != .None && e.inlining != pi { if e.inlining != .None && e.inlining != pi {
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal") error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal")
@@ -2350,9 +2352,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
elem := parse_expr(p, false) elem := parse_expr(p, false)
append(&args, elem) append(&args, elem)
if !allow_token(p, .Comma) { allow_token(p, .Comma) or_break
break
}
} }
close := expect_token(p, .Close_Brace) close := expect_token(p, .Close_Brace)
@@ -2685,9 +2685,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
if _, ok := type.derived.(^ast.Bad_Expr); !ok { if _, ok := type.derived.(^ast.Bad_Expr); !ok {
append(&variants, type) append(&variants, type)
} }
if !allow_token(p, .Comma) { allow_token(p, .Comma) or_break
break
}
} }
close := expect_closing_brace_of_field_list(p) close := expect_closing_brace_of_field_list(p)
@@ -2905,9 +2903,7 @@ parse_elem_list :: proc(p: ^Parser) -> []^ast.Expr {
append(&elems, elem) append(&elems, elem)
if !allow_token(p, .Comma) { allow_token(p, .Comma) or_break
break
}
} }
return elems[:] return elems[:]
@@ -2941,9 +2937,9 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
p.expr_level += 1 p.expr_level += 1
open := expect_token(p, .Open_Paren) open := expect_token(p, .Open_Paren)
seen_ellipsis := false
for p.curr_tok.kind != .Close_Paren && for p.curr_tok.kind != .Close_Paren &&
p.curr_tok.kind != .EOF && p.curr_tok.kind != .EOF {
ellipsis.pos.line == 0 {
if p.curr_tok.kind == .Comma { if p.curr_tok.kind == .Comma {
error(p, p.curr_tok.pos, "expected an expression not ,") error(p, p.curr_tok.pos, "expected an expression not ,")
@@ -2972,13 +2968,17 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
fv.value = value fv.value = value
arg = fv arg = fv
} else if seen_ellipsis {
error(p, arg.pos, "Positional arguments are not allowed after '..'")
} }
append(&args, arg) append(&args, arg)
if !allow_token(p, .Comma) { if ellipsis.pos.line != 0 {
break seen_ellipsis = true
} }
allow_token(p, .Comma) or_break
} }
close := expect_token_after(p, .Close_Paren, "argument list") close := expect_token_after(p, .Close_Paren, "argument list")
@@ -3173,6 +3173,23 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
operand = oe operand = oe
case .Or_Break, .Or_Continue:
token := advance_token(p)
label: ^ast.Ident
end := end_pos(token)
if p.curr_tok.kind == .Ident {
end = end_pos(p.curr_tok)
label = parse_ident(p)
}
oe := ast.new(ast.Or_Branch_Expr, operand.pos, end)
oe.expr = operand
oe.token = token
oe.label = label
operand = oe
case .Open_Brace: case .Open_Brace:
if !is_lhs && is_literal_type(operand) && p.expr_level >= 0 { if !is_lhs && is_literal_type(operand) && p.expr_level >= 0 {
operand = parse_literal_value(p, operand) operand = parse_literal_value(p, operand)
+7
View File
@@ -972,6 +972,13 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
case ^ast.Or_Return_Expr: case ^ast.Or_Return_Expr:
visit_expr(p, v.expr) visit_expr(p, v.expr)
push_generic_token(p, v.token.kind, 1) push_generic_token(p, v.token.kind, 1)
case ^ast.Or_Branch_Expr:
visit_expr(p, v.expr)
push_generic_token(p, v.token.kind, 1)
if v.label != nil {
visit_expr(p, v.label)
}
case ^ast.Selector_Call_Expr: case ^ast.Selector_Call_Expr:
visit_expr(p, v.call.expr) visit_expr(p, v.call.expr)
push_generic_token(p, .Open_Paren, 1) push_generic_token(p, .Open_Paren, 1)
+4
View File
@@ -147,6 +147,8 @@ Token_Kind :: enum u32 {
Context, // context Context, // context
Or_Else, // or_else Or_Else, // or_else
Or_Return, // or_return Or_Return, // or_return
Or_Break, // or_break
Or_Continue, // or_continue
Asm, // asm Asm, // asm
Inline, // inline Inline, // inline
No_Inline, // no_inline No_Inline, // no_inline
@@ -278,6 +280,8 @@ tokens := [Token_Kind.COUNT]string {
"context", "context",
"or_else", "or_else",
"or_return", "or_return",
"or_break",
"or_continue",
"asm", "asm",
"inline", "inline",
"no_inline", "no_inline",
+1 -1
View File
@@ -124,7 +124,7 @@ Allocation_Header :: struct #raw_union {
requested: u64, requested: u64,
} }
Region_Header :: struct #align 16 { Region_Header :: struct #align(16) {
next_region: ^Region, // points to next region in global_heap (linked list) next_region: ^Region, // points to next region in global_heap (linked list)
local_addr: ^^Region, // tracks region ownership via address of _local_region local_addr: ^^Region, // tracks region ownership via address of _local_region
reset_addr: ^^Region, // tracks old local addr for reset reset_addr: ^^Region, // tracks old local addr for reset
+2 -2
View File
@@ -441,7 +441,7 @@ pollfd :: struct {
sigset_t :: distinct u64 sigset_t :: distinct u64
foreign libc { foreign libc {
@(link_name="__errno_location") __errno_location :: proc() -> ^int --- @(link_name="__errno_location") __errno_location :: proc() -> ^c.int ---
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int --- @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
@(link_name="get_nprocs") _unix_get_nprocs :: proc() -> c.int --- @(link_name="get_nprocs") _unix_get_nprocs :: proc() -> c.int ---
@@ -488,7 +488,7 @@ _get_errno :: proc(res: int) -> Errno {
// get errno from libc // get errno from libc
get_last_error :: proc "contextless" () -> int { get_last_error :: proc "contextless" () -> int {
return __errno_location()^ return int(__errno_location()^)
} }
personality :: proc(persona: u64) -> (Errno) { personality :: proc(persona: u64) -> (Errno) {
+1 -3
View File
@@ -99,9 +99,7 @@ scan_chunk :: proc(pattern: string) -> (star: bool, chunk, rest: string) {
case ']': case ']':
in_range = false in_range = false
case '*': case '*':
if !in_range { in_range or_break scan_loop
break scan_loop
}
} }
} }
+3 -4
View File
@@ -392,9 +392,8 @@ rel :: proc(base_path, target_path: string, allocator := context.allocator) -> (
for ti < tl && target[ti] != SEPARATOR { for ti < tl && target[ti] != SEPARATOR {
ti += 1 ti += 1
} }
if !strings.equal_fold(target[t0:ti], base[b0:bi]) { strings.equal_fold(target[t0:ti], base[b0:bi]) or_break
break
}
if bi < bl { if bi < bl {
bi += 1 bi += 1
} }
@@ -416,7 +415,7 @@ rel :: proc(base_path, target_path: string, allocator := context.allocator) -> (
} }
buf := make([]byte, size) buf := make([]byte, size)
n := copy(buf, "..") n := copy(buf, "..")
for in 0..<seps { for _ in 0..<seps {
buf[n] = SEPARATOR buf[n] = SEPARATOR
copy(buf[n+1:], "..") copy(buf[n+1:], "..")
n += 3 n += 3
+1 -4
View File
@@ -93,10 +93,7 @@ scan_chunk :: proc(pattern: string) -> (star: bool, chunk, rest: string) {
case ']': case ']':
in_range = false in_range = false
case '*': case '*':
if !in_range { in_range or_break scan_loop
break scan_loop
}
} }
} }
return star, pattern[:i], pattern[i:] return star, pattern[:i], pattern[i:]
+59 -60
View File
@@ -8,35 +8,35 @@ _ :: intrinsics
Type_Info :: runtime.Type_Info Type_Info :: runtime.Type_Info
Type_Info_Named :: runtime.Type_Info_Named Type_Info_Named :: runtime.Type_Info_Named
Type_Info_Integer :: runtime.Type_Info_Integer Type_Info_Integer :: runtime.Type_Info_Integer
Type_Info_Rune :: runtime.Type_Info_Rune Type_Info_Rune :: runtime.Type_Info_Rune
Type_Info_Float :: runtime.Type_Info_Float Type_Info_Float :: runtime.Type_Info_Float
Type_Info_Complex :: runtime.Type_Info_Complex Type_Info_Complex :: runtime.Type_Info_Complex
Type_Info_Quaternion :: runtime.Type_Info_Quaternion Type_Info_Quaternion :: runtime.Type_Info_Quaternion
Type_Info_String :: runtime.Type_Info_String Type_Info_String :: runtime.Type_Info_String
Type_Info_Boolean :: runtime.Type_Info_Boolean Type_Info_Boolean :: runtime.Type_Info_Boolean
Type_Info_Any :: runtime.Type_Info_Any Type_Info_Any :: runtime.Type_Info_Any
Type_Info_Type_Id :: runtime.Type_Info_Type_Id Type_Info_Type_Id :: runtime.Type_Info_Type_Id
Type_Info_Pointer :: runtime.Type_Info_Pointer Type_Info_Pointer :: runtime.Type_Info_Pointer
Type_Info_Multi_Pointer :: runtime.Type_Info_Multi_Pointer Type_Info_Multi_Pointer :: runtime.Type_Info_Multi_Pointer
Type_Info_Procedure :: runtime.Type_Info_Procedure Type_Info_Procedure :: runtime.Type_Info_Procedure
Type_Info_Array :: runtime.Type_Info_Array Type_Info_Array :: runtime.Type_Info_Array
Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array
Type_Info_Dynamic_Array :: runtime.Type_Info_Dynamic_Array Type_Info_Dynamic_Array :: runtime.Type_Info_Dynamic_Array
Type_Info_Slice :: runtime.Type_Info_Slice Type_Info_Slice :: runtime.Type_Info_Slice
Type_Info_Parameters :: runtime.Type_Info_Parameters Type_Info_Parameters :: runtime.Type_Info_Parameters
Type_Info_Tuple :: runtime.Type_Info_Parameters Type_Info_Tuple :: runtime.Type_Info_Parameters
Type_Info_Struct :: runtime.Type_Info_Struct Type_Info_Struct :: runtime.Type_Info_Struct
Type_Info_Union :: runtime.Type_Info_Union Type_Info_Union :: runtime.Type_Info_Union
Type_Info_Enum :: runtime.Type_Info_Enum Type_Info_Enum :: runtime.Type_Info_Enum
Type_Info_Map :: runtime.Type_Info_Map Type_Info_Map :: runtime.Type_Info_Map
Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set
Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector
Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer
Type_Info_Relative_Slice :: runtime.Type_Info_Relative_Slice Type_Info_Relative_Multi_Pointer :: runtime.Type_Info_Relative_Multi_Pointer
Type_Info_Matrix :: runtime.Type_Info_Matrix Type_Info_Matrix :: runtime.Type_Info_Matrix
Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer
Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value
@@ -69,7 +69,7 @@ Type_Kind :: enum {
Bit_Set, Bit_Set,
Simd_Vector, Simd_Vector,
Relative_Pointer, Relative_Pointer,
Relative_Slice, Relative_Multi_Pointer,
Matrix, Matrix,
Soa_Pointer, Soa_Pointer,
} }
@@ -80,34 +80,34 @@ type_kind :: proc(T: typeid) -> Type_Kind {
ti := type_info_of(T) ti := type_info_of(T)
if ti != nil { if ti != nil {
switch _ in ti.variant { switch _ in ti.variant {
case Type_Info_Named: return .Named case Type_Info_Named: return .Named
case Type_Info_Integer: return .Integer case Type_Info_Integer: return .Integer
case Type_Info_Rune: return .Rune case Type_Info_Rune: return .Rune
case Type_Info_Float: return .Float case Type_Info_Float: return .Float
case Type_Info_Complex: return .Complex case Type_Info_Complex: return .Complex
case Type_Info_Quaternion: return .Quaternion case Type_Info_Quaternion: return .Quaternion
case Type_Info_String: return .String case Type_Info_String: return .String
case Type_Info_Boolean: return .Boolean case Type_Info_Boolean: return .Boolean
case Type_Info_Any: return .Any case Type_Info_Any: return .Any
case Type_Info_Type_Id: return .Type_Id case Type_Info_Type_Id: return .Type_Id
case Type_Info_Pointer: return .Pointer case Type_Info_Pointer: return .Pointer
case Type_Info_Multi_Pointer: return .Multi_Pointer case Type_Info_Multi_Pointer: return .Multi_Pointer
case Type_Info_Procedure: return .Procedure case Type_Info_Procedure: return .Procedure
case Type_Info_Array: return .Array case Type_Info_Array: return .Array
case Type_Info_Enumerated_Array: return .Enumerated_Array case Type_Info_Enumerated_Array: return .Enumerated_Array
case Type_Info_Dynamic_Array: return .Dynamic_Array case Type_Info_Dynamic_Array: return .Dynamic_Array
case Type_Info_Slice: return .Slice case Type_Info_Slice: return .Slice
case Type_Info_Parameters: return .Tuple case Type_Info_Parameters: return .Tuple
case Type_Info_Struct: return .Struct case Type_Info_Struct: return .Struct
case Type_Info_Union: return .Union case Type_Info_Union: return .Union
case Type_Info_Enum: return .Enum case Type_Info_Enum: return .Enum
case Type_Info_Map: return .Map case Type_Info_Map: return .Map
case Type_Info_Bit_Set: return .Bit_Set case Type_Info_Bit_Set: return .Bit_Set
case Type_Info_Simd_Vector: return .Simd_Vector case Type_Info_Simd_Vector: return .Simd_Vector
case Type_Info_Relative_Pointer: return .Relative_Pointer case Type_Info_Relative_Pointer: return .Relative_Pointer
case Type_Info_Relative_Slice: return .Relative_Slice case Type_Info_Relative_Multi_Pointer: return .Relative_Multi_Pointer
case Type_Info_Matrix: return .Matrix case Type_Info_Matrix: return .Matrix
case Type_Info_Soa_Pointer: return .Soa_Pointer case Type_Info_Soa_Pointer: return .Soa_Pointer
} }
} }
@@ -1457,8 +1457,6 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
return equal(va, vb, including_indirect_array_recursion, recursion_level+1) return equal(va, vb, including_indirect_array_recursion, recursion_level+1)
case Type_Info_Map: case Type_Info_Map:
return false return false
case Type_Info_Relative_Slice:
return false
case case
Type_Info_Boolean, Type_Info_Boolean,
Type_Info_Integer, Type_Info_Integer,
@@ -1474,6 +1472,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
Type_Info_Enum, Type_Info_Enum,
Type_Info_Simd_Vector, Type_Info_Simd_Vector,
Type_Info_Relative_Pointer, Type_Info_Relative_Pointer,
Type_Info_Relative_Multi_Pointer,
Type_Info_Soa_Pointer, Type_Info_Soa_Pointer,
Type_Info_Matrix: Type_Info_Matrix:
return runtime.memory_compare(a.data, b.data, t.size) == 0 return runtime.memory_compare(a.data, b.data, t.size) == 0
+11 -12
View File
@@ -165,9 +165,9 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
y := b.variant.(Type_Info_Relative_Pointer) or_return y := b.variant.(Type_Info_Relative_Pointer) or_return
return x.base_integer == y.base_integer && x.pointer == y.pointer return x.base_integer == y.base_integer && x.pointer == y.pointer
case Type_Info_Relative_Slice: case Type_Info_Relative_Multi_Pointer:
y := b.variant.(Type_Info_Relative_Slice) or_return y := b.variant.(Type_Info_Relative_Multi_Pointer) or_return
return x.base_integer == y.base_integer && x.slice == y.slice return x.base_integer == y.base_integer && x.pointer == y.pointer
case Type_Info_Matrix: case Type_Info_Matrix:
y := b.variant.(Type_Info_Matrix) or_return y := b.variant.(Type_Info_Matrix) or_return
@@ -383,9 +383,9 @@ is_relative_pointer :: proc(info: ^Type_Info) -> bool {
return ok return ok
} }
@(require_results) @(require_results)
is_relative_slice :: proc(info: ^Type_Info) -> bool { is_relative_multi_pointer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false } if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Relative_Slice) _, ok := type_info_base(info).variant.(Type_Info_Relative_Multi_Pointer)
return ok return ok
} }
@@ -395,7 +395,6 @@ is_relative_slice :: proc(info: ^Type_Info) -> bool {
write_typeid_builder :: proc(buf: ^strings.Builder, id: typeid, n_written: ^int = nil) -> (n: int, err: io.Error) { write_typeid_builder :: proc(buf: ^strings.Builder, id: typeid, n_written: ^int = nil) -> (n: int, err: io.Error) {
return write_type_writer(strings.to_writer(buf), type_info_of(id)) return write_type_writer(strings.to_writer(buf), type_info_of(id))
} }
@@ -581,9 +580,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
if info.is_packed { io.write_string(w, "#packed ", &n) or_return } if info.is_packed { io.write_string(w, "#packed ", &n) or_return }
if info.is_raw_union { io.write_string(w, "#raw_union ", &n) or_return } if info.is_raw_union { io.write_string(w, "#raw_union ", &n) or_return }
if info.custom_align { if info.custom_align {
io.write_string(w, "#align ", &n) or_return io.write_string(w, "#align(", &n) or_return
io.write_i64(w, i64(ti.align), 10, &n) or_return io.write_i64(w, i64(ti.align), 10, &n) or_return
io.write_byte(w, ' ', &n) or_return io.write_string(w, ") ", &n) or_return
} }
io.write_byte(w, '{', &n) or_return io.write_byte(w, '{', &n) or_return
for name, i in info.names { for name, i in info.names {
@@ -599,9 +598,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
if info.no_nil { io.write_string(w, "#no_nil ", &n) or_return } if info.no_nil { io.write_string(w, "#no_nil ", &n) or_return }
if info.shared_nil { io.write_string(w, "#shared_nil ", &n) or_return } if info.shared_nil { io.write_string(w, "#shared_nil ", &n) or_return }
if info.custom_align { if info.custom_align {
io.write_string(w, "#align ", &n) or_return io.write_string(w, "#align(", &n) or_return
io.write_i64(w, i64(ti.align), 10, &n) or_return io.write_i64(w, i64(ti.align), 10, &n) or_return
io.write_byte(w, ' ', &n) or_return io.write_string(w, ") ", &n) or_return
} }
io.write_byte(w, '{', &n) or_return io.write_byte(w, '{', &n) or_return
for variant, i in info.variants { for variant, i in info.variants {
@@ -652,11 +651,11 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
io.write_string(w, ") ", &n) or_return io.write_string(w, ") ", &n) or_return
write_type(w, info.pointer, &n) or_return write_type(w, info.pointer, &n) or_return
case Type_Info_Relative_Slice: case Type_Info_Relative_Multi_Pointer:
io.write_string(w, "#relative(", &n) or_return io.write_string(w, "#relative(", &n) or_return
write_type(w, info.base_integer, &n) or_return write_type(w, info.base_integer, &n) or_return
io.write_string(w, ") ", &n) or_return io.write_string(w, ") ", &n) or_return
write_type(w, info.slice, &n) or_return write_type(w, info.pointer, &n) or_return
case Type_Info_Matrix: case Type_Info_Matrix:
io.write_string(w, "matrix[", &n) or_return io.write_string(w, "matrix[", &n) or_return
+32 -6
View File
@@ -162,11 +162,11 @@ Type_Info_Simd_Vector :: struct {
count: int, count: int,
} }
Type_Info_Relative_Pointer :: struct { Type_Info_Relative_Pointer :: struct {
pointer: ^Type_Info, pointer: ^Type_Info, // ^T
base_integer: ^Type_Info, base_integer: ^Type_Info,
} }
Type_Info_Relative_Slice :: struct { Type_Info_Relative_Multi_Pointer :: struct {
slice: ^Type_Info, pointer: ^Type_Info, // [^]T
base_integer: ^Type_Info, base_integer: ^Type_Info,
} }
Type_Info_Matrix :: struct { Type_Info_Matrix :: struct {
@@ -219,7 +219,7 @@ Type_Info :: struct {
Type_Info_Bit_Set, Type_Info_Bit_Set,
Type_Info_Simd_Vector, Type_Info_Simd_Vector,
Type_Info_Relative_Pointer, Type_Info_Relative_Pointer,
Type_Info_Relative_Slice, Type_Info_Relative_Multi_Pointer,
Type_Info_Matrix, Type_Info_Matrix,
Type_Info_Soa_Pointer, Type_Info_Soa_Pointer,
}, },
@@ -252,12 +252,13 @@ Typeid_Kind :: enum u8 {
Bit_Set, Bit_Set,
Simd_Vector, Simd_Vector,
Relative_Pointer, Relative_Pointer,
Relative_Slice, Relative_Multi_Pointer,
Matrix, Matrix,
Soa_Pointer,
} }
#assert(len(Typeid_Kind) < 32) #assert(len(Typeid_Kind) < 32)
// Typeid_Bit_Field :: bit_field #align align_of(uintptr) { // Typeid_Bit_Field :: bit_field #align(align_of(uintptr)) {
// index: 8*size_of(uintptr) - 8, // index: 8*size_of(uintptr) - 8,
// kind: 5, // Typeid_Kind // kind: 5, // Typeid_Kind
// named: 1, // named: 1,
@@ -337,6 +338,8 @@ Kilobyte :: 1024 * Byte
Megabyte :: 1024 * Kilobyte Megabyte :: 1024 * Kilobyte
Gigabyte :: 1024 * Megabyte Gigabyte :: 1024 * Megabyte
Terabyte :: 1024 * Gigabyte Terabyte :: 1024 * Gigabyte
Petabyte :: 1024 * Terabyte
Exabyte :: 1024 * Petabyte
// Logging stuff // Logging stuff
@@ -499,6 +502,29 @@ Odin_Build_Mode_Type :: type_of(ODIN_BUILD_MODE)
Odin_Endian_Type :: type_of(ODIN_ENDIAN) Odin_Endian_Type :: type_of(ODIN_ENDIAN)
/*
// Defined internally by the compiler
Odin_Platform_Subtarget_Type :: enum int {
Default,
iOS,
}
*/
Odin_Platform_Subtarget_Type :: type_of(ODIN_PLATFORM_SUBTARGET)
/*
// Defined internally by the compiler
Odin_Sanitizer_Flag :: enum u32 {
Address = 0,
Memory = 1,
Thread = 2,
}
Odin_Sanitizer_Flags :: distinct bitset[Odin_Sanitizer_Flag; u32]
ODIN_SANITIZER_FLAGS // is a constant
*/
Odin_Sanitizer_Flags :: type_of(ODIN_SANITIZER_FLAGS)
///////////////////////////// /////////////////////////////
// Init Startup Procedures // // Init Startup Procedures //
///////////////////////////// /////////////////////////////
+6 -5
View File
@@ -601,14 +601,15 @@ assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
@builtin @builtin
assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if len(args) == 0 { new_size := index + len(arg)
if len(arg) == 0 {
ok = true ok = true
} else if index+len(args) < len(array) { } else if new_size < len(array) {
copy(array[index:], args) copy(array[index:], arg)
ok = true ok = true
} else { } else {
resize(array, index+1+len(args), loc) or_return resize(array, new_size, loc) or_return
copy(array[index:], args) copy(array[index:], arg)
ok = true ok = true
} }
return return
+5 -2
View File
@@ -4,13 +4,16 @@
//+build !js //+build !js
package runtime package runtime
// TODO(bill): reimplement these procedures in the os_specific stuff
import "core:os"
when ODIN_DEFAULT_TO_NIL_ALLOCATOR { when ODIN_DEFAULT_TO_NIL_ALLOCATOR {
_ :: os
// mem.nil_allocator reimplementation // mem.nil_allocator reimplementation
default_allocator_proc :: nil_allocator_proc default_allocator_proc :: nil_allocator_proc
default_allocator :: nil_allocator default_allocator :: nil_allocator
} else { } else {
// TODO(bill): reimplement these procedures in the os_specific stuff
import "core:os"
default_allocator_proc :: os.heap_allocator_proc default_allocator_proc :: os.heap_allocator_proc
+1 -1
View File
@@ -87,7 +87,7 @@ MAP_CACHE_LINE_SIZE :: 1 << MAP_CACHE_LINE_LOG2
// //
// In the optimal case, len(Map_Cell(T){}.data) = 1 so the cell array can be treated // In the optimal case, len(Map_Cell(T){}.data) = 1 so the cell array can be treated
// as a regular array of T, which is the case for hashes. // as a regular array of T, which is the case for hashes.
Map_Cell :: struct($T: typeid) #align MAP_CACHE_LINE_SIZE { Map_Cell :: struct($T: typeid) #align(MAP_CACHE_LINE_SIZE) {
data: [MAP_CACHE_LINE_SIZE / size_of(T) when 0 < size_of(T) && size_of(T) < MAP_CACHE_LINE_SIZE else 1]T, data: [MAP_CACHE_LINE_SIZE / size_of(T) when 0 < size_of(T) && size_of(T) < MAP_CACHE_LINE_SIZE else 1]T,
} }
+68 -13
View File
@@ -11,7 +11,10 @@ RUNTIME_LINKAGE :: "strong" when (
ODIN_BUILD_MODE == .Dynamic || ODIN_BUILD_MODE == .Dynamic ||
!ODIN_NO_CRT) && !ODIN_NO_CRT) &&
!IS_WASM) else "internal" !IS_WASM) else "internal"
RUNTIME_REQUIRE :: true RUNTIME_REQUIRE :: !ODIN_TILDE
@(private)
__float16 :: f16 when __ODIN_LLVM_F16_SUPPORTED else u16
@(private) @(private)
@@ -218,10 +221,18 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
case n == 0: return true case n == 0: return true
case x == y: return true case x == y: return true
} }
a, b := ([^]byte)(x), ([^]byte)(y) a, b := ([^]byte)(x), ([^]byte)(y)
length := uint(n) length := uint(n)
for i := uint(0); i < length; i += 1 {
if a[i] != b[i] {
return false
}
}
return true
/*
when size_of(uint) == 8 { when size_of(uint) == 8 {
if word_length := length >> 3; word_length != 0 { if word_length := length >> 3; word_length != 0 {
for _ in 0..<word_length { for _ in 0..<word_length {
@@ -276,6 +287,7 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
return true return true
} }
*/
} }
memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check { memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check {
@@ -401,6 +413,48 @@ cstring_to_string :: proc "contextless" (s: cstring) -> string {
} }
cstring_eq :: proc "contextless" (lhs, rhs: cstring) -> bool {
x := ([^]byte)(lhs)
y := ([^]byte)(rhs)
if x == y {
return true
}
if (x == nil) ~ (y == nil) {
return false
}
xn := cstring_len(lhs)
yn := cstring_len(rhs)
if xn != yn {
return false
}
return #force_inline memory_equal(x, y, xn)
}
cstring_cmp :: proc "contextless" (lhs, rhs: cstring) -> int {
x := ([^]byte)(lhs)
y := ([^]byte)(rhs)
if x == y {
return 0
}
if (x == nil) ~ (y == nil) {
return -1 if x == nil else +1
}
xn := cstring_len(lhs)
yn := cstring_len(rhs)
ret := memory_compare(x, y, min(xn, yn))
if ret == 0 && xn != yn {
return -1 if xn < yn else +1
}
return ret
}
cstring_ne :: #force_inline proc "contextless" (a, b: cstring) -> bool { return !cstring_eq(a, b) }
cstring_lt :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) < 0 }
cstring_gt :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) > 0 }
cstring_le :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) <= 0 }
cstring_ge :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) >= 0 }
complex32_eq :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) == real(b) && imag(a) == imag(b) } complex32_eq :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) == real(b) && imag(a) == imag(b) }
complex32_ne :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) != real(b) || imag(a) != imag(b) } complex32_ne :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) != real(b) || imag(a) != imag(b) }
@@ -746,7 +800,7 @@ quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
} }
@(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) @(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
truncsfhf2 :: proc "c" (value: f32) -> u16 { truncsfhf2 :: proc "c" (value: f32) -> __float16 {
v: struct #raw_union { i: u32, f: f32 } v: struct #raw_union { i: u32, f: f32 }
i, s, e, m: i32 i, s, e, m: i32
@@ -760,7 +814,7 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 {
if e <= 0 { if e <= 0 {
if e < -10 { if e < -10 {
return u16(s) return transmute(__float16)u16(s)
} }
m = (m | 0x00800000) >> u32(1 - e) m = (m | 0x00800000) >> u32(1 - e)
@@ -768,14 +822,14 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 {
m += 0x00002000 m += 0x00002000
} }
return u16(s | (m >> 13)) return transmute(__float16)u16(s | (m >> 13))
} else if e == 0xff - (127 - 15) { } else if e == 0xff - (127 - 15) {
if m == 0 { if m == 0 {
return u16(s | 0x7c00) /* NOTE(bill): infinity */ return transmute(__float16)u16(s | 0x7c00) /* NOTE(bill): infinity */
} else { } else {
/* NOTE(bill): NAN */ /* NOTE(bill): NAN */
m >>= 13 m >>= 13
return u16(s | 0x7c00 | m | i32(m == 0)) return transmute(__float16)u16(s | 0x7c00 | m | i32(m == 0))
} }
} else { } else {
if m & 0x00001000 != 0 { if m & 0x00001000 != 0 {
@@ -795,23 +849,24 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 {
intrinsics.volatile_store(&f, g) intrinsics.volatile_store(&f, g)
} }
return u16(s | 0x7c00) return transmute(__float16)u16(s | 0x7c00)
} }
return u16(s | (e << 10) | (m >> 13)) return transmute(__float16)u16(s | (e << 10) | (m >> 13))
} }
} }
@(link_name="__truncdfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) @(link_name="__truncdfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
truncdfhf2 :: proc "c" (value: f64) -> u16 { truncdfhf2 :: proc "c" (value: f64) -> __float16 {
return truncsfhf2(f32(value)) return truncsfhf2(f32(value))
} }
@(link_name="__gnu_h2f_ieee", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) @(link_name="__gnu_h2f_ieee", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
gnu_h2f_ieee :: proc "c" (value: u16) -> f32 { gnu_h2f_ieee :: proc "c" (value_: __float16) -> f32 {
fp32 :: struct #raw_union { u: u32, f: f32 } fp32 :: struct #raw_union { u: u32, f: f32 }
value := transmute(u16)value_
v: fp32 v: fp32
magic, inf_or_nan: fp32 magic, inf_or_nan: fp32
magic.u = u32((254 - 15) << 23) magic.u = u32((254 - 15) << 23)
@@ -828,12 +883,12 @@ gnu_h2f_ieee :: proc "c" (value: u16) -> f32 {
@(link_name="__gnu_f2h_ieee", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) @(link_name="__gnu_f2h_ieee", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
gnu_f2h_ieee :: proc "c" (value: f32) -> u16 { gnu_f2h_ieee :: proc "c" (value: f32) -> __float16 {
return truncsfhf2(value) return truncsfhf2(value)
} }
@(link_name="__extendhfsf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) @(link_name="__extendhfsf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
extendhfsf2 :: proc "c" (value: u16) -> f32 { extendhfsf2 :: proc "c" (value: __float16) -> f32 {
return gnu_h2f_ieee(value) return gnu_h2f_ieee(value)
} }
+6 -9
View File
@@ -1,9 +1,6 @@
//+private
//+build windows //+build windows
package runtime package runtime
import "core:intrinsics"
foreign import kernel32 "system:Kernel32.lib" foreign import kernel32 "system:Kernel32.lib"
@(private="file") @(private="file")
@@ -102,12 +99,12 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol
allocated_mem: rawptr allocated_mem: rawptr
if old_ptr != nil { if old_ptr != nil {
original_old_ptr := intrinsics.ptr_offset((^rawptr)(old_ptr), -1)^ original_old_ptr := ([^]rawptr)(old_ptr)[-1]
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr)) allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
} else { } else {
allocated_mem = heap_alloc(space+size_of(rawptr), zero_memory) allocated_mem = heap_alloc(space+size_of(rawptr), zero_memory)
} }
aligned_mem := rawptr(intrinsics.ptr_offset((^u8)(allocated_mem), size_of(rawptr))) aligned_mem := ([^]u8)(allocated_mem)[size_of(rawptr):]
ptr := uintptr(aligned_mem) ptr := uintptr(aligned_mem)
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a) aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
@@ -116,10 +113,10 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol
return nil, .Out_Of_Memory return nil, .Out_Of_Memory
} }
aligned_mem = rawptr(aligned_ptr) aligned_mem = ([^]byte)(aligned_ptr)
intrinsics.ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem ([^]rawptr)(aligned_mem)[-1] = allocated_mem
return byte_slice(aligned_mem, size), nil return aligned_mem[:size], nil
} }
_windows_default_alloc :: proc "contextless" (size, alignment: int, zero_memory := true) -> ([]byte, Allocator_Error) { _windows_default_alloc :: proc "contextless" (size, alignment: int, zero_memory := true) -> ([]byte, Allocator_Error) {
@@ -129,7 +126,7 @@ _windows_default_alloc :: proc "contextless" (size, alignment: int, zero_memory
_windows_default_free :: proc "contextless" (ptr: rawptr) { _windows_default_free :: proc "contextless" (ptr: rawptr) {
if ptr != nil { if ptr != nil {
heap_free(intrinsics.ptr_offset((^rawptr)(ptr), -1)^) heap_free(([^]rawptr)(ptr)[-1])
} }
} }
+15 -6
View File
@@ -8,6 +8,11 @@ _INTEGER_DIGITS_VAR := _INTEGER_DIGITS
when !ODIN_NO_RTTI { when !ODIN_NO_RTTI {
print_any_single :: proc "contextless" (arg: any) { print_any_single :: proc "contextless" (arg: any) {
x := arg x := arg
if x.data == nil {
print_string("nil")
return
}
if loc, ok := x.(Source_Code_Location); ok { if loc, ok := x.(Source_Code_Location); ok {
print_caller_location(loc) print_caller_location(loc)
return return
@@ -48,6 +53,7 @@ when !ODIN_NO_RTTI {
case int: print_int(v) case int: print_int(v)
case uint: print_uint(v) case uint: print_uint(v)
case uintptr: print_uintptr(v) case uintptr: print_uintptr(v)
case rawptr: print_uintptr(uintptr(v))
case bool: print_string("true" if v else "false") case bool: print_string("true" if v else "false")
case b8: print_string("true" if v else "false") case b8: print_string("true" if v else "false")
@@ -58,7 +64,7 @@ when !ODIN_NO_RTTI {
case: case:
ti := type_info_of(x.id) ti := type_info_of(x.id)
#partial switch v in ti.variant { #partial switch v in ti.variant {
case Type_Info_Pointer: case Type_Info_Pointer, Type_Info_Multi_Pointer:
print_uintptr((^uintptr)(x.data)^) print_uintptr((^uintptr)(x.data)^)
return return
} }
@@ -67,7 +73,9 @@ when !ODIN_NO_RTTI {
} }
} }
println_any :: proc "contextless" (args: ..any) { println_any :: proc "contextless" (args: ..any) {
context = default_context()
loop: for arg, i in args { loop: for arg, i in args {
assert(arg.id != nil)
if i != 0 { if i != 0 {
print_string(" ") print_string(" ")
} }
@@ -390,9 +398,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
if info.is_packed { print_string("#packed ") } if info.is_packed { print_string("#packed ") }
if info.is_raw_union { print_string("#raw_union ") } if info.is_raw_union { print_string("#raw_union ") }
if info.custom_align { if info.custom_align {
print_string("#align ") print_string("#align(")
print_u64(u64(ti.align)) print_u64(u64(ti.align))
print_byte(' ') print_string(") ")
} }
print_byte('{') print_byte('{')
for name, i in info.names { for name, i in info.names {
@@ -406,8 +414,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
case Type_Info_Union: case Type_Info_Union:
print_string("union ") print_string("union ")
if info.custom_align { if info.custom_align {
print_string("#align ") print_string("#align(")
print_u64(u64(ti.align)) print_u64(u64(ti.align))
print_string(") ")
} }
if info.no_nil { if info.no_nil {
print_string("#no_nil ") print_string("#no_nil ")
@@ -463,11 +472,11 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
print_string(") ") print_string(") ")
print_type(info.pointer) print_type(info.pointer)
case Type_Info_Relative_Slice: case Type_Info_Relative_Multi_Pointer:
print_string("#relative(") print_string("#relative(")
print_type(info.base_integer) print_type(info.base_integer)
print_string(") ") print_string(") ")
print_type(info.slice) print_type(info.pointer)
case Type_Info_Matrix: case Type_Info_Matrix:
print_string("matrix[") print_string("matrix[")
+2 -2
View File
@@ -31,7 +31,7 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
if ptr != nil && len != 0 { if ptr != nil && len != 0 {
b := byte(val) b := byte(val)
p := ([^]byte)(ptr) p := ([^]byte)(ptr)
for i in 0..<len { for i := 0; i < len; i += 1 {
p[i] = b p[i] = b
} }
} }
@@ -75,7 +75,7 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
if ptr != nil && len != 0 { if ptr != nil && len != 0 {
b := byte(val) b := byte(val)
p := ([^]byte)(ptr) p := ([^]byte)(ptr)
for i in 0..<len { for i := 0; i < len; i += 1 {
p[i] = b p[i] = b
} }
} }
+4 -4
View File
@@ -77,10 +77,10 @@ shr_masked :: intrinsics.simd_shr_masked
add_sat :: intrinsics.simd_add_sat add_sat :: intrinsics.simd_add_sat
sub_sat :: intrinsics.simd_sub_sat sub_sat :: intrinsics.simd_sub_sat
and :: intrinsics.simd_and bit_and :: intrinsics.simd_bit_and
or :: intrinsics.simd_or bit_or :: intrinsics.simd_bit_or
xor :: intrinsics.simd_xor bit_xor :: intrinsics.simd_bit_xor
and_not :: intrinsics.simd_and_not bit_and_not :: intrinsics.simd_bit_and_not
neg :: intrinsics.simd_neg neg :: intrinsics.simd_neg
+1 -1
View File
@@ -259,7 +259,7 @@ _quick_sort :: proc(it: Interface, a, b, max_depth: int) {
a, b, max_depth := a, b, max_depth a, b, max_depth := a, b, max_depth
if b-a > 12 { // only use shell sort for lengths <= 12 for b-a > 12 { // only use shell sort for lengths <= 12
if max_depth == 0 { if max_depth == 0 {
heap_sort(it, a, b) heap_sort(it, a, b)
return return
+12 -12
View File
@@ -35,8 +35,8 @@ Returns:
- res: The new Builder - res: The new Builder
- err: An optional allocator error if one occured, `nil` otherwise - err: An optional allocator error if one occured, `nil` otherwise
*/ */
builder_make_none :: proc(allocator := context.allocator) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error { builder_make_none :: proc(allocator := context.allocator, loc := #caller_location) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
return Builder{buf=make([dynamic]byte, allocator) or_return }, nil return Builder{buf=make([dynamic]byte, allocator, loc) or_return }, nil
} }
/* /*
Produces a Builder with a specified length and cap of max(16,len) byte buffer Produces a Builder with a specified length and cap of max(16,len) byte buffer
@@ -51,8 +51,8 @@ Returns:
- res: The new Builder - res: The new Builder
- err: An optional allocator error if one occured, `nil` otherwise - err: An optional allocator error if one occured, `nil` otherwise
*/ */
builder_make_len :: proc(len: int, allocator := context.allocator) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error { builder_make_len :: proc(len: int, allocator := context.allocator, loc := #caller_location) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
return Builder{buf=make([dynamic]byte, len, allocator) or_return }, nil return Builder{buf=make([dynamic]byte, len, allocator, loc) or_return }, nil
} }
/* /*
Produces a Builder with a specified length and cap Produces a Builder with a specified length and cap
@@ -68,8 +68,8 @@ Returns:
- res: The new Builder - res: The new Builder
- err: An optional allocator error if one occured, `nil` otherwise - err: An optional allocator error if one occured, `nil` otherwise
*/ */
builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error { builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator, loc := #caller_location) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
return Builder{buf=make([dynamic]byte, len, cap, allocator) or_return }, nil return Builder{buf=make([dynamic]byte, len, cap, allocator, loc) or_return }, nil
} }
/* /*
Produces a String Builder Produces a String Builder
@@ -116,8 +116,8 @@ Returns:
- res: A pointer to the initialized Builder - res: A pointer to the initialized Builder
- err: An optional allocator error if one occured, `nil` otherwise - err: An optional allocator error if one occured, `nil` otherwise
*/ */
builder_init_none :: proc(b: ^Builder, allocator := context.allocator) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error { builder_init_none :: proc(b: ^Builder, allocator := context.allocator, loc := #caller_location) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error {
b.buf = make([dynamic]byte, allocator) or_return b.buf = make([dynamic]byte, allocator, loc) or_return
return b, nil return b, nil
} }
/* /*
@@ -135,8 +135,8 @@ Returns:
- res: A pointer to the initialized Builder - res: A pointer to the initialized Builder
- err: An optional allocator error if one occured, `nil` otherwise - err: An optional allocator error if one occured, `nil` otherwise
*/ */
builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error { builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator, loc := #caller_location) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error {
b.buf = make([dynamic]byte, len, allocator) or_return b.buf = make([dynamic]byte, len, allocator, loc) or_return
return b, nil return b, nil
} }
/* /*
@@ -153,8 +153,8 @@ Returns:
- res: A pointer to the initialized Builder - res: A pointer to the initialized Builder
- err: An optional allocator error if one occured, `nil` otherwise - err: An optional allocator error if one occured, `nil` otherwise
*/ */
builder_init_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error { builder_init_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator, loc := #caller_location) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error {
b.buf = make([dynamic]byte, len, cap, allocator) or_return b.buf = make([dynamic]byte, len, cap, allocator, loc) or_return
return b, nil return b, nil
} }
// Overload simple `builder_init_*` with or without len / ap parameters // Overload simple `builder_init_*` with or without len / ap parameters
+2 -2
View File
@@ -34,9 +34,9 @@ Inputs:
Returns: Returns:
- err: An allocator error if one occured, `nil` otherwise - err: An allocator error if one occured, `nil` otherwise
*/ */
intern_init :: proc(m: ^Intern, allocator := context.allocator, map_allocator := context.allocator) -> (err: mem.Allocator_Error) { intern_init :: proc(m: ^Intern, allocator := context.allocator, map_allocator := context.allocator, loc := #caller_location) -> (err: mem.Allocator_Error) {
m.allocator = allocator m.allocator = allocator
m.entries = make(map[string]^Intern_Entry, 16, map_allocator) or_return m.entries = make(map[string]^Intern_Entry, 16, map_allocator, loc) or_return
return nil return nil
} }
/* /*
+23 -23
View File
@@ -595,7 +595,7 @@ Output:
a...b...c a...b...c
*/ */
join :: proc(a: []string, sep: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { join :: proc(a: []string, sep: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
if len(a) == 0 { if len(a) == 0 {
return "", nil return "", nil
} }
@@ -605,7 +605,7 @@ join :: proc(a: []string, sep: string, allocator := context.allocator) -> (res:
n += len(s) n += len(s)
} }
b := make([]byte, n, allocator) or_return b := make([]byte, n, allocator, loc) or_return
i := copy(b, a[0]) i := copy(b, a[0])
for s in a[1:] { for s in a[1:] {
i += copy(b[i:], sep) i += copy(b[i:], sep)
@@ -659,7 +659,7 @@ Output:
abc abc
*/ */
concatenate :: proc(a: []string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { concatenate :: proc(a: []string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
if len(a) == 0 { if len(a) == 0 {
return "", nil return "", nil
} }
@@ -668,7 +668,7 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> (res: string
for s in a { for s in a {
n += len(s) n += len(s)
} }
b := make([]byte, n, allocator) or_return b := make([]byte, n, allocator, loc) or_return
i := 0 i := 0
for s in a { for s in a {
i += copy(b[i:], s) i += copy(b[i:], s)
@@ -724,7 +724,7 @@ Output:
example example
*/ */
cut :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { cut :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
s := s; rune_length := rune_length s := s; rune_length := rune_length
context.allocator = allocator context.allocator = allocator
@@ -752,7 +752,7 @@ cut :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator :
// But we do know it's bounded by the number of runes * 4 bytes, // But we do know it's bounded by the number of runes * 4 bytes,
// and can be no more than the size of the input string. // and can be no more than the size of the input string.
bytes_needed := min(rune_length * 4, len(s)) bytes_needed := min(rune_length * 4, len(s))
buf := make([]u8, bytes_needed) or_return buf := make([]u8, bytes_needed, allocator, loc) or_return
byte_offset := 0 byte_offset := 0
for i := 0; i < rune_count; i += 1 { for i := 0; i < rune_count; i += 1 {
@@ -796,7 +796,7 @@ Returns:
- err: An optional allocator error if one occured, `nil` otherwise - err: An optional allocator error if one occured, `nil` otherwise
*/ */
@private @private
_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) { _split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: mem.Allocator_Error) {
s, n := s_, n_ s, n := s_, n_
if n == 0 { if n == 0 {
@@ -809,7 +809,7 @@ _split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocato
n = l n = l
} }
res := make([]string, n, allocator) or_return res := make([]string, n, allocator, loc) or_return
for i := 0; i < n-1; i += 1 { for i := 0; i < n-1; i += 1 {
_, w := utf8.decode_rune_in_string(s) _, w := utf8.decode_rune_in_string(s)
res[i] = s[:w] res[i] = s[:w]
@@ -825,7 +825,7 @@ _split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocato
n = count(s, sep) + 1 n = count(s, sep) + 1
} }
res = make([]string, n, allocator) or_return res = make([]string, n, allocator, loc) or_return
n -= 1 n -= 1
@@ -1965,14 +1965,14 @@ Output:
abcabc abcabc
*/ */
repeat :: proc(s: string, count: int, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { repeat :: proc(s: string, count: int, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
if count < 0 { if count < 0 {
panic("strings: negative repeat count") panic("strings: negative repeat count")
} else if count > 0 && (len(s)*count)/count != len(s) { } else if count > 0 && (len(s)*count)/count != len(s) {
panic("strings: repeat count will cause an overflow") panic("strings: repeat count will cause an overflow")
} }
b := make([]byte, len(s)*count, allocator) or_return b := make([]byte, len(s)*count, allocator, loc) or_return
i := copy(b, s) i := copy(b, s)
for i < len(b) { // 2^N trick to reduce the need to copy for i < len(b) { // 2^N trick to reduce the need to copy
copy(b[i:], b[:i]) copy(b[i:], b[:i])
@@ -2052,7 +2052,7 @@ Output:
zzzz true zzzz true
*/ */
replace :: proc(s, old, new: string, n: int, allocator := context.allocator) -> (output: string, was_allocation: bool) { replace :: proc(s, old, new: string, n: int, allocator := context.allocator, loc := #caller_location) -> (output: string, was_allocation: bool) {
if old == new || n == 0 { if old == new || n == 0 {
was_allocation = false was_allocation = false
output = s output = s
@@ -2068,7 +2068,7 @@ replace :: proc(s, old, new: string, n: int, allocator := context.allocator) ->
} }
t := make([]byte, len(s) + byte_count*(len(new) - len(old)), allocator) t := make([]byte, len(s) + byte_count*(len(new) - len(old)), allocator, loc)
was_allocation = true was_allocation = true
w := 0 w := 0
@@ -2637,7 +2637,7 @@ Output:
["testing", "this", "out", "nice", "done", "last"] ["testing", "this", "out", "nice", "done", "last"]
*/ */
split_multi :: proc(s: string, substrs: []string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check { split_multi :: proc(s: string, substrs: []string, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check {
if s == "" || len(substrs) <= 0 { if s == "" || len(substrs) <= 0 {
return nil, nil return nil, nil
} }
@@ -2660,7 +2660,7 @@ split_multi :: proc(s: string, substrs: []string, allocator := context.allocator
it = it[i+w:] it = it[i+w:]
} }
results := make([dynamic]string, 0, n, allocator) or_return results := make([dynamic]string, 0, n, allocator, loc) or_return
{ {
it := s it := s
for len(it) > 0 { for len(it) > 0 {
@@ -2825,10 +2825,10 @@ Output:
abcxyz zyxcba abcxyz zyxcba
*/ */
reverse :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { reverse :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
str := s str := s
n := len(str) n := len(str)
buf := make([]byte, n) or_return buf := make([]byte, n, allocator, loc) or_return
i := n i := n
for len(str) > 0 { for len(str) > 0 {
@@ -3107,7 +3107,7 @@ Returns:
- res: A slice of substrings of the input string, or an empty slice if the input string only contains white space - res: A slice of substrings of the input string, or an empty slice if the input string only contains white space
- err: An optional allocator error if one occured, `nil` otherwise - err: An optional allocator error if one occured, `nil` otherwise
*/ */
fields :: proc(s: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check { fields :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check {
n := 0 n := 0
was_space := 1 was_space := 1
set_bits := u8(0) set_bits := u8(0)
@@ -3129,7 +3129,7 @@ fields :: proc(s: string, allocator := context.allocator) -> (res: []string, err
return nil, nil return nil, nil
} }
a := make([]string, n, allocator) or_return a := make([]string, n, allocator, loc) or_return
na := 0 na := 0
field_start := 0 field_start := 0
i := 0 i := 0
@@ -3171,8 +3171,8 @@ Returns:
- res: A slice of substrings of the input string, or an empty slice if all code points in the input string satisfy the predicate or if the input string is empty - res: A slice of substrings of the input string, or an empty slice if all code points in the input string satisfy the predicate or if the input string is empty
- err: An optional allocator error if one occured, `nil` otherwise - err: An optional allocator error if one occured, `nil` otherwise
*/ */
fields_proc :: proc(s: string, f: proc(rune) -> bool, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check { fields_proc :: proc(s: string, f: proc(rune) -> bool, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check {
substrings := make([dynamic]string, 0, 32, allocator) or_return substrings := make([dynamic]string, 0, 32, allocator, loc) or_return
start, end := -1, -1 start, end := -1, -1
for r, offset in s { for r, offset in s {
@@ -3252,7 +3252,7 @@ Returns:
NOTE: This implementation is a single-row-version of the WagnerFischer algorithm, based on C code by Martin Ettl. NOTE: This implementation is a single-row-version of the WagnerFischer algorithm, based on C code by Martin Ettl.
*/ */
levenshtein_distance :: proc(a, b: string, allocator := context.allocator) -> (res: int, err: mem.Allocator_Error) #optional_allocator_error { levenshtein_distance :: proc(a, b: string, allocator := context.allocator, loc := #caller_location) -> (res: int, err: mem.Allocator_Error) #optional_allocator_error {
LEVENSHTEIN_DEFAULT_COSTS: []int : { LEVENSHTEIN_DEFAULT_COSTS: []int : {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
@@ -3275,7 +3275,7 @@ levenshtein_distance :: proc(a, b: string, allocator := context.allocator) -> (r
costs: []int costs: []int
if n + 1 > len(LEVENSHTEIN_DEFAULT_COSTS) { if n + 1 > len(LEVENSHTEIN_DEFAULT_COSTS) {
costs = make([]int, n + 1, allocator) or_return costs = make([]int, n + 1, allocator, loc) or_return
for k in 0..=n { for k in 0..=n {
costs[k] = k costs[k] = k
} }
+2
View File
@@ -88,6 +88,7 @@ wait :: proc{
atomic_cond_wait, atomic_cond_wait,
atomic_sema_wait, atomic_sema_wait,
futex_wait, futex_wait,
wait_group_wait,
} }
wait_with_timeout :: proc{ wait_with_timeout :: proc{
@@ -96,6 +97,7 @@ wait_with_timeout :: proc{
atomic_cond_wait_with_timeout, atomic_cond_wait_with_timeout,
atomic_sema_wait_with_timeout, atomic_sema_wait_with_timeout,
futex_wait_with_timeout, futex_wait_with_timeout,
wait_group_wait_with_timeout,
} }
post :: proc{ post :: proc{
+8 -8
View File
@@ -17,42 +17,42 @@ PTHREAD_RWLOCKATTR_SIZE :: 16
pthread_t :: distinct u64 pthread_t :: distinct u64
pthread_attr_t :: struct #align 16 { pthread_attr_t :: struct #align(16) {
sig: c.long, sig: c.long,
_: [PTHREAD_ATTR_SIZE] c.char, _: [PTHREAD_ATTR_SIZE] c.char,
} }
pthread_cond_t :: struct #align 16 { pthread_cond_t :: struct #align(16) {
sig: c.long, sig: c.long,
_: [PTHREAD_COND_SIZE] c.char, _: [PTHREAD_COND_SIZE] c.char,
} }
pthread_condattr_t :: struct #align 16 { pthread_condattr_t :: struct #align(16) {
sig: c.long, sig: c.long,
_: [PTHREAD_CONDATTR_SIZE] c.char, _: [PTHREAD_CONDATTR_SIZE] c.char,
} }
pthread_mutex_t :: struct #align 16 { pthread_mutex_t :: struct #align(16) {
sig: c.long, sig: c.long,
_: [PTHREAD_MUTEX_SIZE] c.char, _: [PTHREAD_MUTEX_SIZE] c.char,
} }
pthread_mutexattr_t :: struct #align 16 { pthread_mutexattr_t :: struct #align(16) {
sig: c.long, sig: c.long,
_: [PTHREAD_MUTEXATTR_SIZE] c.char, _: [PTHREAD_MUTEXATTR_SIZE] c.char,
} }
pthread_once_t :: struct #align 16 { pthread_once_t :: struct #align(16) {
sig: c.long, sig: c.long,
_: [PTHREAD_ONCE_SIZE] c.char, _: [PTHREAD_ONCE_SIZE] c.char,
} }
pthread_rwlock_t :: struct #align 16 { pthread_rwlock_t :: struct #align(16) {
sig: c.long, sig: c.long,
_: [PTHREAD_RWLOCK_SIZE] c.char, _: [PTHREAD_RWLOCK_SIZE] c.char,
} }
pthread_rwlockattr_t :: struct #align 16 { pthread_rwlockattr_t :: struct #align(16) {
sig: c.long, sig: c.long,
_: [PTHREAD_RWLOCKATTR_SIZE] c.char, _: [PTHREAD_RWLOCKATTR_SIZE] c.char,
} }
+10 -10
View File
@@ -4,7 +4,7 @@ package unix
import "core:c" import "core:c"
pthread_t :: distinct u64 pthread_t :: distinct u64
// pthread_t :: struct #align 16 { x: u64 } // pthread_t :: struct #align(16) { x: u64 }
PTHREAD_COND_T_SIZE :: 8 PTHREAD_COND_T_SIZE :: 8
@@ -27,32 +27,32 @@ when size_of(int) == 8 {
PTHREAD_BARRIER_T_SIZE :: 20 PTHREAD_BARRIER_T_SIZE :: 20
} }
pthread_cond_t :: struct #align 16 { pthread_cond_t :: struct #align(16) {
_: [PTHREAD_COND_T_SIZE] c.char, _: [PTHREAD_COND_T_SIZE] c.char,
} }
pthread_mutex_t :: struct #align 16 { pthread_mutex_t :: struct #align(16) {
_: [PTHREAD_MUTEX_T_SIZE] c.char, _: [PTHREAD_MUTEX_T_SIZE] c.char,
} }
pthread_rwlock_t :: struct #align 16 { pthread_rwlock_t :: struct #align(16) {
_: [PTHREAD_RWLOCK_T_SIZE] c.char, _: [PTHREAD_RWLOCK_T_SIZE] c.char,
} }
pthread_barrier_t :: struct #align 16 { pthread_barrier_t :: struct #align(16) {
_: [PTHREAD_BARRIER_T_SIZE] c.char, _: [PTHREAD_BARRIER_T_SIZE] c.char,
} }
pthread_attr_t :: struct #align 16 { pthread_attr_t :: struct #align(16) {
_: [PTHREAD_ATTR_T_SIZE] c.char, _: [PTHREAD_ATTR_T_SIZE] c.char,
} }
pthread_condattr_t :: struct #align 16 { pthread_condattr_t :: struct #align(16) {
_: [PTHREAD_CONDATTR_T_SIZE] c.char, _: [PTHREAD_CONDATTR_T_SIZE] c.char,
} }
pthread_mutexattr_t :: struct #align 16 { pthread_mutexattr_t :: struct #align(16) {
_: [PTHREAD_MUTEXATTR_T_SIZE] c.char, _: [PTHREAD_MUTEXATTR_T_SIZE] c.char,
} }
pthread_rwlockattr_t :: struct #align 16 { pthread_rwlockattr_t :: struct #align(16) {
_: [PTHREAD_RWLOCKATTR_T_SIZE] c.char, _: [PTHREAD_RWLOCKATTR_T_SIZE] c.char,
} }
pthread_barrierattr_t :: struct #align 16 { pthread_barrierattr_t :: struct #align(16) {
_: [PTHREAD_BARRIERATTR_T_SIZE] c.char, _: [PTHREAD_BARRIERATTR_T_SIZE] c.char,
} }
+11 -11
View File
@@ -8,7 +8,7 @@ import "core:c"
// And at the time of writing there is a bug with putting it // And at the time of writing there is a bug with putting it
// as the only field in a struct. // as the only field in a struct.
pthread_t :: distinct u64 pthread_t :: distinct u64
// pthread_t :: struct #align 16 { x: u64 }; // pthread_t :: struct #align(16) { x: u64 };
// NOTE(tetra): Got all the size constants from pthreadtypes-arch.h on my // NOTE(tetra): Got all the size constants from pthreadtypes-arch.h on my
// Linux machine. // Linux machine.
@@ -34,32 +34,32 @@ when size_of(int) == 8 {
PTHREAD_BARRIER_T_SIZE :: 20 PTHREAD_BARRIER_T_SIZE :: 20
} }
pthread_cond_t :: struct #align 16 { pthread_cond_t :: struct #align(16) {
_: [PTHREAD_COND_T_SIZE] c.char, _: [PTHREAD_COND_T_SIZE] c.char,
} }
pthread_mutex_t :: struct #align 16 { pthread_mutex_t :: struct #align(16) {
_: [PTHREAD_MUTEX_T_SIZE] c.char, _: [PTHREAD_MUTEX_T_SIZE] c.char,
} }
pthread_rwlock_t :: struct #align 16 { pthread_rwlock_t :: struct #align(16) {
_: [PTHREAD_RWLOCK_T_SIZE] c.char, _: [PTHREAD_RWLOCK_T_SIZE] c.char,
} }
pthread_barrier_t :: struct #align 16 { pthread_barrier_t :: struct #align(16) {
_: [PTHREAD_BARRIER_T_SIZE] c.char, _: [PTHREAD_BARRIER_T_SIZE] c.char,
} }
pthread_attr_t :: struct #align 16 { pthread_attr_t :: struct #align(16) {
_: [PTHREAD_ATTR_T_SIZE] c.char, _: [PTHREAD_ATTR_T_SIZE] c.char,
} }
pthread_condattr_t :: struct #align 16 { pthread_condattr_t :: struct #align(16) {
_: [PTHREAD_CONDATTR_T_SIZE] c.char, _: [PTHREAD_CONDATTR_T_SIZE] c.char,
} }
pthread_mutexattr_t :: struct #align 16 { pthread_mutexattr_t :: struct #align(16) {
_: [PTHREAD_MUTEXATTR_T_SIZE] c.char, _: [PTHREAD_MUTEXATTR_T_SIZE] c.char,
} }
pthread_rwlockattr_t :: struct #align 16 { pthread_rwlockattr_t :: struct #align(16) {
_: [PTHREAD_RWLOCKATTR_T_SIZE] c.char, _: [PTHREAD_RWLOCKATTR_T_SIZE] c.char,
} }
pthread_barrierattr_t :: struct #align 16 { pthread_barrierattr_t :: struct #align(16) {
_: [PTHREAD_BARRIERATTR_T_SIZE] c.char, _: [PTHREAD_BARRIERATTR_T_SIZE] c.char,
} }
@@ -84,7 +84,7 @@ sched_param :: struct {
sched_priority: c.int, sched_priority: c.int,
} }
sem_t :: struct #align 16 { sem_t :: struct #align(16) {
_: [SEM_T_SIZE] c.char, _: [SEM_T_SIZE] c.char,
} }
+19 -4
View File
@@ -132,6 +132,21 @@ foreign kernel32 {
SetThreadPriority :: proc(thread: HANDLE, priority: c_int) -> BOOL --- SetThreadPriority :: proc(thread: HANDLE, priority: c_int) -> BOOL ---
GetExitCodeThread :: proc(thread: HANDLE, exit_code: ^DWORD) -> BOOL --- GetExitCodeThread :: proc(thread: HANDLE, exit_code: ^DWORD) -> BOOL ---
TerminateThread :: proc(thread: HANDLE, exit_code: DWORD) -> BOOL --- TerminateThread :: proc(thread: HANDLE, exit_code: DWORD) -> BOOL ---
SuspendThread :: proc(hThread: HANDLE) -> DWORD ---
GetProcessAffinityMask :: proc(
hProcess: HANDLE,
lpProcessAffinityMask: PDWORD_PTR,
lpSystemAffinityMask: PDWORD_PTR,
) -> BOOL ---
SetProcessAffinityMask :: proc(
hProcess: HANDLE,
dwProcessAffinityMask: DWORD_PTR,
) -> BOOL ---
SetThreadAffinityMask :: proc(
hThread: HANDLE,
dwThreadAffinityMask: DWORD_PTR,
) -> DWORD_PTR ---
CreateSemaphoreW :: proc(attributes: LPSECURITY_ATTRIBUTES, initial_count, maximum_count: LONG, name: LPCWSTR) -> HANDLE --- CreateSemaphoreW :: proc(attributes: LPSECURITY_ATTRIBUTES, initial_count, maximum_count: LONG, name: LPCWSTR) -> HANDLE ---
ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: LONG, previous_count: ^LONG) -> BOOL --- ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: LONG, previous_count: ^LONG) -> BOOL ---
@@ -389,9 +404,9 @@ foreign kernel32 {
CreatePipe :: proc(hReadPipe, hWritePipe: ^HANDLE, lpPipeAttributes: LPSECURITY_ATTRIBUTES, nSize: DWORD) -> BOOL --- CreatePipe :: proc(hReadPipe, hWritePipe: ^HANDLE, lpPipeAttributes: LPSECURITY_ATTRIBUTES, nSize: DWORD) -> BOOL ---
ConnectNamedPipe :: proc(hNamedPipe: HANDLE, lpOverlapped: LPOVERLAPPED,) -> BOOL --- ConnectNamedPipe :: proc(hNamedPipe: HANDLE, lpOverlapped: LPOVERLAPPED) -> BOOL ---
DisconnectNamedPipe :: proc(hNamedPipe: HANDLE,) -> BOOL --- DisconnectNamedPipe :: proc(hNamedPipe: HANDLE) -> BOOL ---
WaitNamedPipeW :: proc(lpNamedPipeName: LPCWSTR, nTimeOut: DWORD,) -> BOOL --- WaitNamedPipeW :: proc(lpNamedPipeName: LPCWSTR, nTimeOut: DWORD) -> BOOL ---
SetConsoleCtrlHandler :: proc(HandlerRoutine: PHANDLER_ROUTINE, Add: BOOL) -> BOOL --- SetConsoleCtrlHandler :: proc(HandlerRoutine: PHANDLER_ROUTINE, Add: BOOL) -> BOOL ---
GenerateConsoleCtrlEvent :: proc(dwCtrlEvent: DWORD, dwProcessGroupId: DWORD) -> BOOL --- GenerateConsoleCtrlEvent :: proc(dwCtrlEvent: DWORD, dwProcessGroupId: DWORD) -> BOOL ---
@@ -886,7 +901,7 @@ WIN32_MEMORY_REGION_INFORMATION_u_s :: struct {
Bitfield: ULONG, Bitfield: ULONG,
} }
WIN32_MEMORY_REGION_INFORMATION_u_s_Bitfield :: distinct ULONG WIN32_MEMORY_REGION_INFORMATION_u_s_Bitfield :: distinct ULONG
/*bit_field #align align_of(ULONG) { /*bit_field #align(align_of(ULONG)) {
Private : 1-0, Private : 1-0,
MappedDataFile : 2-1, MappedDataFile : 2-1,
MappedImage : 3-2, MappedImage : 3-2,
+8 -2
View File
@@ -1709,6 +1709,12 @@ MONITORINFO :: struct {
} }
LPMONITORINFO :: ^MONITORINFO LPMONITORINFO :: ^MONITORINFO
CCHDEVICENAME :: 32
MONITORINFOEXW :: struct {
using _: MONITORINFO,
szDevice: [CCHDEVICENAME]WCHAR,
}
// SetWindowsHook() codes // SetWindowsHook() codes
WH_MIN :: -1 WH_MIN :: -1
WH_MSGFILTER :: -1 WH_MSGFILTER :: -1
@@ -2469,9 +2475,9 @@ OVERLAPPED :: struct {
} }
OVERLAPPED_ENTRY :: struct { OVERLAPPED_ENTRY :: struct {
lpCompletionKey: c_ulong, lpCompletionKey: ULONG_PTR,
lpOverlapped: ^OVERLAPPED, lpOverlapped: ^OVERLAPPED,
Internal: c_ulong, Internal: ULONG_PTR,
dwNumberOfBytesTransferred: DWORD, dwNumberOfBytesTransferred: DWORD,
} }
+3
View File
@@ -228,6 +228,9 @@ foreign user32 {
SetWindowRgn :: proc(hWnd: HWND, hRgn: HRGN, bRedraw: BOOL) -> int --- SetWindowRgn :: proc(hWnd: HWND, hRgn: HRGN, bRedraw: BOOL) -> int ---
CreateRectRgnIndirect :: proc(lprect: ^RECT) -> HRGN --- CreateRectRgnIndirect :: proc(lprect: ^RECT) -> HRGN ---
GetSystemMetricsForDpi :: proc(nIndex: int, dpi: UINT) -> int --- GetSystemMetricsForDpi :: proc(nIndex: int, dpi: UINT) -> int ---
GetSystemMenu :: proc(hWnd: HWND, bRevert: BOOL) -> HMENU ---
EnableMenuItem :: proc(hMenu: HMENU, uIDEnableItem: UINT, uEnable: UINT) -> BOOL ---
} }
CreateWindowW :: #force_inline proc "stdcall" ( CreateWindowW :: #force_inline proc "stdcall" (
+1 -1
View File
@@ -50,7 +50,7 @@ Example Load:
bytes: u32 bytes: u32
guid_accept_ex := WSAID_ACCEPTEX guid_accept_ex := WSAID_ACCEPTEX
rc := WSAIoctl(listener, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid_accept_ex, size_of(guid_accept_ex), rc := WSAIoctl(listener, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid_accept_ex, size_of(guid_accept_ex),
fn_acceptex, size_of(fn_acceptex), &bytes, nil, nil,) fn_acceptex, size_of(fn_acceptex), &bytes, nil, nil)
assert(rc != windows.SOCKET_ERROR) assert(rc != windows.SOCKET_ERROR)
} }
*/ */
+11 -21
View File
@@ -30,9 +30,12 @@ TS_XML_Options := xml.Options{
parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) { parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) {
context.allocator = allocator context.allocator = allocator
get_str :: proc(val: xml.Value) -> (str: string, err: Error) { get_str :: proc(val: xml.Value, intern: ^strings.Intern) -> (str: string, err: Error) {
v, ok := val.(string) v, ok := val.(string)
if ok { if ok {
if intern != nil {
v, _ = strings.intern_get(intern, v)
}
return v, .None return v, .None
} }
return "", .Bad_Str return "", .Bad_Str
@@ -79,8 +82,7 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
section_name, _ := strings.intern_get(&translation.intern, "") section_name, _ := strings.intern_get(&translation.intern, "")
if !options.merge_sections { if !options.merge_sections {
value_text := get_str(ts.elements[section_name_id].value[0]) or_return section_name = get_str(ts.elements[section_name_id].value[0], &translation.intern) or_return
section_name, _ = strings.intern_get(&translation.intern, value_text)
} }
if section_name not_in translation.k_v { if section_name not_in translation.k_v {
@@ -91,10 +93,7 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
// Find messages in section. // Find messages in section.
nth: int nth: int
for { for {
message_id, message_found := xml.find_child_by_ident(ts, child_id, "message", nth) message_id := xml.find_child_by_ident(ts, child_id, "message", nth) or_break
if !message_found {
break
}
numerus_tag, _ := xml.find_attribute_val_by_key(ts, message_id, "numerus") numerus_tag, _ := xml.find_attribute_val_by_key(ts, message_id, "numerus")
has_plurals := numerus_tag == "yes" has_plurals := numerus_tag == "yes"
@@ -111,13 +110,11 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
return translation, .TS_File_Expected_Translation return translation, .TS_File_Expected_Translation
} }
source := get_str(ts.elements[source_id].value[0]) or_return source := get_str(ts.elements[source_id].value[0], &translation.intern) or_return
source, _ = strings.intern_get(&translation.intern, source)
xlat := "" xlat := ""
if !has_plurals { if !has_plurals {
xlat = get_str(ts.elements[translation_id].value[0]) or_return xlat = get_str(ts.elements[translation_id].value[0], &translation.intern) or_return
xlat, _ = strings.intern_get(&translation.intern, xlat)
} }
if source in section { if source in section {
@@ -131,10 +128,7 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
num_plurals: int num_plurals: int
for { for {
numerus_id, numerus_found := xml.find_child_by_ident(ts, translation_id, "numerusform", num_plurals) numerus_id := xml.find_child_by_ident(ts, translation_id, "numerusform", num_plurals) or_break
if !numerus_found {
break
}
num_plurals += 1 num_plurals += 1
} }
@@ -145,12 +139,8 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
num_plurals = 0 num_plurals = 0
for { for {
numerus_id, numerus_found := xml.find_child_by_ident(ts, translation_id, "numerusform", num_plurals) numerus_id := xml.find_child_by_ident(ts, translation_id, "numerusform", num_plurals) or_break
if !numerus_found { numerus := get_str(ts.elements[numerus_id].value[0], &translation.intern) or_return
break
}
numerus := get_str(ts.elements[numerus_id].value[0]) or_return
numerus, _ = strings.intern_get(&translation.intern, numerus)
section[source][num_plurals] = numerus section[source][num_plurals] = numerus
num_plurals += 1 num_plurals += 1
+2 -3
View File
@@ -775,10 +775,9 @@ gsub_with :: proc(
haystack := haystack haystack := haystack
for { for {
length, err := find_aux(haystack, pattern, 0, false, &captures) length := find_aux(haystack, pattern, 0, false, &captures) or_break
// done // done
if length == 0 || err != .OK { if length == 0 {
break break
} }
+2 -2
View File
@@ -200,7 +200,7 @@ peek :: proc(s: ^Scanner, n := 0) -> (ch: rune) {
ch = s.ch ch = s.ch
if n > 0 { if n > 0 {
prev_s := s^ prev_s := s^
for in 0..<n { for _ in 0..<n {
next(s) next(s)
} }
ch = s.ch ch = s.ch
@@ -214,7 +214,7 @@ peek :: proc(s: ^Scanner, n := 0) -> (ch: rune) {
peek_token :: proc(s: ^Scanner, n := 0) -> (tok: rune) { peek_token :: proc(s: ^Scanner, n := 0) -> (tok: rune) {
assert(n >= 0) assert(n >= 0)
prev_s := s^ prev_s := s^
for in 0..<n { for _ in 0..<n {
tok = scan(s) tok = scan(s)
} }
tok = scan(s) tok = scan(s)
+1 -1
View File
@@ -10,7 +10,7 @@ CAS :: intrinsics.atomic_compare_exchange_strong
// NOTE(tetra): Aligned here because of core/unix/pthread_linux.odin/pthread_t. // NOTE(tetra): Aligned here because of core/unix/pthread_linux.odin/pthread_t.
// Also see core/sys/darwin/mach_darwin.odin/semaphore_t. // Also see core/sys/darwin/mach_darwin.odin/semaphore_t.
Thread_Os_Specific :: struct #align 16 { Thread_Os_Specific :: struct #align(16) {
unix_thread: unix.pthread_t, // NOTE: very large on Darwin, small on Linux. unix_thread: unix.pthread_t, // NOTE: very large on Darwin, small on Linux.
cond: sync.Cond, cond: sync.Cond,
mutex: sync.Mutex, mutex: sync.Mutex,
+33 -37
View File
@@ -86,44 +86,40 @@ generate_encoding_entity_table :: proc() {
nth := 0 nth := 0
for { for {
character_entity, entity_ok := xml.find_child_by_ident(char, "entity", nth) character_entity := xml.find_child_by_ident(char, "entity", nth) or_break
if !entity_ok { break } nth += 1
name := xml.find_attribute_val_by_key(character_entity, "id") or_continue
nth += 1 if len(name) == 0 {
if name, name_ok := xml.find_attribute_val_by_key(character_entity, "id"); name_ok { /*
Invalid name. Skip.
if len(name) == 0 { */
/* continue
Invalid name. Skip.
*/
continue
}
if name == "\"\"" {
printf("%#v\n", char)
printf("%#v\n", character_entity)
}
if len(name) > max_name_length { longest_name = name }
if len(name) < min_name_length { shortest_name = name }
min_name_length = min(min_name_length, len(name))
max_name_length = max(max_name_length, len(name))
e := Entity{
name = name,
codepoint = rune(codepoint),
description = description,
}
if _, seen := entity_map[name]; seen {
continue
}
entity_map[name] = e
append(&names, name)
count += 1
} }
if name == "\"\"" {
printf("%#v\n", char)
printf("%#v\n", character_entity)
}
if len(name) > max_name_length { longest_name = name }
if len(name) < min_name_length { shortest_name = name }
min_name_length = min(min_name_length, len(name))
max_name_length = max(max_name_length, len(name))
e := Entity{
name = name,
codepoint = rune(codepoint),
description = description,
}
if name in entity_map {
continue
}
entity_map[name] = e
append(&names, name)
count += 1
} }
} }
} }
+176 -83
View File
@@ -459,6 +459,27 @@ named_proc_return_parameters :: proc() {
fmt.println("foo2 =", foo2()) // 567 321 fmt.println("foo2 =", foo2()) // 567 321
} }
variadic_procedures :: proc() {
fmt.println("\n# variadic procedures")
sum :: proc(nums: ..int, init_value:= 0) -> (result: int) {
result = init_value
for n in nums {
result += n
}
return
}
fmt.println("sum(()) =", sum())
fmt.println("sum(1, 2) =", sum(1, 2))
fmt.println("sum(1, 2, 3, 4, 5) =", sum(1, 2, 3, 4, 5))
fmt.println("sum(1, 2, 3, 4, 5, init_value = 5) =", sum(1, 2, 3, 4, 5, init_value = 5))
// pass a slice as varargs
odds := []int{1, 3, 5}
fmt.println("odds =", odds)
fmt.println("sum(..odds) =", sum(..odds))
fmt.println("sum(..odds, init_value = 5) =", sum(..odds, init_value = 5))
}
explicit_procedure_overloading :: proc() { explicit_procedure_overloading :: proc() {
fmt.println("\n# explicit procedure overloading") fmt.println("\n# explicit procedure overloading")
@@ -539,7 +560,7 @@ struct_type :: proc() {
{ {
// Structs can tagged with different memory layout and alignment requirements: // Structs can tagged with different memory layout and alignment requirements:
a :: struct #align 4 {} // align to 4 bytes a :: struct #align(4) {} // align to 4 bytes
b :: struct #packed {} // remove padding between fields b :: struct #packed {} // remove padding between fields
c :: struct #raw_union {} // all fields share the same offset (0). This is the same as C's union c :: struct #raw_union {} // all fields share the same offset (0). This is the same as C's union
} }
@@ -1134,7 +1155,7 @@ threading_example :: proc() {
threads := make([dynamic]^thread.Thread, 0, len(prefix_table)) threads := make([dynamic]^thread.Thread, 0, len(prefix_table))
defer delete(threads) defer delete(threads)
for in prefix_table { for _ in prefix_table {
if t := thread.create(worker_proc); t != nil { if t := thread.create(worker_proc); t != nil {
t.init_context = context t.init_context = context
t.user_index = len(threads) t.user_index = len(threads)
@@ -1333,13 +1354,13 @@ partial_switch :: proc() {
{ // union { // union
Foo :: union {int, bool} Foo :: union {int, bool}
f: Foo = 123 f: Foo = 123
switch in f { switch _ in f {
case int: fmt.println("int") case int: fmt.println("int")
case bool: fmt.println("bool") case bool: fmt.println("bool")
case: case:
} }
#partial switch in f { #partial switch _ in f {
case bool: fmt.println("bool") case bool: fmt.println("bool")
} }
} }
@@ -1765,19 +1786,7 @@ range_statements_with_multiple_return_values :: proc() {
data[i] = i32(i*i) data[i] = i32(i*i)
} }
{ { // Manual Style
it := make_my_iterator(data)
for val in my_iterator(&it) {
fmt.println(val)
}
}
{
it := make_my_iterator(data)
for val, idx in my_iterator(&it) {
fmt.println(val, idx)
}
}
{
it := make_my_iterator(data) it := make_my_iterator(data)
for { for {
val, _, cond := my_iterator(&it) val, _, cond := my_iterator(&it)
@@ -1787,6 +1796,25 @@ range_statements_with_multiple_return_values :: proc() {
fmt.println(val) fmt.println(val)
} }
} }
{ // or_break
it := make_my_iterator(data)
loop: for {
val, _ := my_iterator(&it) or_break loop
fmt.println(val)
}
}
{ // first value
it := make_my_iterator(data)
for val in my_iterator(&it) {
fmt.println(val)
}
}
{ // first and second value
it := make_my_iterator(data)
for val, idx in my_iterator(&it) {
fmt.println(val, idx)
}
}
} }
@@ -2024,12 +2052,11 @@ relative_data_types :: proc() {
fmt.println(ptr^) fmt.println(ptr^)
arr := [3]int{1, 2, 3} arr := [3]int{1, 2, 3}
s := arr[:] multi_ptr: #relative(i16) [^]int
rel_slice: #relative(i16) []int multi_ptr = &arr[0]
rel_slice = s fmt.println(multi_ptr)
fmt.println(rel_slice) fmt.println(multi_ptr[:3])
fmt.println(rel_slice[:]) fmt.println(multi_ptr[1])
fmt.println(rel_slice[1])
} }
or_else_operator :: proc() { or_else_operator :: proc() {
@@ -2052,7 +2079,7 @@ or_else_operator :: proc() {
// have optional ok semantics // have optional ok semantics
v: union{int, f64} v: union{int, f64}
i: int i: int
i = v.(int) or_else 123 i = v.(int) or_else 123
i = v.? or_else 123 // Type inference magic i = v.? or_else 123 // Type inference magic
assert(i == 123) assert(i == 123)
@@ -2158,6 +2185,70 @@ or_return_operator :: proc() {
foo_2() foo_2()
} }
or_break_and_or_continue_operators :: proc() {
fmt.println("\n#'or_break' and 'or_continue'")
// The concept of 'or_break' and 'or_continue' is very similar to that of 'or_return'.
// The difference is that unlike 'or_return', the value does not get returned from
// the current procedure but rather discarded if it is 'false' or not 'nil', and then
// the specified branch (i.e. break or_continue).
// The or branch expression can be labelled if a specific statement needs to be used.
Error :: enum {
None,
Something_Bad,
Something_Worse,
The_Worst,
Your_Mum,
}
caller_1 :: proc() -> Error {
return .Something_Bad
}
caller_2 :: proc() -> (int, Error) {
return 123, .Something_Worse
}
caller_3 :: proc() -> (int, int, Error) {
return 123, 345, .None
}
for { // common approach
err := caller_1()
if err != nil {
break
}
}
for { // or_break approach
caller_1() or_break
}
for { // or_break approach with multiple values
n := caller_2() or_break
_ = n
}
loop: for { // or_break approach with named label
n := caller_2() or_break loop
_ = n
}
for { // or_continue
x, y := caller_3() or_continue
_, _ = x, y
break
}
continue_loop: for { // or_continue with named label
x, y := caller_3() or_continue continue_loop
_, _ = x, y
break
}
}
arbitrary_precision_mathematics :: proc() { arbitrary_precision_mathematics :: proc() {
fmt.println("\n# core:math/big") fmt.println("\n# core:math/big")
@@ -2238,98 +2329,98 @@ matrix_type :: proc() {
fmt.println("\n# matrix type") fmt.println("\n# matrix type")
// A matrix is a mathematical type built into Odin. It is a regular array of numbers, // A matrix is a mathematical type built into Odin. It is a regular array of numbers,
// arranged in rows and columns // arranged in rows and columns
{ {
// The following represents a matrix that has 2 rows and 3 columns // The following represents a matrix that has 2 rows and 3 columns
m: matrix[2, 3]f32 m: matrix[2, 3]f32
m = matrix[2, 3]f32{ m = matrix[2, 3]f32{
1, 9, -13, 1, 9, -13,
20, 5, -6, 20, 5, -6,
} }
// Element types of integers, float, and complex numbers are supported by matrices. // Element types of integers, float, and complex numbers are supported by matrices.
// There is no support for booleans, quaternions, or any compound type. // There is no support for booleans, quaternions, or any compound type.
// Indexing a matrix can be used with the matrix indexing syntax // Indexing a matrix can be used with the matrix indexing syntax
// This mirrors othe type usages: type on the left, usage on the right // This mirrors othe type usages: type on the left, usage on the right
elem := m[1, 2] // row 1, column 2 elem := m[1, 2] // row 1, column 2
assert(elem == -6) assert(elem == -6)
// Scalars act as if they are scaled identity matrices // Scalars act as if they are scaled identity matrices
// and can be assigned to matrices as them // and can be assigned to matrices as them
b := matrix[2, 2]f32{} b := matrix[2, 2]f32{}
f := f32(3) f := f32(3)
b = f b = f
fmt.println("b", b) fmt.println("b", b)
fmt.println("b == f", b == f) fmt.println("b == f", b == f)
} }
{ // Matrices support multiplication between matrices { // Matrices support multiplication between matrices
a := matrix[2, 3]f32{ a := matrix[2, 3]f32{
2, 3, 1, 2, 3, 1,
4, 5, 0, 4, 5, 0,
} }
b := matrix[3, 2]f32{ b := matrix[3, 2]f32{
1, 2, 1, 2,
3, 4, 3, 4,
5, 6, 5, 6,
} }
fmt.println("a", a) fmt.println("a", a)
fmt.println("b", b) fmt.println("b", b)
c := a * b c := a * b
#assert(type_of(c) == matrix[2, 2]f32) #assert(type_of(c) == matrix[2, 2]f32)
fmt.tprintln("c = a * b", c) fmt.tprintln("c = a * b", c)
} }
{ // Matrices support multiplication between matrices and arrays { // Matrices support multiplication between matrices and arrays
m := matrix[4, 4]f32{ m := matrix[4, 4]f32{
1, 2, 3, 4, 1, 2, 3, 4,
5, 5, 4, 2, 5, 5, 4, 2,
0, 1, 3, 0, 0, 1, 3, 0,
0, 1, 4, 1, 0, 1, 4, 1,
} }
v := [4]f32{1, 5, 4, 3} v := [4]f32{1, 5, 4, 3}
// treating 'v' as a column vector // treating 'v' as a column vector
fmt.println("m * v", m * v) fmt.println("m * v", m * v)
// treating 'v' as a row vector // treating 'v' as a row vector
fmt.println("v * m", v * m) fmt.println("v * m", v * m)
// Support with non-square matrices // Support with non-square matrices
s := matrix[2, 4]f32{ // [4][2]f32 s := matrix[2, 4]f32{ // [4][2]f32
2, 4, 3, 1, 2, 4, 3, 1,
7, 8, 6, 5, 7, 8, 6, 5,
} }
w := [2]f32{1, 2} w := [2]f32{1, 2}
r: [4]f32 = w * s r: [4]f32 = w * s
fmt.println("r", r) fmt.println("r", r)
} }
{ // Component-wise operations { // Component-wise operations
// if the element type supports it // if the element type supports it
// Not support for '/', '%', or '%%' operations // Not support for '/', '%', or '%%' operations
a := matrix[2, 2]i32{ a := matrix[2, 2]i32{
1, 2, 1, 2,
3, 4, 3, 4,
} }
b := matrix[2, 2]i32{ b := matrix[2, 2]i32{
-5, 1, -5, 1,
9, -7, 9, -7,
} }
c0 := a + b c0 := a + b
c1 := a - b c1 := a - b
c2 := a & b c2 := a & b
@@ -2339,9 +2430,9 @@ matrix_type :: proc() {
// component-wise multiplication // component-wise multiplication
// since a * b would be a standard matrix multiplication // since a * b would be a standard matrix multiplication
c6 := hadamard_product(a, b) c6 := hadamard_product(a, b)
fmt.println("a + b", c0) fmt.println("a + b", c0)
fmt.println("a - b", c1) fmt.println("a - b", c1)
fmt.println("a & b", c2) fmt.println("a & b", c2)
@@ -2350,23 +2441,23 @@ matrix_type :: proc() {
fmt.println("a &~ b", c5) fmt.println("a &~ b", c5)
fmt.println("hadamard_product(a, b)", c6) fmt.println("hadamard_product(a, b)", c6)
} }
{ // Submatrix casting square matrices { // Submatrix casting square matrices
// Casting a square matrix to another square matrix with same element type // Casting a square matrix to another square matrix with same element type
// is supported. // is supported.
// If the cast is to a smaller matrix type, the top-left submatrix is taken. // If the cast is to a smaller matrix type, the top-left submatrix is taken.
// If the cast is to a larger matrix type, the matrix is extended with zeros // If the cast is to a larger matrix type, the matrix is extended with zeros
// everywhere and ones in the diagonal for the unfilled elements of the // everywhere and ones in the diagonal for the unfilled elements of the
// extended matrix. // extended matrix.
mat2 :: distinct matrix[2, 2]f32 mat2 :: distinct matrix[2, 2]f32
mat4 :: distinct matrix[4, 4]f32 mat4 :: distinct matrix[4, 4]f32
m2 := mat2{ m2 := mat2{
1, 3, 1, 3,
2, 4, 2, 4,
} }
m4 := mat4(m2) m4 := mat4(m2)
assert(m4[2, 2] == 1) assert(m4[2, 2] == 1)
assert(m4[3, 3] == 1) assert(m4[3, 3] == 1)
@@ -2374,7 +2465,7 @@ matrix_type :: proc() {
fmt.println("m4", m4) fmt.println("m4", m4)
fmt.println("mat2(m4)", mat2(m4)) fmt.println("mat2(m4)", mat2(m4))
assert(mat2(m4) == m2) assert(mat2(m4) == m2)
b4 := mat4{ b4 := mat4{
1, 2, 0, 0, 1, 2, 0, 0,
3, 4, 0, 0, 3, 4, 0, 0,
@@ -2383,43 +2474,43 @@ matrix_type :: proc() {
} }
fmt.println("b4", matrix_flatten(b4)) fmt.println("b4", matrix_flatten(b4))
} }
{ // Casting non-square matrices { // Casting non-square matrices
// Casting a matrix to another matrix is allowed as long as they share // Casting a matrix to another matrix is allowed as long as they share
// the same element type and the number of elements (rows*columns). // the same element type and the number of elements (rows*columns).
// Matrices in Odin are stored in column-major order, which means // Matrices in Odin are stored in column-major order, which means
// the casts will preserve this element order. // the casts will preserve this element order.
mat2x4 :: distinct matrix[2, 4]f32 mat2x4 :: distinct matrix[2, 4]f32
mat4x2 :: distinct matrix[4, 2]f32 mat4x2 :: distinct matrix[4, 2]f32
x := mat2x4{ x := mat2x4{
1, 3, 5, 7, 1, 3, 5, 7,
2, 4, 6, 8, 2, 4, 6, 8,
} }
y := mat4x2(x) y := mat4x2(x)
fmt.println("x", x) fmt.println("x", x)
fmt.println("y", y) fmt.println("y", y)
} }
// TECHNICAL INFORMATION: the internal representation of a matrix in Odin is stored // TECHNICAL INFORMATION: the internal representation of a matrix in Odin is stored
// in column-major format // in column-major format
// e.g. matrix[2, 3]f32 is internally [3][2]f32 (with different a alignment requirement) // e.g. matrix[2, 3]f32 is internally [3][2]f32 (with different a alignment requirement)
// Column-major is used in order to utilize (SIMD) vector instructions effectively on // Column-major is used in order to utilize (SIMD) vector instructions effectively on
// modern hardware, if possible. // modern hardware, if possible.
// //
// Unlike normal arrays, matrices try to maximize alignment to allow for the (SIMD) vectorization // Unlike normal arrays, matrices try to maximize alignment to allow for the (SIMD) vectorization
// properties whilst keeping zero padding (either between columns or at the end of the type). // properties whilst keeping zero padding (either between columns or at the end of the type).
// //
// Zero padding is a compromise for use with third-party libraries, instead of optimizing for performance. // Zero padding is a compromise for use with third-party libraries, instead of optimizing for performance.
// Padding between columns was not taken even if that would have allowed each column to be loaded // Padding between columns was not taken even if that would have allowed each column to be loaded
// individually into a SIMD register with the correct alignment properties. // individually into a SIMD register with the correct alignment properties.
// //
// Currently, matrices are limited to a maximum of 16 elements (rows*columns), and a minimum of 1 element. // Currently, matrices are limited to a maximum of 16 elements (rows*columns), and a minimum of 1 element.
// This is because matrices are stored as values (not a reference type), and thus operations on them will // This is because matrices are stored as values (not a reference type), and thus operations on them will
// be stored on the stack. Restricting the maximum element count minimizing the possibility of stack overflows. // be stored on the stack. Restricting the maximum element count minimizing the possibility of stack overflows.
// Built-in Procedures (Compiler Level) // Built-in Procedures (Compiler Level)
// transpose(m) // transpose(m)
// transposes a matrix // transposes a matrix
@@ -2434,13 +2525,13 @@ matrix_type :: proc() {
// Example: // Example:
// m := matrix[2, 2]f32{ // m := matrix[2, 2]f32{
// x0, x1, // x0, x1,
// y0, y1, // y0, y1,
// } // }
// array: [4]f32 = matrix_flatten(m) // array: [4]f32 = matrix_flatten(m)
// assert(array == {x0, y0, x1, y1}) // assert(array == {x0, y0, x1, y1})
// conj(x) // conj(x)
// conjugates the elements of a matrix for complex element types only // conjugates the elements of a matrix for complex element types only
// Built-in Procedures (Runtime Level) (all square matrix procedures) // Built-in Procedures (Runtime Level) (all square matrix procedures)
// determinant(m) // determinant(m)
// adjugate(m) // adjugate(m)
@@ -2454,8 +2545,8 @@ matrix_type :: proc() {
main :: proc() { main :: proc() {
/* /*
For More Odin Examples - https://github.com/odin-lang/examples For More Odin Examples - https://github.com/odin-lang/examples
This repository contains examples of how certain things can be accomplished This repository contains examples of how certain things can be accomplished
in idiomatic Odin, allowing you learn its semantics, as well as how to use in idiomatic Odin, allowing you learn its semantics, as well as how to use
parts of the core and vendor package collections. parts of the core and vendor package collections.
*/ */
@@ -2463,6 +2554,7 @@ main :: proc() {
the_basics() the_basics()
control_flow() control_flow()
named_proc_return_parameters() named_proc_return_parameters()
variadic_procedures()
explicit_procedure_overloading() explicit_procedure_overloading()
struct_type() struct_type()
union_type() union_type()
@@ -2492,7 +2584,8 @@ main :: proc() {
relative_data_types() relative_data_types()
or_else_operator() or_else_operator()
or_return_operator() or_return_operator()
or_break_and_or_continue_operators()
arbitrary_precision_mathematics() arbitrary_precision_mathematics()
matrix_type() matrix_type()
} }
} }
+2 -1
View File
@@ -2,9 +2,10 @@
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
set _NO_DEBUG_HEAP=1 set _NO_DEBUG_HEAP=1
set ODIN_IGNORE_MSVC_CHECK=1 set ODIN_IGNORE_MSVC_CHECK=1
+19
View File
@@ -168,6 +168,17 @@ gb_internal gb_inline Slice<T> slice(Slice<T> const &array, isize lo, isize hi)
} }
return out; return out;
} }
template <typename T>
gb_internal gb_inline Slice<T> slice(Array<T> const &array, isize lo, isize hi) {
GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
Slice<T> out = {};
isize len = hi-lo;
if (len > 0) {
out.data = array.data+lo;
out.count = len;
}
return out;
}
template <typename T> template <typename T>
@@ -303,6 +314,14 @@ gb_internal void array_add(Array<T> *array, T const &t) {
array->count++; array->count++;
} }
gb_internal void array_add(Array<char const *> *array, char const *t) {
if (array->capacity < array->count+1) {
array__grow(array, 0);
}
array->data[array->count] = t;
array->count++;
}
template <typename T> template <typename T>
gb_internal T *array_add_and_get(Array<T> *array) { gb_internal T *array_add_and_get(Array<T> *array) {
if (array->count < array->capacity) { if (array->count < array->capacity) {
+79 -7
View File
@@ -123,6 +123,18 @@ struct TargetMetrics {
TargetABIKind abi; TargetABIKind abi;
}; };
enum Subtarget : u32 {
Subtarget_Default,
Subtarget_iOS,
Subtarget_COUNT,
};
gb_global String subtarget_strings[Subtarget_COUNT] = {
str_lit(""),
str_lit("ios"),
};
enum QueryDataSetKind { enum QueryDataSetKind {
QueryDataSet_Invalid, QueryDataSet_Invalid,
@@ -225,9 +237,7 @@ enum VetFlags : u64 {
VetFlag_Style = 1u<<4, // 16 VetFlag_Style = 1u<<4, // 16
VetFlag_Semicolon = 1u<<5, // 32 VetFlag_Semicolon = 1u<<5, // 32
VetFlag_Extra = 1u<<16, VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt,
VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt, // excluding extra
VetFlag_Using = VetFlag_UsingStmt|VetFlag_UsingParam, VetFlag_Using = VetFlag_UsingStmt|VetFlag_UsingParam,
}; };
@@ -245,13 +255,19 @@ u64 get_vet_flag_from_name(String const &name) {
return VetFlag_Style; return VetFlag_Style;
} else if (name == "semicolon") { } else if (name == "semicolon") {
return VetFlag_Semicolon; return VetFlag_Semicolon;
} else if (name == "extra") {
return VetFlag_Extra;
} }
return VetFlag_NONE; return VetFlag_NONE;
} }
enum SanitizerFlags : u32 {
SanitizerFlag_NONE = 0,
SanitizerFlag_Address = 1u<<0,
SanitizerFlag_Memory = 1u<<1,
SanitizerFlag_Thread = 1u<<2,
};
// This stores the information for the specify architecture of this build // This stores the information for the specify architecture of this build
struct BuildContext { struct BuildContext {
@@ -293,6 +309,7 @@ struct BuildContext {
String pdb_filepath; String pdb_filepath;
u64 vet_flags; u64 vet_flags;
u32 sanitizer_flags;
bool has_resource; bool has_resource;
String link_flags; String link_flags;
@@ -354,6 +371,8 @@ struct BuildContext {
isize max_error_count; isize max_error_count;
bool tilde_backend;
u32 cmd_doc_flags; u32 cmd_doc_flags;
Array<String> extra_packages; Array<String> extra_packages;
@@ -583,6 +602,8 @@ gb_global NamedTargetMetrics named_targets[] = {
}; };
gb_global NamedTargetMetrics *selected_target_metrics; gb_global NamedTargetMetrics *selected_target_metrics;
gb_global Subtarget selected_subtarget;
gb_internal TargetOsKind get_target_os_from_string(String str) { gb_internal TargetOsKind get_target_os_from_string(String str) {
for (isize i = 0; i < TargetOs_COUNT; i++) { for (isize i = 0; i < TargetOs_COUNT; i++) {
@@ -1145,7 +1166,7 @@ gb_internal char *token_pos_to_string(TokenPos const &pos) {
return s; return s;
} }
gb_internal void init_build_context(TargetMetrics *cross_target) { gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subtarget) {
BuildContext *bc = &build_context; BuildContext *bc = &build_context;
gb_affinity_init(&bc->affinity); gb_affinity_init(&bc->affinity);
@@ -1240,6 +1261,21 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
bc->metrics = *metrics; bc->metrics = *metrics;
switch (subtarget) {
case Subtarget_Default:
break;
case Subtarget_iOS:
GB_ASSERT(metrics->os == TargetOs_darwin);
if (metrics->arch == TargetArch_arm64) {
bc->metrics.target_triplet = str_lit("arm64-apple-ios");
} else if (metrics->arch == TargetArch_amd64) {
bc->metrics.target_triplet = str_lit("x86_64-apple-ios");
} else {
GB_PANIC("Unknown architecture for darwin");
}
break;
}
bc->ODIN_OS = target_os_names[metrics->os]; bc->ODIN_OS = target_os_names[metrics->os];
bc->ODIN_ARCH = target_arch_names[metrics->arch]; bc->ODIN_ARCH = target_arch_names[metrics->arch];
bc->endian_kind = target_endians[metrics->arch]; bc->endian_kind = target_endians[metrics->arch];
@@ -1350,7 +1386,7 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
bc->optimization_level = -1; // -o:none bc->optimization_level = -1; // -o:none
} }
bc->optimization_level = gb_clamp(bc->optimization_level, -1, 2); bc->optimization_level = gb_clamp(bc->optimization_level, -1, 3);
// ENFORCE DYNAMIC MAP CALLS // ENFORCE DYNAMIC MAP CALLS
bc->dynamic_map_calls = true; bc->dynamic_map_calls = true;
@@ -1707,6 +1743,42 @@ gb_internal bool init_build_paths(String init_filename) {
return false; return false;
} }
if (build_context.sanitizer_flags & SanitizerFlag_Address) {
switch (build_context.metrics.os) {
case TargetOs_windows:
case TargetOs_linux:
case TargetOs_darwin:
break;
default:
gb_printf_err("-sanitize:address is only supported on windows, linux, and darwin\n");
return false;
}
}
if (build_context.sanitizer_flags & SanitizerFlag_Memory) {
switch (build_context.metrics.os) {
case TargetOs_linux:
break;
default:
gb_printf_err("-sanitize:memory is only supported on linux\n");
return false;
}
if (build_context.metrics.os != TargetOs_linux) {
return false;
}
}
if (build_context.sanitizer_flags & SanitizerFlag_Thread) {
switch (build_context.metrics.os) {
case TargetOs_linux:
case TargetOs_darwin:
break;
default:
gb_printf_err("-sanitize:thread is only supported on linux and darwin\n");
return false;
}
}
if (bc->target_features_string.len != 0) { if (bc->target_features_string.len != 0) {
enable_target_feature({}, bc->target_features_string); enable_target_feature({}, bc->target_features_string);
+9 -6
View File
@@ -471,10 +471,10 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
// Integer only // Integer only
case BuiltinProc_simd_add_sat: case BuiltinProc_simd_add_sat:
case BuiltinProc_simd_sub_sat: case BuiltinProc_simd_sub_sat:
case BuiltinProc_simd_and: case BuiltinProc_simd_bit_and:
case BuiltinProc_simd_or: case BuiltinProc_simd_bit_or:
case BuiltinProc_simd_xor: case BuiltinProc_simd_bit_xor:
case BuiltinProc_simd_and_not: case BuiltinProc_simd_bit_and_not:
{ {
Operand x = {}; Operand x = {};
Operand y = {}; Operand y = {};
@@ -1748,7 +1748,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
mode = Addressing_Constant; mode = Addressing_Constant;
value = exact_value_i64(at->EnumeratedArray.count); value = exact_value_i64(at->EnumeratedArray.count);
type = t_untyped_integer; type = t_untyped_integer;
} else if ((is_type_slice(op_type) || is_type_relative_slice(op_type)) && id == BuiltinProc_len) { } else if (is_type_slice(op_type) && id == BuiltinProc_len) {
mode = Addressing_Value; mode = Addressing_Value;
} else if (is_type_dynamic_array(op_type)) { } else if (is_type_dynamic_array(op_type)) {
mode = Addressing_Value; mode = Addressing_Value;
@@ -2120,7 +2120,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
return false; return false;
} }
Type *t = o.type; Type *t = o.type;
if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(operand->type)) { if (t == nullptr || t == t_invalid || is_type_asm_proc(t) || is_type_polymorphic(t)) {
error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name)); error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name));
return false; return false;
} }
@@ -3692,6 +3692,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
case Type_SimdVector: case Type_SimdVector:
operand->type = alloc_type_multi_pointer(base_array_type(base)); operand->type = alloc_type_multi_pointer(base_array_type(base));
break; break;
case Type_Matrix:
operand->type = alloc_type_multi_pointer(base->Matrix.elem);
break;
} }
} }
break; break;
+7 -4
View File
@@ -321,7 +321,14 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr,
gb_string_free(str); gb_string_free(str);
is_distinct = false; is_distinct = false;
} }
} else {
if (is_type_typeid(e->type)) {
error(init_expr, "'typeid' cannot be aliased");
} else if (is_type_any(e->type)) {
error(init_expr, "'any' cannot be aliased");
}
} }
if (!is_distinct) { if (!is_distinct) {
e->type = bt; e->type = bt;
named->Named.base = bt; named->Named.base = bt;
@@ -1329,10 +1336,6 @@ gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, D
is_invalid = true; is_invalid = true;
break; break;
case ProcOverload_Polymorphic: case ProcOverload_Polymorphic:
#if 0
error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in the procedure group '%.*s' which is not allowed", LIT(name), LIT(proc_group_name));
is_invalid = true;
#endif
break; break;
case ProcOverload_ParamCount: case ProcOverload_ParamCount:
case ProcOverload_ParamTypes: case ProcOverload_ParamTypes:
+210 -104
View File
@@ -629,6 +629,9 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
if (operand->mode == Addressing_Type) { if (operand->mode == Addressing_Type) {
if (is_type_typeid(type)) { if (is_type_typeid(type)) {
if (is_type_polymorphic(operand->type)) {
return -1;
}
add_type_info_type(c, operand->type); add_type_info_type(c, operand->type);
return 4; return 4;
} }
@@ -856,8 +859,8 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
} }
} }
if (is_type_relative_slice(dst)) { if (is_type_relative_multi_pointer(dst)) {
i64 score = check_distance_between_types(c, operand, dst->RelativeSlice.slice_type); i64 score = check_distance_between_types(c, operand, dst->RelativeMultiPointer.pointer_type);
if (score >= 0) { if (score >= 0) {
return score+2; return score+2;
} }
@@ -1005,8 +1008,8 @@ gb_internal AstPackage *get_package_of_type(Type *type) {
case Type_RelativePointer: case Type_RelativePointer:
type = type->RelativePointer.pointer_type; type = type->RelativePointer.pointer_type;
continue; continue;
case Type_RelativeSlice: case Type_RelativeMultiPointer:
type = type->RelativeSlice.slice_type; type = type->RelativeMultiPointer.pointer_type;
continue; continue;
} }
return nullptr; return nullptr;
@@ -1118,10 +1121,17 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
LIT(context_name)); LIT(context_name));
break; break;
case Addressing_Type: case Addressing_Type:
error(operand->expr, if (is_type_polymorphic(operand->type)) {
"Cannot assign '%s' which is a type in %.*s", error(operand->expr,
op_type_str, "Cannot assign '%s' which is a polymorphic type in %.*s",
LIT(context_name)); op_type_str,
LIT(context_name));
} else {
error(operand->expr,
"Cannot assign '%s' which is a type in %.*s",
op_type_str,
LIT(context_name));
}
break; break;
default: default:
// TODO(bill): is this a good enough error message? // TODO(bill): is this a good enough error message?
@@ -2452,8 +2462,9 @@ gb_internal void add_comparison_procedures_for_fields(CheckerContext *c, Type *t
add_package_dependency(c, "runtime", "quaternion256_ne"); add_package_dependency(c, "runtime", "quaternion256_ne");
break; break;
case Basic_cstring: case Basic_cstring:
add_package_dependency(c, "runtime", "cstring_to_string"); add_package_dependency(c, "runtime", "cstring_eq");
/*fallthrough*/ add_package_dependency(c, "runtime", "cstring_ne");
break;
case Basic_string: case Basic_string:
add_package_dependency(c, "runtime", "string_eq"); add_package_dependency(c, "runtime", "string_eq");
add_package_dependency(c, "runtime", "string_ne"); add_package_dependency(c, "runtime", "string_ne");
@@ -2611,7 +2622,16 @@ gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Oper
if (!is_type_untyped(x->type)) size = gb_max(size, type_size_of(x->type)); if (!is_type_untyped(x->type)) size = gb_max(size, type_size_of(x->type));
if (!is_type_untyped(y->type)) size = gb_max(size, type_size_of(y->type)); if (!is_type_untyped(y->type)) size = gb_max(size, type_size_of(y->type));
if (is_type_string(x->type) || is_type_string(y->type)) { if (is_type_cstring(x->type) && is_type_cstring(y->type)) {
switch (op) {
case Token_CmpEq: add_package_dependency(c, "runtime", "cstring_eq"); break;
case Token_NotEq: add_package_dependency(c, "runtime", "cstring_ne"); break;
case Token_Lt: add_package_dependency(c, "runtime", "cstring_lt"); break;
case Token_Gt: add_package_dependency(c, "runtime", "cstring_gt"); break;
case Token_LtEq: add_package_dependency(c, "runtime", "cstring_le"); break;
case Token_GtEq: add_package_dependency(c, "runtime", "cstring_gt"); break;
}
} else if (is_type_string(x->type) || is_type_string(y->type)) {
switch (op) { switch (op) {
case Token_CmpEq: add_package_dependency(c, "runtime", "string_eq"); break; case Token_CmpEq: add_package_dependency(c, "runtime", "string_eq"); break;
case Token_NotEq: add_package_dependency(c, "runtime", "string_ne"); break; case Token_NotEq: add_package_dependency(c, "runtime", "string_ne"); break;
@@ -3082,14 +3102,6 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) {
update_untyped_expr_type(c, x->expr, final_type, true); update_untyped_expr_type(c, x->expr, final_type, true);
} }
if (check_vet_flags(x->expr) & VetFlag_Extra) {
if (are_types_identical(x->type, type)) {
gbString str = type_to_string(type);
warning(x->expr, "Unneeded cast to the same type '%s'", str);
gb_string_free(str);
}
}
x->type = type; x->type = type;
} }
@@ -3154,14 +3166,6 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
return false; return false;
} }
if (check_vet_flags(node) & VetFlag_Extra) {
if (are_types_identical(o->type, dst_t)) {
gbString str = type_to_string(dst_t);
warning(o->expr, "Unneeded transmute to the same type '%s'", str);
gb_string_free(str);
}
}
o->expr = node; o->expr = node;
o->type = dst_t; o->type = dst_t;
if (o->mode == Addressing_Constant) { if (o->mode == Addressing_Constant) {
@@ -3663,18 +3667,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
ExactValue b = y->value; ExactValue b = y->value;
if (!is_type_constant_type(x->type)) { if (!is_type_constant_type(x->type)) {
#if 0
gbString xt = type_to_string(x->type);
gbString err_str = expr_to_string(node);
error(op, "Invalid type, '%s', for constant binary expression '%s'", xt, err_str);
gb_string_free(err_str);
gb_string_free(xt);
x->mode = Addressing_Invalid;
#else
// NOTE(bill, 2021-04-21): The above is literally a useless error message.
// Why did I add it in the first place?!
x->mode = Addressing_Value; x->mode = Addressing_Value;
#endif
return; return;
} }
@@ -3817,6 +3810,15 @@ gb_internal void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type,
update_untyped_expr_type(c, ore->expr, type, final); update_untyped_expr_type(c, ore->expr, type, final);
case_end; case_end;
case_ast_node(obe, OrBranchExpr, e);
if (old->value.kind != ExactValue_Invalid) {
// See above note in UnaryExpr case
break;
}
update_untyped_expr_type(c, obe->expr, type, final);
case_end;
case_ast_node(oee, OrElseExpr, e); case_ast_node(oee, OrElseExpr, e);
if (old->value.kind != ExactValue_Invalid) { if (old->value.kind != ExactValue_Invalid) {
// See above note in UnaryExpr case // See above note in UnaryExpr case
@@ -5092,27 +5094,6 @@ gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = fals
return false; return false;
} }
gb_internal isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) {
if (lhs != nullptr && c->decl != nullptr) {
for (isize j = 0; (tuple_index + j) < lhs_count && j < tuple_count; j++) {
Entity *e = lhs[tuple_index + j];
if (e != nullptr) {
DeclInfo *decl = decl_info_of_entity(e);
if (decl != nullptr) {
rw_mutex_shared_lock(&decl->deps_mutex);
rw_mutex_lock(&c->decl->deps_mutex);
for (Entity *dep : decl->deps) {
ptr_set_add(&c->decl->deps, dep);
}
rw_mutex_unlock(&c->decl->deps_mutex);
rw_mutex_shared_unlock(&decl->deps_mutex);
}
}
}
}
return tuple_count;
}
gb_internal bool check_no_copy_assignment(Operand const &o, String const &context) { gb_internal bool check_no_copy_assignment(Operand const &o, String const &context) {
if (o.type && is_type_no_copy(o.type)) { if (o.type && is_type_no_copy(o.type)) {
Ast *expr = unparen_expr(o.expr); Ast *expr = unparen_expr(o.expr);
@@ -5220,6 +5201,31 @@ enum UnpackFlag : u32 {
gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs_arguments, UnpackFlags flags) { gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs_arguments, UnpackFlags flags) {
auto const &add_dependencies_from_unpacking = [](CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) -> isize {
if (lhs == nullptr || c->decl == nullptr) {
return tuple_count;
}
for (isize j = 0; (tuple_index + j) < lhs_count && j < tuple_count; j++) {
Entity *e = lhs[tuple_index + j];
if (e == nullptr) {
continue;
}
DeclInfo *decl = decl_info_of_entity(e);
if (decl == nullptr) {
continue;
}
rw_mutex_shared_lock(&decl->deps_mutex);
rw_mutex_lock(&c->decl->deps_mutex);
for (Entity *dep : decl->deps) {
ptr_set_add(&c->decl->deps, dep);
}
rw_mutex_unlock(&c->decl->deps_mutex);
rw_mutex_shared_unlock(&decl->deps_mutex);
}
return tuple_count;
};
bool allow_ok = (flags & UnpackFlag_AllowOk) != 0; bool allow_ok = (flags & UnpackFlag_AllowOk) != 0;
bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0; bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0;
bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0; bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0;
@@ -5474,6 +5480,8 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
auto variadic_operands = slice(slice_from_array(positional_operands), positional_operand_count, positional_operands.count); auto variadic_operands = slice(slice_from_array(positional_operands), positional_operand_count, positional_operands.count);
bool named_variadic_param = false;
if (named_operands.count != 0) { if (named_operands.count != 0) {
GB_ASSERT(ce->split_args->named.count == named_operands.count); GB_ASSERT(ce->split_args->named.count == named_operands.count);
for_array(i, ce->split_args->named) { for_array(i, ce->split_args->named) {
@@ -5499,6 +5507,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
err = CallArgumentError_ParameterNotFound; err = CallArgumentError_ParameterNotFound;
continue; continue;
} }
if (pt->variadic && param_index == pt->variadic_index) {
named_variadic_param = true;
}
if (visited[param_index]) { if (visited[param_index]) {
if (show_error) { if (show_error) {
error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(name)); error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(name));
@@ -5546,11 +5557,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
o.expr->Ident.token.pos = ast_token(variadic_operands[0].expr).pos; o.expr->Ident.token.pos = ast_token(variadic_operands[0].expr).pos;
Entity *vt = pt->params->Tuple.variables[pt->variadic_index]; Entity *vt = pt->params->Tuple.variables[pt->variadic_index];
if (is_type_polymorphic(vt->type)) { o.type = vt->type;
o.type = alloc_type_slice(default_type(variadic_operands[0].type));
} else {
o.type = vt->type;
}
} else { } else {
dummy_argument_count += 1; dummy_argument_count += 1;
o.type = t_untyped_nil; o.type = t_untyped_nil;
@@ -5704,7 +5711,6 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
if (param_is_variadic) { if (param_is_variadic) {
continue; continue;
} }
score += eval_param_and_score(c, o, e->type, err, param_is_variadic, e, show_error); score += eval_param_and_score(c, o, e->type, err, param_is_variadic, e, show_error);
} }
} }
@@ -7154,6 +7160,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
c->decl->defer_used += 1; c->decl->defer_used += 1;
} }
} }
add_entity_use(c, operand->expr, initial_entity);
} }
if (operand->mode != Addressing_ProcGroup) { if (operand->mode != Addressing_ProcGroup) {
@@ -7361,11 +7368,11 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64
} }
return true; return true;
case Type_RelativeSlice: case Type_RelativeMultiPointer:
{ {
Type *slice_type = base_type(t->RelativeSlice.slice_type); Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type);
GB_ASSERT(slice_type->kind == Type_Slice); GB_ASSERT(pointer_type->kind == Type_MultiPointer);
o->type = slice_type->Slice.elem; o->type = pointer_type->MultiPointer.elem;
if (o->mode != Addressing_Constant) { if (o->mode != Addressing_Constant) {
o->mode = Addressing_Variable; o->mode = Addressing_Variable;
} }
@@ -7753,7 +7760,10 @@ gb_internal void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Op
multi_map_get_all(seen, key, taps); multi_map_get_all(seen, key, taps);
for (isize i = 0; i < count; i++) { for (isize i = 0; i < count; i++) {
TypeAndToken tap = taps[i]; TypeAndToken tap = taps[i];
if (!are_types_identical(operand.type, tap.type)) { Operand to = {};
to.mode = Addressing_Value;
to.type = tap.type;
if (!check_is_assignable_to_with_score(ctx, &to, operand.type, nullptr)) {
continue; continue;
} }
@@ -7796,20 +7806,8 @@ gb_internal void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, TokenKind u
break; break;
} }
bool found = false; v.value = exact_value_i64(vi);
for (Entity *f : bt->Enum.fields) { add_constant_switch_case(ctx, seen, v);
GB_ASSERT(f->kind == Entity_Constant);
i64 fv = exact_value_to_i64(f->Constant.value);
if (fv == vi) {
found = true;
break;
}
}
if (found) {
v.value = exact_value_i64(vi);
add_constant_switch_case(ctx, seen, v);
}
} }
} else { } else {
add_constant_switch_case(ctx, seen, lhs); add_constant_switch_case(ctx, seen, lhs);
@@ -7931,7 +7929,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n
// NOTE(bill, 2023-01-30): Allow for expression like this: // NOTE(bill, 2023-01-30): Allow for expression like this:
// x: union{f32} = f32(123) if cond else nil // x: union{f32} = f32(123) if cond else nil
if (type_hint && !is_type_any(type_hint) && !ternary_compare_types(x.type, y.type)) { if (type_hint && !is_type_any(type_hint)) {
if (check_is_assignable_to(c, &x, type_hint) && check_is_assignable_to(c, &y, type_hint)) { if (check_is_assignable_to(c, &x, type_hint) && check_is_assignable_to(c, &y, type_hint)) {
check_cast(c, &x, type_hint); check_cast(c, &x, type_hint);
check_cast(c, &y, type_hint); check_cast(c, &y, type_hint);
@@ -8188,6 +8186,104 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no
return Expr_Expr; return Expr_Expr;
} }
gb_internal ExprKind check_or_branch_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
ast_node(be, OrBranchExpr, node);
String name = be->token.string;
Operand x = {};
check_multi_expr_with_type_hint(c, &x, be->expr, type_hint);
if (x.mode == Addressing_Invalid) {
o->mode = Addressing_Value;
o->type = t_invalid;
o->expr = node;
return Expr_Expr;
}
Type *left_type = nullptr;
Type *right_type = nullptr;
check_or_return_split_types(c, &x, name, &left_type, &right_type);
add_type_and_value(c, be->expr, x.mode, x.type, x.value);
if (right_type == nullptr) {
check_or_else_expr_no_value_error(c, name, x, type_hint);
} else {
if (is_type_boolean(right_type) || type_has_nil(right_type)) {
// okay
} else {
gbString s = type_to_string(right_type);
error(node, "'%.*s' requires a boolean or nil-able type, got %s", s);
gb_string_free(s);
}
}
o->expr = node;
o->type = left_type;
if (left_type != nullptr) {
o->mode = Addressing_Value;
} else {
o->mode = Addressing_NoValue;
}
if (c->curr_proc_sig == nullptr) {
error(node, "'%.*s' can only be used within a procedure", LIT(name));
}
Ast *label = be->label;
switch (be->token.kind) {
case Token_or_break:
if ((c->stmt_flags & Stmt_BreakAllowed) == 0 && label == nullptr) {
error(be->token, "'%.*s' only allowed in non-inline loops or 'switch' statements", LIT(name));
}
break;
case Token_or_continue:
if ((c->stmt_flags & Stmt_ContinueAllowed) == 0 && label == nullptr) {
error(be->token, "'%.*s' only allowed in non-inline loops", LIT(name));
}
break;
}
if (label != nullptr) {
if (label->kind != Ast_Ident) {
error(label, "A branch statement's label name must be an identifier");
return Expr_Expr;
}
Ast *ident = label;
String name = ident->Ident.token.string;
Operand o = {};
Entity *e = check_ident(c, &o, ident, nullptr, nullptr, false);
if (e == nullptr) {
error(ident, "Undeclared label name: %.*s", LIT(name));
return Expr_Expr;
}
add_entity_use(c, ident, e);
if (e->kind != Entity_Label) {
error(ident, "'%.*s' is not a label", LIT(name));
return Expr_Expr;
}
Ast *parent = e->Label.parent;
GB_ASSERT(parent != nullptr);
switch (parent->kind) {
case Ast_BlockStmt:
case Ast_IfStmt:
case Ast_SwitchStmt:
if (be->token.kind != Token_or_break) {
error(label, "Label '%.*s' can only be used with 'or_break'", LIT(e->token.string));
}
break;
case Ast_RangeStmt:
case Ast_ForStmt:
if ((be->token.kind != Token_or_break) && (be->token.kind != Token_or_continue)) {
error(label, "Label '%.*s' can only be used with 'or_break' and 'or_continue'", LIT(e->token.string));
}
break;
}
}
return Expr_Expr;
}
gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<Ast *> const &elems, Operand *o, Type *type, bool &is_constant) { gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<Ast *> const &elems, Operand *o, Type *type, bool &is_constant) {
Type *bt = base_type(type); Type *bt = base_type(type);
@@ -9497,14 +9593,14 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
if (is_const) { if (is_const) {
if (is_type_array(t)) { if (is_type_array(t)) {
// OKay // Okay
} else if (is_type_slice(t)) { } else if (is_type_slice(t)) {
// Okay // Okay
} else if (is_type_enumerated_array(t)) { } else if (is_type_enumerated_array(t)) {
// Okay // Okay
} else if (is_type_string(t)) { } else if (is_type_string(t)) {
// Okay // Okay
} else if (is_type_relative_slice(t)) { } else if (is_type_relative_multi_pointer(t)) {
// Okay // Okay
} else if (is_type_matrix(t)) { } else if (is_type_matrix(t)) {
// Okay // Okay
@@ -9642,17 +9738,9 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
} }
break; break;
case Type_RelativeSlice: case Type_RelativeMultiPointer:
valid = true; valid = true;
o->type = t->RelativeSlice.slice_type; o->type = type_deref(o->type);
if (o->mode != Addressing_Variable) {
gbString str = expr_to_string(node);
error(node, "Cannot relative slice '%s', as value is not addressable", str);
gb_string_free(str);
o->mode = Addressing_Invalid;
o->expr = node;
return kind;
}
break; break;
case Type_EnumeratedArray: case Type_EnumeratedArray:
@@ -9731,8 +9819,19 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
x[i:n] -> []T x[i:n] -> []T
*/ */
o->type = alloc_type_slice(t->MultiPointer.elem); o->type = alloc_type_slice(t->MultiPointer.elem);
} else if (t->kind == Type_RelativeMultiPointer && se->high != nullptr) {
/*
x[:] -> [^]T
x[i:] -> [^]T
x[:n] -> []T
x[i:n] -> []T
*/
Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type);
GB_ASSERT(pointer_type->kind == Type_MultiPointer);
o->type = alloc_type_slice(pointer_type->MultiPointer.elem);
} }
o->mode = Addressing_Value; o->mode = Addressing_Value;
if (is_type_string(t) && max_count >= 0) { if (is_type_string(t) && max_count >= 0) {
@@ -9939,6 +10038,10 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
return check_or_return_expr(c, o, node, type_hint); return check_or_return_expr(c, o, node, type_hint);
case_end; case_end;
case_ast_node(re, OrBranchExpr, node);
return check_or_branch_expr(c, o, node, type_hint);
case_end;
case_ast_node(cl, CompoundLit, node); case_ast_node(cl, CompoundLit, node);
kind = check_compound_literal(c, o, node, type_hint); kind = check_compound_literal(c, o, node, type_hint);
case_end; case_end;
@@ -10005,14 +10108,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
return kind; return kind;
} }
if (type_hint) { if (type_hint) {
Type *type = type_of_expr(ac->expr);
check_cast(c, o, type_hint); check_cast(c, o, type_hint);
if (is_type_typed(type) && are_types_identical(type, type_hint)) {
if (check_vet_flags(node) & VetFlag_Extra) {
error(node, "Redundant 'auto_cast' applied to expression");
}
}
} }
o->expr = node; o->expr = node;
return Expr_Expr; return Expr_Expr;
@@ -10505,6 +10601,16 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
str = gb_string_appendc(str, " or_return"); str = gb_string_appendc(str, " or_return");
case_end; case_end;
case_ast_node(oe, OrBranchExpr, node);
str = write_expr_to_string(str, oe->expr, shorthand);
str = gb_string_append_rune(str, ' ');
str = string_append_token(str, oe->token);
if (oe->label) {
str = gb_string_append_rune(str, ' ');
str = write_expr_to_string(str, oe->label, shorthand);
}
case_end;
case_ast_node(pe, ParenExpr, node); case_ast_node(pe, ParenExpr, node);
str = gb_string_append_rune(str, '('); str = gb_string_append_rune(str, '(');
str = write_expr_to_string(str, pe->expr, shorthand); str = write_expr_to_string(str, pe->expr, shorthand);
+7 -2
View File
@@ -102,8 +102,13 @@ gb_internal void check_stmt_list(CheckerContext *ctx, Slice<Ast *> const &stmts,
new_flags |= Stmt_FallthroughAllowed; new_flags |= Stmt_FallthroughAllowed;
} }
u32 prev_stmt_flags = ctx->stmt_flags;
ctx->stmt_flags = new_flags;
check_stmt(ctx, n, new_flags); check_stmt(ctx, n, new_flags);
ctx->stmt_flags = prev_stmt_flags;
if (i+1 < max_non_constant_declaration) { if (i+1 < max_non_constant_declaration) {
switch (n->kind) { switch (n->kind) {
case Ast_ReturnStmt: case Ast_ReturnStmt:
@@ -1893,7 +1898,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
} }
if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) { if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) {
error(e->token, "@(thread_local) is not supported for this target platform"); // error(e->token, "@(thread_local) is not supported for this target platform");
} }
@@ -1983,7 +1988,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
for (auto const &entry : scope->elements) { for (auto const &entry : scope->elements) {
Entity *f = entry.value; Entity *f = entry.value;
if (f->kind == Entity_Variable) { if (f->kind == Entity_Variable) {
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr); Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, e->identifier);
uvar->flags |= (e->flags & EntityFlag_Value); uvar->flags |= (e->flags & EntityFlag_Value);
Entity *prev = scope_insert(ctx->scope, uvar); Entity *prev = scope_insert(ctx->scope, uvar);
if (prev != nullptr) { if (prev != nullptr) {

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