Compare commits

...

218 Commits

Author SHA1 Message Date
gingerBill aa796a1032 v0.11.1 2019-11-12 21:20:40 +00:00
gingerBill 5bf71ba75c big_int addition overflow rules 2019-11-11 22:47:25 +00:00
gingerBill 967981aacd Add -show-more-timings 2019-11-10 21:49:02 +00:00
gingerBill 33d05a07de Fix big_int_or and big_int_xor 2019-11-10 20:06:04 +00:00
gingerBill 8da8301b09 Fix big subtraction for very large numbers on edges of overflow. 2019-11-10 19:55:26 +00:00
gingerBill 536cceeef9 Add intrinsics.type_is_unsigned 2019-11-10 18:51:21 +00:00
gingerBill 098684a6fe Add 128-bit random procedures to package math/rand 2019-11-10 18:47:16 +00:00
gingerBill 2ef7bfc06e Remove debug message 2019-11-09 10:45:03 +00:00
gingerBill 7bfdb4f9f4 Fix Compile time assert on non-constant boolean parameters #467 2019-11-09 10:44:42 +00:00
gingerBill 0a35b13411 Fix inline for bug for #468 2019-11-09 10:24:27 +00:00
gingerBill dacfc9de15 Fix //+build for ! e.g. //+build !windows amd64, linux !amd64 2019-11-05 20:09:09 +00:00
gingerBill 689aa4d734 Fix //+build system 2019-11-05 20:02:11 +00:00
gingerBill 8a46b493fd Fix Slice passed incorrectly in LLVM IR to procedure called via procedure pointer #465 2019-11-05 19:40:08 +00:00
gingerBill 86abdc0603 Merge branch 'master' of https://github.com/odin-lang/Odin 2019-11-05 19:37:30 +00:00
gingerBill a634444f99 Fix "Polymorphic parameter declared in return type doesn't compile #464" by giving a conversion error (code wasn't handling polymorphic result types as intended) 2019-11-05 19:37:19 +00:00
vassvik 04a25b11ad Fix incorrect math.linalg.cross3 indices. 2019-11-04 17:39:26 +01:00
gingerBill 40546fbde2 Use runtime.mem_copy in package me 2019-11-03 19:59:41 +00:00
gingerBill c1176c2bcb Fix typeid comparison bug; Add extra messages for pointer address errors 2019-11-03 19:49:21 +00:00
gingerBill 57853fe1b1 Add SOA Struct Layout (experimental) to demo.odin 2019-11-03 12:52:13 +00:00
gingerBill 013b3b9fb3 Fix for -vet 2019-11-03 11:42:00 +00:00
gingerBill dc0f04e53b Fix typo in fmt 2019-11-03 00:50:47 +00:00
gingerBill 40606d9272 Fix fmt printing of anonymous SOA structs 2019-11-03 00:47:27 +00:00
gingerBill ebf7926fa4 SOA support of Structures and Arrays; Runtime information for SOA structs; fmt printing support for SOA structs 2019-11-03 00:32:22 +00:00
gingerBill dfb3101ecf SOA Struct support intrinsics.soa_struct 2019-11-02 21:08:51 +00:00
gingerBill e3d3a81617 multivalued procedure calls allows in for in to allow a pseudo-iterator; @thread_local for variables in procedure 2019-11-02 16:36:46 +00:00
gingerBill dbdbbcd60f Fix range in statement bug caused by incorrectly assigned addressing mode #461 2019-11-02 10:57:42 +00:00
gingerBill f9aaff99c6 Fix linalg.mul; add linalg.Matrix1xN 2019-11-02 10:30:11 +00:00
gingerBill 57565b78a6 v0.11.0 2019-11-01 19:45:39 +00:00
gingerBill b5b085914a Merge pull request #404 from hazeycode/master
Impl time for macOS
2019-11-01 19:44:50 +00:00
Chris Heyes 044e64beb0 Add missing foreign import to time_darwin 2019-11-01 19:39:26 +00:00
Chris Heyes adca5b57cd Move time code from os to time package 2019-11-01 19:33:48 +00:00
gingerBill 3b898e5224 Add @force to foreign import 2019-11-01 19:26:22 +00:00
Chris Heyes 153e7525b5 Merge remote-tracking branch 'upstream/master' 2019-11-01 19:18:33 +00:00
gingerBill 44a303e577 Add dummy packages purely for documentation of builtin and intrinsics 2019-11-01 19:00:23 +00:00
gingerBill d63878d0dd Merge pull request #437 from nakst/master
updated os_essence.odin
2019-11-01 10:20:29 +00:00
gingerBill a20c31d6b5 Fix polymorphic record parameter determination bug caused by polymorphic constants not being handled correctly #447 2019-10-31 22:58:38 +00:00
gingerBill 560bdc339b Fix stack overflow bug caused by polymorphic record with polymorphic constant parameters. #447
DOES NOT FIX THE UNDERLYING BUG
2019-10-31 22:39:12 +00:00
gingerBill 01dfb1dac8 Fix double calling of lhs of logical binary expressions 2019-10-31 20:17:50 +00:00
gingerBill ee8d3e03f8 Delay determination of procedure abi types until as late as possible to prevent type undetermination in self-referential data types #454 2019-10-31 18:25:39 +00:00
gingerBill 4aad45e3e7 Merge pull request #453 from kevinw/master
Remove unused variables in utf8.odin.
2019-10-29 11:47:37 +00:00
gingerBill fe5c642d9f Fix runtime.cstring_len 2019-10-29 08:47:05 +00:00
Kevin Watters b5fdb3f855 Remove unused variables in utf8.odin. 2019-10-28 11:13:47 -04:00
gingerBill 416ff149bd Fix procedure group "best fit" algorithm for polymorphic procedures 2019-10-27 19:42:21 +00:00
gingerBill 233c6e2d3a Merge branch 'master' of https://github.com/odin-lang/Odin 2019-10-27 18:43:53 +00:00
gingerBill a29a6d9285 Fix typos in package linalg; Fix norm_float64 in package rand 2019-10-27 18:43:40 +00:00
Mikkel Hjortshøj a7a31e4c23 Set CI shell on windows to cmd.exe 2019-10-27 18:12:23 +01:00
Mikkel Hjortshøj 72cad591bd Update ci.yml 2019-10-27 18:07:14 +01:00
Mikkel Hjortshøj 684bf7aa61 Update ci.yml 2019-10-27 18:04:14 +01:00
Mikkel Hjortshøj d760b95e4f Update ci.yml 2019-10-27 18:02:39 +01:00
gingerBill 5e81fc72b9 New package math and package math/linalg 2019-10-27 10:35:35 +00:00
gingerBill 0977ac111a Fix typo in package utf8; add wchar_t to package c 2019-10-27 08:34:20 +00:00
gingerBill 2db16d6a32 Add for package utf8: rune_at_pos, rune_string_at_pos, rune_at, rune_offset 2019-10-26 15:05:36 +01:00
gingerBill 5aa46d31b2 Move package decimal to be a subpackage of package strconv 2019-10-26 14:46:21 +01:00
gingerBill 14e8b299b7 Fix slice and dynamic array lengths determined from ranged compound literals 2019-10-26 14:43:06 +01:00
gingerBill c7cb754514 Fix typos 2019-10-26 14:37:27 +01:00
gingerBill a5e42a0465 Add ranged_fields_for_array_compound_literals 2019-10-26 14:36:28 +01:00
gingerBill d808f9eccf Add range_cache.cpp 2019-10-26 14:29:04 +01:00
gingerBill 1734eb949f Update utf8.accept_sizes to use ranged fields 2019-10-26 14:18:38 +01:00
gingerBill 7fae890ef9 Allow ranges for array-like compound literals 2019-10-26 14:06:29 +01:00
gingerBill 94879ed149 Fix Compiler assertion when applying using to _ procedure parameter. #451 2019-10-26 12:14:04 +01:00
gingerBill 2c75fe2314 Allow for cycles in record polymorphic parameters but not in actualized fields 2019-10-26 11:50:42 +01:00
gingerBill 1da0668653 Add utf8.rune_index 2019-10-26 11:50:01 +01:00
gingerBill c60fb10a6a Move old demos and old stuff to /misc 2019-10-26 10:40:17 +01:00
gingerBill 7140f42915 Modify runtime to reduce dependencies on other packages 2019-10-23 21:43:13 +01:00
gingerBill ad92fbfd4e Merge branch 'master' of https://github.com/odin-lang/Odin 2019-10-23 21:42:42 +01:00
gingerBill 1416946757 Add token.odin 2019-10-23 21:42:28 +01:00
gingerBill 6a8c4ee04c Merge pull request #450 from ThisDrunkDane/master
Setup Github Actions instead of Travis and Appveyor
2019-10-21 22:17:05 +01:00
Mikkel Hjortshøj 516df9123d Update README.md 2019-10-21 23:08:16 +02:00
Mikkel Hjortshøj 818d6dbbea Update README.md with new CI badge 2019-10-21 23:05:18 +02:00
Mikkel Hjortshoej 286c5b7b24 Remove old CI runners 2019-10-21 23:01:32 +02:00
Mikkel Hjortshøj c0e8113f6f Add github CI action 2019-10-21 23:00:24 +02:00
gingerBill e15dfa8eb6 Fix missing check for zero elements 2019-10-20 18:26:30 +01:00
gingerBill f12ded54f2 Support for named indices for array-like compound literals {3 = a, 1 = b} 2019-10-20 13:11:28 +01:00
gingerBill b4951c9b39 Merge branch 'master' of https://github.com/odin-lang/Odin 2019-10-20 10:50:30 +01:00
gingerBill 9f0a28017d Fix typo in string_to_string16 #444 2019-10-20 10:50:18 +01:00
Mikkel Hjortshøj d7c8a3a9dd Merge pull request #445 from Tetralux/patch-2
Clarify that you can pass a directory to `odin build`
2019-10-19 18:57:23 +02:00
Tetralux 10b109e25f Clarify that you can pass a directory to odin build
Changes the usage information to this:
```
D:\Software\odin\odin.exe is a tool for managing Odin source code
Usage:
        D:\Software\odin\odin.exe command [arguments]
Commands:
        build     compile .odin file, or directory of .odin files, as an executable.
                  one must contain the program's entry point, all must be in the same package.
        run       same as 'build', but also then runs the newly compiled executable.
        check     parse and type check .odin file
        query     parse, type check, and output a .json file containing information about the program
        docs      generate documentation for a .odin file
        version   print version
```
2019-10-19 17:55:05 +01:00
gingerBill 2afe4bea67 Add instrincs.type_is_valid_map_key 2019-10-15 22:43:04 +01:00
gingerBill 12ae5ed09e Fix missing typeid conversion case for variadic parameters 2019-10-15 20:47:27 +01:00
gingerBill 0bdc3b4f21 Fix Values coerce to typeid #443 2019-10-15 17:54:37 +01:00
gingerBill eaabb888d4 Update Odin Logo 2019-10-15 17:42:55 +01:00
gingerBill b53fe14c22 Change error to syntax_error in parser 2019-10-13 16:06:41 +01:00
gingerBill 45683703ea Fix System V for certain structs 2019-10-13 14:29:56 +01:00
gingerBill 03053a18ce Fix IR generation bug for nested foreign procedure declaration 2019-10-13 12:51:47 +01:00
gingerBill 2a6d9e8927 #panic; Minor change to demo.odin; Fix #assert bug at file scope 2019-10-13 12:38:23 +01:00
gingerBill fa81061db0 Minor fix to Odin types with System V ABI 2019-10-10 21:50:20 +01:00
gingerBill 39b3c8c80f Update System V ABI to for more Odin types 2019-10-10 21:39:46 +01:00
gingerBill 3139151935 Minor fix to systemv_distribute_struct_fields 2019-10-10 21:24:32 +01:00
gingerBill 672a8f5dbd Add Odin types for System V ABI 2019-10-10 21:13:06 +01:00
gingerBill 8672ff1c55 Fix typo in System V ABI determination 2019-10-10 20:57:31 +01:00
gingerBill abfa894566 Fix general IR parameter case 2019-10-10 20:52:07 +01:00
gingerBill 5b52fed268 Correct (experimental) System V AMD64 ABI support 2019-10-10 20:41:16 +01:00
Mikkel Hjortshøj 94a638b436 Update README.md
Remove license badge (Github shows it themselves now) and add discord badge
2019-10-10 11:10:10 +02:00
gingerBill 1b8c3ca22a Fix typos and make demo work with -vet 2019-10-08 20:28:45 +01:00
gingerBill 71b32ae117 Update demo.odin 2019-10-06 19:20:00 +01:00
gingerBill 939459b635 Change implicit semicolon rules for record types within procedure bodies; Update package odin/* 2019-10-06 19:16:55 +01:00
gingerBill 562b518394 Change print*_err to eprint* in core library 2019-10-06 18:54:29 +01:00
gingerBill d62503d031 Change precedence for in and notin to match + - | ~ 2019-10-06 18:14:02 +01:00
gingerBill 4e8a801b35 strings.split; strings.index; eprint* over print*_err; 2019-10-06 18:13:15 +01:00
gingerBill e1b711b3b3 Update demo.odin with more information 2019-10-06 15:07:16 +01:00
gingerBill 6c69e8c043 Make typeid semantics consistent across variables and constants 2019-10-06 14:55:25 +01:00
gingerBill 7fa2d25eea Fix #complete switch with pointer case doesn't compile #416 2019-10-05 10:22:41 +01:00
gingerBill dae514a2c9 Fix Using any in if statement asserts compiler #441 2019-10-05 09:40:05 +01:00
gingerBill 068993a819 Remove os_osx.odin 2019-10-01 20:55:15 +01:00
gingerBill 66ae4e5afc Change ODIN_OS string for osx from "osx" to "darwin" to allow for other platforms 2019-10-01 20:38:50 +01:00
gingerBill 218d1131e8 Change how foreign imports work for mac 2019-09-29 09:25:33 +01:00
gingerBill f4f6e9ad49 Fix -debug crash on windows caused by missing debug info for files. 2019-09-25 21:07:56 +01:00
gingerBill 48ab7f876c Fix Implicit Selector Expressions do not work for parameteric struct parameters. #438 2019-09-25 20:52:47 +01:00
nakst 1e53a6fa96 updated os_essence.odin 2019-09-18 16:19:19 +01:00
gingerBill 4cef160c87 Merge branch 'master' of https://github.com/odin-lang/Odin 2019-09-17 19:47:13 +01:00
gingerBill 68582c5ad1 Add suggestions to errors on casts and assignments. 2019-09-17 19:47:04 +01:00
gingerBill a9a2dafca5 Merge pull request #430 from nakst/master
New Essence OS layer; cross-compiling improvements
2019-09-09 14:39:35 +01:00
gingerBill da3467c25f Merge pull request #434 from odin-lang/ThisDrunkDane-patch-1
Make `odin run` return the process exit code
2019-09-08 20:28:10 +01:00
gingerBill 5fc42bf9c9 Update demo.odin 2019-09-08 19:15:12 +01:00
gingerBill 42bbd31df1 Disallow where clauses on non-polymorphic records 2019-09-08 19:03:57 +01:00
gingerBill c7cc38b7d8 Remove assert 2019-09-08 15:47:57 +01:00
gingerBill 4afc78efc6 Add where clauses to struct and union 2019-09-08 12:12:41 +01:00
Mikkel Hjortshøj bc34083c9c Also return on unix 2019-09-08 01:10:54 +02:00
Mikkel Hjortshøj 08dd8414c1 Make odin run return the process exit code 2019-09-08 01:09:04 +02:00
gingerBill d54255505a Fix Compiler does not complain about missing semicolon #433 2019-09-04 18:10:02 +01:00
gingerBill d4914c3546 Fix Ir panic on using append() from within anonymous function #432 2019-09-04 18:06:02 +01:00
gingerBill 772c8779fa Clean up thread pool code 2019-09-03 22:11:21 +01:00
gingerBill c92b2e9612 Fix semaphore posting 2019-09-03 21:17:46 +01:00
gingerBill 1af143b749 Fix debug mode for build.bat 2019-09-02 21:16:17 +01:00
gingerBill 1370c10d1b Fix Converting addresses to function pointers produces llvm-opt error #431 2019-09-02 18:59:07 +01:00
gingerBill 1348d8a8cd Improve thread pool (volatile hints, etc) 2019-09-02 18:49:23 +01:00
gingerBill 495aaacb81 Fix build.bat 2019-09-02 18:35:00 +01:00
nakst 22e982c8fb New Essence OS layer; cross-compiling improvements 2019-09-02 16:46:50 +01:00
gingerBill 6d614ef07c Remove thread naming on thread pool 2019-09-01 23:16:01 +01:00
gingerBill 723f351a6d Remove custom allocator for thread pool 2019-09-01 23:13:29 +01:00
gingerBill c93872cc13 Thread pool fixes 2019-09-01 22:57:53 +01:00
gingerBill 97dece15d7 Minor changes 2019-09-01 22:18:55 +01:00
gingerBill 657103c4cf ThreadPool for the parser 2019-09-01 20:02:39 +01:00
gingerBill b9d3129fb3 where clauses for procedure literals 2019-08-31 20:13:28 +01:00
gingerBill b311540b16 Make require_results an attribute rather than a suffix tag for procedures 2019-08-31 14:48:56 +01:00
gingerBill 07ced1cf0e Fix variable dependency ordering issues caused by procedure literals 2019-08-31 11:12:41 +01:00
gingerBill a1d4ea7718 Merge pull request #425 from thebirk/parser-threading
Fixed parser creating a new thread for each file.
2019-08-29 20:44:48 +01:00
thebirk f921a91fc8 Properly removed the semaphore. 2019-08-29 20:35:12 +02:00
thebirk 4dade34603 Removed unused semaphore on Parser. 2019-08-29 20:34:09 +02:00
thebirk d76249d90b Cleaned up parse_packages and the worker proc. 2019-08-29 20:27:38 +02:00
gingerBill d118fc569a Add intrinsincs.type_is_quaternion 2019-08-29 16:45:36 +01:00
gingerBill 2dc39a5cbd Improve demo.odin 2019-08-29 15:25:46 +01:00
gingerBill c89fc35e94 Fix global variable initialization ordering
(related to #427)
2019-08-29 14:36:42 +01:00
gingerBill 614d209824 Add debug information for quaternion types (fixes #428) 2019-08-29 10:39:03 +01:00
gingerBill f1a7b31209 Fix nested raw_union with using #428 2019-08-28 13:34:55 +01:00
thebirk 6a8b3fee38 Removed gb_thread_set_name because it segfaults on linux. 2019-08-26 20:23:52 +02:00
thebirk 4551521b2c Im just trying things at this point, Bill should just squash this PR at merge time ;) 2019-08-26 19:51:33 +02:00
thebirk 97dfcffa76 Fixed error where the parser would end early. 2019-08-26 19:09:52 +02:00
gingerBill 6d3feb4531 Fix typo in tokenizer (no actual bug) 2019-08-26 16:18:26 +01:00
thebirk c44d25d14f Fixed parser creating a new thread for each file. 2019-08-26 16:47:41 +02:00
gingerBill 25dd00cd0b Add complex/quaternion raw layouts to mem/raw.odin 2019-08-26 14:40:04 +01:00
gingerBill 01c10aa944 inline for loops (only for 'in' based for loops) 2019-08-26 13:54:35 +01:00
gingerBill 4908d1ebdd Update odin_tokenizer to support quaternion literals 2019-08-26 11:56:04 +01:00
gingerBill 7bc146e6fd Built-in Quaternions (Not just an April Fool's Joke any more) 2019-08-26 11:33:05 +01:00
gingerBill 59ab51acec Fix typo 2019-08-23 11:54:23 +01:00
gingerBill cf23954297 Improve #assert to show the procedure and signature it was called with; Allow the ability to print ExactValue correct now. 2019-08-23 11:51:04 +01:00
gingerBill d1cc6534cd Remove the rule that made any declaration prefixed with an underscore private to that package. 2019-08-23 10:32:05 +01:00
gingerBill 1b454c7ded Merge branch 'master' of https://github.com/odin-lang/Odin 2019-08-23 10:24:25 +01:00
gingerBill 150d4e343d Fix ~(1 << x) type inference bug 2019-08-23 10:24:18 +01:00
gingerBill 28ada801a0 Merge pull request #419 from zhibog/master
Added an implementation for Base64. Also provides the ability to supp…
2019-08-16 19:42:03 +01:00
zhibog a7676bff6e Added an implementation for Base64. Also provides the ability to supply your own alphabet and decoding table. 2019-08-15 22:05:06 +02:00
gingerBill 4369298e96 Add reflect/types.odin 2019-08-13 23:21:51 +01:00
gingerBill a58c29582e Add new stuff to package reflect; fix -vet for odin_parser 2019-08-13 23:21:33 +01:00
gingerBill 3ad20a2d2d Remove package types and merge with package reflect 2019-08-13 22:59:07 +01:00
gingerBill b86dfa7af7 Fix compiler crash with #defined #417 2019-08-13 22:51:04 +01:00
gingerBill 980890ee8a Make -vet happy on *nix 2019-08-13 22:39:53 +01:00
gingerBill 0a63690b39 Fix typo in ? array lengths error 2019-08-13 22:34:02 +01:00
gingerBill 0076a4df62 Fix compound literal printing for structs with custom alignment requirements 2019-08-13 22:33:05 +01:00
gingerBill 4c065a7e99 Keep -vet happy 2019-08-13 22:27:52 +01:00
gingerBill 04036aba9c package reflect; fix substring type bug; fix scoping rules for using on procedure parameter 2019-08-11 23:58:49 +01:00
gingerBill b08aa857b3 Remove dead keywords in odin_token 2019-08-09 23:01:22 +01:00
gingerBill 2d26278a65 Make structs with the same fields but with different tags distinct types 2019-08-09 22:52:19 +01:00
gingerBill 27a3c5449a Fix global variable initialization for certain types. 2019-08-09 22:35:48 +01:00
gingerBill 9c63212824 Struct field tags 2019-08-09 21:59:58 +01:00
gingerBill 65d41d4248 Fix bit_field comparison against nil #414 2019-08-09 20:31:11 +01:00
gingerBill b04231dd95 Improve implementation of intrinsics.type_* procedures 2019-08-04 14:54:23 +01:00
gingerBill 37633c1d2a intrinsics.type_* constant evaluation procedures 2019-08-04 11:02:00 +01:00
gingerBill 5877017d30 Add error message for non-constant polymorphic name parameters 2019-08-03 10:15:31 +01:00
gingerBill 132fdf14b8 Fix min, max, clamp final type bug 2019-08-03 10:07:09 +01:00
gingerBill e7d3001dd1 Fix constant default value error #408 (typo) 2019-07-29 18:33:06 +01:00
gingerBill f163181204 Add extra hints for LLVM for implicit reference parameters 2019-07-29 10:43:07 +01:00
gingerBill 2c5c8192f8 Fix parsing for procedure literals expression statements; improve assert performance; other minor fixes 2019-07-28 22:58:56 +01:00
gingerBill 162c87b1b8 Minor code clean-up 2019-07-28 18:44:50 +01:00
gingerBill 77734ea967 Improve the performance of simple array comparisons 2019-07-27 11:59:50 +01:00
gingerBill 912fc2890b Fix array comparisons and fix f32 literal LLVM issue regarding accurate representation 2019-07-27 11:33:22 +01:00
gingerBill 14059583cd Fix array comparisons 2019-07-27 10:44:40 +01:00
gingerBill f3bffb9810 Improvement to the Odin calling conventions to pass certain things by "implicit reference" (const & in C++) 2019-07-27 10:20:11 +01:00
gingerBill 540730c0be Merge branch 'master' of https://github.com/odin-lang/Odin 2019-07-27 00:45:44 +01:00
gingerBill 40f0e74b8c Change scoping rules to allow for shadowing of procedure parameters but not named return values 2019-07-27 00:45:36 +01:00
Mikkel Hjortshøj 5ca0cd60d0 Merge pull request #406 from JoshuaManton/master
Fix `scale_f32` and `scale_vec3` returning the wrong variable
2019-07-20 22:21:58 +02:00
Joshua Mark Manton 96f0a08725 Fix scale_f32 and scale_vec3 from returning the wrong variable. 2019-07-20 13:15:51 -07:00
Chris Heyes d85893954d Impl time for macOS 2019-07-16 23:49:53 +01:00
gingerBill d26033eb23 Revert demo.odin 2019-07-15 22:41:25 +01:00
gingerBill c7a70be824 Fix __get_map_key 2019-07-15 22:38:51 +01:00
gingerBill 08c490d9ac Fix bounds checking on slices for constant parameters 2019-07-15 22:26:51 +01:00
gingerBill 8ee7ee7120 Fix core library for the new procedure parameter addressing mode 2019-07-15 22:16:27 +01:00
gingerBill d471a59041 IR fix array comparisons 2019-07-15 21:32:38 +01:00
gingerBill f25818e923 Make procedure parameters just named values rather than copied variables 2019-07-15 21:18:37 +01:00
gingerBill 3d531be711 Improve type hinting for named parameters in call expressions 2019-07-13 15:38:50 +01:00
gingerBill 56d365a4e7 Improve type inference for procedure group parameters 2019-07-13 13:34:21 +01:00
gingerBill 308300c1fc Add extra error handling for parsing slices 2019-07-09 11:18:50 +01:00
gingerBill 927d6814f2 slice_data_cast 2019-07-09 11:09:46 +01:00
gingerBill 7c99f52187 Add minimum requirement of 2 variants for #no_nil 2019-07-09 10:49:45 +01:00
gingerBill 4ab9edeb53 union #no_nil 2019-07-09 10:28:13 +01:00
gingerBill c5b3d7a736 Update package odin_parser 2019-07-07 16:20:58 +01:00
gingerBill d7172e168e Fix target list branch rules for name-labelled block/if statements 2019-07-07 16:06:41 +01:00
gingerBill d99ffe604f Fix unions with zero variants 2019-07-07 14:38:11 +01:00
gingerBill b77c79294c Merge branch 'master' of https://github.com/odin-lang/Odin 2019-07-07 14:14:36 +01:00
gingerBill 8e722274f0 Disallow blank identifier polymorphic types $_ 2019-07-07 14:14:28 +01:00
gingerBill ebe7fc23a5 Merge pull request #400 from asmoaesl/patch-1
Correct two typos
2019-06-29 12:09:46 +01:00
Luke I. Wilson 4d40f564ef Correct two typos 2019-06-28 20:42:59 -05:00
gingerBill fd62959bf4 Fix procedure constant declaration value type assignment checking 2019-06-21 23:11:14 +01:00
gingerBill 8b8cada33e Fix procedure group compiler assert with no matching arguments #393 2019-06-21 22:55:00 +01:00
gingerBill aaa24894b6 Fix double-pointer indexing bug #396 2019-06-21 22:50:29 +01:00
gingerBill 2af19c496e Fix comparison for bit field values #386 2019-06-21 22:48:37 +01:00
gingerBill fea34b32ea Merge branch 'master' of https://github.com/odin-lang/Odin 2019-06-21 22:40:20 +01:00
gingerBill b891c0feab Fix ranges in switch statement for strings 2019-06-21 22:40:11 +01:00
gingerBill 9f039c323e Update FUNDING.yml 2019-06-20 09:29:18 +01:00
96 changed files with 11980 additions and 3480 deletions
-1
View File
@@ -1,4 +1,3 @@
# These are supported funding model platforms
github: [gingerBill]
patreon: gingerbill
+57
View File
@@ -0,0 +1,57 @@
name: CI
on: [push, pull_request]
jobs:
build_unix:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- name: (macOS) Download LLVM and setup PATH
if: startsWith(matrix.os, 'macOS')
run: |
brew install llvm
echo ::add-path::/usr/local/opt/llvm/bin
echo ::set-env name=CPATH::`xcrun --show-sdk-path`/usr/include
- name: (Linux) Download LLVM
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get install llvm
- name: build odin
run: make release
- name: Odin run
run: ./odin run examples/demo/demo.odin
- name: Odin check
run: ./odin check examples/demo/demo.odin -vet
build_windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: Install cURL
run: choco install curl
- name: Download and unpack LLVM bins
shell: cmd
run: |
cd bin
curl -sL https://github.com/odin-lang/Odin/releases/download/llvm-windows/llvm-binaries.zip --output llvm-binaries.zip
7z x llvm-binaries.zip > nul
- name: build Odin
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
./build_ci.bat
- name: Odin run
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin run examples/demo/demo.odin
- name: Odin check
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin check examples/demo/demo.odin -vet
-24
View File
@@ -1,24 +0,0 @@
language: cpp
git:
depth: false
os:
- linux
- osx
compiler:
- clang
addons:
homebrew:
packages:
- llvm
script:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PATH="/usr/local/opt/llvm/bin:$PATH" ; fi
- make release
- ./odin run examples/demo/demo.odin
- ./odin check examples/demo/demo.odin -vet
notifications:
email: false
+6 -9
View File
@@ -10,15 +10,12 @@
<a href="https://github.com/odin-lang/odin/releases/latest">
<img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
</a>
<a href="https://github.com/odin-lang/odin/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/odin-lang/odin.svg">
</a>
<br>
<a href="https://ci.appveyor.com/project/ThisDrunkDane/odin-vf0ap">
<img src="https://ci.appveyor.com/api/projects/status/qss6l921c0eu85u6/branch/master?svg=true">
<a href="https://discord.gg/hnwN2Rj">
<img src="https://img.shields.io/discord/568138951836172421?logo=discord">
</a>
<a href="https://travis-ci.org/odin-lang/Odin">
<img src="https://travis-ci.org/odin-lang/Odin.svg?branch=master">
<a href="https://github.com/odin-lang/odin/actions">
<img src="https://github.com/odin-lang/odin/workflows/CI/badge.svg">
</a>
</p>
@@ -71,9 +68,9 @@ Instructions for downloading and install the Odin compiler and libraries.
An overview of the Odin programming language.
#### [Frequently Asked Questsions (FAQ)](https://odin-lang.org/docs/faq)
#### [Frequently Asked Questions (FAQ)](https://odin-lang.org/docs/faq)
Answers to common questsions about Odin.
Answers to common questions about Odin.
#### [The Odin Wiki](https://github.com/odin-lang/Odin/wiki)
-19
View File
@@ -1,19 +0,0 @@
image:
- Visual Studio 2017
shallow_clone: true
platform: x64
install:
- cd bin
- appveyor DownloadFile https://github.com/odin-lang/Odin/releases/download/llvm-windows/llvm-binaries.zip
- 7z x llvm-binaries.zip > nul
- cd ..
build_script:
- call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
- ./build_ci.bat
test_script:
- odin run examples/demo/demo.odin
- odin check examples/demo/demo.odin -vet
-1
View File
@@ -39,7 +39,6 @@ set linker_settings=%libs% %linker_flags%
del *.pdb > NUL 2> NUL
del *.ilk > NUL 2> NUL
cl %compiler_settings% "src\main.cpp" ^
/link %linker_settings% -OUT:%exe_name% ^
&& odin run examples/demo/demo.odin
+105
View File
@@ -0,0 +1,105 @@
// This is purely for documentation
package builtin
nil :: nil;
false :: 0!==0;
true :: 0==0;
ODIN_OS :: ODIN_OS;
ODIN_ARCH :: ODIN_ARCH;
ODIN_ENDIAN :: ODIN_ENDIAN;
ODIN_VENDOR :: ODIN_VENDOR;
ODIN_VERSION :: ODIN_VERSION;
ODIN_ROOT :: ODIN_ROOT;
ODIN_DEBUG :: ODIN_DEBUG;
byte :: u8; // alias
bool :: bool;
b8 :: b8;
b16 :: b16;
b32 :: b32;
b64 :: b64;
i8 :: i8;
u8 :: u8;
i16 :: i16;
u16 :: u16;
i32 :: i32;
u32 :: u32;
i64 :: i64;
u64 :: u64;
i128 :: i128;
u128 :: u128;
rune :: rune;
f16 :: f16;
f32 :: f32;
f64 :: f64;
complex32 :: complex32;
complex64 :: complex64;
complex128 :: complex128;
quaternion128 :: quaternion128;
quaternion256 :: quaternion256;
int :: int;
uint :: uint;
uintptr :: uintptr;
rawptr :: rawptr;
string :: string;
cstring :: cstring;
any :: any;
typeid :: typeid;
// Endian Specific Types
i16le :: i16le;
u16le :: u16le;
i32le :: i32le;
u32le :: u32le;
i64le :: i64le;
u64le :: u64le;
i128le :: i128le;
u128le :: u128le;
i16be :: i16be;
u16be :: u16be;
i32be :: i32be;
u32be :: u32be;
i64be :: i64be;
u64be :: u64be;
i128be :: i128be;
u128be :: u128be;
// Procedures
len :: proc(array: Array_Type) -> int ---
cap :: proc(array: Array_Type) -> int ---
size_of :: proc($T: typeid) -> int ---
align_of :: proc($T: typeid) -> int ---
offset_of :: proc($T: typeid) -> uintptr ---
type_of :: proc(x: expr) -> type ---
type_info_of :: proc($T: typeid) -> ^runtime.Type_Info ---
typeid_of :: proc($T: typeid) -> typeid ---
swizzle :: proc(x: [N]T, indices: ..int) -> [len(indices)]T ---
complex :: proc(real, imag: Float) -> Complex_Type ---
quaternion :: proc(real, imag, jmag, kmag: Float) -> Quaternion_Type ---
real :: proc(value: Complex_Or_Quaternion) -> Float ---
imag :: proc(value: Complex_Or_Quaternion) -> Float ---
jmag :: proc(value: Quaternion) -> Float ---
kmag :: proc(value: Quaternion) -> Float ---
conj :: proc(value: Complex_Or_Quaternion) -> Complex_Or_Quaternion ---
expand_to_tuple :: proc(value: Struct_Or_Array) -> (A, B, C, ...) ---
min :: proc(values: ..T) -> T ---
max :: proc(values: ..T) -> T ---
abs :: proc(value: T) -> T ---
clamp :: proc(value, minimum, maximum: T) -> T ---
+2
View File
@@ -31,3 +31,5 @@ ssize_t :: b.int;
ptrdiff_t :: b.int;
uintptr_t :: b.uintptr;
intptr_t :: b.int;
wchar_t :: (ODIN_OS == "windows") ? b.u16 : b.u32;
+1 -1
View File
@@ -19,6 +19,6 @@ unload_library :: proc(library: Library) -> bool {
symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
c_str := strings.clone_to_cstring(symbol, context.temp_allocator);
ptr = win32.get_proc_address(cast(win32.Hmodule)library, c_str);
found == ptr != nil;
found = ptr != nil;
return;
}
+93
View File
@@ -0,0 +1,93 @@
package base64
// @note(zh): Encoding utility for Base64
// A secondary param can be used to supply a custom alphabet to
// @link(encode) and a matching decoding table to @link(decode).
// If none is supplied it just uses the standard Base64 alphabet.
// Incase your specific version does not use padding, you may
// truncate it from the encoded output.
ENC_TABLE := [64]byte {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'
};
PADDING :: '=';
DEC_TABLE := [128]int {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59,
60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, -1, -1, -1, -1, -1
};
encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string #no_bounds_check {
length := len(data);
if length == 0 do return "";
out_length := ((4 * length / 3) + 3) &~ 3;
out := make([]byte, out_length, allocator);
c0, c1, c2, block: int;
for i, d := 0, 0; i < length; i, d = i + 3, d + 4 {
c0, c1, c2 = int(data[i]), 0, 0;
if i + 1 < length do c1 = int(data[i + 1]);
if i + 2 < length do c2 = int(data[i + 2]);
block = (c0 << 16) | (max(c1, 0) << 8) | max(c2, 0);
out[d] = ENC_TBL[block >> 18 & 63];
out[d + 1] = ENC_TBL[block >> 12 & 63];
out[d + 2] = c1 == 0 ? PADDING : ENC_TBL[block >> 6 & 63];
out[d + 3] = c2 == 0 ? PADDING : ENC_TBL[block & 63];
}
return string(out);
}
decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> []byte #no_bounds_check{
length := len(data);
if length == 0 do return []byte{};
pad_count := data[length - 1] == PADDING ? (data[length - 2] == PADDING ? 2 : 1) : 0;
out_length := ((length * 6) >> 3) - pad_count;
out := make([]byte, out_length, allocator);
c0, c1, c2, c3: int;
b0, b1, b2: int;
for i, j := 0, 0; i < length; i, j = i + 4, j + 3 {
c0 = DEC_TBL[data[i]];
c1 = DEC_TBL[data[i + 1]];
c2 = DEC_TBL[data[i + 2]];
c3 = DEC_TBL[data[i + 3]];
b0 = (c0 << 2) | (c1 >> 4);
b1 = (c1 << 4) | (c2 >> 2);
b2 = (c2 << 6) | c3;
out[j] = byte(b0);
out[j + 1] = byte(b1);
out[j + 2] = byte(b2);
}
return out;
}
+15 -13
View File
@@ -168,9 +168,9 @@ destroy :: proc(p: ^Parser) {
}
error :: proc(p: ^Parser, pos: Pos, msg: string, args: ..any) {
fmt.printf_err("%s(%d:%d) Error: ", pos.file, pos.line, pos.column);
fmt.printf_err(msg, ..args);
fmt.println_err();
fmt.eprintf("%s(%d:%d) Error: ", pos.file, pos.line, pos.column);
fmt.eprintf(msg, ..args);
fmt.eprintln();
p.error_count += 1;
}
@@ -190,7 +190,7 @@ next_token :: proc(p: ^Parser) -> Token {
return prev;
}
unquote_char :: proc(s: string, quote: byte) -> (r: rune, multiple_bytes: bool, tail_string: string, success: bool) {
unquote_char :: proc(str: string, quote: byte) -> (r: rune, multiple_bytes: bool, tail_string: string, success: bool) {
hex_to_int :: proc(c: byte) -> int {
switch c {
case '0'..'9': return int(c-'0');
@@ -201,18 +201,19 @@ unquote_char :: proc(s: string, quote: byte) -> (r: rune, multiple_bytes: bool,
}
w: int;
if s[0] == quote && quote == '"' {
if str[0] == quote && quote == '"' {
return;
} else if s[0] >= 0x80 {
r, w = utf8.decode_rune_in_string(s);
return r, true, s[w:], true;
} else if s[0] != '\\' {
return rune(s[0]), false, s[1:], true;
} else if str[0] >= 0x80 {
r, w = utf8.decode_rune_in_string(str);
return r, true, str[w:], true;
} else if str[0] != '\\' {
return rune(str[0]), false, str[1:], true;
}
if len(s) <= 1 {
if len(str) <= 1 {
return;
}
s := str;
c := s[1];
s = s[2:];
@@ -502,7 +503,7 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) {
parse_atom_expr :: proc(p: ^Parser, operand: Value, pos: Pos) -> (Value, Pos) {
loop := true;
for loop {
for operand := operand; loop; {
switch p.curr_token.kind {
case Kind.Period:
next_token(p);
@@ -664,8 +665,9 @@ match_values :: proc(left, right: ^Value) -> bool {
return false;
}
calculate_binary_value :: proc(p: ^Parser, op: Kind, x, y: Value) -> (Value, bool) {
calculate_binary_value :: proc(p: ^Parser, op: Kind, a, b: Value) -> (Value, bool) {
// TODO(bill): Calculate value as you go!
x, y := a, b;
match_values(&x, &y);
+12 -9
View File
@@ -183,9 +183,9 @@ tokenizer_init :: proc(t: ^Tokenizer, src: []byte, file := "") {
}
token_error :: proc(t: ^Tokenizer, msg: string, args: ..any) {
fmt.printf_err("%s(%d:%d) Error: ", t.file, t.line_count, t.read_offset-t.line_offset+1);
fmt.printf_err(msg, ..args);
fmt.println_err();
fmt.eprintf("%s(%d:%d) Error: ", t.file, t.line_count, t.read_offset-t.line_offset+1);
fmt.eprintf(msg, ..args);
fmt.eprintln();
t.error_count += 1;
}
@@ -286,9 +286,10 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
advance_to_next_rune(t);
}
}
scan_exponent :: proc(t: ^Tokenizer, tok: Kind, offset: int) -> (Kind, string) {
scan_exponent :: proc(t: ^Tokenizer, tok: Kind, offset: int) -> (kind: Kind, text: string) {
kind = tok;
if t.curr_rune == 'e' || t.curr_rune == 'E' {
tok = Float;
kind = Float;
advance_to_next_rune(t);
if t.curr_rune == '-' || t.curr_rune == '+' {
advance_to_next_rune(t);
@@ -299,16 +300,18 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
token_error(t, "Illegal floating point exponent");
}
}
return tok, string(t.src[offset : t.offset]);
text = string(t.src[offset : t.offset]);
return;
}
scan_fraction :: proc(t: ^Tokenizer, tok: Kind, offset: int) -> (Kind, string) {
scan_fraction :: proc(t: ^Tokenizer, tok: Kind, offset: int) -> (kind: Kind, text: string) {
kind = tok;
if t.curr_rune == '.' {
tok = Float;
kind = Float;
advance_to_next_rune(t);
scan_mantissa(t, 10);
}
return scan_exponent(t, tok, offset);
return scan_exponent(t, kind, offset);
}
offset := t.offset;
+7 -8
View File
@@ -5,7 +5,7 @@ import "core:math/bits"
import "core:runtime"
import "core:strconv"
import "core:strings"
import "core:types"
import "core:reflect"
Marshal_Error :: enum {
None,
@@ -194,7 +194,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
data := uintptr(entries.data) + uintptr(i*entry_size);
header := cast(^Map_Entry_Header)data;
if types.is_string(info.key) {
if reflect.is_string(info.key) {
marshal_arg(b, header.key.str);
} else {
marshal_arg(b, any{rawptr(&header.key.hash), info.key.id});
@@ -281,14 +281,13 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
if ti == nil {
return false;
}
ti = runtime.type_info_base(ti);
switch info in ti.variant {
t := runtime.type_info_base(ti);
switch info in t.variant {
case runtime.Type_Info_Integer:
using runtime.Type_Info_Endianness;
switch info.endianness {
case Platform: return false;
case Little: return ODIN_ENDIAN != "little";
case Big: return ODIN_ENDIAN != "big";
case .Platform: return false;
case .Little: return ODIN_ENDIAN != "little";
case .Big: return ODIN_ENDIAN != "big";
}
}
return false;
+4 -2
View File
@@ -333,7 +333,8 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
is_valid_number :: proc(s: string, spec: Specification) -> bool {
is_valid_number :: proc(str: string, spec: Specification) -> bool {
s := str;
if s == "" {
return false;
}
@@ -395,7 +396,8 @@ is_valid_number :: proc(s: string, spec: Specification) -> bool {
return s == "";
}
is_valid_string_literal :: proc(s: string, spec: Specification) -> bool {
is_valid_string_literal :: proc(str: string, spec: Specification) -> bool {
s := str;
if len(s) < 2 {
return false;
}
+201 -271
View File
@@ -5,9 +5,9 @@ import "core:os"
import "core:mem"
import "core:math/bits"
import "core:unicode/utf8"
import "core:types"
import "core:strconv"
import "core:strings"
import "core:reflect"
@private
@@ -59,12 +59,18 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
// print* procedures return the number of bytes written
print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); }
print_err :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); }
println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); }
println_err :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); }
printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); }
printf_err :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); }
print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); }
println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); }
printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); }
eprint :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); }
eprintln :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); }
eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); }
@(deprecated="prefer eprint") print_err :: proc(args: ..any) -> int { return eprint(..args); }
@(deprecated="prefer eprintf") printf_err :: proc(fmt: string, args: ..any) -> int { return eprintf(fmt, ..args); }
@(deprecated="prefer eprintln") println_err :: proc(args: ..any) -> int { return eprintln(..args); }
// aprint* procedures return a string that was allocated with the current context
@@ -143,7 +149,7 @@ panicf :: proc "contextless" (fmt: string, args: ..any, loc := #caller_location)
fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) {
data: [DEFAULT_BUFFER_SIZE]byte;
buf := strings.builder_from_slice(data[:]);
write_type(&buf, info);
reflect.write_type(&buf, info);
os.write_string(fd, strings.to_string(buf));
}
@@ -156,7 +162,7 @@ sbprint :: proc(buf: ^strings.Builder, args: ..any) -> string {
fi.buf = buf;
for arg, i in args {
is_string := arg != nil && types.is_string(type_info_of(arg.id));
is_string := arg != nil && reflect.is_string(type_info_of(arg.id));
if i > 0 && !is_string && !prev_string {
strings.write_byte(buf, ' ');
}
@@ -399,7 +405,7 @@ fmt_bad_verb :: proc(using fi: ^Info, verb: rune) {
strings.write_rune(buf, verb);
strings.write_byte(buf, '(');
if arg.id != nil {
write_typeid(buf, arg.id);
reflect.write_typeid(buf, arg.id);
strings.write_byte(buf, '=');
fmt_value(fi, arg, 'v');
} else {
@@ -783,7 +789,8 @@ fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) {
}
}
enum_value_to_string :: proc(v: any) -> (string, bool) {
enum_value_to_string :: proc(val: any) -> (string, bool) {
v := val;
v.id = runtime.typeid_base(v.id);
type_info := type_info_of(v.id);
@@ -791,7 +798,7 @@ enum_value_to_string :: proc(v: any) -> (string, bool) {
case: return "", false;
case runtime.Type_Info_Enum:
get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) {
if types.is_string(e.base) {
if reflect.is_string(e.base) {
for val, idx in e.values {
if v, ok := val.(T); ok && v == i {
return e.names[idx], true;
@@ -890,8 +897,8 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
if ti == nil {
return false;
}
ti = runtime.type_info_base(ti);
switch info in ti.variant {
t := runtime.type_info_base(ti);
switch info in t.variant {
case runtime.Type_Info_Integer:
switch info.endianness {
case .Platform: return false;
@@ -946,7 +953,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
if name != "" {
strings.write_string(fi.buf, name);
} else {
write_type(fi.buf, type_info);
reflect.write_type(fi.buf, type_info);
}
strings.write_byte(fi.buf, '{');
defer strings.write_byte(fi.buf, '}');
@@ -1041,7 +1048,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) {
if ot, ok := rt.type_info_base(type_info).variant.(rt.Type_Info_Opaque); ok {
elem := rt.type_info_base(ot.elem);
if elem == nil do return;
write_type(fi.buf, type_info);
reflect.write_type(fi.buf, type_info);
strings.write_byte(fi.buf, '{');
defer strings.write_byte(fi.buf, '}');
@@ -1052,7 +1059,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) {
// Okay
}
} else {
write_type(fi.buf, type_info);
reflect.write_type(fi.buf, type_info);
strings.write_byte(fi.buf, '{');
strings.write_byte(fi.buf, '}');
}
@@ -1078,8 +1085,11 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
strings.write_string(fi.buf, "{}");
return;
};
is_soa := b.soa_base_type != nil;
strings.write_string(fi.buf, info.name);
strings.write_byte(fi.buf, '{');
strings.write_byte(fi.buf, is_soa ? '[' : '{');
hash := fi.hash; defer fi.hash = hash;
indent := fi.indent; defer fi.indent -= 1;
@@ -1088,30 +1098,73 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
fi.indent += 1;
if hash do strings.write_byte(fi.buf, '\n');
field_count := -1;
for name, i in b.names {
// if len(name) > 0 && name[0] == '_' do continue;
field_count += 1;
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t');
strings.write_string(fi.buf, name);
strings.write_string(fi.buf, " = ");
if t := b.types[i]; types.is_any(t) {
strings.write_string(fi.buf, "any{}");
} else {
data := rawptr(uintptr(v.data) + b.offsets[i]);
fmt_arg(fi, any{data, t.id}, 'v');
}
if hash do strings.write_string(fi.buf, ",\n");
defer {
if hash do for in 0..<indent do strings.write_byte(fi.buf, '\t');
strings.write_byte(fi.buf, is_soa ? ']' : '}');
}
if hash do for in 0..<indent do strings.write_byte(fi.buf, '\t');
strings.write_byte(fi.buf, '}');
if is_soa {
fi.indent += 1;
defer fi.indent -= 1;
base_type_name: string;
if v, ok := b.soa_base_type.variant.(runtime.Type_Info_Named); ok {
base_type_name = v.name;
}
for index in 0..<uintptr(b.soa_len) {
if !hash && index > 0 do strings.write_string(fi.buf, ", ");
field_count := -1;
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
strings.write_string(fi.buf, base_type_name);
strings.write_byte(fi.buf, '{');
defer strings.write_byte(fi.buf, '}');
for name, i in b.names {
field_count += 1;
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t');
strings.write_string(fi.buf, name);
strings.write_string(fi.buf, " = ");
t := b.types[i].variant.(runtime.Type_Info_Array).elem;
t_size := uintptr(t.size);
if reflect.is_any(t) {
strings.write_string(fi.buf, "any{}");
} else {
data := rawptr(uintptr(v.data) + b.offsets[i] + index*t_size);
fmt_arg(fi, any{data, t.id}, 'v');
}
if hash do strings.write_string(fi.buf, ",\n");
}
}
} else {
field_count := -1;
for name, i in b.names {
field_count += 1;
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t');
strings.write_string(fi.buf, name);
strings.write_string(fi.buf, " = ");
if t := b.types[i]; reflect.is_any(t) {
strings.write_string(fi.buf, "any{}");
} else {
data := rawptr(uintptr(v.data) + b.offsets[i]);
fmt_arg(fi, any{data, t.id}, 'v');
}
if hash do strings.write_string(fi.buf, ",\n");
}
}
case runtime.Type_Info_Bit_Set:
fmt_bit_set(fi, v);
@@ -1128,11 +1181,12 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
case runtime.Type_Info_Rune: fmt_arg(fi, v, verb);
case runtime.Type_Info_Float: fmt_arg(fi, v, verb);
case runtime.Type_Info_Complex: fmt_arg(fi, v, verb);
case runtime.Type_Info_Quaternion: fmt_arg(fi, v, verb);
case runtime.Type_Info_String: fmt_arg(fi, v, verb);
case runtime.Type_Info_Pointer:
if v.id == typeid_of(^runtime.Type_Info) {
write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
reflect.write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
} else {
ptr := (^rawptr)(v.data)^;
if verb != 'p' && info.elem != nil {
@@ -1255,7 +1309,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
data := uintptr(entries.data) + uintptr(i*entry_size);
header := cast(^runtime.Map_Entry_Header)data;
if types.is_string(info.key) {
if reflect.is_string(info.key) {
strings.write_string(fi.buf, header.key.str);
} else {
fi := Info{buf = fi.buf};
@@ -1275,8 +1329,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
return;
}
strings.write_byte(fi.buf, '{');
defer strings.write_byte(fi.buf, '}');
is_soa := info.soa_base_type != nil;
strings.write_byte(fi.buf, is_soa ? '[' : '{');
defer strings.write_byte(fi.buf, is_soa ? ']' : '}');
fi.indent += 1; defer fi.indent -= 1;
hash := fi.hash; defer fi.hash = hash;
@@ -1285,27 +1341,76 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
if hash do strings.write_byte(fi.buf, '\n');
for _, i in info.names {
if !hash && i > 0 do strings.write_string(fi.buf, ", ");
if hash {
for in 0..<fi.indent {
strings.write_byte(fi.buf, '\t');
if is_soa {
fi.indent += 1;
defer fi.indent -= 1;
base_type_name: string;
if v, ok := info.soa_base_type.variant.(runtime.Type_Info_Named); ok {
base_type_name = v.name;
}
for index in 0..<uintptr(info.soa_len) {
if !hash && index > 0 do strings.write_string(fi.buf, ", ");
field_count := -1;
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
strings.write_string(fi.buf, base_type_name);
strings.write_byte(fi.buf, '{');
defer strings.write_byte(fi.buf, '}');
for name, i in info.names {
field_count += 1;
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t');
strings.write_string(fi.buf, name);
strings.write_string(fi.buf, " = ");
t := info.types[i].variant.(runtime.Type_Info_Array).elem;
t_size := uintptr(t.size);
if reflect.is_any(t) {
strings.write_string(fi.buf, "any{}");
} else {
data := rawptr(uintptr(v.data) + info.offsets[i] + index*t_size);
fmt_arg(fi, any{data, t.id}, 'v');
}
if hash do strings.write_string(fi.buf, ",\n");
}
}
} else {
field_count := -1;
for name, i in info.names {
field_count += 1;
strings.write_string(fi.buf, info.names[i]);
strings.write_string(fi.buf, " = ");
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t');
if t := info.types[i]; types.is_any(t) {
strings.write_string(fi.buf, "any{}");
} else {
data := uintptr(v.data) + info.offsets[i];
fmt_arg(fi, any{rawptr(data), t.id}, 'v');
strings.write_string(fi.buf, name);
strings.write_string(fi.buf, " = ");
if t := info.types[i]; reflect.is_any(t) {
strings.write_string(fi.buf, "any{}");
} else {
data := rawptr(uintptr(v.data) + info.offsets[i]);
fmt_arg(fi, any{data, t.id}, 'v');
}
if hash do strings.write_string(fi.buf, ",\n");
}
if hash do strings.write_string(fi.buf, ",\n");
}
case runtime.Type_Info_Union:
if type_info.size == 0 {
strings.write_string(fi.buf, "nil");
return;
}
tag_ptr := uintptr(v.data) + info.tag_offset;
tag_any := any{rawptr(tag_ptr), info.tag_type.id};
@@ -1321,8 +1426,14 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
case i64: tag = i64(i);
case: panic("Invalid union tag type");
}
assert(tag >= 0);
if v.data == nil || tag == 0 {
if v.data == nil {
strings.write_string(fi.buf, "nil");
} else if info.no_nil {
id := info.variants[tag].id;
fmt_arg(fi, any{v.data, id}, verb);
} else if tag == 0 {
strings.write_string(fi.buf, "nil");
} else {
id := info.variants[tag-1].id;
@@ -1337,14 +1448,14 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
if ptr == nil {
strings.write_string(fi.buf, "nil");
} else {
write_typeid(fi.buf, v.id);
reflect.write_typeid(fi.buf, v.id);
strings.write_string(fi.buf, " @ ");
fmt_pointer(fi, ptr, 'p');
}
case runtime.Type_Info_Type_Id:
id := (^typeid)(v.data)^;
write_typeid(fi.buf, id);
reflect.write_typeid(fi.buf, id);
case runtime.Type_Info_Bit_Field:
fmt_bit_field(fi, v);
@@ -1374,6 +1485,31 @@ fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) {
}
}
fmt_quaternion :: proc(fi: ^Info, q: quaternion256, bits: int, verb: rune) {
switch verb {
case 'f', 'F', 'v', 'h', 'H':
r, i, j, k := real(q), imag(q), jmag(q), kmag(q);
fmt_float(fi, r, bits/4, verb);
if !fi.plus && i >= 0 do strings.write_rune(fi.buf, '+');
fmt_float(fi, i, bits/4, verb);
strings.write_rune(fi.buf, 'i');
if !fi.plus && j >= 0 do strings.write_rune(fi.buf, '+');
fmt_float(fi, j, bits/4, verb);
strings.write_rune(fi.buf, 'j');
if !fi.plus && k >= 0 do strings.write_rune(fi.buf, '+');
fmt_float(fi, k, bits/4, verb);
strings.write_rune(fi.buf, 'k');
case:
fmt_bad_verb(fi, verb);
return;
}
}
fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
if arg == nil {
strings.write_string(fi.buf, "<nil>");
@@ -1386,7 +1522,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
switch a in arg {
case ^runtime.Type_Info: ti = a;
}
write_type(fi.buf, ti);
reflect.write_type(fi.buf, ti);
return;
}
@@ -1422,6 +1558,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
case complex64: fmt_complex(fi, complex128(a), 64, verb);
case complex128: fmt_complex(fi, a, 128, verb);
case quaternion128: fmt_quaternion(fi, quaternion256(a), 128, verb);
case quaternion256: fmt_quaternion(fi, a, 256, verb);
case i8: fmt_int(fi, u64(a), true, 8, verb);
case u8: fmt_int(fi, u64(a), false, 8, verb);
case i16: fmt_int(fi, u64(a), true, 16, verb);
@@ -1437,7 +1576,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
case string: fmt_string(fi, a, verb);
case cstring: fmt_cstring(fi, a, verb);
case typeid: write_typeid(fi.buf, a);
case typeid: reflect.write_typeid(fi.buf, a);
case i16le: fmt_int(fi, u64(a), true, 16, verb);
case u16le: fmt_int(fi, u64(a), false, 16, verb);
@@ -1470,212 +1609,3 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
write_type(buf, type_info_of(id));
}
write_type :: proc(buf: ^strings.Builder, ti: ^runtime.Type_Info) {
using strings;
if ti == nil {
write_string(buf, "nil");
return;
}
switch info in ti.variant {
case runtime.Type_Info_Named:
write_string(buf, info.name);
case runtime.Type_Info_Integer:
switch ti.id {
case int: write_string(buf, "int");
case uint: write_string(buf, "uint");
case uintptr: write_string(buf, "uintptr");
case:
write_byte(buf, info.signed ? 'i' : 'u');
write_i64(buf, i64(8*ti.size), 10);
switch info.endianness {
case runtime.Type_Info_Endianness.Little:
write_string(buf, "le");
case runtime.Type_Info_Endianness.Big:
write_string(buf, "be");
}
}
case runtime.Type_Info_Rune:
write_string(buf, "rune");
case runtime.Type_Info_Float:
write_byte(buf, 'f');
write_i64(buf, i64(8*ti.size), 10);
case runtime.Type_Info_Complex:
write_string(buf, "complex");
write_i64(buf, i64(8*ti.size), 10);
case runtime.Type_Info_String:
if info.is_cstring {
write_string(buf, "cstring");
} else {
write_string(buf, "string");
}
case runtime.Type_Info_Boolean:
switch ti.id {
case bool: write_string(buf, "bool");
case:
write_byte(buf, 'b');
write_i64(buf, i64(8*ti.size), 10);
}
case runtime.Type_Info_Any:
write_string(buf, "any");
case runtime.Type_Info_Type_Id:
write_string(buf, "typeid");
case runtime.Type_Info_Pointer:
if info.elem == nil {
write_string(buf, "rawptr");
} else {
write_string(buf, "^");
write_type(buf, info.elem);
}
case runtime.Type_Info_Procedure:
write_string(buf, "proc");
if info.params == nil {
write_string(buf, "()");
} else {
t := info.params.variant.(runtime.Type_Info_Tuple);
write_string(buf, "(");
for t, i in t.types {
if i > 0 do write_string(buf, ", ");
write_type(buf, t);
}
write_string(buf, ")");
}
if info.results != nil {
write_string(buf, " -> ");
write_type(buf, info.results);
}
case runtime.Type_Info_Tuple:
count := len(info.names);
if count != 1 do write_string(buf, "(");
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
t := info.types[i];
if len(name) > 0 {
write_string(buf, name);
write_string(buf, ": ");
}
write_type(buf, t);
}
if count != 1 do write_string(buf, ")");
case runtime.Type_Info_Array:
write_string(buf, "[");
write_i64(buf, i64(info.count), 10);
write_string(buf, "]");
write_type(buf, info.elem);
case runtime.Type_Info_Dynamic_Array:
write_string(buf, "[dynamic]");
write_type(buf, info.elem);
case runtime.Type_Info_Slice:
write_string(buf, "[]");
write_type(buf, info.elem);
case runtime.Type_Info_Map:
write_string(buf, "map[");
write_type(buf, info.key);
write_byte(buf, ']');
write_type(buf, info.value);
case runtime.Type_Info_Struct:
write_string(buf, "struct ");
if info.is_packed do write_string(buf, "#packed ");
if info.is_raw_union do write_string(buf, "#raw_union ");
if info.custom_align {
write_string(buf, "#align ");
write_i64(buf, i64(ti.align), 10);
write_byte(buf, ' ');
}
write_byte(buf, '{');
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
write_string(buf, name);
write_string(buf, ": ");
write_type(buf, info.types[i]);
}
write_byte(buf, '}');
case runtime.Type_Info_Union:
write_string(buf, "union ");
if info.custom_align {
write_string(buf, "#align ");
write_i64(buf, i64(ti.align), 10);
write_byte(buf, ' ');
}
write_byte(buf, '{');
for variant, i in info.variants {
if i > 0 do write_string(buf, ", ");
write_type(buf, variant);
}
write_byte(buf, '}');
case runtime.Type_Info_Enum:
write_string(buf, "enum ");
write_type(buf, info.base);
write_string(buf, " {");
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
write_string(buf, name);
}
write_byte(buf, '}');
case runtime.Type_Info_Bit_Field:
write_string(buf, "bit_field ");
if ti.align != 1 {
write_string(buf, "#align ");
write_i64(buf, i64(ti.align), 10);
write_byte(buf, ' ');
}
write_string(buf, " {");
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
write_string(buf, name);
write_string(buf, ": ");
write_i64(buf, i64(info.bits[i]), 10);
}
write_byte(buf, '}');
case runtime.Type_Info_Bit_Set:
write_string(buf, "bit_set[");
switch {
case types.is_enum(info.elem):
write_type(buf, info.elem);
case types.is_rune(info.elem):
write_encoded_rune(buf, rune(info.lower));
write_string(buf, "..");
write_encoded_rune(buf, rune(info.upper));
case:
write_i64(buf, info.lower, 10);
write_string(buf, "..");
write_i64(buf, info.upper, 10);
}
if info.underlying != nil {
write_string(buf, "; ");
write_type(buf, info.underlying);
}
write_byte(buf, ']');
case runtime.Type_Info_Opaque:
write_string(buf, "opaque ");
write_type(buf, info.elem);
case runtime.Type_Info_Simd_Vector:
if info.is_x86_mmx {
write_string(buf, "intrinsics.x86_mmx");
} else {
write_string(buf, "intrinsics.vector(");
write_i64(buf, i64(info.count));
write_string(buf, ", ");
write_type(buf, info.elem);
write_byte(buf, ')');
}
}
}
+127
View File
@@ -0,0 +1,127 @@
// This is purely for documentation
package intrinsics
vector :: proc() ---
atomic_fence :: proc() ---
atomic_fence_acq :: proc() ---
atomic_fence_rel :: proc() ---
atomic_fence_acqrel :: proc() ---
atomic_store :: proc(dst: ^$T, val: $T) ---
atomic_store_rel :: proc(dst: ^$T, val: $T) ---
atomic_store_relaxed :: proc(dst: ^$T, val: $T) ---
atomic_store_unordered :: proc(dst: ^$T, val: $T) ---
atomic_load :: proc(dst: ^$T) -> T ---
atomic_load_acq :: proc(dst: ^$T) -> T ---
atomic_load_relaxed :: proc(dst: ^$T) -> T ---
atomic_load_unordered :: proc(dst: ^$T) -> T ---
atomic_add :: proc(dst; ^$T, val: $T) -> T ---
atomic_add_acq :: proc(dst; ^$T, val: $T) -> T ---
atomic_add_rel :: proc(dst; ^$T, val: $T) -> T ---
atomic_add_acqrel :: proc(dst; ^$T, val: $T) -> T ---
atomic_add_relaxed :: proc(dst; ^$T, val: $T) -> T ---
atomic_sub :: proc(dst; ^$T, val: $T) -> T ---
atomic_sub_acq :: proc(dst; ^$T, val: $T) -> T ---
atomic_sub_rel :: proc(dst; ^$T, val: $T) -> T ---
atomic_sub_acqrel :: proc(dst; ^$T, val: $T) -> T ---
atomic_sub_relaxed :: proc(dst; ^$T, val: $T) -> T ---
atomic_and :: proc(dst; ^$T, val: $T) -> T ---
atomic_and_acq :: proc(dst; ^$T, val: $T) -> T ---
atomic_and_rel :: proc(dst; ^$T, val: $T) -> T ---
atomic_and_acqrel :: proc(dst; ^$T, val: $T) -> T ---
atomic_and_relaxed :: proc(dst; ^$T, val: $T) -> T ---
atomic_nand :: proc(dst; ^$T, val: $T) -> T ---
atomic_nand_acq :: proc(dst; ^$T, val: $T) -> T ---
atomic_nand_rel :: proc(dst; ^$T, val: $T) -> T ---
atomic_nand_acqrel :: proc(dst; ^$T, val: $T) -> T ---
atomic_nand_relaxed :: proc(dst; ^$T, val: $T) -> T ---
atomic_or :: proc(dst; ^$T, val: $T) -> T ---
atomic_or_acq :: proc(dst; ^$T, val: $T) -> T ---
atomic_or_rel :: proc(dst; ^$T, val: $T) -> T ---
atomic_or_acqrel :: proc(dst; ^$T, val: $T) -> T ---
atomic_or_relaxed :: proc(dst; ^$T, val: $T) -> T ---
atomic_xor :: proc(dst; ^$T, val: $T) -> T ---
atomic_xor_acq :: proc(dst; ^$T, val: $T) -> T ---
atomic_xor_rel :: proc(dst; ^$T, val: $T) -> T ---
atomic_xor_acqrel :: proc(dst; ^$T, val: $T) -> T ---
atomic_xor_relaxed :: proc(dst; ^$T, val: $T) -> T ---
atomic_xchg :: proc(dst; ^$T, val: $T) -> T ---
atomic_xchg_acq :: proc(dst; ^$T, val: $T) -> T ---
atomic_xchg_rel :: proc(dst; ^$T, val: $T) -> T ---
atomic_xchg_acqrel :: proc(dst; ^$T, val: $T) -> T ---
atomic_xchg_relaxed :: proc(dst; ^$T, val: $T) -> T ---
atomic_cxchg :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_acq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_rel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_acqrel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_relaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_failacq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchg_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_acq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_rel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_acqrel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_relaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_failacq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
atomic_cxchgweak_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
// Constant type tests
type_base_type :: proc($T: typeid) -> type ---
type_core_type :: proc($T: typeid) -> type ---
type_elem_type :: proc($T: typeid) -> type ---
type_is_boolean :: proc($T: typeid) -> bool ---
type_is_integer :: proc($T: typeid) -> bool ---
type_is_rune :: proc($T: typeid) -> bool ---
type_is_float :: proc($T: typeid) -> bool ---
type_is_complex :: proc($T: typeid) -> bool ---
type_is_quaternion :: proc($T: typeid) -> bool ---
type_is_string :: proc($T: typeid) -> bool ---
type_is_typeid :: proc($T: typeid) -> bool ---
type_is_any :: proc($T: typeid) -> bool ---
type_is_endian_little :: proc($T: typeid) -> bool ---
type_is_endian_big :: proc($T: typeid) -> bool ---
type_is_unsigned :: proc($T: typeid) -> bool ---
type_is_numeric :: proc($T: typeid) -> bool ---
type_is_ordered :: proc($T: typeid) -> bool ---
type_is_ordered_numeric :: proc($T: typeid) -> bool ---
type_is_indexable :: proc($T: typeid) -> bool ---
type_is_sliceable :: proc($T: typeid) -> bool ---
type_is_simple_compare :: proc($T: typeid) -> bool --- // easily compared using memcmp
type_is_dereferenceable :: proc($T: typeid) -> bool ---
type_is_valid_map_key :: proc($T: typeid) -> bool ---
type_is_named :: proc($T: typeid) -> bool ---
type_is_pointer :: proc($T: typeid) -> bool ---
type_is_opaque :: proc($T: typeid) -> bool ---
type_is_array :: proc($T: typeid) -> bool ---
type_is_slice :: proc($T: typeid) -> bool ---
type_is_dynamic_array :: proc($T: typeid) -> bool ---
type_is_map :: proc($T: typeid) -> bool ---
type_is_struct :: proc($T: typeid) -> bool ---
type_is_union :: proc($T: typeid) -> bool ---
type_is_enum :: proc($T: typeid) -> bool ---
type_is_proc :: proc($T: typeid) -> bool ---
type_is_bit_field :: proc($T: typeid) -> bool ---
type_is_bit_field_value :: proc($T: typeid) -> bool ---
type_is_bit_set :: proc($T: typeid) -> bool ---
type_is_simd_vector :: proc($T: typeid) -> bool ---
type_has_nil :: proc($T: typeid) -> bool ---
type_proc_parameter_count :: proc($T: typeid) -> int where type_is_proc(T) ---
type_proc_return_count :: proc($T: typeid) -> int where type_is_proc(T) ---
+16 -16
View File
@@ -14,18 +14,18 @@ Level_Headers := []string{
};
Default_Console_Logger_Opts :: Options{
Option.Level,
Option.Terminal_Color,
Option.Short_File_Path,
Option.Line,
Option.Procedure,
.Level,
.Terminal_Color,
.Short_File_Path,
.Line,
.Procedure,
} | Full_Timestamp_Opts;
Default_File_Logger_Opts :: Options{
Option.Level,
Option.Short_File_Path,
Option.Line,
Option.Procedure,
.Level,
.Short_File_Path,
.Line,
.Procedure,
} | Full_Timestamp_Opts;
@@ -109,10 +109,10 @@ do_level_header :: proc(opts : Options, level : Level, str : ^strings.Builder) {
case Level.Error, Level.Fatal : col = RED;
}
if Option.Level in opts {
if Option.Terminal_Color in opts do fmt.sbprint(str, col);
if .Level in opts {
if .Terminal_Color in opts do fmt.sbprint(str, col);
fmt.sbprint(str, Level_Headers[level]);
if Option.Terminal_Color in opts do fmt.sbprint(str, RESET);
if .Terminal_Color in opts do fmt.sbprint(str, RESET);
}
}
@@ -120,7 +120,7 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := #
if Location_Header_Opts & opts != nil do fmt.sbprint(buf, "["); else do return;
file := location.file_path;
if Option.Short_File_Path in opts {
if .Short_File_Path in opts {
when os.OS == "windows" do delimiter := '\\'; else do delimiter := '/';
last := 0;
for r, i in location.file_path do if r == delimiter do last = i+1;
@@ -129,13 +129,13 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := #
if Location_File_Opts & opts != nil do fmt.sbprint(buf, file);
if Option.Procedure in opts {
if .Procedure in opts {
if Location_File_Opts & opts != nil do fmt.sbprint(buf, ".");
fmt.sbprintf(buf, "%s()", location.procedure);
}
if Option.Line in opts {
if Location_File_Opts & opts != nil || Option.Procedure in opts do fmt.sbprint(buf, ":");
if .Line in opts {
if Location_File_Opts & opts != nil || .Procedure in opts do fmt.sbprint(buf, ":");
fmt.sbprint(buf, location.line);
}
+36 -31
View File
@@ -11,30 +11,30 @@ Level :: enum {
}
Option :: enum {
Level,
Date,
Time,
Short_File_Path,
Long_File_Path,
Line,
Procedure,
Terminal_Color
Level,
Date,
Time,
Short_File_Path,
Long_File_Path,
Line,
Procedure,
Terminal_Color
}
Options :: bit_set[Option];
Full_Timestamp_Opts :: Options{
Option.Date,
Option.Time
.Date,
.Time
};
Location_Header_Opts :: Options{
Option.Short_File_Path,
Option.Long_File_Path,
Option.Line,
Option.Procedure,
.Short_File_Path,
.Long_File_Path,
.Line,
.Procedure,
};
Location_File_Opts :: Options{
Option.Short_File_Path,
Option.Long_File_Path
.Short_File_Path,
.Long_File_Path
};
Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
@@ -42,30 +42,34 @@ Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Opt
Logger :: struct {
procedure: Logger_Proc,
data: rawptr,
options: Options,
options: Options,
}
Multi_Logger_Data :: struct {
loggers : []Logger,
loggers : []Logger,
}
create_multi_logger :: proc(logs: ..Logger) -> Logger {
data := new(Multi_Logger_Data);
data.loggers = make([]Logger, len(logs));
copy(data.loggers, logs);
return Logger{multi_logger_proc, data, nil};
data := new(Multi_Logger_Data);
data.loggers = make([]Logger, len(logs));
copy(data.loggers, logs);
return Logger{multi_logger_proc, data, nil};
}
destroy_multi_logger ::proc(log : ^Logger) {
free(log.data);
log^ = nil_logger();
destroy_multi_logger :: proc(log : ^Logger) {
free(log.data);
log^ = nil_logger();
}
multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string,
options: Options, location := #caller_location) {
data := cast(^Multi_Logger_Data)logger_data;
if data.loggers == nil || len(data.loggers) == 0 do return;
for log in data.loggers do log.procedure(log.data, level, text, log.options, location);
data := cast(^Multi_Logger_Data)logger_data;
if data.loggers == nil || len(data.loggers) == 0 {
return;
}
for log in data.loggers {
log.procedure(log.data, level, text, log.options, location);
}
}
nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
@@ -76,6 +80,7 @@ nil_logger :: proc() -> Logger {
return Logger{nil_logger_proc, nil, nil};
}
// TODO(bill): Should these be redesigned so that they are do not rely upon `package fmt`?
debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug, fmt_str=fmt_str, args=args, location=location);
info :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info, fmt_str=fmt_str, args=args, location=location);
warn :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location);
@@ -83,7 +88,7 @@ error :: proc(fmt_str : string, args : ..any, location := #caller_location) do l
fatal :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Fatal, fmt_str=fmt_str, args=args, location=location);
logf :: proc(level : Level, fmt_str : string, args : ..any, location := #caller_location) {
logger := context.logger;
str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
logger.procedure(logger.data, level, str, logger.options, location);
logger := context.logger;
str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
logger.procedure(logger.data, level, str, logger.options, location);
}
+289
View File
@@ -0,0 +1,289 @@
package linalg
import "core:math"
import "intrinsics"
// Generic
dot_vector :: proc(a, b: $T/[$N]$E) -> (c: E) {
for i in 0..<N {
c += a[i] * b[i];
}
return;
}
dot_quaternion128 :: proc(a, b: $T/quaternion128) -> (c: f32) {
return real(a)*real(a) + imag(a)*imag(b) + jmag(a)*jmag(b) + kmag(a)*kmag(b);
}
dot_quaternion256 :: proc(a, b: $T/quaternion256) -> (c: f64) {
return real(a)*real(a) + imag(a)*imag(b) + jmag(a)*jmag(b) + kmag(a)*kmag(b);
}
dot :: proc{dot_vector, dot_quaternion128, dot_quaternion256};
cross2 :: proc(a, b: $T/[2]$E) -> E {
return a[0]*b[1] - b[0]*a[1];
}
cross3 :: proc(a, b: $T/[3]$E) -> (c: T) {
c[0] = +(a[1]*b[2] - b[1]*a[2]);
c[1] = -(a[2]*b[0] - b[2]*a[0]);
c[2] = +(a[0]*b[1] - b[0]*a[1]);
return;
}
cross :: proc{cross2, cross3};
normalize_vector :: proc(v: $T/[$N]$E) -> T {
return v / length(v);
}
normalize_quaternion128 :: proc(q: $Q/quaternion128) -> Q {
return q/abs(q);
}
normalize_quaternion256 :: proc(q: $Q/quaternion256) -> Q {
return q/abs(q);
}
normalize :: proc{normalize_vector, normalize_quaternion128, normalize_quaternion256};
normalize0_vector :: proc(v: $T/[$N]$E) -> T {
m := length(v);
return m == 0 ? 0 : v/m;
}
normalize0_quaternion128 :: proc(q: $Q/quaternion128) -> Q {
m := abs(q);
return m == 0 ? 0 : q/m;
}
normalize0_quaternion256 :: proc(q: $Q/quaternion256) -> Q {
m := abs(q);
return m == 0 ? 0 : q/m;
}
normalize0 :: proc{normalize0_vector, normalize0_quaternion128, normalize0_quaternion256};
length :: proc(v: $T/[$N]$E) -> E {
return math.sqrt(dot(v, v));
}
identity :: proc($T: typeid/[$N][N]$E) -> (m: T) {
for i in 0..<N do m[i][i] = E(1);
return m;
}
transpose :: proc(a: $T/[$N][$M]$E) -> (m: [M][N]E) {
for j in 0..<M {
for i in 0..<N {
m[j][i] = a[i][j];
}
}
return;
}
mul_matrix :: proc(a, b: $M/[$N][N]$E) -> (c: M)
where !intrinsics.type_is_array(E),
intrinsics.type_is_numeric(E) {
for i in 0..<N {
for k in 0..<N {
for j in 0..<N {
c[k][i] += a[j][i] * b[k][j];
}
}
}
return;
}
mul_matrix_differ :: proc(a: $A/[$J][$I]$E, b: $B/[$K][J]E) -> (c: [K][I]E)
where !intrinsics.type_is_array(E),
intrinsics.type_is_numeric(E),
I != K {
for k in 0..<K {
for j in 0..<J {
for i in 0..<I {
c[k][i] += a[j][i] * b[k][j];
}
}
}
return;
}
mul_matrix_vector :: proc(a: $A/[$I][$J]$E, b: $B/[I]E) -> (c: B)
where !intrinsics.type_is_array(E),
intrinsics.type_is_numeric(E) {
for i in 0..<I {
for j in 0..<J {
c[i] += a[i][j] * b[i];
}
}
return;
}
mul_quaternion128_vector3 :: proc(q: $Q/quaternion128, v: $V/[3]$F/f32) -> V {
Raw_Quaternion :: struct {xyz: [3]f32, r: f32};
q := transmute(Raw_Quaternion)q;
v := transmute([3]f32)v;
t := cross(2*q.xyz, v);
return V(v + q.r*t + cross(q.xyz, t));
}
mul_quaternion256_vector3 :: proc(q: $Q/quaternion256, v: $V/[3]$F/f64) -> V {
Raw_Quaternion :: struct {xyz: [3]f64, r: f64};
q := transmute(Raw_Quaternion)q;
v := transmute([3]f64)v;
t := cross(2*q.xyz, v);
return V(v + q.r*t + cross(q.xyz, t));
}
mul_quaternion_vector3 :: proc{mul_quaternion128_vector3, mul_quaternion256_vector3};
mul :: proc{
mul_matrix,
mul_matrix_differ,
mul_matrix_vector,
mul_quaternion128_vector3,
mul_quaternion256_vector3,
};
// Specific
Float :: f32;
Vector2 :: distinct [2]Float;
Vector3 :: distinct [3]Float;
Vector4 :: distinct [4]Float;
Matrix1x1 :: distinct [1][1]Float;
Matrix1x2 :: distinct [1][2]Float;
Matrix1x3 :: distinct [1][3]Float;
Matrix1x4 :: distinct [1][4]Float;
Matrix2x1 :: distinct [2][1]Float;
Matrix2x2 :: distinct [2][2]Float;
Matrix2x3 :: distinct [2][3]Float;
Matrix2x4 :: distinct [2][4]Float;
Matrix3x1 :: distinct [3][1]Float;
Matrix3x2 :: distinct [3][2]Float;
Matrix3x3 :: distinct [3][3]Float;
Matrix3x4 :: distinct [3][4]Float;
Matrix4x1 :: distinct [4][1]Float;
Matrix4x2 :: distinct [4][2]Float;
Matrix4x3 :: distinct [4][3]Float;
Matrix4x4 :: distinct [4][4]Float;
Matrix1 :: Matrix1x1;
Matrix2 :: Matrix2x2;
Matrix3 :: Matrix3x3;
Matrix4 :: Matrix4x4;
Quaternion :: distinct (size_of(Float) == size_of(f32) ? quaternion128 : quaternion256);
translate_matrix4 :: proc(v: Vector3) -> Matrix4 {
m := identity(Matrix4);
m[3][0] = v[0];
m[3][1] = v[1];
m[3][2] = v[2];
return m;
}
rotate_matrix4 :: proc(v: Vector3, angle_radians: Float) -> Matrix4 {
c := math.cos(angle_radians);
s := math.sin(angle_radians);
a := normalize(v);
t := a * (1-c);
rot := identity(Matrix4);
rot[0][0] = c + t[0]*a[0];
rot[0][1] = 0 + t[0]*a[1] + s*a[2];
rot[0][2] = 0 + t[0]*a[2] - s*a[1];
rot[0][3] = 0;
rot[1][0] = 0 + t[1]*a[0] - s*a[2];
rot[1][1] = c + t[1]*a[1];
rot[1][2] = 0 + t[1]*a[2] + s*a[0];
rot[1][3] = 0;
rot[2][0] = 0 + t[2]*a[0] + s*a[1];
rot[2][1] = 0 + t[2]*a[1] - s*a[0];
rot[2][2] = c + t[2]*a[2];
rot[2][3] = 0;
return rot;
}
scale_matrix4 :: proc(m: Matrix4, v: Vector3) -> Matrix4 {
mm := m;
mm[0][0] *= v[0];
mm[1][1] *= v[1];
mm[2][2] *= v[2];
return mm;
}
look_at :: proc(eye, centre, up: Vector3) -> Matrix4 {
f := normalize(centre - eye);
s := normalize(cross(f, up));
u := cross(s, f);
return Matrix4{
{+s.x, +u.x, -f.x, 0},
{+s.y, +u.y, -f.y, 0},
{+s.z, +u.z, -f.z, 0},
{-dot(s, eye), -dot(u, eye), +dot(f, eye), 1},
};
}
perspective :: proc(fovy, aspect, near, far: Float) -> (m: Matrix4) {
tan_half_fovy := math.tan(0.5 * fovy);
m[0][0] = 1 / (aspect*tan_half_fovy);
m[1][1] = 1 / (tan_half_fovy);
m[2][2] = -(far + near) / (far - near);
m[2][3] = -1;
m[3][2] = -2*far*near / (far - near);
return;
}
ortho3d :: proc(left, right, bottom, top, near, far: Float) -> (m: Matrix4) {
m[0][0] = +2 / (right - left);
m[1][1] = +2 / (top - bottom);
m[2][2] = -2 / (far - near);
m[3][0] = -(right + left) / (right - left);
m[3][1] = -(top + bottom) / (top - bottom);
m[3][2] = -(far + near) / (far- near);
m[3][3] = 1;
return;
}
axis_angle :: proc(axis: Vector3, angle_radians: Float) -> Quaternion {
t := angle_radians*0.5;
w := math.cos(t);
v := normalize(axis) * math.sin(t);
return quaternion(w, v.x, v.y, v.z);
}
angle_axis :: proc(angle_radians: Float, axis: Vector3) -> Quaternion {
t := angle_radians*0.5;
w := math.cos(t);
v := normalize(axis) * math.sin(t);
return quaternion(w, v.x, v.y, v.z);
}
euler_angles :: proc(pitch, yaw, roll: Float) -> Quaternion {
p := axis_angle({1, 0, 0}, pitch);
y := axis_angle({0, 1, 0}, yaw);
r := axis_angle({0, 0, 1}, roll);
return (y * p) * r;
}
+390 -391
View File
@@ -1,36 +1,41 @@
package math
import "intrinsics"
Float_Class :: enum {
Normal, // an ordinary nonzero floating point value
Subnormal, // a subnormal floating point value
Zero, // zero
Neg_Zero, // the negative zero
NaN, // Not-A-Number (NaN)
Inf, // positive infinity
Neg_Inf // negative infinity
};
TAU :: 6.28318530717958647692528676655900576;
PI :: 3.14159265358979323846264338327950288;
E :: 2.71828182845904523536;
τ :: TAU;
π :: PI;
e :: E;
SQRT_TWO :: 1.41421356237309504880168872420969808;
SQRT_THREE :: 1.73205080756887729352744634150587236;
SQRT_FIVE :: 2.23606797749978969640917366873127623;
LOG_TWO :: 0.693147180559945309417232121458176568;
LOG_TEN :: 2.30258509299404568401799145468436421;
LN2 :: 0.693147180559945309417232121458176568;
LN10 :: 2.30258509299404568401799145468436421;
EPSILON :: 1.19209290e-7;
MAX_F64_PRECISION :: 16; // Maximum number of meaningful digits after the decimal point for 'f64'
MAX_F32_PRECISION :: 8; // Maximum number of meaningful digits after the decimal point for 'f32'
τ :: TAU;
π :: PI;
Vec2 :: distinct [2]f32;
Vec3 :: distinct [3]f32;
Vec4 :: distinct [4]f32;
// Column major
Mat2 :: distinct [2][2]f32;
Mat3 :: distinct [3][3]f32;
Mat4 :: distinct [4][4]f32;
Quat :: struct {x, y, z, w: f32};
QUAT_IDENTITY := Quat{x = 0, y = 0, z = 0, w = 1};
RAD_PER_DEG :: TAU/360.0;
DEG_PER_RAD :: 360.0/TAU;
@(default_calling_convention="c")
@(default_calling_convention="none")
foreign _ {
@(link_name="llvm.sqrt.f32")
sqrt_f32 :: proc(x: f32) -> f32 ---;
@@ -58,9 +63,9 @@ foreign _ {
fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---;
@(link_name="llvm.log.f32")
log_f32 :: proc(x: f32) -> f32 ---;
ln_f32 :: proc(x: f32) -> f32 ---;
@(link_name="llvm.log.f64")
log_f64 :: proc(x: f64) -> f64 ---;
ln_f64 :: proc(x: f64) -> f64 ---;
@(link_name="llvm.exp.f32")
exp_f32 :: proc(x: f32) -> f32 ---;
@@ -68,20 +73,40 @@ foreign _ {
exp_f64 :: proc(x: f64) -> f64 ---;
}
log :: proc{log_f32, log_f64};
exp :: proc{exp_f32, exp_f64};
sqrt :: proc{sqrt_f32, sqrt_f64};
sin :: proc{sin_f32, sin_f64};
cos :: proc{cos_f32, cos_f64};
pow :: proc{pow_f32, pow_f64};
fmuladd :: proc{fmuladd_f32, fmuladd_f64};
ln :: proc{ln_f32, ln_f64};
exp :: proc{exp_f32, exp_f64};
log_f32 :: proc(x, base: f32) -> f32 { return ln(x) / ln(base); }
log_f64 :: proc(x, base: f64) -> f64 { return ln(x) / ln(base); }
log :: proc{log_f32, log_f64};
log2_f32 :: proc(x: f32) -> f32 { return ln(x)/LN2; }
log2_f64 :: proc(x: f64) -> f64 { return ln(x)/LN2; }
log2 :: proc{log2_f32, log2_f64};
log10_f32 :: proc(x: f32) -> f32 { return ln(x)/LN10; }
log10_f64 :: proc(x: f64) -> f64 { return ln(x)/LN10; }
log10 :: proc{log10_f32, log10_f64};
tan_f32 :: proc "c" (θ: f32) -> f32 { return sin(θ)/cos(θ); }
tan_f64 :: proc "c" (θ: f64) -> f64 { return sin(θ)/cos(θ); }
tan :: proc{tan_f32, tan_f64};
lerp :: proc(a, b: $T, t: $E) -> (x: T) { return a*(1-t) + b*t; }
unlerp_f32 :: proc(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); }
unlerp_f64 :: proc(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); }
unlerp :: proc{unlerp_f32, unlerp_f64};
sign_f32 :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
sign_f64 :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
sign_f32 :: proc(x: f32) -> f32 { return f32(int(0 < x) - int(x < 0)); }
sign_f64 :: proc(x: f64) -> f64 { return f64(int(0 < x) - int(x < 0)); }
sign :: proc{sign_f32, sign_f64};
copy_sign_f32 :: proc(x, y: f32) -> f32 {
ix := transmute(u32)x;
@@ -90,7 +115,6 @@ copy_sign_f32 :: proc(x, y: f32) -> f32 {
ix |= iy & 0x8000_0000;
return transmute(f32)ix;
}
copy_sign_f64 :: proc(x, y: f64) -> f64 {
ix := transmute(u64)x;
iy := transmute(u64)y;
@@ -98,22 +122,89 @@ copy_sign_f64 :: proc(x, y: f64) -> f64 {
ix |= iy & 0x8000_0000_0000_0000;
return transmute(f64)ix;
}
sqrt :: proc{sqrt_f32, sqrt_f64};
sin :: proc{sin_f32, sin_f64};
cos :: proc{cos_f32, cos_f64};
tan :: proc{tan_f32, tan_f64};
pow :: proc{pow_f32, pow_f64};
fmuladd :: proc{fmuladd_f32, fmuladd_f64};
sign :: proc{sign_f32, sign_f64};
copy_sign :: proc{copy_sign_f32, copy_sign_f64};
round_f32 :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
round_f64 :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
to_radians_f32 :: proc(degrees: f32) -> f32 { return degrees * RAD_PER_DEG; }
to_radians_f64 :: proc(degrees: f64) -> f64 { return degrees * RAD_PER_DEG; }
to_degrees_f32 :: proc(radians: f32) -> f32 { return radians * DEG_PER_RAD; }
to_degrees_f64 :: proc(radians: f64) -> f64 { return radians * DEG_PER_RAD; }
to_radians :: proc{to_radians_f32, to_radians_f64};
to_degrees :: proc{to_degrees_f32, to_degrees_f64};
trunc_f32 :: proc(x: f32) -> f32 {
trunc_internal :: proc(f: f32) -> f32 {
mask :: 0xff;
shift :: 32 - 9;
bias :: 0x7f;
if f < 1 {
switch {
case f < 0: return -trunc_internal(-f);
case f == 0: return f;
case: return 0;
}
}
x := transmute(u32)f;
e := (x >> shift) & mask - bias;
if e < shift {
x &= ~(1 << (shift-e)) - 1;
}
return transmute(f32)x;
}
switch classify(x) {
case .Zero, .Neg_Zero, .NaN, .Inf, .Neg_Inf:
return x;
}
return trunc_internal(x);
}
trunc_f64 :: proc(x: f64) -> f64 {
trunc_internal :: proc(f: f64) -> f64 {
mask :: 0x7ff;
shift :: 64 - 12;
bias :: 0x3ff;
if f < 1 {
switch {
case f < 0: return -trunc_internal(-f);
case f == 0: return f;
case: return 0;
}
}
x := transmute(u64)f;
e := (x >> shift) & mask - bias;
if e < shift {
x &= ~(1 << (shift-e)) - 1;
}
return transmute(f64)x;
}
switch classify(x) {
case .Zero, .Neg_Zero, .NaN, .Inf, .Neg_Inf:
return x;
}
return trunc_internal(x);
}
trunc :: proc{trunc_f32, trunc_f64};
round_f32 :: proc(x: f32) -> f32 {
return x < 0 ? ceil(x - 0.5) : floor(x + 0.5);
}
round_f64 :: proc(x: f64) -> f64 {
return x < 0 ? ceil(x - 0.5) : floor(x + 0.5);
}
round :: proc{round_f32, round_f64};
ceil_f32 :: proc(x: f32) -> f32 { return -floor(-x); }
ceil_f64 :: proc(x: f64) -> f64 { return -floor(-x); }
ceil :: proc{ceil_f32, ceil_f64};
floor_f32 :: proc(x: f32) -> f32 {
if x == 0 || is_nan(x) || is_inf(x) {
return x;
@@ -144,35 +235,27 @@ floor_f64 :: proc(x: f64) -> f64 {
}
floor :: proc{floor_f32, floor_f64};
ceil_f32 :: proc(x: f32) -> f32 { return -floor_f32(-x); }
ceil_f64 :: proc(x: f64) -> f64 { return -floor_f64(-x); }
ceil :: proc{ceil_f32, ceil_f64};
remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
remainder :: proc{remainder_f32, remainder_f64};
mod_f32 :: proc(x, y: f32) -> f32 {
result: f32;
y = abs(y);
result = remainder(abs(x), y);
if sign(result) < 0 {
result += y;
floor_div :: proc(x, y: $T) -> T
where intrinsics.type_is_integer(T) {
a := x / y;
r := x % y;
if (r > 0 && y < 0) || (r < 0 && y > 0) {
a -= 1;
}
return copy_sign(result, x);
return a;
}
mod_f64 :: proc(x, y: f64) -> f64 {
result: f64;
y = abs(y);
result = remainder(abs(x), y);
if sign(result) < 0 {
result += y;
}
return copy_sign(result, x);
}
mod :: proc{mod_f32, mod_f64};
// TODO(bill): These need to implemented with the actual instructions
floor_mod :: proc(x, y: $T) -> T
where intrinsics.type_is_integer(T) {
r := x % y;
if (r > 0 && y < 0) || (r < 0 && y > 0) {
r += y;
}
return r;
}
modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
shift :: 32 - 8 - 1;
mask :: 0xff;
@@ -192,8 +275,8 @@ modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
i := transmute(u32)x;
e := uint(i>>shift)&mask - bias;
if e < 32-9 {
i &~= 1<<(32-9-e) - 1;
if e < shift {
i &~= 1<<(shift-e) - 1;
}
int = transmute(f32)i;
frac = x - int;
@@ -218,358 +301,274 @@ modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) {
i := transmute(u64)x;
e := uint(i>>shift)&mask - bias;
if e < 64-12 {
i &~= 1<<(64-12-e) - 1;
if e < shift {
i &~= 1<<(shift-e) - 1;
}
int = transmute(f64)i;
frac = x - int;
return;
}
modf :: proc{modf_f32, modf_f64};
split_decimal :: modf;
is_nan_f32 :: inline proc(x: f32) -> bool { return x != x; }
is_nan_f64 :: inline proc(x: f64) -> bool { return x != x; }
mod_f32 :: proc(x, y: f32) -> (n: f32) {
z := abs(y);
n = remainder(abs(x), z);
if sign(n) < 0 {
n += z;
}
return copy_sign(n, x);
}
mod_f64 :: proc(x, y: f64) -> (n: f64) {
z := abs(y);
n = remainder(abs(x), z);
if sign(n) < 0 {
n += z;
}
return copy_sign(n, x);
}
mod :: proc{mod_f32, mod_f64};
remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
remainder :: proc{remainder_f32, remainder_f64};
gcd :: proc(x, y: $T) -> T
where intrinsics.type_is_ordered_numeric(T) {
x, y := x, y;
for y != 0 {
x %= y;
x, y = y, x;
}
return abs(x);
}
lcm :: proc(x, y: $T) -> T
where intrinsics.type_is_ordered_numeric(T) {
return x / gcd(x, y) * y;
}
frexp_f32 :: proc(x: f32) -> (significand: f32, exponent: int) {
switch {
case x == 0:
return 0, 0;
case x < 0:
significand, exponent = frexp(-x);
return -significand, exponent;
}
ex := trunc(log2(x));
exponent = int(ex);
significand = x / pow(2.0, ex);
if abs(significand) >= 1 {
exponent += 1;
significand /= 2;
}
if exponent == 1024 && significand == 0 {
significand = 0.99999999999999988898;
}
return;
}
frexp_f64 :: proc(x: f64) -> (significand: f64, exponent: int) {
switch {
case x == 0:
return 0, 0;
case x < 0:
significand, exponent = frexp(-x);
return -significand, exponent;
}
ex := trunc(log2(x));
exponent = int(ex);
significand = x / pow(2.0, ex);
if abs(significand) >= 1 {
exponent += 1;
significand /= 2;
}
if exponent == 1024 && significand == 0 {
significand = 0.99999999999999988898;
}
return;
}
frexp :: proc{frexp_f32, frexp_f64};
binomial :: proc(n, k: int) -> int {
switch {
case k <= 0: return 1;
case 2*k > n: return binomial(n, n-k);
}
b := n;
for i in 2..<k {
b = (b * (n+1-i))/i;
}
return b;
}
factorial :: proc(n: int) -> int {
when size_of(int) == size_of(i64) {
@static table := [21]int{
1,
1,
2,
6,
24,
120,
720,
5_040,
40_320,
362_880,
3_628_800,
39_916_800,
479_001_600,
6_227_020_800,
87_178_291_200,
1_307_674_368_000,
20_922_789_888_000,
355_687_428_096_000,
6_402_373_705_728_000,
121_645_100_408_832_000,
2_432_902_008_176_640_000,
};
} else {
@static table := [13]int{
1,
1,
2,
6,
24,
120,
720,
5_040,
40_320,
362_880,
3_628_800,
39_916_800,
479_001_600,
};
}
assert(n >= 0, "parameter must not be negative");
assert(n < len(table), "parameter is too large to lookup in the table");
return 0;
}
classify_f32 :: proc(x: f32) -> Float_Class {
switch {
case x == 0:
i := transmute(i32)x;
if i < 0 {
return .Neg_Zero;
}
return .Zero;
case x*0.5 == x:
if x < 0 {
return .Neg_Inf;
}
return .Inf;
case x != x:
return .NaN;
}
u := transmute(u32)x;
exp := int(u>>23) & (1<<8 - 1);
if exp == 0 {
return .Subnormal;
}
return .Normal;
}
classify_f64 :: proc(x: f64) -> Float_Class {
switch {
case x == 0:
i := transmute(i64)x;
if i < 0 {
return .Neg_Zero;
}
return .Zero;
case x*0.5 == x:
if x < 0 {
return .Neg_Inf;
}
return .Inf;
case x != x:
return .NaN;
}
u := transmute(u64)x;
exp := int(u>>52) & (1<<11 - 1);
if exp == 0 {
return .Subnormal;
}
return .Normal;
}
classify :: proc{classify_f32, classify_f64};
is_nan_f32 :: proc(x: f32) -> bool { return classify(x) == .NaN; }
is_nan_f64 :: proc(x: f64) -> bool { return classify(x) == .NaN; }
is_nan :: proc{is_nan_f32, is_nan_f64};
is_finite_f32 :: inline proc(x: f32) -> bool { return !is_nan(x-x); }
is_finite_f64 :: inline proc(x: f64) -> bool { return !is_nan(x-x); }
is_finite :: proc{is_finite_f32, is_finite_f64};
is_inf_f32 :: proc(x: f32, sign := 0) -> bool {
return sign >= 0 && x > F32_MAX || sign <= 0 && x < -F32_MAX;
}
is_inf_f64 :: proc(x: f64, sign := 0) -> bool {
return sign >= 0 && x > F64_MAX || sign <= 0 && x < -F64_MAX;
}
// If sign > 0, is_inf reports whether f is positive infinity
// If sign < 0, is_inf reports whether f is negative infinity
// If sign == 0, is_inf reports whether f is either infinity
is_inf_f32 :: proc(x: f32) -> bool { return classify(abs(x)) == .Inf; }
is_inf_f64 :: proc(x: f64) -> bool { return classify(abs(x)) == .Inf; }
is_inf :: proc{is_inf_f32, is_inf_f64};
to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360; }
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
is_power_of_two :: proc(x: int) -> bool {
return x > 0 && (x & (x-1)) == 0;
}
mul :: proc{
mat3_mul,
mat4_mul, mat4_mul_vec4,
quat_mul, quat_mulf,
};
div :: proc{quat_div, quat_divf};
inverse :: proc{mat4_inverse, quat_inverse};
dot :: proc{vec_dot, quat_dot};
cross :: proc{cross2, cross3};
vec_dot :: proc(a, b: $T/[$N]$E) -> E {
res: E;
for i in 0..<N {
res += a[i] * b[i];
next_power_of_two :: proc(x: int) -> int {
k := x -1;
when size_of(int) == 8 {
k = k | (k >> 32);
}
return res;
k = k | (k >> 16);
k = k | (k >> 8);
k = k | (k >> 4);
k = k | (k >> 2);
k = k | (k >> 1);
k += 1 + int(x <= 0);
return k;
}
cross2 :: proc(a, b: $T/[2]$E) -> E {
return a[0]*b[1] - a[1]*b[0];
sum :: proc(x: $T/[]$E) -> (res: E)
where intrinsics.BuiltinProc_type_is_numeric(E) {
for i in x {
res += i;
}
return;
}
cross3 :: proc(a, b: $T/[3]$E) -> T {
i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1);
j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0);
return T(i - j);
prod :: proc(x: $T/[]$E) -> (res: E)
where intrinsics.BuiltinProc_type_is_numeric(E) {
for i in x {
res *= i;
}
return;
}
cumsum_inplace :: proc(x: $T/[]$E) -> T
where intrinsics.BuiltinProc_type_is_numeric(E) {
for i in 1..<len(x) {
x[i] = x[i-1] + x[i];
}
}
length :: proc(v: $T/[$N]$E) -> E { return sqrt(dot(v, v)); }
norm :: proc(v: $T/[$N]$E) -> T { return v / length(v); }
norm0 :: proc(v: $T/[$N]$E) -> T {
m := length(v);
return m == 0 ? 0 : v/m;
}
identity :: proc($T: typeid/[$N][N]$E) -> T {
m: T;
for i in 0..<N do m[i][i] = E(1);
return m;
}
transpose :: proc(m: $M/[$N][N]f32) -> M {
for j in 0..<N {
for i in 0..<N {
m[i][j], m[j][i] = m[j][i], m[i][j];
cumsum :: proc(dst, src: $T/[]$E) -> T
where intrinsics.BuiltinProc_type_is_numeric(E) {
N := min(len(dst), len(src));
if N > 0 {
dst[0] = src[0];
for i in 1..<N {
dst[i] = dst[i-1] + src[i];
}
}
return m;
return dst[:N];
}
mat3_mul :: proc(a, b: Mat3) -> Mat3 {
c: Mat3;
for j in 0..<3 {
for i in 0..<3 {
c[j][i] = a[0][i]*b[j][0] +
a[1][i]*b[j][1] +
a[2][i]*b[j][2];
}
}
return c;
}
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
c: Mat4;
for j in 0..<4 {
for i in 0..<4 {
c[j][i] = a[0][i]*b[j][0] +
a[1][i]*b[j][1] +
a[2][i]*b[j][2] +
a[3][i]*b[j][3];
}
}
return c;
}
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
return Vec4{
m[0][0]*v[0] + m[1][0]*v[1] + m[2][0]*v[2] + m[3][0]*v[3],
m[0][1]*v[0] + m[1][1]*v[1] + m[2][1]*v[2] + m[3][1]*v[3],
m[0][2]*v[0] + m[1][2]*v[1] + m[2][2]*v[2] + m[3][2]*v[3],
m[0][3]*v[0] + m[1][3]*v[1] + m[2][3]*v[2] + m[3][3]*v[3],
};
}
mat4_inverse :: proc(m: Mat4) -> Mat4 {
o: Mat4;
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3];
sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2];
sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3];
sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2];
sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1];
sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3];
sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2];
sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3];
sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2];
sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1];
sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3];
sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3];
sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2];
sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3];
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2];
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1];
o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02);
o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04);
o[0][2] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05);
o[0][3] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05);
o[1][0] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02);
o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04);
o[1][2] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05);
o[1][3] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05);
o[2][0] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08);
o[2][1] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10);
o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12);
o[2][3] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12);
o[3][0] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15);
o[3][1] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17);
o[3][2] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18);
o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18);
ood := 1.0 / (m[0][0] * o[0][0] +
m[0][1] * o[0][1] +
m[0][2] * o[0][2] +
m[0][3] * o[0][3]);
o[0][0] *= ood;
o[0][1] *= ood;
o[0][2] *= ood;
o[0][3] *= ood;
o[1][0] *= ood;
o[1][1] *= ood;
o[1][2] *= ood;
o[1][3] *= ood;
o[2][0] *= ood;
o[2][1] *= ood;
o[2][2] *= ood;
o[2][3] *= ood;
o[3][0] *= ood;
o[3][1] *= ood;
o[3][2] *= ood;
o[3][3] *= ood;
return o;
}
mat4_translate :: proc(v: Vec3) -> Mat4 {
m := identity(Mat4);
m[3][0] = v[0];
m[3][1] = v[1];
m[3][2] = v[2];
m[3][3] = 1;
return m;
}
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
c := cos(angle_radians);
s := sin(angle_radians);
a := norm(v);
t := a * (1-c);
rot := identity(Mat4);
rot[0][0] = c + t[0]*a[0];
rot[0][1] = 0 + t[0]*a[1] + s*a[2];
rot[0][2] = 0 + t[0]*a[2] - s*a[1];
rot[0][3] = 0;
rot[1][0] = 0 + t[1]*a[0] - s*a[2];
rot[1][1] = c + t[1]*a[1];
rot[1][2] = 0 + t[1]*a[2] + s*a[0];
rot[1][3] = 0;
rot[2][0] = 0 + t[2]*a[0] + s*a[1];
rot[2][1] = 0 + t[2]*a[1] - s*a[0];
rot[2][2] = c + t[2]*a[2];
rot[2][3] = 0;
return rot;
}
scale_vec3 :: proc(m: Mat4, v: Vec3) -> Mat4 {
m[0][0] *= v[0];
m[1][1] *= v[1];
m[2][2] *= v[2];
return m;
}
scale_f32 :: proc(m: Mat4, s: f32) -> Mat4 {
m[0][0] *= s;
m[1][1] *= s;
m[2][2] *= s;
return m;
}
scale :: proc{scale_vec3, scale_f32};
look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
f := norm(centre - eye);
s := norm(cross(f, up));
u := cross(s, f);
return Mat4{
{+s.x, +u.x, -f.x, 0},
{+s.y, +u.y, -f.y, 0},
{+s.z, +u.z, -f.z, 0},
{-dot(s, eye), -dot(u, eye), dot(f, eye), 1},
};
}
perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
m: Mat4;
tan_half_fovy := tan(0.5 * fovy);
m[0][0] = 1.0 / (aspect*tan_half_fovy);
m[1][1] = 1.0 / (tan_half_fovy);
m[2][2] = -(far + near) / (far - near);
m[2][3] = -1.0;
m[3][2] = -2.0*far*near / (far - near);
return m;
}
ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
m := identity(Mat4);
m[0][0] = +2.0 / (right - left);
m[1][1] = +2.0 / (top - bottom);
m[2][2] = -2.0 / (far - near);
m[3][0] = -(right + left) / (right - left);
m[3][1] = -(top + bottom) / (top - bottom);
m[3][2] = -(far + near) / (far - near);
return m;
}
// Quaternion operations
conj :: proc(q: Quat) -> Quat {
return Quat{-q.x, -q.y, -q.z, q.w};
}
quat_mul :: proc(q0, q1: Quat) -> Quat {
d: Quat;
d.x = q0.w * q1.x + q0.x * q1.w + q0.y * q1.z - q0.z * q1.y;
d.y = q0.w * q1.y - q0.x * q1.z + q0.y * q1.w + q0.z * q1.x;
d.z = q0.w * q1.z + q0.x * q1.y - q0.y * q1.x + q0.z * q1.w;
d.w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z;
return d;
}
quat_mulf :: proc(q: Quat, f: f32) -> Quat { return Quat{q.x*f, q.y*f, q.z*f, q.w*f}; }
quat_divf :: proc(q: Quat, f: f32) -> Quat { return Quat{q.x/f, q.y/f, q.z/f, q.w/f}; }
quat_div :: proc(q0, q1: Quat) -> Quat { return mul(q0, quat_inverse(q1)); }
quat_inverse :: proc(q: Quat) -> Quat { return div(conj(q), dot(q, q)); }
quat_dot :: proc(q0, q1: Quat) -> f32 { return q0.x*q1.x + q0.y*q1.y + q0.z*q1.z + q0.w*q1.w; }
quat_norm :: proc(q: Quat) -> Quat {
m := sqrt(dot(q, q));
return div(q, m);
}
axis_angle :: proc(axis: Vec3, angle_radians: f32) -> Quat {
v := norm(axis) * sin(0.5*angle_radians);
w := cos(0.5*angle_radians);
return Quat{v.x, v.y, v.z, w};
}
euler_angles :: proc(pitch, yaw, roll: f32) -> Quat {
p := axis_angle(Vec3{1, 0, 0}, pitch);
y := axis_angle(Vec3{0, 1, 0}, yaw);
r := axis_angle(Vec3{0, 0, 1}, roll);
return mul(mul(y, p), r);
}
quat_to_mat4 :: proc(q: Quat) -> Mat4 {
a := quat_norm(q);
xx := a.x*a.x; yy := a.y*a.y; zz := a.z*a.z;
xy := a.x*a.y; xz := a.x*a.z; yz := a.y*a.z;
wx := a.w*a.x; wy := a.w*a.y; wz := a.w*a.z;
m := identity(Mat4);
m[0][0] = 1 - 2*(yy + zz);
m[0][1] = 2*(xy + wz);
m[0][2] = 2*(xz - wy);
m[1][0] = 2*(xy - wz);
m[1][1] = 1 - 2*(xx + zz);
m[1][2] = 2*(yz + wx);
m[2][0] = 2*(xz + wy);
m[2][1] = 2*(yz - wx);
m[2][2] = 1 - 2*(xx + yy);
return m;
}
F32_DIG :: 6;
F32_EPSILON :: 1.192092896e-07;
+2 -2
View File
@@ -128,8 +128,8 @@ norm_float64 :: proc(r: ^Rand = global_rand_ptr) -> f64 {
if i == 0 {
for {
x = -math.log(float64(r)) * (1.0/ rn);
y := -math.log(float64(r));
x = -math.ln(float64(r)) * (1.0/ rn);
y := -math.ln(float64(r));
if y+y >= x*x {
break;
}
+24 -2
View File
@@ -47,8 +47,17 @@ uint64 :: proc(r: ^Rand = global_rand_ptr) -> u64 {
return (a<<32) | b;
}
int31 :: proc(r: ^Rand = global_rand_ptr) -> i32 { return i32(uint32(r) << 1 >> 1); }
int63 :: proc(r: ^Rand = global_rand_ptr) -> i64 { return i64(uint64(r) << 1 >> 1); }
uint128 :: proc(r: ^Rand = global_rand_ptr) -> u128 {
a := u128(_random(r));
b := u128(_random(r));
c := u128(_random(r));
d := u128(_random(r));
return (a<<96) | (b<<64) | (c<<32) | d;
}
int31 :: proc(r: ^Rand = global_rand_ptr) -> i32 { return i32(uint32(r) << 1 >> 1); }
int63 :: proc(r: ^Rand = global_rand_ptr) -> i64 { return i64(uint64(r) << 1 >> 1); }
int127 :: proc(r: ^Rand = global_rand_ptr) -> i128 { return i128(uint128(r) << 1 >> 1); }
int31_max :: proc(n: i32, r: ^Rand = global_rand_ptr) -> i32 {
if n <= 0 do panic("Invalid argument to int31_max");
@@ -76,6 +85,19 @@ int63_max :: proc(n: i64, r: ^Rand = global_rand_ptr) -> i64 {
return v % n;
}
int127_max :: proc(n: i128, r: ^Rand = global_rand_ptr) -> i128 {
if n <= 0 do panic("Invalid argument to int63_max");
if n&(n-1) == 0 {
return int127(r) & (n-1);
}
max := i128((1<<63) - 1 - (1<<63)&u128(n));
v := int127(r);
for v > max {
v = int127(r);
}
return v % n;
}
int_max :: proc(n: int, r: ^Rand = global_rand_ptr) -> int {
if n <= 0 do panic("Invalid argument to int_max");
when size_of(int) == 4 {
+11 -12
View File
@@ -1,7 +1,5 @@
package mem
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
@@ -377,7 +375,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return nil;
}
alignment = clamp(alignment, 1, 8*size_of(Stack_Allocation_Header{}.padding)/2);
align := clamp(alignment, 1, 8*size_of(Stack_Allocation_Header{}.padding)/2);
raw_alloc :: proc(s: ^Small_Stack, size, alignment: int) -> rawptr {
curr_addr := uintptr(&s.data[0]) + uintptr(s.offset);
@@ -400,7 +398,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
switch mode {
case .Alloc:
return raw_alloc(s, size, alignment);
return raw_alloc(s, size, align);
case .Free:
if old_memory == nil {
return nil;
@@ -429,7 +427,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
case .Resize:
if old_memory == nil {
return raw_alloc(s, size, alignment);
return raw_alloc(s, size, align);
}
if size == 0 {
return nil;
@@ -452,7 +450,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return old_memory;
}
ptr := raw_alloc(s, size, alignment);
ptr := raw_alloc(s, size, align);
copy(ptr, old_memory, min(old_size, size));
return ptr;
}
@@ -568,9 +566,10 @@ dynamic_pool_alloc :: proc(using pool: ^Dynamic_Pool, bytes: int) -> rawptr {
}
extra := alignment - (bytes % alignment);
bytes += extra;
if bytes >= out_band_size {
n := bytes;
extra := alignment - (n % alignment);
n += extra;
if n >= out_band_size {
assert(block_allocator.procedure != nil);
memory := block_allocator.procedure(block_allocator.data, Allocator_Mode.Alloc,
block_size, alignment,
@@ -581,7 +580,7 @@ dynamic_pool_alloc :: proc(using pool: ^Dynamic_Pool, bytes: int) -> rawptr {
return memory;
}
if bytes_left < bytes {
if bytes_left < n {
cycle_new_block(pool);
if current_block == nil {
return nil;
@@ -589,8 +588,8 @@ dynamic_pool_alloc :: proc(using pool: ^Dynamic_Pool, bytes: int) -> rawptr {
}
memory := current_pos;
current_pos = ptr_offset((^byte)(current_pos), bytes);
bytes_left -= bytes;
current_pos = ptr_offset((^byte)(current_pos), n);
bytes_left -= n;
return memory;
}
+14 -26
View File
@@ -1,5 +1,7 @@
package mem
import "core:runtime"
foreign _ {
@(link_name = "llvm.bswap.i16") swap16 :: proc(b: u16) -> u16 ---;
@(link_name = "llvm.bswap.i32") swap32 :: proc(b: u32) -> u32 ---;
@@ -38,34 +40,10 @@ zero_slice :: proc "contextless" (data: $T/[]$E) {
copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
if src == nil do return dst;
// NOTE(bill): This _must_ be implemented like C's memmove
foreign _ {
when size_of(rawptr) == 8 {
@(link_name="llvm.memmove.p0i8.p0i8.i64")
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
} else {
@(link_name="llvm.memmove.p0i8.p0i8.i32")
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
}
}
llvm_memmove(dst, src, len, 1, false);
return dst;
return runtime.mem_copy(dst, src, len);
}
copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
if src == nil do return dst;
// NOTE(bill): This _must_ be implemented like C's memcpy
foreign _ {
when size_of(rawptr) == 8 {
@(link_name="llvm.memcpy.p0i8.p0i8.i64")
llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
} else {
@(link_name="llvm.memcpy.p0i8.p0i8.i32")
llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
}
}
llvm_memcpy(dst, src, len, 1, false);
return dst;
return runtime.mem_copy_non_overlapping(dst, src, len);
}
compare :: inline proc "contextless" (a, b: []byte) -> int {
return compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
@@ -129,6 +107,16 @@ slice_to_bytes :: inline proc "contextless" (slice: $E/[]$T) -> []byte {
return transmute([]byte)s;
}
slice_data_cast :: inline proc "contextless" ($T: typeid/[]$A, slice: $S/[]$B) -> T {
when size_of(A) == 0 || size_of(B) == 0 {
return nil;
} else {
s := transmute(Raw_Slice)slice;
s.len = (len(slice) * size_of(B)) / size_of(A);
return transmute(T)s;
}
}
buffer_from_slice :: inline proc(backing: $T/[]$E) -> [dynamic]E {
s := transmute(Raw_Slice)backing;
+9 -3
View File
@@ -31,19 +31,25 @@ Raw_Map :: struct {
entries: Raw_Dynamic_Array,
}
Raw_Complex64 :: struct {real, imag: f32};
Raw_Complex128 :: struct {real, imag: f64};
Raw_Quaternion128 :: struct {imag, jmag, kmag: f32, real: f32};
Raw_Quaternion256 :: struct {imag, jmag, kmag: f64, real: f64};
Raw_Quaternion128_Vector_Scalar :: struct {vector: [3]f32, scalar: f32};
Raw_Quaternion256_Vector_Scalar :: struct {vector: [3]f64, scalar: f64};
make_any :: inline proc(data: rawptr, id: typeid) -> any {
return transmute(any)Raw_Any{data, id};
}
raw_string_data :: inline proc(s: $T/string) -> ^byte {
return (^Raw_String)(&s).data;
return (transmute(Raw_String)s).data;
}
raw_slice_data :: inline proc(a: $T/[]$E) -> ^E {
return cast(^E)(^Raw_Slice)(&a).data;
return cast(^E)(transmute(Raw_Slice)a).data;
}
raw_dynamic_array_data :: inline proc(a: $T/[dynamic]$E) -> ^E {
return cast(^E)(^Raw_Dynamic_Array)(&a).data;
return cast(^E)(transmute(Raw_Dynamic_Array)a).data;
}
raw_data :: proc{raw_string_data, raw_slice_data, raw_dynamic_array_data};
+121 -110
View File
@@ -1,11 +1,10 @@
package odin_ast
import "core:odin/token"
import "core:odin/tokenizer"
Proc_Tag :: enum {
Bounds_Check,
No_Bounds_Check,
Require_Results,
}
Proc_Tags :: distinct bit_set[Proc_Tag; u32];
@@ -34,12 +33,12 @@ Node_State_Flags :: distinct bit_set[Node_State_Flag];
Comment_Group :: struct {
list: []token.Token,
list: []tokenizer.Token,
}
Node :: struct {
pos: token.Pos,
end: token.Pos,
pos: tokenizer.Pos,
end: tokenizer.Pos,
derived: any,
state_flags: Node_State_Flags,
}
@@ -68,29 +67,29 @@ Ident :: struct {
Implicit :: struct {
using node: Expr,
tok: token.Token,
tok: tokenizer.Token,
}
Undef :: struct {
using node: Expr,
tok: token.Kind,
tok: tokenizer.Token_Kind,
}
Basic_Lit :: struct {
using node: Expr,
tok: token.Token,
tok: tokenizer.Token,
}
Basic_Directive :: struct {
using node: Expr,
tok: token.Token,
tok: tokenizer.Token,
name: string,
}
Ellipsis :: struct {
using node: Expr,
tok: token.Kind,
tok: tokenizer.Token_Kind,
expr: ^Expr,
}
@@ -100,42 +99,44 @@ Proc_Lit :: struct {
body: ^Stmt,
tags: Proc_Tags,
inlining: Proc_Inlining,
where_token: tokenizer.Token,
where_clauses: []^Expr,
}
Comp_Lit :: struct {
using node: Expr,
type: ^Expr,
open: token.Pos,
open: tokenizer.Pos,
elems: []^Expr,
close: token.Pos,
close: tokenizer.Pos,
}
Tag_Expr :: struct {
using node: Expr,
op: token.Token,
op: tokenizer.Token,
name: string,
expr: ^Expr,
}
Unary_Expr :: struct {
using node: Expr,
op: token.Token,
op: tokenizer.Token,
expr: ^Expr,
}
Binary_Expr :: struct {
using node: Expr,
left: ^Expr,
op: token.Token,
op: tokenizer.Token,
right: ^Expr,
}
Paren_Expr :: struct {
using node: Expr,
open: token.Pos,
open: tokenizer.Pos,
expr: ^Expr,
close: token.Pos,
close: tokenizer.Pos,
}
Selector_Expr :: struct {
@@ -152,74 +153,74 @@ Implicit_Selector_Expr :: struct {
Index_Expr :: struct {
using node: Expr,
expr: ^Expr,
open: token.Pos,
open: tokenizer.Pos,
index: ^Expr,
close: token.Pos,
close: tokenizer.Pos,
}
Deref_Expr :: struct {
using node: Expr,
expr: ^Expr,
op: token.Token,
op: tokenizer.Token,
}
Slice_Expr :: struct {
using node: Expr,
expr: ^Expr,
open: token.Pos,
open: tokenizer.Pos,
low: ^Expr,
interval: token.Token,
interval: tokenizer.Token,
high: ^Expr,
close: token.Pos,
close: tokenizer.Pos,
}
Call_Expr :: struct {
using node: Expr,
inlining: Proc_Inlining,
expr: ^Expr,
open: token.Pos,
open: tokenizer.Pos,
args: []^Expr,
ellipsis: token.Token,
close: token.Pos,
ellipsis: tokenizer.Token,
close: tokenizer.Pos,
}
Field_Value :: struct {
using node: Expr,
field: ^Expr,
sep: token.Pos,
sep: tokenizer.Pos,
value: ^Expr,
}
Ternary_Expr :: struct {
using node: Expr,
cond: ^Expr,
op1: token.Token,
op1: tokenizer.Token,
x: ^Expr,
op2: token.Token,
op2: tokenizer.Token,
y: ^Expr,
}
Type_Assertion :: struct {
using node: Expr,
expr: ^Expr,
dot: token.Pos,
open: token.Pos,
dot: tokenizer.Pos,
open: tokenizer.Pos,
type: ^Expr,
close: token.Pos,
close: tokenizer.Pos,
}
Type_Cast :: struct {
using node: Expr,
tok: token.Token,
open: token.Pos,
tok: tokenizer.Token,
open: tokenizer.Pos,
type: ^Expr,
close: token.Pos,
close: tokenizer.Pos,
expr: ^Expr,
}
Auto_Cast :: struct {
using node: Expr,
op: token.Token,
op: tokenizer.Token,
expr: ^Expr,
}
@@ -234,7 +235,7 @@ Bad_Stmt :: struct {
Empty_Stmt :: struct {
using node: Stmt,
semicolon: token.Pos, // Position of the following ';'
semicolon: tokenizer.Pos, // Position of the following ';'
}
Expr_Stmt :: struct {
@@ -244,7 +245,7 @@ Expr_Stmt :: struct {
Tag_Stmt :: struct {
using node: Stmt,
op: token.Token,
op: tokenizer.Token,
name: string,
stmt: ^Stmt,
}
@@ -252,7 +253,7 @@ Tag_Stmt :: struct {
Assign_Stmt :: struct {
using node: Stmt,
lhs: []^Expr,
op: token.Token,
op: tokenizer.Token,
rhs: []^Expr,
}
@@ -260,15 +261,15 @@ Assign_Stmt :: struct {
Block_Stmt :: struct {
using node: Stmt,
label: ^Expr,
open: token.Pos,
open: tokenizer.Pos,
stmts: []^Stmt,
close: token.Pos,
close: tokenizer.Pos,
}
If_Stmt :: struct {
using node: Stmt,
label: ^Expr,
if_pos: token.Pos,
if_pos: tokenizer.Pos,
init: ^Stmt,
cond: ^Expr,
body: ^Stmt,
@@ -277,7 +278,7 @@ If_Stmt :: struct {
When_Stmt :: struct {
using node: Stmt,
when_pos: token.Pos,
when_pos: tokenizer.Pos,
cond: ^Expr,
body: ^Stmt,
else_stmt: ^Stmt,
@@ -296,7 +297,7 @@ Defer_Stmt :: struct {
For_Stmt :: struct {
using node: Stmt,
label: ^Expr,
for_pos: token.Pos,
for_pos: tokenizer.Pos,
init: ^Stmt,
cond: ^Expr,
post: ^Stmt,
@@ -306,10 +307,10 @@ For_Stmt :: struct {
Range_Stmt :: struct {
using node: Stmt,
label: ^Expr,
for_pos: token.Pos,
for_pos: tokenizer.Pos,
val0: ^Expr,
val1: ^Expr,
in_pos: token.Pos,
in_pos: tokenizer.Pos,
expr: ^Expr,
body: ^Stmt,
}
@@ -317,16 +318,16 @@ Range_Stmt :: struct {
Case_Clause :: struct {
using node: Stmt,
case_pos: token.Pos,
case_pos: tokenizer.Pos,
list: []^Expr,
terminator: token.Token,
terminator: tokenizer.Token,
body: []^Stmt,
}
Switch_Stmt :: struct {
using node: Stmt,
label: ^Expr,
switch_pos: token.Pos,
switch_pos: tokenizer.Pos,
init: ^Stmt,
cond: ^Expr,
body: ^Stmt,
@@ -336,7 +337,7 @@ Switch_Stmt :: struct {
Type_Switch_Stmt :: struct {
using node: Stmt,
label: ^Expr,
switch_pos: token.Pos,
switch_pos: tokenizer.Pos,
tag: ^Stmt,
expr: ^Expr,
body: ^Stmt,
@@ -345,7 +346,7 @@ Type_Switch_Stmt :: struct {
Branch_Stmt :: struct {
using node: Stmt,
tok: token.Token,
tok: tokenizer.Token,
label: ^Ident,
}
@@ -376,7 +377,7 @@ Value_Decl :: struct {
Package_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
token: token.Token,
token: tokenizer.Token,
name: string,
comment: ^Comment_Group,
}
@@ -385,9 +386,9 @@ Import_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
is_using: bool,
import_tok: token.Token,
name: token.Token,
relpath: token.Token,
import_tok: tokenizer.Token,
name: tokenizer.Token,
relpath: tokenizer.Token,
fullpath: string,
comment: ^Comment_Group,
}
@@ -396,7 +397,7 @@ Foreign_Block_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
tok: token.Token,
tok: tokenizer.Token,
foreign_library: ^Expr,
body: ^Stmt,
}
@@ -404,27 +405,29 @@ Foreign_Block_Decl :: struct {
Foreign_Import_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
foreign_tok: token.Token,
import_tok: token.Token,
foreign_tok: tokenizer.Token,
import_tok: tokenizer.Token,
name: ^Ident,
collection_name: string,
fullpaths: []string,
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
comment: ^Comment_Group,
}
// Other things
unparen_expr :: proc(expr: ^Expr) -> ^Expr {
unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
val = expr;
if expr == nil {
return nil;
return;
}
for {
e, ok := expr.derived.(Paren_Expr);
e, ok := val.derived.(Paren_Expr);
if !ok do break;
expr = e.expr;
val = e.expr;
}
return expr;
return;
}
Field_Flag :: enum {
@@ -434,7 +437,9 @@ Field_Flag :: enum {
C_Vararg,
Auto_Cast,
In,
Results,
Tags,
Default_Parameters,
Typeid_Token,
}
@@ -442,18 +447,19 @@ Field_Flag :: enum {
Field_Flags :: distinct bit_set[Field_Flag];
Field_Flags_Struct :: Field_Flags{
Field_Flag.Using,
.Using,
.Tags,
};
Field_Flags_Record_Poly_Params :: Field_Flags{
Field_Flag.Typeid_Token,
.Typeid_Token,
};
Field_Flags_Signature :: Field_Flags{
Field_Flag.Ellipsis,
Field_Flag.Using,
Field_Flag.No_Alias,
Field_Flag.C_Vararg,
Field_Flag.Auto_Cast,
Field_Flag.Default_Parameters,
.Ellipsis,
.Using,
.No_Alias,
.C_Vararg,
.Auto_Cast,
.Default_Parameters,
};
Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token};
@@ -462,18 +468,18 @@ Field_Flags_Signature_Results :: Field_Flags_Signature;
Proc_Group :: struct {
using node: Expr,
tok: token.Token,
open: token.Pos,
tok: tokenizer.Token,
open: tokenizer.Pos,
args: []^Expr,
close: token.Pos,
close: tokenizer.Pos,
}
Attribute :: struct {
using node: Node,
tok: token.Kind,
open: token.Pos,
tok: tokenizer.Token_Kind,
open: tokenizer.Pos,
elems: []^Expr,
close: token.Pos,
close: tokenizer.Pos,
}
Field :: struct {
@@ -482,56 +488,57 @@ Field :: struct {
names: []^Expr, // Could be polymorphic
type: ^Expr,
default_value: ^Expr,
tag: tokenizer.Token,
flags: Field_Flags,
comment: ^Comment_Group,
}
Field_List :: struct {
using node: Node,
open: token.Pos,
open: tokenizer.Pos,
list: []^Field,
close: token.Pos,
close: tokenizer.Pos,
}
// Types
Typeid_Type :: struct {
using node: Expr,
tok: token.Kind,
tok: tokenizer.Token_Kind,
specialization: ^Expr,
}
Helper_Type :: struct {
using node: Expr,
tok: token.Kind,
tok: tokenizer.Token_Kind,
type: ^Expr,
}
Distinct_Type :: struct {
using node: Expr,
tok: token.Kind,
tok: tokenizer.Token_Kind,
type: ^Expr,
}
Opaque_Type :: struct {
using node: Expr,
tok: token.Kind,
tok: tokenizer.Token_Kind,
type: ^Expr,
}
Poly_Type :: struct {
using node: Expr,
dollar: token.Pos,
dollar: tokenizer.Pos,
type: ^Ident,
specialization: ^Expr,
}
Proc_Type :: struct {
using node: Expr,
tok: token.Token,
tok: tokenizer.Token,
calling_convention: Proc_Calling_Convention,
params: ^Field_List,
arrow: token.Pos,
arrow: tokenizer.Pos,
results: ^Field_List,
tags: Proc_Tags,
generic: bool,
@@ -540,77 +547,81 @@ Proc_Type :: struct {
Pointer_Type :: struct {
using node: Expr,
pointer: token.Pos,
pointer: tokenizer.Pos,
elem: ^Expr,
}
Array_Type :: struct {
using node: Expr,
open: token.Pos,
open: tokenizer.Pos,
len: ^Expr, // Ellipsis node for [?]T arrray types, nil for slice types
close: token.Pos,
close: tokenizer.Pos,
elem: ^Expr,
}
Dynamic_Array_Type :: struct {
using node: Expr,
open: token.Pos,
dynamic_pos: token.Pos,
close: token.Pos,
open: tokenizer.Pos,
dynamic_pos: tokenizer.Pos,
close: tokenizer.Pos,
elem: ^Expr,
}
Struct_Type :: struct {
using node: Expr,
tok_pos: token.Pos,
poly_params: ^Field_List,
align: ^Expr,
is_packed: bool,
is_raw_union: bool,
fields: ^Field_List,
name_count: int,
tok_pos: tokenizer.Pos,
poly_params: ^Field_List,
align: ^Expr,
fields: ^Field_List,
name_count: int,
where_token: tokenizer.Token,
where_clauses: []^Expr,
is_packed: bool,
is_raw_union: bool,
}
Union_Type :: struct {
using node: Expr,
tok_pos: token.Pos,
tok_pos: tokenizer.Pos,
poly_params: ^Field_List,
align: ^Expr,
variants: []^Expr,
where_token: tokenizer.Token,
where_clauses: []^Expr,
}
Enum_Type :: struct {
using node: Expr,
tok_pos: token.Pos,
tok_pos: tokenizer.Pos,
base_type: ^Expr,
open: token.Pos,
open: tokenizer.Pos,
fields: []^Expr,
close: token.Pos,
close: tokenizer.Pos,
is_using: bool,
}
Bit_Field_Type :: struct {
using node: Expr,
tok_pos: token.Pos,
tok_pos: tokenizer.Pos,
align: ^Expr,
open: token.Pos,
open: tokenizer.Pos,
fields: []^Field_Value, // Field_Value with ':' rather than '='
close: token.Pos,
close: tokenizer.Pos,
}
Bit_Set_Type :: struct {
using node: Expr,
tok_pos: token.Pos,
open: token.Pos,
tok_pos: tokenizer.Pos,
open: tokenizer.Pos,
elem: ^Expr,
underlying: ^Expr,
close: token.Pos,
close: tokenizer.Pos,
}
Map_Type :: struct {
using node: Expr,
tok_pos: token.Pos,
tok_pos: tokenizer.Pos,
key: ^Expr,
value: ^Expr,
}
+2 -2
View File
@@ -2,9 +2,9 @@ package odin_ast
import "core:mem"
import "core:fmt"
import "core:odin/token"
import "core:odin/tokenizer"
new :: proc($T: typeid, pos, end: token.Pos) -> ^T {
new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
n := mem.new(T);
n.pos = pos;
n.end = end;
+2 -2
View File
@@ -1,6 +1,6 @@
package odin_ast
import "core:odin/token"
import "core:odin/tokenizer"
Package_Kind :: enum {
Normal,
@@ -26,7 +26,7 @@ File :: struct {
src: []byte,
pkg_decl: ^Package_Decl,
pkg_token: token.Token,
pkg_token: tokenizer.Token,
pkg_name: string,
decls: [dynamic]^Stmt,
File diff suppressed because it is too large Load Diff
@@ -1,9 +1,9 @@
package odin_token
package odin_tokenizer
import "core:strings"
Token :: struct {
kind: Kind,
kind: Token_Kind,
text: string,
pos: Pos,
}
@@ -28,7 +28,7 @@ pos_compare :: proc(lhs, rhs: Pos) -> int {
return strings.compare(lhs.file, rhs.file);
}
using Kind :: enum u32 {
Token_Kind :: enum u32 {
Invalid,
EOF,
Comment,
@@ -118,6 +118,7 @@ using Kind :: enum u32 {
Package,
Typeid,
When,
Where,
If,
Else,
For,
@@ -154,9 +155,6 @@ using Kind :: enum u32 {
Offset_Of,
Type_Of,
Const,
Asm,
Yield,
Await,
B_Keyword_End,
COUNT,
@@ -165,7 +163,7 @@ using Kind :: enum u32 {
// ... Custom keywords
};
tokens := [Kind.COUNT]string {
tokens := [Token_Kind.COUNT]string {
"Invalid",
"EOF",
"Comment",
@@ -255,6 +253,7 @@ tokens := [Kind.COUNT]string {
"package",
"typeid",
"when",
"where",
"if",
"else",
"for",
@@ -291,20 +290,17 @@ tokens := [Kind.COUNT]string {
"offset_of",
"type_of",
"const",
"asm",
"yield",
"await",
"",
};
custom_keyword_tokens: []string;
to_string :: proc(kind: Kind) -> string {
if Invalid <= kind && kind < COUNT {
to_string :: proc(kind: Token_Kind) -> string {
if Token_Kind.Invalid <= kind && kind < Token_Kind.COUNT {
return tokens[kind];
}
if B_Custom_Keyword_Begin < kind {
n := int(u16(kind)-u16(B_Custom_Keyword_Begin));
if Token_Kind.B_Custom_Keyword_Begin < kind {
n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin));
if n < len(custom_keyword_tokens) {
return custom_keyword_tokens[n];
}
@@ -313,24 +309,26 @@ to_string :: proc(kind: Kind) -> string {
return "Invalid";
}
is_literal :: proc(kind: Kind) -> bool { return B_Literal_Begin < kind && kind < B_Literal_End; }
is_operator :: proc(kind: Kind) -> bool {
is_literal :: proc(kind: Token_Kind) -> bool {
return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End;
}
is_operator :: proc(kind: Token_Kind) -> bool {
switch kind {
case B_Operator_Begin..B_Operator_End:
case .B_Operator_Begin .. .B_Operator_End:
return true;
case In, Notin:
case .In, .Notin:
return true;
}
return false;
}
is_assignment_operator :: proc(kind: Kind) -> bool {
return B_Assign_Op_Begin < kind && kind < B_Assign_Op_End || kind == Eq;
is_assignment_operator :: proc(kind: Token_Kind) -> bool {
return Token_Kind.B_Assign_Op_Begin < kind && kind < Token_Kind.B_Assign_Op_End || kind == Token_Kind.Eq;
}
is_keyword :: proc(kind: Kind) -> bool {
is_keyword :: proc(kind: Token_Kind) -> bool {
switch {
case B_Keyword_Begin < kind && kind < B_Keyword_End:
case Token_Kind.B_Keyword_Begin < kind && kind < Token_Kind.B_Keyword_End:
return true;
case B_Custom_Keyword_Begin < kind:
case Token_Kind.B_Custom_Keyword_Begin < kind:
return true;
}
return false;
+86 -85
View File
@@ -1,10 +1,9 @@
package odin_tokenizer
import "core:fmt"
import "core:odin/token"
import "core:unicode/utf8"
Error_Handler :: #type proc(pos: token.Pos, fmt: string, args: ..any);
Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any);
Tokenizer :: struct {
// Immutable data
@@ -41,11 +40,11 @@ init :: proc(t: ^Tokenizer, src: []byte, path: string, err: Error_Handler = defa
}
@(private)
offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos {
offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos {
line := t.line_count;
column := offset - t.line_offset + 1;
return token.Pos {
return Pos {
file = t.path,
offset = offset,
line = line,
@@ -53,10 +52,10 @@ offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos {
};
}
default_error_handler :: proc(pos: token.Pos, msg: string, args: ..any) {
fmt.printf_err("%s(%d:%d) ", pos.file, pos.line, pos.column);
fmt.printf_err(msg, ..args);
fmt.printf_err("\n");
default_error_handler :: proc(pos: Pos, msg: string, args: ..any) {
fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column);
fmt.eprintf(msg, ..args);
fmt.eprintf("\n");
}
error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
@@ -98,9 +97,9 @@ advance_rune :: proc(using t: ^Tokenizer) {
}
}
peek_byte :: proc(using t: ^Tokenizer, offset := 0) -> byte {
if read_offset+offset < len(src) {
return src[read_offset+offset];
peek_byte :: proc(t: ^Tokenizer, offset := 0) -> byte {
if t.read_offset+offset < len(t.src) {
return t.src[t.read_offset+offset];
}
return 0;
}
@@ -322,15 +321,15 @@ scan_rune :: proc(t: ^Tokenizer) -> string {
return string(t.src[offset : t.offset]);
}
scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, string) {
scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Token_Kind, string) {
scan_mantissa :: proc(t: ^Tokenizer, base: int) {
for digit_val(t.ch) < base || t.ch == '_' {
advance_rune(t);
}
}
scan_exponent :: proc(t: ^Tokenizer, kind: ^token.Kind) {
scan_exponent :: proc(t: ^Tokenizer, kind: ^Token_Kind) {
if t.ch == 'e' || t.ch == 'E' {
kind^ = token.Float;
kind^ = .Float;
advance_rune(t);
if t.ch == '-' || t.ch == '+' {
advance_rune(t);
@@ -343,17 +342,18 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
}
// NOTE(bill): This needs to be here for sanity's sake
if t.ch == 'i' {
kind^ = token.Imag;
switch t.ch {
case 'i', 'j', 'k':
kind^ = .Imag;
advance_rune(t);
}
}
scan_fraction :: proc(t: ^Tokenizer, kind: ^token.Kind) -> (early_exit: bool) {
scan_fraction :: proc(t: ^Tokenizer, kind: ^Token_Kind) -> (early_exit: bool) {
if t.ch == '.' && peek_byte(t) == '.' {
return true;
}
if t.ch == '.' {
kind^ = token.Float;
kind^ = .Float;
advance_rune(t);
scan_mantissa(t, 10);
}
@@ -362,21 +362,22 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
offset := t.offset;
kind := token.Integer;
kind := Token_Kind.Integer;
seen_point := seen_decimal_point;
if seen_decimal_point {
if seen_point {
offset -= 1;
kind = token.Float;
kind = .Float;
scan_mantissa(t, 10);
scan_exponent(t, &kind);
} else {
if t.ch == '0' {
int_base :: inline proc(t: ^Tokenizer, kind: ^token.Kind, base: int, msg: string) {
int_base :: inline proc(t: ^Tokenizer, kind: ^Token_Kind, base: int, msg: string) {
prev := t.offset;
advance_rune(t);
scan_mantissa(t, base);
if t.offset - prev <= 1 {
kind^ = token.Invalid;
kind^ = .Invalid;
error(t, t.offset, msg);
}
}
@@ -393,7 +394,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
advance_rune(t);
scan_mantissa(t, 16);
if t.offset - prev <= 1 {
kind = token.Invalid;
kind = .Invalid;
error(t, t.offset, "illegal hexadecimal floating-point number");
} else {
sub := t.src[prev+1 : t.offset];
@@ -412,10 +413,10 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
}
case:
seen_decimal_point = false;
seen_point = false;
scan_mantissa(t, 10);
if t.ch == '.' {
seen_decimal_point = true;
seen_point = true;
if scan_fraction(t, &kind) {
return kind, string(t.src[offset : t.offset]);
}
@@ -438,15 +439,15 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
}
scan :: proc(t: ^Tokenizer) -> token.Token {
switch2 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind) -> token.Kind {
scan :: proc(t: ^Tokenizer) -> Token {
switch2 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind) -> Token_Kind {
if t.ch == '=' {
advance_rune(t);
return tok1;
}
return tok0;
}
switch3 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2: token.Kind) -> token.Kind {
switch3 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2: Token_Kind) -> Token_Kind {
if t.ch == '=' {
advance_rune(t);
return tok1;
@@ -457,7 +458,7 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
}
return tok0;
}
switch4 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2, tok3: token.Kind) -> token.Kind {
switch4 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2, tok3: Token_Kind) -> Token_Kind {
if t.ch == '=' {
advance_rune(t);
return tok1;
@@ -478,25 +479,25 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
offset := t.offset;
kind: token.Kind;
kind: Token_Kind;
lit: string;
pos := offset_to_pos(t, offset);
switch ch := t.ch; true {
case is_letter(ch):
lit = scan_identifier(t);
kind = token.Ident;
kind = .Ident;
check_keyword: if len(lit) > 1 {
// TODO(bill): Maybe have a hash table lookup rather than this linear search
for i in token.B_Keyword_Begin .. token.B_Keyword_End {
if lit == token.tokens[i] {
kind = token.Kind(i);
for i in Token_Kind.B_Keyword_Begin .. Token_Kind.B_Keyword_End {
if lit == tokens[i] {
kind = Token_Kind(i);
break check_keyword;
}
}
for keyword, i in token.custom_keyword_tokens {
for keyword, i in custom_keyword_tokens {
if lit == keyword {
kind = token.Kind(i+1)+token.B_Custom_Keyword_Begin;
kind = Token_Kind(i+1) + .B_Custom_Keyword_Begin;
break check_keyword;
}
}
@@ -507,115 +508,115 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
advance_rune(t);
switch ch {
case -1:
kind = token.EOF;
kind = .EOF;
case '"':
kind = token.String;
kind = .String;
lit = scan_string(t);
case '\'':
kind = token.Rune;
kind = .Rune;
lit = scan_rune(t);
case '`':
kind = token.String;
kind = .String;
lit = scan_raw_string(t);
case '=':
if t.ch == '>' {
advance_rune(t);
kind = token.Double_Arrow_Right;
kind = .Double_Arrow_Right;
} else {
kind = switch2(t, token.Eq, token.Cmp_Eq);
kind = switch2(t, .Eq, .Cmp_Eq);
}
case '!': kind = switch2(t, token.Not, token.Not_Eq);
case '!': kind = switch2(t, .Not, .Not_Eq);
case '#':
kind = token.Hash;
kind = .Hash;
if t.ch == '!' {
kind = token.Comment;
kind = .Comment;
lit = scan_comment(t);
}
case '?': kind = token.Question;
case '@': kind = token.At;
case '$': kind = token.Dollar;
case '^': kind = token.Pointer;
case '+': kind = switch2(t, token.Add, token.Add_Eq);
case '?': kind = .Question;
case '@': kind = .At;
case '$': kind = .Dollar;
case '^': kind = .Pointer;
case '+': kind = switch2(t, .Add, .Add_Eq);
case '-':
if t.ch == '>' {
advance_rune(t);
kind = token.Arrow_Right;
kind = .Arrow_Right;
} else if t.ch == '-' && peek_byte(t) == '-' {
advance_rune(t);
advance_rune(t);
kind = token.Undef;
kind = .Undef;
} else {
kind = switch2(t, token.Sub, token.Sub_Eq);
kind = switch2(t, .Sub, .Sub_Eq);
}
case '*': kind = switch2(t, token.Mul, token.Mul_Eq);
case '*': kind = switch2(t, .Mul, .Mul_Eq);
case '/':
if t.ch == '/' || t.ch == '*' {
kind = token.Comment;
kind = .Comment;
lit = scan_comment(t);
} else {
kind = switch2(t, token.Quo, token.Quo_Eq);
kind = switch2(t, .Quo, .Quo_Eq);
}
case '%': kind = switch4(t, token.Mod, token.Mod_Eq, '%', token.Mod_Mod, token.Mod_Mod_Eq);
case '%': kind = switch4(t, .Mod, .Mod_Eq, '%', .Mod_Mod, .Mod_Mod_Eq);
case '&':
if t.ch == '~' {
advance_rune(t);
kind = switch2(t, token.And_Not, token.And_Not_Eq);
kind = switch2(t, .And_Not, .And_Not_Eq);
} else {
kind = switch3(t, token.And, token.And_Eq, '&', token.Cmp_And);
kind = switch3(t, .And, .And_Eq, '&', .Cmp_And);
}
case '|': kind = switch3(t, token.Or, token.Or_Eq, '|', token.Cmp_Or);
case '~': kind = token.Xor;
case '|': kind = switch3(t, .Or, .Or_Eq, '|', .Cmp_Or);
case '~': kind = .Xor;
case '<':
if t.ch == '-' {
advance_rune(t);
kind = token.Arrow_Left;
kind = .Arrow_Left;
} else {
kind = switch4(t, token.Lt, token.Lt_Eq, '<', token.Shl, token.Shl_Eq);
kind = switch4(t, .Lt, .Lt_Eq, '<', .Shl, .Shl_Eq);
}
case '>': kind = switch4(t, token.Gt, token.Gt_Eq, '>', token.Shr,token.Shr_Eq);
case '>': kind = switch4(t, .Gt, .Gt_Eq, '>', .Shr,.Shr_Eq);
case '≠': kind = token.Not_Eq;
case '≤': kind = token.Lt_Eq;
case '≥': kind = token.Gt_Eq;
case '∈': kind = token.In;
case '∉': kind = token.Notin;
case '≠': kind = .Not_Eq;
case '≤': kind = .Lt_Eq;
case '≥': kind = .Gt_Eq;
case '∈': kind = .In;
case '∉': kind = .Notin;
case '.':
if '0' <= t.ch && t.ch <= '9' {
kind, lit = scan_number(t, true);
} else {
kind = token.Period;
kind = .Period;
if t.ch == '.' {
advance_rune(t);
kind = token.Ellipsis;
kind = .Ellipsis;
if t.ch == '<' {
advance_rune(t);
kind = token.Range_Half;
kind = .Range_Half;
}
}
}
case ':': kind = token.Colon;
case ',': kind = token.Comma;
case ';': kind = token.Semicolon;
case '(': kind = token.Open_Paren;
case ')': kind = token.Close_Paren;
case '[': kind = token.Open_Bracket;
case ']': kind = token.Close_Bracket;
case '{': kind = token.Open_Brace;
case '}': kind = token.Close_Brace;
case ':': kind = .Colon;
case ',': kind = .Comma;
case ';': kind = .Semicolon;
case '(': kind = .Open_Paren;
case ')': kind = .Close_Paren;
case '[': kind = .Open_Bracket;
case ']': kind = .Close_Bracket;
case '{': kind = .Open_Brace;
case '}': kind = .Close_Brace;
case '\\': kind = token.Back_Slash;
case '\\': kind = .Back_Slash;
case:
if ch != utf8.RUNE_BOM {
error(t, t.offset, "illegal character '%r': %d", ch, ch);
}
kind = token.Invalid;
kind = .Invalid;
}
}
if lit == "" {
lit = string(t.src[offset : t.offset]);
}
return token.Token{kind, lit, pos};
return Token{kind, lit, pos};
}
@@ -6,7 +6,7 @@ foreign import libc "system:c"
import "core:runtime"
import "core:strings"
OS :: "osx";
OS :: "darwin";
Handle :: distinct i32;
File_Time :: distinct u64;
@@ -258,7 +258,6 @@ exit :: inline proc(code: int) -> ! {
_unix_exit(code);
}
current_thread_id :: proc "contextless" () -> int {
// return int(_unix_gettid());
return 0;
@@ -287,9 +286,9 @@ dlerror :: proc() -> string {
_alloc_command_line_arguments :: proc() -> []string {
args := make([]string, len(runtime.args__));
res := make([]string, len(runtime.args__));
for arg, i in runtime.args__ {
args[i] = string(arg);
res[i] = string(arg);
}
return args;
return res;
}
+2422 -162
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -392,9 +392,9 @@ dlerror :: proc() -> string {
_alloc_command_line_arguments :: proc() -> []string {
args := make([]string, len(runtime.args__));
res := make([]string, len(runtime.args__));
for arg, i in runtime.args__ {
args[i] = string(arg);
res[i] = string(arg);
}
return args;
return res;
}
+1 -1
View File
@@ -322,4 +322,4 @@ is_windows_8_1 :: proc() -> bool {
is_windows_10 :: proc() -> bool {
osvi := get_windows_version_ansi();
return (osvi.major_version == 10 && osvi.minor_version == 0);
}
}
+396
View File
@@ -0,0 +1,396 @@
package reflect
import "core:runtime"
import "core:mem"
Type_Kind :: enum {
Invalid,
Named,
Integer,
Rune,
Float,
Complex,
Quaternion,
String,
Boolean,
Any,
Type_Id,
Pointer,
Procedure,
Array,
Dynamic_Array,
Slice,
Tuple,
Struct,
Union,
Enum,
Map,
Bit_Field,
Bit_Set,
Opaque,
Simd_Vector,
}
type_kind :: proc(T: typeid) -> Type_Kind {
ti := type_info_of(T);
if ti != nil {
#complete switch _ in ti.variant {
case runtime.Type_Info_Named: return .Named;
case runtime.Type_Info_Integer: return .Integer;
case runtime.Type_Info_Rune: return .Rune;
case runtime.Type_Info_Float: return .Float;
case runtime.Type_Info_Complex: return .Complex;
case runtime.Type_Info_Quaternion: return .Quaternion;
case runtime.Type_Info_String: return .String;
case runtime.Type_Info_Boolean: return .Boolean;
case runtime.Type_Info_Any: return .Any;
case runtime.Type_Info_Type_Id: return .Type_Id;
case runtime.Type_Info_Pointer: return .Pointer;
case runtime.Type_Info_Procedure: return .Procedure;
case runtime.Type_Info_Array: return .Array;
case runtime.Type_Info_Dynamic_Array: return .Dynamic_Array;
case runtime.Type_Info_Slice: return .Slice;
case runtime.Type_Info_Tuple: return .Tuple;
case runtime.Type_Info_Struct: return .Struct;
case runtime.Type_Info_Union: return .Union;
case runtime.Type_Info_Enum: return .Enum;
case runtime.Type_Info_Map: return .Map;
case runtime.Type_Info_Bit_Field: return .Bit_Field;
case runtime.Type_Info_Bit_Set: return .Bit_Set;
case runtime.Type_Info_Opaque: return .Opaque;
case runtime.Type_Info_Simd_Vector: return .Simd_Vector;
}
}
return .Invalid;
}
// TODO(bill): Better name
underlying_type_kind :: proc(T: typeid) -> Type_Kind {
return type_kind(runtime.typeid_base(T));
}
// TODO(bill): Better name
backing_type_kind :: proc(T: typeid) -> Type_Kind {
return type_kind(runtime.typeid_core(T));
}
size_of_typeid :: proc(T: typeid) -> int {
if ti := type_info_of(T); ti != nil {
return ti.size;
}
return 0;
}
align_of_typeid :: proc(T: typeid) -> int {
if ti := type_info_of(T); ti != nil {
return ti.align;
}
return 1;
}
to_bytes :: proc(v: any) -> []byte {
if v != nil {
sz := size_of_typeid(v.id);
return mem.slice_ptr((^byte)(v.data), sz);
}
return nil;
}
any_data :: inline proc(v: any) -> (data: rawptr, id: typeid) {
return v.data, v.id;
}
is_nil :: proc(v: any) -> bool {
data := to_bytes(v);
if data != nil {
return true;
}
for v in data do if v != 0 {
return false;
}
return true;
}
length :: proc(val: any) -> int {
if val == nil do return 0;
v := val;
v.id = runtime.typeid_base(v.id);
switch a in v {
case runtime.Type_Info_Array:
return a.count;
case runtime.Type_Info_Slice:
return (^mem.Raw_Slice)(v.data).len;
case runtime.Type_Info_Dynamic_Array:
return (^mem.Raw_Dynamic_Array)(v.data).len;
case runtime.Type_Info_String:
if a.is_cstring {
return len((^cstring)(v.data)^);
} else {
return (^mem.Raw_String)(v.data).len;
}
}
return 0;
}
index :: proc(val: any, i: int, loc := #caller_location) -> any {
if val == nil do return nil;
v := val;
v.id = runtime.typeid_base(v.id);
switch a in v {
case runtime.Type_Info_Array:
runtime.bounds_check_error_loc(loc, i, a.count);
offset := uintptr(a.elem.size * i);
data := rawptr(uintptr(v.data) + offset);
return any{data, a.elem.id};
case runtime.Type_Info_Slice:
raw := (^mem.Raw_Slice)(v.data);
runtime.bounds_check_error_loc(loc, i, raw.len);
offset := uintptr(a.elem.size * i);
data := rawptr(uintptr(raw.data) + offset);
return any{data, a.elem.id};
case runtime.Type_Info_Dynamic_Array:
raw := (^mem.Raw_Dynamic_Array)(v.data);
runtime.bounds_check_error_loc(loc, i, raw.len);
offset := uintptr(a.elem.size * i);
data := rawptr(uintptr(raw.data) + offset);
return any{data, a.elem.id};
case runtime.Type_Info_String:
if a.is_cstring do return nil;
raw := (^mem.Raw_String)(v.data);
runtime.bounds_check_error_loc(loc, i, raw.len);
offset := uintptr(size_of(u8) * i);
data := rawptr(uintptr(raw.data) + offset);
return any{data, typeid_of(u8)};
}
return nil;
}
Struct_Tag :: distinct string;
Struct_Field :: struct {
name: string,
type: typeid,
tag: Struct_Tag,
offset: uintptr,
}
struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
if 0 <= i && i < len(s.names) {
field.name = s.names[i];
field.type = s.types[i].id;
field.tag = Struct_Tag(s.tags[i]);
field.offset = s.offsets[i];
}
}
return;
}
struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
for fname, i in s.names {
if fname == name {
field.name = s.names[i];
field.type = s.types[i].id;
field.tag = Struct_Tag(s.tags[i]);
field.offset = s.offsets[i];
break;
}
}
}
return;
}
struct_field_value_by_name :: proc(a: any, field: string, recurse := false) -> any {
if a == nil do return nil;
ti := runtime.type_info_base(type_info_of(a.id));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
for name, i in s.names {
if name == field {
return any{
rawptr(uintptr(a.data) + s.offsets[i]),
s.types[i].id,
};
}
if recurse && s.usings[i] {
f := any{
rawptr(uintptr(a.data) + s.offsets[i]),
s.types[i].id,
};
if res := struct_field_value_by_name(f, field, recurse); res != nil {
return res;
}
}
}
}
return nil;
}
struct_field_names :: proc(T: typeid) -> []string {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
return s.names;
}
return nil;
}
struct_field_types :: proc(T: typeid) -> []^runtime.Type_Info {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
return s.types;
}
return nil;
}
struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
return transmute([]Struct_Tag)s.tags;
}
return nil;
}
struct_field_offsets :: proc(T: typeid) -> []uintptr {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
return s.offsets;
}
return nil;
}
struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: string) {
value, _ = struct_tag_lookup(tag, key);
return;
}
struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: bool) {
for t := tag; t != ""; /**/ {
i := 0;
for i < len(t) && t[i] == ' ' { // Skip whitespace
i += 1;
}
t = t[i:];
if len(t) == 0 do break;
i = 0;
loop: for i < len(t) {
switch t[i] {
case ':', '"':
break loop;
case 0x00 ..< ' ', 0x7f .. 0x9f: // break if control character is found
break loop;
}
i += 1;
}
if i == 0 do break;
if i+1 >= len(t) do break;
if t[i] != ':' || t[i+1] != '"' {
break;
}
name := string(t[:i]);
t = t[i+1:];
i = 1;
for i < len(t) && t[i] != '"' { // find closing quote
if t[i] == '\\' do i += 1; // Skip escaped characters
i += 1;
}
if i >= len(t) do break;
val := string(t[:i+1]);
t = t[i+1:];
if key == name {
return val[1:i], true;
}
}
return;
}
enum_string :: proc(a: any) -> string {
if a == nil do return "";
ti := runtime.type_info_base(type_info_of(a.id));
if e, ok := ti.variant.(runtime.Type_Info_Enum); ok {
for _, i in e.values {
value := &e.values[i];
n := mem.compare_byte_ptrs((^byte)(a.data), (^byte)(value), ti.size);
if n == 0 {
return e.names[i];
}
}
} else {
panic("expected an enum to reflect.enum_string");
}
return "";
}
union_variant_type_info :: proc(a: any) -> ^runtime.Type_Info {
id := union_variant_typeid(a);
return type_info_of(id);
}
union_variant_typeid :: proc(a: any) -> typeid {
if a == nil do return nil;
ti := runtime.type_info_base(type_info_of(a.id));
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
tag_ptr := uintptr(a.data) + info.tag_offset;
tag_any := any{rawptr(tag_ptr), info.tag_type.id};
tag: i64 = ---;
switch i in tag_any {
case u8: tag = i64(i);
case i8: tag = i64(i);
case u16: tag = i64(i);
case i16: tag = i64(i);
case u32: tag = i64(i);
case i32: tag = i64(i);
case u64: tag = i64(i);
case i64: tag = i64(i);
case: unimplemented();
}
if a.data != nil && tag != 0 {
return info.variants[tag-1].id;
}
} else {
panic("expected a union to reflect.union_variant_typeid");
}
return nil;
}
@@ -1,6 +1,7 @@
package types
package reflect
import rt "core:runtime"
import "core:strings"
are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
if a == b do return true;
@@ -108,9 +109,11 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
for _, i in x.types {
xn, yn := x.names[i], y.names[i];
xt, yt := x.types[i], y.types[i];
xl, yl := x.tags[i], y.tags[i];
if xn != yn do return false;
if !are_types_identical(xt, yt) do return false;
if xl != yl do return false;
}
return true;
@@ -272,3 +275,216 @@ is_simd_vector :: proc(info: ^rt.Type_Info) -> bool {
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector);
return ok;
}
write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
write_type(buf, type_info_of(id));
}
write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
using strings;
if ti == nil {
write_string(buf, "nil");
return;
}
switch info in ti.variant {
case rt.Type_Info_Named:
write_string(buf, info.name);
case rt.Type_Info_Integer:
switch ti.id {
case int: write_string(buf, "int");
case uint: write_string(buf, "uint");
case uintptr: write_string(buf, "uintptr");
case:
write_byte(buf, info.signed ? 'i' : 'u');
write_i64(buf, i64(8*ti.size), 10);
switch info.endianness {
case .Little: write_string(buf, "le");
case .Big: write_string(buf, "be");
}
}
case rt.Type_Info_Rune:
write_string(buf, "rune");
case rt.Type_Info_Float:
write_byte(buf, 'f');
write_i64(buf, i64(8*ti.size), 10);
case rt.Type_Info_Complex:
write_string(buf, "complex");
write_i64(buf, i64(8*ti.size), 10);
case rt.Type_Info_String:
if info.is_cstring {
write_string(buf, "cstring");
} else {
write_string(buf, "string");
}
case rt.Type_Info_Boolean:
switch ti.id {
case bool: write_string(buf, "bool");
case:
write_byte(buf, 'b');
write_i64(buf, i64(8*ti.size), 10);
}
case rt.Type_Info_Any:
write_string(buf, "any");
case rt.Type_Info_Type_Id:
write_string(buf, "typeid");
case rt.Type_Info_Pointer:
if info.elem == nil {
write_string(buf, "rawptr");
} else {
write_string(buf, "^");
write_type(buf, info.elem);
}
case rt.Type_Info_Procedure:
write_string(buf, "proc");
if info.params == nil {
write_string(buf, "()");
} else {
t := info.params.variant.(rt.Type_Info_Tuple);
write_string(buf, "(");
for t, i in t.types {
if i > 0 do write_string(buf, ", ");
write_type(buf, t);
}
write_string(buf, ")");
}
if info.results != nil {
write_string(buf, " -> ");
write_type(buf, info.results);
}
case rt.Type_Info_Tuple:
count := len(info.names);
if count != 1 do write_string(buf, "(");
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
t := info.types[i];
if len(name) > 0 {
write_string(buf, name);
write_string(buf, ": ");
}
write_type(buf, t);
}
if count != 1 do write_string(buf, ")");
case rt.Type_Info_Array:
write_string(buf, "[");
write_i64(buf, i64(info.count), 10);
write_string(buf, "]");
write_type(buf, info.elem);
case rt.Type_Info_Dynamic_Array:
write_string(buf, "[dynamic]");
write_type(buf, info.elem);
case rt.Type_Info_Slice:
write_string(buf, "[]");
write_type(buf, info.elem);
case rt.Type_Info_Map:
write_string(buf, "map[");
write_type(buf, info.key);
write_byte(buf, ']');
write_type(buf, info.value);
case rt.Type_Info_Struct:
write_string(buf, "struct ");
if info.is_packed do write_string(buf, "#packed ");
if info.is_raw_union do write_string(buf, "#raw_union ");
if info.custom_align {
write_string(buf, "#align ");
write_i64(buf, i64(ti.align), 10);
write_byte(buf, ' ');
}
write_byte(buf, '{');
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
write_string(buf, name);
write_string(buf, ": ");
write_type(buf, info.types[i]);
}
write_byte(buf, '}');
case rt.Type_Info_Union:
write_string(buf, "union ");
if info.custom_align {
write_string(buf, "#align ");
write_i64(buf, i64(ti.align), 10);
write_byte(buf, ' ');
}
write_byte(buf, '{');
for variant, i in info.variants {
if i > 0 do write_string(buf, ", ");
write_type(buf, variant);
}
write_byte(buf, '}');
case rt.Type_Info_Enum:
write_string(buf, "enum ");
write_type(buf, info.base);
write_string(buf, " {");
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
write_string(buf, name);
}
write_byte(buf, '}');
case rt.Type_Info_Bit_Field:
write_string(buf, "bit_field ");
if ti.align != 1 {
write_string(buf, "#align ");
write_i64(buf, i64(ti.align), 10);
write_byte(buf, ' ');
}
write_string(buf, " {");
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
write_string(buf, name);
write_string(buf, ": ");
write_i64(buf, i64(info.bits[i]), 10);
}
write_byte(buf, '}');
case rt.Type_Info_Bit_Set:
write_string(buf, "bit_set[");
switch {
case is_enum(info.elem):
write_type(buf, info.elem);
case is_rune(info.elem):
write_encoded_rune(buf, rune(info.lower));
write_string(buf, "..");
write_encoded_rune(buf, rune(info.upper));
case:
write_i64(buf, info.lower, 10);
write_string(buf, "..");
write_i64(buf, info.upper, 10);
}
if info.underlying != nil {
write_string(buf, "; ");
write_type(buf, info.underlying);
}
write_byte(buf, ']');
case rt.Type_Info_Opaque:
write_string(buf, "opaque ");
write_type(buf, info.elem);
case rt.Type_Info_Simd_Vector:
if info.is_x86_mmx {
write_string(buf, "intrinsics.x86_mmx");
} else {
write_string(buf, "intrinsics.vector(");
write_i64(buf, i64(info.count));
write_string(buf, ", ");
write_type(buf, info.elem);
write_byte(buf, ')');
}
}
}
+108 -79
View File
@@ -6,6 +6,7 @@ package runtime
import "core:os"
import "core:mem"
import "core:log"
import "intrinsics"
// Naming Conventions:
// In general, Ada_Case for types and snake_case for values
@@ -40,23 +41,24 @@ Type_Info_Enum_Value :: union {
u8, u16, u32, u64, uint, uintptr,
};
Type_Info_Endianness :: enum u8 {
Platform_Endianness :: enum u8 {
Platform = 0,
Little = 1,
Big = 2,
}
// Variant Types
Type_Info_Named :: struct {name: string, base: ^Type_Info};
Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness};
Type_Info_Rune :: struct {};
Type_Info_Float :: struct {};
Type_Info_Complex :: struct {};
Type_Info_String :: struct {is_cstring: bool};
Type_Info_Boolean :: struct {};
Type_Info_Any :: struct {};
Type_Info_Type_Id :: struct {};
Type_Info_Pointer :: struct {
Type_Info_Named :: struct {name: string, base: ^Type_Info};
Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness};
Type_Info_Rune :: struct {};
Type_Info_Float :: struct {};
Type_Info_Complex :: struct {};
Type_Info_Quaternion :: struct {};
Type_Info_String :: struct {is_cstring: bool};
Type_Info_Boolean :: struct {};
Type_Info_Any :: struct {};
Type_Info_Type_Id :: struct {};
Type_Info_Pointer :: struct {
elem: ^Type_Info // nil -> rawptr
};
Type_Info_Procedure :: struct {
@@ -79,17 +81,22 @@ Type_Info_Tuple :: struct { // Only really used for procedures
Type_Info_Struct :: struct {
types: []^Type_Info,
names: []string,
offsets: []uintptr, // offsets may not be used in tuples
usings: []bool, // usings may not be used in tuples
offsets: []uintptr,
usings: []bool,
tags: []string,
is_packed: bool,
is_raw_union: bool,
custom_align: bool,
// These are only set iff this structure is an SOA structure
soa_base_type: ^Type_Info,
soa_len: int,
};
Type_Info_Union :: struct {
variants: []^Type_Info,
tag_offset: uintptr,
tag_type: ^Type_Info,
variants: []^Type_Info,
tag_offset: uintptr,
tag_type: ^Type_Info,
custom_align: bool,
no_nil: bool,
};
Type_Info_Enum :: struct {
base: ^Type_Info,
@@ -133,6 +140,7 @@ Type_Info :: struct {
Type_Info_Rune,
Type_Info_Float,
Type_Info_Complex,
Type_Info_Quaternion,
Type_Info_String,
Type_Info_Boolean,
Type_Info_Any,
@@ -161,6 +169,7 @@ Typeid_Kind :: enum u8 {
Rune,
Float,
Complex,
Quaternion,
String,
Boolean,
Any,
@@ -182,12 +191,13 @@ Typeid_Kind :: enum u8 {
#assert(len(Typeid_Kind) < 32);
Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
index: 8*size_of(align_of(uintptr)) - 8,
index: 8*size_of(uintptr) - 8,
kind: 5, // Typeid_Kind
named: 1,
special: 1, // signed, cstring, etc
reserved: 1,
}
#assert(size_of(Typeid_Bit_Field) == size_of(uintptr));
// NOTE(bill): only the ones that are needed (not all types)
// This will be set by the compiler
@@ -230,7 +240,22 @@ global_scratch_allocator_data: mem.Scratch_Allocator;
Raw_Slice :: struct {
data: rawptr,
len: int,
}
Raw_Dynamic_Array :: struct {
data: rawptr,
len: int,
cap: int,
allocator: mem.Allocator,
}
Raw_Map :: struct {
hashes: []int,
entries: Raw_Dynamic_Array,
}
INITIAL_MAP_CAP :: 16;
@@ -254,7 +279,7 @@ Map_Entry_Header :: struct {
}
Map_Header :: struct {
m: ^mem.Raw_Map,
m: ^Raw_Map,
is_key_string: bool,
entry_size: int,
@@ -281,19 +306,21 @@ type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
}
type_info_base_without_enum :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
if info == nil do return nil;
base := info;
loop: for {
switch i in base.variant {
case Type_Info_Named: base = i.base;
case Type_Info_Enum: base = i.base;
case Type_Info_Named: base = i.base;
case Type_Info_Enum: base = i.base;
case Type_Info_Opaque: base = i.elem;
case: break loop;
}
}
return base;
}
type_info_base_without_enum :: type_info_core;
__type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info {
data := transmute(Typeid_Bit_Field)id;
@@ -309,10 +336,11 @@ typeid_base :: proc "contextless" (id: typeid) -> typeid {
ti = type_info_base(ti);
return ti.id;
}
typeid_base_without_enum :: proc "contextless" (id: typeid) -> typeid {
typeid_core :: proc "contextless" (id: typeid) -> typeid {
ti := type_info_base_without_enum(type_info_of(id));
return ti.id;
}
typeid_base_without_enum :: typeid_core;
@@ -384,7 +412,7 @@ default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code
@builtin
copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
n := max(0, min(len(dst), len(src)));
if n > 0 do mem.copy(&dst[0], &src[0], n*size_of(E));
if n > 0 do mem_copy(&dst[0], &src[0], n*size_of(E));
return n;
}
@@ -395,7 +423,7 @@ pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E {
if array == nil do return E{};
assert(len(array) > 0);
res := array[len(array)-1];
(^mem.Raw_Dynamic_Array)(array).len -= 1;
(^Raw_Dynamic_Array)(array).len -= 1;
return res;
}
@@ -459,14 +487,11 @@ make :: proc{
mem.make_map,
};
@builtin
clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
if m == nil do return;
raw_map := (^mem.Raw_Map)(m);
entries := (^mem.Raw_Dynamic_Array)(&raw_map.entries);
raw_map := (^Raw_Map)(m);
entries := (^Raw_Dynamic_Array)(&raw_map.entries);
entries.len = 0;
for _, i in raw_map.hashes {
raw_map.hashes[i] = -1;
@@ -497,10 +522,11 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
}
arg_len = min(cap(array)-len(array), arg_len);
if arg_len > 0 {
a := (^mem.Raw_Dynamic_Array)(array);
a := (^Raw_Dynamic_Array)(array);
data := (^E)(a.data);
assert(data != nil);
mem.copy(mem.ptr_offset(data, a.len), &arg, size_of(E));
val := arg;
mem_copy(mem.ptr_offset(data, a.len), &val, size_of(E));
a.len += arg_len;
}
}
@@ -518,10 +544,10 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
}
arg_len = min(cap(array)-len(array), arg_len);
if arg_len > 0 {
a := (^mem.Raw_Dynamic_Array)(array);
a := (^Raw_Dynamic_Array)(array);
data := (^E)(a.data);
assert(data != nil);
mem.copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
mem_copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
a.len += arg_len;
}
}
@@ -538,13 +564,13 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
@builtin
clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) {
if array != nil do (^mem.Raw_Dynamic_Array)(array).len = 0;
if array != nil do (^Raw_Dynamic_Array)(array).len = 0;
}
@builtin
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
if array == nil do return false;
a := (^mem.Raw_Dynamic_Array)(array);
a := (^Raw_Dynamic_Array)(array);
if capacity <= a.cap do return true;
@@ -571,7 +597,7 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
@builtin
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
if array == nil do return false;
a := (^mem.Raw_Dynamic_Array)(array);
a := (^Raw_Dynamic_Array)(array);
if length <= a.cap {
a.len = max(length, 0);
@@ -664,11 +690,13 @@ card :: proc(s: $S/bit_set[$E; $U]) -> int {
@builtin
assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool {
if !condition {
p := context.assertion_failure_proc;
if p == nil {
p = default_assertion_failure_proc;
}
p("Runtime assertion", message, loc);
proc(message: string, loc: Source_Code_Location) {
p := context.assertion_failure_proc;
if p == nil {
p = default_assertion_failure_proc;
}
p("runtime assertion", message, loc);
}(message, loc);
}
return condition;
}
@@ -679,7 +707,7 @@ panic :: proc(message: string, loc := #caller_location) -> ! {
if p == nil {
p = default_assertion_failure_proc;
}
p("Panic", message, loc);
p("panic", message, loc);
}
@builtin
@@ -709,7 +737,7 @@ unreachable :: proc(message := "", loc := #caller_location) -> ! {
__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) {
array := (^mem.Raw_Dynamic_Array)(array_);
array := (^Raw_Dynamic_Array)(array_);
array.allocator = context.allocator;
assert(array.allocator.procedure != nil);
@@ -720,7 +748,7 @@ __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, ca
}
__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int, loc := #caller_location) -> bool {
array := (^mem.Raw_Dynamic_Array)(array_);
array := (^Raw_Dynamic_Array)(array_);
if cap <= array.cap do return true;
@@ -742,7 +770,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap:
}
__dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool {
array := (^mem.Raw_Dynamic_Array)(array_);
array := (^Raw_Dynamic_Array)(array_);
ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc);
if ok do array.len = len;
@@ -752,7 +780,7 @@ __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len:
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
items: rawptr, item_count: int, loc := #caller_location) -> int {
array := (^mem.Raw_Dynamic_Array)(array_);
array := (^Raw_Dynamic_Array)(array_);
if items == nil do return 0;
if item_count <= 0 do return 0;
@@ -769,13 +797,13 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
assert(array.data != nil);
data := uintptr(array.data) + uintptr(elem_size*array.len);
mem.copy(rawptr(data), items, elem_size * item_count);
mem_copy(rawptr(data), items, elem_size * item_count);
array.len += item_count;
return array.len;
}
__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int {
array := (^mem.Raw_Dynamic_Array)(array_);
array := (^Raw_Dynamic_Array)(array_);
ok := true;
if array.cap <= array.len+1 {
@@ -798,15 +826,14 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
// Map
__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
header := Map_Header{m = (^mem.Raw_Map)(m)};
header := Map_Header{m = (^Raw_Map)(m)};
Entry :: struct {
key: Map_Key,
next: int,
value: V,
}
};
_, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String);
header.is_key_string = is_string;
header.is_key_string = intrinsics.type_is_string(K);
header.entry_size = int(size_of(Entry));
header.entry_align = int(align_of(Entry));
header.value_offset = uintptr(offset_of(Entry, value));
@@ -814,35 +841,37 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
return header;
}
__get_map_key :: proc "contextless" (key: $K) -> Map_Key {
__get_map_key :: proc "contextless" (k: $K) -> Map_Key {
key := k;
map_key: Map_Key;
ti := type_info_base_without_enum(type_info_of(K));
switch _ in ti.variant {
case Type_Info_Integer:
switch 8*size_of(key) {
case 8: map_key.hash = u64(( ^u8)(&key)^);
case 16: map_key.hash = u64(( ^u16)(&key)^);
case 32: map_key.hash = u64(( ^u32)(&key)^);
case 64: map_key.hash = u64(( ^u64)(&key)^);
case: panic("Unhandled integer size");
}
case Type_Info_Rune:
T :: intrinsics.type_core_type(K);
when intrinsics.type_is_integer(T) {
sz :: 8*size_of(T);
when sz == 8 do map_key.hash = u64(( ^u8)(&key)^);
else when sz == 16 do map_key.hash = u64((^u16)(&key)^);
else when sz == 32 do map_key.hash = u64((^u32)(&key)^);
else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
else do #assert(false, "Unhandled integer size");
} else when intrinsics.type_is_rune(T) {
map_key.hash = u64((^rune)(&key)^);
case Type_Info_Pointer:
} else when intrinsics.type_is_pointer(T) {
map_key.hash = u64(uintptr((^rawptr)(&key)^));
case Type_Info_Float:
switch 8*size_of(key) {
case 32: map_key.hash = u64((^u32)(&key)^);
case 64: map_key.hash = u64((^u64)(&key)^);
case: panic("Unhandled float size");
}
case Type_Info_String:
} else when intrinsics.type_is_float(T) {
sz :: 8*size_of(T);
when sz == 32 do map_key.hash = u64((^u32)(&key)^);
else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
else do #assert(false, "Unhandled float size");
} else when intrinsics.type_is_string(T) {
#assert(T == string);
str := (^string)(&key)^;
map_key.hash = default_hash_string(str);
map_key.str = str;
case:
panic("Unhandled map key type");
} else {
#assert(false, "Unhandled map key type");
}
return map_key;
}
@@ -871,7 +900,7 @@ source_code_location_hash :: proc(s: Source_Code_Location) -> u64 {
__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: mem.Allocator, loc := #caller_location) -> bool {
array := (^mem.Raw_Slice)(array_);
array := (^Raw_Slice)(array_);
if new_count < array.len do return true;
@@ -897,7 +926,7 @@ __dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller
}
__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) #no_bounds_check {
new_header: Map_Header = header;
nm := mem.Raw_Map{};
nm := Raw_Map{};
nm.entries.allocator = m.entries.allocator;
new_header.m = &nm;
@@ -929,7 +958,7 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #c
e := __dynamic_map_get_entry(new_header, j);
e.next = fr.entry_index;
ndata := uintptr(e);
mem.copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size);
mem_copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size);
if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc);
}
@@ -972,7 +1001,7 @@ __dynamic_map_set :: proc(h: Map_Header, key: Map_Key, value: rawptr, loc := #ca
e := __dynamic_map_get_entry(h, index);
e.key = key;
val := (^byte)(uintptr(e) + h.value_offset);
mem.copy(val, value, h.value_size);
mem_copy(val, value, h.value_size);
}
if __dynamic_map_full(h) {
@@ -1051,7 +1080,7 @@ __dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds
} else {
old := __dynamic_map_get_entry(h, fr.entry_index);
end := __dynamic_map_get_entry(h, m.entries.len-1);
mem.copy(old, end, entry_size);
mem_copy(old, end, entry_size);
if last := __dynamic_map_find(h, old.key); last.entry_prev >= 0 {
last_entry := __dynamic_map_get_entry(h, last.entry_prev);
+262 -14
View File
@@ -1,16 +1,46 @@
package runtime
import "core:mem"
import "core:os"
import "core:unicode/utf8"
mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
if src == nil do return dst;
// NOTE(bill): This _must_ be implemented like C's memmove
foreign _ {
when size_of(rawptr) == 8 {
@(link_name="llvm.memmove.p0i8.p0i8.i64")
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
} else {
@(link_name="llvm.memmove.p0i8.p0i8.i32")
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
}
}
llvm_memmove(dst, src, len, 1, false);
return dst;
}
print_u64 :: proc(fd: os.Handle, u: u64) {
mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
if src == nil do return dst;
// NOTE(bill): This _must_ be implemented like C's memmove
foreign _ {
when size_of(rawptr) == 8 {
@(link_name="llvm.memmove.p0i8.p0i8.i64")
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
} else {
@(link_name="llvm.memmove.p0i8.p0i8.i32")
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
}
}
llvm_memmove(dst, src, len, 1, false);
return dst;
}
print_u64 :: proc(fd: os.Handle, x: u64) {
digits := "0123456789";
a: [129]byte;
i := len(a);
b := u64(10);
u := x;
for u >= b {
i -= 1; a[i] = digits[u % b];
u /= b;
@@ -20,10 +50,11 @@ print_u64 :: proc(fd: os.Handle, u: u64) {
os.write(fd, a[i:]);
}
print_i64 :: proc(fd: os.Handle, u: i64) {
print_i64 :: proc(fd: os.Handle, x: i64) {
digits := "0123456789";
b :: i64(10);
u := x;
neg := u < 0;
u = abs(u);
@@ -241,6 +272,78 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
}
}
memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check {
x := uintptr(a);
y := uintptr(b);
n := uintptr(n);
SU :: size_of(uintptr);
fast := uintptr(n/SU + 1);
offset := (fast-1)*SU;
curr_block := uintptr(0);
if n < SU {
fast = 0;
}
for /**/; curr_block < fast; curr_block += 1 {
va := (^uintptr)(x + curr_block * size_of(uintptr))^;
vb := (^uintptr)(y + curr_block * size_of(uintptr))^;
if va ~ vb != 0 {
for pos := curr_block*SU; pos < n; pos += 1 {
a := (^byte)(x+pos)^;
b := (^byte)(y+pos)^;
if a ~ b != 0 {
return (int(a) - int(b)) < 0 ? -1 : +1;
}
}
}
}
for /**/; offset < n; offset += 1 {
a := (^byte)(x+offset)^;
b := (^byte)(y+offset)^;
if a ~ b != 0 {
return (int(a) - int(b)) < 0 ? -1 : +1;
}
}
return 0;
}
memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check {
x := uintptr(a);
n := uintptr(n);
SU :: size_of(uintptr);
fast := uintptr(n/SU + 1);
offset := (fast-1)*SU;
curr_block := uintptr(0);
if n < SU {
fast = 0;
}
for /**/; curr_block < fast; curr_block += 1 {
va := (^uintptr)(x + curr_block * size_of(uintptr))^;
if va ~ 0 != 0 {
for pos := curr_block*SU; pos < n; pos += 1 {
a := (^byte)(x+pos)^;
if a ~ 0 != 0 {
return int(a) < 0 ? -1 : +1;
}
}
}
}
for /**/; offset < n; offset += 1 {
a := (^byte)(x+offset)^;
if a ~ 0 != 0 {
return int(a) < 0 ? -1 : +1;
}
}
return 0;
}
string_eq :: proc "contextless" (a, b: string) -> bool {
switch {
case len(a) != len(b): return false;
@@ -251,7 +354,7 @@ string_eq :: proc "contextless" (a, b: string) -> bool {
}
string_cmp :: proc "contextless" (a, b: string) -> int {
return mem.compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
return memory_compare(&a[0], &b[0], min(len(a), len(b)));
}
string_ne :: inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b); }
@@ -261,18 +364,23 @@ string_le :: inline proc "contextless" (a, b: string) -> bool { return string_cm
string_ge :: inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0; }
cstring_len :: proc "contextless" (s: cstring) -> int {
n := 0;
for p := (^byte)(s); p != nil && p^ != 0; p = mem.ptr_offset(p, 1) {
n += 1;
p0 := uintptr((^byte)(s));
p := p0;
for p != 0 && (^byte)(p)^ != 0 {
p += 1;
}
return n;
return int(p - p0);
}
cstring_to_string :: proc "contextless" (s: cstring) -> string {
Raw_String :: struct {
data: ^byte,
len: int,
};
if s == nil do return "";
ptr := (^byte)(s);
n := cstring_len(s);
return transmute(string)mem.Raw_String{ptr, n};
return transmute(string)Raw_String{ptr, n};
}
@@ -283,6 +391,11 @@ complex128_eq :: inline proc "contextless" (a, b: complex128) -> bool { return r
complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
quaternion128_eq :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
quaternion128_ne :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
quaternion256_eq :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
quaternion256_ne :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) {
@@ -356,8 +469,84 @@ type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column
handle_error(file, line, column, from, to);
}
string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) {
return utf8.decode_rune_in_string(s);
// NOTE(bill): Duplicated here to remove dependency on package unicode/utf8
@static accept_sizes := [256]u8{
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
};
Accept_Range :: struct {lo, hi: u8};
@static accept_ranges := [5]Accept_Range{
{0x80, 0xbf},
{0xa0, 0xbf},
{0x80, 0x9f},
{0x90, 0xbf},
{0x80, 0x8f},
};
MASKX :: 0b0011_1111;
MASK2 :: 0b0001_1111;
MASK3 :: 0b0000_1111;
MASK4 :: 0b0000_0111;
LOCB :: 0b1000_0000;
HICB :: 0b1011_1111;
RUNE_ERROR :: '\ufffd';
n := len(s);
if n < 1 {
return RUNE_ERROR, 0;
}
s0 := s[0];
x := accept_sizes[s0];
if x >= 0xF0 {
mask := rune(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
return rune(s[0])&~mask | RUNE_ERROR&mask, 1;
}
sz := x & 7;
accept := accept_ranges[x>>4];
if n < int(sz) {
return RUNE_ERROR, 1;
}
b1 := s[1];
if b1 < accept.lo || accept.hi < b1 {
return RUNE_ERROR, 1;
}
if sz == 2 {
return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2;
}
b2 := s[2];
if b2 < LOCB || HICB < b2 {
return RUNE_ERROR, 1;
}
if sz == 3 {
return rune(s0&MASK3)<<12 | rune(b1&MASKX)<<6 | rune(b2&MASKX), 3;
}
b3 := s[3];
if b3 < LOCB || HICB < b3 {
return RUNE_ERROR, 1;
}
return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4;
}
bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_location, index, count: int) {
@@ -472,9 +661,16 @@ abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 {
r, i := real(x), imag(x);
return _sqrt_f64(r*r + i*i);
}
abs_quaternion128 :: inline proc "contextless" (x: quaternion128) -> f32 {
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
return _sqrt_f32(r*r + i*i + j*j + k*k);
}
abs_quaternion256 :: inline proc "contextless" (x: quaternion256) -> f64 {
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
return _sqrt_f64(r*r + i*i + j*j + k*k);
}
quo_complex64 :: proc(n, m: complex64) -> complex64 {
quo_complex64 :: proc "contextless" (n, m: complex64) -> complex64 {
e, f: f32;
if abs(real(m)) >= abs(imag(m)) {
@@ -492,7 +688,7 @@ quo_complex64 :: proc(n, m: complex64) -> complex64 {
return complex(e, f);
}
quo_complex128 :: proc(n, m: complex128) -> complex128 {
quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 {
e, f: f64;
if abs(real(m)) >= abs(imag(m)) {
@@ -509,3 +705,55 @@ quo_complex128 :: proc(n, m: complex128) -> complex128 {
return complex(e, f);
}
mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
return quaternion(t0, t1, t2, t3);
}
mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
return quaternion(t0, t1, t2, t3);
}
quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
return quaternion(t0, t1, t2, t3);
}
quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
return quaternion(t0, t1, t2, t3);
}
+6 -5
View File
@@ -1,6 +1,7 @@
package sort
import "core:mem"
import "intrinsics"
bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
assert(f != nil);
@@ -26,7 +27,7 @@ bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
}
}
bubble_sort :: proc(array: $A/[]$T) {
bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
count := len(array);
init_j, last_j := 0, count-1;
@@ -73,7 +74,7 @@ quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
quick_sort_proc(a[i:n], f);
}
quick_sort :: proc(array: $A/[]$T) {
quick_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
a := array;
n := len(a);
if n < 2 do return;
@@ -96,9 +97,9 @@ quick_sort :: proc(array: $A/[]$T) {
quick_sort(a[i:n]);
}
_log2 :: proc(n: int) -> int {
_log2 :: proc(x: int) -> int {
res := 0;
for ; n != 0; n >>= 1 do res += 1;
for n := x; n != 0; n >>= 1 do res += 1;
return res;
}
@@ -146,7 +147,7 @@ merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
if M & 1 == 0 do copy(arr2, arr1);
}
merge_sort :: proc(array: $A/[]$T) {
merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
merge_slices :: proc(arr1, arr2, out: A) {
N1, N2 := len(arr1), len(arr2);
i, j := 0, 0;
@@ -1,6 +1,6 @@
// Multiple precision decimal numbers
// NOTE: This is only for floating point printing and nothing else
package decimal
package strconv_decimal
Decimal :: struct {
digits: [384]byte, // big-endian digits
@@ -20,29 +20,29 @@ decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
// TODO(bill): make this work with a buffer that's not big enough
assert(len(buf) >= n);
buf = buf[0:n];
b := buf[0:n];
if a.count == 0 {
buf[0] = '0';
return string(buf[0:1]);
b[0] = '0';
return string(b[0:1]);
}
w := 0;
if a.decimal_point <= 0 {
buf[w] = '0'; w += 1;
buf[w] = '.'; w += 1;
w += digit_zero(buf[w : w-a.decimal_point]);
w += copy(buf[w:], a.digits[0:a.count]);
b[w] = '0'; w += 1;
b[w] = '.'; w += 1;
w += digit_zero(b[w : w-a.decimal_point]);
w += copy(b[w:], a.digits[0:a.count]);
} else if a.decimal_point < a.count {
w += copy(buf[w:], a.digits[0:a.decimal_point]);
buf[w] = '.'; w += 1;
w += copy(buf[w:], a.digits[a.decimal_point : a.count]);
w += copy(b[w:], a.digits[0:a.decimal_point]);
b[w] = '.'; w += 1;
w += copy(b[w:], a.digits[a.decimal_point : a.count]);
} else {
w += copy(buf[w:], a.digits[0:a.count]);
w += digit_zero(buf[w : w+a.decimal_point-a.count]);
w += copy(b[w:], a.digits[0:a.count]);
w += digit_zero(b[w : w+a.decimal_point-a.count]);
}
return string(buf[0:w]);
return string(b[0:w]);
}
// trim trailing zeros
@@ -56,10 +56,10 @@ trim :: proc(a: ^Decimal) {
}
assign :: proc(a: ^Decimal, i: u64) {
assign :: proc(a: ^Decimal, idx: u64) {
buf: [64]byte;
n := 0;
for i > 0 {
for i := idx; i > 0; {
j := i/10;
i -= 10*j;
buf[n] = byte('0'+i);
@@ -175,11 +175,11 @@ shift_left :: proc(a: ^Decimal, k: uint) {
trim(a);
}
shift :: proc(a: ^Decimal, k: int) {
shift :: proc(a: ^Decimal, i: int) {
uint_size :: 8*size_of(uint);
max_shift :: uint_size-4;
switch {
switch k := i; {
case a.count == 0:
// no need to update
case k > 0:
+16 -14
View File
@@ -1,6 +1,6 @@
package strconv
using import "core:decimal"
using import "decimal"
Int_Flag :: enum {
Prefix,
@@ -28,7 +28,7 @@ _f32_info := Float_Info{23, 8, -127};
_f64_info := Float_Info{52, 11, -1023};
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte {
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int) -> []byte {
bits: u64;
flt: ^Float_Info;
switch bit_size {
@@ -73,6 +73,7 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
assign(d, mant);
shift(d, exp - int(flt.mantbits));
digs: Decimal_Slice;
prec := precision;
shortest := prec < 0;
if shortest {
round_shortest(d, mant, exp, flt);
@@ -100,11 +101,11 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte {
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, precision: int, fmt: byte) -> []byte {
Buffer :: struct {
b: []byte,
n: int,
}
};
to_bytes :: proc(b: Buffer) -> []byte do return b.b[:b.n];
add_bytes :: proc(buf: ^Buffer, bytes: ..byte) {
@@ -112,6 +113,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
}
b := Buffer{b = buf};
prec := precision;
switch fmt {
case 'f', 'F':
@@ -289,7 +291,8 @@ MAX_BASE :: 32;
digits := "0123456789abcdefghijklmnopqrstuvwxyz";
is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) {
is_integer_negative :: proc(x: u64, is_signed: bool, bit_size: int) -> (u: u64, neg: bool) {
u = x;
if is_signed {
switch bit_size {
case 8:
@@ -312,18 +315,17 @@ is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned
panic("is_integer_negative: Unknown integer size");
}
}
return u, neg;
return;
}
append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
if base < 2 || base > MAX_BASE {
panic("strconv: illegal base passed to append_bits");
}
neg: bool;
a: [129]byte;
i := len(a);
u, neg = is_integer_negative(u, is_signed, bit_size);
u, neg := is_integer_negative(x, is_signed, bit_size);
b := u64(base);
for u >= b {
i-=1; a[i] = digits[u % b];
@@ -360,7 +362,8 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i
return string(buf[0:len(out)]);
}
is_integer_negative_128 :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
is_integer_negative_128 :: proc(x: u128, is_signed: bool, bit_size: int) -> (u: u128, neg: bool) {
u = x;
if is_signed {
switch bit_size {
case 8:
@@ -387,19 +390,18 @@ is_integer_negative_128 :: proc(u: u128, is_signed: bool, bit_size: int) -> (uns
panic("is_integer_negative: Unknown integer size");
}
}
return u, neg;
return;
}
append_bits_128 :: proc(buf: []byte, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
if base < 2 || base > MAX_BASE {
panic("strconv: illegal base passed to append_bits");
}
neg: bool;
a: [140]byte;
i := len(a);
u, neg = is_integer_negative_128(u, is_signed, bit_size);
u, neg := is_integer_negative_128(x, is_signed, bit_size);
b := u128(base);
for u >= b {
i-=1; a[i] = digits[u % b];
+10 -3
View File
@@ -23,7 +23,8 @@ _digit_value :: proc(r: rune) -> int {
return v;
}
parse_i64 :: proc(s: string) -> i64 {
parse_i64 :: proc(str: string) -> i64 {
s := str;
neg := false;
if len(s) > 1 {
switch s[0] {
@@ -66,7 +67,8 @@ parse_i64 :: proc(s: string) -> i64 {
return value;
}
parse_u64 :: proc(s: string) -> u64 {
parse_u64 :: proc(str: string) -> u64 {
s := str;
neg := false;
if len(s) > 1 && s[0] == '+' {
s = s[1:];
@@ -203,13 +205,17 @@ itoa :: proc(buf: []byte, i: int) -> string {
atoi :: proc(s: string) -> int {
return parse_int(s);
}
atof :: proc(s: string) -> f64 {
return parse_f64(s);
}
ftoa :: append_float;
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
}
quote :: proc(buf: []byte, s: string) -> string {
quote :: proc(buf: []byte, str: string) -> string {
write_byte :: inline proc(buf: []byte, i: ^int, bytes: ..byte) {
if i^ >= len(buf) do return;
n := copy(buf[i^:], bytes[:]);
@@ -222,6 +228,7 @@ quote :: proc(buf: []byte, s: string) -> string {
c :: '"';
i := 0;
s := str;
write_byte(buf, &i, c);
for width := 0; len(s) > 0; s = s[width:] {
+15 -11
View File
@@ -21,6 +21,10 @@ grow_builder :: proc(b: ^Builder, cap: int) {
reserve(&b.buf, cap);
}
reset_builder :: proc(b: ^Builder) {
clear(&b.buf);
}
builder_from_slice :: proc(backing: []byte) -> Builder {
s := transmute(mem.Raw_Slice)backing;
d := mem.Raw_Dynamic_Array{
@@ -68,9 +72,9 @@ write_bytes :: proc(b: ^Builder, x: []byte) {
@(private, static)
DIGITS_LOWER := "0123456789abcdefx";
write_quoted_string :: proc(b: ^Builder, s: string, quote: byte = '"') {
write_quoted_string :: proc(b: ^Builder, str: string, quote: byte = '"') {
write_byte(b, quote);
for width := 0; len(s) > 0; s = s[width:] {
for width, s := 0, str; len(s) > 0; s = s[width:] {
r := rune(s[0]);
width = 1;
if r >= utf8.RUNE_SELF {
@@ -166,27 +170,27 @@ write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false
case '\t': write_string(b, `\t`);
case '\v': write_string(b, `\v`);
case:
switch {
case r < ' ':
switch c := r; {
case c < ' ':
write_byte(b, '\\');
write_byte(b, 'x');
write_byte(b, DIGITS_LOWER[byte(r)>>4]);
write_byte(b, DIGITS_LOWER[byte(r)&0xf]);
write_byte(b, DIGITS_LOWER[byte(c)>>4]);
write_byte(b, DIGITS_LOWER[byte(c)&0xf]);
case r > utf8.MAX_RUNE:
r = 0xfffd;
case c > utf8.MAX_RUNE:
c = 0xfffd;
fallthrough;
case r < 0x10000:
case c < 0x10000:
write_byte(b, '\\');
write_byte(b, 'u');
for s := 12; s >= 0; s -= 4 {
write_byte(b, DIGITS_LOWER[r>>uint(s) & 0xf]);
write_byte(b, DIGITS_LOWER[c>>uint(s) & 0xf]);
}
case:
write_byte(b, '\\');
write_byte(b, 'U');
for s := 28; s >= 0; s -= 4 {
write_byte(b, DIGITS_LOWER[r>>uint(s) & 0xf]);
write_byte(b, DIGITS_LOWER[c>>uint(s) & 0xf]);
}
}
}
+173 -21
View File
@@ -67,7 +67,8 @@ rune_count :: proc(s: string) -> int {
}
equal_fold :: proc(s, t: string) -> bool {
equal_fold :: proc(u, v: string) -> bool {
s, t := u, v;
loop: for s != "" && t != "" {
sr, tr: rune;
if s[0] < utf8.RUNE_SELF {
@@ -154,6 +155,73 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string {
return string(b);
}
@private
_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator) -> []string {
s, n := s_, n_;
if n == 0 {
return nil;
}
if sep == "" {
l := utf8.rune_count_in_string(s);
if n < 0 || n > l {
n = l;
}
res := make([dynamic]string, n, allocator);
for i := 0; i < n-1; i += 1 {
_, w := utf8.decode_rune_in_string(s);
res[i] = s[:w];
s = s[w:];
}
if n > 0 {
res[n-1] = s;
}
return res[:];
}
if n < 0 {
n = count(s, sep) + 1;
}
res := make([dynamic]string, n, allocator);
n -= 1;
i := 0;
for ; i < n; i += 1 {
m := index(s, sep);
if m < 0 {
break;
}
res[i] = s[:m+sep_save];
s = s[m+len(sep):];
}
res[i] = s;
return res[:i+1];
}
split :: inline proc(s, sep: string, allocator := context.allocator) -> []string {
return _split(s, sep, 0, -1, allocator);
}
split_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string {
return _split(s, sep, 0, n, allocator);
}
split_after :: inline proc(s, sep: string, allocator := context.allocator) -> []string {
return _split(s, sep, len(sep), -1, allocator);
}
split_after_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string {
return _split(s, sep, len(sep), n, allocator);
}
index_byte :: proc(s: string, c: byte) -> int {
for i := 0; i < len(s); i += 1 {
if s[i] == c do return i;
@@ -169,7 +237,25 @@ last_index_byte :: proc(s: string, c: byte) -> int {
return -1;
}
@private PRIME_RABIN_KARP :: 16777619;
index :: proc(s, substr: string) -> int {
hash_str_rabin_karp :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
for i := 0; i < len(s); i += 1 {
hash = hash*PRIME_RABIN_KARP + u32(s[i]);
}
sq := u32(PRIME_RABIN_KARP);
for i := len(s); i > 0; i >>= 1 {
if (i & 1) != 0 {
pow *= sq;
}
sq *= sq;
}
return;
}
n := len(substr);
switch {
case n == 0:
@@ -185,9 +271,68 @@ index :: proc(s, substr: string) -> int {
return -1;
}
for i := 0; i < len(s)-n+1; i += 1 {
x := s[i:i+n];
if x == substr {
hash, pow := hash_str_rabin_karp(substr);
h: u32;
for i := 0; i < n; i += 1 {
h = h*PRIME_RABIN_KARP + u32(s[i]);
}
if h == hash && s[:n] == substr {
return 0;
}
for i := n; i < len(s); /**/ {
h *= PRIME_RABIN_KARP;
h += u32(s[i]);
h -= pow * u32(s[i-n]);
i += 1;
if h == hash && s[i-n:i] == substr {
return i - n;
}
}
return -1;
}
last_index :: proc(s, substr: string) -> int {
hash_str_rabin_karp_reverse :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
for i := len(s) - 1; i >= 0; i -= 1 {
hash = hash*PRIME_RABIN_KARP + u32(s[i]);
}
sq := u32(PRIME_RABIN_KARP);
for i := len(s); i > 0; i >>= 1 {
if (i & 1) != 0 {
pow *= sq;
}
sq *= sq;
}
return;
}
n := len(substr);
switch {
case n == 0:
return len(s);
case n == 1:
return last_index_byte(s, substr[0]);
case n == len(s):
return substr == s ? 0 : -1;
case n > len(s):
return -1;
}
hash, pow := hash_str_rabin_karp_reverse(substr);
last := len(s) - n;
h: u32;
for i := len(s)-1; i >= last; i -= 1 {
h = h*PRIME_RABIN_KARP + u32(s[i]);
}
if h == hash && s[last:] == substr {
return last;
}
for i := last-1; i >= 0; i -= 1 {
h *= PRIME_RABIN_KARP;
h += u32(s[i]);
h -= pow * u32(s[i+n]);
if h == hash && s[i:i+n] == substr {
return i;
}
}
@@ -250,13 +395,14 @@ count :: proc(s, substr: string) -> int {
// TODO(bill): Use a non-brute for approach
n := 0;
str := s;
for {
i := index(s, substr);
i := index(str, substr);
if i == -1 {
return n;
}
n += 1;
s = s[i+len(substr):];
str = str[i+len(substr):];
}
return n;
}
@@ -289,22 +435,22 @@ replace :: proc(s, old, new: string, n: int, allocator := context.allocator) ->
output = s;
return;
}
byte_count := n;
if m := count(s, old); m == 0 {
was_allocation = false;
output = s;
return;
} else if n < 0 || m < n {
n = m;
byte_count = m;
}
t := make([]byte, len(s) + n*(len(new) - len(old)), allocator);
t := make([]byte, len(s) + byte_count*(len(new) - len(old)), allocator);
was_allocation = true;
w := 0;
start := 0;
for i := 0; i < n; i += 1 {
for i := 0; i < byte_count; i += 1 {
j := start;
if len(old) == 0 {
if i > 0 {
@@ -475,14 +621,16 @@ trim_left :: proc(s: string, cutset: string) -> string {
if s == "" || cutset == "" {
return s;
}
return trim_left_proc_with_state(s, is_in_cutset, &cutset);
state := cutset;
return trim_left_proc_with_state(s, is_in_cutset, &state);
}
trim_right :: proc(s: string, cutset: string) -> string {
if s == "" || cutset == "" {
return s;
}
return trim_right_proc_with_state(s, is_in_cutset, &cutset);
state := cutset;
return trim_right_proc_with_state(s, is_in_cutset, &state);
}
trim :: proc(s: string, cutset: string) -> string {
@@ -515,7 +663,8 @@ trim_null :: proc(s: string) -> string {
// scrub scruvs invalid utf-8 characters and replaces them with the replacement string
// Adjacent invalid bytes are only replaced once
scrub :: proc(str: string, replacement: string, allocator := context.allocator) -> string {
scrub :: proc(s: string, replacement: string, allocator := context.allocator) -> string {
str := s;
b := make_builder(allocator);;
grow_builder(&b, len(str));
@@ -547,7 +696,8 @@ scrub :: proc(str: string, replacement: string, allocator := context.allocator)
}
reverse :: proc(str: string, allocator := context.allocator) -> string {
reverse :: proc(s: string, allocator := context.allocator) -> string {
str := s;
n := len(str);
buf := make([]byte, n);
i := 0;
@@ -560,17 +710,18 @@ reverse :: proc(str: string, allocator := context.allocator) -> string {
return string(buf);
}
expand_tabs :: proc(str: string, tab_size: int, allocator := context.allocator) -> string {
expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) -> string {
if tab_size <= 0 {
panic("tab size must be positive");
}
if str == "" {
if s == "" {
return "";
}
b := make_builder(allocator);
str := s;
column: int;
for len(str) > 0 {
@@ -683,11 +834,12 @@ write_pad_string :: proc(b: ^Builder, pad: string, pad_len, remains: int) {
write_string(b, pad);
}
remains = remains % pad_len;
n := remains % pad_len;
p := pad;
if remains != 0 do for i := 0; i < remains; i += 1 {
r, w := utf8.decode_rune_in_string(pad);
for i := 0; i < n; i += 1 {
r, w := utf8.decode_rune_in_string(p);
write_rune(b, r);
pad = pad[w:];
p = p[w:];
}
}
-24
View File
@@ -1,24 +0,0 @@
ENTRY(_start)
SECTIONS
{
. = 0x100000;
.text BLOCK(4K) : ALIGN(4K)
{
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
}
+4 -5
View File
@@ -89,7 +89,6 @@ _open_file_dialog :: proc(title: string, dir: string,
// Filters need to be passed as a pair of strings (title, filter)
filter_len := u32(len(filters));
if filter_len % 2 != 0 do return "", false;
default_filter = clamp(default_filter, 1, filter_len / 2);
filter: string;
filter = strings.join(filters, "\u0000", context.temp_allocator);
@@ -102,7 +101,7 @@ _open_file_dialog :: proc(title: string, dir: string,
title = utf8_to_wstring(title, context.temp_allocator),
filter = utf8_to_wstring(filter, context.temp_allocator),
initial_dir = utf8_to_wstring(dir, context.temp_allocator),
filter_index = u32(default_filter),
filter_index = u32(clamp(default_filter, 1, filter_len / 2)),
def_ext = utf8_to_wstring(default_ext, context.temp_allocator),
flags = u32(flags),
};
@@ -121,7 +120,7 @@ _open_file_dialog :: proc(title: string, dir: string,
return "", false;
}
file_name := ucs2_to_utf8(file_buf[:], allocator);
file_name := utf16_to_utf8(file_buf[:], allocator);
path = strings.trim_right_null(file_name);
return;
}
@@ -143,7 +142,7 @@ select_file_to_save :: proc(title := SAVE_TITLE, dir := ".",
return;
}
// TODO: Implement convenience function for select_file_to_open with ALLOW_MULTI_SELECT that takes
// TODO: Implement convenience function for select_file_to_open with ALLOW_MULTI_SELECT that takes
// it output of the form "path\u0000\file1u\0000file2" and turns it into []string with the path + file pre-concatenated for you.
OFN_ALLOWMULTISELECT :: 0x00000200; // NOTE(Jeroen): Without OFN_EXPLORER it uses the Win3 dialog.
@@ -186,4 +185,4 @@ CDERR_LOCKRESFAILURE :: 0x00000008;
CDERR_MEMALLOCFAILURE :: 0x00000009;
CDERR_MEMLOCKFAILURE :: 0x0000000A;
CDERR_NOHOOK :: 0x0000000B;
CDERR_REGISTERMSGFAIL :: 0x0000000C;
CDERR_REGISTERMSGFAIL :: 0x0000000C;
+2 -2
View File
@@ -9,6 +9,6 @@ foreign {
get_cwd :: proc(allocator := context.temp_allocator) -> string {
buffer := make([]u16, MAX_PATH_WIDE, allocator);
_get_cwd_wide(Wstring(&buffer[0]), MAX_PATH_WIDE);
file := ucs2_to_utf8(buffer[:], allocator);
file := utf16_to_utf8(buffer[:], allocator);
return strings.trim_right_null(file);
}
}
+3 -3
View File
@@ -728,7 +728,7 @@ CP_UTF8 :: 65001; // UTF-8 translation
MB_ERR_INVALID_CHARS :: 8;
WC_ERR_INVALID_CHARS :: 128;
utf8_to_ucs2 :: proc(s: string, allocator := context.temp_allocator) -> []u16 {
utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 {
if len(s) < 1 {
return nil;
}
@@ -751,13 +751,13 @@ utf8_to_ucs2 :: proc(s: string, allocator := context.temp_allocator) -> []u16 {
return text[:len(text)-1];
}
utf8_to_wstring :: proc(s: string, allocator := context.temp_allocator) -> Wstring {
if res := utf8_to_ucs2(s, allocator); res != nil {
if res := utf8_to_utf16(s, allocator); res != nil {
return Wstring(&res[0]);
}
return nil;
}
ucs2_to_utf8 :: proc(s: []u16, allocator := context.temp_allocator) -> string {
utf16_to_utf8 :: proc(s: []u16, allocator := context.temp_allocator) -> string {
if len(s) < 1 {
return "";
}
+1 -1
View File
@@ -23,7 +23,7 @@ foreign kernel32 {
@(link_name="GetModuleFileNameA") get_module_file_name_a :: proc(module: Hmodule, filename: cstring, size: u32) -> u32 ---;
@(link_name="GetModuleFileNameW") get_module_file_name_w :: proc(module: Hmodule, filename: Wstring, size: u32) -> u32 ---;
@(link_name="Sleep") sleep :: proc(ms: i32) -> i32 ---;
@(link_name="Sleep") sleep :: proc(ms: u32) ---;
@(link_name="QueryPerformanceFrequency") query_performance_frequency :: proc(result: ^i64) -> i32 ---;
@(link_name="QueryPerformanceCounter") query_performance_counter :: proc(result: ^i64) -> i32 ---;
@(link_name="OutputDebugStringA") output_debug_string_a :: proc(c_str: cstring) ---;
+1 -1
View File
@@ -182,7 +182,7 @@ foreign user32 {
@(link_name="DestroyIcon") destroy_icon :: proc(icon: Hicon) -> Bool ---;
@(link_name="LoadCursorA") load_cursor_a :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
@(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
@(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: Wstring) -> Hcursor ---;
@(link_name="GetCursor") get_cursor :: proc() -> Hcursor ---;
@(link_name="SetCursor") set_cursor :: proc(cursor: Hcursor) -> Hcursor ---;
+56
View File
@@ -0,0 +1,56 @@
package time
foreign import libc "system:c"
TimeSpec :: struct {
tv_sec : i64, /* seconds */
tv_nsec : i64, /* nanoseconds */
};
CLOCK_SYSTEM :: 0;
CLOCK_CALENDAR :: 1;
IS_SUPPORTED :: true;
foreign libc {
@(link_name="clock_gettime") _clock_gettime :: proc(clock_id: u64, timespec: ^TimeSpec) ---;
@(link_name="nanosleep") _nanosleep :: proc(requested: ^TimeSpec, remaining: ^TimeSpec) -> int ---;
@(link_name="sleep") _sleep :: proc(seconds: u64) -> int ---;
}
clock_gettime :: proc(clock_id: u64) -> TimeSpec {
ts : TimeSpec;
_clock_gettime(clock_id, &ts);
return ts;
}
now :: proc() -> Time {
time_spec_now := clock_gettime(CLOCK_SYSTEM);
ns := time_spec_now.tv_sec * 1e9 + time_spec_now.tv_nsec;
return Time{_nsec=ns};
}
seconds_since_boot :: proc() -> f64 {
ts_boottime := clock_gettime(CLOCK_SYSTEM);
return f64(ts_boottime.tv_sec) + f64(ts_boottime.tv_nsec) / 1e9;
}
sleep :: proc(d: Duration) {
ds := duration_seconds(d);
seconds := u64(ds);
nanoseconds := i64((ds - f64(seconds)) * 1e9);
if seconds > 0 do _sleep(seconds);
if nanoseconds > 0 do nanosleep(nanoseconds);
}
nanosleep :: proc(nanoseconds: i64) -> int {
assert(nanoseconds <= 999999999);
requested, remaining : TimeSpec;
requested = TimeSpec{tv_nsec = nanoseconds};
return _nanosleep(&requested, &remaining);
}
+2
View File
@@ -0,0 +1,2 @@
package time
IS_SUPPORTED :: false;
-3
View File
@@ -1,3 +0,0 @@
package time
IS_SUPPORTED :: false;
+1 -1
View File
@@ -20,5 +20,5 @@ now :: proc() -> Time {
sleep :: proc(d: Duration) {
win32.sleep(i32(d/Millisecond));
win32.sleep(u32(d/Millisecond));
}
+2 -1
View File
@@ -21,7 +21,8 @@ decode_surrogate_pair :: proc(r1, r2: rune) -> rune {
}
encode_surrogate_pair :: proc(r: rune) -> (r1, r2: rune) {
encode_surrogate_pair :: proc(c: rune) -> (r1, r2: rune) {
r := c;
if r < _surr_self || r > MAX_RUNE {
return REPLACEMENT_CHAR, REPLACEMENT_CHAR;
}
+63 -18
View File
@@ -41,26 +41,22 @@ accept_ranges := [5]Accept_Range{
};
accept_sizes := [256]u8{
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
0x00..0x7f = 0xf0,
0x80..0xc1 = 0xf1,
0xc2..0xdf = 0x02,
0xe0 = 0x13,
0xe1..0xec = 0x03,
0xed = 0x23,
0xee..0xef = 0x03,
0xf0 = 0x34,
0xf1..0xf3 = 0x04,
0xf4 = 0x44,
0xf5..0xff = 0xf1,
};
encode_rune :: proc(r: rune) -> ([4]u8, int) {
encode_rune :: proc(c: rune) -> ([4]u8, int) {
r := c;
buf: [4]u8;
i := u32(r);
mask :: u8(0x3f);
@@ -165,9 +161,58 @@ decode_last_rune :: proc(s: []u8) -> (rune, int) {
return r, size;
}
rune_at_pos :: proc(s: string, pos: int) -> rune {
if pos < 0 {
return RUNE_ERROR;
}
i := 0;
for r in s {
if i == pos {
return r;
}
i += 1;
}
return RUNE_ERROR;
}
rune_string_at_pos :: proc(s: string, pos: int) -> string {
if pos < 0 {
return "";
}
i := 0;
for c, offset in s {
if i == pos {
w := rune_size(c);
return s[offset:][:w];
}
i += 1;
}
return "";
}
rune_at :: proc(s: string, byte_index: int) -> rune {
r, _ := decode_rune_in_string(s[byte_index:]);
return r;
}
// Returns the byte position of rune at position pos in s with an optional start byte position.
// Returns -1 if it runs out of the string.
rune_offset :: proc(s: string, pos: int, start: int = 0) -> int {
if pos < 0 {
return -1;
}
i := 0;
for _, offset in s[start:] {
if i == pos {
return offset+start;
}
i += 1;
}
return -1;
}
valid_rune :: proc(r: rune) -> bool {
if r < 0 {
+452 -40
View File
@@ -3,14 +3,34 @@ package main
import "core:fmt"
import "core:mem"
import "core:os"
import "core:reflect"
import "intrinsics"
when os.OS == "windows" {
import "core:thread"
}
@(link_name="general_stuff")
general_stuff :: proc() {
fmt.println("# general_stuff");
/*
The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
* simplicity
* high performance
* built for modern systems
* joy of programming
# Installing Odin
Getting Started - https://odin-lang.org/docs/install/
Instructions for downloading and install the Odin compiler and libraries.
# Learning Odin
Overview of Odin - https://odin-lang.org/docs/overview/
An overview of the Odin programming language.
Frequently Asked Questions (FAQ) - https://odin-lang.org/docs/faq/
Answers to common questions about Odin.
*/
@(link_name="extra_general_stuff")
extra_general_stuff :: proc() {
fmt.println("# extra_general_stuff");
{ // `do` for inline statements rather than block
foo :: proc() do fmt.println("Foo!");
if false do foo();
@@ -30,14 +50,12 @@ general_stuff :: proc() {
i := i32(137);
ptr := &i;
_ = (^f32)(ptr);
_ = (^f32)(ptr); // Call-based syntax
// ^f32(ptr) == ^(f32(ptr))
_ = cast(^f32)ptr;
_ = cast(^f32)ptr; // Operator-based syntax
_ = (^f32)(ptr)^;
_ = (cast(^f32)ptr)^;
// Questions: Should there be two ways to do it?
}
/*
@@ -50,7 +68,7 @@ general_stuff :: proc() {
Foo :: struct {
x: int,
b: bool,
}
};
f := Foo{137, true};
x, b := expand_to_tuple(f);
fmt.println(f);
@@ -191,8 +209,8 @@ union_type :: proc() {
}
}
Vector3 :: struct {x, y, z: f32};
Quaternion :: struct {x, y, z, w: f32};
Vector3 :: distinct [3]f32;
Quaternion :: distinct quaternion128;
// More realistic examples
{
@@ -209,18 +227,18 @@ union_type :: proc() {
orientation: Quaternion,
derived: any,
}
};
Frog :: struct {
using entity: Entity,
jump_height: f32,
}
};
Monster :: struct {
using entity: Entity,
is_robot: bool,
is_zombie: bool,
}
};
// See `parametric_polymorphism` procedure for details
new_entity :: proc($T: typeid) -> ^Entity {
@@ -254,18 +272,18 @@ union_type :: proc() {
orientation: Quaternion,
derived: union {Frog, Monster},
}
};
Frog :: struct {
using entity: ^Entity,
jump_height: f32,
}
};
Monster :: struct {
using entity: ^Entity,
is_robot: bool,
is_zombie: bool,
}
};
// See `parametric_polymorphism` procedure for details
new_entity :: proc($T: typeid) -> ^Entity {
@@ -302,17 +320,17 @@ union_type :: proc() {
/*
Entity :: struct {
..
...
derived: union{^Frog, ^Monster},
}
Frog :: struct {
using entity: Entity,
..
...
}
Monster :: struct {
using entity: Entity,
..
...
}
new_entity :: proc(T: type) -> ^Entity {
@@ -325,7 +343,7 @@ union_type :: proc() {
}
parametric_polymorphism :: proc() {
fmt.println("# parametric_polymorphism");
fmt.println("\n# parametric_polymorphism");
print_value :: proc(value: $T) {
fmt.printf("print_value: %T %v\n", value, value);
@@ -383,13 +401,13 @@ parametric_polymorphism :: proc() {
hash: u32,
key: Key,
value: Value,
}
};
TABLE_SIZE_MIN :: 32;
Table :: struct(Key, Value: typeid) {
count: int,
allocator: mem.Allocator,
slots: []Table_Slot(Key, Value),
}
};
// Only allow types that are specializations of a (polymorphic) slice
make_slice :: proc($T: typeid/[]$E, len: int) -> T {
@@ -513,7 +531,7 @@ parametric_polymorphism :: proc() {
Foo1,
Foo2,
Foo3,
}
};
Para_Union :: union(T: typeid) {T, Error};
r: Para_Union(int);
fmt.println(typeid_of(type_of(r)));
@@ -521,7 +539,7 @@ parametric_polymorphism :: proc() {
fmt.println(r);
r = 123;
fmt.println(r);
r = Error.Foo0;
r = Error.Foo0; // r = .Foo0; is allow too, see implicit selector expressions below
fmt.println(r);
}
@@ -543,6 +561,30 @@ parametric_polymorphism :: proc() {
for v, i in array {
assert(v == T(i*i));
}
// Matrix multiplication
mul :: proc(a: [$M][$N]$T, b: [N][$P]T) -> (c: [M][P]T) {
for i in 0..<M {
for j in 0..<P {
for k in 0..<N {
c[i][j] += a[i][k] * b[k][j];
}
}
}
return;
}
x := [2][3]f32{
{1, 2, 3},
{3, 2, 1},
};
y := [3][2]f32{
{0, 8},
{6, 2},
{8, 4},
};
z := mul(x, y);
assert(z == {{36, 24}, {20, 32}});
}
}
@@ -560,7 +602,7 @@ prefix_table := [?]string{
threading_example :: proc() {
when os.OS == "windows" {
fmt.println("# threading_example");
fmt.println("\n# threading_example");
worker_proc :: proc(t: ^thread.Thread) -> int {
for iteration in 1..5 {
@@ -600,7 +642,7 @@ threading_example :: proc() {
}
array_programming :: proc() {
fmt.println("# array_programming");
fmt.println("\n# array_programming");
{
a := [3]f32{1, 2, 3};
b := [3]f32{5, 6, 7};
@@ -645,7 +687,7 @@ array_programming :: proc() {
}
named_proc_return_parameters :: proc() {
fmt.println("# named proc return parameters");
fmt.println("\n# named proc return parameters");
foo0 :: proc() -> int {
return 123;
@@ -667,7 +709,7 @@ named_proc_return_parameters :: proc() {
using_enum :: proc() {
fmt.println("# using enum");
fmt.println("\n# using enum");
using Foo :: enum {A, B, C};
@@ -679,25 +721,25 @@ using_enum :: proc() {
}
map_type :: proc() {
fmt.println("# map type");
fmt.println("\n# map type");
// enums of type u16, u32, i16 & i32 also work
Enum_u8 :: enum u8 {
A = 0,
B = 1 << 8 - 1,
}
};
Enum_u64 :: enum u64 {
A = 0,
B = 1 << 64 - 1,
}
};
Enum_i8 :: enum i8 {
A = 0,
B = -(1 << 7),
}
};
Enum_i64 :: enum i64 {
A = 0,
B = -(1 << 63),
}
};
map_u8: map[Enum_u8]u8;
map_u8[Enum_u8.A] = u8(Enum_u8.B);
@@ -721,7 +763,7 @@ map_type :: proc() {
demo_struct :: struct {
member: Enum_i64,
}
};
map_string: map[string]demo_struct;
map_string["Hellope!"] = demo_struct{Enum_i64.B};
@@ -734,7 +776,7 @@ map_type :: proc() {
}
implicit_selector_expression :: proc() {
fmt.println("# implicit selector expression");
fmt.println("\n# implicit selector expression");
Foo :: enum {A, B, C};
@@ -762,7 +804,7 @@ implicit_selector_expression :: proc() {
}
explicit_procedure_overloading :: proc() {
fmt.println("# explicit procedure overloading");
fmt.println("\n# explicit procedure overloading");
add_ints :: proc(a, b: int) -> int {
x := a + b;
@@ -796,14 +838,14 @@ explicit_procedure_overloading :: proc() {
}
complete_switch :: proc() {
fmt.println("# complete_switch");
fmt.println("\n# complete_switch");
{ // enum
using Foo :: enum {
A,
B,
C,
D,
}
};
b := Foo.B;
f := Foo.A;
@@ -829,6 +871,8 @@ complete_switch :: proc() {
}
cstring_example :: proc() {
fmt.println("\n# cstring_example");
W :: "Hellope";
X :: cstring(W);
Y :: string(X);
@@ -860,6 +904,8 @@ deprecated_attribute :: proc() {
}
bit_set_type :: proc() {
fmt.println("\n# bit_set_type");
{
using Day :: enum {
Sunday,
@@ -869,7 +915,7 @@ bit_set_type :: proc() {
Thursday,
Friday,
Saturday,
}
};
Days :: distinct bit_set[Day];
WEEKEND :: Days{Sunday, Saturday};
@@ -921,6 +967,8 @@ bit_set_type :: proc() {
}
diverging_procedures :: proc() {
fmt.println("\n# diverging_procedures");
// Diverging procedures may never return
foo :: proc() -> ! {
fmt.println("I'm a diverging procedure");
@@ -930,6 +978,8 @@ diverging_procedures :: proc() {
}
deferred_procedure_associations :: proc() {
fmt.println("\n# deferred_procedure_associations");
@(deferred_out=closure)
open :: proc(s: string) -> bool {
fmt.println(s);
@@ -945,9 +995,363 @@ deferred_procedure_associations :: proc() {
}
}
reflection :: proc() {
fmt.println("\n# reflection");
Foo :: struct {
x: int `tag1`,
y: string `json:"y_field"`,
z: bool, // no tag
};
id := typeid_of(Foo);
names := reflect.struct_field_names(id);
types := reflect.struct_field_types(id);
tags := reflect.struct_field_tags(id);
assert(len(names) == len(types) && len(names) == len(tags));
fmt.println("Foo :: struct {");
for tag, i in tags {
name, type := names[i], types[i];
if tag != "" {
fmt.printf("\t%s: %T `%s`,\n", name, type, tag);
} else {
fmt.printf("\t%s: %T,\n", name, type);
}
}
fmt.println("}");
for tag, i in tags {
if val, ok := reflect.struct_tag_lookup(tag, "json"); ok {
fmt.printf("json: %s -> %s\n", names[i], val);
}
}
}
quaternions :: proc() {
fmt.println("\n# quaternions");
{ // Quaternion operations
q := 1 + 2i + 3j + 4k;
r := quaternion(5, 6, 7, 8);
t := q * r;
fmt.printf("(%v) * (%v) = %v\n", q, r, t);
v := q / r;
fmt.printf("(%v) / (%v) = %v\n", q, r, v);
u := q + r;
fmt.printf("(%v) + (%v) = %v\n", q, r, u);
s := q - r;
fmt.printf("(%v) - (%v) = %v\n", q, r, s);
}
{ // The quaternion types
q128: quaternion128; // 4xf32
q256: quaternion256; // 4xf64
q128 = quaternion(1, 0, 0, 0);
q256 = 1; // quaternion(1, 0, 0, 0);
}
{ // Built-in procedures
q := 1 + 2i + 3j + 4k;
fmt.println("q =", q);
fmt.println("real(q) =", real(q));
fmt.println("imag(q) =", imag(q));
fmt.println("jmag(q) =", jmag(q));
fmt.println("kmag(q) =", kmag(q));
fmt.println("conj(q) =", conj(q));
fmt.println("abs(q) =", abs(q));
}
{ // Conversion of a complex type to a quaternion type
c := 1 + 2i;
q := quaternion256(c);
fmt.println(c);
fmt.println(q);
}
{ // Memory layout of Quaternions
q := 1 + 2i + 3j + 4k;
a := transmute([4]f64)q;
fmt.println("Quaternion memory layout: xyzw/(ijkr)");
fmt.println(q); // 1.000+2.000i+3.000j+4.000k
fmt.println(a); // [2.000, 3.000, 4.000, 1.000]
}
}
inline_for_statement :: proc() {
fmt.println("\n#inline for statements");
// 'inline for' works the same as if the 'inline' prefix did not
// exist but these ranged loops are explicitly unrolled which can
// be very very useful for certain optimizations
fmt.println("Ranges");
inline for x, i in 1..<4 {
fmt.println(x, i);
}
fmt.println("Strings");
inline for r, i in "Hello, 世界" {
fmt.println(r, i);
}
fmt.println("Arrays");
inline for elem, idx in ([4]int{1, 4, 9, 16}) {
fmt.println(elem, idx);
}
Foo_Enum :: enum {
A = 1,
B,
C = 6,
D,
};
fmt.println("Enum types");
inline for elem, idx in Foo_Enum {
fmt.println(elem, idx);
}
}
where_clauses :: proc() {
fmt.println("\n#procedure 'where' clauses");
{ // Sanity checks
simple_sanity_check :: proc(x: [2]int)
where len(x) > 1,
type_of(x) == [2]int {
fmt.println(x);
}
}
{ // Parametric polymorphism checks
cross_2d :: proc(a, b: $T/[2]$E) -> E
where intrinsics.type_is_numeric(E) {
return a.x*b.y - a.y*b.x;
}
cross_3d :: proc(a, b: $T/[3]$E) -> T
where intrinsics.type_is_numeric(E) {
x := a.y*b.z - a.z*b.y;
y := a.z*b.x - a.x*b.z;
z := a.x*b.y - a.y*b.z;
return T{x, y, z};
}
a := [2]int{1, 2};
b := [2]int{5, -3};
fmt.println(cross_2d(a, b));
x := [3]f32{1, 4, 9};
y := [3]f32{-5, 0, 3};
fmt.println(cross_3d(x, y));
// Failure case
// i := [2]bool{true, false};
// j := [2]bool{false, true};
// fmt.println(cross_2d(i, j));
}
{ // Procedure groups usage
foo :: proc(x: [$N]int) -> bool
where N > 2 {
fmt.println(#procedure, "was called with the parameter", x);
return true;
}
bar :: proc(x: [$N]int) -> bool
where 0 < N,
N <= 2 {
fmt.println(#procedure, "was called with the parameter", x);
return false;
}
baz :: proc{foo, bar};
x := [3]int{1, 2, 3};
y := [2]int{4, 9};
ok_x := baz(x);
ok_y := baz(y);
assert(ok_x == true);
assert(ok_y == false);
}
{ // Record types
Foo :: struct(T: typeid, N: int)
where intrinsics.type_is_integer(T),
N > 2 {
x: [N]T,
y: [N-2]T,
};
T :: i32;
N :: 5;
f: Foo(T, N);
#assert(size_of(f) == (N+N-2)*size_of(T));
}
}
ranged_fields_for_array_compound_literals :: proc() {
fmt.println("\n#ranged fields for array compound literals");
{ // Normal Array Literal
foo := [?]int{1, 4, 9, 16};
fmt.println(foo);
}
{ // Indexed
foo := [?]int{
3 = 16,
1 = 4,
2 = 9,
0 = 1,
};
fmt.println(foo);
}
{ // Ranges
i := 2;
foo := [?]int {
0 = 123,
5..9 = 54,
10..<16 = i*3 + (i-1)*2,
};
#assert(len(foo) == 16);
fmt.println(foo); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8]
}
{ // Slice and Dynamic Array support
i := 2;
foo_slice := []int {
0 = 123,
5..9 = 54,
10..<16 = i*3 + (i-1)*2,
};
assert(len(foo_slice) == 16);
fmt.println(foo_slice); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8]
foo_dynamic_array := [dynamic]int {
0 = 123,
5..9 = 54,
10..<16 = i*3 + (i-1)*2,
};
assert(len(foo_dynamic_array) == 16);
fmt.println(foo_dynamic_array); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8]
}
}
range_statements_with_multiple_return_values :: proc() {
// IMPORTANT NOTE(bill, 2019-11-02): This feature is subject to be changed/removed
fmt.println("\n#range statements with multiple return values");
My_Iterator :: struct {
index: int,
data: []i32,
};
make_my_iterator :: proc(data: []i32) -> My_Iterator {
return My_Iterator{data = data};
}
my_iterator :: proc(it: ^My_Iterator) -> (val: i32, idx: int, cond: bool) {
if cond = it.index < len(it.data); cond {
val = it.data[it.index];
idx = it.index;
it.index += 1;
}
return;
}
data := make([]i32, 6);
for _, i in data {
data[i] = i32(i*i);
}
{
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);
for {
val, _, cond := my_iterator(&it);
if !cond do break;
fmt.println(val);
}
}
}
soa_struct_layout :: proc() {
// IMPORTANT NOTE(bill, 2019-11-03): This feature is subject to be changed/removed
fmt.println("\n#SOA Struct Layout");
{
Vector3 :: struct {x, y, z: f32};
N :: 2;
v_aos: [N]Vector3;
v_aos[0].x = 1;
v_aos[0].y = 4;
v_aos[0].z = 9;
fmt.println(len(v_aos));
fmt.println(v_aos[0]);
fmt.println(v_aos[0].x);
fmt.println(&v_aos[0].x);
v_aos[1] = {0, 3, 4};
v_aos[1].x = 2;
fmt.println(v_aos[1]);
fmt.println(v_aos);
v_soa: intrinsics.soa_struct(N, Vector3);
v_soa[0].x = 1;
v_soa[0].y = 4;
v_soa[0].z = 9;
// Same syntax as AOS and treat as if it was an array
fmt.println(len(v_soa));
fmt.println(v_soa[0]);
fmt.println(v_soa[0].x);
v_soa[1] = {0, 3, 4};
v_soa[1].x = 2;
fmt.println(v_soa[1]);
// Can use SOA syntax if necessary
v_soa.x[0] = 1;
v_soa.y[0] = 4;
v_soa.z[0] = 9;
fmt.println(v_soa.x[0]);
// Same pointer addresses with both syntaxes
assert(&v_soa[0].x == &v_soa.x[0]);
// Same fmt printing
fmt.println(v_aos);
fmt.println(v_soa);
}
{
// Works with arrays of length <= 4 which have the implicit fields xyzw/rgba
Vector3 :: distinct [3]f32;
N :: 2;
v_aos: [N]Vector3;
v_aos[0].x = 1;
v_aos[0].y = 4;
v_aos[0].z = 9;
v_soa: intrinsics.soa_struct(N, Vector3);
v_soa[0].x = 1;
v_soa[0].y = 4;
v_soa[0].z = 9;
}
}
main :: proc() {
when true {
general_stuff();
extra_general_stuff();
union_type();
parametric_polymorphism();
threading_example();
@@ -963,5 +1367,13 @@ main :: proc() {
bit_set_type();
diverging_procedures();
deferred_procedure_associations();
reflection();
quaternions();
inline_for_statement();
where_clauses();
ranged_fields_for_array_compound_literals();
range_statements_with_multiple_return_values();
soa_struct_layout();
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 75 KiB

+2 -2
View File
@@ -1,8 +1,8 @@
@echo off
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
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 14.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\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
set _NO_DEBUG_HEAP=1
+21 -16
View File
@@ -499,7 +499,7 @@ void big_int_add(BigInt *dst, BigInt const *x, BigInt const *y) {
smaller = &neg_abs;
break;
default:
GB_PANIC("Invalid bit_int_cmp value");
GB_PANIC("Invalid big_int_cmp value");
return;
}
@@ -530,6 +530,9 @@ void big_int_add(BigInt *dst, BigInt const *x, BigInt const *y) {
if (sub_overflow_u64(v, prev_overflow, &v)) {
found_word = true;
overflow += 1;
} else {
// IMPORTANT TODO(bill): Is this mathematics correct here?
v += overflow;
}
dst->d.words[i] = v;
i += 1;
@@ -1245,15 +1248,15 @@ void big_int_xor(BigInt *dst, BigInt const *x, BigInt const *y) {
x = y;
y = tmp;
}
// x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1)
dst->neg = false;
BigInt y1 = big_int_make_abs(y);
big_int_sub_eq(&y1, &BIG_INT_ONE);
big_int__xor_abs(dst, x, &y1);
big_int_add_eq(dst, &BIG_INT_ONE);
dst->neg = true;
if (y->neg) {
// x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1)
BigInt y1 = big_int_make_abs(y);
big_int_sub_eq(&y1, &BIG_INT_ONE);
big_int__xor_abs(dst, x, &y1);
big_int_add_eq(dst, &BIG_INT_ONE);
dst->neg = true;
}
return;
}
@@ -1313,13 +1316,15 @@ void big_int_or(BigInt *dst, BigInt const *x, BigInt const *y) {
x = y;
y = tmp;
}
// x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(~((y-1) &~ x) + 1)
BigInt y1 = big_int_make_abs(y);
big_int_sub_eq(&y1, &BIG_INT_ONE);
big_int__and_not_abs(dst, &y1, x);
big_int_add_eq(dst, &BIG_INT_ONE);
dst->neg = true;
dst->neg = false;
if (y->neg) {
// x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(~((y-1) &~ x) + 1)
BigInt y1 = big_int_make_abs(y);
big_int_sub_eq(&y1, &BIG_INT_ONE);
big_int__and_not_abs(dst, &y1, x);
big_int_add_eq(dst, &BIG_INT_ONE);
dst->neg = true;
}
return;
}
+43 -14
View File
@@ -2,7 +2,7 @@ enum TargetOsKind {
TargetOs_Invalid,
TargetOs_windows,
TargetOs_osx,
TargetOs_darwin,
TargetOs_linux,
TargetOs_essence,
@@ -30,7 +30,7 @@ enum TargetEndianKind {
String target_os_names[TargetOs_COUNT] = {
str_lit(""),
str_lit("windows"),
str_lit("osx"),
str_lit("darwin"),
str_lit("linux"),
str_lit("essence"),
};
@@ -55,9 +55,7 @@ TargetEndianKind target_endians[TargetArch_COUNT] = {
String const ODIN_VERSION = str_lit("0.10.0");
String cross_compile_target = str_lit("");
String cross_compile_lib_dir = str_lit("");
String const ODIN_VERSION = str_lit("0.11.1");
@@ -66,6 +64,7 @@ struct TargetMetrics {
TargetArchKind arch;
isize word_size;
isize max_align;
String target_triplet;
};
@@ -109,11 +108,13 @@ struct BuildContext {
bool has_resource;
String opt_flags;
String llc_flags;
String target_triplet;
String link_flags;
bool is_dll;
bool generate_docs;
i32 optimization_level;
bool show_timings;
bool show_more_timings;
bool keep_temp_files;
bool ignore_unknown_attributes;
bool no_bounds_check;
@@ -121,6 +122,7 @@ struct BuildContext {
bool no_crt;
bool use_lld;
bool vet;
bool cross_compiling;
QueryDataSetSettings query_data_set_settings;
@@ -135,18 +137,19 @@ struct BuildContext {
gb_global BuildContext build_context = {0};
gb_global TargetMetrics target_windows_386 = {
TargetOs_windows,
TargetArch_386,
4,
8,
str_lit("i686-pc-windows"),
};
gb_global TargetMetrics target_windows_amd64 = {
TargetOs_windows,
TargetArch_amd64,
8,
16,
str_lit("x86_64-pc-windows-gnu"),
};
gb_global TargetMetrics target_linux_386 = {
@@ -154,23 +157,47 @@ gb_global TargetMetrics target_linux_386 = {
TargetArch_386,
4,
8,
str_lit("i686-pc-linux-gnu"),
};
gb_global TargetMetrics target_linux_amd64 = {
TargetOs_linux,
TargetArch_amd64,
8,
16,
str_lit("x86_64-pc-linux-gnu"),
};
gb_global TargetMetrics target_osx_amd64 = {
TargetOs_osx,
gb_global TargetMetrics target_darwin_amd64 = {
TargetOs_darwin,
TargetArch_amd64,
8,
16,
str_lit("x86_64-apple-darwin"),
};
gb_global TargetMetrics target_essence_amd64 = {
TargetOs_essence,
TargetArch_amd64,
8,
16,
str_lit("x86_64-pc-none-elf"),
};
struct NamedTargetMetrics {
String name;
TargetMetrics *metrics;
};
gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("essence_amd64"), &target_essence_amd64 },
{ str_lit("darwin_amd64"), &target_darwin_amd64 },
{ str_lit("linux_386"), &target_linux_386 },
{ str_lit("linux_amd64"), &target_linux_amd64 },
{ str_lit("windows_386"), &target_windows_386 },
{ str_lit("windows_amd64"), &target_windows_amd64 },
};
NamedTargetMetrics *selected_target_metrics;
TargetOsKind get_target_os_from_string(String str) {
for (isize i = 0; i < TargetOs_COUNT; i++) {
@@ -522,7 +549,7 @@ String get_fullpath_core(gbAllocator a, String path) {
void init_build_context(void) {
void init_build_context(TargetMetrics *cross_target) {
BuildContext *bc = &build_context;
gb_affinity_init(&bc->affinity);
@@ -540,7 +567,7 @@ void init_build_context(void) {
#if defined(GB_SYSTEM_WINDOWS)
metrics = target_windows_amd64;
#elif defined(GB_SYSTEM_OSX)
metrics = target_osx_amd64;
metrics = target_darwin_amd64;
#else
metrics = target_linux_amd64;
#endif
@@ -554,8 +581,9 @@ void init_build_context(void) {
#endif
#endif
if (cross_compile_target.len) {
bc->ODIN_OS = cross_compile_target;
if (cross_target) {
metrics = *cross_target;
bc->cross_compiling = true;
}
GB_ASSERT(metrics.os != TargetOs_Invalid);
@@ -573,6 +601,7 @@ void init_build_context(void) {
bc->max_align = metrics.max_align;
bc->link_flags = str_lit(" ");
bc->opt_flags = str_lit(" ");
bc->target_triplet = metrics.target_triplet;
gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64);
@@ -590,7 +619,7 @@ void init_build_context(void) {
case TargetOs_windows:
bc->link_flags = str_lit("/machine:x64 ");
break;
case TargetOs_osx:
case TargetOs_darwin:
break;
case TargetOs_linux:
bc->link_flags = str_lit("-arch x86-64 ");
@@ -603,7 +632,7 @@ void init_build_context(void) {
case TargetOs_windows:
bc->link_flags = str_lit("/machine:x86 ");
break;
case TargetOs_osx:
case TargetOs_darwin:
gb_printf_err("Unsupported architecture\n");
gb_exit(1);
break;
+217 -85
View File
@@ -41,11 +41,20 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
}
if (operand->mode == Addressing_Type) {
gbString t = type_to_string(operand->type);
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
gb_string_free(t);
e->type = operand->type;
return nullptr;
if (e->type != nullptr && is_type_typeid(e->type)) {
add_type_info_type(ctx, operand->type);
add_type_and_value(ctx->info, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
return e->type;
} else {
gbString t = type_to_string(operand->type);
defer (gb_string_free(t));
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
if (e->type == nullptr) {
error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a type\n", LIT(e->token.string));
}
e->type = operand->type;
return nullptr;
}
}
@@ -112,7 +121,8 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Ar
isize rhs_count = operands.count;
for_array(i, operands) {
if (operands[i].mode == Addressing_Invalid) {
rhs_count--;
// TODO(bill): Should I ignore invalid parameters?
// rhs_count--;
}
}
@@ -239,7 +249,7 @@ isize total_attribute_count(DeclInfo *decl) {
}
void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) {
void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) {
GB_ASSERT(e->type == nullptr);
DeclInfo *decl = decl_info_of_entity(e);
@@ -247,9 +257,8 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr);
}
bool is_distinct = is_type_distinct(type_expr);
Ast *te = remove_type_alias_clutter(type_expr);
bool is_distinct = is_type_distinct(init_expr);
Ast *te = remove_type_alias_clutter(init_expr);
e->type = t_invalid;
String name = e->token.string;
Type *named = alloc_type_named(name, nullptr, e);
@@ -265,7 +274,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
named->Named.base = base_type(bt);
if (is_distinct && is_type_typeid(e->type)) {
error(type_expr, "'distinct' cannot be applied to 'typeid'");
error(init_expr, "'distinct' cannot be applied to 'typeid'");
is_distinct = false;
}
if (!is_distinct) {
@@ -274,6 +283,19 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
e->TypeName.is_type_alias = true;
}
if (decl->type_expr != nullptr) {
Type *t = check_type(ctx, decl->type_expr);
if (t != nullptr && !is_type_typeid(t)) {
Operand operand = {};
operand.mode = Addressing_Type;
operand.type = e->type;
operand.expr = init_expr;
check_assignment(ctx, &operand, t, str_lit("constant declaration"));
}
}
// using decl
if (decl->is_using) {
// NOTE(bill): Must be an enum declaration
@@ -338,7 +360,7 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
if (type_expr) {
Type *t = check_type(ctx, type_expr);
if (!is_type_constant_type(t)) {
if (!is_type_constant_type(t) && !is_type_proc(t)) {
gbString str = type_to_string(t);
error(type_expr, "Invalid constant type '%s'", str);
gb_string_free(str);
@@ -362,15 +384,14 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
switch (operand.mode) {
case Addressing_Type: {
if (e->type != nullptr && !is_type_typeid(e->type)) {
check_assignment(ctx, &operand, e->type, str_lit("constant declaration"));
}
e->kind = Entity_TypeName;
e->type = nullptr;
DeclInfo *d = ctx->decl;
if (d->type_expr != nullptr) {
error(e->token, "A type declaration cannot have an type parameter");
}
d->type_expr = d->init_expr;
check_type_decl(ctx, e, d->type_expr, named_type);
check_type_decl(ctx, e, ctx->decl->init_expr, named_type);
return;
}
@@ -392,6 +413,25 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
}
if (entity != nullptr) {
if (e->type != nullptr) {
Operand x = {};
x.type = entity->type;
x.mode = Addressing_Variable;
if (!check_is_assignable_to(ctx, &x, e->type)) {
gbString expr_str = expr_to_string(init);
gbString op_type_str = type_to_string(entity->type);
gbString type_str = type_to_string(e->type);
error(e->token,
"Cannot assign '%s' of type '%s' to '%s'",
expr_str,
op_type_str,
type_str);
gb_string_free(type_str);
gb_string_free(op_type_str);
gb_string_free(expr_str);
}
}
// NOTE(bill): Override aliased entity
switch (entity->kind) {
@@ -583,11 +623,45 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
check_open_scope(ctx, pl->type);
defer (check_close_scope(ctx));
Type *decl_type = nullptr;
if (d->type_expr != nullptr) {
decl_type = check_type(ctx, d->type_expr);
if (!is_type_proc(decl_type)) {
gbString str = type_to_string(decl_type);
error(d->type_expr, "Expected a procedure type, got '%s'", str);
gb_string_free(str);
}
}
auto tmp_ctx = *ctx;
tmp_ctx.allow_polymorphic_types = true;
if (decl_type != nullptr) {
tmp_ctx.type_hint = decl_type;
}
check_procedure_type(&tmp_ctx, proc_type, pl->type);
if (decl_type != nullptr) {
Operand x = {};
x.type = e->type;
x.mode = Addressing_Variable;
if (!check_is_assignable_to(ctx, &x, decl_type)) {
gbString expr_str = expr_to_string(d->proc_lit);
gbString op_type_str = type_to_string(e->type);
gbString type_str = type_to_string(decl_type);
error(e->token,
"Cannot assign '%s' of type '%s' to '%s'",
expr_str,
op_type_str,
type_str);
gb_string_free(type_str);
gb_string_free(op_type_str);
gb_string_free(expr_str);
}
}
TypeProc *pt = &proc_type->Proc;
AttributeContext ac = make_attribute_context(e->Procedure.link_prefix);
@@ -601,7 +675,6 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
bool is_foreign = e->Procedure.is_foreign;
bool is_export = e->Procedure.is_export;
bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
if (e->pkg != nullptr && e->token.string == "main") {
if (pt->param_count != 0 ||
@@ -661,10 +734,10 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
}
}
if (pt->result_count == 0 && is_require_results) {
error(pl->type, "'#require_results' is not needed on a procedure with no results");
if (pt->result_count == 0 && ac.require_results) {
error(pl->type, "'require_results' is not needed on a procedure with no results");
} else {
pt->require_results = is_require_results;
pt->require_results = ac.require_results;
}
if (ac.link_name.len > 0) {
@@ -738,7 +811,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
}
}
void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) {
void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) {
GB_ASSERT(e->type == nullptr);
GB_ASSERT(e->kind == Entity_Variable);
@@ -752,6 +825,7 @@ void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_ex
ac.init_expr_list_count = init_expr != nullptr ? 1 : 0;
DeclInfo *decl = decl_info_of_entity(e);
GB_ASSERT(decl == ctx->decl);
if (decl != nullptr) {
check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
}
@@ -883,7 +957,6 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
ptr_set_destroy(&entity_set);
for_array(j, pge->entities) {
Entity *p = pge->entities[j];
if (p->type == t_invalid) {
@@ -909,27 +982,40 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
defer (end_error_block());
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
switch (kind) {
bool both_have_where_clauses = false;
if (p->decl_info->proc_lit != nullptr && q->decl_info->proc_lit != nullptr) {
GB_ASSERT(p->decl_info->proc_lit->kind == Ast_ProcLit);
GB_ASSERT(q->decl_info->proc_lit->kind == Ast_ProcLit);
auto pl = &p->decl_info->proc_lit->ProcLit;
auto ql = &q->decl_info->proc_lit->ProcLit;
// Allow collisions if the procedures both have 'where' clauses and are both polymorphic
bool pw = pl->where_token.kind != Token_Invalid && is_type_polymorphic(p->type, true);
bool qw = ql->where_token.kind != Token_Invalid && is_type_polymorphic(q->type, true);
both_have_where_clauses = pw && qw;
}
if (!both_have_where_clauses) switch (kind) {
case ProcOverload_Identical:
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
is_invalid = true;
break;
// case ProcOverload_CallingConvention:
// error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
// error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
// is_invalid = true;
// break;
case ProcOverload_ParamVariadic:
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
is_invalid = true;
break;
case ProcOverload_ResultCount:
case ProcOverload_ResultTypes:
error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in this scope", LIT(name));
error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
is_invalid = true;
break;
case ProcOverload_Polymorphic:
#if 0
error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in this scope which is not allowed", LIT(name));
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;
@@ -998,13 +1084,13 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_
switch (e->kind) {
case Entity_Variable:
check_var_decl(&c, e, d->type_expr, d->init_expr);
check_global_variable_decl(&c, e, d->type_expr, d->init_expr);
break;
case Entity_Constant:
check_const_decl(&c, e, d->type_expr, d->init_expr, named_type);
break;
case Entity_TypeName: {
check_type_decl(&c, e, d->type_expr, named_type);
check_type_decl(&c, e, d->init_expr, named_type);
break;
}
case Entity_Procedure:
@@ -1021,6 +1107,11 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_
}
struct ProcUsingVar {
Entity *e;
Entity *uvar;
};
void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) {
if (body == nullptr) {
@@ -1045,76 +1136,117 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
ctx->curr_proc_decl = decl;
ctx->curr_proc_sig = type;
GB_ASSERT(type->kind == Type_Proc);
if (type->Proc.param_count > 0) {
TypeTuple *params = &type->Proc.params->Tuple;
for_array(i, params->variables) {
Entity *e = params->variables[i];
if (e->kind != Entity_Variable) {
continue;
}
if (!(e->flags & EntityFlag_Using)) {
continue;
}
bool is_immutable = e->Variable.is_immutable;
bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type);
String name = e->token.string;
Type *t = base_type(type_deref(e->type));
if (t->kind == Type_Struct) {
Scope *scope = t->Struct.scope;
if (scope == nullptr) {
scope = scope_of_node(t->Struct.node);
}
GB_ASSERT(scope != nullptr);
for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
uvar->Variable.is_immutable = is_immutable;
if (is_value) uvar->flags |= EntityFlag_Value;
ast_node(bs, BlockStmt, body);
Array<ProcUsingVar> using_entities = {};
using_entities.allocator = heap_allocator();
defer (array_free(&using_entities));
{
GB_ASSERT(type->kind == Type_Proc);
if (type->Proc.param_count > 0) {
TypeTuple *params = &type->Proc.params->Tuple;
for_array(i, params->variables) {
Entity *e = params->variables[i];
if (e->kind != Entity_Variable) {
continue;
}
if (!(e->flags & EntityFlag_Using)) {
continue;
}
bool is_immutable = e->Variable.is_immutable;
bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type);
String name = e->token.string;
Type *t = base_type(type_deref(e->type));
if (t->kind == Type_Struct) {
Scope *scope = t->Struct.scope;
if (scope == nullptr) {
scope = scope_of_node(t->Struct.node);
}
GB_ASSERT(scope != nullptr);
for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
uvar->Variable.is_immutable = is_immutable;
if (is_value) uvar->flags |= EntityFlag_Value;
ProcUsingVar puv = {e, uvar};
array_add(&using_entities, puv);
Entity *prev = scope_insert(ctx->scope, uvar);
if (prev != nullptr) {
error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
break;
}
}
} else {
error(e->token, "'using' can only be applied to variables of type struct");
break;
}
} else {
error(e->token, "'using' can only be applied to variables of type struct");
break;
}
}
}
ast_node(bs, BlockStmt, body);
// check_open_scope(ctx, body);
check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
if (type->Proc.result_count > 0) {
if (!check_is_terminating(body)) {
if (token.kind == Token_Ident) {
error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string));
} else {
// NOTE(bill): Anonymous procedure (lambda)
error(bs->close, "Missing return statement at the end of the procedure");
for_array(i, using_entities) {
Entity *e = using_entities[i].e;
Entity *uvar = using_entities[i].uvar;
Entity *prev = scope_insert(ctx->scope, uvar);
if (prev != nullptr) {
error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string));
break;
}
}
bool where_clause_ok = evaluate_where_clauses(ctx, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true);
if (!where_clause_ok) {
// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
return;
}
check_open_scope(ctx, body);
{
for_array(i, using_entities) {
Entity *e = using_entities[i].e;
Entity *uvar = using_entities[i].uvar;
Entity *prev = scope_insert(ctx->scope, uvar);
// NOTE(bill): Don't err here
}
check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
if (type->Proc.result_count > 0) {
if (!check_is_terminating(body)) {
if (token.kind == Token_Ident) {
error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string));
} else {
// NOTE(bill): Anonymous procedure (lambda)
error(bs->close, "Missing return statement at the end of the procedure");
}
}
}
}
// check_close_scope(ctx);
check_close_scope(ctx);
check_scope_usage(ctx->checker, ctx->scope);
#if 1
if (decl->parent != nullptr) {
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
for_array(i, decl->deps.entries) {
Entity *e = decl->deps.entries[i].ptr;
ptr_set_add(&decl->parent->deps, e);
}
for_array(i, decl->type_info_deps.entries) {
Type *t = decl->type_info_deps.entries[i].ptr;
ptr_set_add(&decl->parent->type_info_deps, t);
Scope *ps = decl->parent->scope;
if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) {
return;
} else {
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
// But only at the procedure level
for_array(i, decl->deps.entries) {
Entity *e = decl->deps.entries[i].ptr;
ptr_set_add(&decl->parent->deps, e);
}
for_array(i, decl->type_info_deps.entries) {
Type *t = decl->type_info_deps.entries[i].ptr;
ptr_set_add(&decl->parent->type_info_deps, t);
}
}
}
#endif
}
+1452 -220
View File
File diff suppressed because it is too large Load Diff
+269 -136
View File
@@ -132,6 +132,10 @@ bool check_is_terminating(Ast *node) {
}
case_end;
case_ast_node(rs, InlineRangeStmt, node);
return false;
case_end;
case_ast_node(rs, RangeStmt, node);
return false;
case_end;
@@ -172,6 +176,9 @@ bool check_is_terminating(Ast *node) {
return false;
}
Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) {
if (rhs->mode == Addressing_Invalid) {
return nullptr;
@@ -249,48 +256,19 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
case Addressing_Invalid:
return nullptr;
case Addressing_Variable: {
case Addressing_Variable:
if (is_type_bit_field_value(lhs->type)) {
Type *lt = base_type(lhs->type);
i64 lhs_bits = lt->BitFieldValue.bits;
if (rhs->mode == Addressing_Constant) {
ExactValue v = exact_value_to_integer(rhs->value);
if (v.kind == ExactValue_Integer) {
BigInt i = v.value_integer;
if (!i.neg) {
u64 imax_ = ~cast(u64)0ull;
if (lhs_bits < 64) {
imax_ = (1ull << cast(u64)lhs_bits) - 1ull;
}
BigInt imax = big_int_make_u64(imax_);
if (big_int_cmp(&i, &imax) <= 0) {
return rhs->type;
}
}
} else if (rhs->value.kind == ExactValue_Bool) {
bool b = rhs->value.value_bool;
if (lhs_bits == 1) {
return rhs->type;
}
}
} else if (is_type_integer(rhs->type)) {
// TODO(bill): Any other checks?
return rhs->type;
} else if (is_type_boolean(rhs->type)) {
if (lhs_bits == 1) {
return rhs->type;
}
Type *res = check_assignment_bit_field(ctx, rhs, lhs->type);
if (res == nullptr) {
gbString lhs_expr = expr_to_string(lhs->expr);
gbString rhs_expr = expr_to_string(rhs->expr);
error(rhs->expr, "Cannot assign '%s' to bit field '%s'", rhs_expr, lhs_expr);
gb_string_free(rhs_expr);
gb_string_free(lhs_expr);
}
gbString lhs_expr = expr_to_string(lhs->expr);
gbString rhs_expr = expr_to_string(rhs->expr);
error(rhs->expr, "Cannot assign '%s' to bit field '%s'", rhs_expr, lhs_expr);
gb_string_free(rhs_expr);
gb_string_free(lhs_expr);
return nullptr;
return res;
}
break;
}
case Addressing_MapIndex: {
Ast *ln = unparen_expr(lhs->expr);
@@ -315,6 +293,9 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
break;
}
case Addressing_SoaVariable:
break;
default: {
if (lhs->expr->kind == Ast_SelectorExpr) {
// NOTE(bill): Extra error checks
@@ -329,9 +310,13 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
}
}
Entity *e = entity_of_ident(lhs->expr);
gbString str = expr_to_string(lhs->expr);
if (lhs->mode == Addressing_Immutable) {
error(lhs->expr, "Cannot assign to an immutable: '%s'", str);
} else if (e != nullptr && e->flags & EntityFlag_Param) {
error(lhs->expr, "Cannot assign to '%s' which is a procedure parameter", str);
} else {
error(lhs->expr, "Cannot assign to '%s'", str);
}
@@ -514,8 +499,7 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b
for_array(i, found->elements.entries) {
Entity *f = found->elements.entries[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
uvar->using_expr = expr;
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, expr);
Entity *prev = scope_insert(ctx->scope, uvar);
if (prev != nullptr) {
gbString expr_str = expr_to_string(expr);
@@ -609,6 +593,162 @@ void add_constant_switch_case(CheckerContext *ctx, Map<TypeAndToken> *seen, Oper
multi_map_insert(seen, key, tap);
}
void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
ast_node(irs, InlineRangeStmt, node);
check_open_scope(ctx, node);
Type *val0 = nullptr;
Type *val1 = nullptr;
Entity *entities[2] = {};
isize entity_count = 0;
Ast *expr = unparen_expr(irs->expr);
ExactValue inline_for_depth = exact_value_i64(0);
if (is_ast_range(expr)) {
ast_node(ie, BinaryExpr, expr);
Operand x = {};
Operand y = {};
bool ok = check_range(ctx, expr, &x, &y, &inline_for_depth);
if (!ok) {
goto skip_expr;
}
val0 = x.type;
val1 = t_int;
} else {
Operand operand = {Addressing_Invalid};
check_expr_or_type(ctx, &operand, irs->expr);
if (operand.mode == Addressing_Type) {
if (!is_type_enum(operand.type)) {
gbString t = type_to_string(operand.type);
error(operand.expr, "Cannot iterate over the type '%s'", t);
gb_string_free(t);
goto skip_expr;
} else {
val0 = operand.type;
val1 = t_int;
add_type_info_type(ctx, operand.type);
Type *bt = base_type(operand.type);
inline_for_depth = exact_value_i64(bt->Enum.fields.count);
goto skip_expr;
}
} else if (operand.mode != Addressing_Invalid) {
Type *t = base_type(operand.type);
switch (t->kind) {
case Type_Basic:
if (is_type_string(t) && t->Basic.kind != Basic_cstring) {
val0 = t_rune;
val1 = t_int;
inline_for_depth = exact_value_i64(operand.value.value_string.len);
}
break;
case Type_Array:
val0 = t->Array.elem;
val1 = t_int;
inline_for_depth = exact_value_i64(t->Array.count);
break;
}
}
if (val0 == nullptr) {
gbString s = expr_to_string(operand.expr);
gbString t = type_to_string(operand.type);
error(operand.expr, "Cannot iterate over '%s' of type '%s' in an 'inline for' statement", s, t);
gb_string_free(t);
gb_string_free(s);
} else if (operand.mode != Addressing_Constant) {
error(operand.expr, "An 'inline for' expression must be known at compile time");
}
}
skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird.
Ast * lhs[2] = {irs->val0, irs->val1};
Type *rhs[2] = {val0, val1};
for (isize i = 0; i < 2; i++) {
if (lhs[i] == nullptr) {
continue;
}
Ast * name = lhs[i];
Type *type = rhs[i];
Entity *entity = nullptr;
if (name->kind == Ast_Ident) {
Token token = name->Ident.token;
String str = token.string;
Entity *found = nullptr;
if (!is_blank_ident(str)) {
found = scope_lookup_current(ctx->scope, str);
}
if (found == nullptr) {
bool is_immutable = true;
entity = alloc_entity_variable(ctx->scope, token, type, is_immutable, EntityState_Resolved);
entity->flags |= EntityFlag_Value;
add_entity_definition(&ctx->checker->info, name, entity);
} else {
TokenPos pos = found->token.pos;
error(token,
"Redeclaration of '%.*s' in this scope\n"
"\tat %.*s(%td:%td)",
LIT(str), LIT(pos.file), pos.line, pos.column);
entity = found;
}
} else {
error(name, "A variable declaration must be an identifier");
}
if (entity == nullptr) {
entity = alloc_entity_dummy_variable(builtin_pkg->scope, ast_token(name));
}
entities[entity_count++] = entity;
if (type == nullptr) {
entity->type = t_invalid;
entity->flags |= EntityFlag_Used;
}
}
for (isize i = 0; i < entity_count; i++) {
add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]);
}
// NOTE(bill): Minimize the amount of nesting of an 'inline for'
i64 prev_inline_for_depth = ctx->inline_for_depth;
defer (ctx->inline_for_depth = prev_inline_for_depth);
{
i64 v = exact_value_to_i64(inline_for_depth);
if (v <= 0) {
// Do nothing
} else {
ctx->inline_for_depth = gb_max(ctx->inline_for_depth, 1) * v;
}
if (ctx->inline_for_depth >= MAX_INLINE_FOR_DEPTH && prev_inline_for_depth < MAX_INLINE_FOR_DEPTH) {
if (prev_inline_for_depth > 0) {
error(node, "Nested 'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH);
} else {
error(node, "'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH);
}
error_line("\tUse a normal 'for' loop instead by removing the 'inline' prefix\n");
ctx->inline_for_depth = MAX_INLINE_FOR_DEPTH;
}
}
check_stmt(ctx, irs->body, mod_flags);
check_close_scope(ctx);
}
void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
ast_node(ss, SwitchStmt, node);
@@ -746,6 +886,13 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
if (upper_op == Token_GtEq) {
add_constant_switch_case(ctx, &seen, rhs);
}
if (is_type_string(x.type)) {
// NOTE(bill): Force dependency for strings here
add_package_dependency(ctx, "runtime", "string_le");
add_package_dependency(ctx, "runtime", "string_lt");
}
} else {
Operand y = {};
if (is_type_typeid(x.type)) {
@@ -986,7 +1133,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
GB_PANIC("Unknown type to type switch statement");
}
if (ptr_set_exists(&seen, y.type)) {
if (type_ptr_set_exists(&seen, y.type)) {
TokenPos pos = cc->token.pos;
gbString expr_str = expr_to_string(y.expr);
error(y.expr,
@@ -1038,7 +1185,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
for_array(i, variants) {
Type *t = variants[i];
if (!ptr_set_exists(&seen, t)) {
if (!type_ptr_set_exists(&seen, t)) {
array_add(&unhandled, t);
}
}
@@ -1147,7 +1294,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
isize rhs_count = rhs_operands.count;
for_array(i, rhs_operands) {
if (rhs_operands[i].mode == Addressing_Invalid) {
rhs_count--;
// TODO(bill): Should I ignore invalid parameters?
// rhs_count--;
}
}
@@ -1183,7 +1331,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
be->right = as->rhs[0];
check_expr(ctx, &lhs, as->lhs[0]);
check_binary_expr(ctx, &rhs, &binary_expr, true);
check_binary_expr(ctx, &rhs, &binary_expr, nullptr, true);
if (rhs.mode == Addressing_Invalid) {
return;
}
@@ -1313,6 +1461,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
check_close_scope(ctx);
case_end;
case_ast_node(rs, RangeStmt, node);
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
@@ -1330,104 +1479,31 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
if (is_ast_range(expr)) {
ast_node(ie, BinaryExpr, expr);
Operand x = {Addressing_Invalid};
Operand y = {Addressing_Invalid};
Operand x = {};
Operand y = {};
check_expr(ctx, &x, ie->left);
if (x.mode == Addressing_Invalid) {
goto skip_expr;
bool ok = check_range(ctx, expr, &x, &y, nullptr);
if (!ok) {
goto skip_expr_range_stmt;
}
check_expr(ctx, &y, ie->right);
if (y.mode == Addressing_Invalid) {
goto skip_expr;
}
convert_to_typed(ctx, &x, y.type);
if (x.mode == Addressing_Invalid) {
goto skip_expr;
}
convert_to_typed(ctx, &y, x.type);
if (y.mode == Addressing_Invalid) {
goto skip_expr;
}
convert_to_typed(ctx, &x, default_type(y.type));
if (x.mode == Addressing_Invalid) {
goto skip_expr;
}
convert_to_typed(ctx, &y, default_type(x.type));
if (y.mode == Addressing_Invalid) {
goto skip_expr;
}
if (!are_types_identical(x.type, y.type)) {
if (x.type != t_invalid &&
y.type != t_invalid) {
gbString xt = type_to_string(x.type);
gbString yt = type_to_string(y.type);
gbString expr_str = expr_to_string(x.expr);
error(ie->op, "Mismatched types in interval expression '%s' : '%s' vs '%s'", expr_str, xt, yt);
gb_string_free(expr_str);
gb_string_free(yt);
gb_string_free(xt);
}
goto skip_expr;
}
Type *type = x.type;
if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) {
error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
goto skip_expr;
}
if (x.mode == Addressing_Constant &&
y.mode == Addressing_Constant) {
ExactValue a = x.value;
ExactValue b = y.value;
GB_ASSERT(are_types_identical(x.type, y.type));
TokenKind op = Token_Lt;
switch (ie->op.kind) {
case Token_Ellipsis: op = Token_LtEq; break;
case Token_RangeHalf: op = Token_Lt; break;
default: error(ie->op, "Invalid range operator"); break;
}
bool ok = compare_exact_values(op, a, b);
if (!ok) {
// TODO(bill): Better error message
error(ie->op, "Invalid interval range");
goto skip_expr;
}
}
if (x.mode != Addressing_Constant) {
x.value = empty_exact_value;
}
if (y.mode != Addressing_Constant) {
y.value = empty_exact_value;
}
add_type_and_value(&ctx->checker->info, ie->left, x.mode, x.type, x.value);
add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value);
val0 = type;
val0 = x.type;
val1 = t_int;
} else {
Operand operand = {Addressing_Invalid};
check_expr_or_type(ctx, &operand, rs->expr);
check_expr_base(ctx, &operand, expr, nullptr);
error_operand_no_value(&operand);
if (operand.mode == Addressing_Type) {
if (!is_type_enum(operand.type)) {
gbString t = type_to_string(operand.type);
error(operand.expr, "Cannot iterate over the type '%s'", t);
gb_string_free(t);
goto skip_expr;
goto skip_expr_range_stmt;
} else {
val0 = operand.type;
val1 = t_int;
add_type_info_type(ctx, operand.type);
goto skip_expr;
goto skip_expr_range_stmt;
}
} else if (operand.mode != Addressing_Invalid) {
bool is_ptr = is_type_pointer(operand.type);
@@ -1460,6 +1536,45 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
val0 = t->Map.key;
val1 = t->Map.value;
break;
case Type_Tuple:
if (false) {
check_not_tuple(ctx, &operand);
} else {
isize count = t->Tuple.variables.count;
if (count < 1 || count > 3) {
check_not_tuple(ctx, &operand);
error_line("\tMultiple return valued parameters in a range statement are limited to a maximum of 2 usable values with a trailing boolean for the conditional\n");
break;
}
Type *cond_type = t->Tuple.variables[count-1]->type;
if (!is_type_boolean(cond_type)) {
gbString s = type_to_string(cond_type);
error(operand.expr, "The final type of %td-valued tuple must be a boolean, got %s", count, s);
gb_string_free(s);
break;
}
if (count > 1) val0 = t->Tuple.variables[0]->type;
if (count > 2) val1 = t->Tuple.variables[1]->type;
if (rs->val1 != nullptr && count < 3) {
gbString s = type_to_string(t);
error(operand.expr, "Expected a 3-value tuple on the rhs, got (%s)", s);
gb_string_free(s);
break;
}
if (rs->val0 != nullptr && count < 2) {
gbString s = type_to_string(t);
error(operand.expr, "Expected at least a 2-values tuple on the rhs, got (%s)", s);
gb_string_free(s);
break;
}
}
break;
}
}
@@ -1472,7 +1587,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
}
}
skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird.
skip_expr_range_stmt:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird.
Ast * lhs[2] = {rs->val0, rs->val1};
Type *rhs[2] = {val0, val1};
@@ -1522,7 +1638,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
}
for (isize i = 0; i < entity_count; i++) {
add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]);
Entity *e = entities[i];
DeclInfo *d = decl_info_of_entity(e);
GB_ASSERT(d == nullptr);
add_entity(ctx->checker, ctx->scope, e->identifier, e);
d = make_decl_info(ctx->allocator, ctx->scope, ctx->decl);
add_entity_and_decl_info(ctx, e->identifier, e, d);
}
check_stmt(ctx, rs->body, new_flags);
@@ -1530,6 +1651,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
check_close_scope(ctx);
case_end;
case_ast_node(irs, InlineRangeStmt, node);
check_inline_range_stmt(ctx, node, mod_flags);
case_end;
case_ast_node(ss, SwitchStmt, node);
check_switch_stmt(ctx, node, mod_flags);
case_end;
@@ -1729,11 +1854,6 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
error(vd->type, "Invalid use of a polymorphic type '%s' in variable declaration", str);
gb_string_free(str);
init_type = t_invalid;
} else if (is_type_empty_union(init_type)) {
gbString str = type_to_string(init_type);
error(vd->type, "An empty union '%s' cannot be instantiated in variable declaration", str);
gb_string_free(str);
init_type = t_invalid;
}
}
@@ -1772,6 +1892,19 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
e->flags |= EntityFlag_Static;
}
}
if (ac.thread_local_model != "") {
String name = e->token.string;
if (name == "_") {
error(e->token, "The 'thread_local' attribute is not allowed to be applied to '_'");
} else {
e->flags |= EntityFlag_Static;
}
e->Variable.thread_local_model = ac.thread_local_model;
}
if (ac.is_static && ac.thread_local_model != "") {
error(e->token, "The 'static' attribute is not needed if 'thread_local' is applied");
}
}
check_arity_match(ctx, vd);
@@ -1834,7 +1967,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
// TODO(bill): Should a 'continue' happen here?
}
for (isize entity_index = 0; entity_index < entity_count; entity_index++) {
for (isize entity_index = 0; entity_index < 1; entity_index++) {
Entity *e = entities[entity_index];
if (e == nullptr) {
continue;
@@ -1853,7 +1986,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
uvar->Variable.is_immutable = is_immutable;
Entity *prev = scope_insert(ctx->scope, uvar);
if (prev != nullptr) {
+390 -53
View File
@@ -110,9 +110,10 @@ bool does_field_type_allow_using(Type *t) {
return false;
}
void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<Ast *> const &params,
void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<String> *tags, Array<Ast *> const &params,
isize init_field_capacity, Type *struct_type, String context) {
*fields = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
*tags = array_make<String>(heap_allocator(), 0, init_field_capacity);
GB_ASSERT(node->kind == Ast_StructType);
GB_ASSERT(struct_type->kind == Type_Struct);
@@ -171,6 +172,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields
Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
add_entity(ctx->checker, ctx->scope, name, field);
array_add(fields, field);
array_add(tags, p->tag.string);
field_src_index += 1;
}
@@ -246,38 +248,51 @@ bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
}
Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array<Operand> ordered_operands) {
Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array<Operand> const &ordered_operands, bool *failure) {
auto *found_gen_types = map_get(&ctx->checker->info.gen_types, hash_pointer(original_type));
if (found_gen_types != nullptr) {
for_array(i, *found_gen_types) {
Entity *e = (*found_gen_types)[i];
Type *t = base_type(e->type);
TypeTuple *tuple = get_record_polymorphic_params(t);
bool ok = true;
GB_ASSERT(param_count == tuple->variables.count);
bool skip = false;
for (isize j = 0; j < param_count; j++) {
Entity *p = tuple->variables[j];
Operand o = ordered_operands[j];
Entity *oe = entity_of_node(o.expr);
if (p == oe) {
// NOTE(bill): This is the same type, make sure that it will be be same thing and use that
// Saves on a lot of checking too below
continue;
}
if (p->kind == Entity_TypeName) {
if (is_type_polymorphic(o.type)) {
// NOTE(bill): Do not add polymorphic version to the gen_types
ok = false;
skip = true;
break;
}
if (!are_types_identical(o.type, p->type)) {
ok = false;
skip = true;
break;
}
} else if (p->kind == Entity_Constant) {
if (!are_types_identical(o.type, p->type)) {
ok = false;
}
if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) {
ok = false;
skip = true;
break;
}
if (!are_types_identical(o.type, p->type)) {
skip = true;
break;
}
} else {
GB_PANIC("Unknown entity kind");
}
}
if (ok) {
if (!skip) {
return e;
}
}
@@ -439,8 +454,6 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
if (poly_operands != nullptr) {
Operand operand = (*poly_operands)[entities.count];
if (is_type_param) {
GB_ASSERT(operand.mode == Addressing_Type ||
operand.mode == Addressing_Invalid);
if (is_type_polymorphic(base_type(operand.type))) {
is_polymorphic = true;
can_check_fields = false;
@@ -448,6 +461,10 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
e = alloc_entity_type_name(scope, token, operand.type);
e->TypeName.is_type_alias = true;
} else {
if (is_type_polymorphic(base_type(operand.type))) {
is_polymorphic = true;
can_check_fields = false;
}
e = alloc_entity_constant(scope, token, operand.type, operand.value);
}
} else {
@@ -502,9 +519,13 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
struct_type->Struct.polymorphic_params = polymorphic_params;
struct_type->Struct.is_poly_specialized = is_poly_specialized;
if (!is_polymorphic) {
check_struct_fields(ctx, node, &struct_type->Struct.fields, st->fields, min_field_count, struct_type, context);
if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) {
error(st->where_clauses[0], "'where' clauses can only be used on structures with polymorphic parameters");
} else {
bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &st->where_clauses, true);
}
check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context);
}
if (st->align != nullptr) {
@@ -686,6 +707,13 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
union_type->Union.is_polymorphic = is_polymorphic;
union_type->Union.is_poly_specialized = is_poly_specialized;
if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
error(ut->where_clauses[0], "'where' clauses can only be used on unions with polymorphic parameters");
} else {
bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &ut->where_clauses, true);
}
for_array(i, ut->variants) {
Ast *node = ut->variants[i];
Type *t = check_type_expr(ctx, node, nullptr);
@@ -715,6 +743,12 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
}
union_type->Union.variants = variants;
union_type->Union.no_nil = ut->no_nil;
if (union_type->Union.no_nil) {
if (variants.count < 2) {
error(ut->align, "A union with #no_nil must have at least 2 variants");
}
}
if (ut->align != nullptr) {
i64 custom_align = 1;
@@ -1246,20 +1280,21 @@ bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Typ
Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand operand) {
bool modify_type = !ctx->no_polymorphic_errors;
bool show_error = modify_type && !ctx->hide_polymorphic_errors;
if (!is_operand_value(operand)) {
if (modify_type) {
if (show_error) {
error(operand.expr, "Cannot determine polymorphic type from parameter");
}
return t_invalid;
}
if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) {
if (modify_type) {
set_procedure_abi_types(ctx, poly_type);
if (show_error) {
set_procedure_abi_types(ctx->allocator, poly_type);
}
return poly_type;
}
if (modify_type) {
if (show_error) {
gbString pts = type_to_string(poly_type);
gbString ots = type_to_string(operand.type);
defer (gb_string_free(pts));
@@ -1513,18 +1548,6 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
}
}
if (p->flags&FieldFlag_in) {
if (is_type_param) {
error(param, "'in' cannot be applied to a type parameter");
p->flags &= ~FieldFlag_in;
} else if (is_variadic) {
error(param, "'in' cannot be applied to a variadic parameter");
p->flags &= ~FieldFlag_in;
}
}
bool is_in = (p->flags&FieldFlag_in) != 0;
for_array(j, p->names) {
Ast *name = p->names[j];
@@ -1544,7 +1567,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
}
if (is_poly_name) {
if (type != nullptr && type_expr->kind == Ast_TypeidType) {
if (type_expr != nullptr && type_expr->kind == Ast_TypeidType) {
is_type_param = true;
} else {
if (param_value.kind != ParameterValue_Invalid) {
@@ -1628,6 +1651,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
if (op.mode == Addressing_Constant) {
poly_const = op.value;
} else {
error(op.expr, "Expected a constant value for this polymorphic name parameter");
success = false;
}
}
@@ -1664,7 +1688,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
param = alloc_entity_const_param(scope, name->Ident.token, type, poly_const, is_type_polymorphic(type));
} else {
param = alloc_entity_param(scope, name->Ident.token, type, is_using, is_in);
param = alloc_entity_param(scope, name->Ident.token, type, is_using, true);
param->Variable.param_value = param_value;
}
}
@@ -1831,6 +1855,282 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
return tuple;
}
Array<Type *> systemv_distribute_struct_fields(Type *t) {
Type *bt = core_type(t);
isize distributed_cap = 1;
if (bt->kind == Type_Struct) {
distributed_cap = bt->Struct.fields.count;
}
auto distributed = array_make<Type *>(heap_allocator(), 0, distributed_cap);
i64 sz = type_size_of(bt);
switch (bt->kind) {
case Type_Basic:
switch (bt->Basic.kind){
case Basic_complex64:
array_add(&distributed, t_f32);
array_add(&distributed, t_f32);
break;
case Basic_complex128:
array_add(&distributed, t_f64);
array_add(&distributed, t_f64);
break;
case Basic_quaternion128:
array_add(&distributed, t_f32);
array_add(&distributed, t_f32);
array_add(&distributed, t_f32);
array_add(&distributed, t_f32);
break;
case Basic_quaternion256:
goto DEFAULT;
case Basic_string:
array_add(&distributed, t_u8_ptr);
array_add(&distributed, t_int);
break;
case Basic_any:
GB_ASSERT(type_size_of(t_uintptr) == type_size_of(t_typeid));
array_add(&distributed, t_rawptr);
array_add(&distributed, t_uintptr);
break;
case Basic_u128:
case Basic_i128:
if (build_context.ODIN_OS == "windows") {
array_add(&distributed, alloc_type_simd_vector(2, t_u64));
} else {
array_add(&distributed, bt);
}
break;
default:
goto DEFAULT;
}
break;
case Type_Struct:
if (bt->Struct.is_raw_union) {
goto DEFAULT;
} else {
// IMPORTANT TOOD(bill): handle #packed structs correctly
// IMPORTANT TODO(bill): handle #align structs correctly
for_array(field_index, bt->Struct.fields) {
Entity *f = bt->Struct.fields[field_index];
auto nested = systemv_distribute_struct_fields(f->type);
array_add_elems(&distributed, nested.data, nested.count);
array_free(&nested);
}
}
break;
case Type_Array:
for (i64 i = 0; i < bt->Array.count; i++) {
array_add(&distributed, bt->Array.elem);
}
break;
case Type_BitSet:
array_add(&distributed, bit_set_to_int(bt));
break;
case Type_Tuple:
GB_PANIC("Invalid struct field type");
break;
case Type_Slice:
array_add(&distributed, t_rawptr);
array_add(&distributed, t_int);
break;
case Type_Union:
case Type_DynamicArray:
case Type_Map:
case Type_BitField: // TODO(bill): Ignore?
// NOTE(bill, 2019-10-10): Odin specific, don't worry about C calling convention yet
goto DEFAULT;
case Type_Pointer:
case Type_Proc:
case Type_SimdVector: // TODO(bill): Is this correct logic?
default:
DEFAULT:;
if (sz > 0) {
array_add(&distributed, bt);
}
break;
}
return distributed;
}
Type *struct_type_from_systemv_distribute_struct_fields(Type *abi_type) {
GB_ASSERT(is_type_tuple(abi_type));
Type *final_type = alloc_type_struct();
final_type->Struct.fields = abi_type->Tuple.variables;
return final_type;
}
Type *handle_single_distributed_type_parameter(Array<Type *> const &types, bool packed, isize *offset) {
GB_ASSERT(types.count > 0);
if (types.count == 1) {
if (offset) *offset = 1;
i64 sz = type_size_of(types[0]);
if (is_type_float(types[0])) {
return types[0];
}
switch (sz) {
case 0:
GB_PANIC("Zero sized type found!");
case 1: return t_u8;
case 2: return t_u16;
case 4: return t_u32;
case 8: return t_u64;
default:
return types[0];
}
} else if (types.count >= 2) {
if (types[0] == t_f32 && types[1] == t_f32) {
if (offset) *offset = 2;
return alloc_type_simd_vector(2, t_f32);
} else if (type_size_of(types[0]) == 8) {
if (offset) *offset = 1;
return types[0];
}
i64 total_size = 0;
isize i = 0;
if (packed) {
for (; i < types.count && total_size < 8; i += 1) {
Type *t = types[i];
i64 s = type_size_of(t);
total_size += s;
}
} else {
for (; i < types.count && total_size < 8; i += 1) {
Type *t = types[i];
i64 s = gb_max(type_size_of(t), 0);
i64 a = gb_max(type_align_of(t), 1);
isize ts = align_formula(total_size, a);
if (ts >= 8) {
break;
}
total_size = ts + s;
}
}
if (offset) *offset = i;
switch (total_size) {
case 1: return t_u8;
case 2: return t_u16;
case 4: return t_u32;
case 8: return t_u64;
}
return t_u64;
}
return nullptr;
}
Type *handle_struct_system_v_amd64_abi_type(Type *t) {
if (type_size_of(t) > 16) {
return alloc_type_pointer(t);
}
Type *original_type = t;
Type *bt = core_type(t);
t = base_type(t);
i64 size = type_size_of(bt);
switch (t->kind) {
case Type_Slice:
case Type_Struct:
break;
case Type_Basic:
switch (bt->Basic.kind) {
case Basic_string:
case Basic_any:
case Basic_complex64:
case Basic_complex128:
case Basic_quaternion128:
break;
default:
return original_type;
}
break;
default:
return original_type;
}
bool is_packed = false;
if (is_type_struct(bt)) {
is_packed = bt->Struct.is_packed;
}
if (is_type_raw_union(bt)) {
// TODO(bill): Handle raw union correctly for
return t;
} else {
auto field_types = systemv_distribute_struct_fields(bt);
defer (array_free(&field_types));
GB_ASSERT(field_types.count <= 16);
Type *final_type = nullptr;
if (field_types.count == 0) {
final_type = t;
} else if (field_types.count == 1) {
final_type = field_types[0];
} else {
if (size <= 8) {
isize offset = 0;
final_type = handle_single_distributed_type_parameter(field_types, is_packed, &offset);
} else {
isize offset = 0;
isize next_offset = 0;
Type *two_types[2] = {};
two_types[0] = handle_single_distributed_type_parameter(field_types, is_packed, &offset);
auto remaining = array_slice(field_types, offset, field_types.count);
two_types[1] = handle_single_distributed_type_parameter(remaining, is_packed, &next_offset);
GB_ASSERT(offset + next_offset == field_types.count);
auto variables = array_make<Entity *>(heap_allocator(), 2);
variables[0] = alloc_entity_param(nullptr, empty_token, two_types[0], false, false);
variables[1] = alloc_entity_param(nullptr, empty_token, two_types[1], false, false);
final_type = alloc_type_tuple();
final_type->Tuple.variables = variables;
if (t->kind == Type_Struct) {
// NOTE(bill): Make this packed
final_type->Tuple.is_packed = t->Struct.is_packed;
}
}
}
GB_ASSERT(final_type != nullptr);
i64 ftsz = type_size_of(final_type);
i64 otsz = type_size_of(original_type);
if (ftsz != otsz) {
// TODO(bill): Handle this case which will be caused by #packed most likely
switch (otsz) {
case 1:
case 2:
case 4:
case 8:
GB_PANIC("Incorrectly handled case for handle_struct_system_v_amd64_abi_type, %s %lld vs %s %lld", type_to_string(final_type), ftsz, type_to_string(original_type), otsz);
}
}
return final_type;
}
}
Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc) {
Type *new_type = original_type;
@@ -1895,6 +2195,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
{
i64 align = type_align_of(original_type);
i64 size = type_size_of(original_type);
switch (8*size) {
case 8: new_type = t_u8; break;
case 16: new_type = t_u16; break;
@@ -1909,7 +2210,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
}
}
} else if (build_context.ODIN_OS == "linux" ||
build_context.ODIN_OS == "osx") {
build_context.ODIN_OS == "darwin") {
Type *bt = core_type(original_type);
switch (bt->kind) {
// Okay to pass by value (usually)
@@ -1926,18 +2227,17 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
case Type_Pointer: break;
case Type_Proc: break; // NOTE(bill): Just a pointer
// Odin specific
case Type_Slice:
case Type_Array:
case Type_DynamicArray:
case Type_Map:
case Type_Union:
// Could be in C too
case Type_Struct: {
i64 align = type_align_of(original_type);
i64 size = type_size_of(original_type);
if (8*size > 16) {
default: {
i64 size = type_size_of(original_type);
if (size > 16) {
new_type = alloc_type_pointer(original_type);
} else if (build_context.ODIN_ARCH == "amd64") {
// NOTE(bill): System V AMD64 ABI
new_type = handle_struct_system_v_amd64_abi_type(bt);
if (are_types_identical(core_type(original_type), new_type)) {
new_type = original_type;
}
return new_type;
}
break;
@@ -2010,8 +2310,10 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal
break;
}
}
} else if (build_context.ODIN_OS == "linux") {
} else if (build_context.ODIN_OS == "linux" || build_context.ODIN_OS == "darwin") {
if (build_context.ODIN_ARCH == "amd64") {
}
} else {
// IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for
// their architectures
@@ -2077,25 +2379,52 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type
return false;
}
void set_procedure_abi_types(CheckerContext *c, Type *type) {
void set_procedure_abi_types(gbAllocator allocator, Type *type) {
type = base_type(type);
if (type->kind != Type_Proc) {
return;
}
type->Proc.abi_compat_params = array_make<Type *>(c->allocator, cast(isize)type->Proc.param_count);
if (type->Proc.abi_types_set) {
return;
}
type->Proc.abi_compat_params = array_make<Type *>(allocator, cast(isize)type->Proc.param_count);
for (i32 i = 0; i < type->Proc.param_count; i++) {
Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind == Entity_Variable) {
Type *original_type = e->type;
Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type, type->Proc.calling_convention);
Type *new_type = type_to_abi_compat_param_type(allocator, original_type, type->Proc.calling_convention);
type->Proc.abi_compat_params[i] = new_type;
switch (type->Proc.calling_convention) {
case ProcCC_Odin:
case ProcCC_Contextless:
if (is_type_pointer(new_type) & !is_type_pointer(e->type)) {
e->flags |= EntityFlag_ImplicitReference;
}
break;
}
}
}
for (i32 i = 0; i < type->Proc.param_count; i++) {
Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind == Entity_Variable) {
set_procedure_abi_types(allocator, e->type);
}
}
for (i32 i = 0; i < type->Proc.result_count; i++) {
Entity *e = type->Proc.results->Tuple.variables[i];
if (e->kind == Entity_Variable) {
set_procedure_abi_types(allocator, e->type);
}
}
// NOTE(bill): The types are the same
type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results, type->Proc.calling_convention);
type->Proc.return_by_pointer = abi_compat_return_by_pointer(c->allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type);
type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(allocator, type->Proc.results, type->Proc.calling_convention);
type->Proc.return_by_pointer = abi_compat_return_by_pointer(allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type);
type->Proc.abi_types_set = true;
}
// NOTE(bill): 'operands' is for generating non generic procedure type
@@ -2191,10 +2520,18 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
break;
}
}
for (isize i = 0; i < result_count; i++) {
Entity *e = results->Tuple.variables[i];
if (e->kind != Entity_Variable) {
is_polymorphic = true;
break;
} else if (is_type_polymorphic(e->type)) {
is_polymorphic = true;
break;
}
}
type->Proc.is_polymorphic = is_polymorphic;
set_procedure_abi_types(c, type);
return success;
}
@@ -2543,7 +2880,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
generic_type = o.type;
}
if (count < 0) {
error(at->count, "... can only be used in conjuction with compound literals");
error(at->count, "? can only be used in conjuction with compound literals");
count = 0;
}
Type *elem = check_type_expr(ctx, at->elem, nullptr);
+211 -100
View File
@@ -13,6 +13,7 @@ bool is_operand_value(Operand o) {
case Addressing_Constant:
case Addressing_MapIndex:
case Addressing_OptionalOk:
case Addressing_SoaVariable:
return true;
}
return false;
@@ -85,9 +86,13 @@ int entity_graph_node_cmp(EntityGraphNode **data, isize i, isize j) {
EntityGraphNode *y = data[j];
isize a = x->entity->order_in_src;
isize b = y->entity->order_in_src;
if (x->dep_count < y->dep_count) return -1;
if (x->dep_count > y->dep_count) return +1;
return a < b ? -1 : b > a;
if (x->dep_count < y->dep_count) {
return -1;
}
if (x->dep_count == y->dep_count) {
return a < b ? -1 : b > a;
}
return +1;
}
void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) {
@@ -400,6 +405,15 @@ Entity *scope_insert_with_name(Scope *s, String name, Entity *entity) {
if (found) {
return *found;
}
if (s->parent != nullptr && (s->parent->flags & ScopeFlag_Proc) != 0) {
Entity **found = map_get(&s->parent->elements, key);
if (found) {
if ((*found)->flags & EntityFlag_Result) {
return *found;
}
}
}
map_set(&s->elements, key, entity);
if (entity->scope == nullptr) {
entity->scope = s;
@@ -790,6 +804,7 @@ void init_checker_info(CheckerInfo *i) {
map_init(&i->files, a);
map_init(&i->packages, a);
array_init(&i->variable_init_order, a);
array_init(&i->required_foreign_imports_through_force, a);
i->allow_identifier_uses = build_context.query_data_set_settings.kind == QueryDataSet_GoToDefinitions;
if (i->allow_identifier_uses) {
@@ -810,6 +825,8 @@ void destroy_checker_info(CheckerInfo *i) {
map_destroy(&i->packages);
array_free(&i->variable_init_order);
array_free(&i->identifier_uses);
array_free(&i->required_foreign_imports_through_force);
}
CheckerContext make_checker_context(Checker *c) {
@@ -1017,7 +1034,11 @@ void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mode, Type *ty
expr->tav.mode = mode;
expr->tav.type = type;
expr->tav.value = value;
if (mode == Addressing_Constant || mode == Addressing_Invalid) {
expr->tav.value = value;
} else if (mode == Addressing_Value && is_type_typeid(type)) {
expr->tav.value = value;
}
}
void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) {
@@ -1044,21 +1065,37 @@ bool redeclaration_error(String name, Entity *prev, Entity *found) {
// NOTE(bill): Error should have been handled already
return false;
}
error(prev->token,
"Redeclaration of '%.*s' in this scope through 'using'\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
if (found->flags & EntityFlag_Result) {
error(prev->token,
"Direct shadowing of the named return value '%.*s' in this scope through 'using'\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
} else {
error(prev->token,
"Redeclaration of '%.*s' in this scope through 'using'\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
}
} else {
if (pos == prev->token.pos) {
// NOTE(bill): Error should have been handled already
return false;
}
error(prev->token,
"Redeclaration of '%.*s' in this scope\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(pos.file), pos.line, pos.column);
if (found->flags & EntityFlag_Result) {
error(prev->token,
"Direct shadowing of the named return value '%.*s' in this scope\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(pos.file), pos.line, pos.column);
} else {
error(prev->token,
"Redeclaration of '%.*s' in this scope\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(pos.file), pos.line, pos.column);
}
}
return false;
}
@@ -1139,6 +1176,7 @@ void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, Dec
add_entity_definition(&c->checker->info, identifier, e);
GB_ASSERT(e->decl_info == nullptr);
e->decl_info = d;
d->entity = e;
array_add(&c->checker->info.entities, e);
e->order_in_src = c->checker->info.entities.count;
e->pkg = c->pkg;
@@ -1220,6 +1258,9 @@ void add_type_info_type(CheckerContext *c, Type *t) {
break;
case Type_Basic:
switch (bt->Basic.kind) {
case Basic_cstring:
add_type_info_type(c, t_u8_ptr);
break;
case Basic_string:
add_type_info_type(c, t_u8_ptr);
add_type_info_type(c, t_int);
@@ -1239,6 +1280,14 @@ void add_type_info_type(CheckerContext *c, Type *t) {
add_type_info_type(c, t_type_info_float);
add_type_info_type(c, t_f64);
break;
case Basic_quaternion128:
add_type_info_type(c, t_type_info_float);
add_type_info_type(c, t_f32);
break;
case Basic_quaternion256:
add_type_info_type(c, t_type_info_float);
add_type_info_type(c, t_f64);
break;
}
break;
@@ -1293,7 +1342,11 @@ void add_type_info_type(CheckerContext *c, Type *t) {
if (bt->Struct.scope != nullptr) {
for_array(i, bt->Struct.scope->elements.entries) {
Entity *e = bt->Struct.scope->elements.entries[i].value;
add_type_info_type(c, e->type);
if (bt->Struct.is_soa) {
add_type_info_type(c, alloc_type_pointer(e->type));
} else {
add_type_info_type(c, e->type);
}
}
}
for_array(i, bt->Struct.fields) {
@@ -1415,6 +1468,14 @@ void add_min_dep_type_info(Checker *c, Type *t) {
add_min_dep_type_info(c, t_type_info_float);
add_min_dep_type_info(c, t_f64);
break;
case Basic_quaternion128:
add_min_dep_type_info(c, t_type_info_float);
add_min_dep_type_info(c, t_f32);
break;
case Basic_quaternion256:
add_min_dep_type_info(c, t_type_info_float);
add_min_dep_type_info(c, t_f64);
break;
}
break;
@@ -1577,6 +1638,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
str_lit("args__"),
str_lit("type_table"),
str_lit("__type_info_of"),
str_lit("global_scratch_allocator"),
str_lit("Type_Info"),
@@ -1585,9 +1647,17 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
str_lit("quo_complex64"),
str_lit("quo_complex128"),
str_lit("mul_quaternion128"),
str_lit("mul_quaternion256"),
str_lit("quo_quaternion128"),
str_lit("quo_quaternion256"),
str_lit("cstring_to_string"),
str_lit("umodti3"),
str_lit("udivti3"),
str_lit("memory_compare"),
str_lit("memory_compare_zero"),
};
for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) {
add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i]));
@@ -1649,6 +1719,11 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
}
}
for_array(i, c->info.required_foreign_imports_through_force) {
Entity *e = c->info.required_foreign_imports_through_force[i];
add_dependency_to_set(c, e);
}
add_dependency_to_set(c, start);
}
@@ -1656,9 +1731,10 @@ bool is_entity_a_dependency(Entity *e) {
if (e == nullptr) return false;
switch (e->kind) {
case Entity_Procedure:
case Entity_Variable:
case Entity_Constant:
return true;
case Entity_Constant:
case Entity_Variable:
return e->pkg != nullptr;
}
return false;
}
@@ -1679,28 +1755,35 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
}
}
#define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0)
TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 1");
// Calculate edges for graph M
for_array(i, M.entries) {
Entity * e = cast(Entity *)M.entries[i].key.ptr;
EntityGraphNode *n = M.entries[i].value;
DeclInfo *decl = decl_info_of_entity(e);
if (decl != nullptr) {
for_array(j, decl->deps.entries) {
auto entry = decl->deps.entries[j];
Entity *dep = entry.ptr;
if (dep && is_entity_a_dependency(dep)) {
EntityGraphNode **m_ = map_get(&M, hash_pointer(dep));
if (m_ != nullptr) {
EntityGraphNode *m = *m_;
entity_graph_node_set_add(&n->succ, m);
entity_graph_node_set_add(&m->pred, n);
}
}
GB_ASSERT(decl != nullptr);
for_array(j, decl->deps.entries) {
Entity *dep = decl->deps.entries[j].ptr;
GB_ASSERT(dep != nullptr);
if (is_entity_a_dependency(dep)) {
EntityGraphNode **m_ = map_get(&M, hash_pointer(dep));
GB_ASSERT(m_ != nullptr);
EntityGraphNode *m = *m_;
entity_graph_node_set_add(&n->succ, m);
entity_graph_node_set_add(&m->pred, n);
}
}
}
// TODO(bill): This could be multithreaded to improve performance
// This means that the entity graph node set will have to be thread safe
TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2");
auto G = array_make<EntityGraphNode *>(a, 0, M.entries.count);
for_array(i, M.entries) {
@@ -1737,14 +1820,18 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
}
}
TIME_SECTION("generate_entity_dependency_graph: Dependency Count Checker");
for_array(i, G) {
EntityGraphNode *n = G[i];
n->index = i;
n->dep_count = n->succ.entries.count;
GB_ASSERT(n->dep_count >= 0);
}
return G;
#undef TIME_SECTION
}
@@ -1863,6 +1950,7 @@ void init_core_type_info(Checker *c) {
t_type_info_integer = find_core_type(c, str_lit("Type_Info_Integer"));
t_type_info_rune = find_core_type(c, str_lit("Type_Info_Rune"));
t_type_info_float = find_core_type(c, str_lit("Type_Info_Float"));
t_type_info_quaternion = find_core_type(c, str_lit("Type_Info_Quaternion"));
t_type_info_complex = find_core_type(c, str_lit("Type_Info_Complex"));
t_type_info_string = find_core_type(c, str_lit("Type_Info_String"));
t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean"));
@@ -1887,6 +1975,7 @@ void init_core_type_info(Checker *c) {
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
t_type_info_rune_ptr = alloc_type_pointer(t_type_info_rune);
t_type_info_float_ptr = alloc_type_pointer(t_type_info_float);
t_type_info_quaternion_ptr = alloc_type_pointer(t_type_info_quaternion);
t_type_info_complex_ptr = alloc_type_pointer(t_type_info_complex);
t_type_info_string_ptr = alloc_type_pointer(t_type_info_string);
t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean);
@@ -2138,6 +2227,12 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
error(elem, "Expected a string value for '%.*s'", LIT(name));
}
return true;
} else if (name == "require_results") {
if (value != nullptr) {
error(elem, "Expected no value for '%.*s'", LIT(name));
}
ac->require_results = true;
return true;
}
return false;
}
@@ -2151,6 +2246,33 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
}
ac->is_static = true;
return true;
} else if (name == "thread_local") {
if (ac->init_expr_list_count > 0) {
error(elem, "A thread local variable declaration cannot have initialization values");
} else if (c->foreign_context.curr_library) {
error(elem, "A foreign block variable cannot be thread local");
} else if (ac->is_export) {
error(elem, "An exported variable cannot be thread local");
} else if (ev.kind == ExactValue_Invalid) {
ac->thread_local_model = str_lit("default");
} else if (ev.kind == ExactValue_String) {
String model = ev.value_string;
if (model == "default" ||
model == "localdynamic" ||
model == "initialexec" ||
model == "localexec") {
ac->thread_local_model = model;
} else {
error(elem, "Invalid thread local model '%.*s'. Valid models:", LIT(model));
error_line("\tdefault\n");
error_line("\tlocaldynamic\n");
error_line("\tinitialexec\n");
error_line("\tlocalexec\n");
}
} else {
error(elem, "Expected either no value or a string for '%.*s'", LIT(name));
}
return true;
}
if (c->curr_proc_decl != nullptr) {
@@ -2191,33 +2313,6 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
error(elem, "Expected a string value for '%.*s'", LIT(name));
}
return true;
} else if (name == "thread_local") {
if (ac->init_expr_list_count > 0) {
error(elem, "A thread local variable declaration cannot have initialization values");
} else if (c->foreign_context.curr_library) {
error(elem, "A foreign block variable cannot be thread local");
} else if (ac->is_export) {
error(elem, "An exported variable cannot be thread local");
} else if (ev.kind == ExactValue_Invalid) {
ac->thread_local_model = str_lit("default");
} else if (ev.kind == ExactValue_String) {
String model = ev.value_string;
if (model == "default" ||
model == "localdynamic" ||
model == "initialexec" ||
model == "localexec") {
ac->thread_local_model = model;
} else {
error(elem, "Invalid thread local model '%.*s'. Valid models:", LIT(model));
error_line("\tdefault\n");
error_line("\tlocaldynamic\n");
error_line("\tinitialexec\n");
error_line("\tlocalexec\n");
}
} else {
error(elem, "Expected either no value or a string for '%.*s'", LIT(name));
}
return true;
}
return false;
}
@@ -2528,6 +2623,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
Ast *init_expr = value;
DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl);
d->entity = e;
d->type_expr = vd->type;
d->init_expr = init_expr;
d->attributes = vd->attributes;
@@ -2557,14 +2653,14 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
Entity *e = nullptr;
d->attributes = vd->attributes;
d->type_expr = vd->type;
d->init_expr = init;
if (is_ast_type(init)) {
e = alloc_entity_type_name(d->scope, token, nullptr);
if (vd->type != nullptr) {
error(name, "A type declaration cannot have an type parameter");
}
d->type_expr = init;
d->init_expr = init;
// if (vd->type != nullptr) {
// error(name, "A type declaration cannot have an type parameter");
// }
} else if (init->kind == Ast_ProcLit) {
if (c->scope->flags&ScopeFlag_Type) {
error(name, "Procedure declarations are not allowed within a struct");
@@ -2591,18 +2687,15 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
pl->type->ProcType.calling_convention = cc;
}
d->proc_lit = init;
d->type_expr = pl->type;
d->init_expr = init;
} else if (init->kind == Ast_ProcGroup) {
ast_node(pg, ProcGroup, init);
e = alloc_entity_proc_group(d->scope, token, nullptr);
if (fl != nullptr) {
error(name, "Procedure groups are not allowed within a foreign block");
}
d->init_expr = init;
} else {
e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value);
d->type_expr = vd->type;
d->init_expr = init;
}
e->identifier = name;
@@ -3100,7 +3193,7 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
Entity *e = scope->elements.entries[elem_index].value;
if (e->scope == parent_scope) continue;
if (is_entity_exported(e)) {
if (is_entity_exported(e, true)) {
Entity *found = scope_lookup_current(parent_scope, name);
if (found != nullptr) {
// NOTE(bill):
@@ -3118,6 +3211,16 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
scope->flags |= ScopeFlag_HasBeenImported;
}
DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
if (name == "force") {
if (value != nullptr) {
error(elem, "Expected no parameter for '%.*s'", LIT(name));
}
ac->force_foreign_import = true;
return true;
}
return false;
}
void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
if (decl->been_handled) return;
@@ -3162,6 +3265,14 @@ void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid,
fl->fullpaths, library_name);
add_entity(ctx->checker, parent_scope, nullptr, e);
AttributeContext ac = {};
check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac);
if (ac.force_foreign_import) {
array_add(&ctx->info->required_foreign_imports_through_force, e);
add_entity_use(ctx, nullptr, e);
}
}
bool collect_checked_packages_from_decl_list(Checker *c, Array<Ast *> const &decls) {
@@ -3314,8 +3425,9 @@ bool collect_file_decls(CheckerContext *ctx, Array<Ast *> const &decls) {
if (es->expr->kind == Ast_CallExpr) {
ast_node(ce, CallExpr, es->expr);
if (ce->proc->kind == Ast_BasicDirective) {
Operand o = {};
check_expr(ctx, &o, es->expr);
if (ctx->collect_delayed_decls) {
array_add(&ctx->scope->delayed_directives, es->expr);
}
}
}
case_end;
@@ -3472,12 +3584,18 @@ void check_import_entities(Checker *c) {
for_array(i, pkg->files) {
AstFile *f = pkg->files[i];
CheckerContext ctx = c->init_ctx;
add_curr_ast_file(&ctx, f);
for_array(j, f->scope->delayed_imports) {
Ast *decl = f->scope->delayed_imports[j];
check_add_import_decl(&ctx, decl);
}
}
for_array(i, pkg->files) {
AstFile *f = pkg->files[i];
CheckerContext ctx = c->init_ctx;
add_curr_ast_file(&ctx, f);
for_array(j, f->scope->delayed_directives) {
Ast *expr = f->scope->delayed_directives[j];
Operand o = {};
@@ -3529,22 +3647,11 @@ Array<Entity *> find_entity_path(Entity *start, Entity *end, Map<Entity *> *visi
void calculate_global_init_order(Checker *c) {
#if 0
Timings timings = {};
timings_init(&timings, str_lit("calculate_global_init_order"), 16);
defer ({
timings_print_all(&timings);
timings_destroy(&timings);
});
#define TIME_SECTION(str) timings_start_section(&timings, str_lit(str))
#else
#define TIME_SECTION(str)
#endif
#define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0)
CheckerInfo *info = &c->info;
TIME_SECTION("generate entity dependency graph");
TIME_SECTION("calculate_global_init_order: generate entity dependency graph");
Array<EntityGraphNode *> dep_graph = generate_entity_dependency_graph(info);
defer ({
for_array(i, dep_graph) {
@@ -3553,7 +3660,7 @@ void calculate_global_init_order(Checker *c) {
array_free(&dep_graph);
});
TIME_SECTION("priority queue create");
TIME_SECTION("calculate_global_init_order: priority queue create");
// NOTE(bill): Priority queue
auto pq = priority_queue_create(dep_graph, entity_graph_node_cmp, entity_graph_node_swap);
@@ -3561,7 +3668,7 @@ void calculate_global_init_order(Checker *c) {
ptr_set_init(&emitted, heap_allocator());
defer (ptr_set_destroy(&emitted));
TIME_SECTION("queue sort");
TIME_SECTION("calculate_global_init_order: queue sort");
while (pq.queue.count > 0) {
EntityGraphNode *n = priority_queue_pop(&pq);
Entity *e = n->entity;
@@ -3583,21 +3690,26 @@ void calculate_global_init_order(Checker *c) {
for_array(i, n->pred.entries) {
EntityGraphNode *p = n->pred.entries[i].ptr;
p->dep_count -= gb_max(p->dep_count-1, 0);
p->dep_count -= 1;
p->dep_count = gb_max(p->dep_count, 0);
priority_queue_fix(&pq, p->index);
}
if (e == nullptr || e->kind != Entity_Variable) {
DeclInfo *d = decl_info_of_entity(e);
if (e->kind != Entity_Variable) {
continue;
}
DeclInfo *d = decl_info_of_entity(e);
// IMPORTANT NOTE(bill, 2019-08-29): Just add it regardless of the ordering
// because it does not need any initialization other than zero
// if (!decl_info_has_init(d)) {
// continue;
// }
if (ptr_set_exists(&emitted, d)) {
continue;
}
ptr_set_add(&emitted, d);
d->entity = e;
array_add(&info->variable_init_order, d);
}
@@ -3636,6 +3748,14 @@ void check_proc_info(Checker *c, ProcInfo pi) {
return;
}
if (pt->is_polymorphic && pt->is_poly_specialized) {
Entity *e = pi.decl->entity;
if ((e->flags & EntityFlag_Used) == 0) {
// NOTE(bill, 2019-08-31): It was never used, don't check
return;
}
}
bool bounds_check = (pi.tags & ProcTag_bounds_check) != 0;
bool no_bounds_check = (pi.tags & ProcTag_no_bounds_check) != 0;
@@ -3660,17 +3780,7 @@ GB_THREAD_PROC(check_proc_info_worker_proc) {
void check_parsed_files(Checker *c) {
#if 0
Timings timings = {};
timings_init(&timings, str_lit("check_parsed_files"), 16);
defer ({
timings_print_all(&timings);
timings_destroy(&timings);
});
#define TIME_SECTION(str) timings_start_section(&timings, str_lit(str))
#else
#define TIME_SECTION(str)
#endif
#define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0)
TIME_SECTION("map full filepaths to scope");
add_type_info_type(&c->init_ctx, t_invalid);
@@ -3732,6 +3842,7 @@ void check_parsed_files(Checker *c) {
check_proc_info(c, pi);
}
TIME_SECTION("check scope usage");
for_array(i, c->info.files.entries) {
AstFile *f = c->info.files.entries[i].value;
check_scope_usage(c, f->scope);
+10 -211
View File
@@ -59,218 +59,8 @@ struct BuiltinProc {
BuiltinProcPkg pkg;
};
enum BuiltinProcId {
BuiltinProc_Invalid,
BuiltinProc_len,
BuiltinProc_cap,
BuiltinProc_size_of,
BuiltinProc_align_of,
BuiltinProc_offset_of,
BuiltinProc_type_of,
BuiltinProc_type_info_of,
BuiltinProc_typeid_of,
BuiltinProc_swizzle,
BuiltinProc_complex,
BuiltinProc_real,
BuiltinProc_imag,
BuiltinProc_conj,
BuiltinProc_expand_to_tuple,
BuiltinProc_min,
BuiltinProc_max,
BuiltinProc_abs,
BuiltinProc_clamp,
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
// "Intrinsics"
BuiltinProc_vector,
BuiltinProc_atomic_fence,
BuiltinProc_atomic_fence_acq,
BuiltinProc_atomic_fence_rel,
BuiltinProc_atomic_fence_acqrel,
BuiltinProc_atomic_store,
BuiltinProc_atomic_store_rel,
BuiltinProc_atomic_store_relaxed,
BuiltinProc_atomic_store_unordered,
BuiltinProc_atomic_load,
BuiltinProc_atomic_load_acq,
BuiltinProc_atomic_load_relaxed,
BuiltinProc_atomic_load_unordered,
BuiltinProc_atomic_add,
BuiltinProc_atomic_add_acq,
BuiltinProc_atomic_add_rel,
BuiltinProc_atomic_add_acqrel,
BuiltinProc_atomic_add_relaxed,
BuiltinProc_atomic_sub,
BuiltinProc_atomic_sub_acq,
BuiltinProc_atomic_sub_rel,
BuiltinProc_atomic_sub_acqrel,
BuiltinProc_atomic_sub_relaxed,
BuiltinProc_atomic_and,
BuiltinProc_atomic_and_acq,
BuiltinProc_atomic_and_rel,
BuiltinProc_atomic_and_acqrel,
BuiltinProc_atomic_and_relaxed,
BuiltinProc_atomic_nand,
BuiltinProc_atomic_nand_acq,
BuiltinProc_atomic_nand_rel,
BuiltinProc_atomic_nand_acqrel,
BuiltinProc_atomic_nand_relaxed,
BuiltinProc_atomic_or,
BuiltinProc_atomic_or_acq,
BuiltinProc_atomic_or_rel,
BuiltinProc_atomic_or_acqrel,
BuiltinProc_atomic_or_relaxed,
BuiltinProc_atomic_xor,
BuiltinProc_atomic_xor_acq,
BuiltinProc_atomic_xor_rel,
BuiltinProc_atomic_xor_acqrel,
BuiltinProc_atomic_xor_relaxed,
BuiltinProc_atomic_xchg,
BuiltinProc_atomic_xchg_acq,
BuiltinProc_atomic_xchg_rel,
BuiltinProc_atomic_xchg_acqrel,
BuiltinProc_atomic_xchg_relaxed,
BuiltinProc_atomic_cxchg,
BuiltinProc_atomic_cxchg_acq,
BuiltinProc_atomic_cxchg_rel,
BuiltinProc_atomic_cxchg_acqrel,
BuiltinProc_atomic_cxchg_relaxed,
BuiltinProc_atomic_cxchg_failrelaxed,
BuiltinProc_atomic_cxchg_failacq,
BuiltinProc_atomic_cxchg_acq_failrelaxed,
BuiltinProc_atomic_cxchg_acqrel_failrelaxed,
BuiltinProc_atomic_cxchgweak,
BuiltinProc_atomic_cxchgweak_acq,
BuiltinProc_atomic_cxchgweak_rel,
BuiltinProc_atomic_cxchgweak_acqrel,
BuiltinProc_atomic_cxchgweak_relaxed,
BuiltinProc_atomic_cxchgweak_failrelaxed,
BuiltinProc_atomic_cxchgweak_failacq,
BuiltinProc_atomic_cxchgweak_acq_failrelaxed,
BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed,
BuiltinProc_COUNT,
};
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_builtin},
{STR_LIT("len"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("cap"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("size_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("align_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("offset_of"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("type_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("type_info_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("typeid_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("abs"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("clamp"), 3, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE
// "Intrinsics"
{STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
{STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_fence_acqrel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_store_rel"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_store_relaxed"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_store_unordered"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_load_acq"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_load_relaxed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_load_unordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
};
#include "checker_builtin_procs.hpp"
// Operand is used as an intermediate value whilst checking
@@ -307,6 +97,8 @@ struct DeferredProcedure {
struct AttributeContext {
bool is_export;
bool is_static;
bool require_results;
bool force_foreign_import;
String link_name;
String link_prefix;
isize init_expr_list_count;
@@ -431,6 +223,7 @@ struct ForeignContext {
typedef Array<Entity *> CheckerTypePath;
typedef Array<Type *> CheckerPolyPath;
// CheckerInfo stores all the symbol information for a type-checked program
struct CheckerInfo {
Map<ExprInfo> untyped; // Key: Ast * | Expression -> ExprInfo
@@ -457,6 +250,8 @@ struct CheckerInfo {
PtrSet<Entity *> minimum_dependency_set;
PtrSet<isize> minimum_dependency_type_info_set;
Array<Entity *> required_foreign_imports_through_force;
bool allow_identifier_uses;
Array<Ast *> identifier_uses; // only used by 'odin query'
@@ -486,10 +281,14 @@ struct CheckerContext {
CheckerPolyPath *poly_path;
isize poly_level; // TODO(bill): Actually handle correctly
#define MAX_INLINE_FOR_DEPTH 1024ll
i64 inline_for_depth;
bool in_enum_type;
bool collect_delayed_decls;
bool allow_polymorphic_types;
bool no_polymorphic_errors;
bool hide_polymorphic_errors;
bool in_polymorphic_specialization;
Scope * polymorphic_scope;
};
+325
View File
@@ -0,0 +1,325 @@
// checker_builtin_procs.hpp
enum BuiltinProcId {
BuiltinProc_Invalid,
BuiltinProc_len,
BuiltinProc_cap,
BuiltinProc_size_of,
BuiltinProc_align_of,
BuiltinProc_offset_of,
BuiltinProc_type_of,
BuiltinProc_type_info_of,
BuiltinProc_typeid_of,
BuiltinProc_swizzle,
BuiltinProc_complex,
BuiltinProc_quaternion,
BuiltinProc_real,
BuiltinProc_imag,
BuiltinProc_jmag,
BuiltinProc_kmag,
BuiltinProc_conj,
BuiltinProc_expand_to_tuple,
BuiltinProc_min,
BuiltinProc_max,
BuiltinProc_abs,
BuiltinProc_clamp,
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
// "Intrinsics"
BuiltinProc_vector,
BuiltinProc_soa_struct,
BuiltinProc_atomic_fence,
BuiltinProc_atomic_fence_acq,
BuiltinProc_atomic_fence_rel,
BuiltinProc_atomic_fence_acqrel,
BuiltinProc_atomic_store,
BuiltinProc_atomic_store_rel,
BuiltinProc_atomic_store_relaxed,
BuiltinProc_atomic_store_unordered,
BuiltinProc_atomic_load,
BuiltinProc_atomic_load_acq,
BuiltinProc_atomic_load_relaxed,
BuiltinProc_atomic_load_unordered,
BuiltinProc_atomic_add,
BuiltinProc_atomic_add_acq,
BuiltinProc_atomic_add_rel,
BuiltinProc_atomic_add_acqrel,
BuiltinProc_atomic_add_relaxed,
BuiltinProc_atomic_sub,
BuiltinProc_atomic_sub_acq,
BuiltinProc_atomic_sub_rel,
BuiltinProc_atomic_sub_acqrel,
BuiltinProc_atomic_sub_relaxed,
BuiltinProc_atomic_and,
BuiltinProc_atomic_and_acq,
BuiltinProc_atomic_and_rel,
BuiltinProc_atomic_and_acqrel,
BuiltinProc_atomic_and_relaxed,
BuiltinProc_atomic_nand,
BuiltinProc_atomic_nand_acq,
BuiltinProc_atomic_nand_rel,
BuiltinProc_atomic_nand_acqrel,
BuiltinProc_atomic_nand_relaxed,
BuiltinProc_atomic_or,
BuiltinProc_atomic_or_acq,
BuiltinProc_atomic_or_rel,
BuiltinProc_atomic_or_acqrel,
BuiltinProc_atomic_or_relaxed,
BuiltinProc_atomic_xor,
BuiltinProc_atomic_xor_acq,
BuiltinProc_atomic_xor_rel,
BuiltinProc_atomic_xor_acqrel,
BuiltinProc_atomic_xor_relaxed,
BuiltinProc_atomic_xchg,
BuiltinProc_atomic_xchg_acq,
BuiltinProc_atomic_xchg_rel,
BuiltinProc_atomic_xchg_acqrel,
BuiltinProc_atomic_xchg_relaxed,
BuiltinProc_atomic_cxchg,
BuiltinProc_atomic_cxchg_acq,
BuiltinProc_atomic_cxchg_rel,
BuiltinProc_atomic_cxchg_acqrel,
BuiltinProc_atomic_cxchg_relaxed,
BuiltinProc_atomic_cxchg_failrelaxed,
BuiltinProc_atomic_cxchg_failacq,
BuiltinProc_atomic_cxchg_acq_failrelaxed,
BuiltinProc_atomic_cxchg_acqrel_failrelaxed,
BuiltinProc_atomic_cxchgweak,
BuiltinProc_atomic_cxchgweak_acq,
BuiltinProc_atomic_cxchgweak_rel,
BuiltinProc_atomic_cxchgweak_acqrel,
BuiltinProc_atomic_cxchgweak_relaxed,
BuiltinProc_atomic_cxchgweak_failrelaxed,
BuiltinProc_atomic_cxchgweak_failacq,
BuiltinProc_atomic_cxchgweak_acq_failrelaxed,
BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed,
// Constant type tests
BuiltinProc__type_begin,
BuiltinProc_type_base_type,
BuiltinProc_type_core_type,
BuiltinProc_type_elem_type,
BuiltinProc_type_is_boolean,
BuiltinProc_type_is_integer,
BuiltinProc_type_is_rune,
BuiltinProc_type_is_float,
BuiltinProc_type_is_complex,
BuiltinProc_type_is_quaternion,
BuiltinProc_type_is_string,
BuiltinProc_type_is_typeid,
BuiltinProc_type_is_any,
BuiltinProc_type_is_endian_little,
BuiltinProc_type_is_endian_big,
BuiltinProc_type_is_unsigned,
BuiltinProc_type_is_numeric,
BuiltinProc_type_is_ordered,
BuiltinProc_type_is_ordered_numeric,
BuiltinProc_type_is_indexable,
BuiltinProc_type_is_sliceable,
BuiltinProc_type_is_simple_compare, // easily compared using memcmp
BuiltinProc_type_is_dereferenceable,
BuiltinProc_type_is_valid_map_key,
BuiltinProc_type_is_named,
BuiltinProc_type_is_pointer,
BuiltinProc_type_is_opaque,
BuiltinProc_type_is_array,
BuiltinProc_type_is_slice,
BuiltinProc_type_is_dynamic_array,
BuiltinProc_type_is_map,
BuiltinProc_type_is_struct,
BuiltinProc_type_is_union,
BuiltinProc_type_is_enum,
BuiltinProc_type_is_proc,
BuiltinProc_type_is_bit_field,
BuiltinProc_type_is_bit_field_value,
BuiltinProc_type_is_bit_set,
BuiltinProc_type_is_simd_vector,
BuiltinProc_type_has_nil,
BuiltinProc_type_proc_parameter_count,
BuiltinProc_type_proc_return_count,
BuiltinProc__type_end,
BuiltinProc_COUNT,
};
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_builtin},
{STR_LIT("len"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("cap"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("size_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("align_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("offset_of"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("type_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("type_info_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("typeid_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("quaternion"), 4, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("jmag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("kmag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("abs"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("clamp"), 3, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE
// "Intrinsics"
{STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
{STR_LIT("soa_struct"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
{STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_fence_acqrel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_store_rel"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_store_relaxed"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_store_unordered"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_load_acq"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_load_relaxed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_load_unordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("type_base_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_core_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_integer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_rune"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_float"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_complex"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_quaternion"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_string"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_typeid"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_endian_little"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_endian_big"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_unsigned"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_numeric"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_ordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_ordered_numeric"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_indexable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_sliceable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_simple_compare"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_dereferenceable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_valid_map_key"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_named"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_pointer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_opaque"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_slice"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_dynamic_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_map"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_struct"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_union"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_enum"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_bit_field"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_bit_field_value"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_bit_set"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_simd_vector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_has_nil"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_proc_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_proc_return_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
};
+4 -4
View File
@@ -10,13 +10,11 @@
#define GB_IMPLEMENTATION
#include "gb/gb.h"
#include <wchar.h>
#include <stdio.h>
#include <math.h>
template <typename U, typename V>
gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(v); }
@@ -145,6 +143,9 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
#include "range_cache.cpp"
u64 fnv64a(void const *data, isize len) {
u8 const *bytes = cast(u8 const *)data;
@@ -331,7 +332,7 @@ void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) {
#include "ptr_set.cpp"
#include "string_set.cpp"
#include "priority_queue.cpp"
#include "thread_pool.cpp"
gb_global String global_module_path = {0};
@@ -873,7 +874,6 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
info.size = size;
info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
array_add(fi, info);
} while (FindNextFileW(find_file, &file_data));
if (fi->count == 0) {
+8 -5
View File
@@ -48,7 +48,8 @@ enum EntityFlag {
EntityFlag_NotExported = 1<<14,
EntityFlag_Static = 1<<16,
// EntityFlag_Reference = 1<<17,
EntityFlag_ImplicitReference = 1<<17, // NOTE(bill): equivalent to `const &` in C++
EntityFlag_CVarArg = 1<<20,
EntityFlag_AutoCast = 1<<21,
@@ -183,10 +184,11 @@ bool is_entity_exported(Entity *e, bool allow_builtin = false) {
}
String name = e->token.string;
if (name.len == 0) {
return false;
switch (name.len) {
case 0: return false;
case 1: return name[0] != '_';
}
return name[0] != '_';
return true;
}
bool entity_has_deferred_procedure(Entity *e) {
@@ -219,12 +221,13 @@ Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, bool is_imm
return entity;
}
Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type) {
Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast *using_expr) {
GB_ASSERT(parent != nullptr);
token.pos = parent->token.pos;
Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type);
entity->using_parent = parent;
entity->parent_proc_decl = parent->parent_proc_decl;
entity->using_expr = using_expr;
entity->flags |= EntityFlag_Using;
entity->flags |= EntityFlag_Used;
entity->state = EntityState_Resolved;
+249 -15
View File
@@ -12,6 +12,19 @@ bool are_types_identical(Type *x, Type *y);
struct Complex128 {
f64 real, imag;
};
struct Quaternion256 {
f64 imag, jmag, kmag, real;
};
Quaternion256 quaternion256_inverse(Quaternion256 x) {
f64 invmag2 = 1.0 / (x.real*x.real + x.imag*x.imag + x.jmag*x.jmag + x.kmag*x.kmag);
x.real = +x.real * invmag2;
x.imag = -x.imag * invmag2;
x.jmag = -x.jmag * invmag2;
x.kmag = -x.kmag * invmag2;
return x;
}
enum ExactValueKind {
ExactValue_Invalid,
@@ -21,9 +34,11 @@ enum ExactValueKind {
ExactValue_Integer,
ExactValue_Float,
ExactValue_Complex,
ExactValue_Quaternion,
ExactValue_Pointer,
ExactValue_Compound, // TODO(bill): Is this good enough?
ExactValue_Procedure, // TODO(bill): Is this good enough?
ExactValue_Typeid,
ExactValue_Count,
};
@@ -37,8 +52,10 @@ struct ExactValue {
f64 value_float;
i64 value_pointer;
Complex128 value_complex;
Quaternion256 value_quaternion;
Ast * value_compound;
Ast * value_procedure;
Type * value_typeid;
};
};
@@ -53,25 +70,22 @@ HashKey hash_exact_value(ExactValue v) {
return hash_integer(u64(v.value_bool));
case ExactValue_String:
return hash_string(v.value_string);
case ExactValue_Integer: {
u64 *d = big_int_ptr(&v.value_integer);
u64 x = 0;
for (i32 i = 0; i < v.value_integer.len; i++) {
x |= d[i];
}
return hash_integer(x);
}
case ExactValue_Integer:
return hashing_proc(big_int_ptr(&v.value_integer), v.value_integer.len * gb_size_of(u64));
case ExactValue_Float:
return hash_f64(v.value_float);
case ExactValue_Pointer:
return hash_integer(v.value_pointer);
case ExactValue_Complex:
return hashing_proc(&v.value_complex, gb_size_of(Complex128));
case ExactValue_Quaternion:
return hashing_proc(&v.value_quaternion, gb_size_of(Quaternion256));
case ExactValue_Compound:
return hash_pointer(v.value_compound);
case ExactValue_Procedure:
return hash_pointer(v.value_procedure);
case ExactValue_Typeid:
return hash_pointer(v.value_typeid);
}
return hashing_proc(&v, gb_size_of(ExactValue));
@@ -122,6 +136,15 @@ ExactValue exact_value_complex(f64 real, f64 imag) {
return result;
}
ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
ExactValue result = {ExactValue_Quaternion};
result.value_quaternion.real = real;
result.value_quaternion.imag = imag;
result.value_quaternion.jmag = jmag;
result.value_quaternion.kmag = kmag;
return result;
}
ExactValue exact_value_pointer(i64 ptr) {
ExactValue result = {ExactValue_Pointer};
result.value_pointer = ptr;
@@ -135,6 +158,13 @@ ExactValue exact_value_procedure(Ast *node) {
}
ExactValue exact_value_typeid(Type *type) {
ExactValue result = {ExactValue_Typeid};
result.value_typeid = type;
return result;
}
ExactValue exact_value_integer_from_string(String const &string) {
ExactValue result = {ExactValue_Integer};
big_int_from_string(&result.value_integer, string);
@@ -259,14 +289,16 @@ ExactValue exact_value_from_basic_literal(Token token) {
str.len--; // Ignore the 'i|j|k'
f64 imag = float_from_string(str);
if (last_rune == 'i') {
return exact_value_complex(0, imag);
switch (last_rune) {
case 'i': return exact_value_complex(0, imag);
case 'j': return exact_value_quaternion(0, 0, imag, 0);
case 'k': return exact_value_quaternion(0, 0, 0, imag);
default: GB_PANIC("Invalid imaginary basic literal");
}
}
case Token_Rune: {
Rune r = GB_RUNE_INVALID;
gb_utf8_decode(token.string.text, token.string.len, &r);
// gb_printf("%.*s rune: %d\n", LIT(token.string), r);
return exact_value_i64(r);
}
default:
@@ -324,11 +356,26 @@ ExactValue exact_value_to_complex(ExactValue v) {
return exact_value_complex(v.value_float, 0);
case ExactValue_Complex:
return v;
// case ExactValue_Quaternion:
// return exact_value_complex(v.value_quaternion.real, v.value_quaternion.imag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_to_quaternion(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(big_int_to_f64(&v.value_integer), 0, 0, 0);
case ExactValue_Float:
return exact_value_quaternion(v.value_float, 0, 0, 0);
case ExactValue_Complex:
return exact_value_quaternion(v.value_complex.real, v.value_complex.imag, 0, 0);
case ExactValue_Quaternion:
return v;
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_real(ExactValue v) {
switch (v.kind) {
@@ -337,6 +384,8 @@ ExactValue exact_value_real(ExactValue v) {
return v;
case ExactValue_Complex:
return exact_value_float(v.value_complex.real);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.real);
}
ExactValue r = {ExactValue_Invalid};
return r;
@@ -349,6 +398,34 @@ ExactValue exact_value_imag(ExactValue v) {
return exact_value_i64(0);
case ExactValue_Complex:
return exact_value_float(v.value_complex.imag);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.imag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
return exact_value_i64(0);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.jmag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
return exact_value_i64(0);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.kmag);
}
ExactValue r = {ExactValue_Invalid};
return r;
@@ -367,6 +444,32 @@ ExactValue exact_value_make_imag(ExactValue v) {
return r;
}
ExactValue exact_value_make_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
case ExactValue_Float:
return exact_value_quaternion(0, 0, v.value_float, 0);
default:
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_make_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
case ExactValue_Float:
return exact_value_quaternion(0, 0, 0, v.value_float);
default:
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
i64 exact_value_to_i64(ExactValue v) {
v = exact_value_to_integer(v);
if (v.kind == ExactValue_Integer) {
@@ -395,6 +498,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
case ExactValue_Quaternion:
return v;
}
break;
@@ -419,6 +523,13 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
f64 imag = v.value_complex.imag;
return exact_value_complex(-real, -imag);
}
case ExactValue_Quaternion: {
f64 real = v.value_quaternion.real;
f64 imag = v.value_quaternion.imag;
f64 jmag = v.value_quaternion.jmag;
f64 kmag = v.value_quaternion.kmag;
return exact_value_quaternion(-real, -imag, -jmag, -kmag);
}
}
break;
}
@@ -469,8 +580,10 @@ i32 exact_value_order(ExactValue const &v) {
return 3;
case ExactValue_Complex:
return 4;
case ExactValue_Pointer:
case ExactValue_Quaternion:
return 5;
case ExactValue_Pointer:
return 6;
default:
GB_PANIC("How'd you get here? Invalid Value.kind");
@@ -491,7 +604,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Bool:
case ExactValue_String:
case ExactValue_Complex:
case ExactValue_Quaternion:
return;
case ExactValue_Integer:
@@ -505,6 +618,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Complex:
*x = exact_value_complex(big_int_to_f64(&x->value_integer), 0);
return;
case ExactValue_Quaternion:
*x = exact_value_quaternion(big_int_to_f64(&x->value_integer), 0, 0, 0);
return;
}
break;
@@ -515,6 +631,17 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Complex:
*x = exact_value_to_complex(*x);
return;
case ExactValue_Quaternion:
*x = exact_value_to_quaternion(*x);
return;
}
break;
case ExactValue_Complex:
switch (y->kind) {
case ExactValue_Quaternion:
*x = exact_value_to_quaternion(*x);
return;
}
break;
}
@@ -612,6 +739,56 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
break;
}
case ExactValue_Quaternion: {
y = exact_value_to_quaternion(y);
f64 xr = x.value_quaternion.real;
f64 xi = x.value_quaternion.imag;
f64 xj = x.value_quaternion.jmag;
f64 xk = x.value_quaternion.kmag;
f64 yr = y.value_quaternion.real;
f64 yi = y.value_quaternion.imag;
f64 yj = y.value_quaternion.jmag;
f64 yk = y.value_quaternion.kmag;
f64 real = 0;
f64 imag = 0;
f64 jmag = 0;
f64 kmag = 0;
switch (op) {
case Token_Add:
real = xr + yr;
imag = xi + yi;
jmag = xj + yj;
kmag = xk + yk;
break;
case Token_Sub:
real = xr - yr;
imag = xi - yi;
jmag = xj - yj;
kmag = xk - yk;
break;
case Token_Mul:
imag = xr * yi + xi * yr + xj * yk - xk * yj;
jmag = xr * yj - xi * yk + xj * yr + xk * yi;
kmag = xr * yk + xi * yj - xj * yi + xk * yr;
real = xr * yr - xi * yi - xj * yj - xk * yk;
break;
case Token_Quo: {
f64 invmag2 = 1.0 / (yr*yr + yi*yi + yj*yj + yk*yk);
imag = (xr * -yi + xi * +yr + xj * -yk - xk * -yj) * invmag2;
jmag = (xr * -yj - xi * -yk + xj * +yr + xk * -yi) * invmag2;
kmag = (xr * -yk + xi * -yj - xj * -yi + xk * +yr) * invmag2;
real = (xr * +yr - xi * -yi - xj * -yj - xk * -yk) * invmag2;
break;
}
default: goto error;
}
return exact_value_quaternion(real, imag, jmag, kmag);
break;
}
case ExactValue_String: {
if (op != Token_Add) goto error;
@@ -647,6 +824,10 @@ gb_inline ExactValue exact_value_shift(TokenKind op, ExactValue const &x, ExactV
return exact_binary_operator_value(op, x, y);
}
gb_inline ExactValue exact_value_increment_one(ExactValue const &x) {
return exact_binary_operator_value(Token_Add, x, exact_value_i64(1));
}
i32 cmp_f64(f64 a, f64 b) {
return (a > b) - (a < b);
@@ -719,8 +900,61 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
}
break;
}
case ExactValue_Typeid:
switch (op) {
case Token_CmpEq: return are_types_identical(x.value_typeid, y.value_typeid);
case Token_NotEq: return !are_types_identical(x.value_typeid, y.value_typeid);
}
break;
}
GB_PANIC("Invalid comparison");
return false;
}
gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
switch (v.kind) {
case ExactValue_Invalid:
return str;
case ExactValue_Bool:
return gb_string_appendc(str, v.value_bool ? "true" : "false");
case ExactValue_String: {
String s = quote_to_ascii(heap_allocator(), v.value_string);
string_limit = gb_max(string_limit, 36);
if (s.len <= string_limit) {
str = gb_string_append_length(str, s.text, s.len);
} else {
isize n = string_limit/5;
str = gb_string_append_length(str, s.text, n);
str = gb_string_append_fmt(str, "\"..%lld chars..\"", s.len-(2*n));
str = gb_string_append_length(str, s.text+s.len-n, n);
}
gb_free(heap_allocator(), s.text);
return str;
}
case ExactValue_Integer: {
String s = big_int_to_string(heap_allocator(), &v.value_integer);
str = gb_string_append_length(str, s.text, s.len);
gb_free(heap_allocator(), s.text);
return str;
}
case ExactValue_Float:
return gb_string_append_fmt(str, "%f", v.value_float);
case ExactValue_Complex:
return gb_string_append_fmt(str, "%f+%fi", v.value_complex.real, v.value_complex.imag);
case ExactValue_Pointer:
return str;
case ExactValue_Compound:
return str;
case ExactValue_Procedure:
return str;
}
return str;
};
gbString exact_value_to_string(ExactValue const &v, isize string_limit=36) {
return write_exact_value_to_string(gb_string_make(heap_allocator(), ""), v, string_limit);
}
+19 -11
View File
@@ -918,7 +918,7 @@ GB_DEF void gb_lfence (void);
#if defined(GB_SYSTEM_WINDOWS)
typedef struct gbSemaphore { void *win32_handle; } gbSemaphore;
typedef struct gbSemaphore { void *win32_handle;} gbSemaphore;
#elif defined(GB_SYSTEM_OSX)
typedef struct gbSemaphore { semaphore_t osx_handle; } gbSemaphore;
#elif defined(GB_SYSTEM_UNIX)
@@ -930,7 +930,7 @@ typedef struct gbSemaphore { sem_t unix_handle; } gbSemaphore;
GB_DEF void gb_semaphore_init (gbSemaphore *s);
GB_DEF void gb_semaphore_destroy(gbSemaphore *s);
GB_DEF void gb_semaphore_post (gbSemaphore *s, i32 count);
GB_DEF void gb_semaphore_release(gbSemaphore *s); // NOTE(bill): gb_semaphore_post(s, 1)
GB_DEF void gb_semaphore_release(gbSemaphore *s);
GB_DEF void gb_semaphore_wait (gbSemaphore *s);
@@ -975,10 +975,10 @@ typedef struct gbThread {
pthread_t posix_handle;
#endif
gbThreadProc *proc;
void * user_data;
isize user_index;
isize return_value;
gbThreadProc * proc;
void * user_data;
isize user_index;
isize volatile return_value;
gbSemaphore semaphore;
isize stack_size;
@@ -4588,10 +4588,18 @@ gb_inline void gb_lfence(void) {
gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); }
#if defined(GB_SYSTEM_WINDOWS)
gb_inline void gb_semaphore_init (gbSemaphore *s) { s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL); }
gb_inline void gb_semaphore_destroy(gbSemaphore *s) { CloseHandle(s->win32_handle); }
gb_inline void gb_semaphore_post (gbSemaphore *s, i32 count) { ReleaseSemaphore(s->win32_handle, count, NULL); }
gb_inline void gb_semaphore_wait (gbSemaphore *s) { WaitForSingleObject(s->win32_handle, INFINITE); }
gb_inline void gb_semaphore_init(gbSemaphore *s) {
s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL);
}
gb_inline void gb_semaphore_destroy(gbSemaphore *s) {
CloseHandle(s->win32_handle);
}
gb_inline void gb_semaphore_post(gbSemaphore *s, i32 count) {
ReleaseSemaphore(s->win32_handle, count, NULL);
}
gb_inline void gb_semaphore_wait(gbSemaphore *s) {
WaitForSingleObjectEx(s->win32_handle, INFINITE, FALSE);
}
#elif defined(GB_SYSTEM_OSX)
gb_inline void gb_semaphore_init (gbSemaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); }
@@ -8975,7 +8983,7 @@ gb_inline void gb_exit(u32 code) { exit(code); }
gb_inline void gb_yield(void) {
#if defined(GB_SYSTEM_WINDOWS)
Sleep(0);
YieldProcessor();
#else
sched_yield();
#endif
+1020 -160
View File
File diff suppressed because it is too large Load Diff
+237 -61
View File
@@ -323,12 +323,15 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) {
set_procedure_abi_types(heap_allocator(), t);
i64 word_bits = 8*build_context.word_size;
t = base_type(t);
GB_ASSERT(is_type_proc(t));
isize param_count = t->Proc.param_count;
isize result_count = t->Proc.result_count;
ir_print_proc_results(f, m, t);
ir_write_string(f, str_lit(" ("));
if (t->Proc.return_by_pointer) {
@@ -418,20 +421,23 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
}
return;
// case Basic_f16: ir_write_str_lit(f, "half"); return;
case Basic_f32: ir_write_str_lit(f, "float"); return;
case Basic_f64: ir_write_str_lit(f, "double"); return;
// case Basic_f16: ir_write_str_lit(f, "half"); return;
case Basic_f32: ir_write_str_lit(f, "float"); return;
case Basic_f64: ir_write_str_lit(f, "double"); return;
// case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return;
case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return;
case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return;
// case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return;
case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return;
case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return;
case Basic_any: ir_write_str_lit(f, "%..any"); return;
case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return;
case Basic_string: ir_write_str_lit(f, "%..string"); return;
case Basic_cstring: ir_write_str_lit(f, "i8*"); return;
case Basic_quaternion128: ir_write_str_lit(f, "%..quaternion128"); return;
case Basic_quaternion256: ir_write_str_lit(f, "%..quaternion256"); return;
case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return;
case Basic_any: ir_write_str_lit(f, "%..any"); return;
case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return;
case Basic_string: ir_write_str_lit(f, "%..string"); return;
case Basic_cstring: ir_write_str_lit(f, "i8*"); return;
case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return;
}
break;
@@ -767,15 +773,17 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
case ExactValue_Float: {
GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
type = core_type(type);
u64 u = bit_cast<u64>(value.value_float);
u64 u_64 = bit_cast<u64>(value.value_float);
u32 u_32 = bit_cast<u32>(cast(f32)value.value_float);
#if 0
switch (type->Basic.kind) {
case Basic_f32:
// IMPORTANT NOTE(bill): LLVM requires all floating point constants to be
// a 64 bit number if bits_of(float type) <= 64.
// https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M
// 64 bit mantissa: 52 bits
// 32 bit mantissa: 23 bits
// 16 bit mantissa: 10 bits
// 64 bit mantissa: 52 bits ==> 52-52 == 0
// 32 bit mantissa: 23 bits ==> 52-23 == 29
// 16 bit mantissa: 10 bits ==> 52=10 == 42
// 29 == 52-23
u >>= 29;
u <<= 29;
@@ -792,9 +800,24 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_fprintf(f, "0x%016llx", u);
break;
}
#else
switch (type->Basic.kind) {
case Basic_f32: {
ir_fprintf(f, "bitcast (i32 %u to float)", u_32);
break;
}
case Basic_f64:
ir_fprintf(f, "0x%016llx", u_64);
break;
default:
ir_fprintf(f, "0x%016llx", u_64);
break;
}
#endif
break;
}
case ExactValue_Complex: {
// xy/ri format
type = core_type(type);
GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type));
Type *ft = base_complex_elem_type(type);
@@ -807,6 +830,26 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_write_byte(f, '}');
break;
}
case ExactValue_Quaternion: {
// xyzw/ijkr format
type = core_type(type);
GB_ASSERT_MSG(is_type_quaternion(type), "%s", type_to_string(type));
Type *ft = base_complex_elem_type(type);
ir_write_byte(f, ' ');
ir_write_byte(f, '{');
ir_print_type(f, m, ft); ir_write_byte(f, ' ');
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.imag), ft);
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.jmag), ft);
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.kmag), ft);
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.real), ft);
ir_write_byte(f, '}');
break;
}
case ExactValue_Pointer:
if (value.value_pointer == 0) {
if (is_type_typeid(type)) {
@@ -836,22 +879,86 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_write_str_lit(f, "zeroinitializer");
break;
}
GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
if (cl->elems[0]->kind == Ast_FieldValue) {
// TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
ir_write_byte(f, '[');
for (i64 i = 0; i < type->Array.count; i++) {
if (i > 0) ir_write_str_lit(f, ", ");
ir_write_byte(f, '[');
bool found = false;
for (isize i = 0; i < elem_count; i++) {
if (i > 0) ir_write_str_lit(f, ", ");
TypeAndValue tav = cl->elems[i]->tav;
GB_ASSERT(tav.mode != Addressing_Invalid);
ir_print_compound_element(f, m, tav.value, elem_type);
for (isize j = 0; j < elem_count; j++) {
Ast *elem = cl->elems[j];
ast_node(fv, FieldValue, elem);
if (is_ast_range(fv->field)) {
ast_node(ie, BinaryExpr, fv->field);
TypeAndValue lo_tav = ie->left->tav;
TypeAndValue hi_tav = ie->right->tav;
GB_ASSERT(lo_tav.mode == Addressing_Constant);
GB_ASSERT(hi_tav.mode == Addressing_Constant);
TokenKind op = ie->op.kind;
i64 lo = exact_value_to_i64(lo_tav.value);
i64 hi = exact_value_to_i64(hi_tav.value);
if (op == Token_Ellipsis) {
hi += 1;
}
if (lo == i) {
TypeAndValue tav = fv->value->tav;
if (tav.mode != Addressing_Constant) {
break;
}
for (i64 k = lo; k < hi; k++) {
if (k > lo) ir_write_str_lit(f, ", ");
ir_print_compound_element(f, m, tav.value, elem_type);
}
found = true;
i += (hi-lo-1);
break;
}
} else {
TypeAndValue index_tav = fv->field->tav;
GB_ASSERT(index_tav.mode == Addressing_Constant);
i64 index = exact_value_to_i64(index_tav.value);
if (index == i) {
TypeAndValue tav = fv->value->tav;
if (tav.mode != Addressing_Constant) {
break;
}
ir_print_compound_element(f, m, tav.value, elem_type);
found = true;
break;
}
}
}
if (!found) {
ir_print_type(f, m, elem_type);
ir_write_byte(f, ' ');
ir_write_str_lit(f, "zeroinitializer");
}
}
ir_write_byte(f, ']');
} else {
GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
ir_write_byte(f, '[');
for (isize i = 0; i < elem_count; i++) {
if (i > 0) ir_write_str_lit(f, ", ");
TypeAndValue tav = cl->elems[i]->tav;
GB_ASSERT(tav.mode != Addressing_Invalid);
ir_print_compound_element(f, m, tav.value, elem_type);
}
for (isize i = elem_count; i < type->Array.count; i++) {
if (i >= elem_count) ir_write_str_lit(f, ", ");
ir_print_compound_element(f, m, empty_exact_value, elem_type);
}
ir_write_byte(f, ']');
}
for (isize i = elem_count; i < type->Array.count; i++) {
if (i >= elem_count) ir_write_str_lit(f, ", ");
ir_print_compound_element(f, m, empty_exact_value, elem_type);
}
ir_write_byte(f, ']');
} else if (is_type_simd_vector(type)) {
ast_node(cl, CompoundLit, value.value_compound);
@@ -927,7 +1034,8 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
if (type->Struct.is_packed) ir_write_byte(f, '<');
ir_write_byte(f, '{');
if (type->Struct.custom_align > 0) {
ir_fprintf(f, "[0 x <%lld x i8>] zeroinitializer", cast(i64)type->Struct.custom_align);
ir_print_alignment_prefix_hack(f, cast(i64)type->Struct.custom_align);
ir_write_str_lit(f, " zeroinitializer");
if (value_count > 0) {
ir_write_string(f, str_lit(", "));
}
@@ -1089,7 +1197,11 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
break;
}
case irValue_Param:
ir_print_encoded_local(f, value->Param.entity->token.string);
if (value->Param.index >= 0) {
ir_fprintf(f, "%%_.%d", value->Param.index);
} else {
ir_print_encoded_local(f, value->Param.entity->token.string);
}
break;
case irValue_SourceCodeLocation: {
irValue *file = value->SourceCodeLocation.file;
@@ -1124,7 +1236,8 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
switch (cc) {
case ProcCC_Odin: ir_write_str_lit(f, ""); break;
case ProcCC_Contextless: ir_write_str_lit(f, ""); break;
case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break;
// case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break;
case ProcCC_CDecl: ir_write_str_lit(f, ""); break;
case ProcCC_StdCall: ir_write_str_lit(f, "cc 64 "); break;
case ProcCC_FastCall: ir_write_str_lit(f, "cc 65 "); break;
case ProcCC_None: ir_write_str_lit(f, ""); break;
@@ -1134,8 +1247,8 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
void ir_print_context_parameter_prefix(irFileBuffer *f, irModule *m) {
ir_print_type(f, m, t_context_ptr);
ir_write_str_lit(f, " noalias nonnull nocapture inreg ");
// ir_write_str_lit(f, " noalias nonnull nocapture ");
// ir_write_str_lit(f, " noalias nonnull nocapture inreg ");
ir_write_str_lit(f, " noalias nonnull nocapture ");
}
void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
@@ -1186,6 +1299,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_write_str_lit(f, ", ");
ir_print_type(f, m, type);
ir_fprintf(f, "* %%%d, align 1", instr->ZeroInit.address->index);
// ir_fprintf(f, "* %%%d", instr->ZeroInit.address->index);
break;
}
@@ -1888,11 +2002,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
if (e->flags&EntityFlag_NoAlias) {
ir_write_str_lit(f, " noalias");
}
if (e->flags&EntityFlag_ImplicitReference) {
ir_write_str_lit(f, " nonnull dereferenceable");
}
ir_write_byte(f, ' ');
irValue *arg = call->args[i];
if (is_type_boolean(t)) {
}
ir_print_value(f, m, arg, t);
param_index++;
}
@@ -1907,24 +2021,43 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
param_index++;
}
} else {
GB_ASSERT(call->args.count == params->variables.count);
// GB_ASSERT(call->args.count == params->variables.count);
isize arg_index = 0;
for_array(i, params->variables) {
Entity *e = params->variables[i];
GB_ASSERT(e != nullptr);
if (e->kind != Entity_Variable) continue;
if (e->kind != Entity_Variable) {
arg_index++;
continue;
}
if (param_index > 0) ir_write_str_lit(f, ", ");
irValue *arg = call->args[i];
Type *t = proc_type->Proc.abi_compat_params[i];
if (is_type_tuple(t)) {
for_array(j, t->Tuple.variables) {
if (j > 0) ir_write_str_lit(f, ", ");
ir_print_type(f, m, t);
if (e->flags&EntityFlag_NoAlias) {
ir_write_str_lit(f, " noalias");
irValue *arg = call->args[arg_index++];
ir_print_type(f, m, t->Tuple.variables[j]->type);
if (e->flags&EntityFlag_NoAlias) {
ir_write_str_lit(f, " noalias");
}
ir_write_byte(f, ' ');
ir_print_value(f, m, arg, t);
param_index++;
}
} else {
irValue *arg = call->args[arg_index++];
ir_print_type(f, m, t);
if (e->flags&EntityFlag_NoAlias) {
ir_write_str_lit(f, " noalias");
}
ir_write_byte(f, ' ');
ir_print_value(f, m, arg, t);
param_index++;
}
ir_write_byte(f, ' ');
ir_print_value(f, m, arg, t);
param_index++;
}
}
}
@@ -1995,6 +2128,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
set_procedure_abi_types(heap_allocator(), proc->type);
if (proc->body == nullptr) {
ir_write_str_lit(f, "declare ");
// if (proc->tags & ProcTag_dll_import) {
@@ -2043,7 +2178,8 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
if (param_count > 0) {
TypeTuple *params = &proc_type->params->Tuple;
for (isize i = 0; i < param_count; i++) {
isize parameter_index = 0;
for (isize i = 0; i < param_count; i++, parameter_index++) {
Entity *e = params->variables[i];
Type *original_type = e->type;
Type *abi_type = proc_type->abi_compat_params[i];
@@ -2053,16 +2189,29 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
if (i+1 == params->variables.count && proc_type->c_vararg) {
ir_write_str_lit(f, " ...");
} else {
ir_print_type(f, m, abi_type);
if (e->flags&EntityFlag_NoAlias) {
ir_write_str_lit(f, " noalias");
}
if (proc->body != nullptr) {
if (e->token.string != "" && !is_blank_ident(e->token)) {
ir_write_byte(f, ' ');
ir_print_encoded_local(f, e->token.string);
} else {
ir_fprintf(f, " %%_.param_%td", i);
if (is_type_tuple(abi_type)) {
for_array(j, abi_type->Tuple.variables) {
if (j > 0) ir_write_string(f, str_lit(", "));
Type *tft = abi_type->Tuple.variables[j]->type;
ir_print_type(f, m, tft);
if (e->flags&EntityFlag_NoAlias) {
ir_write_str_lit(f, " noalias");
}
if (proc->body != nullptr) {
ir_fprintf(f, " %%_.%td", parameter_index+j);
}
}
parameter_index += abi_type->Tuple.variables.count-1;
param_index += abi_type->Tuple.variables.count-1;
} else {
ir_print_type(f, m, abi_type);
if (e->flags&EntityFlag_NoAlias) {
ir_write_str_lit(f, " noalias");
}
if (proc->body != nullptr) {
ir_fprintf(f, " %%_.%td", parameter_index);
}
}
}
@@ -2176,6 +2325,22 @@ void ir_print_type_name(irFileBuffer *f, irModule *m, irValue *v) {
ir_write_byte(f, '\n');
}
bool ir_print_global_type_allowed(Type *t) {
if (t == nullptr) {
return true;
}
t = core_type(t);
switch (t->kind) {
case Type_DynamicArray:
case Type_Map:
case Type_Union:
case Type_BitField:
return false;
}
return true;
}
void print_llvm_ir(irGen *ir) {
irModule *m = &ir->module;
@@ -2184,9 +2349,11 @@ void print_llvm_ir(irGen *ir) {
defer (ir_file_buffer_destroy(f));
i32 word_bits = cast(i32)(8*build_context.word_size);
if (build_context.ODIN_OS == "osx" || build_context.ODIN_OS == "macos") {
if (build_context.ODIN_OS == "darwin") {
GB_ASSERT(word_bits == 64);
ir_write_str_lit(f, "target triple = \"x86_64-apple-macosx10.8\"\n\n");
ir_write_str_lit(f, "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n");
ir_write_str_lit(f, "target triple = \"x86_64-apple-macosx10.8\"\n");
ir_write_str_lit(f, "\n");
} else if (build_context.ODIN_OS == "windows") {
ir_fprintf(f, "target triple = \"x86%s-pc-windows-msvc\"\n\n", word_bits == 64 ? "_64" : "");
if (word_bits == 64 && build_context.metrics.arch == TargetArch_amd64) {
@@ -2210,6 +2377,13 @@ void print_llvm_ir(irGen *ir) {
ir_print_encoded_local(f, str_lit("..complex128"));
ir_write_str_lit(f, " = type {double, double} ; Basic_complex128\n");
ir_print_encoded_local(f, str_lit("..quaternion64"));
ir_write_str_lit(f, " = type {half, half, half, half} ; Basic_quaternion64\n");
ir_print_encoded_local(f, str_lit("..quaternion128"));
ir_write_str_lit(f, " = type {float, float, float, float} ; Basic_quaternion128\n");
ir_print_encoded_local(f, str_lit("..quaternion256"));
ir_write_str_lit(f, " = type {double, double, double, double} ; Basic_quaternion256\n");
ir_print_encoded_local(f, str_lit("..typeid"));
ir_write_str_lit(f, " = type ");
ir_print_type(f, m, t_uintptr);
@@ -2339,7 +2513,7 @@ void print_llvm_ir(irGen *ir) {
ir_print_type(f, m, g->entity->type);
ir_write_byte(f, ' ');
if (!g->is_foreign) {
if (g->value != nullptr) {
if (g->value != nullptr && ir_print_global_type_allowed(g->entity->type)) {
ir_print_value(f, m, g->value, g->entity->type);
} else {
ir_write_string(f, str_lit("zeroinitializer"));
@@ -2383,11 +2557,13 @@ void print_llvm_ir(irGen *ir) {
for_array(di_index, m->debug_info.entries) {
irDebugInfo *di = m->debug_info.entries[di_index].value;
GB_ASSERT_MSG(di != nullptr, "Invalid irDebugInfo");
ir_fprintf(f, "!%d = ", di->id);
switch (di->kind) {
case irDebugInfo_CompileUnit: {
irDebugInfo *file = *map_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
irDebugInfo **found = map_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
GB_ASSERT_MSG(found != nullptr, "Missing debug info for: %.*s\n", LIT(di->CompileUnit.file->fullpath));
irDebugInfo *file = *found;
ir_fprintf(f,
"distinct !DICompileUnit("
"language: DW_LANG_C_plus_plus" // Is this good enough?
+98 -90
View File
@@ -1,5 +1,6 @@
// #define NO_ARRAY_BOUNDS_CHECK
#include "common.cpp"
#include "timings.cpp"
#include "tokenizer.cpp"
@@ -7,6 +8,10 @@
#include "exact_value.cpp"
#include "build_settings.cpp"
gb_global Timings global_timings = {0};
#include "parser.hpp"
#include "checker.hpp"
@@ -75,7 +80,7 @@ i32 system_exec_command_line_app(char *name, char *fmt, ...) {
va_end(va);
cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
//printf("do: %s\n", cmd_line);
// printf("do: %s\n", cmd_line);
exit_code = system(&cmd_line[0]);
// pid_t pid = fork();
@@ -160,8 +165,9 @@ void usage(String argv0) {
print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
print_usage_line(0, "Commands:");
print_usage_line(1, "build compile .odin file as executable");
print_usage_line(1, "run compile and run .odin file");
print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable.");
print_usage_line(1, " one must contain the program's entry point, all must be in the same package.");
print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable.");
print_usage_line(1, "check parse and type check .odin file");
print_usage_line(1, "query parse, type check, and output a .json file containing information about the program");
print_usage_line(1, "docs generate documentation for a .odin file");
@@ -205,14 +211,14 @@ enum BuildFlagKind {
BuildFlag_OutFile,
BuildFlag_OptimizationLevel,
BuildFlag_ShowTimings,
BuildFlag_ShowMoreTimings,
BuildFlag_ThreadCount,
BuildFlag_KeepTempFiles,
BuildFlag_Collection,
BuildFlag_Define,
BuildFlag_BuildMode,
BuildFlag_Target,
BuildFlag_Debug,
BuildFlag_CrossCompile,
BuildFlag_CrossLibDir,
BuildFlag_NoBoundsCheck,
BuildFlag_NoCRT,
BuildFlag_UseLLD,
@@ -290,21 +296,21 @@ ExactValue build_param_to_exact_value(String name, String param) {
bool parse_build_flags(Array<String> args) {
auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer);
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_CrossCompile, str_lit("cross-compile"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_CrossLibDir, str_lit("cross-lib-dir"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer);
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_ShowMoreTimings, str_lit("show-more-timings"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None);
@@ -375,7 +381,7 @@ bool parse_build_flags(Array<String> args) {
param == "0") {
value = exact_value_bool(false);
} else {
gb_printf_err("Invalid flag parameter for '%.*s' = '%.*s'\n", LIT(name), LIT(param));
gb_printf_err("Invalid flag parameter for '%.*s' : '%.*s'\n", LIT(name), LIT(param));
}
} break;
case BuildFlagParam_Integer:
@@ -447,7 +453,7 @@ bool parse_build_flags(Array<String> args) {
path = substring(path, 0, string_extension_position(path));
}
#endif
build_context.out_filepath = path;
build_context.out_filepath = path_to_full_path(heap_allocator(), path);
} else {
gb_printf_err("Invalid -out path, got %.*s\n", LIT(path));
bad_flags = true;
@@ -462,6 +468,11 @@ bool parse_build_flags(Array<String> args) {
GB_ASSERT(value.kind == ExactValue_Invalid);
build_context.show_timings = true;
break;
case BuildFlag_ShowMoreTimings:
GB_ASSERT(value.kind == ExactValue_Invalid);
build_context.show_timings = true;
build_context.show_more_timings = true;
break;
case BuildFlag_ThreadCount: {
GB_ASSERT(value.kind == ExactValue_Integer);
isize count = cast(isize)big_int_to_i64(&value.value_integer);
@@ -478,33 +489,6 @@ bool parse_build_flags(Array<String> args) {
build_context.keep_temp_files = true;
break;
case BuildFlag_CrossCompile: {
GB_ASSERT(value.kind == ExactValue_String);
cross_compile_target = value.value_string;
#if defined(GB_SYSTEM_UNIX) && defined(GB_ARCH_64_BIT)
if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
} else
#endif
{
gb_printf_err("Unsupported cross compilation target '%.*s'\n", LIT(cross_compile_target));
gb_printf_err("Currently supported targets: Essence (from 64-bit Unixes only)\n");
bad_flags = true;
}
break;
}
case BuildFlag_CrossLibDir: {
GB_ASSERT(value.kind == ExactValue_String);
if (cross_compile_lib_dir.len) {
gb_printf_err("Multiple cross compilation library directories\n");
bad_flags = true;
} else {
cross_compile_lib_dir = concatenate_strings(heap_allocator(), str_lit("-L"), value.value_string);
}
break;
}
case BuildFlag_Collection: {
GB_ASSERT(value.kind == ExactValue_String);
String str = value.value_string;
@@ -623,7 +607,25 @@ bool parse_build_flags(Array<String> args) {
break;
}
case BuildFlag_Target: {
String str = value.value_string;
bool found = false;
for (int i = 0; i < sizeof(named_targets) / sizeof(named_targets[0]); i++) {
if (str_eq_ignore_case(str, named_targets[i].name)) {
found = true;
selected_target_metrics = named_targets + i;
break;
}
}
if (!found) {
gb_printf_err("Unknown target '%.*s'\n", LIT(str));
bad_flags = true;
}
break;
}
case BuildFlag_BuildMode: {
GB_ASSERT(value.kind == ExactValue_String);
@@ -635,7 +637,7 @@ bool parse_build_flags(Array<String> args) {
break;
}
if (str == "dll") {
if (str == "dll" || str == "shared") {
build_context.is_dll = true;
} else if (str == "exe") {
build_context.is_dll = false;
@@ -889,8 +891,8 @@ i32 exec_llvm_opt(String output_base) {
}
i32 exec_llvm_llc(String output_base) {
#if defined(GB_SYSTEM_WINDOWS)
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
#if defined(GB_SYSTEM_WINDOWS)
return system_exec_command_line_app("llvm-llc",
"\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d "
"-o \"%.*s.obj\" "
@@ -903,30 +905,29 @@ i32 exec_llvm_llc(String output_base) {
LIT(build_context.llc_flags));
#else
// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
return system_exec_command_line_app("llc",
"llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
"%.*s "
"%s"
"",
"%s%.*s",
LIT(output_base),
build_context.optimization_level,
LIT(build_context.llc_flags),
str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : "");
build_context.cross_compiling ? "-mtriple=" : "",
(int) (build_context.cross_compiling ? build_context.target_triplet.len : 0),
build_context.target_triplet.text);
#endif
}
int main(int arg_count, char **arg_ptr) {
if (arg_count < 2) {
usage(make_string_c(arg_ptr[0]));
return 1;
}
Timings timings = {0};
timings_init(&timings, str_lit("Total Time"), 128);
defer (timings_destroy(&timings));
Timings *timings = &global_timings;
timings_init(timings, str_lit("Total Time"), 128);
defer (timings_destroy(timings));
init_string_buffer_memory();
init_global_error_collector();
@@ -1026,7 +1027,7 @@ int main(int arg_count, char **arg_ptr) {
}
init_build_context();
init_build_context(selected_target_metrics ? selected_target_metrics->metrics : nullptr);
if (build_context.word_size == 4) {
print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
return 1;
@@ -1035,7 +1036,7 @@ int main(int arg_count, char **arg_ptr) {
init_universal();
// TODO(bill): prevent compiling without a linker
timings_start_section(&timings, str_lit("parse files"));
timings_start_section(timings, str_lit("parse files"));
Parser parser = {0};
if (!init_parser(&parser)) {
@@ -1051,7 +1052,7 @@ int main(int arg_count, char **arg_ptr) {
// generate_documentation(&parser);
return 0;
}
timings_start_section(&timings, str_lit("type check"));
timings_start_section(timings, str_lit("type check"));
Checker checker = {0};
@@ -1067,10 +1068,10 @@ int main(int arg_count, char **arg_ptr) {
if (build_context.no_output_files) {
if (build_context.query_data_set_settings.ok) {
generate_and_print_query_data(&checker, &timings);
generate_and_print_query_data(&checker, timings);
} else {
if (build_context.show_timings) {
show_timings(&checker, &timings);
show_timings(&checker, timings);
}
}
@@ -1092,13 +1093,13 @@ int main(int arg_count, char **arg_ptr) {
// defer (ir_gen_destroy(&ir_gen));
timings_start_section(&timings, str_lit("llvm ir gen"));
timings_start_section(timings, str_lit("llvm ir gen"));
ir_gen_tree(&ir_gen);
timings_start_section(&timings, str_lit("llvm ir opt tree"));
timings_start_section(timings, str_lit("llvm ir opt tree"));
ir_opt_tree(&ir_gen);
timings_start_section(&timings, str_lit("llvm ir print"));
timings_start_section(timings, str_lit("llvm ir print"));
print_llvm_ir(&ir_gen);
@@ -1109,20 +1110,31 @@ int main(int arg_count, char **arg_ptr) {
i32 exit_code = 0;
timings_start_section(&timings, str_lit("llvm-opt"));
timings_start_section(timings, str_lit("llvm-opt"));
exit_code = exec_llvm_opt(output_base);
if (exit_code != 0) {
return exit_code;
}
timings_start_section(&timings, str_lit("llvm-llc"));
timings_start_section(timings, str_lit("llvm-llc"));
exit_code = exec_llvm_llc(output_base);
if (exit_code != 0) {
return exit_code;
}
if (build_context.cross_compiling) {
if (0) {
#ifdef GB_SYSTEM_UNIX
} else if (selected_target_metrics->metrics == &target_essence_amd64) {
system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s",
LIT(output_base), LIT(output_base), LIT(build_context.link_flags));
#endif
} else {
gb_printf_err("Don't know how to cross compile to selected target.\n");
}
} else {
#if defined(GB_SYSTEM_WINDOWS)
timings_start_section(&timings, str_lit("msvc-link"));
timings_start_section(timings, str_lit("msvc-link"));
gbString lib_str = gb_string_make(heap_allocator(), "");
defer (gb_string_free(lib_str));
@@ -1213,16 +1225,16 @@ int main(int arg_count, char **arg_ptr) {
}
if (build_context.show_timings) {
show_timings(&checker, &timings);
show_timings(&checker, timings);
}
remove_temp_files(output_base);
if (run_output) {
system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
}
#else
timings_start_section(&timings, str_lit("ld-link"));
timings_start_section(timings, str_lit("ld-link"));
// NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe
char cwd[256];
@@ -1241,15 +1253,17 @@ int main(int arg_count, char **arg_ptr) {
// This allows you to specify '-f' in a #foreign_system_library,
// without having to implement any new syntax specifically for MacOS.
#if defined(GB_SYSTEM_OSX)
if (lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
if (string_ends_with(lib, str_lit(".framework"))) {
// framework thingie
lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
String lib_name = lib;
lib_name = remove_extension_from_path(lib_name);
lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
} else if (string_ends_with(lib, str_lit(".a"))) {
// static libs, absolute full path relative to the file in which the lib was imported from
lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
} else if (string_ends_with(lib, str_lit(".dylib"))) {
// dynamic lib, relative path to executable
lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib));
// dynamic lib
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
} else {
// dynamic or static system lib, just link regularly searching system library paths
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
@@ -1309,11 +1323,7 @@ int main(int arg_count, char **arg_ptr) {
// It probably has to do with including the entire CRT, but
// that's quite a complicated issue to solve while remaining distro-agnostic.
// Clang can figure out linker flags for us, and that's good enough _for now_.
if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
linker = "x86_64-elf-gcc -T core/sys/essence_linker_userland64.ld -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 -Wno-unused-command-line-argument";
} else {
linker = "clang -Wno-unused-command-line-argument";
}
linker = "clang -Wno-unused-command-line-argument";
#endif
exit_code = system_exec_command_line_app("ld-link",
@@ -1321,7 +1331,6 @@ int main(int arg_count, char **arg_ptr) {
" %s "
" %.*s "
" %s "
" %.*s "
#if defined(GB_SYSTEM_OSX)
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
@@ -1332,11 +1341,9 @@ int main(int arg_count, char **arg_ptr) {
#endif
, linker, LIT(output_base), LIT(output_base), LIT(output_ext),
lib_str,
str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-lfreetype -lglue" : "-lc -lm",
"-lc -lm",
LIT(build_context.link_flags),
link_settings,
LIT(cross_compile_lib_dir)
);
link_settings);
if (exit_code != 0) {
return exit_code;
}
@@ -1357,7 +1364,7 @@ int main(int arg_count, char **arg_ptr) {
if (build_context.show_timings) {
show_timings(&checker, &timings);
show_timings(&checker, timings);
}
remove_temp_files(output_base);
@@ -1366,9 +1373,10 @@ int main(int arg_count, char **arg_ptr) {
//NOTE(thebirk): This whole thing is a little leaky
String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext);
complete_path = path_to_full_path(heap_allocator(), complete_path);
system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
}
#endif
}
return 0;
}
+387 -284
View File
File diff suppressed because it is too large Load Diff
+48 -15
View File
@@ -21,6 +21,7 @@ enum AddressingMode {
// lhs: acts like a Variable
// rhs: acts like OptionalOk
Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
Addressing_SoaVariable, // Struct-Of-Arrays indexed variable
};
struct TypeAndValue {
@@ -134,13 +135,26 @@ struct Parser {
Map<AstPackage *> package_map; // Key: String (package name)
Array<AstPackage *> packages;
Array<ImportedPackage> package_imports;
Array<ImportedFile> files_to_process;
isize file_to_process_count;
isize total_token_count;
isize total_line_count;
gbMutex file_add_mutex;
gbMutex file_decl_mutex;
};
gb_global ThreadPool parser_thread_pool = {};
struct ParserWorkerData {
Parser *parser;
ImportedFile imported_file;
};
enum ProcInlining {
ProcInlining_none = 0,
ProcInlining_inline = 1,
@@ -186,13 +200,12 @@ enum FieldFlag {
FieldFlag_c_vararg = 1<<3,
FieldFlag_auto_cast = 1<<4,
FieldFlag_in = 1<<5,
FieldFlag_Tags = 1<<10,
FieldFlag_Results = 1<<16,
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast,
FieldFlag_Struct = FieldFlag_using,
FieldFlag_Struct = FieldFlag_using|FieldFlag_Tags,
};
enum StmtAllowFlag {
@@ -210,6 +223,7 @@ enum StmtAllowFlag {
AST_KIND(Undef, "undef", Token) \
AST_KIND(BasicLit, "basic literal", struct { \
Token token; \
ExactValue value; \
}) \
AST_KIND(BasicDirective, "basic directive", struct { \
Token token; \
@@ -230,11 +244,14 @@ enum StmtAllowFlag {
Ast *body; \
u64 tags; \
ProcInlining inlining; \
Token where_token; \
Array<Ast *> where_clauses; \
}) \
AST_KIND(CompoundLit, "compound literal", struct { \
Ast *type; \
Array<Ast *> elems; \
Token open, close; \
i64 max_count; \
}) \
AST_KIND(_ExprBegin, "", bool) \
AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \
@@ -327,6 +344,15 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
Ast *expr; \
Ast *body; \
}) \
AST_KIND(InlineRangeStmt, "inline range statement", struct { \
Token inline_token; \
Token for_token; \
Ast *val0; \
Ast *val1; \
Token in_token; \
Ast *expr; \
Ast *body; \
}) \
AST_KIND(CaseClause, "case clause", struct { \
Token token; \
Array<Ast *> list; \
@@ -401,6 +427,7 @@ AST_KIND(_DeclBegin, "", bool) \
Token library_name; \
String collection_name; \
Array<String> fullpaths; \
Array<Ast *> attributes; \
CommentGroup *docs; \
CommentGroup *comment; \
}) \
@@ -414,6 +441,7 @@ AST_KIND(_DeclEnd, "", bool) \
Array<Ast *> names; \
Ast * type; \
Ast * default_value; \
Token tag; \
u32 flags; \
CommentGroup * docs; \
CommentGroup * comment; \
@@ -467,19 +495,24 @@ AST_KIND(_TypeBegin, "", bool) \
Ast *elem; \
}) \
AST_KIND(StructType, "struct type", struct { \
Token token; \
Array<Ast *> fields; \
isize field_count; \
Ast *polymorphic_params; \
Ast *align; \
bool is_packed; \
bool is_raw_union; \
Token token; \
Array<Ast *> fields; \
isize field_count; \
Ast *polymorphic_params; \
Ast *align; \
Token where_token; \
Array<Ast *> where_clauses; \
bool is_packed; \
bool is_raw_union; \
}) \
AST_KIND(UnionType, "union type", struct { \
Token token; \
Array<Ast *> variants; \
Ast *polymorphic_params; \
Ast * align; \
Token token; \
Array<Ast *> variants; \
Ast *polymorphic_params; \
Ast * align; \
bool no_nil; \
Token where_token; \
Array<Ast *> where_clauses; \
}) \
AST_KIND(EnumType, "enum type", struct { \
Token token; \
+2 -2
View File
@@ -20,7 +20,7 @@ bool priority_queue_shift_down(PriorityQueue<T> *pq, isize i0, isize n) {
if (j2 < n && pq->cmp(&pq->queue[0], j2, j1) < 0) {
j = j2;
}
if (pq->cmp(&pq->queue[0], i, j) < 0) break;
if (pq->cmp(&pq->queue[0], j, i) >= 0) break;
pq->swap(&pq->queue[0], i, j);
i = j;
@@ -32,7 +32,7 @@ template <typename T>
void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
while (0 <= j && j < pq->queue.count) {
isize i = (j-1)/2;
if (i == j || pq->cmp(&pq->queue[0], i, j) < 0) {
if (i == j || pq->cmp(&pq->queue[0], j, i) >= 0) {
break;
}
pq->swap(&pq->queue[0], i, j);
+70
View File
@@ -0,0 +1,70 @@
// Integers only
struct RangeValue {
i64 lo;
i64 hi;
};
struct RangeCache {
Array<RangeValue> ranges;
};
RangeCache range_cache_make(gbAllocator a) {
RangeCache cache = {};
array_init(&cache.ranges, a);
return cache;
}
void range_cache_destroy(RangeCache *c) {
array_free(&c->ranges);
}
bool range_cache_add_index(RangeCache *c, i64 index) {
for_array(i, c->ranges) {
RangeValue v = c->ranges[i];
if (v.lo <= index && index <= v.hi) {
return false;
}
}
RangeValue v = {index, index};
array_add(&c->ranges, v);
return true;
}
bool range_cache_add_range(RangeCache *c, i64 lo, i64 hi) {
GB_ASSERT(lo <= hi);
for_array(i, c->ranges) {
RangeValue v = c->ranges[i];
if (hi < v.lo) {
continue;
}
if (lo > v.hi) {
continue;
}
if (v.hi < hi) {
v.hi = hi;
}
if (lo < v.lo) {
v.lo = lo;
}
c->ranges[i] = v;
return false;
}
RangeValue v = {lo, hi};
array_add(&c->ranges, v);
return true;
}
bool range_cache_index_exists(RangeCache *c, i64 index) {
for_array(i, c->ranges) {
RangeValue v = c->ranges[i];
if (v.lo <= index && index <= v.hi) {
return true;
}
}
return false;
}
+86 -4
View File
@@ -404,7 +404,7 @@ String16 string_to_string16(gbAllocator a, String s) {
}
text[len] = 0;
return make_string16(text, len-1);
return make_string16(text, len);
}
@@ -440,12 +440,94 @@ String string16_to_string(gbAllocator a, String16 s) {
bool is_printable(Rune r) {
if (r <= 0xff) {
if (0x20 <= r && r <= 0x7e) {
return true;
}
if (0xa1 <= r && r <= 0xff) {
return r != 0xad;
}
return false;
}
return false;
}
gb_global char const lower_hex[] = "0123456789abcdef";
String quote_to_ascii(gbAllocator a, String str, u8 quote='"') {
u8 *s = str.text;
isize n = str.len;
auto buf = array_make<u8>(a, 0, n);
array_add(&buf, quote);
for (isize width = 0; n > 0; s += width, n -= width) {
Rune r = cast(Rune)s[0];
width = 1;
if (r >= 0x80) {
width = gb_utf8_decode(s, n, &r);
}
if (width == 1 && r == GB_RUNE_INVALID) {
array_add(&buf, cast(u8)'\\');
array_add(&buf, cast(u8)'x');
array_add(&buf, cast(u8)lower_hex[s[0]>>4]);
array_add(&buf, cast(u8)lower_hex[s[0]&0xf]);
continue;
}
if (r == quote || r == '\\') {
array_add(&buf, cast(u8)'\\');
array_add(&buf, u8(r));
continue;
}
if (r < 0x80 && is_printable(r)) {
array_add(&buf, u8(r));
continue;
}
switch (r) {
case '\a':
case '\b':
case '\f':
case '\n':
case '\r':
case '\t':
case '\v':
default:
if (r < ' ') {
u8 b = cast(u8)r;
array_add(&buf, cast(u8)'\\');
array_add(&buf, cast(u8)'x');
array_add(&buf, cast(u8)lower_hex[b>>4]);
array_add(&buf, cast(u8)lower_hex[b&0xf]);
}
if (r > GB_RUNE_MAX) {
r = 0XFFFD;
}
if (r < 0x10000) {
u8 b = cast(u8)r;
array_add(&buf, cast(u8)'\\');
array_add(&buf, cast(u8)'u');
for (isize i = 12; i >= 0; i -= 4) {
array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]);
}
} else {
u8 b = cast(u8)r;
array_add(&buf, cast(u8)'\\');
array_add(&buf, cast(u8)'U');
for (isize i = 28; i >= 0; i -= 4) {
array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]);
}
}
}
}
array_add(&buf, quote);
String res = {};
res.text = buf.data;
res.len = buf.count;
return res;
}
+184
View File
@@ -0,0 +1,184 @@
// worker_queue.cpp
#define WORKER_TASK_PROC(name) isize name(void *data)
typedef WORKER_TASK_PROC(WorkerTaskProc);
struct WorkerTask {
WorkerTaskProc *do_work;
void *data;
isize result;
};
struct ThreadPool {
gbMutex mutex;
gbSemaphore sem_available;
gbAtomic32 processing_work_count;
bool is_running;
gbAllocator allocator;
WorkerTask *tasks;
isize volatile task_head;
isize volatile task_tail;
isize volatile task_capacity;
gbThread *threads;
isize thread_count;
char worker_prefix[10];
i32 worker_prefix_len;
};
void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_prefix = nullptr);
void thread_pool_destroy(ThreadPool *pool);
void thread_pool_start(ThreadPool *pool);
void thread_pool_join(ThreadPool *pool);
void thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data);
void thread_pool_kick(ThreadPool *pool);
void thread_pool_kick_and_wait(ThreadPool *pool);
GB_THREAD_PROC(worker_thread_internal);
void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_prefix) {
pool->allocator = a;
pool->task_head = 0;
pool->task_tail = 0;
pool->task_capacity = 1024;
pool->tasks = gb_alloc_array(a, WorkerTask, pool->task_capacity);
pool->thread_count = gb_max(thread_count, 0);
pool->threads = gb_alloc_array(a, gbThread, pool->thread_count);
gb_mutex_init(&pool->mutex);
gb_semaphore_init(&pool->sem_available);
pool->is_running = true;
pool->worker_prefix_len = 0;
if (worker_prefix) {
i32 worker_prefix_len = cast(i32)gb_strlen(worker_prefix);
worker_prefix_len = gb_min(worker_prefix_len, 10);
gb_memmove(pool->worker_prefix, worker_prefix, worker_prefix_len);
pool->worker_prefix_len = worker_prefix_len;
}
for (isize i = 0; i < pool->thread_count; i++) {
gbThread *t = &pool->threads[i];
gb_thread_init(t);
t->user_index = i;
#if 0
// TODO(bill): Fix this on Linux as it causes a seg-fault
if (pool->worker_prefix_len > 0) {
char worker_name[16] = {};
gb_snprintf(worker_name, gb_size_of(worker_name), "%.*s%u", pool->worker_prefix_len, pool->worker_prefix, cast(u16)i);
gb_thread_set_name(t, worker_name);
}
#endif
}
}
void thread_pool_start(ThreadPool *pool) {
for (isize i = 0; i < pool->thread_count; i++) {
gbThread *t = &pool->threads[i];
gb_thread_start(t, worker_thread_internal, pool);
}
}
void thread_pool_join(ThreadPool *pool) {
pool->is_running = false;
gb_semaphore_post(&pool->sem_available, cast(i32)pool->thread_count);
gb_yield();
for (isize i = 0; i < pool->thread_count; i++) {
gbThread *t = &pool->threads[i];
gb_thread_join(t);
}
}
void thread_pool_destroy(ThreadPool *pool) {
thread_pool_join(pool);
gb_semaphore_destroy(&pool->sem_available);
gb_mutex_destroy(&pool->mutex);
gb_free(pool->allocator, pool->threads);
pool->thread_count = 0;
gb_free(pool->allocator, pool->tasks);
pool->task_head = 0;
pool->task_tail = 0;
pool->task_capacity = 0;
}
void thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data) {
gb_mutex_lock(&pool->mutex);
if (pool->task_tail == pool->task_capacity) {
isize new_cap = 2*pool->task_capacity + 8;
WorkerTask *new_tasks = gb_alloc_array(pool->allocator, WorkerTask, new_cap);
gb_memmove(new_tasks, pool->tasks, (pool->task_tail)*gb_size_of(WorkerTask));
pool->tasks = new_tasks;
pool->task_capacity = new_cap;
}
WorkerTask task = {};
task.do_work = proc;
task.data = data;
pool->tasks[pool->task_tail++] = task;
gb_semaphore_post(&pool->sem_available, 1);
gb_mutex_unlock(&pool->mutex);
}
bool thread_pool_try_and_pop_task(ThreadPool *pool, WorkerTask *task) {
bool got_task = false;
if (gb_mutex_try_lock(&pool->mutex)) {
if (pool->task_tail > pool->task_head) {
gb_atomic32_fetch_add(&pool->processing_work_count, +1);
*task = pool->tasks[pool->task_head++];
got_task = true;
}
gb_mutex_unlock(&pool->mutex);
}
return got_task;
}
void thread_pool_do_work(ThreadPool *pool, WorkerTask *task) {
task->result = task->do_work(task->data);
gb_atomic32_fetch_add(&pool->processing_work_count, -1);
}
void thread_pool_wait_to_process(ThreadPool *pool) {
while (pool->task_tail > pool->task_head || gb_atomic32_load(&pool->processing_work_count) != 0) {
WorkerTask task = {};
if (thread_pool_try_and_pop_task(pool, &task)) {
thread_pool_do_work(pool, &task);
}
// Safety-kick
if (pool->task_tail > pool->task_head && gb_atomic32_load(&pool->processing_work_count) == 0) {
gb_mutex_lock(&pool->mutex);
gb_semaphore_post(&pool->sem_available, cast(i32)(pool->task_tail-pool->task_head));
gb_mutex_unlock(&pool->mutex);
}
gb_yield();
}
thread_pool_join(pool);
}
GB_THREAD_PROC(worker_thread_internal) {
ThreadPool *pool = cast(ThreadPool *)thread->user_data;
while (pool->is_running) {
gb_semaphore_wait(&pool->sem_available);
WorkerTask task = {};
if (thread_pool_try_and_pop_task(pool, &task)) {
thread_pool_do_work(pool, &task);
}
}
// Cascade
gb_semaphore_release(&pool->sem_available);
return 0;
}
+6 -4
View File
@@ -159,19 +159,21 @@ f64 time_stamp(TimeStamp const &ts, u64 freq, TimingUnit unit) {
}
void timings_print_all(Timings *t, TimingUnit unit = TimingUnit_Millisecond) {
char const SPACES[] = " ";
isize max_len;
isize const SPACES_LEN = 256;
char SPACES[SPACES_LEN+1] = {0};
gb_memset(SPACES, ' ', SPACES_LEN);
timings__stop_current_section(t);
t->total.finish = time_stamp_time_now();
max_len = gb_min(36, t->total.label.len);
isize max_len = gb_min(36, t->total.label.len);
for_array(i, t->sections) {
TimeStamp ts = t->sections[i];
max_len = gb_max(max_len, ts.label.len);
}
GB_ASSERT(max_len <= gb_size_of(SPACES)-1);
GB_ASSERT(max_len <= SPACES_LEN);
t->total_time_seconds = time_stamp_as_s(t->total, t->freq);
+13 -1
View File
@@ -86,6 +86,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
TOKEN_KIND(Token_package, "package"), \
TOKEN_KIND(Token_typeid, "typeid"), \
TOKEN_KIND(Token_when, "when"), \
TOKEN_KIND(Token_where, "where"), \
TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_else, "else"), \
TOKEN_KIND(Token_for, "for"), \
@@ -400,6 +401,15 @@ void syntax_error(Token token, char *fmt, ...) {
va_end(va);
}
void syntax_error(TokenPos pos, char *fmt, ...) {
va_list va;
va_start(va, fmt);
Token token = {};
token.pos = pos;
syntax_error_va(token, fmt, va);
va_end(va);
}
void syntax_warning(Token token, char *fmt, ...) {
va_list va;
va_start(va, fmt);
@@ -745,9 +755,11 @@ exponent:
scan_mantissa(t, 10);
}
if (t->curr_rune == 'i') {
switch (t->curr_rune) {
case 'i': case 'j': case 'k':
token.kind = Token_Imag;
advance_to_next_rune(t);
break;
}
end:
+233 -75
View File
@@ -32,6 +32,9 @@ enum BasicKind {
Basic_complex64,
Basic_complex128,
Basic_quaternion128,
Basic_quaternion256,
Basic_int,
Basic_uint,
Basic_uintptr,
@@ -66,6 +69,7 @@ enum BasicKind {
Basic_UntypedInteger,
Basic_UntypedFloat,
Basic_UntypedComplex,
Basic_UntypedQuaternion,
Basic_UntypedString,
Basic_UntypedRune,
Basic_UntypedNil,
@@ -82,17 +86,18 @@ enum BasicFlag {
BasicFlag_Unsigned = GB_BIT(2),
BasicFlag_Float = GB_BIT(3),
BasicFlag_Complex = GB_BIT(4),
BasicFlag_Pointer = GB_BIT(5),
BasicFlag_String = GB_BIT(6),
BasicFlag_Rune = GB_BIT(7),
BasicFlag_Untyped = GB_BIT(8),
BasicFlag_Quaternion = GB_BIT(5),
BasicFlag_Pointer = GB_BIT(6),
BasicFlag_String = GB_BIT(7),
BasicFlag_Rune = GB_BIT(8),
BasicFlag_Untyped = GB_BIT(9),
BasicFlag_LLVM = GB_BIT(10),
BasicFlag_LLVM = GB_BIT(11),
BasicFlag_EndianLittle = GB_BIT(13),
BasicFlag_EndianBig = GB_BIT(14),
BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex,
BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex | BasicFlag_Quaternion,
BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Rune,
BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
@@ -107,21 +112,26 @@ struct BasicType {
struct TypeStruct {
Array<Entity *> fields;
Ast *node;
Scope * scope;
Array<String> tags;
Array<i64> offsets;
Ast * node;
Scope * scope;
Array<i64> offsets;
bool are_offsets_set;
bool are_offsets_being_processed;
bool is_packed;
bool is_raw_union;
bool is_polymorphic;
bool is_poly_specialized;
Type * polymorphic_params; // Type_Tuple
Type * polymorphic_parent;
i64 custom_align; // NOTE(bill): Only used in structs at the moment
i64 custom_align;
Entity * names;
bool are_offsets_set;
bool are_offsets_being_processed;
bool is_packed;
bool is_raw_union;
bool is_polymorphic;
bool is_poly_specialized;
bool is_soa;
Type *soa_elem;
i64 soa_count;
};
struct TypeUnion {
@@ -131,11 +141,11 @@ struct TypeUnion {
i64 variant_block_size;
i64 custom_align;
i64 tag_size;
bool is_polymorphic;
bool is_poly_specialized;
Type * polymorphic_params; // Type_Tuple
Type * polymorphic_parent;
Type * polymorphic_params; // Type_Tuple
Type * polymorphic_parent;
bool no_nil;
bool is_polymorphic;
bool is_poly_specialized;
};
#define TYPE_KINDS \
@@ -183,7 +193,9 @@ struct TypeUnion {
TYPE_KIND(Tuple, struct { \
Array<Entity *> variables; /* Entity_Variable */ \
Array<i64> offsets; \
bool are_offsets_being_processed; \
bool are_offsets_set; \
bool is_packed; \
}) \
TYPE_KIND(Proc, struct { \
Ast *node; \
@@ -194,9 +206,9 @@ struct TypeUnion {
i32 result_count; \
Array<Type *> abi_compat_params; \
Type * abi_compat_result_type; \
bool return_by_pointer; \
bool variadic; \
i32 variadic_index; \
bool variadic; \
bool abi_types_set; \
bool require_results; \
bool c_vararg; \
bool is_polymorphic; \
@@ -204,6 +216,7 @@ struct TypeUnion {
bool has_proc_default_values; \
bool has_named_results; \
bool diverging; /* no return */ \
bool return_by_pointer; \
u64 tags; \
isize specialization_count; \
ProcCallingConvention calling_convention; \
@@ -340,6 +353,9 @@ gb_global Type basic_types[] = {
{Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}},
{Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}},
{Type_Basic, {Basic_quaternion128, BasicFlag_Quaternion, 16, STR_LIT("quaternion128")}},
{Type_Basic, {Basic_quaternion256, BasicFlag_Quaternion, 32, STR_LIT("quaternion256")}},
{Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}},
{Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}},
{Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}},
@@ -375,6 +391,7 @@ gb_global Type basic_types[] = {
{Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}},
{Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, 0, STR_LIT("untyped float")}},
{Type_Basic, {Basic_UntypedComplex, BasicFlag_Complex | BasicFlag_Untyped, 0, STR_LIT("untyped complex")}},
{Type_Basic, {Basic_UntypedQuaternion, BasicFlag_Quaternion | BasicFlag_Untyped, 0, STR_LIT("untyped quaternion")}},
{Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}},
{Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}},
{Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}},
@@ -410,6 +427,9 @@ gb_global Type *t_f64 = &basic_types[Basic_f64];
gb_global Type *t_complex64 = &basic_types[Basic_complex64];
gb_global Type *t_complex128 = &basic_types[Basic_complex128];
gb_global Type *t_quaternion128 = &basic_types[Basic_quaternion128];
gb_global Type *t_quaternion256 = &basic_types[Basic_quaternion256];
gb_global Type *t_int = &basic_types[Basic_int];
gb_global Type *t_uint = &basic_types[Basic_uint];
gb_global Type *t_uintptr = &basic_types[Basic_uintptr];
@@ -444,6 +464,7 @@ gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool];
gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger];
gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat];
gb_global Type *t_untyped_complex = &basic_types[Basic_UntypedComplex];
gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion];
gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString];
gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil];
@@ -470,6 +491,7 @@ gb_global Type *t_type_info_integer = nullptr;
gb_global Type *t_type_info_rune = nullptr;
gb_global Type *t_type_info_float = nullptr;
gb_global Type *t_type_info_complex = nullptr;
gb_global Type *t_type_info_quaternion = nullptr;
gb_global Type *t_type_info_any = nullptr;
gb_global Type *t_type_info_typeid = nullptr;
gb_global Type *t_type_info_string = nullptr;
@@ -494,6 +516,7 @@ gb_global Type *t_type_info_integer_ptr = nullptr;
gb_global Type *t_type_info_rune_ptr = nullptr;
gb_global Type *t_type_info_float_ptr = nullptr;
gb_global Type *t_type_info_complex_ptr = nullptr;
gb_global Type *t_type_info_quaternion_ptr = nullptr;
gb_global Type *t_type_info_any_ptr = nullptr;
gb_global Type *t_type_info_typeid_ptr = nullptr;
gb_global Type *t_type_info_string_ptr = nullptr;
@@ -534,8 +557,27 @@ i64 type_offset_of (Type *t, i32 index);
gbString type_to_string (Type *type);
void init_map_internal_types(Type *type);
Type * bit_set_to_int(Type *t);
bool are_types_identical(Type *x, Type *y);
bool type_ptr_set_exists(PtrSet<Type *> *s, Type *t) {
if (ptr_set_exists(s, t)) {
return true;
}
// TODO(bill, 2019-10-05): This is very slow and it's probably a lot
// faster to cache types correctly
for_array(i, s->entries) {
Type *f = s->entries[i].ptr;
if (are_types_identical(t, f)) {
ptr_set_add(s, t);
return true;
}
}
return false;
}
Type *base_type(Type *t) {
for (;;) {
if (t == nullptr) {
@@ -922,6 +964,13 @@ bool is_type_complex(Type *t) {
}
return false;
}
bool is_type_quaternion(Type *t) {
t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Quaternion) != 0;
}
return false;
}
bool is_type_f32(Type *t) {
t = core_type(t);
if (t->kind == Type_Basic) {
@@ -1036,14 +1085,40 @@ Type *core_array_type(Type *t) {
return t;
}
// NOTE(bill): type can be easily compared using memcmp
bool is_type_simple_compare(Type *t) {
t = core_type(t);
switch (t->kind) {
case Type_Array:
return is_type_simple_compare(t->Array.elem);
case Type_Basic:
if (t->Basic.flags & (BasicFlag_Integer|BasicFlag_Float|BasicFlag_Complex|BasicFlag_Rune|BasicFlag_Pointer)) {
return true;
}
return false;
case Type_Pointer:
case Type_Proc:
case Type_BitSet:
case Type_BitField:
return true;
}
return false;
}
Type *base_complex_elem_type(Type *t) {
t = core_type(t);
if (is_type_complex(t)) {
if (t->kind == Type_Basic) {
switch (t->Basic.kind) {
// case Basic_complex32: return t_f16;
case Basic_complex64: return t_f32;
case Basic_complex128: return t_f64;
case Basic_UntypedComplex: return t_untyped_float;
// case Basic_complex32: return t_f16;
case Basic_complex64: return t_f32;
case Basic_complex128: return t_f64;
case Basic_quaternion128: return t_f32;
case Basic_quaternion256: return t_f64;
case Basic_UntypedComplex: return t_untyped_float;
case Basic_UntypedQuaternion: return t_untyped_float;
}
}
GB_PANIC("Invalid complex type");
@@ -1058,6 +1133,10 @@ bool is_type_union(Type *t) {
t = base_type(t);
return t->kind == Type_Union;
}
bool is_type_soa_struct(Type *t) {
t = base_type(t);
return t->kind == Type_Struct && t->Struct.is_soa;
}
bool is_type_raw_union(Type *t) {
t = base_type(t);
@@ -1098,12 +1177,11 @@ bool is_type_integer_endian_big(Type *t) {
return is_type_integer_endian_big(bit_set_to_int(t));
} else if (t->kind == Type_Pointer) {
return is_type_integer_endian_big(&basic_types[Basic_uintptr]);
} else {
GB_PANIC("Unsupported type: %s", type_to_string(t));
}
return build_context.endian_kind == TargetEndian_Big;
}
bool is_type_integer_endian_little(Type *t) {
t = core_type(t);
if (t->kind == Type_Basic) {
@@ -1117,11 +1195,24 @@ bool is_type_integer_endian_little(Type *t) {
return is_type_integer_endian_little(bit_set_to_int(t));
} else if (t->kind == Type_Pointer) {
return is_type_integer_endian_little(&basic_types[Basic_uintptr]);
} else {
GB_PANIC("Unsupported type: %s", type_to_string(t));
}
return build_context.endian_kind == TargetEndian_Little;
}
bool is_type_endian_big(Type *t) {
return is_type_integer_endian_big(t);
}
bool is_type_endian_little(Type *t) {
return is_type_integer_endian_little(t);
}
bool is_type_dereferenceable(Type *t) {
if (is_type_rawptr(t)) {
return false;
}
return is_type_pointer(t);
}
bool is_type_different_to_arch_endianness(Type *t) {
switch (build_context.endian_kind) {
@@ -1283,6 +1374,19 @@ bool is_type_indexable(Type *t) {
return false;
}
bool is_type_sliceable(Type *t) {
Type *bt = base_type(t);
switch (bt->kind) {
case Type_Basic:
return bt->Basic.kind == Basic_string;
case Type_Array:
case Type_Slice:
case Type_DynamicArray:
return true;
}
return false;
}
bool is_type_polymorphic_record(Type *t) {
t = base_type(t);
@@ -1468,7 +1572,7 @@ bool type_has_nil(Type *t) {
case Type_Map:
return true;
case Type_Union:
return true;
return !t->Union.no_nil;
case Type_Struct:
return false;
case Type_Opaque:
@@ -1625,7 +1729,8 @@ bool are_types_identical(Type *x, Type *y) {
case Type_Union:
if (y->kind == Type_Union) {
if (x->Union.variants.count == y->Union.variants.count &&
x->Union.custom_align == y->Union.custom_align) {
x->Union.custom_align == y->Union.custom_align &&
x->Union.no_nil == y->Union.no_nil) {
// NOTE(bill): zeroth variant is nullptr
for_array(i, x->Union.variants) {
if (!are_types_identical(x->Union.variants[i], y->Union.variants[i])) {
@@ -1661,6 +1766,12 @@ bool are_types_identical(Type *x, Type *y) {
if (xf_is_using ^ yf_is_using) {
return false;
}
if (x->Struct.tags.count != y->Struct.tags.count) {
return false;
}
if (x->Struct.tags.count > 0 && x->Struct.tags[i] != y->Struct.tags[i]) {
return false;
}
}
return true;
}
@@ -1681,7 +1792,8 @@ bool are_types_identical(Type *x, Type *y) {
case Type_Tuple:
if (y->kind == Type_Tuple) {
if (x->Tuple.variables.count == y->Tuple.variables.count) {
if (x->Tuple.variables.count == y->Tuple.variables.count &&
x->Tuple.is_packed == y->Tuple.is_packed) {
for_array(i, x->Tuple.variables) {
Entity *xe = x->Tuple.variables[i];
Entity *ye = y->Tuple.variables[i];
@@ -1761,6 +1873,7 @@ Type *default_type(Type *type) {
case Basic_UntypedInteger: return t_int;
case Basic_UntypedFloat: return t_f64;
case Basic_UntypedComplex: return t_complex128;
case Basic_UntypedQuaternion: return t_quaternion256;
case Basic_UntypedString: return t_string;
case Basic_UntypedRune: return t_rune;
}
@@ -1778,7 +1891,11 @@ i64 union_variant_index(Type *u, Type *v) {
for_array(i, u->Union.variants) {
Type *vt = u->Union.variants[i];
if (are_types_identical(v, vt)) {
return cast(i64)(i+1);
if (u->Union.no_nil) {
return cast(i64)(i+0);
} else {
return cast(i64)(i+1);
}
}
}
return 0;
@@ -2081,6 +2198,19 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
sel.index.count = prev_count;
}
}
bool is_soa = type->Struct.is_soa;
bool is_soa_of_array = is_soa && is_type_array(type->Struct.soa_elem);
if (is_soa_of_array) {
String mapped_field_name = {};
if (field_name == "r") mapped_field_name = str_lit("x");
else if (field_name == "g") mapped_field_name = str_lit("y");
else if (field_name == "b") mapped_field_name = str_lit("z");
else if (field_name == "a") mapped_field_name = str_lit("w");
return lookup_field_with_selection(type, mapped_field_name, is_type, sel, allow_blank_ident);
}
} else if (type->kind == Type_BitField) {
for_array(i, type->BitField.fields) {
Entity *f = type->BitField.fields[i];
@@ -2125,19 +2255,22 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
if (type->Array.count <= 4) {
// HACK(bill): Memory leak
switch (type->Array.count) {
#define _ARRAY_FIELD_CASE(_length, _name) \
case (_length): \
if (field_name == _name) { \
#define _ARRAY_FIELD_CASE_IF(_length, _name) \
if (field_name == (_name)) { \
selection_add_index(&sel, (_length)-1); \
sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
return sel; \
} \
}
#define _ARRAY_FIELD_CASE(_length, _name0, _name1) \
case (_length): \
_ARRAY_FIELD_CASE_IF(_length, _name0); \
_ARRAY_FIELD_CASE_IF(_length, _name1); \
/*fallthrough*/
_ARRAY_FIELD_CASE(4, "w");
_ARRAY_FIELD_CASE(3, "z");
_ARRAY_FIELD_CASE(2, "y");
_ARRAY_FIELD_CASE(1, "x");
_ARRAY_FIELD_CASE(4, "w", "a");
_ARRAY_FIELD_CASE(3, "z", "b");
_ARRAY_FIELD_CASE(2, "y", "g");
_ARRAY_FIELD_CASE(1, "x", "r");
default: break;
#undef _ARRAY_FIELD_CASE
@@ -2248,7 +2381,9 @@ i64 type_size_of(Type *t) {
return 0;
}
// NOTE(bill): Always calculate the size when it is a Type_Basic
if (t->kind != Type_Basic && t->cached_size >= 0) {
if (t->kind == Type_Named && t->cached_size >= 0) {
} else if (t->kind != Type_Basic && t->cached_size >= 0) {
return t->cached_size;
}
TypePath path = {0};
@@ -2263,7 +2398,9 @@ i64 type_align_of(Type *t) {
return 1;
}
// NOTE(bill): Always calculate the size when it is a Type_Basic
if (t->kind != Type_Basic && t->cached_align > 0) {
if (t->kind == Type_Named && t->cached_align >= 0) {
} if (t->kind != Type_Basic && t->cached_align > 0) {
return t->cached_align;
}
@@ -2297,6 +2434,8 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
case Basic_complex64: case Basic_complex128:
return type_size_of_internal(t, path) / 2;
case Basic_quaternion128: case Basic_quaternion256:
return type_size_of_internal(t, path) / 4;
}
} break;
@@ -2482,9 +2621,9 @@ bool type_set_offsets(Type *t) {
}
} else if (is_type_tuple(t)) {
if (!t->Tuple.are_offsets_set) {
t->Struct.are_offsets_being_processed = true;
t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, false, false);
t->Struct.are_offsets_being_processed = false;
t->Tuple.are_offsets_being_processed = true;
t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false);
t->Tuple.are_offsets_being_processed = false;
t->Tuple.are_offsets_set = true;
return true;
}
@@ -2907,35 +3046,54 @@ gbString write_type_to_string(gbString str, Type *type) {
isize comma_index = 0;
for_array(i, type->Tuple.variables) {
Entity *var = type->Tuple.variables[i];
if (var != nullptr) {
if (var->kind == Entity_Constant) {
// Ignore
continue;
}
if (comma_index++ > 0) {
str = gb_string_appendc(str, ", ");
}
if (var->kind == Entity_Variable) {
if (var->flags&EntityFlag_CVarArg) {
str = gb_string_appendc(str, "#c_vararg ");
}
if (var->flags&EntityFlag_Ellipsis) {
Type *slice = base_type(var->type);
str = gb_string_appendc(str, "..");
GB_ASSERT(var->type->kind == Type_Slice);
str = write_type_to_string(str, slice->Slice.elem);
} else {
str = write_type_to_string(str, var->type);
}
if (var == nullptr) {
continue;
}
String name = var->token.string;
if (var->kind == Entity_Constant) {
str = gb_string_appendc(str, "$");
str = gb_string_append_length(str, name.text, name.len);
if (!is_type_untyped(var->type)) {
str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, var->type);
str = gb_string_appendc(str, " = ");
str = write_exact_value_to_string(str, var->Constant.value);
} else {
GB_ASSERT(var->kind == Entity_TypeName);
if (var->type->kind == Type_Generic) {
str = gb_string_appendc(str, "type/");
str = gb_string_appendc(str, "=");
str = write_exact_value_to_string(str, var->Constant.value);
}
continue;
}
if (comma_index++ > 0) {
str = gb_string_appendc(str, ", ");
}
if (var->kind == Entity_Variable) {
if (var->flags&EntityFlag_CVarArg) {
str = gb_string_appendc(str, "#c_vararg ");
}
if (var->flags&EntityFlag_Ellipsis) {
Type *slice = base_type(var->type);
str = gb_string_appendc(str, "..");
GB_ASSERT(var->type->kind == Type_Slice);
str = write_type_to_string(str, slice->Slice.elem);
} else {
str = write_type_to_string(str, var->type);
}
} else {
GB_ASSERT(var->kind == Entity_TypeName);
if (var->type->kind == Type_Generic) {
str = gb_string_appendc(str, "typeid/");
str = write_type_to_string(str, var->type);
} else {
if (var->kind == Entity_TypeName) {
str = gb_string_appendc(str, "$");
str = gb_string_append_length(str, name.text, name.len);
str = gb_string_appendc(str, "=");
str = write_type_to_string(str, var->type);
} else {
str = gb_string_appendc(str, "type");
str = gb_string_appendc(str, "typeid");
}
}
}
-1
View File
@@ -2,7 +2,6 @@
#pragma warning(disable: 4245)
extern "C" {
#include "utf8proc/utf8proc.h"
#include "utf8proc/utf8proc.c"
}
#pragma warning(pop)
-1
View File
@@ -40,7 +40,6 @@
* Implementation of libutf8proc.
*/
#include "utf8proc.h"
#include "utf8proc_data.c"