Compare commits

..

1331 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
gingerBill b0dd3ac599 v0.10.0 2019-06-02 12:27:36 +01:00
gingerBill b38a8cfb12 Move internal 128-bit stuff to a windows specific file 2019-06-01 12:26:54 +01:00
gingerBill 4c79b52867 Update README.md 2019-05-30 18:08:35 +01:00
gingerBill 6dba05b00d Update README.md 2019-05-30 18:07:54 +01:00
gingerBill 32a29d627a Create FUNDING.yml 2019-05-30 17:42:15 +01:00
gingerBill caf9bc6be9 Pedantic conversions on query data 2019-05-29 16:59:28 +01:00
gingerBill 654740d5b1 Fixes to ABI 2019-05-29 16:49:26 +01:00
gingerBill b894e2b378 Fix bit set size with 128-bit integers 2019-05-28 20:57:02 +01:00
gingerBill c40acd008e Add i128/u128 support for bit sets 2019-05-28 20:53:56 +01:00
gingerBill 3d2279fba0 Support 128-bit integers i128 u128 2019-05-28 20:27:45 +01:00
gingerBill 2b080dbbc2 sync_atomic_* make most ordering parameters compile-time constant 2019-05-28 15:57:06 +01:00
gingerBill 9cadd58465 Improve tokenizer slightly 2019-05-28 14:44:32 +01:00
gingerBill 65e9b4d5f0 Update parsers 2019-05-28 12:55:55 +01:00
gingerBill fb3d73cb20 Make core library use a..<b rather than doing a..b-1 2019-05-28 12:52:20 +01:00
gingerBill 222941727f Add ..< operator for ranges; Add extra checking for bit set assignments 2019-05-28 12:45:20 +01:00
gingerBill 5697d6df74 -go-to-definitions (OGTD file format) 2019-05-26 15:16:45 +01:00
gingerBill 426c1ed6f4 -compact flag for 'odin query' 2019-05-25 20:28:49 +01:00
gingerBill 458ec5922e odin query
Output .json file containing information about the program
2019-05-25 20:24:19 +01:00
gingerBill f5fdd031f9 Fix polymorphic procedure return by pointer values #374 2019-05-19 10:45:27 +01:00
gingerBill ceb58ae04f Change import name rules 2019-05-19 10:01:35 +01:00
gingerBill 868603f617 Merge pull request #375 from Zilarrezko/master
make_builder function now properly uses given allocator
2019-05-19 09:55:03 +01:00
Zilarrezko d2faa9bef1 make_builder function now properly uses given allocator 2019-05-18 18:57:34 -07:00
gingerBill b1663a14e9 Add an error for C-style pointer selector expressions using '->' when parsing 2019-05-09 22:59:17 +01:00
gingerBill 3fc60930e6 Fix constant representability rules 2019-05-09 22:46:50 +01:00
gingerBill 665734f04f Fix package odin/parser 2019-05-09 16:35:35 +01:00
gingerBill 16f3bc2c0b Allow comparisons with bit field values 2019-05-09 13:18:57 +01:00
gingerBill 71a733e3b5 Allow booleans to be assigned to a 1-bit bit field value 2019-05-09 13:04:15 +01:00
gingerBill a66612e8ae Remove test code 2019-05-09 11:07:26 +01:00
gingerBill 00c0ce45b3 Fix bug with clamp 2019-05-06 18:29:22 +01:00
gingerBill ab0afa548b Fix ||= and &&= 2019-05-06 11:32:35 +01:00
gingerBill ea1690b7a1 Improve type inference for variadic parameters 2019-05-04 14:01:04 +01:00
gingerBill a5ff983266 Fix parapoly related bugs #370 2019-05-04 13:11:56 +01:00
gingerBill a46a1f5f34 Minor change to bit_field assignment rules 2019-05-04 13:02:15 +01:00
gingerBill 40135cbc66 Add float64_range and float32_range to package math/rand 2019-04-28 20:35:14 +01:00
gingerBill c61fd3a70a Modify type_set_offsets to patch minor bug 2019-04-28 20:34:51 +01:00
gingerBill 45fbc4e8c5 Add #load to package odin/parser 2019-04-21 22:36:52 +01:00
gingerBill 9ce8f124bb Slight change to determine_path_from_string rules 2019-04-20 16:52:09 +01:00
gingerBill 63bbb9b62f Change the file name rules for imports (use / rather than \ on windows) 2019-04-20 16:47:28 +01:00
gingerBill 56c4039e72 #load directive (request from #368) (Basic implementation) 2019-04-20 15:05:35 +01:00
gingerBill 0755dfbd5d Merge branch 'master' of https://github.com/odin-lang/Odin 2019-04-19 11:39:12 +01:00
gingerBill 2780f82f30 Fix is_operand_value to support more addressing modes 2019-04-19 11:39:01 +01:00
Jeroen van Rijn 5dcb5c2ba3 Merge pull request #367 from kevinw/fix-json-parsing
Fix some JSON parsing bugs.
2019-04-06 16:35:46 +02:00
Jeroen van Rijn 9d552d04ea Merge pull request #358 from kevinw/master
Fix some -vet warnings; change import to core:math/bits
2019-04-06 16:34:01 +02:00
Kevin Watters 88e1b93786 Fix som JSON parsing bugs.
- Single digit integer keys `{"a": 5}`
` Negative float keys `{"b": -42.0}`
2019-04-06 09:24:53 -04:00
Kevin Watters 62f5eb5bca Fix som JSON parsing bugs.
- Single digit integer keys `{"a": 5}`
` Negative float keys `{"b": -42.0}`
2019-04-06 09:19:09 -04:00
Kevin Watters 6ab471ff87 Merge branch 'master' of github.com:odin-lang/Odin 2019-04-06 08:41:56 -04:00
Jeroen van Rijn 155b138aa4 call_external_process cleanup 2019-04-05 13:18:50 +02:00
Jeroen van Rijn a730b04bf1 Add helpers to launch process and open website. 2019-04-05 13:02:49 +02:00
Kevin Watters 957e1e1f07 Merge branch 'master' of github.com:odin-lang/Odin 2019-04-01 09:34:25 -04:00
gingerBill 133f88406f The Proposal Process 2019-03-31 23:50:56 +01:00
gingerBill ecd2eacd75 Remove dead keywords; Fix min and max for enum types 2019-03-31 22:35:05 +01:00
gingerBill 2614830c69 Minor code organization change 2019-03-31 18:29:57 +01:00
Kevin Watters 381fbd3daf Merge branch 'master' of github.com:odin-lang/Odin 2019-03-31 12:03:22 -04:00
gingerBill dd9113786c Remove -keep-temp-files from the build.bat 2019-03-31 13:06:01 +01:00
gingerBill 1354f53d02 Remove derived from context; Fix parsing issue for typeid specializations in record parameters; Fix runtime printing of types 2019-03-31 11:58:54 +01:00
gingerBill 564e85ee29 Modify ir_generate_array name logic slightly 2019-03-31 11:22:27 +01:00
gingerBill ef04d13337 Use context for assert-based things. 2019-03-30 15:10:40 +00:00
gingerBill 68d4bde82f Overrideable stdin, stdout, stderr at the context level 2019-03-30 14:51:42 +00:00
gingerBill a019059975 Fix -vet for demo.odin 2019-03-30 10:52:53 +00:00
gingerBill 7580ec494b Disallow ambiguous singularly variadic polymorphic parameters #361 2019-03-30 10:43:53 +00:00
gingerBill a9b20c29b1 Fix slicing issue; Change path of math/bits in package json #363 2019-03-30 10:17:31 +00:00
Kevin Watters 76a2807b56 Remove unused import from demo.odin. 2019-03-26 11:20:49 -04:00
Kevin Watters 14ff561f6c Merge branch 'master' of github.com:odin-lang/Odin 2019-03-26 11:17:58 -04:00
gingerBill 1fd677b42e Remove *_remove from demo and use built-in versions 2019-03-25 21:29:21 +00:00
gingerBill 6b18b90222 Fix possible buffer overflows in package strconv 2019-03-25 21:26:23 +00:00
gingerBill 9e6d488063 Modify slice_expr_error_* logic to change depending on which parameters are passed 2019-03-25 21:20:12 +00:00
gingerBill 4a15689776 Remove bounds checks for slice expressions with both indices empty 2019-03-25 21:00:45 +00:00
gingerBill c785c3569f Fix runtime.*_expr_error error 2019-03-25 20:42:47 +00:00
Kevin Watters e6f9b4fb11 Fix some -vet warnings; change import to core:math/bits 2019-03-25 09:23:46 -04:00
gingerBill b978959fae Improve package strconv 2019-03-24 20:58:01 +00:00
gingerBill 8b09ab6fe7 Move core:bits to core:math/bits 2019-03-24 20:39:01 +00:00
gingerBill 2347dca9d9 Improve package math/rand 2019-03-24 20:36:39 +00:00
gingerBill 2ada90e094 Improve a tokenizer error message; Add extra tokens for in and notin for fun! 2019-03-24 19:12:41 +00:00
gingerBill a137a06b00 Allow implicit selectors to unions with only one enum variant 2019-03-24 12:14:45 +00:00
gingerBill b1684fe455 @(private) for foreign blocks; Improve foreign signature similarity rules 2019-03-24 11:58:26 +00:00
gingerBill 886054f0f8 Add error message for when trying to assign a type to a variable. 2019-03-22 13:55:29 +00:00
gingerBill 0e1cfa5a0a Disallow casting to and from cstring/pointers
TODO: get a better error message
2019-03-19 20:34:06 +00:00
gingerBill 400558abcd Fix fmt.println a rawptr causes access violation #356 2019-03-19 20:27:29 +00:00
gingerBill d75634ff5e Merge branch 'master' of https://github.com/odin-lang/Odin 2019-03-19 20:22:32 +00:00
gingerBill 0c04b9398a Fix bug with assigning certain integers to a bit_field #353 2019-03-19 20:22:25 +00:00
Jeroen van Rijn 290c111206 Merge pull request #355 from mattt-b/master
Replace calls to deprecated string functions on linux
2019-03-18 15:27:07 +01:00
matt 314d5a778e Replace calls to deprecated string functions on linux 2019-03-18 07:13:52 -07:00
Jeroen van Rijn dc706d8a6b Vet CEL 2019-03-17 23:27:13 +01:00
gingerBill a6fb2dd587 Fix Erroneous redeclaration error with using import #354 2019-03-17 20:43:54 +00:00
gingerBill 4e93b70f8a Fix bit_field scoping bug 2019-03-17 14:48:32 +00:00
gingerBill 1eaa47ebae Fix using import behaviour - #352 2019-03-17 13:03:39 +00:00
gingerBill 3a31444656 Minor changes to fmt of auto deferencing 2019-03-16 11:00:37 +00:00
gingerBill f7efaf2ba2 fmt.printf support for pointer to container (one level deep) 2019-03-16 00:10:57 +00:00
gingerBill 14c6f2f258 Add extra pointer printing options to fmt.printf 2019-03-15 23:49:47 +00:00
gingerBill 231f3cc15a %h support in fmt.printf for hexadecimal floats 2019-03-15 23:22:05 +00:00
gingerBill 332e598357 %e and %g support in fmt.printf 2019-03-15 23:13:06 +00:00
gingerBill 716373836c Disallow attributes on alias declarations 2019-03-15 19:01:36 +00:00
gingerBill fdb60b2d51 Improve package strings 2019-03-15 18:30:39 +00:00
gingerBill 885c5dc8b7 Fix issue with deferred_* attributes 2019-03-15 16:39:49 +00:00
gingerBill 394baa9ddd Merge branch 'master' of https://github.com/odin-lang/Odin 2019-03-15 15:41:15 +00:00
gingerBill 3d86fc2f2f Minor adjustments 2019-03-15 15:41:06 +00:00
Jeroen van Rijn 61b07335d8 Fix build error on !Windows. 2019-03-15 07:37:20 +01:00
gingerBill 712744ef36 Fix ir_copy_value_to_ptr usage in ir_emit_call #350 2019-03-14 23:41:48 +00:00
gingerBill dbcd49acfc Add -pdb-name for custom names of PDBs 2019-03-14 23:26:32 +00:00
gingerBill 291bf0c143 Fix #raw_union bug caused by typo #349 2019-03-14 23:25:55 +00:00
gingerBill bdab5e00da Minor code clean up 2019-03-11 19:52:40 +00:00
gingerBill e781056df1 Merge branch 'master' of https://github.com/odin-lang/Odin 2019-03-11 09:32:24 +00:00
gingerBill b08d944c33 Fix typo in demo.odin 2019-03-11 09:32:15 +00:00
Jeroen van Rijn 4f24f1172e Stylistic improvements to new comdlg helpers. 2019-03-09 13:48:48 +01:00
Jeroen van Rijn 4446a1431a Merge pull request #348 from Kelimion/master
Add win32.get_cwd for current working directory and convenience functions for open + save dialogs.
2019-03-09 12:51:14 +01:00
Jeroen van Rijn 090937f8af Add convenience functions for open + save dialogs. 2019-03-09 12:45:17 +01:00
Jeroen van Rijn d852b0c948 Add win32.get_cwd to return the current working directory 2019-03-09 11:08:50 +01:00
gingerBill 007a7989b8 Add implicit selector expression examples to demo.odin 2019-03-06 20:06:37 +00:00
gingerBill 5c04800831 Add type inference to index expressions for maps 2019-03-06 20:01:46 +00:00
gingerBill c634d4a96d Using implicit selector expressions in the core library 2019-03-06 19:13:50 +00:00
gingerBill c67ea97845 Add implicit selector expressions for in/notin 2019-03-06 19:08:37 +00:00
gingerBill 15d3f4c190 Allow implicit selector expressions in switch statements 2019-03-06 16:23:50 +00:00
gingerBill 1b3ec66fa2 Merge branch 'master' of https://github.com/odin-lang/Odin 2019-03-06 16:19:55 +00:00
gingerBill ad3b6ab718 Implicit Selector Expressions: .A 2019-03-06 16:19:47 +00:00
Jeroen van Rijn 8c618225bf Merge pull request #347 from Kelimion/master
Fix typo in `cel` tokeniser.
2019-03-04 13:46:51 +01:00
Jeroen van Rijn 1f5ab0b5f1 Fix typo in cel tokeniser. 2019-03-04 13:41:47 +01:00
gingerBill 1652d5033b Merge branch 'master' of https://github.com/odin-lang/Odin 2019-03-03 12:09:06 +00:00
gingerBill 9b4b20e8b1 package dynlib 2019-03-03 12:08:26 +00:00
Jeroen van Rijn 8fb8b5ed7e Merge pull request #346 from Kelimion/fix-issue-345
Fix #345: panic when using enum as map key
2019-03-03 13:00:00 +01:00
Jeroen van Rijn 7bd86bb3ec well, that was a stupid copy/paste bug 2019-03-02 13:24:11 +01:00
Jeroen van Rijn b6d6eb6ae2 Fix #345: Panic when using enum as map key
Also add a little map demo.
2019-03-02 13:21:01 +01:00
Jeroen van Rijn a126d2ba16 Merge remote-tracking branch 'upstream/master' into fix-issue-345 2019-03-02 12:31:45 +01:00
Jeroen van Rijn 6faab8e47a Fix #345: panic when using enum as map key 2019-02-26 13:51:56 +01:00
gingerBill 76a6757ee9 Add os.file_size_from_path 2019-02-25 18:03:44 +00:00
gingerBill 0c8746ada6 Add support for custom keywords in core:odin/* packages 2019-02-25 12:41:43 +00:00
gingerBill a0c81c79ad Fix bugs: Array Literals with constant elements; IR printing of raw procedure types 2019-02-24 10:30:58 +00:00
gingerBill cdfaa643cc Reimplement -collection; remove static from Odin tokenizer/parser in core library 2019-02-23 23:30:03 +00:00
gingerBill 989cc893ef FIX TYPO! 2019-02-23 23:25:46 +00:00
gingerBill 2878cd8241 New build flag: -define:foo=123 2019-02-23 23:21:27 +00:00
gingerBill a9ab90bd24 Make static an attribute rather than a keyword prefix 2019-02-23 22:17:27 +00:00
gingerBill e551d2b25e Replace foreign export {} with @export 2019-02-23 21:39:47 +00:00
gingerBill 38ae2e9efa Allow basic arithmetic operations for vectors 2019-02-23 18:05:41 +00:00
gingerBill 684945ea57 Fix calling conventions for simd vector types 2019-02-23 17:45:30 +00:00
gingerBill 4c51384ad6 intrinsics.vector type (Experimental) 2019-02-23 16:44:16 +00:00
gingerBill 64bd884d94 Add "none" calling convention 2019-02-23 14:42:44 +00:00
gingerBill a07232ea63 Fix missing break in switch statement for deferred_in in the IR 2019-02-23 14:11:48 +00:00
gingerBill 79b585ada8 Add minor additions to mem, sync, and sys/win32 2019-02-21 21:45:33 +00:00
gingerBill f917935f9d Disallow compound literals for struct #raw_union (fix) 2019-02-19 10:04:36 +00:00
gingerBill dbd0638853 Fix untyped ternary string IR conversion 2019-02-14 11:11:05 +00:00
gingerBill 53d8216311 Reorganize package mem 2019-02-10 22:15:34 +00:00
gingerBill 6a0c3d5599 Add default_parser procedure to package odin_parser 2019-02-10 22:05:18 +00:00
gingerBill 9647fb2a4b Add Stack and Small_Stack allocators to package mem 2019-02-10 22:04:58 +00:00
gingerBill 42f936742e Add extra dead code elimination 2019-02-10 21:23:02 +00:00
gingerBill e2d4667639 Fix data layout issue on Windows; Remove unused loads in SSA 2019-02-10 20:51:19 +00:00
gingerBill b74d828af7 Merge branch 'master' of https://github.com/odin-lang/Odin 2019-02-09 22:34:37 +00:00
gingerBill e16409f88a Fix package odin_parser bugs 2019-02-09 22:34:27 +00:00
thebirk 6571f07c7e Fixed typo in copy_sign_f64. 2019-02-08 12:58:30 +01:00
gingerBill 4b7a09b92e Merge branch 'master' of https://github.com/odin-lang/Odin 2019-02-06 22:45:04 +00:00
gingerBill 26fb1fa18c Fix lead_comment issue is package odin_parser 2019-02-06 22:44:54 +00:00
Mikkel Hjortshøj 24c43d33bb Export LLVM path on macOS (CI) 2019-02-06 19:08:32 +01:00
Mikkel Hjortshøj 7343f0c7ff Fix recursive variable in makefile on macOS 2019-02-06 18:56:02 +01:00
Mikkel Hjortshøj 3c8cda514b Fix makefile for macOS 2019-02-06 18:49:21 +01:00
gingerBill bc954df80e Merge branch 'master' of https://github.com/odin-lang/Odin 2019-02-06 16:07:32 +00:00
gingerBill e1ae359a77 Replace redundant code 2019-02-06 16:06:48 +00:00
Mikkel Hjortshoej c9602953aa last fixes to bats and README 2019-02-06 15:53:40 +01:00
Mikkel Hjortshoej 0185b43c2f Create CI files 2019-02-06 15:53:40 +01:00
gingerBill bc5c37ebb1 Extra checks to reduce mem.zero calls 2019-02-06 13:47:52 +00:00
gingerBill 0133dd9034 Merge branch 'master' of https://github.com/odin-lang/Odin 2019-02-06 13:33:52 +00:00
gingerBill a194aa5a9e Minimize mem.zero use 2019-02-06 13:33:31 +00:00
gingerBill 766f3e259f Merge pull request #334 from odin-lang/ThisDrunkDane-patch-1
Add issue templates
2019-02-05 22:21:27 +00:00
Mikkel Hjortshøj 6092cc0497 Add issue templates 2019-02-05 21:19:56 +01:00
gingerBill fa5d00521b Remove inline from many of the mem.* procedures 2019-02-04 12:15:51 +00:00
gingerBill d1e29400d3 Merge pull request #331 from thebirk/fix-out-linux
Fixed macOS not compiling
2019-02-02 23:14:26 +00:00
gingerBill 2dc7aaec82 Merge pull request #332 from thebirk/fix-big-string-printing
Fix #322, now correctly printing big strings.
2019-02-02 23:14:08 +00:00
thebirk b7242f9d4b Fix #322, now correctly printing big strings. 2019-02-02 00:11:41 +01:00
thebirk 7ea7fc10db Fixed macOS not compiling. 2019-02-01 15:33:27 +01:00
gingerBill 141da818ba Merge pull request #330 from thebirk/fix-out-linux
Fixed -out dropping extension on linux. Issue #305
2019-02-01 14:25:36 +00:00
thebirk dc3d62d437 Fixed -out dropping extension on linux. 2019-02-01 15:12:20 +01:00
gingerBill dee28d998f Allow for @indent for attributes that don't require any parameters; Add -ignore-unknown-attributes 2019-01-30 14:24:14 +00:00
gingerBill 96ef6aa7f3 Merge pull request #327 from Tetralux/tet/pass-args-to-run
Provide a way to pass arguments to compiled executable during 'odin run program.odin'.
2019-01-29 22:12:01 +00:00
gingerBill 238a40321a inline certain mem.* procedures 2019-01-29 22:08:48 +00:00
gingerBill 1aea59a0fc Fix typo in parser.cpp 2019-01-29 21:53:36 +00:00
gingerBill c6dee52abe Finish up package odin_parser 2019-01-29 21:53:16 +00:00
Tetralux 1e180d611d Allow 'odin run program.odin -- <args-for-program.exe> 2019-01-28 17:58:48 +00:00
gingerBill e452765d28 Patch minor IR bug 2019-01-28 12:13:37 +00:00
gingerBill 2b80683fc7 Vet odin/* packages 2019-01-27 19:01:33 +00:00
gingerBill 5f840ea2fc package odin_parser 2019-01-26 20:17:03 +00:00
gingerBill c72427fd1e package odin_parser 2019-01-26 20:14:06 +00:00
gingerBill 44b959648c Pass any and union "by pointer" to make the tag a pointer 2019-01-26 20:13:43 +00:00
gingerBill a96bf08266 Fix tokenizer.odin bugs 2019-01-24 21:40:09 +00:00
gingerBill ebaf48c07d Fix subtyping rules for heavily nested using in structs 2019-01-24 21:17:30 +00:00
gingerBill c197a27185 Merge branch 'master' of https://github.com/odin-lang/Odin 2019-01-24 15:53:27 +00:00
gingerBill 5ccccf8816 Add package odin/token; package odin/tokenizer 2019-01-24 15:53:17 +00:00
gingerBill 345e790f52 Remove dead code 2019-01-24 15:52:51 +00:00
gingerBill fd529b97be Merge pull request #324 from Tetralux/tet/ptr-endianness
Fix assert when printing IR of pointer with endianness
2019-01-18 14:24:19 +00:00
Jeroen van Rijn be1a3488a4 Initial support for GetVersionExA 2019-01-18 13:37:40 +01:00
Tetralux 46c610d6e5 Fix printing IR of integer as a pointer with endianness.
When converting an integer value into a pointer and writing out the IR
for it in 'ir_print_exact_value', 'is_type_integer_endian_{little,big}'
did not correct handle being asked about pointer types.

They now reply with whether the endianness of 'uintptr' matches the
endianness being asked about.
2019-01-16 17:22:25 +00:00
gingerBill db2eff6847 Fix typo in json/parser.odin 2019-01-14 20:44:27 +00:00
gingerBill e047d9eb5e Update package json parser to store the end position on the values 2019-01-14 15:51:52 +00:00
gingerBill 3113e8c892 Minimize buffer size for write_u64 and write_i64 2019-01-13 21:40:18 +00:00
gingerBill 19e37c852e Change deferred_* scoping behaviour for if 2019-01-13 20:51:26 +00:00
gingerBill 8fc24fd6f2 Replace deferred with deferred_none, deferred_in, deferred_out 2019-01-13 19:34:08 +00:00
gingerBill 493f11521d Check for _ for import names too 2019-01-13 17:44:38 +00:00
gingerBill 3363e2c199 Change import name determination rules
Use custom name if given, then directory name, then the package name
2019-01-13 11:54:25 +00:00
gingerBill cf94d1735d Add extra explicit entity usage 2019-01-13 11:24:03 +00:00
gingerBill d9245a6af3 Update Makefile to reflect build.sh 2019-01-13 11:19:01 +00:00
gingerBill d453b9a5b1 Fix checking _ constant declarations with a procedure 2019-01-10 11:22:52 +00:00
gingerBill 5af20aa467 Make encoding/json use []byte rather than string 2019-01-07 23:08:38 +00:00
gingerBill cd2c4c02e1 Merge pull request #320 from thebirk/add-diff-to-time
Added diff() to core:time.
2019-01-07 15:52:33 +00:00
gingerBill 6c21e99832 json.marshal 2019-01-06 23:32:50 +00:00
gingerBill 08598b9425 Support NaN and Infinity for JSON5 2019-01-06 22:25:02 +00:00
gingerBill 6295f6747f strings.write_quoted_string 2019-01-06 22:16:14 +00:00
gingerBill 64f84ef9a3 fmt.printf("%q", str); (quotes strings) 2019-01-06 22:11:45 +00:00
gingerBill d1b9f3ac74 package json; JSON5 support 2019-01-06 21:48:13 +00:00
gingerBill d732a51587 Add json.is_valid file 2019-01-06 20:44:52 +00:00
gingerBill 9487f8c92e Add json.is_valid 2019-01-06 20:44:39 +00:00
gingerBill c5def60224 Begin work on package json 2019-01-06 20:37:12 +00:00
thebirk ca2220214e Added diff() to core:time. 2019-01-06 19:40:57 +01:00
gingerBill 6e6a053823 Add strings.destroy_builder 2019-01-06 17:59:42 +00:00
gingerBill 686e0ef3d1 Merge pull request #319 from mattt-b/master
Vet time_linux
2019-01-06 15:22:21 +00:00
gingerBill 594238a86c Reorganize fmt and strings; Replace fmt.String_Buffer with strings.Builder 2019-01-06 14:41:42 +00:00
matt c60766f8e6 Vet time_linux 2019-01-06 05:25:27 -07:00
gingerBill 5acea1bceb Source_Code_Location.hash; %#v printing for Source_Code_Location; allow typeid for map keys 2019-01-05 15:56:47 +00:00
gingerBill aac643f476 Remove debug printing text 2019-01-05 11:30:13 +00:00
gingerBill 37edbfeb74 Add missing types for min dep 2019-01-05 11:18:43 +00:00
gingerBill 51da3e469b Add win32 cursor stuff 2019-01-05 11:16:14 +00:00
gingerBill 9156af2bab Add missing types to minimum dependency checking 2019-01-05 11:15:23 +00:00
gingerBill 3a18ae3978 Remove alignment experiment 2019-01-04 17:39:20 +00:00
gingerBill f294c1adee ir_print: Ignore load's align
(experimental idea as it might not be needed)
2019-01-04 10:39:39 +00:00
gingerBill bb93a8b131 Fix TODO ParameterValue_Location 2019-01-04 10:19:39 +00:00
gingerBill 5bfe5ad82e Remove unused directive 2019-01-03 12:21:11 +00:00
gingerBill dd28fe6e82 Update CEL 2019-01-03 00:12:24 +00:00
gingerBill cda0f4d8f3 Fix using struct cycle check 2019-01-02 23:55:21 +00:00
gingerBill 0546b5c218 Add sys/win32/comdlg32.odin 2019-01-02 20:51:48 +00:00
gingerBill 61a3e50d1b Reorganize sys/win32 2019-01-02 19:17:27 +00:00
gingerBill 75aeb02c39 Merge pull request #315 from thebirk/fix-bud-for-lazy-bill
Fixed bug for Bill because he is a lazy boi.
2019-01-02 15:20:35 +00:00
thebirk a32f024d94 Fixed bug for Bill because he is a lazy boi. 2019-01-02 16:18:55 +01:00
gingerBill 37d993c417 Merge pull request #314 from thebirk/int_from_arg_fix
Fixed int_from_arg not consuming argument.
2019-01-02 15:01:45 +00:00
thebirk bcbb59dc11 Fixed int_from_arg not consuming argument. 2019-01-02 15:56:35 +01:00
gingerBill c1ec45dc0a Update sys/win32; Add Menu stuff 2019-01-01 20:18:48 +00:00
gingerBill 0778d18bc7 Fix using with bit_field 2019-01-01 15:11:54 +00:00
gingerBill d7e9b8d374 Update README.md 2019-01-01 14:06:15 +00:00
gingerBill f647187e53 Fix defer on branching with new scoping rules 2019-01-01 11:59:09 +00:00
gingerBill 9dabbc2c95 Add entity use when using is applied to a variable declaration 2018-12-31 16:43:58 +00:00
gingerBill 4167168c63 Fix vetting 2018-12-31 16:37:27 +00:00
gingerBill aa156e4bfc Vet demo.odin 2018-12-31 15:51:53 +00:00
gingerBill 1c9656aedb Vet core library 2018-12-31 15:50:49 +00:00
gingerBill 8b2f902f3d Fix parsing issue with stray } and case at the file scope 2018-12-31 15:20:47 +00:00
gingerBill bbece7e910 Remove some unneeded zero emits 2018-12-31 13:00:55 +00:00
gingerBill e5f188241c Move error handling for bounds checking into separate procedures (eliminate caching issues) 2018-12-31 11:41:56 +00:00
gingerBill 6d3203c11b Remove useless assertion in find_import_path 2018-12-30 15:40:45 +00:00
gingerBill 5ba3d90893 Fix os_windows.odin bugs 2018-12-30 14:43:39 +00:00
gingerBill 894f267bbf Merge pull request #311 from mattt-b/master
Fix bugs and inconsistencies with linux versions of os package
2018-12-30 09:50:00 +00:00
matt e084799b31 Fix bugs and inconsistencies with linux versions of os package 2018-12-30 02:06:41 -07:00
gingerBill 3ba3421f5f Fix static procedure name mangling 2018-12-29 19:57:25 +00:00
gingerBill 2bbad5903f Add static to fix_advance_to_next_stmt 2018-12-28 13:32:59 +00:00
gingerBill a240a3d146 static variable declarations (Experimental) 2018-12-28 13:31:06 +00:00
gingerBill 775f1e2c95 Fix default parameter assignment checking 2018-12-28 11:20:31 +00:00
gingerBill 7c982b6e10 min & max for types 2018-12-27 12:12:14 +00:00
gingerBill cc14180e9d Update README.md 2018-12-27 10:51:15 +00:00
gingerBill b2d40680c8 Fix join and concatenate to use the supplied allocator 2018-12-26 19:38:05 +00:00
gingerBill 8662df2b7f Update package strings 2018-12-26 19:33:56 +00:00
gingerBill 6abbc9f1b5 Merge pull request #310 from mattt-b/master
Fix os.open on linux/osx
2018-12-26 17:37:20 +00:00
gingerBill 66a9fde12c Remove #[...] attribute syntax.
(Not really worth the change)
2018-12-26 16:23:25 +00:00
gingerBill eb5af2876a Support #[...] as an alternative attribute syntax
(Experimentation between `@()` and `#[]`)
2018-12-26 12:19:12 +00:00
gingerBill 1f2fdddc6d Support #! comments 2018-12-26 12:00:16 +00:00
matt 0bcf53b513 Fix os.open on linux/osx 2018-12-26 04:31:12 -07:00
gingerBill 956dd26aa0 Fix race condition; Change for in addressing mode 2018-12-24 16:11:24 +00:00
gingerBill b504d6e12a notin operator 2018-12-21 11:34:15 +00:00
gingerBill b4e83a430a Add card procedure to measure cardinality of a bit_set 2018-12-21 10:31:10 +00:00
gingerBill e3d7e6f76a Fix typo in modf_f32 2018-12-20 18:11:27 +00:00
gingerBill 5c3dc30dc0 More correct floor and ceil procedures. 2018-12-20 10:54:56 +00:00
gingerBill c508e46ed9 Merge pull request #308 from hasenj/master
fix missing declaration in osx
2018-12-18 13:05:44 +00:00
Hasen Judy 9d85f236b8 fix missing declaration in osx 2018-12-18 21:47:23 +09:00
gingerBill 3a05a2e562 Fix not for bit sets 2018-12-17 13:12:48 +00:00
gingerBill 68384a452f Fix scoping determination for IR 2018-12-17 11:36:15 +00:00
gingerBill 34b6486361 Fix constant out of bounds bug 2018-12-15 22:30:52 +00:00
gingerBill 1ce90b2166 Remove weird bit_set shorthand; Add extra type hinting 2018-12-15 21:46:27 +00:00
gingerBill 9d6666f333 Disallow casting between cstring and []u8 2018-12-14 21:58:12 +00:00
gingerBill d29335ecec Add deferred procedure associations to demo.odin 2018-12-14 21:17:32 +00:00
gingerBill 95873e66ab deferred procedure attribute 2018-12-14 21:05:02 +00:00
gingerBill b7eebe5d00 Fix polymorphic record types with constant value parameters 2018-12-14 18:36:06 +00:00
gingerBill 57d4333ed3 Fix polymorphic procedure generation with debug information 2018-12-14 15:45:14 +00:00
gingerBill 26f11f12ab Fix polymorphic type parameter argument count checking #298 2018-12-14 15:05:26 +00:00
gingerBill 0b6fc19fb0 Allow polymorphic cast on fields with _ #302 2018-12-14 14:57:04 +00:00
gingerBill f2dae7023f Fix polymorphic cast with pointers #303 2018-12-14 14:53:31 +00:00
gingerBill f36775ffd8 Add endian specific integers to ir_debug_encoding_for_basic #307 2018-12-14 14:46:26 +00:00
gingerBill 8702a8a477 Merge pull request #299 from CaptainKraft/master
Add the missing INVALID_HANDLE so that the demo will build and run on Linux
2018-12-14 14:44:34 +00:00
gingerBill 47e31c3de8 Remove return value from append 2018-12-14 14:40:27 +00:00
gingerBill b1d0d82254 Fix #raw_union bug #306 2018-12-14 14:38:38 +00:00
gingerBill 542e524a87 Merge branch 'master' of https://github.com/odin-lang/Odin 2018-12-14 14:35:48 +00:00
gingerBill b54c35639b Fix issue with mixture of named and unnamed parameters for a struct literal 2018-12-14 14:35:23 +00:00
CaptainKraft cfcb0514bf Add the missing INVALID_HANDLE so that the demo will build and run on Linux. 2018-12-09 20:52:03 -06:00
Mikkel Hjortshoej 1a6b7f9945 set time_linux IS_SUPPORTED to true 2018-12-08 21:12:01 +01:00
Mikkel Hjortshoej 03957cee64 Merge branch 'log_pr' 2018-12-08 21:08:27 +01:00
Jeroen van Rijn 1584260886 Add Linux support for core:time
In addition to sleep() and now(), it also defines nanosleep(), boot_time() and seconds_since_boot()
2018-12-08 20:39:33 +01:00
Mikkel Hjortshoej a565d842da Copy instead of loop 2018-12-08 16:12:20 +01:00
Mikkel Hjortshoej 411d1450b0 Add timestamp support using the new core:time 2018-12-08 16:02:33 +01:00
Mikkel Hjortshoej 984fa1c672 remove ident from logger struct 2018-12-08 15:32:53 +01:00
Mikkel Hjortshoej 12c810f85d Add a file-, console- and multi-logger 2018-12-08 15:32:53 +01:00
gingerBill 3bf01c8498 package time (windows only at the moment) 2018-12-08 14:32:00 +00:00
gingerBill d05837ab6d Labels for block and if statements (break only) 2018-12-08 14:12:52 +00:00
gingerBill 4369a1714e Fix automatic subtype casting bug 2018-12-08 13:31:25 +00:00
gingerBill 13f084a219 Fix foreign export #294 2018-12-08 11:45:08 +00:00
gingerBill 4205f0f0b1 Remove dummy testing code 2018-12-08 11:26:13 +00:00
gingerBill bd62bceca6 Fix BigInt normalization issue #293 2018-12-08 11:25:35 +00:00
gingerBill ff6ec860b3 Fix typo 2018-12-08 11:06:32 +00:00
gingerBill 2bf60d3337 Merge pull request #291 from dimenus/master
fixed typo in 'GetMonitorInfoA' & added additional window styles
2018-12-08 11:05:59 +00:00
dimenus f288614eaf style fixes & PR changes 2018-12-06 11:44:59 -06:00
dimenus 9761d54c24 added win32 vk codes 2018-12-05 14:37:47 -06:00
dimenus 3794914478 fixed typo in 'GetMonitorInfoA' & added additional window styles 2018-12-05 11:13:43 -06:00
gingerBill 3e11b4fe1e Reorganize decl attribute code 2018-12-04 21:02:12 +00:00
gingerBill 50c3f4d74e Add package encoding/cel 2018-12-03 20:26:10 +00:00
gingerBill 304c7594cd Ignore ir_emit_byte_swap for constant values 2018-12-02 20:59:08 +00:00
gingerBill d02b050850 Fix typos for OS X debug builds 2018-12-02 19:39:21 +00:00
gingerBill 17b0e3a1a1 Fix bit sets with custom endian underlying type 2018-12-02 19:27:42 +00:00
gingerBill 28583bfff8 Change procedure group syntax from proc[] to proc{}; deprecate proc[] (raises warning currently) 2018-12-02 18:01:03 +00:00
gingerBill b2df48dadb Fix typo for little endian integers 2018-12-02 16:14:57 +00:00
gingerBill 04a853c6fe Fix double declarations of bswaps in LLVM IR 2018-12-02 16:02:00 +00:00
gingerBill 84f0c975b5 Merge branch 'master' of https://github.com/odin-lang/Odin 2018-12-02 15:54:04 +00:00
gingerBill 00161023cd Endian specific integers: e.g. i32 i32le i32be 2018-12-02 15:53:52 +00:00
gingerBill 7f063eb5e7 Add new demonstration for Packages, Bit Sets, and cstring 2018-12-02 13:18:55 +00:00
gingerBill 784c48c9e3 Redefine how union tag size is calculated to match alignment of the union 2018-11-29 23:00:16 +00:00
gingerBill 008d8f25c8 Fix assertion on union assignment in compound literal 2018-11-29 22:50:08 +00:00
gingerBill 7ffcf34dca Modify how custom alignment is printed for LLVM IR 2018-11-29 22:47:08 +00:00
gingerBill f3a4904f21 Hack: union compound literal fix 2018-11-29 22:23:30 +00:00
gingerBill 3aec78b1d4 Lock on possible race condition in parser 2018-11-29 20:27:48 +00:00
gingerBill a3e6e8d304 Allow single field struct #raw_union 2018-11-29 19:46:45 +00:00
gingerBill a747c03f29 Fix #complete switch on pointers to unions #286 2018-11-29 18:36:45 +00:00
gingerBill 2301ae157c Fix recursive loop bug for is_type_polymorphic 2018-11-28 16:47:20 +00:00
gingerBill d3c7d6d485 Fix #284 2018-11-26 10:55:15 +00:00
gingerBill 9b063ad9a3 Fix poly proc determination by cloning the signature node 2018-11-25 17:57:49 +00:00
gingerBill c2f9bf489e Fix debug information for entities without an associated identifier 2018-11-25 17:31:53 +00:00
gingerBill e496b95881 Subset and superset operators for bit_set: < <= > >= 2018-11-25 16:19:17 +00:00
gingerBill 444f4f446a -vet flag to do basic vetting of code 2018-11-25 14:14:58 +00:00
gingerBill 41ad896f3f Update README.md 2018-11-25 11:21:11 +00:00
gingerBill 0a4b88f9a6 Fix Issue with referencing a polymorphic struct in another package referencing itself #283 2018-11-25 10:35:49 +00:00
gingerBill 4c2f03b1f2 Fix compile time bounds check test 2018-11-23 10:38:17 +00:00
gingerBill 52dcaeb1e9 Fix transmute with cstring and integers 2018-11-22 20:59:24 +00:00
gingerBill f96fbc94c8 v0.9.0 Release 2018-11-22 10:25:01 +00:00
gingerBill bb62bed981 Remove assert that should have never been there 2018-11-22 09:53:08 +00:00
gingerBill bc6b8c5332 Remove dead code 2018-11-22 09:52:25 +00:00
gingerBill 6ab6447791 Fix is_type_polymorphic infinite recursion bug 2018-11-22 09:41:08 +00:00
gingerBill f61c4715c1 Allow opaque to be polymorphic 2018-11-17 10:08:06 +00:00
gingerBill 3061bc8478 Fix error with polymorphic structs #279 2018-11-17 10:05:35 +00:00
gingerBill d035d48c8e Fix issue #280 2018-11-17 09:45:52 +00:00
gingerBill b55b1ffe14 opaque keyword and type 2018-11-11 17:08:30 +00:00
gingerBill 620d5d34f7 Fix issue with complication of -debug that is caused sometimes due to lambda procedures. 2018-11-11 11:44:55 +00:00
gingerBill f9654b6c36 Fix package usage with when on import #278 2018-11-07 16:11:14 +00:00
gingerBill 6659ceb551 Allow comparisons of cstring; Add resize 2018-10-31 10:04:30 +00:00
gingerBill 5aa591d884 Fix debug info issue 2018-10-29 22:16:43 +00:00
gingerBill efe91b1f91 Disable debug info for bit fields 2018-10-29 18:10:44 +00:00
gingerBill 7c99884afb Fix CompositeType for zero length arrays 2018-10-29 12:52:41 +00:00
gingerBill dfd7a194ed Fix big int shifts of 0 2018-10-28 09:32:59 +00:00
gingerBill 2ddb27869b Built-in procedure #defined 2018-10-27 18:44:28 +01:00
gingerBill 5c608b01ba Place optimization level flag in condition again; -memcpyopt -die only in non-debug builds 2018-10-24 10:19:01 +01:00
gingerBill 2bd85e764e Merge pull request #260 from lachsinc/master
[WIP] Provide llvm with more debug info (for Visual Studio debugger support)
2018-10-24 09:40:05 +01:00
gingerBill 822e4894f2 Minor logic change for reserved package names 2018-10-20 21:19:40 +01:00
gingerBill ce2e23849e Fix context initialization 2018-10-20 16:34:56 +01:00
gingerBill 099995e7dd Add basics for context-based Logger 2018-10-20 13:02:30 +01:00
gingerBill 72f4186b21 Fix atomic.odin 2018-10-20 12:55:48 +01:00
gingerBill 3742d9e7e9 Move atomic intrinsics to the new built-in package intrinsics 2018-10-20 10:44:02 +01:00
gingerBill 4ac1218bf8 sync atomics "wrapper" procedures 2018-10-17 21:43:05 +01:00
gingerBill b171cc41e6 __atomic_* "intrinsics" using LLVM instructions 2018-10-17 21:16:01 +01:00
gingerBill efc3a9e69d Merge pull request #274 from hazeycode/fix/245
Use name of source file as output_name
2018-10-17 15:29:56 +01:00
gingerBill 307c58d908 Fix compilation error #272 2018-10-17 15:27:36 +01:00
Chris Heyes ae02e9c34a Use name of source file as output_name 2018-10-16 23:56:19 +01:00
Chris Heyes 139fa55c27 Merge pull request #1 from hazeycode/fix/272
Fix syntax error in core/os/os_linux.odin
2018-10-16 19:30:02 +01:00
Chris Heyes 562bb6e4c4 Fix syntax error in core/os/os_linux.odin 2018-10-15 21:24:42 +01:00
gingerBill ef2931d4a5 Remove AstTypeType 2018-10-13 14:07:00 +01:00
gingerBill 2d4aa2be6d Remove type as being a keyword 2018-10-13 14:04:34 +01:00
gingerBill 42b42db675 Add unimplemented and unreachable procedures; make os.exit a diverging procedure 2018-10-13 13:19:52 +01:00
gingerBill 73e9dbbf8c switch on typeid with type cases 2018-10-13 11:07:56 +01:00
gingerBill 0971a59493 Update runtime printing code 2018-10-11 18:19:29 +01:00
gingerBill 627c91124a Merge pull request #271 from Breush/267-bugfix-linux-heap-alloc-zero
Fixed heap alloc not allowing empty structs on Linux
2018-10-09 21:49:14 +01:00
Alexis Breust 4eba717281 Fixed heap alloc not allowing empty structs on Linux - Fixes #267 2018-10-09 08:34:48 +02:00
gingerBill 9623e5e032 Merge pull request #270 from Breush/263-bugfix-leading-zeros-count
Replaced __builtin_clz by long long version
2018-10-08 09:39:43 +01:00
Alexis Breust 805cc48f03 Replaced __builtin_clz by long long version - Fixes #268 2018-10-08 08:23:50 +02:00
lachsinc d894fb3708 Cleanup comments. 2018-10-06 09:09:12 +10:00
lachsinc b6ca913cff Cleanup hack as all types appear to be handled!.. 2018-10-06 08:58:39 +10:00
lachsinc 39db428603 Add complex debug info. 2018-10-05 17:10:58 +10:00
lachsinc 992502f03b Add debug info for proc ptrs. 2018-10-05 16:49:48 +10:00
lachsinc edc3a9392a Cleanup. 2018-10-05 15:03:13 +10:00
lachsinc f881ebd007 Cleanup unused AllProcs. 2018-10-05 14:51:08 +10:00
lachsinc 11ea03d2e8 Tuple debug info (untested). Generated locals now flow through debug info. 2018-10-05 14:33:39 +10:00
lachsinc 99b4d59f44 Add arg # for proc param locals. 2018-10-05 12:57:06 +10:00
lachsinc dfeefc5179 Fix dgb.declare using different location to it's associated instructions. 2018-10-05 12:46:53 +10:00
lachsinc ab46406f4d Fix debug info for unnamed aggregate types. 2018-10-05 12:27:36 +10:00
lachsinc 48ad147818 Cleanup; Move enums/globals di inside CompileUnit. Minor comment cleanup. 2018-10-04 14:09:17 +10:00
lachsinc 79d49f1955 Lexical block debug info. 2018-10-04 13:43:52 +10:00
lachsinc 1ccc8700e4 bit_set / bit_field debug info. 2018-10-02 10:06:48 +10:00
lachsinc f38d70a235 Cleanup. 2018-10-01 01:21:15 +10:00
lachsinc b37b7a0f72 Cleanup. 2018-10-01 01:10:22 +10:00
lachsinc f8d7f42208 Minor cleanup. 2018-10-01 00:17:42 +10:00
lachsinc db0756a119 Stepping working. Cleanup. 2018-10-01 00:02:41 +10:00
gingerBill 1a4e25f141 Prefix runtime procedures 2018-09-29 21:09:19 +01:00
lachsinc 79ade6ac7b Add various debug location stuff. 2018-09-30 04:47:21 +10:00
lachsinc ecce1d9974 Add debug location stack. 2018-09-30 04:24:24 +10:00
gingerBill 834308d8ce Fix using import override "bug" 2018-09-29 13:07:46 +01:00
lachsinc 9e73189d63 Tagged union debug info. Aggregate type fixes (unions inside structs etc.). 2018-09-27 21:50:57 +10:00
lachsinc 11bddf270c Cleanup debug info 'name' stuff. 2018-09-27 18:34:59 +10:00
lachsinc 0818a272e2 Cleanup hardcoded bytes to bits 2018-09-27 17:55:37 +10:00
lachsinc 9750b1162a Cleanup. 2018-09-27 01:34:15 +10:00
lachsinc 3106aaaa3d Fix pointers to all things debug info. Cleanup param order. Make scope/file optional for relevent types. 2018-09-27 00:02:35 +10:00
lachsinc d31d4c9bd6 (Basic) Map debug info support. Minor slice fix. 2018-09-26 07:51:16 +10:00
lachsinc 6993777d36 Slices. Fix dynamic array data ptr size. 2018-09-26 06:04:33 +10:00
lachsinc 54c044ee09 Add support for any. Fix rawptr debug type. 2018-09-26 05:43:58 +10:00
lachsinc 2e5cecf9e6 Cleanup dynamic array/string bloat. 2018-09-26 04:01:16 +10:00
lachsinc 7acb49eefb Cleanup comments/todos. 2018-09-26 02:17:05 +10:00
lachsinc 0f6c1f3482 Add debug info for globals. Misc debug info cleanup. 2018-09-26 02:01:03 +10:00
lachsinc 1ee0fe7457 Add DebugInfoArray as separate debug info type. Minor cleanup of various debug infos. 2018-09-25 21:24:15 +10:00
gingerBill 1a18481d8b Fix context assignment with selector expressions 2018-09-24 12:04:26 +01:00
gingerBill 28c61c0f5d Merge branch 'master' of https://github.com/odin-lang/Odin 2018-09-24 10:22:33 +01:00
gingerBill 597fb452b1 Minor fixes 2018-09-24 10:22:22 +01:00
lachsinc 5961a63880 Expose dynamic array data/len/cap debug info. Minor cleanup of odin string debug info. 2018-09-19 13:16:56 +10:00
lachsinc cce5e595e5 String debug info. Minor cleanup of derived / composite debug info output. 2018-09-19 01:52:08 +10:00
lachsinc e7d72f6848 Static array debug info. Temporary dynamic array debug info (pointer to data, no len/cap info provided yet). 2018-09-18 23:21:44 +10:00
lachsinc 7dcad45e0d Add proper procedure type support (return types and param proc signature) 2018-09-18 21:28:28 +10:00
lachsinc 3772ea6ae1 Enum debug info support. 2018-09-18 20:12:36 +10:00
lachsinc 2cc2eb1ec0 Fix stepping/jumping between procedures/files. 2018-09-18 18:10:03 +10:00
lachsinc 8a789e33b0 Remove llc/opt hack. XX.bc now contains useful debug info thanks to removal of optimization flags in debug builds. 2018-09-18 14:17:43 +10:00
lachsinc 2f86f8f8e0 Provide llvm ir with more debug info (for Visual Studio debugger support). 2018-09-18 10:50:56 +10:00
gingerBill 02f9a27f46 Merge pull request #264 from lunaticLipid/master
Remove reference to the runtime package within itself
2018-09-16 22:26:34 +01:00
Lipid 6cb605a025 Remove reference to the runtime package within itself 2018-09-16 08:19:33 +02:00
gingerBill 9f3e42e4ef Fix delete_key #262 2018-09-15 11:21:02 +01:00
gingerBill 71d987bd2e Fix runtime proc names; Change calling convention of context parameter 2018-09-15 10:46:46 +01:00
gingerBill 637899467c Merge branch 'master' of https://github.com/odin-lang/Odin 2018-09-15 10:14:40 +01:00
gingerBill 5bdb424c6b context.allocator = a; Remove __ from runtime procs; improve division for complex numbers 2018-09-15 10:14:24 +01:00
gingerBill c62cfddb9c Merge pull request #263 from hasenj/master
fix macos thread_count value
2018-09-14 17:48:34 +01:00
Hasen Judy 14a4c28f8f fix macos thread_count value 2018-09-15 01:46:50 +09:00
gingerBill f1e1814ff9 Syntactic sugar for anonymous enum within a bit set 2018-09-11 12:10:32 +01:00
gingerBill b468cf141b Fix are_types_identical for bit_set 2018-09-11 11:14:46 +01:00
gingerBill 787ea1feba Fix polymorphic constant parameters for procedures 2018-09-11 11:09:42 +01:00
gingerBill 91477e9e69 Allow for optional ok for return 2018-09-11 10:55:30 +01:00
gingerBill cfd0dfd2bf Remove assertion from constant parameter 2018-09-10 21:56:16 +01:00
gingerBill 46b1868185 Constant polymorphic names 2018-09-10 14:21:19 +01:00
gingerBill 4c4de1d6c4 Fix cloning of auto_cast Ast 2018-09-10 08:50:20 +01:00
gingerBill c8b30de771 Update compiler flags for build.bat 2018-09-09 15:06:04 +01:00
gingerBill 4f3837f0e6 Procedure inlining on call site 2018-09-09 14:46:28 +01:00
gingerBill 76848e8807 Disallow inline for recursive procedures 2018-09-09 13:58:23 +01:00
gingerBill 12902821d6 Make diverging procedure types different from ones without a return type 2018-09-09 13:48:33 +01:00
gingerBill f5549f6bde Make panic a diverging procedure 2018-09-08 12:17:16 +01:00
gingerBill 3825eab989 Diverging procedures proc() -> ! (no return) 2018-09-08 12:16:03 +01:00
gingerBill 3cd6ae311d Parametric polymorphic union type 2018-09-08 12:02:25 +01:00
gingerBill 26cfc0257d Fix array_ordered_remove typo 2018-09-08 10:44:18 +01:00
Ginger Bill 1d31eabb6e Fix minor parsing issue for polymorphic identifiers 2018-09-04 13:47:24 +01:00
Joshua Mark Manton 8cd2797b2e Fixed core library bugs after recent changes. (#257)
* Fix `delete_map` calling `delete_dynamic_array` instead of `delete_slice for its hashes.

* Removed print statements from `__dynamic_map_rehash`
2018-09-02 22:18:32 +02:00
gingerBill 11f5236434 Add $T: typeid/[]$E; Deprecate T: type/[]$E
`type` as a keyword will soon be removed in favour of polymorphic names (identifiers) in procedures
2018-09-02 16:33:54 +01:00
gingerBill 220485a2d2 typeid as keyword (ready to implement polymorphic name parameters) 2018-09-02 15:56:36 +01:00
gingerBill eb274cf316 Remove test code 2018-08-30 19:33:16 +01:00
gingerBill aa542980ce Change memory layout of map to be 3 words smaller 2018-08-30 19:14:10 +01:00
gingerBill e0240c186f Rename buffer entity 2018-08-30 12:53:07 +01:00
gingerBill ae58502a21 Make free_all built-in 2018-08-30 12:21:16 +01:00
gingerBill 6a3697279c Place assertf and printf to package fmt 2018-08-30 12:10:16 +01:00
gingerBill c19ec5d65d Fix delete for dynamic array and map 2018-08-30 12:00:51 +01:00
gingerBill 15dca449c9 Add assertf and panicf 2018-08-30 11:46:57 +01:00
gingerBill dda985f49d Add extra nil check for assert and panic 2018-08-30 11:16:06 +01:00
gingerBill 12256beeb2 Prevent other parameters being the default value 2018-08-30 11:12:57 +01:00
gingerBill 0858ae2024 Add utf8_to_ucs2 for package win32 so that the wide procedures can used by default 2018-08-30 10:59:46 +01:00
gingerBill 6c18864291 Add default_assertion_failure_proc to the minimum dependency build 2018-08-29 21:15:11 +01:00
gingerBill ae57284912 Add Assertion_Failure_Proc to context 2018-08-29 21:10:13 +01:00
gingerBill 001837e6bb Temporary allocator for context 2018-08-29 19:55:55 +01:00
gingerBill 28523f17e2 Add default allocator to allocation related procedures e.g. alloc, free, delete, make 2018-08-28 20:14:56 +01:00
gingerBill ae2af8315e Allow for default parameters that are non-constant entities, but not any non-constant expression 2018-08-28 20:03:27 +01:00
gingerBill adbb3bb75f Add -lld flag for using "bin\lld-link.exe" on Windows 2018-08-28 19:28:34 +01:00
gingerBill 6181c4edb3 Update 2018-08-28 19:26:05 +01:00
gingerBill 830c194da5 Allow enums for array lengths 2018-08-26 18:23:17 +01:00
gingerBill 1830c1e57c Allow bitwise operation on enums 2018-08-26 18:05:59 +01:00
gingerBill e5735af6d6 Disable for in over cstring 2018-08-26 15:10:23 +01:00
gingerBill a6b0ae71b2 Remove assert 2018-08-26 10:56:33 +01:00
gingerBill 3365baee8f runtime.Typeid_Bit_Field layout to store more information into the typeid 2018-08-25 12:11:48 +01:00
gingerBill cc88dd0b71 Allow for variadic min max procs
Request #252
2018-08-25 11:12:52 +01:00
gingerBill f050bfe872 Fix comparisons with union 2018-08-25 10:39:19 +01:00
gingerBill ab71acc3a5 Disable abs for arrays #254 2018-08-25 10:27:44 +01:00
gingerBill 0a85d1af6b Improve error messages for using on fields 2018-08-24 22:28:00 +01:00
gingerBill 68adadb01a Allow using in structs on arrays with count <= 4 2018-08-24 22:12:30 +01:00
gingerBill d56f458d11 Fix file scope #assert 2018-08-24 17:42:13 +01:00
gingerBill a65eadee63 Fix for in enum iteration 2018-08-22 18:56:41 +01:00
gingerBill 16dfae62bc Allow casting to and from rawptr and cstring #249 2018-08-22 15:19:04 +01:00
gingerBill fe680a8b1f Fix default return values #250 2018-08-22 15:17:29 +01:00
gingerBill 54fe9f3eb1 Improve min dep for min/max/abs/clamp 2018-08-21 21:43:38 +01:00
gingerBill cbc6c2666b Improve proc group scoring algorithm 2018-08-21 14:11:18 +01:00
gingerBill a4d0ac1802 Merge branch 'master' of https://github.com/odin-lang/Odin 2018-08-20 19:20:44 +01:00
gingerBill 0dc29a7208 Implement suggestions from #247 2018-08-20 19:20:28 +01:00
gingerBill a9321bc73f Update README.md 2018-08-20 10:27:48 +01:00
gingerBill e3f0ab7c3d Parallelize parser on *nix 2018-08-19 10:58:57 +01:00
gingerBill 5643ea1ba2 Fix typo 2018-08-19 10:56:23 +01:00
gingerBill 3b6523fbd9 Fix gbMutex for *nix 2018-08-19 10:34:31 +01:00
gingerBill ffc4f01470 All enums in array indices 2018-08-17 19:38:15 +01:00
gingerBill e326f41d16 Fix demo 2018-08-17 15:26:29 +01:00
gingerBill 1d0ac72e4a Disable non-comparison operations for enum (use bit_set for flags) 2018-08-17 15:24:44 +01:00
gingerBill b216e44870 Add underlying type for bit_set 2018-08-17 15:11:41 +01:00
gingerBill 7d39b26cf4 Minor refactor 2018-08-16 20:52:46 +01:00
gingerBill 884d5fed9f bit_set['A'..'Z'], bit_set[0..8] 2018-08-16 15:16:57 +01:00
gingerBill ec84188597 Fix typos in parser 2018-08-16 10:30:44 +01:00
gingerBill 85ac95f81b Constant evaluation for in expression for bit_sets 2018-08-16 00:07:26 +01:00
gingerBill 042550cf87 Fix default value bug 2018-08-15 19:36:32 +01:00
gingerBill b3ebff715a Fix defer ir bug 2018-08-15 15:44:41 +01:00
gingerBill 1ee60663bb Fix issue #244 with constant array comparisons 2018-08-14 19:43:36 +01:00
gingerBill 59da98d3f0 Improve type hinting for compound literals 2018-08-14 19:39:28 +01:00
gingerBill 2d41a42f61 Cleaning type hinting for assignments 2018-08-14 19:33:42 +01:00
gingerBill e1e4a916a5 Fix demo and improve type hinting 2018-08-14 19:29:31 +01:00
gingerBill 71f94bff76 Minor sanity features for bit_set 2018-08-14 19:22:48 +01:00
gingerBill c7d6467cfa Fix assigning issue for bit sets 2018-08-14 18:43:47 +01:00
gingerBill 79a3c0b36c Fix bit_set range 2018-08-14 18:35:14 +01:00
gingerBill 966249c10a bit_set constants 2018-08-14 18:32:34 +01:00
gingerBill acc010cba5 Add bit_set type 2018-08-14 17:07:56 +01:00
gingerBill 89f4e7a8db -no-crt flag for windows amd64 2018-08-13 01:22:14 +01:00
gingerBill 55f4eabecd Fix map addressing mode bug 2018-08-10 18:22:37 +01:00
gingerBill d0fc9aa069 Allow for '\"' 2018-08-10 17:48:29 +01:00
gingerBill 8be9b5082c Fix default make parameters for dynamic arrays 2018-08-09 18:15:49 +01:00
gingerBill 708907df31 auto_cast for named parameters 2018-08-09 17:59:18 +01:00
gingerBill 70586b1cf8 auto_cast prefix for procedure parameters 2018-08-09 17:58:11 +01:00
gingerBill 877a78d6ba Fix make error messages 2018-08-08 23:07:51 +01:00
gingerBill 3928614326 Merge pull request #241 from thebirk/fix-sh-main-not-found
Fixed 'sh: main: command not found' error on linux.
2018-08-08 22:41:42 +01:00
thebirk 5e5f5bfa8d Fixed 'sh: main: command not found' error on linux. 2018-08-08 17:48:17 +02:00
gingerBill 3a1a7b40f9 Add runtime messages for make for the len/cap parameters 2018-08-08 13:04:40 +01:00
gingerBill 835d7dcab2 make as a user-level procedure rather than a built-in procedure 2018-08-08 13:04:40 +01:00
gingerBill 28816dc491 Fix parenthesis warning on clang 2018-08-08 13:04:40 +01:00
gingerBill ccdc3438be Refactor handle_parameter_value code 2018-08-06 00:26:38 +01:00
gingerBill 60711dd355 Refactor default parameter values 2018-08-05 23:57:34 +01:00
gingerBill fad3947e26 Add *with_allocator procedures to mem 2018-08-05 23:40:19 +01:00
gingerBill d8e5b2d1a4 Fix cstring cast operation 2018-08-05 19:07:03 +01:00
gingerBill 2d26ad0226 Remove opengl package 2018-08-05 19:01:15 +01:00
gingerBill 45d3c6c0d3 Fix cstring to string conversion 2018-08-05 18:58:35 +01:00
gingerBill c6bffd7c35 Change build.bat to use release_mode=1 by default 2018-08-05 10:37:09 +01:00
gingerBill 462d81430c Fix map runtime issue regarding erasing a key 2018-08-05 10:31:20 +01:00
gingerBill d3cada5bd6 Change rules for how context and defer interact 2018-08-04 23:46:46 +01:00
gingerBill cdbf831a7a Replace context <- c {} with context = c;. context assignments are scope based 2018-08-04 23:14:55 +01:00
gingerBill 0718f14774 Reduce number of range and slice operators #239
Replace .. and ... with : and ..
2018-08-01 21:34:59 +01:00
gingerBill a6fe656f21 foreign import x {"foo.lib", "bar.lib"} 2018-07-29 20:56:09 +01:00
gingerBill dc5da7933a Add older demos 2018-07-29 11:36:24 +01:00
gingerBill 96fc9138d4 Do using Foo :: enum at the type_decl stage 2018-07-29 11:29:20 +01:00
gingerBill 6512a3e5f2 using Foo :: enum {A, B, C}; len(Foo) 2018-07-29 10:50:15 +01:00
gingerBill 49f2124df0 Support larger integer literals to work with the new BigInt system 2018-07-29 10:22:17 +01:00
gingerBill a11d6e696a expand_to_tuple for fixed arrays 2018-07-28 20:56:27 +01:00
gingerBill 1705ba8069 Fix typos 2018-07-28 19:44:00 +01:00
gingerBill 8d2c4a78a1 Merge pull request #238 from odin-lang/big-int
Big int
2018-07-28 18:39:15 +01:00
gingerBill 8504ff920b Correctly handle bitwise operations for negative BigInt 2018-07-28 18:36:45 +01:00
gingerBill e34a9e6185 Fix big_int_shr 2018-07-28 00:48:36 +01:00
gingerBill c3c7834246 BigInt support in the constant system 2018-07-28 00:41:31 +01:00
gingerBill 1ab40d8600 Merge pull request #237 from lunaticLipid/master
Add mat3_mul and generic transpose to math.odin
2018-07-17 08:25:21 +01:00
Lipid 92ce02dab0 Fix indent characters 2018-07-16 20:30:49 +02:00
Lipid 8abe9ef507 Add mat3_mul and generic transpose to math.odin 2018-07-16 20:27:29 +02:00
gingerBill d0e04bf569 Merge pull request #236 from hasenj/master
Fix build errors on osx
2018-07-14 19:39:11 +01:00
Hasen Judy b92599879a free -> delete in os_osx and os_linux 2018-07-13 11:25:46 -06:00
gingerBill 0e91298fd1 Rename free to delete for non pointer types 2018-07-08 11:03:56 +01:00
gingerBill e515220694 Improve array arithmetic inlining 2018-07-08 10:15:46 +01:00
gingerBill a55683d287 Remove allocator parameters in ir.cpp 2018-07-07 11:29:45 +01:00
gingerBill fa4e95105f Loop array arithmetic on large arrays 2018-07-07 11:13:20 +01:00
gingerBill 1e01085ef7 Merge branch 'master' of https://github.com/odin-lang/Odin 2018-07-07 08:12:48 +01:00
gingerBill 04a1f869b5 Fix when statements within a foreign block 2018-07-07 08:11:31 +01:00
Morten Vassvik e04ba7530d Updated makefile to run demo package instead of demo.odin 2018-07-05 15:48:55 +02:00
Morten Vassvik ea055f1465 Surrounded explicit link paths (.a and .so) and the exe path for 'odin run' in quotes, so that it works in paths containing characters that must be escaped (like spaces) 2018-07-05 15:46:11 +02:00
Morten Vassvik 3b2c867817 Replaced CLOCK_PROCESS_CPUTIME_ID with CLOCK_MONOTONIC in calls to clock_gettime and clock_getres to make timings on calling external executables accurate instead of showing them taking negligible time on linux. 2018-07-04 21:04:48 +02:00
gingerBill 3de23eb0bf Merge pull request #233 from zangent/master
Make macOS builds work again
2018-07-02 08:57:22 +01:00
Zachary Pierson 5de3b07e2b Made os_osx.odin use the new-style runtime.args__ and added read_directory for macOS 2018-07-02 02:50:08 -05:00
gingerBill c0ca4d4635 Uncomment code 2018-07-01 18:31:31 +01:00
gingerBill efe4b71bae Fix build.sh 2018-07-01 17:17:31 +01:00
gingerBill bc37bd5429 Merge branch 'packages' of https://github.com/odin-lang/Odin into packages 2018-07-01 17:14:43 +01:00
gingerBill 5f20e04259 Fix on *nix 2018-07-01 17:14:22 +01:00
gingerBill 9bef5ec01a Fix anonymous procedures 2018-07-01 16:21:32 +01:00
gingerBill cdf873542b Add read_directory for linux 2018-06-21 08:39:52 +01:00
gingerBill 4742690dec Fix is_excluded_target_filename 2018-06-21 08:39:07 +01:00
gingerBill 3a16f1e854 Minor style change 2018-06-17 22:25:28 +01:00
gingerBill 877400dd12 Scope to use flags rathers than booleans 2018-06-17 22:22:30 +01:00
gingerBill a4e3201113 Minor cleanup for builtin scope/pkg 2018-06-17 22:07:27 +01:00
gingerBill a99cc2fd70 Clean up import lookup code 2018-06-17 21:50:40 +01:00
gingerBill 5fe4c33d0e Allow importation of core:builtin to get built-in entities 2018-06-17 21:46:37 +01:00
gingerBill 4d9d38cc28 Move TypeAndValue to Ast from Map 2018-06-17 16:35:22 +01:00
gingerBill 5b71ffd4f9 Rename clone_ast_node to clone_ast 2018-06-17 11:03:26 +01:00
gingerBill c2ca24a486 Big renaming: AstNode to Ast 2018-06-17 10:58:59 +01:00
gingerBill e5aff6fd6d Minimize AstNode size 2018-06-17 10:48:50 +01:00
gingerBill 3eb8aa8268 Modify CommentGroup parsing 2018-06-17 10:29:20 +01:00
gingerBill 6d1c32eb77 Add escape code for ESC \e 2018-06-15 23:13:26 +01:00
gingerBill ba776a3c9f Fix bitwise not for signed integers 2018-06-15 23:01:12 +01:00
gingerBill cd7e260f4e Fix cyclic polymorphic procedure usage and improve its error message 2018-06-15 22:49:06 +01:00
gingerBill ba67e474d3 Make source code compile with 32 bit (but not build 32 bit code) 2018-06-15 21:46:03 +01:00
gingerBill b92a8c513e Modify how build settings are handled 2018-06-15 21:38:22 +01:00
gingerBill 13572aeef0 Fix gb.h 2018-06-15 20:26:39 +01:00
gingerBill 5081ea1a0c Fix type aliasing comparison; Fix gb_utf8_decode 2018-06-15 19:59:35 +01:00
gingerBill e9e7ce2606 Allow .allocator for dynamic arrays; Add mem.Pool 2018-06-12 19:10:14 +01:00
gingerBill 915dcb0c28 Fix min dependency check 2018-06-11 22:57:40 +01:00
gingerBill 8236c6d4b7 Allow for base enum type with an enum declaration 2018-06-11 22:50:13 +01:00
gingerBill 555fe37ad8 Remove the need for a look ahead 2018-06-11 18:06:58 +01:00
gingerBill 881f667558 Change how context <- is parsed to remove the need for a look-ahead 2018-06-11 18:02:04 +01:00
gingerBill 0a99595efe Remove using in stuff 2018-06-11 17:34:57 +01:00
gingerBill 268491b224 Use global arena for AstNode allocations 2018-06-09 19:53:06 +01:00
gingerBill 49ea9ed722 Entity aliasing clean up 2018-06-09 10:08:17 +01:00
gingerBill d7108416c9 Remove dead code 2018-06-07 23:52:13 +01:00
gingerBill b136630856 Fix type info generation for empty structs 2018-06-07 23:24:37 +01:00
gingerBill fa6f31186a Merge pull request #228 from shuaDev/shwadev-packages
Fix some core lib errors on packages branch
2018-06-03 21:09:57 +01:00
gingerBill b027b1d60f Fix min type info for polymorphic procedures and named types 2018-06-03 21:09:08 +01:00
Joshua Mark Manton 7ed1d931cb fix quick_sort_proc calling quick_sort instead of recursively calling itself 2018-06-03 11:27:57 -07:00
Joshua Mark Manton 2570296b01 fix core opengl ODIN_OS reference and pointer math stuff 2018-06-03 11:25:46 -07:00
Joshua Mark Manton f0a4526250 Fix alloc.odin using old raw file 2018-06-03 11:22:42 -07:00
gingerBill c39332c7e7 Revert name mangling 2018-06-03 19:18:47 +01:00
gingerBill 3f4b6b22dc Change our IR name mangling rules 2018-06-03 17:55:13 +01:00
gingerBill e0549df03e Fix minor possible issue 2018-06-03 17:44:10 +01:00
gingerBill e46662a546 Rename os.default_allocator to os.heap_allocator 2018-06-03 16:40:58 +01:00
gingerBill 360a74e2fe Merge pull request #226 from BrettRToomey/packages
Dsymutil fixes
2018-06-03 16:35:43 +01:00
Brett R. Toomey 597c4591bc Merge branch 'packages' of github.com:odin-lang/Odin into packages 2018-06-03 17:13:11 +02:00
Brett R. Toomey 80833ed703 Dsymutil fixes for macOS 2018-06-03 17:12:30 +02:00
gingerBill 106302189c Use gbString for opt_flags 2018-06-03 16:09:24 +01:00
gingerBill 05c5f98e8e Add -debug-compile parameter for llc 2018-06-03 15:55:14 +01:00
gingerBill d556fa2cd8 Remove special shared scope for runtime stuff 2018-06-03 15:06:40 +01:00
gingerBill 9bd7f023b2 Split up init_preload into specific parts 2018-06-03 11:38:02 +01:00
gingerBill 398109ac84 Remove need for __llvm_core 2018-06-03 10:51:43 +01:00
gingerBill 12b870ba66 Use const & for Array<AstNode *> parameters 2018-06-03 10:30:31 +01:00
gingerBill 6202fb8373 Re-allow when statements at the file scope 2018-06-02 19:44:34 +01:00
gingerBill ced818ad54 Remove dead code from checker 2018-06-02 11:58:35 +01:00
gingerBill ccbb6df749 Handle multiple +build package tags with '!' (nots) 2018-05-28 21:25:08 +01:00
gingerBill 6eb505a677 Comment based build tags for packages (basic and temporary) 2018-05-28 20:59:06 +01:00
gingerBill 619783ca1b Remove clutter parameters and begin parallelizing the type checker 2018-05-28 18:46:39 +01:00
gingerBill 642aa0bc4b Refactor: use CheckerContext rather than Checker in type checking part 2018-05-28 15:57:53 +01:00
gingerBill 45b3067068 Remove tmp_allocator from Checker 2018-05-28 14:15:08 +01:00
gingerBill b7858a66b9 Parallelize per file rather than per package 2018-05-28 12:06:50 +01:00
gingerBill 4e203feaf4 Change import lookup 2018-05-27 23:46:08 +01:00
gingerBill a513b47780 Remove unused packages 2018-05-27 23:33:10 +01:00
gingerBill 547a2831c7 Clean up name mangling by using unique package names per project 2018-05-27 22:09:11 +01:00
gingerBill 5c52ffe24e Reorganize runtime package 2018-05-27 21:22:25 +01:00
gingerBill a5763d6fee Err on empty directory packages 2018-05-27 14:12:10 +01:00
gingerBill 95482c554d Fix build.bat 2018-05-27 13:53:46 +01:00
gingerBill 10758710d4 Fix demo.odin 2018-05-27 13:53:19 +01:00
gingerBill 86cf9383ea Fix delayed assert collection 2018-05-27 13:49:55 +01:00
gingerBill 307977d4cf Remove dead code 2018-05-27 13:30:18 +01:00
gingerBill 1beff539d7 Single file "main" file 2018-05-27 13:22:24 +01:00
gingerBill df578d6ec5 Allow for either .odin file or directory as the initial start 2018-05-27 11:40:27 +01:00
gingerBill 6aae381e83 Move ODIN_* platform constants to core:os 2018-05-27 11:03:46 +01:00
gingerBill 7ee9051a56 IR now builds with the new package system 2018-05-27 10:49:14 +01:00
gingerBill eb11edabe0 Add file scopes for the packages 2018-05-27 00:10:38 +01:00
gingerBill c067b90403 Add basic package support (no IR support yet) 2018-05-26 23:12:55 +01:00
gingerBill 5b6770f3d2 Parse directories to be packages 2018-05-21 20:47:52 +01:00
gingerBill 718b80ba39 Fix demo for removing default struct values 2018-05-20 17:39:49 +01:00
gingerBill 4d052d5119 Remove code relating to default struct values 2018-05-20 17:31:46 +01:00
gingerBill 7e4c643401 Disable default struct field values; Update README.md 2018-05-20 16:00:39 +01:00
gingerBill e920338f21 Remove old dependency 2018-05-20 08:58:48 +01:00
gingerBill af2048570c Merge pull request #222 from shuaDev/master
added compiler command for only parsing and typechecking
2018-05-17 10:33:23 +01:00
Joshua Mark Manton 1ee4f849cb now return 1 if there were errors 2018-05-17 02:08:04 -07:00
Joshua Mark Manton 703393fc63 whitespace 2018-05-16 23:08:01 -07:00
Joshua Mark Manton 81420ab246 removed unneeded block 2018-05-16 23:07:27 -07:00
Joshua Mark Manton c94d19718b added compiler command for only parsing and typechecking 2018-05-16 23:03:05 -07:00
gingerBill e25c72ecdd Fix #219 and #220 2018-05-14 17:05:52 +01:00
gingerBill 780b81a59f Allow for NO_DEFAULT_STRUCT_VALUES
(will decide later if I want them or not)
2018-05-13 21:09:49 +01:00
gingerBill 9f1dda701d Comment out test 2018-05-13 18:43:21 +01:00
gingerBill e597a8d72e Fix issues with exact integer bounds and remove dead code 2018-05-13 17:38:35 +01:00
gingerBill de9a4b5164 Disable pointer arithmetic 2018-05-13 16:10:02 +01:00
gingerBill 319aca3101 Merge pull request #218 from hasenj/osx-timing
Fix timing on macos
2018-05-13 11:45:05 +01:00
Hasen Judy 9dc2c01aaa Fix timing on macos 2018-05-13 19:33:08 +09:00
gingerBill 6164672421 Change FreeAll to Free_All 2018-05-13 10:14:32 +01:00
gingerBill 61906613b0 Add typeid to Type_Info struct 2018-05-13 10:09:21 +01:00
gingerBill 3b48fa8e7d Fix default initialized values for globals (#217) 2018-05-12 21:22:39 +01:00
gingerBill 324b7d65e7 Use __type_info_of internally 2018-05-12 20:17:12 +01:00
gingerBill 373a60b9ef type_info_of allows typeid; typeid_of allows ^Type_Info; Otherwise only allow type 2018-05-12 19:54:16 +01:00
gingerBill 2ef22e86e0 Make any use typeid rather than ^Type_Info 2018-05-12 18:40:49 +01:00
gingerBill 830f4f540f typeid 2018-05-12 17:39:04 +01:00
gingerBill 56ff5496bc Minimal Type Info Dependency handling 2018-05-12 16:53:44 +01:00
gingerBill 20fbece14c Change semantics for distinctness for pointers, arrays, dynamic arrays, and maps. 2018-05-12 10:47:32 +01:00
gingerBill 9fbfd86cde Add log to math.odin 2018-05-12 10:46:00 +01:00
gingerBill 7547bc66cf Complete remove all non required preload stuff from min dep and only use what is used. 2018-05-12 10:38:40 +01:00
gingerBill 18a9fa7355 Improve minimal dependency system 2018-05-12 10:27:55 +01:00
gingerBill b32af841c5 Merge branch 'master' of https://github.com/odin-lang/Odin 2018-05-06 15:31:32 +01:00
gingerBill 66b4252931 Fix #210 2018-05-06 15:31:18 +01:00
gingerBill 2c95eaa418 Merge pull request #216 from lunaticLipid/master
Fix copy-and-forget in math.odin
2018-05-02 19:40:59 +01:00
Lipid 7382f52dc9 Fix copy-and-forget in math.odin 2018-05-02 18:04:50 +02:00
gingerBill 49dd299999 Merge pull request #204 from ThisDrunkDane/master
Added more function to windows.odin
2018-04-14 19:45:00 +01:00
Mikkel Hjortshoej e391b05513 Merge branch 'master' of github.com:ThisDrunkDane/Odin 2018-04-13 22:39:17 +02:00
Mikkel Hjortshoej 2de62910fc Added more function to windows.odin 2018-04-13 22:38:58 +02:00
gingerBill fc77b5b4ac Try to fix internal compiler error in #208 2018-04-10 21:03:51 +01:00
gingerBill a83d916fad Fix immutable context to any assignment #214 2018-04-10 20:51:44 +01:00
gingerBill e71a641379 Fix internal compiler error trigger for issue #212 2018-04-10 20:46:32 +01:00
gingerBill e2eca45188 Fix race condition caused by parallelized parser: #211 2018-04-10 20:35:05 +01:00
gingerBill 4d78540658 Fix #210 2018-04-10 20:20:33 +01:00
gingerBill b83c3f265b Fix #209 #assert bug 2018-04-10 20:18:16 +01:00
gingerBill 30f5a3bb93 Move cycle checking to much earlier on in the semantic stage 2018-03-23 20:48:30 +00:00
gingerBill 2e1e1e6034 Type caching 2018-03-23 16:35:41 +00:00
gingerBill 991479fbf9 Remove allocator parameter to types.cpp functions 2018-03-23 16:01:23 +00:00
gingerBill 5660f98cc3 Merge branch 'master' of https://github.com/odin-lang/Odin 2018-03-23 15:23:31 +00:00
gingerBill 5bf0f9d630 Fix type cycle bug 2018-03-23 15:23:14 +00:00
Mikkel Hjortshoej 15b72119eb Added more function to windows.odin 2018-03-21 19:30:27 +01:00
gingerBill dc30e7a200 Merge pull request #201 from nakst/master
update essence bindings
2018-03-11 20:52:58 +00:00
Nakst db2293144a update essence bindings 2018-03-10 21:33:59 +00:00
gingerBill 5016f45429 Merge pull request #200 from nakst/master
fix compile warnings on linux
2018-03-10 20:50:46 +00:00
Nakst 9fa4aa40b7 fix compile warnings on linux 2018-03-10 20:29:43 +00:00
gingerBill 52f60c706a Merge pull request #199 from ThisDrunkDane/resource
Resource Compiler calling
2018-03-10 13:42:25 +00:00
gingerBill fff4ead96a Fix gb_alloc_str_len 2018-03-07 20:36:15 +00:00
Mikkel Hjortshoej 3574341b6b Missing .rc error message 2018-03-05 13:10:01 +01:00
Mikkel Hjortshoej cbabc80d92 Calls rc.exe if -resource specified 2018-03-05 11:46:50 +01:00
gingerBill f4cf88c2ca Move os_*.odin files to os/ 2018-03-04 11:38:49 +00:00
gingerBill 6db95b554f __args__: []cstring 2018-03-04 11:25:23 +00:00
gingerBill 105de7705a Add unselector_expr 2018-03-04 11:06:59 +00:00
gingerBill 584dffea14 Remove dead code; fix referencing of a type assertion in a selector expression 2018-03-04 09:25:02 +00:00
gingerBill 41b6d215bb Fix using determination order 2018-03-03 20:07:12 +00:00
gingerBill 9274f29ca9 deprecated attribute for procedure declarations 2018-03-03 11:16:48 +00:00
gingerBill 08c87e57f8 Remove cwd in odin run for Linux 2018-03-03 10:26:25 +00:00
gingerBill b21cdd5037 Merge branch 'master' of https://github.com/odin-lang/Odin 2018-03-03 10:25:13 +00:00
gingerBill 63ab8b2418 Make irGen.output_base use full path rather than relative 2018-03-03 10:23:27 +00:00
Morten Vassvik cb7a343caf Fixed '_alloc_command_line_arguments()' in os_linux.odin to use the new cstrings, and made 'odin run' use the full executable path. 2018-03-01 12:58:57 +01:00
gingerBill 40542e6e26 Fix comparison against nil for cstring 2018-02-28 12:01:26 +00:00
gingerBill 9da05dd4cb Update core library with cstring 2018-02-28 11:44:41 +00:00
gingerBill ae9da0abfb Merge branch 'master' of https://github.com/odin-lang/Odin 2018-02-28 11:20:31 +00:00
gingerBill d3ea334e7a cstring 2018-02-28 11:20:11 +00:00
gingerBill d76132a3fb Merge pull request #198 from ThisDrunkDane/terminate_thread
Added terminate_thread to thread.odin
2018-02-26 10:06:08 +00:00
gingerBill 223c473cf6 Demo fix 2018-02-25 20:57:34 +00:00
gingerBill fd57cfa1ae Fix build_settings.cpp 2018-02-25 20:52:06 +00:00
gingerBill f23bd2dc27 Revert demo 2018-02-25 20:46:32 +00:00
gingerBill 69062ba3ab More code tidying with Array 2018-02-25 20:24:38 +00:00
gingerBill e75563cb32 Minor code rearrangement 2018-02-25 19:42:12 +00:00
gingerBill d63885a495 array_make 2018-02-25 19:23:52 +00:00
gingerBill f28a34fa99 Use Array<irValue *> in ir.cpp 2018-02-25 15:31:00 +00:00
gingerBill a1e8de4e00 Fix ir_emit_slice_bounds_check 2018-02-25 15:11:20 +00:00
gingerBill d247ba4751 Hexadecimal floats for "perfect values" 0h42f60000 == 123; use bit_cast in compiler 2018-02-25 15:09:16 +00:00
gingerBill 27b7dc336a Change parsing for floats and disallow x.0 2018-02-25 14:36:41 +00:00
gingerBill 60a7c68aa6 Minor code reorganization 2018-02-25 14:23:45 +00:00
Mikkel Hjortshoej 78c103e62c Merge branch 'terminate_thread' of github.com:ThisDrunkDane/Odin into terminate_thread 2018-02-25 14:57:22 +01:00
Mikkel Hjortshoej ffec1c77f2 Added terminate_thread to thread.odin 2018-02-25 14:56:50 +01:00
gingerBill 5357181484 Multithreaded parser (windows only) 2018-02-25 13:45:44 +00:00
Mikkel Hjortshoej 33ddb3ad4d Added terminate_thread to thread.odin 2018-02-25 14:38:55 +01:00
gingerBill 1cd453db14 Remove unneeded disabled warnings for MSVC 2018-02-25 12:29:48 +00:00
gingerBill 3b5932699c Fix #assert in opengl.odin 2018-02-25 12:14:35 +00:00
gingerBill bada81159d Add #no_bounds_check to __dynamic_map_* procedures 2018-02-25 12:13:45 +00:00
gingerBill 652da98c70 Fix slice bounds checking 2018-02-25 12:10:19 +00:00
gingerBill e14e2c3b4d -out and generate executable in the current working directory 2018-02-25 11:49:44 +00:00
gingerBill f96a897821 Make switch in f { valid 2018-02-25 10:55:18 +00:00
gingerBill b74ae77745 Merge pull request #197 from bpunsky/context-bug-fix
Context bug fix
2018-02-25 00:13:02 +00:00
Brendan Punsky 564226be02 fixed issues with uninitialized contexts
also, `any_to_bytes` I think, and maybe some bindings in `core:sys/windows.odin`
2018-02-24 18:58:22 -05:00
Brendan Punsky f6c45fc68a Merge remote-tracking branch 'origin/master' 2018-02-24 14:29:30 -05:00
gingerBill 35ba5771a5 Replace compile_assert with #assert 2018-02-24 19:03:29 +00:00
gingerBill b2461f7192 Fix issue #195 2018-02-24 18:19:11 +00:00
Brendan Punsky 60a54f404b Auto stash before merge of "master" and "origin/master" 2018-02-22 20:11:17 -05:00
gingerBill 921f261377 Fix os.args on Windows #143 2018-02-22 21:34:09 +00:00
gingerBill d70a555c1c Fix issue #192 2018-02-22 21:24:38 +00:00
gingerBill 4c339360e9 auto_cast 2018-02-18 15:14:13 +00:00
gingerBill 731dad480d Fix issue regarding nullptr Type * 2018-02-18 14:37:58 +00:00
gingerBill a0f2357cb3 Minor fix to demo 2018-02-17 19:40:33 +00:00
gingerBill e86ac75e9c Merge branch 'master' of https://github.com/odin-lang/Odin 2018-02-17 19:24:15 +00:00
gingerBill f51de2e488 Disallow #complete switch ranges 2018-02-17 19:24:02 +00:00
gingerBill 5efefdcf16 Merge pull request #189 from ThisDrunkDane/master
Pretty readme header
2018-02-17 19:16:51 +00:00
gingerBill cabb2bb992 Commit 1000 🎉🎂 2018-02-17 19:15:58 +00:00
gingerBill d560f6c920 Fix compile time issue regarding switch ranges 2018-02-17 19:05:14 +00:00
gingerBill 21432ba96e Clean up range code for switch 2018-02-17 18:34:14 +00:00
gingerBill c341597657 Remove constant from switch for strings 2018-02-17 18:22:43 +00:00
Mikkel Hjortshøj 2a1420d4e7 Update README.md 2018-02-17 15:03:26 +01:00
Mikkel Hjortshoej 28d88f6af4 rounded logo 2018-02-17 15:03:16 +01:00
gingerBill c4d2d287fc #complete switch; Removal of dyncall 2018-02-17 11:54:08 +00:00
gingerBill 6a85546b76 Fix #187 2018-02-14 21:46:39 +00:00
gingerBill 2e92d0c821 Remove old procedures 2018-02-13 22:05:25 +00:00
gingerBill a499a3aa5e Merge pull request #184 from ThisDrunkDane/master
Added widechar versions of functions, plus cursor functions
2018-02-13 22:02:43 +00:00
gingerBill 23ab3c4713 Replace [...] with [?] 2018-02-13 21:59:49 +00:00
gingerBill da300aa9c3 Fix enum #export does not work with export #185 2018-02-13 18:01:42 +00:00
ThisDrunkDane e225158a6f Merge branch 'master' of https://github.com/odin-lang/Odin 2018-02-12 06:07:15 +01:00
gingerBill 2ce55783d2 Fix make 2018-02-11 23:47:46 +00:00
gingerBill 14eeee40b2 Update demo.odin 2018-02-11 11:16:17 +00:00
gingerBill 038dea9202 v0.8.1
Fix initialization values for variables
2018-02-11 11:15:53 +00:00
gingerBill 0ae3484171 Fix zero value initialization in IR 2018-02-11 11:13:52 +00:00
gingerBill 54976c3249 v0.8.0 2018-02-09 18:03:06 +00:00
Mikkel Hjortshoej 4c06b44315 Merge branch 'master' of github.com:odin-lang/odin 2018-02-07 21:23:28 +01:00
Mikkel Hjortshoej 678b58e0b1 Added widechar versions of functions, plus cursor functions 2018-02-07 21:17:59 +01:00
gingerBill 8f913c656c Fix error reporting for assignment to a built-in procedure (#183) 2018-02-07 18:55:01 +00:00
gingerBill 001b48a5c6 Change local variable alignment to 16 bytes for the time being 2018-02-05 23:27:18 +00:00
gingerBill 54929a1b92 Minor context fix 2018-02-05 23:09:34 +00:00
gingerBill 92780e2683 distinct keyword for type declarations 2018-02-05 22:46:30 +00:00
gingerBill 2891988d3b Add extra check to ir_emit_zero_init 2018-02-05 22:26:22 +00:00
gingerBill c1728914c6 Fix typos #type_alias 2018-02-04 21:34:45 +00:00
gingerBill ed2f49e8d2 Remove dead code; Fix issue regarding order of evaluation of function parameters (in C++) depending on the compiler (clang vs gcc vs msvc) 2018-02-04 20:07:05 +00:00
gingerBill 8a76a370a9 Merge pull request #182 from ThisDrunkDane/master
Functions, structs and constants related to getting file notifications
2018-02-04 19:49:04 +00:00
Mikkel Hjortshoej 1160fd4331 functions, structs and constants related to getting file notifications 2018-02-03 21:56:15 +01:00
gingerBill 0134c38759 Fix issue #181 2018-02-03 10:32:47 +00:00
gingerBill d079095517 Fix bug #179 2018-02-03 10:27:33 +00:00
gingerBill 028d628e9f Add extra zero init for IR 2018-01-31 18:27:08 +00:00
gingerBill 5e4b62acfe Fix literal 2018-01-28 15:59:37 +00:00
gingerBill 9366fa8e95 Simplify printing for float and complex types 2018-01-28 15:58:34 +00:00
gingerBill 369db3a8e3 Add __print_type to runtime 2018-01-28 15:55:37 +00:00
gingerBill 8c360b2a3c Reduce type info data size in IR 2018-01-28 15:43:58 +00:00
gingerBill b66e7bed45 Improve min-dep for Type Info 2018-01-28 15:37:15 +00:00
gingerBill e919482aa8 Add ir_emit_store_union_variant to reduce alloca use 2018-01-28 15:09:07 +00:00
gingerBill dce45e7d58 Add ODIN_DEBUG 2018-01-28 14:42:22 +00:00
gingerBill 1a0877e965 Fix minimum dependency generation for foreign entities 2018-01-28 14:39:18 +00:00
gingerBill 0361a18551 Remove old math constants 2018-01-28 11:59:28 +00:00
gingerBill 83d90f1463 Extra check for type_info cycle checking 2018-01-28 09:51:52 +00:00
gingerBill f661ae9d09 Fix issue with proc group cycles #176 2018-01-28 09:19:23 +00:00
gingerBill bee4cb57f2 Fix printf bug #177 2018-01-28 09:13:29 +00:00
gingerBill 53b670b889 Merge branch 'master' of https://github.com/odin-lang/Odin 2018-01-28 08:59:31 +00:00
gingerBill e2600a3e44 Fix #178 2018-01-28 08:59:10 +00:00
gingerBill 25101b2ae0 Merge pull request #175 from ThisDrunkDane/windows.odin-adds
More file handling functions
2018-01-25 14:02:32 +00:00
Mikkel Hjortshoej 4e7867fcc1 More file handling functions 2018-01-25 00:00:34 +01:00
gingerBill 101ee64165 Merge pull request #174 from ThisDrunkDane/windows.odin-adds
Added stuff to windows.odin
2018-01-24 09:41:09 +00:00
Mikkel Hjortshoej 4c3e65791e added stuff to windows.odin 2018-01-24 07:26:29 +01:00
gingerBill a9c8031b61 Fix sync_windows.odin 2018-01-21 21:21:57 +00:00
gingerBill afb3033913 Change thread.odin to use a rawptr rather than any 2018-01-21 21:19:03 +00:00
gingerBill 2ad26640a2 Revert back to gb_memmove 2018-01-21 19:30:05 +00:00
gingerBill 2c0b08145f Fix nested defer blocks 2018-01-21 19:26:55 +00:00
gingerBill aa9c9eda9e Fix boolean casting 2018-01-21 18:41:21 +00:00
gingerBill 1353d61894 Minor parsing change 2018-01-21 16:45:29 +00:00
gingerBill 88ba6d8015 enum #export 2018-01-21 14:30:48 +00:00
gingerBill 8b288a2072 Reimplement opt stage 2018-01-20 16:16:59 +00:00
gingerBill 4e90644527 Remove timing for llvm-opt 2018-01-20 16:15:05 +00:00
gingerBill 6651b65373 Remove need for opt 2018-01-20 16:13:36 +00:00
gingerBill 705352099f Remove #endif 2018-01-20 16:10:26 +00:00
gingerBill 2e28c9d793 Cache type size/align; Improve speed of ir_print.cpp 2018-01-20 15:12:44 +00:00
gingerBill 2fe660a1d7 Fix empty union IR bug 2018-01-19 17:11:28 +00:00
gingerBill b03ce0e9b4 Modify implicit semicolon rules 2018-01-18 17:28:07 +00:00
gingerBill 386f5f596d Change to HeapAlloc et al on Windows 2018-01-18 13:11:51 +00:00
gingerBill add53228b2 -no-bounds-check 2018-01-18 12:22:27 +00:00
gingerBill d90008cc52 Add basic debug information needed for stepping over code 2018-01-18 12:12:18 +00:00
gingerBill dbf8f9ab38 Add extra comments for clarity 2018-01-17 21:22:45 +00:00
gingerBill 81a99cf67b Debug fix target triple and procedure positioning 2018-01-17 20:57:54 +00:00
gingerBill 876af6fb02 Modify boolean conversion in IR 2018-01-17 19:27:13 +00:00
gingerBill b3734a5f77 Add math/rand.odin 2018-01-17 19:09:22 +00:00
gingerBill 419ab6f00c Named return value act as variables; Code reorganization 2018-01-17 19:07:38 +00:00
gingerBill 5558b55e9f Fix ir_emit_store for booleans 2018-01-17 14:06:06 +00:00
gingerBill 4b14d608f4 Update sys/windows.odin to use Bool :: b32; rather than i32 2018-01-17 14:02:19 +00:00
gingerBill 9428d86f2b Specific sized booleans: b8, b16, b32, b64 2018-01-17 14:00:49 +00:00
gingerBill ddebf0daf2 Merge branch 'master' of https://github.com/odin-lang/Odin 2018-01-17 13:16:59 +00:00
gingerBill 3a44c62ecf Remove old "macro" parsing code 2018-01-17 13:16:43 +00:00
gingerBill 184efd4f49 Update demo for using in 2018-01-13 22:42:05 +00:00
gingerBill 6b3c4cc379 Remove u128 and i128 2018-01-13 22:26:37 +00:00
gingerBill 0b137e087c Fix mem.odin #173 2018-01-12 11:44:09 +00:00
gingerBill 37790c13a0 Fix issue #170 2018-01-10 21:17:09 +00:00
gingerBill 82057f08ce Fix issue #172 2018-01-10 21:13:20 +00:00
gingerBill 1553421e1a Fix typo in error 2018-01-01 22:15:43 +00:00
gingerBill f3ea109e6f Fix min/max for floats 2018-01-01 11:41:32 +00:00
gingerBill 90dbfe7660 Fix issue #167 regarding abs, min, and, max for floats 2017-12-27 20:35:50 +00:00
gingerBill 125bad3154 Fix 'llvm bool' emit store 2017-12-23 09:46:28 +00:00
gingerBill 30c83d6c81 Fix map internals 2017-12-23 09:30:40 +00:00
gingerBill 4f12c118a5 Fix Type info bug for 'llvm bool' 2017-12-23 09:06:49 +00:00
gingerBill 423775d50e Merge branch 'master' of https://github.com/odin-lang/Odin 2017-12-22 18:14:50 +00:00
gingerBill 860a5c3e86 "Fix" LLVM boolean bug (more like a bodge) 2017-12-22 18:14:35 +00:00
gingerBill 649e02f209 Add basic example to README.md 2017-12-22 11:29:33 +00:00
gingerBill b449305cc1 Fix free_map 2017-12-21 21:05:53 +00:00
gingerBill 49bee6bad0 Fix free_map 2017-12-21 21:01:28 +00:00
gingerBill ac277a1cce Revert map to be a value type and not a reference type
(Implement code for "const ref" parameters)
2017-12-21 20:59:23 +00:00
gingerBill a17310a83c Fix len, cap, comparison against nil for map 2017-12-18 20:43:02 +00:00
gingerBill b509946b13 Fix fallthrough within a nested block 2017-12-17 21:55:20 +00:00
gingerBill a69ea58388 map is internally backed by a pointer (i.e. a "reference type") 2017-12-17 19:25:35 +00:00
gingerBill 30530d058c Remove struct #ordered 2017-12-17 14:53:40 +00:00
gingerBill 436928d06a Fix "using in import" 2017-12-17 12:12:24 +00:00
gingerBill 32a502d14e using x in bar; 2017-12-17 11:44:26 +00:00
gingerBill 0d665c637f using in importation statements 2017-12-17 11:17:54 +00:00
gingerBill 1b6a14ac39 Fix lhs < rhs bug (#164) 2017-12-14 19:56:32 +00:00
gingerBill 367013f589 Change Map and PtrSet grow rate 2017-12-12 23:39:20 +00:00
gingerBill c980a30bad Merge branch 'checker-optimizations' into explicit-overloading
# Conflicts:
#	examples/demo.odin
2017-12-12 21:22:46 +00:00
gingerBill 78b459590c Print nil for nil procedures in fmt.odin 2017-12-12 21:21:55 +00:00
gingerBill 054e241033 Localize checker data 2017-12-12 20:23:36 +00:00
gingerBill f7e9649be4 Disable struct field reordering (for the time being) 2017-12-12 18:21:40 +00:00
gingerBill fd1f6ec75c Merge branch 'master' into explicit-overloading 2017-12-11 11:13:22 +00:00
gingerBill 6b0d7cb26c Fix issue #162 regarding empty unions 2017-12-11 11:08:02 +00:00
gingerBill 3aea08df78 Change how abs, min, max, and clamp are implemented for floats 2017-12-11 11:06:43 +00:00
gingerBill 3c6f90e552 Fix proc groups from import names 2017-12-10 11:35:11 +00:00
gingerBill 3703ca4df4 Explicit procedure group; Remove implicit procedure overloading 2017-12-09 18:11:36 +00:00
gingerBill 41b8281c73 Set type of a procedure grouping to nullptr 2017-12-06 11:13:00 +00:00
gingerBill acd1f83bd0 Fix procedure groupings 2017-12-06 11:11:53 +00:00
gingerBill ba8371104d Set procedure grouping type to t_invalid 2017-12-06 11:01:52 +00:00
gingerBill 991682e9fd Fix write_entire_file 2017-12-06 10:58:02 +00:00
gingerBill f0de994059 Make core library use procedure groupings rather than normal overloading 2017-12-04 22:01:51 +00:00
gingerBill ebb2a9812c Merge pull request #160 from thebirk/patch-1
Added skip for Entity_ProcedureGrouping
2017-12-04 15:07:09 +00:00
Aleksander Birkeland 265c05927f Added skip for Entity_ProcedureGrouping 2017-12-04 16:05:42 +01:00
gingerBill 05ad38ae2d Fix procedure grouping 2017-12-03 23:19:25 +00:00
gingerBill 596a2c8355 Procedure grouping foo :: proc[foo16, foo32]; 2017-12-03 23:03:40 +00:00
gingerBill 9f52b2c283 Update demo.odin 2017-12-03 22:28:54 +00:00
gingerBill 8035a407a6 Remove dead code 2017-12-03 20:59:48 +00:00
gingerBill 97760c3fa4 Fix union_tag_size; Fix constant array of array literal printing with scalar contents 2017-12-03 20:49:19 +00:00
gingerBill d75291097e &x.(type) 2017-11-30 23:09:21 +00:00
gingerBill db632b7e22 buffer_from_slice 2017-11-30 20:42:16 +00:00
gingerBill 1a75dfe075 Remove vector type (will be replaced by something else in the future) 2017-11-30 20:34:42 +00:00
gingerBill e00d88d82e Fix issue #157 2017-11-30 19:53:40 +00:00
gingerBill 04cce1826b Fix map IR bug 2017-11-28 23:46:01 +00:00
gingerBill cc28cda053 Fix issue #156 2017-11-28 22:49:34 +00:00
gingerBill cfabc0e61f Remove using in arrays; Remove _ non-exported struct fields
Start determining slow parts of the compiler
2017-11-28 22:12:33 +00:00
gingerBill 91b534d128 Fix transmute 2017-11-27 23:00:23 +00:00
gingerBill 3268f43340 Update ABI for basic types 2017-11-27 20:37:09 +00:00
gingerBill 05e374934d Change proc ABI for Odin specific types 2017-11-27 20:18:06 +00:00
gingerBill 3e1ff0ec67 Update fmt for runes; Add strings.contains_rune 2017-11-26 23:54:23 +00:00
gingerBill 65945dac09 Fix comparison against nil for slices 2017-11-26 22:49:31 +00:00
gingerBill 1608da2dc8 for key, val in some_map {}; for val, idx in some_array {} 2017-11-26 18:56:47 +00:00
gingerBill c340827381 Remove old slice procedures 2017-11-26 18:38:46 +00:00
gingerBill 74fa7ca25d New slice memory layout (ptr+len); byte 2017-11-26 18:36:46 +00:00
gingerBill 5a9223afda nil_allocator; Fix IR type checking assert; append_string 2017-11-26 15:25:45 +00:00
gingerBill febcd73323 Fix merge from essence cross compile #154 2017-11-26 11:11:29 +00:00
gingerBill df06236076 Merge pull request #154 from nakst/master
essence cross compile
2017-11-26 11:10:13 +00:00
Nakst b0d3fbba47 essence cross compile 2017-11-26 11:03:11 +00:00
gingerBill adb6c7637e Fix 'fallthrough' 2017-11-25 11:16:23 +00:00
gingerBill 425f83b17d Merge pull request #150 from zangent/master
Changed `string_has_extension` to `string_ends_with` and fix macOS target triple
2017-11-21 22:33:39 +00:00
gingerBill 976415ff9d Fix key lookup of pointer to map 2017-11-21 22:32:41 +00:00
Zachary Pierson 4d7fb3e8d6 Changed string_has_extension to string_ends_with.
Fixed macOS target triple.
2017-11-21 16:16:53 -06:00
gingerBill bcca3bf322 Remove target triple from windows 2017-11-19 16:55:24 +00:00
gingerBill 74aaa3408f Fix debug symbol generation 2017-11-19 16:45:12 +00:00
gingerBill 2a5beee88c Remove /SYMBOLS flag 2017-11-19 15:11:07 +00:00
gingerBill cec9f7abfe Add -debug command (still in development) 2017-11-19 15:06:56 +00:00
gingerBill 284a9cd4c3 Update usage text 2017-11-19 09:57:37 +00:00
gingerBill 5955c101d4 Update version 2017-11-19 09:56:51 +00:00
gingerBill f80b910ba3 Set version number to v0.7.1 2017-11-19 09:50:22 +00:00
gingerBill 2b0521347b Begin with on debugging symbol; fix version number 0.7.0 2017-11-19 09:49:55 +00:00
gingerBill 0c06a8d154 Fix issue #146 regarding polymorphic type parameters 2017-11-18 20:56:53 +00:00
gingerBill b0e3a4e276 build_dll replace with -build-mode=dll 2017-11-17 20:21:58 +00:00
gingerBill b651466630 Add ptr_to_bytes 2017-11-16 19:01:57 +00:00
gingerBill 24c09c9201 Allow for printf style assert and panic 2017-11-16 18:57:03 +00:00
gingerBill e48346a9ee Disable negation of unsigned constants (Issue: #145) 2017-11-15 21:25:16 +00:00
gingerBill 9bd8bdaa5a Disable all cyclic importations 2017-11-13 23:53:01 +00:00
gingerBill a137699d95 Add optional truncate parameter to write_entire_file (#144) 2017-11-13 20:35:21 +00:00
gingerBill f6a56c2f82 Remove #const; Minor fixes 2017-11-12 20:15:17 +00:00
gingerBill dffa791607 In error messages, remove with '; Fix error messages for switch` 2017-11-12 19:00:48 +00:00
gingerBill 5ce6555721 Allow for default arguments after a variadic parameter 2017-11-12 17:55:16 +00:00
gingerBill 53b3ad186f Fix untyped type IR bug 2017-11-10 22:37:38 +00:00
gingerBill 82c1c5b3fe Merge pull request #142 from zangent/master
Added static linking for macOS, too. There's literally %number% of us!
2017-11-10 22:14:40 +00:00
Zachary Pierson 6d880bc3bb Added static linking for macOS. Also fixed the build.sh. Thanks, vass :/ 2017-11-10 16:11:55 -06:00
gingerBill 40281d595d Fix parsing errors for variadic signatures 2017-11-10 22:03:05 +00:00
gingerBill 85fab55e57 Fix make 2017-11-10 21:43:37 +00:00
gingerBill 1d2eb8055e Merge pull request #140 from vassvik/master
Fixed foreign import for linux. Modified .gitignore to ignore temp files and files in shared/. Added a Makefile for linux
2017-11-10 21:17:16 +00:00
vassvik 9e0b69312b Fixed foreign import for linux. Modified .gitignore to ignore temp files and files in shared/. Added a Makefile for linux 2017-11-10 21:31:13 +01:00
gingerBill bbddbba340 Fix cast to uintptr 2017-11-10 18:56:47 +00:00
gingerBill 0d01a6f552 Fix issue #139 2017-11-10 18:24:49 +00:00
gingerBill ae3672608d Fix link_name overriding 2017-11-09 23:36:10 +00:00
gingerBill e5c39fb2a9 Fix opening file without close; Minor fixes 2017-11-09 22:58:44 +00:00
gingerBill eb4b3f5976 Change push allocator system; update core libraries 2017-11-09 22:48:00 +00:00
gingerBill dbb070524f Allow nil in a ternary statement 2017-11-09 21:10:08 +00:00
gingerBill 36b0b50ba4 Amend allocation procedures with caller location; Compound literals missing type can determine type in certain cases. 2017-11-09 20:51:13 +00:00
gingerBill ac46b2053d Remove unnecessary IR bound checks 2017-11-08 22:14:07 +00:00
gingerBill 0ffcccdae5 Add Source_Code_Location parameter Allocator_Proc (#138) 2017-11-08 22:05:51 +00:00
gingerBill 4777bd607e Fix issue #137 2017-11-08 22:02:15 +00:00
gingerBill 39e9b50482 Remove debug code 2017-11-07 23:09:05 +00:00
gingerBill 30adb9c770 Fix issue #134 2017-11-07 23:05:39 +00:00
gingerBill b1d1497f4b Fix array of array arithmetic 2017-11-07 23:02:53 +00:00
gingerBill 9df3a94d33 Fix cyclic type checking bug 2017-11-05 23:38:09 +00:00
gingerBill d4f335d068 Fix fmt.odin %#v fancy printing 2017-11-05 19:47:18 +00:00
gingerBill 74341b9b74 Fix IR generation issue 2017-11-05 19:37:46 +00:00
gingerBill 66ee2cb6ed #const value procedure parameters; $N for polymorphic array lengths 2017-11-05 18:26:24 +00:00
gingerBill 1d4881cbbe Add array programming 2017-11-05 14:22:18 +00:00
gingerBill 04b917a60a More code clean up 2017-11-04 10:53:47 +00:00
gingerBill e6c99cd289 Cleanup attribute handling 2017-11-04 10:26:56 +00:00
gingerBill 6bc5584add Fix fmt printing uintptr type 2017-11-04 00:16:54 +00:00
gingerBill 121f0185d6 Custom thread local models 2017-11-03 23:46:42 +00:00
gingerBill e7999f8450 Foreign context cleanup 2017-11-03 23:20:30 +00:00
gingerBill 0b29e42adb link_prefix; thread_local; fix link_name for file-scope variables 2017-11-03 23:11:06 +00:00
gingerBill fcc8b89e6b Fix issue #130; allow conversion from any pointer to uintptr and vice versa 2017-11-02 22:34:09 +00:00
gingerBill 529d1c78c7 Fix issue #131 2017-11-02 22:30:12 +00:00
gingerBill 414486829a Add string_set.cpp; Code clean up 2017-10-30 20:26:05 +00:00
gingerBill 3e05be8eb8 @(default_calling_convention = ...) for foreign blocks 2017-10-29 18:09:05 +00:00
gingerBill ae24a8e5ae Fix pointer arithmetic; remove suffix #tags for proc types 2017-10-29 17:00:54 +00:00
gingerBill d2588f9d1d Infix proc calling convention proc "std" (...) 2017-10-29 16:44:44 +00:00
gingerBill 1eb9994d88 Attributes; @(link_name="foo") 2017-10-29 15:46:23 +00:00
gingerBill a43b89f36e #alias type declarations; core library additions; _global import name for the global scope 2017-10-29 11:35:21 +00:00
gingerBill 0ed34af19d Fix importation of empty file (issue #128) 2017-10-18 22:52:42 +01:00
gingerBill 71729c2855 Add anonymous using import names with an underscore (#127)
`using import _ "foo.odin"`
2017-10-18 22:29:14 +01:00
gingerBill 6c8c430c2a Fix enum iteration (issue #126) 2017-10-18 22:26:04 +01:00
gingerBill 57b97ad0bd Fix issue #124 2017-10-15 23:30:55 +01:00
gingerBill 56f7a859df Refactor code to remove entity flag for export 2017-10-15 16:16:16 +01:00
gingerBill e5e14b9947 Remove name mangling for foreign export variables 2017-10-15 16:11:34 +01:00
gingerBill 3d8bf36a30 foreign export block
```
foreign export {
    my_i32: i32;
    my_foo :: proc() -> i32 {
        return 123;
    }
}
```
2017-10-15 16:05:42 +01:00
gingerBill 85f7c2d040 Change foreign_library to foreign import 2017-10-15 15:21:56 +01:00
gingerBill 26ea8f6dcb Syntax: Replace foreign_system_library "kernel.lib" to foreign_library "system:kernel.lib"; Remove keyword: foreign_system_library 2017-10-15 12:11:33 +01:00
gingerBill e05fe1837d Fix minimal dependency generation for polymorphic structs (related to issue #121) 2017-10-15 11:21:48 +01:00
gingerBill 94762b56f6 Fix issue #122 2017-10-15 10:14:17 +01:00
gingerBill b3b688fa50 Fix issue #123 2017-10-15 10:09:50 +01:00
Ginger Bill 5eaa8de8f9 Fix issue with #118 2017-10-12 21:01:16 +01:00
Ginger Bill 26d3c54aff Fix issue #119
This may need better error messages
2017-10-12 20:52:19 +01:00
Ginger Bill 349a62121c Fix issue #120 2017-10-12 20:32:44 +01:00
Ginger Bill bbb0e14633 Fix using import to work correctly 2017-10-12 20:28:32 +01:00
Ginger Bill 42312d9def Fix typos in c.odin 2017-10-10 23:43:31 +01:00
Ginger Bill 065d0e4ee3 Fix string_to_enum_value 2017-10-09 22:56:48 +01:00
Ginger Bill b772ad7094 Fix issue #116 2017-10-09 17:58:12 +01:00
Ginger Bill 444d366c39 Fix issue #115 2017-10-09 17:56:26 +01:00
Ginger Bill 8e4233b86a Correct union size 2017-10-08 15:19:01 +01:00
Ginger Bill 6424966b7a Union tag stored as an integer 2017-10-08 15:16:13 +01:00
Ginger Bill 4e42d7df43 Minor code reorganization 2017-10-08 12:27:03 +01:00
Ginger Bill 580ee5cc4a Fix using on import names 2017-10-08 11:08:15 +01:00
Ginger Bill 56a98a483f Better error messages for import cycles 2017-10-08 10:58:16 +01:00
Ginger Bill df7a4eda8a Allow for cyclic import but disallow cyclic using import and export 2017-10-07 11:37:43 +01:00
Ginger Bill 91cc0b282a Fix issue #114 2017-10-04 18:57:27 +01:00
Ginger Bill 01d8aea4df Disallow procedures literals as default values in anonymous struct types 2017-10-01 21:44:55 +01:00
Ginger Bill ee904060c5 Disallow anonymous structs with procedures as default values 2017-10-01 21:22:39 +01:00
Ginger Bill afb5538e83 Default procedure values for proc 2017-10-01 20:27:02 +01:00
Ginger Bill 1f24f105cc "Constant" procedure values for default values in structs 2017-10-01 20:10:13 +01:00
Ginger Bill 8f39ebbe5a Procedure literals for default values in structs 2017-10-01 20:01:00 +01:00
Ginger Bill c1e720a49b match to switch; Optional semicolons after "import" statements 2017-10-01 17:09:57 +01:00
Ginger Bill f38c8875b2 Fix issue #104 2017-10-01 14:29:54 +01:00
Ginger Bill e7e51f53ce Fix cyclic polymorphic struct bug #111 2017-10-01 14:10:31 +01:00
Ginger Bill 5259de5872 Reserve the link_name main 2017-09-30 11:28:17 +01:00
Ginger Bill e2b9c87aa8 Wrap entry point main around the C style main in the IR 2017-09-30 11:20:35 +01:00
Ginger Bill 8c7cf0dbb0 Fix union array bug (Issue #112) 2017-09-29 21:35:59 +01:00
Ginger Bill e6e9375b09 Remove http_test.odin 2017-09-29 21:20:39 +01:00
Ginger Bill c6096f9205 Revert to demo.odin 2017-09-29 21:11:51 +01:00
Ginger Bill 11614c2649 Fix old_demos; Fix when bug; Fix enum .names 2017-09-29 21:11:16 +01:00
Ginger Bill 793bc8c585 Fix issue #89 2017-09-25 23:08:22 +01:00
Ginger Bill 335e88b738 Fix issue #106 2017-09-25 23:06:04 +01:00
Ginger Bill b77ea94976 Fix issue #108 2017-09-25 22:59:59 +01:00
Ginger Bill ae17a51c0d Fix issue #109 2017-09-25 22:53:59 +01:00
gingerBill ee7a83f124 Merge pull request #110 from ThisDrunkDane/invalid-token-print-pos
Print position of the invalid token found during parsing.
2017-09-25 22:51:41 +01:00
Mikkel Hjortshoej 67ac551a2f The position that the invalid token was found at is printed 2017-09-25 21:42:23 +02:00
Ginger Bill 572ac616c1 Prevent statements after branch statements. 2017-09-24 14:58:15 +01:00
Ginger Bill 96bf6a5bcb Fix cyclic importation error printing 2017-09-23 20:47:02 +01:00
Ginger Bill c43d66c286 Use comma for struct field separators (disallow nesting) 2017-09-21 23:18:28 +01:00
Ginger Bill 95fb5fa46c Fix #export proc tag 2017-09-21 22:32:24 +01:00
Ginger Bill d614913c11 Fix decimal.odin, again 2017-09-20 23:17:33 +01:00
Ginger Bill 3bfaac0844 Fix decimal.odin assignment bug 2017-09-20 22:59:46 +01:00
Ginger Bill 14d0cbf6d7 Fix load order of files (again) 2017-09-20 21:42:42 +01:00
Ginger Bill 61a163d773 Fix crash with build_dll (Issue #100) 2017-09-20 21:00:40 +01:00
Ginger Bill 3a644dad78 Fix issue #101 2017-09-20 20:45:40 +01:00
Ginger Bill d2c1c719bd Fix file load order and allow when statements at file scope 2017-09-20 20:38:32 +01:00
Ginger Bill 333db4dc94 Fix issues #95 and #96 2017-09-13 22:20:27 +01:00
Ginger Bill cbcf4b6071 Fix issue #94 2017-09-11 22:49:26 +01:00
Ginger Bill e6e0aba8c3 Remove when suffixes; Implement file scope when statement, evaluated in source order 2017-09-10 15:17:37 +01:00
Ginger Bill 85097a9958 Fix global variable initialization IR bug 2017-09-10 13:50:11 +01:00
Ginger Bill 7791c343c4 Allow for multiple library collections; Store AstFile as pointer 2017-09-10 13:26:14 +01:00
Ginger Bill 3bd762591a Fix path_is_directory for *nix 2017-09-07 21:33:37 +01:00
Ginger Bill 8e3b77aba8 Library collections 2017-09-07 20:55:59 +01:00
Ginger Bill 36e3a02f67 Fix bit_field type information 2017-09-02 22:54:11 +01:00
Ginger Bill 566a242ba3 Fix issue #92 2017-09-02 10:06:44 +01:00
Ginger Bill 1e3b3c107c IR Fix for UnionTagValue 2017-08-28 23:04:48 +01:00
Ginger Bill 2ac33285c1 Remove metagen.odin 2017-08-27 23:28:20 +01:00
Ginger Bill 7cb8016df3 Add examples 2017-08-27 23:27:12 +01:00
Ginger Bill cf3c5a878a export declarations 2017-08-27 19:36:43 +01:00
Ginger Bill 2d20bde495 Remove () grouping for foreign_library 2017-08-27 19:24:30 +01:00
Ginger Bill b9e347ef50 Replace import_load with using import . 2017-08-27 17:03:27 +01:00
Ginger Bill 6707c8750e Import cycle checking 2017-08-27 14:42:19 +01:00
Ginger Bill e5502c13ee Restrict global variables to not allow tuples 2017-08-20 19:35:52 +01:00
Ginger Bill f30d2e43ea Add priority_queue.cpp and ptr_set.cpp 2017-08-20 18:39:09 +01:00
Ginger Bill 6c73f9d3fd Global variable dependency initialization ordering
Fuck graph theory
2017-08-20 18:28:21 +01:00
Ginger Bill 1161aa829d Fix mem.Arena 2017-08-13 22:20:44 +01:00
Ginger Bill 01519f2fd5 Fix push_allocator 2017-08-13 22:09:26 +01:00
Ginger Bill 33aad3a8ce Merge branch 'master' of https://github.com/gingerBill/Odin 2017-08-12 20:04:58 +01:00
Ginger Bill 4262c125c5 Fix struct #packed alignment calculation 2017-08-12 20:04:35 +01:00
Ginger Bill a09d5959ef Fix issues with OSX 2017-08-11 12:47:07 +01:00
Ginger Bill d7bd3f8402 Fix compilation issues on OSX 2017-08-11 00:16:57 +01:00
Ginger Bill 0fff6a2b74 Fix i128 division 2017-08-10 23:46:12 +01:00
Ginger Bill f4c0405221 Fix inline #raw_union bug in issue #87 2017-08-08 21:27:42 +01:00
Ginger Bill 49d337c830 v0.6.2; Use Ada_Case for types 2017-08-03 21:21:56 +01:00
Ginger Bill 294092979e Update build.bat 2017-08-01 21:38:06 +01:00
Ginger Bill c454ede184 v0.6.1a 2017-08-01 17:30:26 +01:00
Ginger Bill d854c5003c Fix minor errors for *nix 2017-08-01 17:28:49 +01:00
Ginger Bill 66d8776b83 v0.6.1 2017-08-01 15:18:37 +01:00
Ginger Bill ba6ecf35cf Disable threading on *nix for the time being 2017-08-01 15:09:43 +01:00
Ginger Bill 10cc9cf661 Add mutexes to string buffer allocator uses 2017-08-01 14:24:40 +01:00
Ginger Bill 2db971eedd Use pthread mutex 2017-08-01 13:49:12 +01:00
Ginger Bill 1775e80b41 HACK: Ignore Mutex check 2017-07-31 23:18:21 +01:00
Ginger Bill e4a93619db Update gb.h 2017-07-31 12:17:53 +01:00
Ginger Bill 4d14b3bcb4 Update remove_temp_files 2017-07-31 12:15:20 +01:00
Ginger Bill 9f4f5f9346 Add -keep-temp-files option 2017-07-31 12:06:04 +01:00
Ginger Bill 0fae31fb54 Extra type safety; Fix typos 2017-07-31 11:36:00 +01:00
Ginger Bill 8987a6630c v0.6.0 2017-07-30 22:26:22 +01:00
Ginger Bill 10ff8e0426 Fix ir for TypeInfo.Map 2017-07-30 20:17:25 +01:00
Ginger Bill a0ae02168a Update add_type_info_type to ignore polymorphic types 2017-07-30 20:13:23 +01:00
Ginger Bill a3c1ac2030 Speed up llvm ir printing; Use CRITICAL_SECTION for Mutex on windows 2017-07-30 19:47:37 +01:00
Ginger Bill 629b248f53 Parallelization of the Parser
~66% reduction (unoptimized build)
~30% reduction (optimized build)
2017-07-30 19:01:02 +01:00
Ginger Bill 62a72f0163 transmute(type)x; Minor code clean up 2017-07-30 14:52:42 +01:00
Ginger Bill 655931f0ea Minor Simplification of threading demo 2017-07-29 15:18:36 +01:00
Ginger Bill ca36fabfc0 Remove dead code for the "fixed" map idea 2017-07-29 14:43:42 +01:00
Ginger Bill 7bd62481ad Fix nil assignment to unions 2017-07-29 14:23:34 +01:00
Ginger Bill fbd27d7c45 Fix map internal type generation 2017-07-29 13:56:45 +01:00
Ginger Bill 3546391311 Merge branch 'master' of https://github.com/gingerBill/Odin 2017-07-29 13:01:28 +01:00
Ginger Bill 24c812115e Remove empty union check on array types; Fix overflowing error printing 2017-07-29 13:01:17 +01:00
gingerBill 28be0ad69b Fix IR print bug for empty structs; 2017-07-28 11:35:01 +01:00
gingerBill f0980c0a98 Fix import name exportation bug; Fix procedure type printing 2017-07-24 07:57:09 +01:00
Ginger Bill 1df4aa90ce Fix struct parameter bugs 2017-07-21 15:25:58 +01:00
Ginger Bill 6b3cf051f8 Fix math.odin, again 2017-07-21 12:39:05 +01:00
Ginger Bill 4ecd6e592b Fix missing semicolons in math.odin 2017-07-21 10:37:49 +01:00
Ginger Bill dbddec33c8 Internal changes; thread.odin for windows only 2017-07-20 23:57:56 +01:00
Ginger Bill 401a5955a4 Fix minor check on vector types 2017-07-20 19:55:54 +01:00
Ginger Bill 9a3b4167bb Fix polymorphic element types usage; Empty union as opaque type 2017-07-20 19:40:51 +01:00
Ginger Bill 13bc6eeea4 Make fields et al an Array rather than a raw pointer 2017-07-20 15:32:34 +01:00
Ginger Bill 2da18b6d33 Change internals from Record to Struct 2017-07-20 15:23:13 +01:00
Ginger Bill 6d37ed12d2 Update internals of a Union and Tuple 2017-07-20 15:17:04 +01:00
Ginger Bill eab23cd5b7 Fix parsing bug with procedure types in return values 2017-07-19 22:34:50 +01:00
Ginger Bill d233706a2d Fix minor parsing bug with procedure return types 2017-07-19 22:17:57 +01:00
Ginger Bill f1ab17ed4e type_info_of; enum_value_to_string and string_to_enum_value 2017-07-19 14:01:56 +01:00
Ginger Bill 6113164211 Change union layout to store type info rather than an integer; ternary expression for types with constant condition 2017-07-19 12:15:21 +01:00
Ginger Bill 4db462a703 Fix copy 2017-07-18 20:39:53 +01:00
Ginger Bill a22c6d6c0c Fix parsing error for compound literals 2017-07-18 19:57:30 +01:00
Ginger Bill 59fb7b020a Merge raw_union into struct as a memory layout tag #raw_union 2017-07-18 19:24:45 +01:00
Ginger Bill 65f079ebc4 Remove atomic, ++, and -- 2017-07-18 18:58:41 +01:00
Ginger Bill d16aa79492 General specialization for polymorphic parameters 2017-07-18 18:05:41 +01:00
Ginger Bill 5af0acc4af Disallow default struct values for any; new_clone 2017-07-18 16:02:01 +01:00
Ginger Bill a459364de3 Ignore missing default values for struct literals at the end 2017-07-18 15:32:34 +01:00
Ginger Bill 277ef1a68f Allow undefined --- as a struct field default value. 2017-07-18 15:09:24 +01:00
Ginger Bill 193c7c82c8 Default struct field values 2017-07-18 14:56:07 +01:00
Ginger Bill f7d8ba408c Fix some preload bugs. 2017-07-18 11:42:16 +01:00
Ginger Bill 9a8759efef Polymorphic type specialization for procedures 2017-07-17 15:08:36 +01:00
Ginger Bill 054948e701 Basic procedure type parameter specialization 2017-07-16 15:00:16 +01:00
Ginger Bill 1c5ddd65b4 Rudimentary support for parametric polymorphic types 2017-07-13 22:35:00 +01:00
Ginger Bill b8697fb4ed Change precedence order for types e.g. ^T(x) == ^(T(x)) 2017-07-13 16:20:07 +01:00
Ginger Bill 03570275c1 Fix issue #78 and have a better error message. 2017-07-13 11:35:01 +01:00
Ginger Bill b5587f1937 Fix aliasing of overloaded procedures from other scopes 2017-07-11 20:54:38 +01:00
Ginger Bill c4c6975f1b cast(Type)expr; Fix overloaded procedure determination on assignment 2017-07-11 14:40:27 +01:00
Ginger Bill 0be0fb2a57 Nested when statements within records 2017-07-10 23:47:22 +01:00
Ginger Bill 115e6e7f9e Update demo for both subtyping and union based Entity 2017-07-10 23:28:53 +01:00
Ginger Bill 3868a9a0f0 Clean up _preload.odin types 2017-07-10 23:15:41 +01:00
Ginger Bill ba5050ac7c Compiler Internal Changes: TypeRecord_Union -> Type_Union 2017-07-10 22:59:23 +01:00
Ginger Bill d936ca1ea0 Compiler internal change: TypeRecord_Enum -> Type_Enum 2017-07-10 22:42:58 +01:00
Ginger Bill fd8c4d58bb union type allow for any types and removes common fields 2017-07-10 22:32:21 +01:00
Ginger Bill ce4b7b8b7d Nested record declarations 2017-07-10 20:39:42 +01:00
Ginger Bill 069a47220e Make record semicolon syntax more consistent 2017-07-10 14:52:58 +01:00
Ginger Bill 66e4aaffc5 Use semicolons as field delimiters in records 2017-07-10 13:49:50 +01:00
Ginger Bill 81336b58cb "Fix" printing of embedded any to prevent recursion 2017-07-10 10:37:51 +01:00
Ginger Bill b201670f7a Fix _preload.odin; Add for in without parameters; Change sync.Mutex for windows 2017-07-08 23:13:57 +01:00
Ginger Bill 4b051a0d3b .. half closed range; ... open range; ... variadic syntax 2017-07-07 23:42:43 +01:00
Ginger Bill 45353465a6 Add sort.odin 2017-07-07 22:26:55 +01:00
Ginger Bill c63cb98019 Fix else do 2017-07-07 17:50:45 +01:00
Ginger Bill 773cf5ca08 Add -show-timings; Clean up polymorphic procedure code a bit 2017-07-07 15:26:49 +01:00
Ginger Bill 2db03cb4a5 Fix aprint* bug; NULL -> nullptr; Better error messages for overloaded functions 2017-07-06 22:43:55 +01:00
Ginger Bill eed873c6ec Add free for maps (a previous oversight) 2017-07-05 13:51:25 +01:00
Ginger Bill 3d2d461867 Replace many built-in procedures with user-level procedures 2017-07-04 23:52:00 +01:00
Ginger Bill 36392d658e Fix demo.odin 2017-07-04 22:43:38 +01:00
Ginger Bill 82696179e8 Merge branch 'master' of https://github.com/gingerBill/Odin 2017-07-04 22:42:41 +01:00
Ginger Bill 188bc28f6a Allow for overloading of polymorphic procedures 2017-07-04 22:42:25 +01:00
Ginger Bill 240da5c8e0 Allow aliasing of aliases 2017-07-04 16:06:08 +01:00
Ginger Bill 689a0c0b49 *_of as keyords; Allow constant aliasing for user/built-in procedures, import names, and library names 2017-07-04 11:23:48 +01:00
Ginger Bill bc16b290ba Disable polymorphic overloading in the global scope
TODO: Figure out why it does not work in the global scope
2017-07-02 22:08:39 +01:00
Ginger Bill 96d32680fe Allow overloading of polymorphic procedures 2017-07-02 10:45:22 +01:00
Ginger Bill d782b3d21d Fix do on for loops 2017-07-01 11:53:01 +01:00
Ginger Bill ed089b44b9 do keyword for inline statements instead of blocks 2017-07-01 11:38:44 +01:00
Ginger Bill 33f4af2e19 Fix demo 2017-06-29 21:01:07 +01:00
Ginger Bill 69f7382eec Implicit parametric polymorphic procedures 2017-06-29 20:56:18 +01:00
Ginger Bill 7e3293fc20 Fix odin version printing 2017-06-29 16:08:30 +01:00
Ginger Bill e4a8283327 Remove Type
What was I thinking?!
2017-06-29 15:48:07 +01:00
Ginger Bill 001baf4419 Add Type -- Runtime type for comparing types (similar to TypeInfo but simpler) 2017-06-29 15:13:41 +01:00
Ginger Bill d167290b28 Make AstNodeIdent a struct wrapping its Token 2017-06-29 12:11:50 +01:00
Ginger Bill f4879d4723 Update procedure names and extend demo.odin 2017-06-29 11:25:05 +01:00
Ginger Bill fd81c06c35 Remove var and const keywords; Fix default parameter syntax 2017-06-28 23:55:40 +01:00
Ginger Bill 94afcec757 :: style procedure declarations; remove old parsing code 2017-06-28 23:47:06 +01:00
Ginger Bill 4f28e9e1fb Remove type prefix declarations 2017-06-28 23:23:10 +01:00
Ginger Bill 0622509807 Disable var and const declarations 2017-06-28 23:17:20 +01:00
Ginger Bill 9ca2246bac Basic allowance for := and :: 2017-06-28 22:38:04 +01:00
Ginger Bill 647e2cafd7 Fix expand_to_tuple 2017-06-27 22:47:19 +01:00
209 changed files with 64520 additions and 31560 deletions
+3
View File
@@ -0,0 +1,3 @@
# These are supported funding model platforms
patreon: gingerbill
+39
View File
@@ -0,0 +1,39 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
## Context
Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.
* Operating System:
* Odin version/Commit:
## Expected Behavior
Please describe the behavior you are expecting
## Current Behavior
What is the current behavior?
## Failure Information (for bugs)
Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template.
### Steps to Reproduce
Please provide detailed steps for reproducing the issue.
1. step 1
2. step 2
3. you get it...
### Failure Logs
Please include any relevant log snippets or files here.
+17
View File
@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Additional context**
Add any other context or screenshots about the feature request here.
+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
+11 -1
View File
@@ -18,7 +18,7 @@ bld/
[Bb]in/
[Oo]bj/
[Ll]og/
![Cc]ore/[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
@@ -257,7 +257,17 @@ paket-files/
builds/
bin/
*.exe
*.obj
*.pdb
# - Linux/MacOS
odin
odin.dSYM
# shared collection
shared/
# temp files
* .ll
*.bc
*.ll
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2016 Ginger Bill. All rights reserved.
Copyright (c) 2016-2017 Ginger Bill. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
+24
View File
@@ -0,0 +1,24 @@
DISABLED_WARNINGS=-Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined -Wno-writable-strings
LDFLAGS=-pthread -ldl -lm -lstdc++
CFLAGS=-std=c++11
CC=clang
OS=$(shell uname)
ifeq ($(OS), Darwin)
LDFLAGS:=$(LDFLAGS) -liconv
endif
all: debug demo
demo:
./odin run examples/demo/demo.odin
debug:
$(CC) src/main.cpp $(DISABLED_WARNINGS) $(CFLAGS) -g $(LDFLAGS) -o odin
release:
$(CC) src/main.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 -march=native $(LDFLAGS) -o odin
+64
View File
@@ -0,0 +1,64 @@
# The Proposal Process
## Introduction
The Odin project's development process is driven by design and pragmatism. Significant changes to the language, libraries, or tools _must_ be first discussed, and maybe formally documented, before they can be implemented.
This document describes the process for proposing, documenting, and implementing changes to the Odin project.
## The Proposal Process
The proposal process is the process for reviewing a proposal and reaching a decision about whether to accept or decline the proposal.
1. [Ginger Bill](https://github.com/gingerBill) is [BDFL](https://wikipedia.org/wiki/Benevolent_dictator_for_life) and significant changes _must_ be passed by him.
2. The proposal author creates a brief issue describing the proposal.
Note: There is no need for a design document at this point.<br>
Note: A non-proposal issue can be turned into a proposal by simply adding the _proposal_ label.
3. A discussion on the issue tracker will classify the proposal into one of three outcomes:
* Accept proposal
* Decline proposal
* Ask for a design document.
If the proposal is accepted or declined, the process is done. Otherwise the discussion around the process is expected to identify issues that ought to be addressed in a more detailed design.
4. The proposal author writes a design document to work out details of the proposed design and address the concerns raised in the initial discussion.
5. Once comments and revisions on the design document calm, there is a final discussion on the issue, to reach one of two outcomes:
* Accept proposal
* Decline proposal
After the proposal is accepted or declined, implementation of the proprosal proceeds in the same way as any other contribution to the project.
## Design Documents
The design document should follow this template:
```
# Proposal: [Title]
Author(s): [Author Name, Co-Author Name]
Last updated: [Date ISO-8601]
Discussion at https://github.com/odin-lang/Odin/issues/######
## Abstract
## Background
## Proposal
## Rationale
## Compatibility
## Implementation
```
## Help
If you need help with this process, please contact an Odin contributor by posting an issue to the [issue tracker](https://github.com/odin-lang/Odin/issues).
+131 -35
View File
@@ -1,4 +1,23 @@
<img src="misc/logo-slim.png" alt="Odin logo" height="74">
<p align="center">
<img src="misc/logo-slim.png" alt="Odin logo" height="120">
<br/>
A fast, concise, readable, pragmatic and open sourced programming language.
<br/>
<br/>
<a href="https://github.com/odin-lang/odin/releases/latest">
<img src="https://img.shields.io/github/release/odin-lang/odin.svg">
</a>
<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>
<br>
<a href="https://discord.gg/hnwN2Rj">
<img src="https://img.shields.io/discord/568138951836172421?logo=discord">
</a>
<a href="https://github.com/odin-lang/odin/actions">
<img src="https://github.com/odin-lang/odin/workflows/CI/badge.svg">
</a>
</p>
# The Odin Programming Language
@@ -7,28 +26,109 @@ The Odin programming language is fast, concise, readable, pragmatic and open sou
* high performance
* built for modern systems
* joy of programming
* metaprogramming
Website: [https://odin.handmade.network/](https://odin.handmade.network/)
Website: [https://odin-lang.org/](https://odin-lang.org/)
## Demonstrations:
* First Talk & Demo
- [Talk](https://youtu.be/TMCkT-uASaE?t=338)
- [Demo](https://youtu.be/TMCkT-uASaE?t=1800)
- [Q&A](https://youtu.be/TMCkT-uASaE?t=5749)
* [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM)
* [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s)
* [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78)
* [when, for & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
* [Context Types, Unexported Entities, Labelled Branches](https://www.youtube.com/watch?v=CkHVwT1Qk-g)
* [Bit Fields, i128 & u128, Syntax Changes](https://www.youtube.com/watch?v=NlTutcLyF64)
```go
package main
import "core:fmt"
main :: proc() {
program := "+ + * 😃 - /";
accumulator := 0;
for token in program {
switch token {
case '+': accumulator += 1;
case '-': accumulator -= 1;
case '*': accumulator *= 2;
case '/': accumulator /= 2;
case '😃': accumulator *= accumulator;
case: // Ignore everything else
}
}
fmt.printf("The program \"%s\" calculates the value %d\n",
program, accumulator);
}
```
## Documentation
#### [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.
#### [The Odin Wiki](https://github.com/odin-lang/Odin/wiki)
A wiki maintained by the Odin community.
#### [Odin Discord](https://discord.gg/sVBPHEv)
Get live support and talk with other odiners on the Odin Discord.
### References
#### [Language Specification](https://odin-lang.org/ref/spec)
The official Odin Language specification.
### Articles
#### [The Odin Blog](https://odin-lang.org/blog)
The official blog of the Odin programming language, featuring announcements, news, and in-depth articles by the Odin team and guests.
## Setup
Odin only supports x86-64 at the moment (64-bit), relies on LLVM for code generation and an external linker.
In addition, the following platform-specific steps are necessary:
- Windows
* Have Visual Studio installed (MSVC 2010 or later, for the linker)
* Have a copy of `opt.exe` and `llc.exe` in `Odin/bin`. Pre-built Windows binaries can be found [here](https://github.com/odin-lang/Odin/releases/tag/llvm-windows) and *must* be explicitly copied
* Open a valid command prompt:
* **Basic:** run the `x64 Native Tools Command Prompt for VS2017` shortcut bundled with VS 2017, or
* **Advanced:** run `vcvarsall.bat x64` from a blank `cmd` session
- MacOS
* Have LLVM explicitly installed (`brew install llvm`)
* Have XCode installed (version X.X or later, for linking)
* Make sure the LLVM binaries and the linker are added to your `$PATH` environmental variable
- GNU/Linux
* Have LLVM installed (opt/llc)
* Have Clang installed (version X.X or later, for linking)
* Make sure the LLVM binaries and the linker are added to your `$PATH` environmental variable
Then build the compiler by calling `build.bat` (Windows) or `make` (Linux/MacOS). This will automatically run the demo program if successful.
**Notes for Linux:**: The compiler currently relies on the `core` and `shared` library collection being relative to the compiler executable. Installing the compiler in the usual sense (to `/usr/local/bin` or similar) is therefore not as straight forward as you need to make sure the mentioned libraries are available. As a result, it is recommended to simply explicitly invoke the compiler with `/path/to/odin` in your preferred build system, or add `/path/to/odin` to `$PATH`.
Please read the [Getting Started Guide](https://github.com/odin-lang/Odin/wiki#getting-started-with-odin) for more information.
## Requirements to build and run
Please read the [Getting Started Guide](https://github.com/odin-lang/Odin/wiki#getting-started-with-odin).
- Windows
* x86-64
* MSVC 2015 installed (C++11 support)
* [LLVM binaries](https://github.com/gingerBill/Odin/releases/tag/llvm-4.0-windows) for `opt.exe` and `llc.exe`
* MSVC 2010 installed (C++11 support)
* [LLVM binaries](https://github.com/odin-lang/Odin/releases/tag/llvm-windows) for `opt.exe`, `llc.exe`, and `lld-link.exe`
* Requires MSVC's link.exe as the linker
* run `vcvarsall.bat` to setup the path
@@ -48,23 +148,19 @@ Website: [https://odin.handmade.network/](https://odin.handmade.network/)
* This is still highly in development and the language's design is quite volatile.
* Syntax is not fixed.
## Roadmap
## Demonstrations:
* First Talk & Demo
- [Talk](https://youtu.be/TMCkT-uASaE?t=338)
- [Demo](https://youtu.be/TMCkT-uASaE?t=1800)
- [Q&A](https://youtu.be/TMCkT-uASaE?t=5749)
* [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM)
* [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s)
* [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78)
* [when, for & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
* [Context Types, Unexported Entities, Labelled Branches](https://www.youtube.com/watch?v=CkHVwT1Qk-g)
* [Bit Fields, i128 & u128, Syntax Changes](https://www.youtube.com/watch?v=NlTutcLyF64)
* [Default and Named Arguments; Explicit Parametric Polymorphism](https://www.youtube.com/watch?v=-XQZE6S6zUU)
* [Loadsachanges](https://www.youtube.com/watch?v=ar0vFMoMtrI)
* [Packages, Bit Sets, cstring](https://youtu.be/b8bJbjiXZrQ)
- [Q&A](https://youtu.be/5jmxyIfyyTk)
Not in any particular order and not be implemented
* Compile Time Execution (CTE)
- More metaprogramming madness
- Compiler as a library
- AST inspection and modification
* CTE-based build system
* Replace LLVM backend with my own custom backend
* Improve SSA design to accommodate for lowering to a "bytecode"
* SSA optimizations
* Documentation Generator for "Entities"
* Multiple Architecture support
* Debug Information
- pdb format too
* Command Line Tooling
* Compiler Internals:
- Big numbers library
- Multithreading for performance increase
+30
View File
@@ -0,0 +1,30 @@
# The Odin Programming Language
## Setup
Odin only supports x86-64 at the moment (64-bit), relies on LLVM for code generation and an external linker.
In addition, the following platform-specific steps are necessary:
- Windows
* Have Visual Studio installed (MSVC 2010 or later, for the linker)
* Have a copy of `opt.exe` and `llc.exe` in `Odin/bin`. Pre-built Windows binaries can be found [here](https://github.com/odin-lang/Odin/releases/tag/llvm-windows) and *must* be explicitly copied
* Open a valid command prompt:
* **Basic:** run the `x64 Native Tools Command Prompt for VS2017` shortcut bundled with VS 2017, or
* **Advanced:** run `vcvarsall.bat x64` from a blank `cmd` session
- MacOS
* Have LLVM explicitly installed (`brew install llvm`)
* Have XCode installed (version X.X or later, for linking)
* Make sure the LLVM binaries and the linker are added to your `$PATH` environmental variable
- GNU/Linux
* Have LLVM installed (opt/llc)
* Have Clang installed (version X.X or later, for linking)
* Make sure the LLVM binaries and the linker are added to your `$PATH` environmental variable
Then build the compiler by calling `build.bat` (Windows) or `make` (Linux/MacOS). This will automatically run the demo program if successful.
**Notes for Linux:**: The compiler currently relies on the `core` and `shared` library collection being relative to the compiler executable. Installing the compiler in the usual sense (to `/usr/local/bin` or similar) is therefore not as straight forward as you need to make sure the mentioned libraries are available. As a result, it is recommended to simply explicitly invoke the compiler with `/path/to/odin` in your preferred build system, or add `/path/to/odin` to `$PATH`.
Please read the [Getting Started Guide](https://github.com/odin-lang/Odin/wiki#getting-started-with-odin) for more information.
+5 -10
View File
@@ -5,27 +5,25 @@ set exe_name=odin.exe
:: Debug = 0, Release = 1
set release_mode=0
set compiler_flags= -nologo -Oi -TP -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -GS- -EHsc- -GR-
if %release_mode% EQU 0 ( rem Debug
set compiler_flags=%compiler_flags% -Od -MDd -Z7
rem -DDISPLAY_TIMING
) else ( rem Release
set compiler_flags=%compiler_flags% -O2 -MT -Z7
set compiler_flags=%compiler_flags% -O2 -MT -Z7 -DNO_ARRAY_BOUNDS_CHECK
)
set compiler_warnings= ^
-W4 -WX ^
-wd4100 -wd4101 -wd4127 -wd4189 ^
-wd4201 -wd4204 -wd4244 ^
-wd4306 ^
-wd4201 -wd4204 ^
-wd4456 -wd4457 -wd4480 ^
-wd4505 -wd4512 -wd4550
-wd4512
set compiler_includes=
set libs= ^
kernel32.lib
rem "src\dyncall\lib\*.lib"
set linker_flags= -incremental:no -opt:ref -subsystem:console
@@ -38,16 +36,13 @@ if %release_mode% EQU 0 ( rem Debug
set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings%
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 code/demo.odin -opt=0
rem && odin docs core/fmt.odin
&& odin run examples/demo/demo.odin
del *.obj > NUL 2> NUL
:end_of_build
+10 -6
View File
@@ -1,15 +1,21 @@
#!/bin/bash
release_mode=0
release_mode=$1
warnings_to_disable="-std=c++11 -g -Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined -Wno-writable-strings"
warnings_to_disable="-std=c++11 -Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined -Wno-writable-strings"
libraries="-pthread -ldl -lm -lstdc++"
other_args=""
compiler="clang"
if [ -z "$release_mode" ]; then release_mode="0"; fi
if [ "$release_mode" -eq "0" ]; then
other_args="${other_args} -g -fno-inline-functions"
other_args="${other_args} -g"
fi
if [ "$release_mode" -eq "1" ]; then
other_args="${other_args} -O3 -march=native"
fi
if [[ "$(uname)" == "Darwin" ]]; then
# Set compiler to clang on MacOS
@@ -19,6 +25,4 @@ if [[ "$(uname)" == "Darwin" ]]; then
other_args="${other_args} -liconv"
fi
${compiler} src/main.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin
./odin run code/demo.odin
${compiler} src/main.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin && ./odin run examples/demo/demo.odin
+24
View File
@@ -0,0 +1,24 @@
@echo off
set exe_name=odin.exe
set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -GS- -EHsc- -GR- -O2 -MT -Z7 -DNO_ARRAY_BOUNDS_CHECK
set compiler_warnings= ^
-W4 -WX ^
-wd4100 -wd4101 -wd4127 -wd4189 ^
-wd4201 -wd4204 ^
-wd4456 -wd4457 -wd4480 ^
-wd4512
set compiler_includes=
set libs= ^
kernel32.lib
set linker_flags= -incremental:no -opt:ref -subsystem:console -debug
set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings%
set linker_settings=%libs% %linker_flags%
cl %compiler_settings% "src\main.cpp" ^
/link %linker_settings% -OUT:%exe_name% ^
-433
View File
@@ -1,433 +0,0 @@
import "fmt.odin";
proc general_stuff() {
// Complex numbers
var a = 3 + 4i;
var b: complex64 = 3 + 4i;
var c: complex128 = 3 + 4i;
var d = complex(2, 3);
var e = a / conj(a);
fmt.println("(3+4i)/(3-4i) =", e);
fmt.println(real(e), "+", imag(e), "i");
// C-style variadic procedures
foreign __llvm_core {
// The variadic part allows for extra type checking too which C does not provide
proc c_printf(fmt: ^u8, #c_vararg args: ..any) -> i32 #link_name "printf";
}
type Foo struct {
x: int,
y: f32,
z: string,
}
var foo = Foo{123, 0.513, "A string"};
var x, y, z = expand_to_tuple(foo);
fmt.println(x, y, z);
// By default, all variables are zeroed
// This can be overridden with the "uninitialized value"
// This is similar to `nil` but applied to everything
var undef_int: int = ---;
// Context system is now implemented using Implicit Parameter Passing (IPP)
// The previous implementation was Thread Local Storage (TLS)
// IPP has the advantage that it works on systems without TLS and that you can
// link the context to the stack frame and thus look at previous contexts
//
// It does mean that a pointer is implicitly passed procedures with the default
// Odin calling convention (#cc_odin)
// This can be overridden with something like #cc_contextless or #cc_c if performance
// is worried about
}
proc foreign_blocks() {
// See sys/windows.odin
}
proc default_arguments() {
proc hello(a: int = 9, b: int = 9) {
fmt.printf("a is %d; b is %d\n", a, b);
}
fmt.println("\nTesting default arguments:");
hello(1, 2);
hello(1);
hello();
}
proc named_arguments() {
type Colour enum {
Red,
Orange,
Yellow,
Green,
Blue,
Octarine,
};
using Colour;
proc make_character(name, catch_phrase: string, favorite_color, least_favorite_color: Colour) {
fmt.println();
fmt.printf("My name is %v and I like %v. %v\n", name, favorite_color, catch_phrase);
}
make_character("Frank", "¡Ay, caramba!", Blue, Green);
// As the procedures have more and more parameters, it is very easy
// to get many of the arguments in the wrong order especialy if the
// types are the same
make_character("¡Ay, caramba!", "Frank", Green, Blue);
// Named arguments help to disambiguate this problem
make_character(catch_phrase = "¡Ay, caramba!", name = "Frank",
least_favorite_color = Green, favorite_color = Blue);
// The named arguments can be specifed in any order.
make_character(favorite_color = Octarine, catch_phrase = "U wot m8!",
least_favorite_color = Green, name = "Dennis");
// NOTE: You cannot mix named arguments with normal values
/*
make_character("Dennis",
favorite_color = Octarine, catch_phrase = "U wot m8!",
least_favorite_color = Green);
*/
// Named arguments can also aid with default arguments
proc numerous_things(s : string, a = 1, b = 2, c = 3.14,
d = "The Best String!", e = false, f = 10.3/3.1, g = false) {
var g_str = g ? "true" : "false";
fmt.printf("How many?! %s: %v\n", s, g_str);
}
numerous_things("First");
numerous_things(s = "Second", g = true);
// Default values can be placed anywhere, not just at the end like in other languages
proc weird(pre: string, mid: int = 0, post: string) {
fmt.println(pre, mid, post);
}
weird("How many things", 42, "huh?");
weird(pre = "Prefix", post = "Pat");
}
proc default_return_values() {
proc foo(x: int) -> (first: string = "Hellope", second = "world!") {
match x {
case 0: return;
case 1: return "Goodbye";
case 2: return "Goodbye", "cruel world...";
case 3: return second = "cruel world...", first = "Goodbye";
}
return second = "my old friend.";
}
fmt.printf("%s %s\n", foo(0));
fmt.printf("%s %s\n", foo(1));
fmt.printf("%s %s\n", foo(2));
fmt.printf("%s %s\n", foo(3));
fmt.printf("%s %s\n", foo(4));
fmt.println();
// A more "real" example
type Error enum {
None,
WhyTheNumberThree,
TenIsTooBig,
};
type Entity struct {
name: string,
id: u32,
}
proc some_thing(input: int) -> (result: ^Entity = nil, err = Error.None) {
match {
case input == 3: return err = Error.WhyTheNumberThree;
case input >= 10: return err = Error.TenIsTooBig;
}
var e = new(Entity);
e.id = u32(input);
return result = e;
}
}
proc call_location() {
proc amazing(n: int, using loc = #caller_location) {
fmt.printf("%s(%d:%d) just asked to do something amazing.\n",
fully_pathed_filename, line, column);
fmt.printf("Normal -> %d\n", n);
fmt.printf("Amazing -> %d\n", n+1);
fmt.println();
}
var loc = #location(main);
fmt.println("`main` is located at", loc);
fmt.println("This line is located at", #location());
fmt.println();
amazing(3);
amazing(4, #location(call_location));
// See _preload.odin for the implementations of `assert` and `panic`
}
proc explicit_parametric_polymorphic_procedures() {
// This is how `new` is actually implemented, see _preload.odin
proc alloc_type(T: type) -> ^T {
return ^T(alloc(size_of(T), align_of(T)));
}
var int_ptr = alloc_type(int);
defer free(int_ptr);
int_ptr^ = 137;
fmt.println(int_ptr, int_ptr^);
// Named arguments work too!
var another_ptr = alloc_type(T = f32);
defer free(another_ptr);
proc add(T: type, args: ..T) -> T {
var res: T;
for arg in args {
res += arg;
}
return res;
}
fmt.println("add =", add(int, 1, 2, 3, 4, 5, 6));
proc swap(T: type, a, b: ^T) {
var tmp = a^;
a^ = b^;
b^ = tmp;
}
var a, b: int = 3, 4;
fmt.println("Pre-swap:", a, b);
swap(int, &a, &b);
fmt.println("Post-swap:", a, b);
a, b = b, a; // Or use this syntax for this silly example case
// A more complicated example using subtyping
// Something like this could be used in a game
type Vector2 struct {x, y: f32};
type Entity struct {
using position: Vector2,
flags: u64,
id: u64,
batch_index: u32,
slot_index: u32,
portable_id: u32,
derived: any,
}
type Rock struct {
using entity: ^Entity,
heavy: bool,
}
type Door struct {
using entity: ^Entity,
open: bool,
}
type Monster struct {
using entity: ^Entity,
is_robot: bool,
is_zombie: bool,
}
type EntityManager struct {
batches: [dynamic]^EntityBatch,
next_portable_id: u32,
}
const ENTITIES_PER_BATCH = 16;
type EntityBatch struct {
data: [ENTITIES_PER_BATCH]Entity,
occupied: [ENTITIES_PER_BATCH]bool,
batch_index: u32,
}
proc use_empty_slot(manager: ^EntityManager, batch: ^EntityBatch) -> ^Entity {
for ok, i in batch.occupied {
if ok -> continue;
batch.occupied[i] = true;
var e = &batch.data[i];
e.batch_index = u32(batch.batch_index);
e.slot_index = u32(i);
e.portable_id = manager.next_portable_id;
manager.next_portable_id++;
return e;
}
return nil;
}
proc gen_new_entity(manager: ^EntityManager) -> ^Entity {
for b in manager.batches {
var e = use_empty_slot(manager, b);
if e != nil -> return e;
}
var new_batch = new(EntityBatch);
append(manager.batches, new_batch);
new_batch.batch_index = u32(len(manager.batches)-1);
return use_empty_slot(manager, new_batch);
}
proc new_entity(manager: ^EntityManager, Type: type, x, y: int) -> ^Type {
var result = new(Type);
result.entity = gen_new_entity(manager);
result.derived.data = result;
result.derived.type_info = type_info(Type);
result.position.x = f32(x);
result.position.y = f32(y);
return result;
}
var manager: EntityManager;
var entities: [dynamic]^Entity;
var rock = new_entity(&manager, Rock, 3, 5);
// Named arguments work too!
var door = new_entity(manager = &manager, Type = Door, x = 3, y = 6);
// And named arguments can be any order
var monster = new_entity(
y = 1,
x = 2,
manager = &manager,
Type = Monster,
);
append(entities, rock, door, monster);
// An alternative to `union`s
for entity in entities {
match e in entity.derived {
case Rock: fmt.println("Rock", e.portable_id);
case Door: fmt.println("Door", e.portable_id);
case Monster: fmt.println("Monster", e.portable_id);
}
}
}
proc main() {
general_stuff();
foreign_blocks();
default_arguments();
named_arguments();
default_return_values();
call_location();
explicit_parametric_polymorphic_procedures();
// Command line argument(s)!
// -opt=0,1,2,3
/*************/
/* Questions */
/*************/
/*
I'm questioning if I should change the declaration syntax back to Jai-like
as I've found solutions to the problems I had with it before.
Should I change back to Jai-like declarations or keep with the Pascal-like?
Jai-like
x: int;
x: int = 123;
x := 123;
foo : int : 123;
foo :: 123;
MyInt :: int;
BarType :: proc();
bar :: proc() {
}
foreign lib {
foreign_bar :: proc() ---;
}
Pascal-like
var x: int;
var x: int = 123;
var x = 123;
const foo: int = 123;
const foo = 123;
type MyInt int;
type BarType proc();
proc bar() {
}
foreign lib {
proc foreign_bar();
}
*/
}
/*
proc main() {
var program = "+ + * - /";
var accumulator = 0;
for token in program {
match token {
case '+': accumulator += 1;
case '-': accumulator -= 1;
case '*': accumulator *= 2;
case '/': accumulator /= 2;
case: // Ignore everything else
}
}
fmt.printf("The program \"%s\" calculates the value %d\n",
program, accumulator);
}
*/
-222
View File
@@ -1,222 +0,0 @@
import win32 "sys/windows.odin" when ODIN_OS == "windows";
import wgl "sys/wgl.odin" when ODIN_OS == "windows";
import "fmt.odin";
import "math.odin";
import "os.odin";
import gl "opengl.odin";
const TWO_HEARTS = '💕';
var win32_perf_count_freq = win32.get_query_performance_frequency();
proc time_now() -> f64 {
assert(win32_perf_count_freq != 0);
var counter: i64;
win32.query_performance_counter(&counter);
return f64(counter) / f64(win32_perf_count_freq);
}
proc win32_print_last_error() {
var err_code = win32.get_last_error();
if err_code != 0 {
fmt.println("get_last_error: ", err_code);
}
}
// Yuk!
proc to_c_string(s: string) -> []u8 {
var c_str = make([]u8, len(s)+1);
copy(c_str, []u8(s));
c_str[len(s)] = 0;
return c_str;
}
type Window struct {
width, height: int,
wc: win32.WndClassExA,
dc: win32.Hdc,
hwnd: win32.Hwnd,
opengl_context, rc: wgl.Hglrc,
c_title: []u8,
}
proc make_window(title: string, msg, height: int, window_proc: win32.WndProc) -> (Window, bool) {
using win32;
var w: Window;
w.width, w.height = msg, height;
var class_name = "Win32-Odin-Window\x00";
var c_class_name = &class_name[0];
if title[len(title)-1] != 0 {
w.c_title = to_c_string(title);
} else {
w.c_title = []u8(title);
}
var instance = get_module_handle_a(nil);
w.wc = WndClassExA{
size = size_of(WndClassExA),
style = CS_VREDRAW | CS_HREDRAW,
instance = Hinstance(instance),
class_name = c_class_name,
wnd_proc = window_proc,
};
if register_class_ex_a(&w.wc) == 0 {
win32_print_last_error();
return w, false;
}
w.hwnd = create_window_ex_a(0,
c_class_name, &w.c_title[0],
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT,
i32(w.width), i32(w.height),
nil, nil, instance, nil);
if w.hwnd == nil {
win32_print_last_error();
return w, false;
}
w.dc = get_dc(w.hwnd);
{
var pfd = PixelFormatDescriptor{
size = size_of(PixelFormatDescriptor),
version = 1,
flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
pixel_type = PFD_TYPE_RGBA,
color_bits = 32,
alpha_bits = 8,
depth_bits = 24,
stencil_bits = 8,
layer_type = PFD_MAIN_PLANE,
};
set_pixel_format(w.dc, choose_pixel_format(w.dc, &pfd), nil);
w.opengl_context = wgl.create_context(w.dc);
wgl.make_current(w.dc, w.opengl_context);
var attribs = [8]i32{
wgl.CONTEXT_MAJOR_VERSION_ARB, 2,
wgl.CONTEXT_MINOR_VERSION_ARB, 1,
wgl.CONTEXT_PROFILE_MASK_ARB, wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
0, // NOTE(bill): tells the proc that this is the end of attribs
};
var wgl_str = "wglCreateContextAttribsARB\x00";
var wglCreateContextAttribsARB = wgl.CreateContextAttribsARBType(wgl.get_proc_address(&wgl_str[0]));
w.rc = wglCreateContextAttribsARB(w.dc, nil, &attribs[0]);
wgl.make_current(w.dc, w.rc);
swap_buffers(w.dc);
}
return w, true;
}
proc destroy_window(w: ^Window) {
free(w.c_title);
}
proc display_window(w: ^Window) {
win32.swap_buffers(w.dc);
}
proc run() {
using math;
proc win32_proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline {
using win32;
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
os.exit(0);
return 0;
}
return def_window_proc_a(hwnd, msg, wparam, lparam);
}
var window, window_success = make_window("Odin Language Demo", 854, 480, win32.WndProc(win32_proc));
if !window_success {
return;
}
defer destroy_window(&window);
gl.init();
using win32;
var prev_time = time_now();
var running = true;
var pos = Vec2{100, 100};
for running {
var curr_time = time_now();
var dt = f32(curr_time - prev_time);
prev_time = curr_time;
var msg: Msg;
for peek_message_a(&msg, nil, 0, 0, PM_REMOVE) > 0 {
if msg.message == WM_QUIT {
running = false;
}
translate_message(&msg);
dispatch_message_a(&msg);
}
if is_key_down(KeyCode.Escape) {
running = false;
}
{
const SPEED = 500;
var v: Vec2;
if is_key_down(KeyCode.Right) { v[0] += 1; }
if is_key_down(KeyCode.Left) { v[0] -= 1; }
if is_key_down(KeyCode.Up) { v[1] += 1; }
if is_key_down(KeyCode.Down) { v[1] -= 1; }
v = norm(v);
pos += v * Vec2{SPEED * dt};
}
gl.ClearColor(0.5, 0.7, 1.0, 1.0);
gl.Clear(gl.COLOR_BUFFER_BIT);
gl.LoadIdentity();
gl.Ortho(0, f64(window.width),
0, f64(window.height), 0, 1);
proc draw_rect(x, y, w, h: f32) {
gl.Begin(gl.TRIANGLES);
defer gl.End();
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0);
gl.Color3f(0, 1, 0); gl.Vertex3f(x+w, y, 0);
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0);
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0);
gl.Color3f(1, 1, 0); gl.Vertex3f(x, y+h, 0);
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0);
}
draw_rect(pos.x, pos.y, 50, 50);
display_window(&window);
var ms_to_sleep = i32(16 - 1000*dt);
if ms_to_sleep > 0 {
win32.sleep(ms_to_sleep);
}
}
}
proc main() {
run();
}
-184
View File
@@ -1,184 +0,0 @@
import "fmt.odin";
foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows";
type SOCKET uint;
const INVALID_SOCKET = ~SOCKET(0);
type AF enum i32 {
UNSPEC = 0, // unspecified
UNIX = 1, // local to host (pipes, portals)
INET = 2, // internetwork: UDP, TCP, etc.
IMPLINK = 3, // arpanet imp addresses
PUP = 4, // pup protocols: e.g. BSP
CHAOS = 5, // mit CHAOS protocols
NS = 6, // XEROX NS protocols
ISO = 7, // ISO protocols
OSI = ISO, // OSI is ISO
ECMA = 8, // european computer manufacturers
DATAKIT = 9, // datakit protocols
CCITT = 10, // CCITT protocols, X.25 etc
SNA = 11, // IBM SNA
DECnet = 12, // DECnet
DLI = 13, // Direct data link interface
LAT = 14, // LAT
HYLINK = 15, // NSC Hyperchannel
APPLETALK = 16, // AppleTalk
ROUTE = 17, // Internal Routing Protocol
LINK = 18, // Link layer interface
XTP = 19, // eXpress Transfer Protocol (no AF)
COIP = 20, // connection-oriented IP, aka ST II
CNT = 21, // Computer Network Technology
RTIP = 22, // Help Identify RTIP packets
IPX = 23, // Novell Internet Protocol
SIP = 24, // Simple Internet Protocol
PIP = 25, // Help Identify PIP packets
MAX = 26,
};
const (
SOCK_STREAM = 1;
SOCKET_ERROR = -1;
IPPROTO_TCP = 6;
AI_PASSIVE = 0x0020;
SOMAXCONN = 128;
)
const (
SD_RECEIVE = 0;
SD_SEND = 1;
SD_BOTH = 2;
)
const WSADESCRIPTION_LEN = 256;
const WSASYS_STATUS_LEN = 128;
type WSADATA struct #ordered {
version: i16,
high_version: i16,
// NOTE(bill): This is x64 ordering
max_sockets: u16,
max_udp_dg: u16,
vendor_info: ^u8,
description: [WSADESCRIPTION_LEN+1]u8,
system_status: [WSASYS_STATUS_LEN+1]u8,
}
type addrinfo struct #ordered {
flags: i32,
family: i32,
socktype: i32,
protocol: i32,
addrlen: uint,
canonname: ^u8,
addr: ^sockaddr,
next: ^addrinfo,
}
type sockaddr struct #ordered {
family: u16,
data: [14]u8,
}
foreign ws2 {
proc WSAStartup (version_requested: i16, data: ^WSADATA) -> i32;
proc WSACleanup () -> i32;
proc getaddrinfo (node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32;
proc freeaddrinfo (ai: ^addrinfo);
proc socket (af, type_, protocol: i32) -> SOCKET;
proc closesocket (s: SOCKET) -> i32;
proc bind (s: SOCKET, name: ^sockaddr, name_len: i32) -> i32;
proc listen (s: SOCKET, back_log: i32) -> i32;
proc accept (s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET;
proc recv (s: SOCKET, buf: ^u8, len: i32, flags: i32) -> i32;
proc send (s: SOCKET, buf: ^u8, len: i32, flags: i32) -> i32;
proc shutdown (s: SOCKET, how: i32) -> i32;
proc WSAGetLastError() -> i32;
}
proc to_c_string(s: string) -> ^u8 {
var c_str = make([]u8, len(s)+1);
copy(c_str, []u8(s));
c_str[len(s)] = 0;
return &c_str[0];
}
proc run() {
var (
wsa: WSADATA;
res: ^addrinfo = nil;
hints: addrinfo;
s, client: SOCKET;
)
if WSAStartup(2 | (2 << 8), &wsa) != 0 {
fmt.println("WSAStartup failed: ", WSAGetLastError());
return;
}
defer WSACleanup();
hints.family = i32(AF.INET);
hints.socktype = SOCK_STREAM;
hints.protocol = IPPROTO_TCP;
hints.flags = AI_PASSIVE;
if getaddrinfo(nil, to_c_string("8080"), &hints, &res) != 0 {
fmt.println("getaddrinfo failed: ", WSAGetLastError());
return;
}
defer freeaddrinfo(res);
s = socket(res.family, res.socktype, res.protocol);
if s == INVALID_SOCKET {
fmt.println("socket failed: ", WSAGetLastError());
return;
}
defer closesocket(s);
bind(s, res.addr, i32(res.addrlen));
listen(s, SOMAXCONN);
client = accept(s, nil, 0);
if client == INVALID_SOCKET {
fmt.println("socket failed: ", WSAGetLastError());
return;
}
defer closesocket(client);
var html =
`HTTP/1.1 200 OK
Connection: close
Content-type: text/html
<html>
<head>
<title>Demo Title</title>
</head>
<body>
<h1 style="color: orange;">Odin Server Demo</h1>
</body>
</html>
`;
var buf: [1024]u8;
for {
var bytes = recv(client, &buf[0], i32(len(buf)), 0);
if bytes > 0 {
// fmt.println(string(buf[0..<bytes]))
var bytes_sent = send(client, &html[0], i32(len(html)-1), 0);
if bytes_sent == SOCKET_ERROR {
fmt.println("send failed: ", WSAGetLastError());
return;
}
break;
} else if bytes == 0 {
fmt.println("Connection closing...");
break;
} else {
fmt.println("recv failed: ", WSAGetLastError());
return;
}
}
shutdown(client, SD_SEND);
}
-498
View File
@@ -1,498 +0,0 @@
import (
win32 "sys/windows.odin";
"fmt.odin";
"os.odin";
"mem.odin";
)
const (
CANVAS_WIDTH = 128;
CANVAS_HEIGHT = 128;
CANVAS_SCALE = 3;
FRAME_TIME = 1.0/30.0;
WINDOW_TITLE = "Punity\x00";
)
const _ = compile_assert(CANVAS_WIDTH % 16 == 0);
const (
WINDOW_WIDTH = CANVAS_WIDTH * CANVAS_SCALE;
WINDOW_HEIGHT = CANVAS_HEIGHT * CANVAS_SCALE;
)
const (
STACK_CAPACITY = 1<<20;
STORAGE_CAPACITY = 1<<20;
DRAW_LIST_RESERVE = 128;
MAX_KEYS = 256;
)
type Core struct {
stack: ^Bank,
storage: ^Bank,
running: bool,
key_modifiers: u32,
key_states: [MAX_KEYS]u8,
key_deltas: [MAX_KEYS]u8,
perf_frame,
perf_frame_inner,
perf_step,
perf_audio,
perf_blit,
perf_blit_cvt,
perf_blit_gdi: Perf_Span,
frame: i64,
canvas: Canvas,
draw_list: ^Draw_List,
}
type Perf_Span struct {
stamp: f64,
delta: f32,
}
type Bank struct {
memory: []u8,
cursor: int,
}
type Bank_State struct {
state: Bank,
bank: ^Bank,
}
type Color raw_union {
using channels: struct{a, b, g, r: u8},
rgba: u32,
}
type Palette struct {
colors: [256]Color,
colors_count: u8,
}
type Rect raw_union {
using minmax: struct {min_x, min_y, max_x, max_y: int},
using pos: struct {left, top, right, bottom: int},
e: [4]int,
}
type Bitmap struct {
pixels: []u8,
width: int,
height: int,
}
type Font struct {
using bitmap: Bitmap,
char_width: int,
char_height: int,
}
type Canvas struct {
using bitmap: ^Bitmap,
palette: Palette,
translate_x: int,
translate_y: int,
clip: Rect,
font: ^Font,
}
type DrawFlag enum {
NONE = 0,
FLIP_H = 1<<0,
FLIP_V = 1<<1,
MASK = 1<<2,
}
type Draw_Item struct {}
type Draw_List struct {
items: []Draw_Item,
}
type Key enum {
ModShift = 0x0001,
ModControl = 0x0002,
ModAlt = 0x0004,
ModSuper = 0x0008,
Unknown =-1,
Invalid =-2,
Lbutton = 1,
Rbutton = 2,
Cancel = 3,
Mbutton = 4,
Back = 8,
Tab = 9,
Clear = 12,
Return = 13,
Shift = 16,
Control = 17,
Menu = 18,
Pause = 19,
Capital = 20,
Kana = 0x15,
Hangeul = 0x15,
Hangul = 0x15,
Junja = 0x17,
Final = 0x18,
Hanja = 0x19,
Kanji = 0x19,
Escape = 0x1B,
Convert = 0x1C,
NonConvert = 0x1D,
Accept = 0x1E,
ModeChange = 0x1F,
Space = 32,
Prior = 33,
Next = 34,
End = 35,
Home = 36,
Left = 37,
Up = 38,
Right = 39,
Down = 40,
Select = 41,
Print = 42,
Exec = 43,
Snapshot = 44,
Insert = 45,
Delete = 46,
Help = 47,
Lwin = 0x5B,
Rwin = 0x5C,
Apps = 0x5D,
Sleep = 0x5F,
Numpad0 = 0x60,
Numpad1 = 0x61,
Numpad2 = 0x62,
Numpad3 = 0x63,
Numpad4 = 0x64,
Numpad5 = 0x65,
Numpad6 = 0x66,
Numpad7 = 0x67,
Numpad8 = 0x68,
Numpad9 = 0x69,
Multiply = 0x6A,
Add = 0x6B,
Separator = 0x6C,
Subtract = 0x6D,
Decimal = 0x6E,
Divide = 0x6F,
F1 = 0x70,
F2 = 0x71,
F3 = 0x72,
F4 = 0x73,
F5 = 0x74,
F6 = 0x75,
F7 = 0x76,
F8 = 0x77,
F9 = 0x78,
F10 = 0x79,
F11 = 0x7A,
F12 = 0x7B,
F13 = 0x7C,
F14 = 0x7D,
F15 = 0x7E,
F16 = 0x7F,
F17 = 0x80,
F18 = 0x81,
F19 = 0x82,
F20 = 0x83,
F21 = 0x84,
F22 = 0x85,
F23 = 0x86,
F24 = 0x87,
Numlock = 0x90,
Scroll = 0x91,
Lshift = 0xA0,
Rshift = 0xA1,
Lcontrol = 0xA2,
Rcontrol = 0xA3,
Lmenu = 0xA4,
Rmenu = 0xA5,
Apostrophe = 39, /* ' */
Comma = 44, /* , */
Minus = 45, /* - */
Period = 46, /* . */
Slash = 47, /* / */
Num0 = 48,
Num1 = 49,
Num2 = 50,
Num3 = 51,
Num4 = 52,
Num5 = 53,
Num6 = 54,
Num7 = 55,
Num8 = 56,
Num9 = 57,
Semicolon = 59, /* ; */
Equal = 61, /* = */
A = 65,
B = 66,
C = 67,
D = 68,
E = 69,
F = 70,
G = 71,
H = 72,
I = 73,
J = 74,
K = 75,
L = 76,
M = 77,
N = 78,
O = 79,
P = 80,
Q = 81,
R = 82,
S = 83,
T = 84,
U = 85,
V = 86,
W = 87,
X = 88,
Y = 89,
Z = 90,
LeftBracket = 91, /* [ */
Backslash = 92, /* \ */
RightBracket = 93, /* ] */
GraveAccent = 96, /* ` */
};
proc key_down(k: Key) -> bool {
return _core.key_states[k] != 0;
}
proc key_pressed(k: Key) -> bool {
return (_core.key_deltas[k] != 0) && key_down(k);
}
let win32_perf_count_freq = win32.get_query_performance_frequency();
proc time_now() -> f64 {
assert(win32_perf_count_freq != 0);
var counter: i64;
win32.query_performance_counter(&counter);
return f64(counter) / f64(win32_perf_count_freq);
}
var _core: Core;
proc run(user_init, user_step: proc(c: ^Core)) {
using win32;
_core.running = true;
proc win32_proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline #cc_c {
proc win32_app_key_mods() -> u32 {
var mods: u32 = 0;
if is_key_down(KeyCode.Shift) {
mods |= u32(Key.ModShift);
}
if is_key_down(KeyCode.Control) {
mods |= u32(Key.ModControl);
}
if is_key_down(KeyCode.Menu) {
mods |= u32(Key.ModAlt);
}
if is_key_down(KeyCode.Lwin) || is_key_down(KeyCode.Rwin) {
mods |= u32(Key.ModSuper);
}
return mods;
}
match msg {
case WM_KEYDOWN:
_core.key_modifiers = win32_app_key_mods();
if wparam < MAX_KEYS {
_core.key_states[wparam] = 1;
_core.key_deltas[wparam] = 1;
}
return 0;
case WM_KEYUP:
_core.key_modifiers = win32_app_key_mods();
if wparam < MAX_KEYS {
_core.key_states[wparam] = 0;
_core.key_deltas[wparam] = 1;
}
return 0;
case WM_CLOSE:
post_quit_message(0);
_core.running = false;
return 0;
}
return def_window_proc_a(hwnd, msg, wparam, lparam);
}
var class_name = "Punity\x00";
var window_class = WndClassExA{
class_name = &class_name[0],
size = size_of(WndClassExA),
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
instance = Hinstance(get_module_handle_a(nil)),
wnd_proc = win32_proc,
// wnd_proc = DefWindowProcA,
background = Hbrush(get_stock_object(BLACK_BRUSH)),
};
if register_class_ex_a(&window_class) == 0 {
fmt.fprintln(os.stderr, "register_class_ex_a failed");
return;
}
var screen_width = get_system_metrics(SM_CXSCREEN);
var screen_height = get_system_metrics(SM_CYSCREEN);
var rc: Rect;
rc.left = (screen_width - WINDOW_WIDTH) / 2;
rc.top = (screen_height - WINDOW_HEIGHT) / 2;
rc.right = rc.left + WINDOW_WIDTH;
rc.bottom = rc.top + WINDOW_HEIGHT;
var style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
assert(adjust_window_rect(&rc, style, 0) != 0);
var wt = WINDOW_TITLE;
var win32_window = create_window_ex_a(0,
window_class.class_name,
&wt[0],
style,
rc.left, rc.top,
rc.right-rc.left, rc.bottom-rc.top,
nil, nil, window_class.instance,
nil);
if win32_window == nil {
fmt.fprintln(os.stderr, "create_window_ex_a failed");
return;
}
var window_bmi: BitmapInfo;
window_bmi.size = size_of(BitmapInfoHeader);
window_bmi.width = CANVAS_WIDTH;
window_bmi.height = CANVAS_HEIGHT;
window_bmi.planes = 1;
window_bmi.bit_count = 32;
window_bmi.compression = BI_RGB;
user_init(&_core);
show_window(win32_window, SW_SHOW);
var window_buffer = make([]u32, CANVAS_WIDTH * CANVAS_HEIGHT);
defer free(window_buffer);
for _, i in window_buffer {
window_buffer[i] = 0xff00ff;
}
var (
dt: f64;
prev_time = time_now();
curr_time = time_now();
total_time : f64 = 0;
offset_x = 0;
offset_y = 0;
)
var message: Msg;
for _core.running {
curr_time = time_now();
dt = curr_time - prev_time;
prev_time = curr_time;
total_time += dt;
offset_x += 1;
offset_y += 2;
{
var buf: [128]u8;
var s = fmt.bprintf(buf[..], "Punity: %.4f ms\x00", dt*1000);
win32.set_window_text_a(win32_window, &s[0]);
}
for var y = 0; y < CANVAS_HEIGHT; y++ {
for var x = 0; x < CANVAS_WIDTH; x++ {
var g = (x % 32) * 8;
var b = (y % 32) * 8;
window_buffer[x + y*CANVAS_WIDTH] = u32(g << 8 | b);
}
}
mem.zero(&_core.key_deltas[0], size_of(_core.key_deltas));
for peek_message_a(&message, nil, 0, 0, PM_REMOVE) != 0 {
if message.message == WM_QUIT {
_core.running = false;
}
translate_message(&message);
dispatch_message_a(&message);
}
user_step(&_core);
var dc = get_dc(win32_window);
stretch_dibits(dc,
0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
&window_buffer[0],
&window_bmi,
DIB_RGB_COLORS,
SRCCOPY);
release_dc(win32_window, dc);
{
var delta = time_now() - prev_time;
var ms = i32((FRAME_TIME - delta) * 1000);
if ms > 0 {
win32.sleep(ms);
}
}
_core.frame++;
}
}
proc main() {
proc user_init(c: ^Core) {
}
proc user_step(c: ^Core) {
}
run(user_init, user_step);
}
-814
View File
@@ -1,814 +0,0 @@
#shared_global_scope;
import (
"os.odin";
"fmt.odin";
"utf8.odin";
"raw.odin";
)
// Naming Conventions:
// In general, PascalCase for types and snake_case for values
//
// Import Name: snake_case (but prefer single word)
// Types: PascalCase
// Union Variants: PascalCase
// Enum Values: PascalCase
// Procedures: snake_case
// Local Variables: snake_case
// Constant Variables: SCREAMING_SNAKE_CASE
// IMPORTANT NOTE(bill): `type_info` cannot be used within a
// #shared_global_scope due to the internals of the compiler.
// This could change at a later date if the all these data structures are
// implemented within the compiler rather than in this "preload" file
// IMPORTANT NOTE(bill): Do not change the order of any of this data
// The compiler relies upon this _exact_ order
type (
TypeInfoEnumValue raw_union {
f: f64,
i: i128,
}
// NOTE(bill): This must match the compiler's
CallingConvention enum {
Invalid = 0,
Odin = 1,
Contextless = 2,
C = 3,
Std = 4,
Fast = 5,
}
TypeInfoRecord struct #ordered {
types: []^TypeInfo,
names: []string,
offsets: []int, // offsets may not be used in tuples
usings: []bool, // usings may not be used in tuples
packed: bool,
ordered: bool,
custom_align: bool,
}
TypeInfo union {
size: int,
align: int,
Named{name: string, base: ^TypeInfo},
Integer{signed: bool},
Rune{},
Float{},
Complex{},
String{},
Boolean{},
Any{},
Pointer{
elem: ^TypeInfo, // nil -> rawptr
},
Atomic{elem: ^TypeInfo},
Procedure{
params: ^TypeInfo, // TypeInfo.Tuple
results: ^TypeInfo, // TypeInfo.Tuple
variadic: bool,
convention: CallingConvention,
},
Array{
elem: ^TypeInfo,
elem_size: int,
count: int,
},
DynamicArray{elem: ^TypeInfo, elem_size: int},
Slice {elem: ^TypeInfo, elem_size: int},
Vector {elem: ^TypeInfo, elem_size, count: int},
Tuple {using record: TypeInfoRecord}, // Only really used for procedures
Struct {using record: TypeInfoRecord},
RawUnion {using record: TypeInfoRecord},
Union{
common_fields: struct {
types: []^TypeInfo,
names: []string,
offsets: []int, // offsets may not be used in tuples
},
variant_names: []string,
variant_types: []^TypeInfo,
},
Enum{
base: ^TypeInfo,
names: []string,
values: []TypeInfoEnumValue,
},
Map{
key: ^TypeInfo,
value: ^TypeInfo,
generated_struct: ^TypeInfo,
count: int, // == 0 if dynamic
},
BitField{
names: []string,
bits: []i32,
offsets: []i32,
},
}
)
// NOTE(bill): only the ones that are needed (not all types)
// This will be set by the compiler
var (
__type_table: []TypeInfo;
__argv__: ^^u8;
__argc__: i32;
)
proc type_info_base(info: ^TypeInfo) -> ^TypeInfo {
if info == nil -> return nil;
var base = info;
match i in base {
case TypeInfo.Named:
base = i.base;
}
return base;
}
proc type_info_base_without_enum(info: ^TypeInfo) -> ^TypeInfo {
if info == nil -> return nil;
var base = info;
match i in base {
case TypeInfo.Named:
base = i.base;
case TypeInfo.Enum:
base = i.base;
}
return base;
}
foreign __llvm_core {
proc assume (cond: bool) #link_name "llvm.assume";
proc __debug_trap () #link_name "llvm.debugtrap";
proc __trap () #link_name "llvm.trap";
proc read_cycle_counter() -> u64 #link_name "llvm.readcyclecounter";
}
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
type (
AllocatorMode enum u8 {
Alloc,
Free,
FreeAll,
Resize,
}
AllocatorProc proc(allocator_data: rawptr, mode: AllocatorMode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64 = 0) -> rawptr;
Allocator struct #ordered {
procedure: AllocatorProc,
data: rawptr,
}
Context struct #ordered {
thread_id: int,
allocator: Allocator,
user_data: rawptr,
user_index: int,
}
)
// #thread_local var __context: Context;
type SourceCodeLocation struct {
fully_pathed_filename: string,
line, column: i64,
procedure: string,
}
proc make_source_code_location(file: string, line, column: i64, procedure: string) -> SourceCodeLocation #cc_contextless #inline {
return SourceCodeLocation{file, line, column, procedure};
}
const DEFAULT_ALIGNMENT = align_of([vector 4]f32);
proc __init_context_from_ptr(c: ^Context, other: ^Context) #cc_contextless {
if c == nil -> return;
c^ = other^;
if c.allocator.procedure == nil {
c.allocator = default_allocator();
}
if c.thread_id == 0 {
c.thread_id = os.current_thread_id();
}
}
proc __init_context(c: ^Context) #cc_contextless {
if c == nil -> return;
if c.allocator.procedure == nil {
c.allocator = default_allocator();
}
if c.thread_id == 0 {
c.thread_id = os.current_thread_id();
}
}
/*
proc __check_context() {
__init_context(&__context);
}
*/
proc alloc(size: int, alignment: int = DEFAULT_ALIGNMENT) -> rawptr #inline {
// __check_context();
var a = context.allocator;
return a.procedure(a.data, AllocatorMode.Alloc, size, alignment, nil, 0, 0);
}
proc free_ptr_with_allocator(a: Allocator, ptr: rawptr) #inline {
if ptr == nil {
return;
}
if a.procedure == nil {
return;
}
a.procedure(a.data, AllocatorMode.Free, 0, 0, ptr, 0, 0);
}
proc free_ptr(ptr: rawptr) #inline {
// __check_context();
free_ptr_with_allocator(context.allocator, ptr);
}
proc free_all() #inline {
// __check_context();
var a = context.allocator;
a.procedure(a.data, AllocatorMode.FreeAll, 0, 0, nil, 0, 0);
}
proc resize(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT) -> rawptr #inline {
// __check_context();
var a = context.allocator;
return a.procedure(a.data, AllocatorMode.Resize, new_size, alignment, ptr, old_size, 0);
}
proc new(T: type) -> ^T #inline {
return ^T(alloc(size_of(T), align_of(T)));
}
proc default_resize_align(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
if old_memory == nil {
return alloc(new_size, alignment);
}
if new_size == 0 {
free(old_memory);
return nil;
}
if new_size == old_size {
return old_memory;
}
var new_memory = alloc(new_size, alignment);
if new_memory == nil {
return nil;
}
__mem_copy(new_memory, old_memory, min(old_size, new_size));;
free(old_memory);
return new_memory;
}
proc default_allocator_proc(allocator_data: rawptr, mode: AllocatorMode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
using AllocatorMode;
match mode {
case Alloc:
return os.heap_alloc(size);
case Free:
os.heap_free(old_memory);
return nil;
case FreeAll:
// NOTE(bill): Does nothing
case Resize:
var ptr = os.heap_resize(old_memory, size);
assert(ptr != nil);
return ptr;
}
return nil;
}
proc default_allocator() -> Allocator {
return Allocator{
procedure = default_allocator_proc,
data = nil,
};
}
proc assert(condition: bool, message = "", using location = #caller_location) -> bool #cc_contextless {
if !condition {
if len(message) > 0 {
fmt.printf("%s(%d:%d) Runtime assertion: %s\n", fully_pathed_filename, line, column, message);
} else {
fmt.printf("%s(%d:%d) Runtime assertion\n", fully_pathed_filename, line, column);
}
__debug_trap();
}
return condition;
}
proc panic(message = "", using location = #caller_location) #cc_contextless {
if len(message) > 0 {
fmt.printf("%s(%d:%d) Panic: %s\n", fully_pathed_filename, line, column, message);
} else {
fmt.printf("%s(%d:%d) Panic\n", fully_pathed_filename, line, column);
}
__debug_trap();
}
proc __string_eq(a, b: string) -> bool #cc_contextless {
if len(a) != len(b) {
return false;
}
if len(a) == 0 {
return true;
}
if &a[0] == &b[0] {
return true;
}
return __string_cmp(a, b) == 0;
}
proc __string_cmp(a, b: string) -> int #cc_contextless {
return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
}
proc __string_ne(a, b: string) -> bool #cc_contextless #inline { return !__string_eq(a, b); }
proc __string_lt(a, b: string) -> bool #cc_contextless #inline { return __string_cmp(a, b) < 0; }
proc __string_gt(a, b: string) -> bool #cc_contextless #inline { return __string_cmp(a, b) > 0; }
proc __string_le(a, b: string) -> bool #cc_contextless #inline { return __string_cmp(a, b) <= 0; }
proc __string_ge(a, b: string) -> bool #cc_contextless #inline { return __string_cmp(a, b) >= 0; }
proc __complex64_eq (a, b: complex64) -> bool #cc_contextless #inline { return real(a) == real(b) && imag(a) == imag(b); }
proc __complex64_ne (a, b: complex64) -> bool #cc_contextless #inline { return real(a) != real(b) || imag(a) != imag(b); }
proc __complex128_eq(a, b: complex128) -> bool #cc_contextless #inline { return real(a) == real(b) && imag(a) == imag(b); }
proc __complex128_ne(a, b: complex128) -> bool #cc_contextless #inline { return real(a) != real(b) || imag(a) != imag(b); }
proc __bounds_check_error(file: string, line, column: int, index, count: int) #cc_contextless {
if 0 <= index && index < count {
return;
}
fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..<%d\n",
file, line, column, index, count);
__debug_trap();
}
proc __slice_expr_error(file: string, line, column: int, low, high, max: int) #cc_contextless {
if 0 <= low && low <= high && high <= max {
return;
}
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..<%d..<%d]\n",
file, line, column, low, high, max);
__debug_trap();
}
proc __substring_expr_error(file: string, line, column: int, low, high: int) #cc_contextless {
if 0 <= low && low <= high {
return;
}
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d..<%d]\n",
file, line, column, low, high);
__debug_trap();
}
proc __type_assertion_check(ok: bool, file: string, line, column: int, from, to: ^TypeInfo) #cc_contextless {
if !ok {
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid type_assertion from %T to %T\n",
file, line, column, from, to);
__debug_trap();
}
}
proc __string_decode_rune(s: string) -> (rune, int) #cc_contextless #inline {
return utf8.decode_rune(s);
}
proc __mem_set(data: rawptr, value: i32, len: int) -> rawptr #cc_contextless {
when size_of(rawptr) == 8 {
foreign __llvm_core proc llvm_memset_64bit(dst: rawptr, val: u8, len: int, align: i32, is_volatile: bool) #link_name "llvm.memset.p0i8.i64";
llvm_memset_64bit(data, u8(value), len, 1, false);
return data;
} else {
foreign __llvm_core proc llvm_memset_32bit(dst: rawptr, val: u8, len: int, align: i32, is_volatile: bool) #link_name "llvm.memset.p0i8.i32";
llvm_memset_32bit(data, u8(value), len, 1, false);
return data;
}
}
proc __mem_zero(data: rawptr, len: int) -> rawptr #cc_contextless {
return __mem_set(data, 0, len);
}
proc __mem_copy(dst, src: rawptr, len: int) -> rawptr #cc_contextless {
// NOTE(bill): This _must_ be implemented like C's memmove
when size_of(rawptr) == 8 {
foreign __llvm_core proc llvm_memmove_64bit(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #link_name "llvm.memmove.p0i8.p0i8.i64";
llvm_memmove_64bit(dst, src, len, 1, false);
return dst;
} else {
foreign __llvm_core proc llvm_memmove_32bit(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #link_name "llvm.memmove.p0i8.p0i8.i32";
llvm_memmove_32bit(dst, src, len, 1, false);
return dst;
}
}
proc __mem_copy_non_overlapping(dst, src: rawptr, len: int) -> rawptr #cc_contextless {
// NOTE(bill): This _must_ be implemented like C's memcpy
when size_of(rawptr) == 8 {
foreign __llvm_core proc llvm_memcpy_64bit(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #link_name "llvm.memcpy.p0i8.p0i8.i64";
llvm_memcpy_64bit(dst, src, len, 1, false);
return dst;
} else {
foreign __llvm_core proc llvm_memcpy_32bit(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #link_name "llvm.memcpy.p0i8.p0i8.i32";
llvm_memcpy_32bit(dst, src, len, 1, false);
return dst;
}
}
proc __mem_compare(a, b: ^u8, n: int) -> int #cc_contextless {
for i in 0..<n {
match {
case (a+i)^ < (b+i)^:
return -1;
case (a+i)^ > (b+i)^:
return +1;
}
}
return 0;
}
foreign __llvm_core {
proc __sqrt_f32(x: f32) -> f32 #link_name "llvm.sqrt.f32";
proc __sqrt_f64(x: f64) -> f64 #link_name "llvm.sqrt.f64";
}
proc __abs_complex64(x: complex64) -> f32 #inline #cc_contextless {
var r, i = real(x), imag(x);
return __sqrt_f32(r*r + i*i);
}
proc __abs_complex128(x: complex128) -> f64 #inline #cc_contextless {
var r, i = real(x), imag(x);
return __sqrt_f64(r*r + i*i);
}
proc __dynamic_array_make(array_: rawptr, elem_size, elem_align: int, len, cap: int) {
var array = ^raw.DynamicArray(array_);
// __check_context();
array.allocator = context.allocator;
assert(array.allocator.procedure != nil);
if cap > 0 {
__dynamic_array_reserve(array_, elem_size, elem_align, cap);
array.len = len;
}
}
proc __dynamic_array_reserve(array_: rawptr, elem_size, elem_align: int, cap: int) -> bool {
var array = ^raw.DynamicArray(array_);
if cap <= array.cap -> return true;
// __check_context();
if array.allocator.procedure == nil {
array.allocator = context.allocator;
}
assert(array.allocator.procedure != nil);
var old_size = array.cap * elem_size;
var new_size = cap * elem_size;
var allocator = array.allocator;
var new_data = allocator.procedure(allocator.data, AllocatorMode.Resize, new_size, elem_align, array.data, old_size, 0);
if new_data == nil -> return false;
array.data = new_data;
array.cap = cap;
return true;
}
proc __dynamic_array_resize(array_: rawptr, elem_size, elem_align: int, len: int) -> bool {
var array = ^raw.DynamicArray(array_);
var ok = __dynamic_array_reserve(array_, elem_size, elem_align, len);
if ok -> array.len = len;
return ok;
}
proc __dynamic_array_append(array_: rawptr, elem_size, elem_align: int,
items: rawptr, item_count: int) -> int {
var array = ^raw.DynamicArray(array_);
if item_count <= 0 || items == nil {
return array.len;
}
var ok = true;
if array.cap <= array.len+item_count {
var cap = 2 * array.cap + max(8, item_count);
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
}
// TODO(bill): Better error handling for failed reservation
if !ok -> return array.len;
var data = ^u8(array.data);
assert(data != nil);
__mem_copy(data + (elem_size*array.len), items, elem_size * item_count);
array.len += item_count;
return array.len;
}
proc __dynamic_array_append_nothing(array_: rawptr, elem_size, elem_align: int) -> int {
var array = ^raw.DynamicArray(array_);
var ok = true;
if array.cap <= array.len+1 {
var cap = 2 * array.cap + max(8, 1);
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
}
// TODO(bill): Better error handling for failed reservation
if !ok -> return array.len;
var data = ^u8(array.data);
assert(data != nil);
__mem_zero(data + (elem_size*array.len), elem_size);
array.len++;
return array.len;
}
proc __slice_append(slice_: rawptr, elem_size, elem_align: int,
items: rawptr, item_count: int) -> int {
var slice = ^raw.Slice(slice_);
if item_count <= 0 || items == nil {
return slice.len;
}
item_count = min(slice.cap-slice.len, item_count);
if item_count > 0 {
var data = ^u8(slice.data);
assert(data != nil);
__mem_copy(data + (elem_size*slice.len), items, elem_size * item_count);
slice.len += item_count;
}
return slice.len;
}
// Map stuff
proc __default_hash(data: []u8) -> u128 {
proc fnv128a(data: []u8) -> u128 {
var h: u128 = 0x6c62272e07bb014262b821756295c58d;
for b in data {
h = (h ~ u128(b)) * 0x1000000000000000000013b;
}
return h;
}
return fnv128a(data);
}
proc __default_hash_string(s: string) -> u128 {
return __default_hash([]u8(s));
}
const __INITIAL_MAP_CAP = 16;
type (
__MapKey struct #ordered {
hash: u128,
str: string,
}
__MapFindResult struct #ordered {
hash_index: int,
entry_prev: int,
entry_index: int,
}
__MapEntryHeader struct #ordered {
key: __MapKey,
next: int,
/*
value: Value_Type,
*/
}
__MapHeader struct #ordered {
m: ^raw.DynamicMap,
is_key_string: bool,
entry_size: int,
entry_align: int,
value_offset: int,
value_size: int,
}
)
proc __dynamic_map_reserve(using header: __MapHeader, cap: int) {
__dynamic_array_reserve(&m.hashes, size_of(int), align_of(int), cap);
__dynamic_array_reserve(&m.entries, entry_size, entry_align, cap);
}
proc __dynamic_map_rehash(using header: __MapHeader, new_count: int) {
var new_header: __MapHeader = header;
var nm: raw.DynamicMap;
new_header.m = &nm;
var header_hashes = ^raw.DynamicArray(&header.m.hashes);
var nm_hashes = ^raw.DynamicArray(&nm.hashes);
__dynamic_array_resize(nm_hashes, size_of(int), align_of(int), new_count);
__dynamic_array_reserve(&nm.entries, entry_size, entry_align, m.entries.len);
for i in 0..<new_count -> nm.hashes[i] = -1;
for var i = 0; i < m.entries.len; i++ {
if len(nm.hashes) == 0 {
__dynamic_map_grow(new_header);
}
var entry_header = __dynamic_map_get_entry(header, i);
var data = ^u8(entry_header);
var fr = __dynamic_map_find(new_header, entry_header.key);
var j = __dynamic_map_add_entry(new_header, entry_header.key);
if fr.entry_prev < 0 {
nm.hashes[fr.hash_index] = j;
} else {
var e = __dynamic_map_get_entry(new_header, fr.entry_prev);
e.next = j;
}
var e = __dynamic_map_get_entry(new_header, j);
e.next = fr.entry_index;
var ndata = ^u8(e);
__mem_copy(ndata+value_offset, data+value_offset, value_size);
if __dynamic_map_full(new_header) {
__dynamic_map_grow(new_header);
}
}
free_ptr_with_allocator(header_hashes.allocator, header_hashes.data);
free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data);
header.m^ = nm;
}
proc __dynamic_map_get(h: __MapHeader, key: __MapKey) -> rawptr {
var index = __dynamic_map_find(h, key).entry_index;
if index >= 0 {
var data = ^u8(__dynamic_map_get_entry(h, index));
var val = data + h.value_offset;
return val;
}
return nil;
}
proc __dynamic_map_set(using h: __MapHeader, key: __MapKey, value: rawptr) {
var index: int;
assert(value != nil);
if len(m.hashes) == 0 {
__dynamic_map_reserve(h, __INITIAL_MAP_CAP);
__dynamic_map_grow(h);
}
var fr = __dynamic_map_find(h, key);
if fr.entry_index >= 0 {
index = fr.entry_index;
} else {
index = __dynamic_map_add_entry(h, key);
if fr.entry_prev >= 0 {
var entry = __dynamic_map_get_entry(h, fr.entry_prev);
entry.next = index;
} else {
m.hashes[fr.hash_index] = index;
}
}
{
var e = __dynamic_map_get_entry(h, index);
e.key = key;
var val = ^u8(e) + value_offset;
__mem_copy(val, value, value_size);
}
if __dynamic_map_full(h) {
__dynamic_map_grow(h);
}
}
proc __dynamic_map_grow(using h: __MapHeader) {
var new_count = max(2*m.entries.cap + 8, __INITIAL_MAP_CAP);
__dynamic_map_rehash(h, new_count);
}
proc __dynamic_map_full(using h: __MapHeader) -> bool {
return int(0.75 * f64(len(m.hashes))) <= m.entries.cap;
}
proc __dynamic_map_hash_equal(h: __MapHeader, a, b: __MapKey) -> bool {
if a.hash == b.hash {
if h.is_key_string -> return a.str == b.str;
return true;
}
return false;
}
proc __dynamic_map_find(using h: __MapHeader, key: __MapKey) -> __MapFindResult {
var fr = __MapFindResult{-1, -1, -1};
if len(m.hashes) > 0 {
fr.hash_index = int(key.hash % u128(len(m.hashes)));
fr.entry_index = m.hashes[fr.hash_index];
for fr.entry_index >= 0 {
var entry = __dynamic_map_get_entry(h, fr.entry_index);
if __dynamic_map_hash_equal(h, entry.key, key) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = entry.next;
}
}
return fr;
}
proc __dynamic_map_add_entry(using h: __MapHeader, key: __MapKey) -> int {
var prev = m.entries.len;
var c = __dynamic_array_append_nothing(&m.entries, entry_size, entry_align);
if c != prev {
var end = __dynamic_map_get_entry(h, c-1);
end.key = key;
end.next = -1;
}
return prev;
}
proc __dynamic_map_delete(using h: __MapHeader, key: __MapKey) {
var fr = __dynamic_map_find(h, key);
if fr.entry_index >= 0 {
__dynamic_map_erase(h, fr);
}
}
proc __dynamic_map_get_entry(using h: __MapHeader, index: int) -> ^__MapEntryHeader {
var data = ^u8(m.entries.data) + index*entry_size;
return ^__MapEntryHeader(data);
}
proc __dynamic_map_erase(using h: __MapHeader, fr: __MapFindResult) {
if fr.entry_prev < 0 {
m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next;
} else {
__dynamic_map_get_entry(h, fr.entry_prev).next = __dynamic_map_get_entry(h, fr.entry_index).next;
}
if fr.entry_index == m.entries.len-1 {
m.entries.len--;
}
__mem_copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.len-1), entry_size);
var last = __dynamic_map_find(h, __dynamic_map_get_entry(h, fr.entry_index).key);
if last.entry_prev >= 0 {
__dynamic_map_get_entry(h, last.entry_prev).next = fr.entry_index;
} else {
m.hashes[last.hash_index] = fr.entry_index;
}
}
-227
View File
@@ -1,227 +0,0 @@
#shared_global_scope;
proc __multi3(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
const bits_in_dword_2 = size_of(i64) * 4;
const lower_mask = u128(~u64(0) >> bits_in_dword_2);
when ODIN_ENDIAN == "bit" {
type TWords raw_union {
all: u128,
using _: struct {lo, hi: u64},
};
} else {
type TWords raw_union {
all: u128,
using _: struct {hi, lo: u64},
};
}
var r: TWords;
var t: u64;
r.lo = u64(a & lower_mask) * u64(b & lower_mask);
t = r.lo >> bits_in_dword_2;
r.lo &= u64(lower_mask);
t += u64(a >> bits_in_dword_2) * u64(b & lower_mask);
r.lo += u64(t & u64(lower_mask)) << bits_in_dword_2;
r.hi = t >> bits_in_dword_2;
t = r.lo >> bits_in_dword_2;
r.lo &= u64(lower_mask);
t += u64(b >> bits_in_dword_2) * u64(a & lower_mask);
r.lo += u64(t & u64(lower_mask)) << bits_in_dword_2;
r.hi += t >> bits_in_dword_2;
r.hi += u64(a >> bits_in_dword_2) * u64(b >> bits_in_dword_2);
return r.all;
}
proc __u128_mod(a, b: u128) -> u128 #cc_c #link_name "__umodti3" {
var r: u128;
__u128_quo_mod(a, b, &r);
return r;
}
proc __u128_quo(a, b: u128) -> u128 #cc_c #link_name "__udivti3" {
return __u128_quo_mod(a, b, nil);
}
proc __i128_mod(a, b: i128) -> i128 #cc_c #link_name "__modti3" {
var r: i128;
__i128_quo_mod(a, b, &r);
return r;
}
proc __i128_quo(a, b: i128) -> i128 #cc_c #link_name "__divti3" {
return __i128_quo_mod(a, b, nil);
}
proc __i128_quo_mod(a, b: i128, rem: ^i128) -> (quo: i128) #cc_c #link_name "__divmodti4" {
var s: i128;
s = b >> 127;
b = (b~s) - s;
s = a >> 127;
b = (a~s) - s;
var uquo: u128;
var urem = __u128_quo_mod(transmute(u128, a), transmute(u128, b), &uquo);
var iquo = transmute(i128, uquo);
var irem = transmute(i128, urem);
iquo = (iquo~s) - s;
irem = (irem~s) - s;
if rem != nil { rem^ = irem; }
return iquo;
}
proc __u128_quo_mod(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "__udivmodti4" {
var alo, ahi = u64(a), u64(a>>64);
var blo, bhi = u64(b), u64(b>>64);
if b == 0 {
if rem != nil { rem^ = 0; }
return u128(alo/blo);
}
var r, d, x, q: u128 = a, b, 1, 0;
for r >= d && (d>>127)&1 == 0 {
x <<= 1;
d <<= 1;
}
for x != 0 {
if r >= d {
r -= d;
q |= x;
}
x >>= 1;
d >>= 1;
}
if rem != nil { rem^ = r; }
return q;
}
/*
proc __f16_to_f32(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee" {
when true {
// Source: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
const FP32 = raw_union {u: u32, f: f32};
magic, was_infnan: FP32;
magic.u = (254-15) << 23;
was_infnan.u = (127+16) << 23;
hu := transmute(u16, f);
o := FP32{};
o.u = u32(hu & 0x7fff) << 13);
o.f *= magic.f;
if o.f >= was_infnan.f {
o.u |= 255 << 23;
}
o.u |= u32(hu & 0x8000) << 16;
return o.f;
} else {
return 0;
}
}
proc __f32_to_f16(f_: f32) -> f16 #cc_c #no_inline #link_name "__gnu_f2h_ieee" {
when false {
// Source: https://gist.github.com/rygorous/2156668
const FP16 = raw_union {u: u16, f: f16};
const FP32 = raw_union {u: u32, f: f32};
f32infty, f16infty, magic: FP32;
f32infty.u = 255<<23;
f16infty.u = 31<<23;
magic.u = 15<<23;
const sign_mask = u32(0x80000000);
const round_mask = ~u32(0x0fff);
f := transmute(FP32, f_);
o: FP16;
sign := f.u & sign_mask;
f.u ~= sign;
// NOTE all the integer compares in this function can be safely
// compiled into signed compares since all operands are below
// 0x80000000. Important if you want fast straight SSE2 code
// (since there's no unsigned PCMPGTD).
if f.u >= f32infty.u { // Inf or NaN (all exponent bits set)
o.u = f.u > f32infty.u ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf
} else { // (De)normalized number or zero
f.u &= round_mask;
f.f *= magic.f;
f.u -= round_mask;
if f.u > f16infty.u {
f.u = f16infty.u; // Clamp to signed infinity if overflowed
}
o.u = u16(f.u >> 13); // Take the bits!
}
o.u |= u16(sign >> 16);
return o.f;
} else {
f := transmute(u32, f_);
h: u16;
hs, he, hf: u16;
fs := (f >> 31) & 1;
fe := (f >> 23) & 0b1111_1111;
ff := (f >> 0) & 0b0111_1111_1111_1111_1111_1111;
add_one := false;
if (fe == 0) {
he = 0;
} else if (fe == 255) {
he = 31;
hf = ff != 0 ? 0x200 : 0;
} else {
ne := fe - 127 + 15;
if ne >= 31 {
he = 31;
} else if ne <= 0 {
if (14-ne) <= 24 {
mant := ff | 0x800000;
hf = u16(mant >> (14-ne));
if (mant >> (13-ne)) & 1 != 0 {
add_one = true;
}
}
} else {
he = u16(ne);
hf = u16(ff >> 13);
if ff&0x1000 != 0 {
add_one = true;
}
}
}
hs = u16(hs);
h |= (he&0b0001_1111)<<10;
h |= (hf&0b0011_1111_1111);
if add_one {
h++;
}
h |= (hs&1) << 15;
return transmute(f16, h);
}
}
proc __f64_to_f16(f: f64) -> f16 #cc_c #no_inline #link_name "__truncdfhf2" {
return __f32_to_f16(f32(f));
}
proc __f16_to_f64(f: f16) -> f64 #cc_c #no_inline {
return f64(__f16_to_f32(f));
}
*/
-100
View File
@@ -1,100 +0,0 @@
// TODO(bill): Use assembly instead here to implement atomics
// Inline vs external file?
import win32 "sys/windows.odin" when ODIN_OS == "windows";
var _ = compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
proc yield_thread() { win32.mm_pause(); }
proc mfence () { win32.read_write_barrier(); }
proc sfence () { win32.write_barrier(); }
proc lfence () { win32.read_barrier(); }
proc load(a: ^i32) -> i32 {
return a^;
}
proc store(a: ^i32, value: i32) {
a^ = value;
}
proc compare_exchange(a: ^i32, expected, desired: i32) -> i32 {
return win32.interlocked_compare_exchange(a, desired, expected);
}
proc exchanged(a: ^i32, desired: i32) -> i32 {
return win32.interlocked_exchange(a, desired);
}
proc fetch_add(a: ^i32, operand: i32) -> i32 {
return win32.interlocked_exchange_add(a, operand);
}
proc fetch_and(a: ^i32, operand: i32) -> i32 {
return win32.interlocked_and(a, operand);
}
proc fetch_or(a: ^i32, operand: i32) -> i32 {
return win32.interlocked_or(a, operand);
}
proc spin_lock(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
var old_value = compare_exchange(a, 1, 0);
var counter = 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter++;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
}
return old_value == 0;
}
proc spin_unlock(a: ^i32) {
store(a, 0);
mfence();
}
proc try_acquire_lock(a: ^i32) -> bool {
yield_thread();
var old_value = compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}
proc load(a: ^i64) -> i64 {
return a^;
}
proc store(a: ^i64, value: i64) {
a^ = value;
}
proc compare_exchange(a: ^i64, expected, desired: i64) -> i64 {
return win32.interlocked_compare_exchange64(a, desired, expected);
}
proc exchanged(a: ^i64, desired: i64) -> i64 {
return win32.interlocked_exchange64(a, desired);
}
proc fetch_add(a: ^i64, operand: i64) -> i64 {
return win32.interlocked_exchange_add64(a, operand);
}
proc fetch_and(a: ^i64, operand: i64) -> i64 {
return win32.interlocked_and64(a, operand);
}
proc fetch_or(a: ^i64, operand: i64) -> i64 {
return win32.interlocked_or64(a, operand);
}
proc spin_lock(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
var old_value = compare_exchange(a, 1, 0);
var counter = 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter++;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
}
return old_value == 0;
}
proc spin_unlock(a: ^i64) {
store(a, 0);
mfence();
}
proc try_acquire_lock(a: ^i64) -> bool {
yield_thread();
var old_value = compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}
-287
View File
@@ -1,287 +0,0 @@
const (
U8_MIN = u8(0);
U16_MIN = u16(0);
U32_MIN = u32(0);
U64_MIN = u64(0);
U128_MIN = u128(0);
I8_MIN = i8(-0x80);
I16_MIN = i16(-0x8000);
I32_MIN = i32(-0x8000_0000);
I64_MIN = i64(-0x8000_0000_0000_0000);
I128_MIN = i128(-0x8000_0000_0000_0000_0000_0000_0000_0000);
U8_MAX = ~u8(0);
U16_MAX = ~u16(0);
U32_MAX = ~u32(0);
U64_MAX = ~u64(0);
U128_MAX = ~u128(0);
I8_MAX = i8(0x7f);
I16_MAX = i16(0x7fff);
I32_MAX = i32(0x7fff_ffff);
I64_MAX = i64(0x7fff_ffff_ffff_ffff);
I128_MAX = i128(0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ffff);
)
proc count_ones(i: u8) -> u8 { foreign __llvm_core proc __llvm_ctpop(u8) -> u8 #link_name "llvm.ctpop.i8"; return __llvm_ctpop(i); }
proc count_ones(i: i8) -> i8 { foreign __llvm_core proc __llvm_ctpop(i8) -> i8 #link_name "llvm.ctpop.i8"; return __llvm_ctpop(i); }
proc count_ones(i: u16) -> u16 { foreign __llvm_core proc __llvm_ctpop(u16) -> u16 #link_name "llvm.ctpop.i16"; return __llvm_ctpop(i); }
proc count_ones(i: i16) -> i16 { foreign __llvm_core proc __llvm_ctpop(i16) -> i16 #link_name "llvm.ctpop.i16"; return __llvm_ctpop(i); }
proc count_ones(i: u32) -> u32 { foreign __llvm_core proc __llvm_ctpop(u32) -> u32 #link_name "llvm.ctpop.i32"; return __llvm_ctpop(i); }
proc count_ones(i: i32) -> i32 { foreign __llvm_core proc __llvm_ctpop(i32) -> i32 #link_name "llvm.ctpop.i32"; return __llvm_ctpop(i); }
proc count_ones(i: u64) -> u64 { foreign __llvm_core proc __llvm_ctpop(u64) -> u64 #link_name "llvm.ctpop.i64"; return __llvm_ctpop(i); }
proc count_ones(i: i64) -> i64 { foreign __llvm_core proc __llvm_ctpop(i64) -> i64 #link_name "llvm.ctpop.i64"; return __llvm_ctpop(i); }
proc count_ones(i: u128) -> u128 { foreign __llvm_core proc __llvm_ctpop(u128) -> u128 #link_name "llvm.ctpop.i128";return __llvm_ctpop(i); }
proc count_ones(i: i128) -> i128 { foreign __llvm_core proc __llvm_ctpop(i128) -> i128 #link_name "llvm.ctpop.i128";return __llvm_ctpop(i); }
proc count_ones(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(count_ones(u32(i))); } else { return uint(count_ones(u64(i))); } }
proc count_ones(i: int) -> int { when size_of(int) == size_of(i32) { return int(count_ones(i32(i))); } else { return int(count_ones(i64(i))); } }
proc count_zeros(i: u8) -> u8 { return 8 - count_ones(i); }
proc count_zeros(i: i8) -> i8 { return 8 - count_ones(i); }
proc count_zeros(i: u16) -> u16 { return 16 - count_ones(i); }
proc count_zeros(i: i16) -> i16 { return 16 - count_ones(i); }
proc count_zeros(i: u32) -> u32 { return 32 - count_ones(i); }
proc count_zeros(i: i32) -> i32 { return 32 - count_ones(i); }
proc count_zeros(i: u64) -> u64 { return 64 - count_ones(i); }
proc count_zeros(i: i64) -> i64 { return 64 - count_ones(i); }
proc count_zeros(i: u128) -> u128 { return 128 - count_ones(i); }
proc count_zeros(i: i128) -> i128 { return 128 - count_ones(i); }
proc count_zeros(i: uint) -> uint { return 8*size_of(uint) - count_ones(i); }
proc count_zeros(i: int) -> int { return 8*size_of(int) - count_ones(i); }
proc rotate_left(i: u8, s: uint) -> u8 { return (i << s)|(i >> (8*size_of(u8) - s)); }
proc rotate_left(i: i8, s: uint) -> i8 { return (i << s)|(i >> (8*size_of(i8) - s)); }
proc rotate_left(i: u16, s: uint) -> u16 { return (i << s)|(i >> (8*size_of(u16) - s)); }
proc rotate_left(i: i16, s: uint) -> i16 { return (i << s)|(i >> (8*size_of(i16) - s)); }
proc rotate_left(i: u32, s: uint) -> u32 { return (i << s)|(i >> (8*size_of(u32) - s)); }
proc rotate_left(i: i32, s: uint) -> i32 { return (i << s)|(i >> (8*size_of(i32) - s)); }
proc rotate_left(i: u64, s: uint) -> u64 { return (i << s)|(i >> (8*size_of(u64) - s)); }
proc rotate_left(i: i64, s: uint) -> i64 { return (i << s)|(i >> (8*size_of(i64) - s)); }
proc rotate_left(i: u128, s: uint) -> u128 { return (i << s)|(i >> (8*size_of(u128) - s)); }
proc rotate_left(i: i128, s: uint) -> i128 { return (i << s)|(i >> (8*size_of(i128) - s)); }
proc rotate_left(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_left(u32(i), s)); } else { return uint(rotate_left(u64(i), s)); } }
proc rotate_left(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_left(i32(i), s)); } else { return int(rotate_left(i64(i), s)); } }
proc rotate_right(i: u8, s: uint) -> u8 { return (i >> s)|(i << (8*size_of(u8) - s)); }
proc rotate_right(i: i8, s: uint) -> i8 { return (i >> s)|(i << (8*size_of(i8) - s)); }
proc rotate_right(i: u16, s: uint) -> u16 { return (i >> s)|(i << (8*size_of(u16) - s)); }
proc rotate_right(i: i16, s: uint) -> i16 { return (i >> s)|(i << (8*size_of(i16) - s)); }
proc rotate_right(i: u32, s: uint) -> u32 { return (i >> s)|(i << (8*size_of(u32) - s)); }
proc rotate_right(i: i32, s: uint) -> i32 { return (i >> s)|(i << (8*size_of(i32) - s)); }
proc rotate_right(i: u64, s: uint) -> u64 { return (i >> s)|(i << (8*size_of(u64) - s)); }
proc rotate_right(i: i64, s: uint) -> i64 { return (i >> s)|(i << (8*size_of(i64) - s)); }
proc rotate_right(i: u128, s: uint) -> u128 { return (i >> s)|(i << (8*size_of(u128) - s)); }
proc rotate_right(i: i128, s: uint) -> i128 { return (i >> s)|(i << (8*size_of(i128) - s)); }
proc rotate_right(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_right(u32(i), s)); } else { return uint(rotate_right(u64(i), s)); } }
proc rotate_right(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_right(i32(i), s)); } else { return int(rotate_right(i64(i), s)); } }
proc leading_zeros(i: u8) -> u8 { foreign __llvm_core proc __llvm_ctlz(u8, bool) -> u8 #link_name "llvm.ctlz.i8"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: i8) -> i8 { foreign __llvm_core proc __llvm_ctlz(i8, bool) -> i8 #link_name "llvm.ctlz.i8"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: u16) -> u16 { foreign __llvm_core proc __llvm_ctlz(u16, bool) -> u16 #link_name "llvm.ctlz.i16"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: i16) -> i16 { foreign __llvm_core proc __llvm_ctlz(i16, bool) -> i16 #link_name "llvm.ctlz.i16"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: u32) -> u32 { foreign __llvm_core proc __llvm_ctlz(u32, bool) -> u32 #link_name "llvm.ctlz.i32"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: i32) -> i32 { foreign __llvm_core proc __llvm_ctlz(i32, bool) -> i32 #link_name "llvm.ctlz.i32"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: u64) -> u64 { foreign __llvm_core proc __llvm_ctlz(u64, bool) -> u64 #link_name "llvm.ctlz.i64"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: i64) -> i64 { foreign __llvm_core proc __llvm_ctlz(i64, bool) -> i64 #link_name "llvm.ctlz.i64"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: u128) -> u128 { foreign __llvm_core proc __llvm_ctlz(u128, bool) -> u128 #link_name "llvm.ctlz.i128";return __llvm_ctlz(i, false); }
proc leading_zeros(i: i128) -> i128 { foreign __llvm_core proc __llvm_ctlz(i128, bool) -> i128 #link_name "llvm.ctlz.i128";return __llvm_ctlz(i, false); }
proc leading_zeros(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(leading_zeros(u32(i))); } else { return uint(leading_zeros(u64(i))); } }
proc leading_zeros(i: int) -> int { when size_of(int) == size_of(i32) { return int(leading_zeros(i32(i))); } else { return int(leading_zeros(i64(i))); } }
proc trailing_zeros(i: u8) -> u8 { foreign __llvm_core proc __llvm_cttz(u8, bool) -> u8 #link_name "llvm.cttz.i8"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: i8) -> i8 { foreign __llvm_core proc __llvm_cttz(i8, bool) -> i8 #link_name "llvm.cttz.i8"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: u16) -> u16 { foreign __llvm_core proc __llvm_cttz(u16, bool) -> u16 #link_name "llvm.cttz.i16"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: i16) -> i16 { foreign __llvm_core proc __llvm_cttz(i16, bool) -> i16 #link_name "llvm.cttz.i16"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: u32) -> u32 { foreign __llvm_core proc __llvm_cttz(u32, bool) -> u32 #link_name "llvm.cttz.i32"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: i32) -> i32 { foreign __llvm_core proc __llvm_cttz(i32, bool) -> i32 #link_name "llvm.cttz.i32"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: u64) -> u64 { foreign __llvm_core proc __llvm_cttz(u64, bool) -> u64 #link_name "llvm.cttz.i64"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: i64) -> i64 { foreign __llvm_core proc __llvm_cttz(i64, bool) -> i64 #link_name "llvm.cttz.i64"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: u128) -> u128 { foreign __llvm_core proc __llvm_cttz(u128, bool) -> u128 #link_name "llvm.cttz.i128";return __llvm_cttz(i, false); }
proc trailing_zeros(i: i128) -> i128 { foreign __llvm_core proc __llvm_cttz(i128, bool) -> i128 #link_name "llvm.cttz.i128";return __llvm_cttz(i, false); }
proc trailing_zeros(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(trailing_zeros(u32(i))); } else { return uint(trailing_zeros(u64(i))); } }
proc trailing_zeros(i: int) -> int { when size_of(int) == size_of(i32) { return int(trailing_zeros(i32(i))); } else { return int(trailing_zeros(i64(i))); } }
proc reverse_bits(i: u8) -> u8 { foreign __llvm_core proc __llvm_bitreverse(u8) -> u8 #link_name "llvm.bitreverse.i8"; return __llvm_bitreverse(i); }
proc reverse_bits(i: i8) -> i8 { foreign __llvm_core proc __llvm_bitreverse(i8) -> i8 #link_name "llvm.bitreverse.i8"; return __llvm_bitreverse(i); }
proc reverse_bits(i: u16) -> u16 { foreign __llvm_core proc __llvm_bitreverse(u16) -> u16 #link_name "llvm.bitreverse.i16"; return __llvm_bitreverse(i); }
proc reverse_bits(i: i16) -> i16 { foreign __llvm_core proc __llvm_bitreverse(i16) -> i16 #link_name "llvm.bitreverse.i16"; return __llvm_bitreverse(i); }
proc reverse_bits(i: u32) -> u32 { foreign __llvm_core proc __llvm_bitreverse(u32) -> u32 #link_name "llvm.bitreverse.i32"; return __llvm_bitreverse(i); }
proc reverse_bits(i: i32) -> i32 { foreign __llvm_core proc __llvm_bitreverse(i32) -> i32 #link_name "llvm.bitreverse.i32"; return __llvm_bitreverse(i); }
proc reverse_bits(i: u64) -> u64 { foreign __llvm_core proc __llvm_bitreverse(u64) -> u64 #link_name "llvm.bitreverse.i64"; return __llvm_bitreverse(i); }
proc reverse_bits(i: i64) -> i64 { foreign __llvm_core proc __llvm_bitreverse(i64) -> i64 #link_name "llvm.bitreverse.i64"; return __llvm_bitreverse(i); }
proc reverse_bits(i: u128) -> u128 { foreign __llvm_core proc __llvm_bitreverse(u128) -> u128 #link_name "llvm.bitreverse.i128";return __llvm_bitreverse(i); }
proc reverse_bits(i: i128) -> i128 { foreign __llvm_core proc __llvm_bitreverse(i128) -> i128 #link_name "llvm.bitreverse.i128";return __llvm_bitreverse(i); }
proc reverse_bits(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(reverse_bits(u32(i))); } else { return uint(reverse_bits(u64(i))); } }
proc reverse_bits(i: int) -> int { when size_of(int) == size_of(i32) { return int(reverse_bits(i32(i))); } else { return int(reverse_bits(i64(i))); } }
foreign __llvm_core {
proc byte_swap(u16) -> u16 #link_name "llvm.bswap.i16";
proc byte_swap(i16) -> i16 #link_name "llvm.bswap.i16";
proc byte_swap(u32) -> u32 #link_name "llvm.bswap.i32";
proc byte_swap(i32) -> i32 #link_name "llvm.bswap.i32";
proc byte_swap(u64) -> u64 #link_name "llvm.bswap.i64";
proc byte_swap(i64) -> i64 #link_name "llvm.bswap.i64";
proc byte_swap(u128) -> u128 #link_name "llvm.bswap.i128";
proc byte_swap(i128) -> i128 #link_name "llvm.bswap.i128";
}
proc byte_swap(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(byte_swap(u32(i))); } else { return uint(byte_swap(u64(i))); } }
proc byte_swap(i: int) -> int { when size_of(int) == size_of(i32) { return int(byte_swap(i32(i))); } else { return int(byte_swap(i64(i))); } }
proc from_be(i: u8) -> u8 { return i; }
proc from_be(i: i8) -> i8 { return i; }
proc from_be(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_le(i: u8) -> u8 { return i; }
proc from_le(i: i8) -> i8 { return i; }
proc from_le(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_be(i: u8) -> u8 { return i; }
proc to_be(i: i8) -> i8 { return i; }
proc to_be(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_le(i: u8) -> u8 { return i; }
proc to_le(i: i8) -> i8 { return i; }
proc to_le(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc overflowing_add(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core proc op(u8, u8) -> (u8, bool) #link_name "llvm.uadd.with.overflow.i8"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core proc op(i8, i8) -> (i8, bool) #link_name "llvm.sadd.with.overflow.i8"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core proc op(u16, u16) -> (u16, bool) #link_name "llvm.uadd.with.overflow.i16"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core proc op(i16, i16) -> (i16, bool) #link_name "llvm.sadd.with.overflow.i16"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core proc op(u32, u32) -> (u32, bool) #link_name "llvm.uadd.with.overflow.i32"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core proc op(i32, i32) -> (i32, bool) #link_name "llvm.sadd.with.overflow.i32"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core proc op(u64, u64) -> (u64, bool) #link_name "llvm.uadd.with.overflow.i64"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core proc op(i64, i64) -> (i64, bool) #link_name "llvm.sadd.with.overflow.i64"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core proc op(u128, u128) -> (u128, bool) #link_name "llvm.uadd.with.overflow.i128"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core proc op(i128, i128) -> (i128, bool) #link_name "llvm.sadd.with.overflow.i128"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
var x, ok = overflowing_add(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
var x, ok = overflowing_add(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
proc overflowing_add(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
var x, ok = overflowing_add(i32(lhs), i32(rhs));
return int(x), ok;
} else {
var x, ok = overflowing_add(i64(lhs), i64(rhs));
return int(x), ok;
}
}
proc overflowing_sub(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core proc op(u8, u8) -> (u8, bool) #link_name "llvm.usub.with.overflow.i8"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core proc op(i8, i8) -> (i8, bool) #link_name "llvm.ssub.with.overflow.i8"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core proc op(u16, u16) -> (u16, bool) #link_name "llvm.usub.with.overflow.i16"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core proc op(i16, i16) -> (i16, bool) #link_name "llvm.ssub.with.overflow.i16"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core proc op(u32, u32) -> (u32, bool) #link_name "llvm.usub.with.overflow.i32"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core proc op(i32, i32) -> (i32, bool) #link_name "llvm.ssub.with.overflow.i32"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core proc op(u64, u64) -> (u64, bool) #link_name "llvm.usub.with.overflow.i64"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core proc op(i64, i64) -> (i64, bool) #link_name "llvm.ssub.with.overflow.i64"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core proc op(u128, u128) -> (u128, bool) #link_name "llvm.usub.with.overflow.i128"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core proc op(i128, i128) -> (i128, bool) #link_name "llvm.ssub.with.overflow.i128"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
var x, ok = overflowing_sub(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
var x, ok = overflowing_sub(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
proc overflowing_sub(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
var x, ok = overflowing_sub(i32(lhs), i32(rhs));
return int(x), ok;
} else {
var x, ok = overflowing_sub(i64(lhs), i64(rhs));
return int(x), ok;
}
}
proc overflowing_mul(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core proc op(u8, u8) -> (u8, bool) #link_name "llvm.umul.with.overflow.i8"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core proc op(i8, i8) -> (i8, bool) #link_name "llvm.smul.with.overflow.i8"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core proc op(u16, u16) -> (u16, bool) #link_name "llvm.umul.with.overflow.i16"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core proc op(i16, i16) -> (i16, bool) #link_name "llvm.smul.with.overflow.i16"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core proc op(u32, u32) -> (u32, bool) #link_name "llvm.umul.with.overflow.i32"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core proc op(i32, i32) -> (i32, bool) #link_name "llvm.smul.with.overflow.i32"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core proc op(u64, u64) -> (u64, bool) #link_name "llvm.umul.with.overflow.i64"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core proc op(i64, i64) -> (i64, bool) #link_name "llvm.smul.with.overflow.i64"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core proc op(u128, u128) -> (u128, bool) #link_name "llvm.umul.with.overflow.i128"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core proc op(i128, i128) -> (i128, bool) #link_name "llvm.smul.with.overflow.i128"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
var x, ok = overflowing_mul(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
var x, ok = overflowing_mul(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
proc overflowing_mul(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
var x, ok = overflowing_mul(i32(lhs), i32(rhs));
return int(x), ok;
} else {
var x, ok = overflowing_mul(i64(lhs), i64(rhs));
return int(x), ok;
}
}
proc is_power_of_two(i: u8) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: i8) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: u16) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: i16) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: u32) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: i32) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: u64) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: i64) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: u128) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: i128) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: int) -> bool { return i > 0 && (i & (i-1)) == 0; }
+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 ---
+35
View File
@@ -0,0 +1,35 @@
package c
import b "core:builtin"
CHAR_BIT :: 8;
bool :: b.bool;
char :: b.u8;
byte :: b.byte;
schar :: b.i8;
uchar :: b.u8;
short :: b.i16;
ushort :: b.u16;
int :: b.i32;
uint :: b.u32;
long :: (ODIN_OS == "windows" || size_of(b.rawptr) == 4) ? b.i32 : b.i64;
ulong :: (ODIN_OS == "windows" || size_of(b.rawptr) == 4) ? b.u32 : b.u64;
longlong :: b.i64;
ulonglong :: b.u64;
float :: b.f32;
double :: b.f64;
complex_float :: b.complex64;
complex_double :: b.complex128;
#assert(size_of(b.uintptr) == size_of(b.int));
size_t :: b.uint;
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;
-257
View File
@@ -1,257 +0,0 @@
// #import "fmt.odin";
// Multiple precision decimal numbers
// NOTE: This is only for floating point printing and nothing else
type Decimal struct {
digits: [384]u8, // big-endian digits
count: int,
decimal_point: int,
neg, trunc: bool,
}
proc decimal_to_string(buf: []u8, a: ^Decimal) -> string {
proc digit_zero(buf: []u8) -> int {
for _, i in buf -> buf[i] = '0';
return len(buf);
}
var n = 10 + a.count + abs(a.decimal_point);
// TODO(bill): make this work with a buffer that's not big enough
assert(len(buf) >= n);
buf = buf[0..<n];
if a.count == 0 {
buf[0] = '0';
return string(buf[0..<1]);
}
var w = 0;
if a.decimal_point <= 0 {
buf[w] = '0'; w++;
buf[w] = '.'; w++;
w += digit_zero(buf[w ..< w-a.decimal_point]);
w += copy(buf[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++;
w += copy(buf[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]);
}
return string(buf[0..<w]);
}
// trim trailing zeros
proc trim(a: ^Decimal) {
for a.count > 0 && a.digits[a.count-1] == '0' {
a.count--;
}
if a.count == 0 {
a.decimal_point = 0;
}
}
proc assign(a: ^Decimal, i: u64) {
var buf: [32]u8;
var n = 0;
for i > 0 {
var j = i/10;
i -= 10*j;
buf[n] = u8('0'+i);
n++;
i = j;
}
a.count = 0;
for n--; n >= 0; n-- {
a.digits[a.count] = buf[n];
a.count++;
}
a.decimal_point = a.count;
trim(a);
}
proc shift_right(a: ^Decimal, k: uint) {
var r = 0; // read index
var w = 0; // write index
var n: uint;
for ; n>>k == 0; r++ {
if r >= a.count {
if n == 0 {
// Just in case
a.count = 0;
return;
}
for n>>k == 0 {
n = n * 10;
r++;
}
break;
}
var c = uint(a.digits[r]);
n = n*10 + c - '0';
}
a.decimal_point -= r-1;
var mask: uint = (1<<k) - 1;
for ; r < a.count; r++ {
var c = uint(a.digits[r]);
var dig = n>>k;
n &= mask;
a.digits[w] = u8('0' + dig);
w++;
n = n*10 + c - '0';
}
for n > 0 {
var dig = n>>k;
n &= mask;
if w < len(a.digits) {
a.digits[w] = u8('0' + dig);
w++;
} else if dig > 0 {
a.trunc = true;
}
n *= 10;
}
a.count = w;
trim(a);
}
proc shift_left(a: ^Decimal, k: uint) {
var delta = int(k/4);
var r = a.count; // read index
var w = a.count+delta; // write index
var n: uint;
for r--; r >= 0; r-- {
n += (uint(a.digits[r]) - '0') << k;
var quo = n/10;
var rem = n - 10*quo;
w--;
if w < len(a.digits) {
a.digits[w] = u8('0' + rem);
} else if rem != 0 {
a.trunc = true;
}
n = quo;
}
for n > 0 {
var quo = n/10;
var rem = n - 10*quo;
w--;
if 0 <= w && w < len(a.digits) {
a.digits[w] = u8('0' + rem);
} else if rem != 0 {
a.trunc = true;
}
n = quo;
}
a.count += delta;
a.count = min(a.count, len(a.digits));
a.decimal_point += delta;
trim(a);
}
proc shift(a: ^Decimal, k: int) {
const (
uint_size = 8*size_of(uint);
max_shift = uint_size-4;
)
match {
case a.count == 0:
// no need to update
case k > 0:
for k > max_shift {
shift_left(a, max_shift);
k -= max_shift;
}
shift_left(a, uint(k));
case k < 0:
for k < -max_shift {
shift_right(a, max_shift);
k += max_shift;
}
shift_right(a, uint(-k));
}
}
proc can_round_up(a: ^Decimal, nd: int) -> bool {
if nd < 0 || nd >= a.count { return false ; }
if a.digits[nd] == '5' && nd+1 == a.count {
if a.trunc -> return true;
return nd > 0 && (a.digits[nd-1]-'0')%2 != 0;
}
return a.digits[nd] >= '5';
}
proc round(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
if can_round_up(a, nd) {
round_up(a, nd);
} else {
round_down(a, nd);
}
}
proc round_up(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
for var i = nd-1; i >= 0; i-- {
if var c = a.digits[i]; c < '9' {
a.digits[i]++;
a.count = i+1;
return;
}
}
// Number is just 9s
a.digits[0] = '1';
a.count = 1;
a.decimal_point++;
}
proc round_down(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
a.count = nd;
trim(a);
}
// Extract integer part, rounded appropriately. There are no guarantees about overflow.
proc rounded_integer(a: ^Decimal) -> u64 {
if a.decimal_point > 20 {
return 0xffff_ffff_ffff_ffff;
}
var i: int;
var n: u64 = 0;
var m = min(a.decimal_point, a.count);
for i = 0; i < m; i++ {
n = n*10 + u64(a.digits[i]-'0');
}
for ; i < a.decimal_point; i++ {
n *= 10;
}
if can_round_up(a, a.decimal_point) {
n++;
}
return n;
}
+3
View File
@@ -0,0 +1,3 @@
package dynlib
Library :: opaque rawptr;
+24
View File
@@ -0,0 +1,24 @@
package dynlib
import "core:sys/win32"
import "core:strings"
load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
wide_path := win32.utf8_to_wstring(path, context.temp_allocator);
handle := cast(Library)win32.load_library_w(wide_path);
return handle, handle != nil;
}
unload_library :: proc(library: Library) -> bool {
ok := win32.free_library(cast(win32.Hmodule)library);
return bool(ok);
}
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;
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;
}
+840
View File
@@ -0,0 +1,840 @@
package cel;
import "core:fmt"
import "core:strconv"
import "core:unicode/utf8"
import "core:strings"
Array :: []Value;
Dict :: map[string]Value;
Nil_Value :: struct{};
Value :: union {
Nil_Value,
bool, i64, f64, string,
Array, Dict,
}
Parser :: struct {
tokens: [dynamic]Token,
prev_token: Token,
curr_token: Token,
curr_token_index: int,
allocated_strings: [dynamic]string,
error_count: int,
root: Dict,
dict_stack: [dynamic]^Dict, // NOTE: Pointers may be stored on the stack
}
print_value :: proc(value: Value, pretty := true, indent := 0) {
print_indent :: proc(indent: int) {
for _ in 0..<indent do fmt.print("\t");
}
switch v in value {
case bool: fmt.print(v);
case i64: fmt.print(v);
case f64: fmt.print(v);
case string: fmt.print(v);
case Array:
fmt.print("[");
if pretty do fmt.println();
for e, i in v {
if pretty {
print_indent(indent+1);
print_value(e, pretty, indent+1);
fmt.println(",");
} else {
if i > 0 do fmt.print(", ");
print_value(e);
}
}
if pretty do print_indent(indent);
fmt.print("]");
case Dict:
fmt.print("{");
if pretty do fmt.println();
i := 0;
for name, val in v {
if pretty {
print_indent(indent+1);
fmt.printf("%s = ", name);
print_value(val, pretty, indent+1);
fmt.println(",");
} else {
if i > 0 do fmt.print(", ");
fmt.printf("%s = ", name);
print_value(val, pretty, indent+1);
i += 1;
}
}
if pretty do print_indent(indent);
fmt.print("}");
case:
fmt.print("nil");
case Nil_Value:
fmt.print("nil");
}
}
print :: proc(p: ^Parser, pretty := false) {
for name, val in p.root {
fmt.printf("%s = ", name);
print_value(val, pretty);
fmt.println(";");
}
}
create_from_string :: proc(src: string) -> (^Parser, bool) {
return init(cast([]byte)src);
}
init :: proc(src: []byte) -> (^Parser, bool) {
t: Tokenizer;
tokenizer_init(&t, src);
return create_from_tokenizer(&t);
}
create_from_tokenizer :: proc(t: ^Tokenizer) -> (^Parser, bool) {
p := new(Parser);
for {
tok := scan(t);
if tok.kind == Kind.Illegal {
return p, false;
}
append(&p.tokens, tok);
if tok.kind == Kind.EOF {
break;
}
}
if t.error_count > 0 {
return p, false;
}
if len(p.tokens) == 0 {
tok := Token{kind = Kind.EOF};
tok.line, tok.column = 1, 1;
append(&p.tokens, tok);
return p, true;
}
p.curr_token_index = 0;
p.prev_token = p.tokens[p.curr_token_index];
p.curr_token = p.tokens[p.curr_token_index];
p.root = Dict{};
p.dict_stack = make([dynamic]^Dict, 0, 4);
append(&p.dict_stack, &p.root);
for p.curr_token.kind != Kind.EOF &&
p.curr_token.kind != Kind.Illegal &&
p.curr_token_index < len(p.tokens) {
if !parse_assignment(p) {
break;
}
}
return p, true;
}
destroy :: proc(p: ^Parser) {
destroy_value :: proc(value: Value) {
switch v in value {
case Array:
for elem in v do destroy_value(elem);
delete(v);
case Dict:
for _, dv in v do destroy_value(dv);
delete(v);
}
}
delete(p.tokens);
for s in p.allocated_strings do delete(s);
delete(p.allocated_strings);
delete(p.dict_stack);
destroy_value(p.root);
free(p);
}
error :: proc(p: ^Parser, pos: Pos, msg: string, args: ..any) {
fmt.eprintf("%s(%d:%d) Error: ", pos.file, pos.line, pos.column);
fmt.eprintf(msg, ..args);
fmt.eprintln();
p.error_count += 1;
}
next_token :: proc(p: ^Parser) -> Token {
p.prev_token = p.curr_token;
prev := p.prev_token;
if p.curr_token_index+1 < len(p.tokens) {
p.curr_token_index += 1;
p.curr_token = p.tokens[p.curr_token_index];
return prev;
}
p.curr_token_index = len(p.tokens);
p.curr_token = p.tokens[p.curr_token_index-1];
error(p, prev.pos, "Token is EOF");
return prev;
}
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');
case 'a'..'f': return int(c-'a')+10;
case 'A'..'F': return int(c-'A')+10;
}
return -1;
}
w: int;
if str[0] == quote && quote == '"' {
return;
} 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(str) <= 1 {
return;
}
s := str;
c := s[1];
s = s[2:];
switch c {
case:
return;
case 'a': r = '\a';
case 'b': r = '\b';
case 'f': r = '\f';
case 'n': r = '\n';
case 'r': r = '\r';
case 't': r = '\t';
case 'v': r = '\v';
case '\\': r = '\\';
case '"': r = '"';
case '\'': r = '\'';
case '0'..'7':
v := int(c-'0');
if len(s) < 2 {
return;
}
for i in 0..<len(s) {
d := int(s[i]-'0');
if d < 0 || d > 7 {
return;
}
v = (v<<3) | d;
}
s = s[2:];
if v > 0xff {
return;
}
r = rune(v);
case 'x', 'u', 'U':
count: int;
switch c {
case 'x': count = 2;
case 'u': count = 4;
case 'U': count = 8;
}
if len(s) < count {
return;
}
for i in 0..<count {
d := hex_to_int(s[i]);
if d < 0 {
return;
}
r = (r<<4) | rune(d);
}
s = s[count:];
if c == 'x' {
break;
}
if r > utf8.MAX_RUNE {
return;
}
multiple_bytes = true;
}
success = true;
tail_string = s;
return;
}
unquote_string :: proc(p: ^Parser, t: Token) -> (string, bool) {
if t.kind != Kind.String {
return t.lit, true;
}
s := t.lit;
quote := '"';
if s == `""` {
return "", true;
}
if strings.contains_rune(s, '\n') >= 0 {
return s, false;
}
if strings.contains_rune(s, '\\') < 0 && strings.contains_rune(s, quote) < 0 {
if quote == '"' {
return s, true;
}
}
buf_len := 3*len(s) / 2;
buf := make([]byte, buf_len);
offset := 0;
for len(s) > 0 {
r, multiple_bytes, tail_string, ok := unquote_char(s, byte(quote));
if !ok {
delete(buf);
return s, false;
}
s = tail_string;
if r < 0x80 || !multiple_bytes {
buf[offset] = byte(r);
offset += 1;
} else {
b, w := utf8.encode_rune(r);
copy(buf[offset:], b[:w]);
offset += w;
}
}
new_string := string(buf[:offset]);
append(&p.allocated_strings, new_string);
return new_string, true;
}
allow_token :: proc(p: ^Parser, kind: Kind) -> bool {
if p.curr_token.kind == kind {
next_token(p);
return true;
}
return false;
}
expect_token :: proc(p: ^Parser, kind: Kind) -> Token {
prev := p.curr_token;
if prev.kind != kind {
got := prev.lit;
if got == "\n" do got = ";";
error(p, prev.pos, "Expected %s, got %s", kind_to_string[kind], got);
}
next_token(p);
return prev;
}
expect_operator :: proc(p: ^Parser) -> Token {
prev := p.curr_token;
if !is_operator(prev.kind) {
error(p, prev.pos, "Expected an operator, got %s", prev.lit);
}
next_token(p);
return prev;
}
fix_advance :: proc(p: ^Parser) {
for {
switch t := p.curr_token; t.kind {
case Kind.EOF, Kind.Semicolon:
return;
}
next_token(p);
}
}
copy_value :: proc(value: Value) -> Value {
switch v in value {
case Array:
a := make(Array, len(v));
for elem, idx in v {
a[idx] = copy_value(elem);
}
return a;
case Dict:
d := make(Dict, cap(v));
for key, val in v {
d[key] = copy_value(val);
}
return d;
}
return value;
}
lookup_value :: proc(p: ^Parser, name: string) -> (Value, bool) {
for i := len(p.dict_stack)-1; i >= 0; i -= 1 {
d := p.dict_stack[i];
if val, ok := d[name]; ok {
return copy_value(val), true;
}
}
return nil, false;
}
parse_operand :: proc(p: ^Parser) -> (Value, Pos) {
tok := p.curr_token;
switch p.curr_token.kind {
case Kind.Ident:
next_token(p);
v, ok := lookup_value(p, tok.lit);
if !ok do error(p, tok.pos, "Undeclared identifier %s", tok.lit);
return v, tok.pos;
case Kind.True:
next_token(p);
return true, tok.pos;
case Kind.False:
next_token(p);
return false, tok.pos;
case Kind.Nil:
next_token(p);
return Nil_Value{}, tok.pos;
case Kind.Integer:
next_token(p);
return strconv.parse_i64(tok.lit), tok.pos;
case Kind.Float:
next_token(p);
return strconv.parse_f64(tok.lit), tok.pos;
case Kind.String:
next_token(p);
str, ok := unquote_string(p, tok);
if !ok do error(p, tok.pos, "Unable to unquote string");
return string(str), tok.pos;
case Kind.Open_Paren:
expect_token(p, Kind.Open_Paren);
expr, _ := parse_expr(p);
expect_token(p, Kind.Close_Paren);
return expr, tok.pos;
case Kind.Open_Bracket:
expect_token(p, Kind.Open_Bracket);
elems := make([dynamic]Value, 0, 4);
for p.curr_token.kind != Kind.Close_Bracket &&
p.curr_token.kind != Kind.EOF {
elem, _ := parse_expr(p);
append(&elems, elem);
if p.curr_token.kind == Kind.Semicolon && p.curr_token.lit == "\n" {
next_token(p);
} else if !allow_token(p, Kind.Comma) {
break;
}
}
expect_token(p, Kind.Close_Bracket);
return Array(elems[:]), tok.pos;
case Kind.Open_Brace:
expect_token(p, Kind.Open_Brace);
dict := Dict{};
append(&p.dict_stack, &dict);
defer pop(&p.dict_stack);
for p.curr_token.kind != Kind.Close_Brace &&
p.curr_token.kind != Kind.EOF {
name_tok := p.curr_token;
if !allow_token(p, Kind.Ident) && !allow_token(p, Kind.String) {
name_tok = expect_token(p, Kind.Ident);
}
name, ok := unquote_string(p, name_tok);
if !ok do error(p, tok.pos, "Unable to unquote string");
expect_token(p, Kind.Assign);
elem, _ := parse_expr(p);
if _, ok2 := dict[name]; ok2 {
error(p, name_tok.pos, "Previous declaration of %s in this scope", name);
} else {
dict[name] = elem;
}
if p.curr_token.kind == Kind.Semicolon && p.curr_token.lit == "\n" {
next_token(p);
} else if !allow_token(p, Kind.Comma) {
break;
}
}
expect_token(p, Kind.Close_Brace);
return dict, tok.pos;
}
return nil, tok.pos;
}
parse_atom_expr :: proc(p: ^Parser, operand: Value, pos: Pos) -> (Value, Pos) {
loop := true;
for operand := operand; loop; {
switch p.curr_token.kind {
case Kind.Period:
next_token(p);
tok := next_token(p);
switch tok.kind {
case Kind.Ident:
d, ok := operand.(Dict);
if !ok || d == nil {
error(p, tok.pos, "Expected a dictionary");
operand = nil;
continue;
}
name, usok := unquote_string(p, tok);
if !usok do error(p, tok.pos, "Unable to unquote string");
val, found := d[name];
if !found {
error(p, tok.pos, "Field %s not found in dictionary", name);
operand = nil;
continue;
}
operand = val;
case:
error(p, tok.pos, "Expected a selector, got %s", tok.kind);
operand = nil;
}
case Kind.Open_Bracket:
expect_token(p, Kind.Open_Bracket);
index, index_pos := parse_expr(p);
expect_token(p, Kind.Close_Bracket);
switch a in operand {
case Array:
i, ok := index.(i64);
if !ok {
error(p, index_pos, "Index must be an integer for an array");
operand = nil;
continue;
}
if 0 <= i && i < i64(len(a)) {
operand = a[i];
} else {
error(p, index_pos, "Index %d out of bounds range 0..%d", i, len(a));
operand = nil;
continue;
}
case Dict:
key, ok := index.(string);
if !ok {
error(p, index_pos, "Index must be a string for a dictionary");
operand = nil;
continue;
}
val, found := a[key];
if found {
operand = val;
} else {
error(p, index_pos, "`%s` was not found in the dictionary", key);
operand = nil;
continue;
}
case:
error(p, index_pos, "Indexing is only allowed on an array or dictionary");
}
case:
loop = false;
}
}
return operand, pos;
}
parse_unary_expr :: proc(p: ^Parser) -> (Value, Pos) {
op := p.curr_token;
switch p.curr_token.kind {
case Kind.At:
next_token(p);
tok := expect_token(p, Kind.String);
v, ok := lookup_value(p, tok.lit);
if !ok do error(p, tok.pos, "Undeclared identifier %s", tok.lit);
return parse_atom_expr(p, v, tok.pos);
case Kind.Add, Kind.Sub:
next_token(p);
// TODO(bill): Calcuate values as you go!
expr, pos := parse_unary_expr(p);
switch e in expr {
case i64: if op.kind == Kind.Sub do return -e, pos;
case f64: if op.kind == Kind.Sub do return -e, pos;
case:
error(p, op.pos, "Unary operator %s can only be used on integers or floats", op.lit);
return nil, op.pos;
}
return expr, op.pos;
case Kind.Not:
next_token(p);
expr, _ := parse_unary_expr(p);
if v, ok := expr.(bool); ok {
return !v, op.pos;
}
error(p, op.pos, "Unary operator %s can only be used on booleans", op.lit);
return nil, op.pos;
}
return parse_atom_expr(p, parse_operand(p));
}
value_order :: proc(v: Value) -> int {
switch _ in v {
case bool, string:
return 1;
case i64:
return 2;
case f64:
return 3;
}
return 0;
}
match_values :: proc(left, right: ^Value) -> bool {
if value_order(right^) < value_order(left^) {
return match_values(right, left);
}
switch x in left^ {
case:
right^ = left^;
case bool, string:
return true;
case i64:
switch y in right^ {
case i64:
return true;
case f64:
left^ = f64(x);
return true;
}
case f64:
switch y in right {
case f64:
return true;
}
}
return false;
}
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);
switch a in x {
case: return x, true;
case bool:
b, ok := y.(bool);
if !ok do return nil, false;
switch op {
case Kind.Eq: return a == b, true;
case Kind.NotEq: return a != b, true;
case Kind.And: return a && b, true;
case Kind.Or: return a || b, true;
}
case i64:
b, ok := y.(i64);
if !ok do return nil, false;
switch op {
case Kind.Add: return a + b, true;
case Kind.Sub: return a - b, true;
case Kind.Mul: return a * b, true;
case Kind.Quo: return a / b, true;
case Kind.Rem: return a % b, true;
case Kind.Eq: return a == b, true;
case Kind.NotEq: return a != b, true;
case Kind.Lt: return a < b, true;
case Kind.Gt: return a > b, true;
case Kind.LtEq: return a <= b, true;
case Kind.GtEq: return a >= b, true;
}
case f64:
b, ok := y.(f64);
if !ok do return nil, false;
switch op {
case Kind.Add: return a + b, true;
case Kind.Sub: return a - b, true;
case Kind.Mul: return a * b, true;
case Kind.Quo: return a / b, true;
case Kind.Eq: return a == b, true;
case Kind.NotEq: return a != b, true;
case Kind.Lt: return a < b, true;
case Kind.Gt: return a > b, true;
case Kind.LtEq: return a <= b, true;
case Kind.GtEq: return a >= b, true;
}
case string:
b, ok := y.(string);
if !ok do return nil, false;
switch op {
case Kind.Add:
n := len(a) + len(b);
data := make([]byte, n);
copy(data[:], cast([]byte)a);
copy(data[len(a):], cast([]byte)b);
s := string(data);
append(&p.allocated_strings, s);
return s, true;
case Kind.Eq: return a == b, true;
case Kind.NotEq: return a != b, true;
case Kind.Lt: return a < b, true;
case Kind.Gt: return a > b, true;
case Kind.LtEq: return a <= b, true;
case Kind.GtEq: return a >= b, true;
}
}
return nil, false;
}
parse_binary_expr :: proc(p: ^Parser, prec_in: int) -> (Value, Pos) {
expr, pos := parse_unary_expr(p);
for prec := precedence(p.curr_token.kind); prec >= prec_in; prec -= 1 {
for {
op := p.curr_token;
op_prec := precedence(op.kind);
if op_prec != prec {
break;
}
expect_operator(p);
if op.kind == Kind.Question {
cond := expr;
x, _ := parse_expr(p);
expect_token(p, Kind.Colon);
y, _ := parse_expr(p);
if t, ok := cond.(bool); ok {
expr = t ? x : y;
} else {
error(p, pos, "Condition must be a boolean");
}
} else {
right, right_pos := parse_binary_expr(p, prec+1);
if right == nil {
error(p, right_pos, "Expected expression on the right-hand side of the binary operator %s", op.lit);
}
left := expr;
ok: bool;
expr, ok = calculate_binary_value(p, op.kind, left, right);
if !ok {
error(p, pos, "Invalid binary operation");
}
}
}
}
return expr, pos;
}
parse_expr :: proc(p: ^Parser) -> (Value, Pos) {
return parse_binary_expr(p, 1);
}
expect_semicolon :: proc(p: ^Parser) {
kind := p.curr_token.kind;
switch kind {
case Kind.Comma:
error(p, p.curr_token.pos, "Expected ';', got ','");
next_token(p);
case Kind.Semicolon:
next_token(p);
case Kind.EOF:
// okay
case:
error(p, p.curr_token.pos, "Expected ';', got %s", p.curr_token.lit);
fix_advance(p);
}
}
parse_assignment :: proc(p: ^Parser) -> bool {
top_dict :: proc(p: ^Parser) -> ^Dict {
assert(len(p.dict_stack) > 0);
return p.dict_stack[len(p.dict_stack)-1];
}
if p.curr_token.kind == Kind.Semicolon {
next_token(p);
return true;
}
if p.curr_token.kind == Kind.EOF {
return false;
}
tok := p.curr_token;
if allow_token(p, Kind.Ident) || allow_token(p, Kind.String) {
expect_token(p, Kind.Assign);
name, ok := unquote_string(p, tok);
if !ok do error(p, tok.pos, "Unable to unquote string");
expr, _ := parse_expr(p);
d := top_dict(p);
if _, ok2 := d[name]; ok2 {
error(p, tok.pos, "Previous declaration of %s", name);
} else {
d[name] = expr;
}
expect_semicolon(p);
return true;
}
error(p, tok.pos, "Expected an assignment, got %s", kind_to_string[tok.kind]);
fix_advance(p);
return false;
}
+51
View File
@@ -0,0 +1,51 @@
/*
package cel
sample := `
x = 123;
y = 321.456;
z = x * (y - 1) / 2;
w = "foo" + "bar";
# This is a comment
asd = "Semicolons are optional"
a = {id = {b = 123}} # Dict
b = a.id.b
f = [1, 4, 9] # Array
g = f[2]
h = x < y and w == "foobar"
i = h ? 123 : "google"
j = nil
"127.0.0.1" = "value" # Keys can be strings
"foo" = {
"bar" = {
"baz" = 123, # optional commas if newline is present
"zab" = 456,
"abz" = 789,
},
};
bar = @"foo"["bar"].baz
`;
main :: proc() {
p, ok := create_from_string(sample);
if !ok {
return;
}
defer destroy(p);
if p.error_count == 0 {
print(p);
}
}
*/
package cel
+523
View File
@@ -0,0 +1,523 @@
package cel
import "core:fmt"
import "core:unicode/utf8"
using Kind :: enum {
Illegal,
EOF,
Comment,
_literal_start,
Ident,
Integer,
Float,
Char,
String,
_literal_end,
_keyword_start,
True, // true
False, // false
Nil, // nil
_keyword_end,
_operator_start,
Question, // ?
And, // and
Or, // or
Add, // +
Sub, // -
Mul, // *
Quo, // /
Rem, // %
Not, // !
Eq, // ==
NotEq, // !=
Lt, // <
Gt, // >
LtEq, // <=
GtEq, // >=
At, // @
_operator_end,
_punc_start,
Assign, // =
Open_Paren, // (
Close_Paren, // )
Open_Bracket, // [
Close_Bracket, // ]
Open_Brace, // {
Close_Brace, // }
Colon, // :
Semicolon, // ;
Comma, // ,
Period, // .
_punc_end,
}
Pos :: struct {
file: string,
line: int,
column: int,
}
Token :: struct {
kind: Kind,
using pos: Pos,
lit: string,
}
Tokenizer :: struct {
src: []byte,
file: string, // May not be used
curr_rune: rune,
offset: int,
read_offset: int,
line_offset: int,
line_count: int,
insert_semi: bool,
error_count: int,
}
keywords := map[string]Kind{
"true" = True,
"false" = False,
"nil" = Nil,
"and" = And,
"or" = Or,
};
kind_to_string := [len(Kind)]string{
"illegal",
"EOF",
"comment",
"",
"identifier",
"integer",
"float",
"character",
"string",
"",
"",
"true", "false", "nil",
"",
"",
"?", "and", "or",
"+", "-", "*", "/", "%",
"!",
"==", "!=", "<", ">", "<=", ">=",
"@",
"",
"",
"=",
"(", ")",
"[", "]",
"{", "}",
":", ";", ",", ".",
"",
};
precedence :: proc(op: Kind) -> int {
switch op {
case Question:
return 1;
case Or:
return 2;
case And:
return 3;
case Eq, NotEq, Lt, Gt, LtEq, GtEq:
return 4;
case Add, Sub:
return 5;
case Mul, Quo, Rem:
return 6;
}
return 0;
}
token_lookup :: proc(ident: string) -> Kind {
if tok, is_keyword := keywords[ident]; is_keyword {
return tok;
}
return Ident;
}
is_literal :: proc(tok: Kind) -> bool do return _literal_start < tok && tok < _literal_end;
is_operator :: proc(tok: Kind) -> bool do return _operator_start < tok && tok < _operator_end;
is_keyword :: proc(tok: Kind) -> bool do return _keyword_start < tok && tok < _keyword_end;
tokenizer_init :: proc(t: ^Tokenizer, src: []byte, file := "") {
t.src = src;
t.file = file;
t.curr_rune = ' ';
t.offset = 0;
t.read_offset = 0;
t.line_offset = 0;
t.line_count = 1;
advance_to_next_rune(t);
if t.curr_rune == utf8.RUNE_BOM {
advance_to_next_rune(t);
}
}
token_error :: proc(t: ^Tokenizer, msg: string, args: ..any) {
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;
}
advance_to_next_rune :: proc(t: ^Tokenizer) {
if t.read_offset < len(t.src) {
t.offset = t.read_offset;
if t.curr_rune == '\n' {
t.line_offset = t.offset;
t.line_count += 1;
}
r, w := rune(t.src[t.read_offset]), 1;
switch {
case r == 0:
token_error(t, "Illegal character NUL");
case r >= utf8.RUNE_SELF:
r, w = utf8.decode_rune(t.src[t.read_offset:]);
if r == utf8.RUNE_ERROR && w == 1 {
token_error(t, "Illegal utf-8 encoding");
} else if r == utf8.RUNE_BOM && t.offset > 0 {
token_error(t, "Illegal byte order mark");
}
}
t.read_offset += w;
t.curr_rune = r;
} else {
t.offset = len(t.src);
if t.curr_rune == '\n' {
t.line_offset = t.offset;
t.line_count += 1;
}
t.curr_rune = utf8.RUNE_EOF;
}
}
get_pos :: proc(t: ^Tokenizer) -> Pos {
return Pos {
file = t.file,
line = t.line_count,
column = t.offset - t.line_offset + 1,
};
}
is_letter :: proc(r: rune) -> bool {
switch r {
case 'a'..'z', 'A'..'Z', '_':
return true;
}
return false;
}
is_digit :: proc(r: rune) -> bool {
switch r {
case '0'..'9':
return true;
}
return false;
}
skip_whitespace :: proc(t: ^Tokenizer) {
loop: for {
switch t.curr_rune {
case '\n':
if t.insert_semi {
break loop;
}
fallthrough;
case ' ', '\t', '\r', '\v', '\f':
advance_to_next_rune(t);
case:
break loop;
}
}
}
scan_identifier :: proc(t: ^Tokenizer) -> string {
offset := t.offset;
for is_letter(t.curr_rune) || is_digit(t.curr_rune) {
advance_to_next_rune(t);
}
return string(t.src[offset : t.offset]);
}
digit_value :: proc(r: rune) -> int {
switch r {
case '0'..'9': return int(r - '0');
case 'a'..'f': return int(r - 'a' + 10);
case 'A'..'F': return int(r - 'A' + 10);
}
return 16;
}
scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
scan_mantissa :: proc(t: ^Tokenizer, base: int) {
for digit_value(t.curr_rune) < base || t.curr_rune == '_' {
advance_to_next_rune(t);
}
}
scan_exponent :: proc(t: ^Tokenizer, tok: Kind, offset: int) -> (kind: Kind, text: string) {
kind = tok;
if t.curr_rune == 'e' || t.curr_rune == 'E' {
kind = Float;
advance_to_next_rune(t);
if t.curr_rune == '-' || t.curr_rune == '+' {
advance_to_next_rune(t);
}
if digit_value(t.curr_rune) < 10 {
scan_mantissa(t, 10);
} else {
token_error(t, "Illegal floating point exponent");
}
}
text = string(t.src[offset : t.offset]);
return;
}
scan_fraction :: proc(t: ^Tokenizer, tok: Kind, offset: int) -> (kind: Kind, text: string) {
kind = tok;
if t.curr_rune == '.' {
kind = Float;
advance_to_next_rune(t);
scan_mantissa(t, 10);
}
return scan_exponent(t, kind, offset);
}
offset := t.offset;
tok := Integer;
if seen_decimal_point {
offset -= 1;
tok = Float;
scan_mantissa(t, 10);
return scan_exponent(t, tok, offset);
}
if t.curr_rune == '0' {
offset = t.offset;
advance_to_next_rune(t);
switch t.curr_rune {
case 'b', 'B':
advance_to_next_rune(t);
scan_mantissa(t, 2);
if t.offset - offset <= 2 {
token_error(t, "Illegal binary number");
}
case 'o', 'O':
advance_to_next_rune(t);
scan_mantissa(t, 8);
if t.offset - offset <= 2 {
token_error(t, "Illegal octal number");
}
case 'x', 'X':
advance_to_next_rune(t);
scan_mantissa(t, 16);
if t.offset - offset <= 2 {
token_error(t, "Illegal hexadecimal number");
}
case:
scan_mantissa(t, 10);
switch t.curr_rune {
case '.', 'e', 'E':
return scan_fraction(t, tok, offset);
}
}
return tok, string(t.src[offset:t.offset]);
}
scan_mantissa(t, 10);
return scan_fraction(t, tok, offset);
}
scan :: proc(t: ^Tokenizer) -> Token {
skip_whitespace(t);
offset := t.offset;
tok: Kind;
pos := get_pos(t);
lit: string;
insert_semi := false;
switch r := t.curr_rune; {
case is_letter(r):
insert_semi = true;
lit = scan_identifier(t);
tok = Ident;
if len(lit) > 1 {
tok = token_lookup(lit);
}
case '0' <= r && r <= '9':
insert_semi = true;
tok, lit = scan_number(t, false);
case:
advance_to_next_rune(t);
switch r {
case -1:
if t.insert_semi {
t.insert_semi = false;
return Token{Semicolon, pos, "\n"};
}
return Token{EOF, pos, "\n"};
case '\n':
t.insert_semi = false;
return Token{Semicolon, pos, "\n"};
case '"':
insert_semi = true;
quote := r;
tok = String;
for {
this_r := t.curr_rune;
if this_r == '\n' || r < 0 {
token_error(t, "String literal not terminated");
break;
}
advance_to_next_rune(t);
if this_r == quote {
break;
}
// TODO(bill); Handle properly
if this_r == '\\' && t.curr_rune == quote {
advance_to_next_rune(t);
}
}
lit = string(t.src[offset+1:t.offset-1]);
case '#':
for t.curr_rune != '\n' && t.curr_rune >= 0 {
advance_to_next_rune(t);
}
if t.insert_semi {
t.insert_semi = false;
return Token{Semicolon, pos, "\n"};
}
// Recursive!
return scan(t);
case '?': tok = Question;
case ':': tok = Colon;
case '@': tok = At;
case ';':
tok = Semicolon;
lit = ";";
case ',': tok = Comma;
case '(':
tok = Open_Paren;
case ')':
insert_semi = true;
tok = Close_Paren;
case '[':
tok = Open_Bracket;
case ']':
insert_semi = true;
tok = Close_Bracket;
case '{':
tok = Open_Brace;
case '}':
insert_semi = true;
tok = Close_Brace;
case '+': tok = Add;
case '-': tok = Sub;
case '*': tok = Mul;
case '/': tok = Quo;
case '%': tok = Rem;
case '!':
tok = Not;
if t.curr_rune == '=' {
advance_to_next_rune(t);
tok = NotEq;
}
case '=':
tok = Assign;
if t.curr_rune == '=' {
advance_to_next_rune(t);
tok = Eq;
}
case '<':
tok = Lt;
if t.curr_rune == '=' {
advance_to_next_rune(t);
tok = LtEq;
}
case '>':
tok = Gt;
if t.curr_rune == '=' {
advance_to_next_rune(t);
tok = GtEq;
}
case '.':
if '0' <= t.curr_rune && t.curr_rune <= '9' {
insert_semi = true;
tok, lit = scan_number(t, true);
} else {
tok = Period;
}
case:
if r != utf8.RUNE_BOM {
token_error(t, "Illegal character '%r'", r);
}
insert_semi = t.insert_semi;
tok = Illegal;
}
}
t.insert_semi = insert_semi;
if lit == "" {
lit = string(t.src[offset:t.offset]);
}
return Token{tok, pos, lit};
}
+330
View File
@@ -0,0 +1,330 @@
package json
import "core:mem"
import "core:math/bits"
import "core:runtime"
import "core:strconv"
import "core:strings"
import "core:reflect"
Marshal_Error :: enum {
None,
Unsupported_Type,
}
marshal :: proc(v: any, allocator := context.allocator) -> ([]byte, Marshal_Error) {
b := strings.make_builder(allocator);
err := marshal_arg(&b, v);
if err != Marshal_Error.None {
strings.destroy_builder(&b);
return nil, err;
}
if len(b.buf) == 0 {
strings.destroy_builder(&b);
return nil, err;
}
return b.buf[:], err;
}
marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
using strings;
using runtime;
if v == nil {
write_string(b, "null");
return Marshal_Error.None;
}
ti := type_info_base(type_info_of(v.id));
a := any{v.data, ti.id};
switch info in ti.variant {
case Type_Info_Named:
panic("Unreachable");
case Type_Info_Integer:
buf: [21]byte;
u: u64;
switch i in a {
case i8: u = u64(i);
case i16: u = u64(i);
case i32: u = u64(i);
case i64: u = u64(i);
case int: u = u64(i);
case u8: u = u64(i);
case u16: u = u64(i);
case u32: u = u64(i);
case u64: u = u64(i);
case uint: u = u64(i);
case uintptr: u = u64(i);
case i16le: u = u64(i);
case i32le: u = u64(i);
case i64le: u = u64(i);
case u16le: u = u64(i);
case u32le: u = u64(i);
case u64le: u = u64(i);
case i16be: u = u64(i);
case i32be: u = u64(i);
case i64be: u = u64(i);
case u16be: u = u64(i);
case u32be: u = u64(i);
case u64be: u = u64(i);
}
s := strconv.append_bits(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil);
write_string(b, s);
case Type_Info_Rune:
r := a.(rune);
write_byte(b, '"');
write_escaped_rune(b, r, '"', true);
write_byte(b, '"');
case Type_Info_Float:
val: f64;
switch f in a {
case f32: val = f64(f);
case f64: val = f64(f);
}
buf: [386]byte;
str := strconv.append_float(buf[1:], val, 'f', 2*ti.size, 8*ti.size);
str = string(buf[:len(str)+1]);
if str[1] == '+' || str[1] == '-' {
str = str[1:];
} else {
str[0] = '+';
}
if str[0] == '+' {
str = str[1:];
}
write_string(b, str);
case Type_Info_Complex:
return Marshal_Error.Unsupported_Type;
case Type_Info_String:
switch s in a {
case string: write_quoted_string(b, s);
case cstring: write_quoted_string(b, string(s));
}
case Type_Info_Boolean:
val: bool;
switch b in a {
case bool: val = bool(b);
case b8: val = bool(b);
case b16: val = bool(b);
case b32: val = bool(b);
case b64: val = bool(b);
}
write_string(b, val ? "true" : "false");
case Type_Info_Any:
return Marshal_Error.Unsupported_Type;
case Type_Info_Type_Id:
return Marshal_Error.Unsupported_Type;
case Type_Info_Pointer:
return Marshal_Error.Unsupported_Type;
case Type_Info_Procedure:
return Marshal_Error.Unsupported_Type;
case Type_Info_Tuple:
return Marshal_Error.Unsupported_Type;
case Type_Info_Array:
write_byte(b, '[');
for i in 0..<info.count {
if i > 0 do write_string(b, ", ");
data := uintptr(v.data) + uintptr(i*info.elem_size);
marshal_arg(b, any{rawptr(data), info.elem.id});
}
write_byte(b, ']');
case Type_Info_Dynamic_Array:
write_byte(b, '[');
array := cast(^mem.Raw_Dynamic_Array)v.data;
for i in 0..<array.len {
if i > 0 do write_string(b, ", ");
data := uintptr(array.data) + uintptr(i*info.elem_size);
marshal_arg(b, any{rawptr(data), info.elem.id});
}
write_byte(b, ']');
case Type_Info_Slice:
write_byte(b, '[');
slice := cast(^mem.Raw_Slice)v.data;
for i in 0..<slice.len {
if i > 0 do write_string(b, ", ");
data := uintptr(slice.data) + uintptr(i*info.elem_size);
marshal_arg(b, any{rawptr(data), info.elem.id});
}
write_byte(b, ']');
case Type_Info_Map:
m := (^mem.Raw_Map)(v.data);
write_byte(b, '{');
if m != nil {
if info.generated_struct == nil {
return Marshal_Error.Unsupported_Type;
}
entries := &m.entries;
gs := type_info_base(info.generated_struct).variant.(Type_Info_Struct);
ed := type_info_base(gs.types[1]).variant.(Type_Info_Dynamic_Array);
entry_type := ed.elem.variant.(Type_Info_Struct);
entry_size := ed.elem_size;
for i in 0..<entries.len {
if i > 0 do write_string(b, ", ");
data := uintptr(entries.data) + uintptr(i*entry_size);
header := cast(^Map_Entry_Header)data;
if reflect.is_string(info.key) {
marshal_arg(b, header.key.str);
} else {
marshal_arg(b, any{rawptr(&header.key.hash), info.key.id});
}
write_string(b, ": ");
value := data + entry_type.offsets[2];
marshal_arg(b, any{rawptr(value), info.value.id});
}
}
write_byte(b, '}');
case Type_Info_Struct:
write_byte(b, '{');
for name, i in info.names {
if i > 0 do write_string(b, ", ");
write_quoted_string(b, name);
write_string(b, ": ");
id := info.types[i].id;
data := rawptr(uintptr(v.data) + info.offsets[i]);
marshal_arg(b, any{data, id});
}
write_byte(b, '}');
case Type_Info_Union:
tag_ptr := uintptr(v.data) + info.tag_offset;
tag_any := any{rawptr(tag_ptr), info.tag_type.id};
tag: i64 = -1;
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: panic("Invalid union tag type");
}
if v.data == nil || tag == 0 {
write_string(b, "null");
} else {
id := info.variants[tag-1].id;
marshal_arg(b, any{v.data, id});
}
case Type_Info_Enum:
return marshal_arg(b, any{v.data, info.base.id});
case Type_Info_Bit_Field:
data: u64 = 0;
switch ti.size {
case 1: data = cast(u64) (^u8)(v.data)^;
case 2: data = cast(u64)(^u16)(v.data)^;
case 4: data = cast(u64)(^u32)(v.data)^;
case 8: data = cast(u64)(^u64)(v.data)^;
}
write_byte(b, '{');
for name, i in info.names {
if i > 0 do write_string(b, ", ");
bits := u64(info.bits[i]);
offset := u64(info.offsets[i]);
marshal_arg(b, name);
write_string(b, ": ");
n := 8*u64(size_of(u64));
sa := n - bits;
u := data>>offset;
u <<= sa;
u >>= sa;
write_u64(b, u, 10);
}
write_byte(b, '}');
case Type_Info_Bit_Set:
is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool {
if ti == nil {
return false;
}
t := runtime.type_info_base(ti);
switch info in t.variant {
case runtime.Type_Info_Integer:
switch info.endianness {
case .Platform: return false;
case .Little: return ODIN_ENDIAN != "little";
case .Big: return ODIN_ENDIAN != "big";
}
}
return false;
}
bit_data: u64;
bit_size := u64(8*ti.size);
do_byte_swap := is_bit_set_different_endian_to_platform(info.underlying);
switch bit_size {
case 0: bit_data = 0;
case 8:
x := (^u8)(v.data)^;
bit_data = u64(x);
case 16:
x := (^u16)(v.data)^;
if do_byte_swap do x = bits.byte_swap(x);
bit_data = u64(x);
case 32:
x := (^u32)(v.data)^;
if do_byte_swap do x = bits.byte_swap(x);
bit_data = u64(x);
case 64:
x := (^u64)(v.data)^;
if do_byte_swap do x = bits.byte_swap(x);
bit_data = u64(x);
case: panic("unknown bit_size size");
}
write_u64(b, bit_data);
return Marshal_Error.Unsupported_Type;
case Type_Info_Opaque:
return Marshal_Error.Unsupported_Type;
}
return Marshal_Error.None;
}
+455
View File
@@ -0,0 +1,455 @@
package json
import "core:mem"
import "core:unicode/utf8"
import "core:strconv"
Parser :: struct {
tok: Tokenizer,
prev_token: Token,
curr_token: Token,
spec: Specification,
allocator: mem.Allocator,
}
make_parser :: proc(data: []byte, spec := Specification.JSON, allocator := context.allocator) -> Parser {
p: Parser;
p.tok = make_tokenizer(data, spec);
p.spec = spec;
p.allocator = allocator;
assert(p.allocator.procedure != nil);
advance_token(&p);
return p;
}
parse :: proc(data: []byte, spec := Specification.JSON, allocator := context.allocator) -> (Value, Error) {
context.allocator = allocator;
p := make_parser(data, spec, allocator);
if p.spec == Specification.JSON5 {
return parse_value(&p);
}
return parse_object(&p);
}
token_end_pos :: proc(tok: Token) -> Pos {
end := tok.pos;
end.offset += len(tok.text);
return end;
}
advance_token :: proc(p: ^Parser) -> (Token, Error) {
err: Error;
p.prev_token = p.curr_token;
p.curr_token, err = get_token(&p.tok);
return p.prev_token, err;
}
allow_token :: proc(p: ^Parser, kind: Kind) -> bool {
if p.curr_token.kind == kind {
advance_token(p);
return true;
}
return false;
}
expect_token :: proc(p: ^Parser, kind: Kind) -> Error {
prev := p.curr_token;
advance_token(p);
if prev.kind == kind {
return Error.None;
}
return Error.Unexpected_Token;
}
parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) {
value.pos = p.curr_token.pos;
defer value.end = token_end_pos(p.prev_token);
token := p.curr_token;
switch token.kind {
case Kind.Null:
value.value = Null{};
advance_token(p);
return;
case Kind.False:
value.value = Boolean(false);
advance_token(p);
return;
case Kind.True:
value.value = Boolean(true);
advance_token(p);
return;
case Kind.Integer:
value.value = Integer(strconv.parse_i64(token.text));
advance_token(p);
return;
case Kind.Float:
value.value = Float(strconv.parse_f64(token.text));
advance_token(p);
return;
case Kind.String:
value.value = String(unquote_string(token, p.spec, p.allocator));
advance_token(p);
return;
case Kind.Open_Brace:
return parse_object(p);
case Kind.Open_Bracket:
return parse_array(p);
case:
if p.spec == Specification.JSON5 {
switch token.kind {
case Kind.Infinity:
inf: u64 = 0x7ff0000000000000;
if token.text[0] == '-' {
inf = 0xfff0000000000000;
}
value.value = transmute(f64)inf;
advance_token(p);
return;
case Kind.NaN:
nan: u64 = 0x7ff7ffffffffffff;
if token.text[0] == '-' {
nan = 0xfff7ffffffffffff;
}
value.value = transmute(f64)nan;
advance_token(p);
return;
}
}
}
err = Error.Unexpected_Token;
advance_token(p);
return;
}
parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
value.pos = p.curr_token.pos;
defer value.end = token_end_pos(p.prev_token);
if err = expect_token(p, Kind.Open_Bracket); err != Error.None {
return;
}
array: Array;
array.allocator = p.allocator;
defer if err != Error.None {
for elem in array {
destroy_value(elem);
}
delete(array);
}
for p.curr_token.kind != Kind.Close_Bracket {
elem, elem_err := parse_value(p);
if elem_err != Error.None {
err = elem_err;
return;
}
append(&array, elem);
// Disallow trailing commas for the time being
if allow_token(p, Kind.Comma) {
continue;
} else {
break;
}
}
if err = expect_token(p, Kind.Close_Bracket); err != Error.None {
return;
}
value.value = array;
return;
}
clone_string :: proc(s: string, allocator: mem.Allocator) -> string {
n := len(s);
b := make([]byte, n+1, allocator);
copy(b, cast([]byte)s);
b[n] = 0;
return string(b[:n]);
}
parse_object_key :: proc(p: ^Parser) -> (key: string, err: Error) {
tok := p.curr_token;
if p.spec == Specification.JSON5 {
if tok.kind == Kind.String {
expect_token(p, Kind.String);
key = unquote_string(tok, p.spec, p.allocator);
return;
} else if tok.kind == Kind.Ident {
expect_token(p, Kind.Ident);
key = clone_string(tok.text, p.allocator);
return;
}
}
if tok_err := expect_token(p, Kind.String); tok_err != Error.None {
err = Error.Expected_String_For_Object_Key;
return;
}
key = unquote_string(tok, p.spec, p.allocator);
return;
}
parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) {
value.pos = p.curr_token.pos;
defer value.end = token_end_pos(p.prev_token);
if err = expect_token(p, Kind.Open_Brace); err != Error.None {
value.pos = p.curr_token.pos;
return;
}
obj: Object;
obj.allocator = p.allocator;
defer if err != Error.None {
for key, elem in obj {
delete(key, p.allocator);
destroy_value(elem);
}
delete(obj);
}
for p.curr_token.kind != Kind.Close_Brace {
key: string;
key, err = parse_object_key(p);
if err != Error.None {
delete(key, p.allocator);
value.pos = p.curr_token.pos;
return;
}
if colon_err := expect_token(p, Kind.Colon); colon_err != Error.None {
err = Error.Expected_Colon_After_Key;
value.pos = p.curr_token.pos;
return;
}
elem, elem_err := parse_value(p);
if elem_err != Error.None {
err = elem_err;
value.pos = p.curr_token.pos;
return;
}
if key in obj {
err = Error.Duplicate_Object_Key;
value.pos = p.curr_token.pos;
delete(key, p.allocator);
return;
}
obj[key] = elem;
if p.spec == Specification.JSON5 {
// Allow trailing commas
if allow_token(p, Kind.Comma) {
continue;
}
} else {
// Disallow trailing commas
if allow_token(p, Kind.Comma) {
continue;
} else {
break;
}
}
}
if err = expect_token(p, Kind.Close_Brace); err != Error.None {
value.pos = p.curr_token.pos;
return;
}
value.value = obj;
return;
}
// IMPORTANT NOTE(bill): unquote_string assumes a mostly valid string
unquote_string :: proc(token: Token, spec: Specification, allocator := context.allocator) -> string {
get_u2_rune :: proc(s: string) -> rune {
if len(s) < 4 || s[0] != '\\' || s[1] != 'x' {
return -1;
}
r: rune;
for c in s[2:4] {
x: rune;
switch c {
case '0'..'9': x = c - '0';
case 'a'..'f': x = c - 'a' + 10;
case 'A'..'F': x = c - 'A' + 10;
case: return -1;
}
r = r*16 + x;
}
return r;
}
get_u4_rune :: proc(s: string) -> rune {
if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
return -1;
}
r: rune;
for c in s[2:6] {
x: rune;
switch c {
case '0'..'9': x = c - '0';
case 'a'..'f': x = c - 'a' + 10;
case 'A'..'F': x = c - 'A' + 10;
case: return -1;
}
r = r*16 + x;
}
return r;
}
if token.kind != Kind.String {
return "";
}
s := token.text;
if len(s) <= 2 {
return "";
}
quote := s[0];
if s[0] != s[len(s)-1] {
// Invalid string
return "";
}
s = s[1:len(s)-1];
i := 0;
for i < len(s) {
c := s[i];
if c == '\\' || c == quote || c < ' ' {
break;
}
if c < utf8.RUNE_SELF {
i += 1;
continue;
}
r, w := utf8.decode_rune_in_string(s);
if r == utf8.RUNE_ERROR && w == 1 {
break;
}
i += w;
}
if i == len(s) {
return clone_string(s, allocator);
}
b := make([]byte, len(s) + 2*utf8.UTF_MAX, allocator);
w := copy(b, cast([]byte)s[0:i]);
loop: for i < len(s) {
c := s[i];
switch {
case c == '\\':
i += 1;
if i >= len(s) {
break loop;
}
switch s[i] {
case: break loop;
case '"', '\'', '\\', '/':
b[w] = s[i];
i += 1;
w += 1;
case 'b':
b[w] = '\b';
i += 1;
w += 1;
case 'f':
b[w] = '\f';
i += 1;
w += 1;
case 'r':
b[w] = '\r';
i += 1;
w += 1;
case 't':
b[w] = '\t';
i += 1;
w += 1;
case 'n':
b[w] = '\n';
i += 1;
w += 1;
case 'u':
i -= 1; // Include the \u in the check for sanity sake
r := get_u4_rune(s[i:]);
if r < 0 {
break loop;
}
i += 6;
buf, buf_width := utf8.encode_rune(r);
copy(b[w:], buf[:buf_width]);
w += buf_width;
case '0':
if spec == Specification.JSON5 {
b[w] = '\x00';
i += 1;
w += 1;
} else {
break loop;
}
case 'v':
if spec == Specification.JSON5 {
b[w] = '\v';
i += 1;
w += 1;
} else {
break loop;
}
case 'x':
if spec == Specification.JSON5 {
i -= 1; // Include the \x in the check for sanity sake
r := get_u2_rune(s[i:]);
if r < 0 {
break loop;
}
i += 4;
buf, buf_width := utf8.encode_rune(r);
copy(b[w:], buf[:buf_width]);
w += buf_width;
} else {
break loop;
}
}
case c == quote, c < ' ':
break loop;
case c < utf8.RUNE_SELF:
b[w] = c;
i += 1;
w += 1;
case:
r, width := utf8.decode_rune_in_string(s[i:]);
i += width;
buf, buf_width := utf8.encode_rune(r);
assert(buf_width <= width);
copy(b[w:], buf[:buf_width]);
w += buf_width;
}
}
return string(b[:w]);
}
+473
View File
@@ -0,0 +1,473 @@
package json
import "core:unicode/utf8"
Token :: struct {
using pos: Pos,
kind: Kind,
text: string,
}
Kind :: enum {
Invalid,
Null,
False,
True,
Infinity,
NaN,
Ident,
Integer,
Float,
String,
Colon,
Comma,
Open_Brace,
Close_Brace,
Open_Bracket,
Close_Bracket,
}
Tokenizer :: struct {
using pos: Pos,
data: []byte,
r: rune, // current rune
w: int, // current rune width in bytes
curr_line_offset: int,
spec: Specification,
}
make_tokenizer :: proc(data: []byte, spec := Specification.JSON) -> Tokenizer {
t := Tokenizer{pos = {line=1}, data = data, spec = spec};
next_rune(&t);
if t.r == utf8.RUNE_BOM {
next_rune(&t);
}
return t;
}
next_rune :: proc(t: ^Tokenizer) -> rune #no_bounds_check {
if t.offset >= len(t.data) {
return utf8.RUNE_EOF;
}
t.offset += t.w;
t.r, t.w = utf8.decode_rune(t.data[t.offset:]);
t.pos.column = t.offset - t.curr_line_offset;
return t.r;
}
get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
skip_digits :: proc(t: ^Tokenizer) {
for t.offset < len(t.data) {
if '0' <= t.r && t.r <= '9' {
// Okay
} else {
return;
}
next_rune(t);
}
}
skip_hex_digits :: proc(t: ^Tokenizer) {
for t.offset < len(t.data) {
next_rune(t);
switch t.r {
case '0'..'9', 'a'..'f', 'A'..'F':
// Okay
case:
return;
}
}
}
scan_espace :: proc(t: ^Tokenizer) -> bool {
switch t.r {
case '"', '\'', '\\', '/', 'b', 'n', 'r', 't', 'f':
next_rune(t);
return true;
case 'u':
// Expect 4 hexadecimal digits
for i := 0; i < 4; i += 1 {
r := next_rune(t);
switch r {
case '0'..'9', 'a'..'f', 'A'..'F':
// Okay
case:
return false;
}
}
case:
// Ignore the next rune regardless
next_rune(t);
}
return false;
}
skip_whitespace :: proc(t: ^Tokenizer) -> rune {
loop: for t.offset < len(t.data) {
switch t.r {
case ' ', '\t', '\v', '\f', '\r':
next_rune(t);
case '\n':
t.line += 1;
t.curr_line_offset = t.offset;
t.pos.column = 1;
next_rune(t);
case:
if t.spec == Specification.JSON5 {
switch t.r {
case 0x2028, 0x2029, 0xFEFF:
next_rune(t);
continue loop;
}
}
break loop;
}
}
return t.r;
}
skip_to_next_line :: proc(t: ^Tokenizer) {
for t.offset < len(t.data) {
r := next_rune(t);
if r == '\n' {
return;
}
}
}
skip_alphanum :: proc(t: ^Tokenizer) {
for t.offset < len(t.data) {
switch next_rune(t) {
case 'A'..'Z', 'a'..'z', '0'..'9', '_':
continue;
}
return;
}
}
skip_whitespace(t);
token.pos = t.pos;
token.kind = Kind.Invalid;
curr_rune := t.r;
next_rune(t);
block: switch curr_rune {
case utf8.RUNE_ERROR:
err = Error.Illegal_Character;
case utf8.RUNE_EOF, '\x00':
err = Error.EOF;
case 'A'..'Z', 'a'..'z', '_':
token.kind = Kind.Ident;
skip_alphanum(t);
switch str := string(t.data[token.offset:t.offset]); str {
case "null": token.kind = Kind.Null;
case "false": token.kind = Kind.False;
case "true": token.kind = Kind.True;
case:
if t.spec == Specification.JSON5 do switch str {
case "Infinity": token.kind = Kind.Infinity;
case "NaN": token.kind = Kind.NaN;
}
}
case '+':
err = Error.Illegal_Character;
if t.spec != Specification.JSON5 {
break;
}
fallthrough;
case '-':
switch t.r {
case '0'..'9':
// Okay
case:
// Illegal use of +/-
err = Error.Illegal_Character;
if t.spec == Specification.JSON5 {
if t.r == 'I' || t.r == 'N' {
skip_alphanum(t);
}
switch string(t.data[token.offset:t.offset]) {
case "-Infinity": token.kind = Kind.Infinity;
case "-NaN": token.kind = Kind.NaN;
}
}
break block;
}
fallthrough;
case '0'..'9':
token.kind = Kind.Integer;
if t.spec == Specification.JSON5 { // Hexadecimal Numbers
if curr_rune == '0' && (t.r == 'x' || t.r == 'X') {
next_rune(t);
skip_hex_digits(t);
break;
}
}
skip_digits(t);
if t.r == '.' {
token.kind = Kind.Float;
next_rune(t);
skip_digits(t);
}
if t.r == 'e' || t.r == 'E' {
switch r := next_rune(t); r {
case '+', '-':
next_rune(t);
}
skip_digits(t);
}
str := string(t.data[token.offset:t.offset]);
if !is_valid_number(str, t.spec) {
err = Error.Invalid_Number;
}
case '.':
err = Error.Illegal_Character;
if t.spec == Specification.JSON5 { // Allow leading decimal point
skip_digits(t);
if t.r == 'e' || t.r == 'E' {
switch r := next_rune(t); r {
case '+', '-':
next_rune(t);
}
skip_digits(t);
}
str := string(t.data[token.offset:t.offset]);
if !is_valid_number(str, t.spec) {
err = Error.Invalid_Number;
}
}
case '\'':
err = Error.Illegal_Character;
if t.spec != Specification.JSON5 {
break;
}
fallthrough;
case '"':
token.kind = Kind.String;
quote := curr_rune;
for t.offset < len(t.data) {
r := t.r;
if r == '\n' || r < 0 {
err = Error.String_Not_Terminated;
break;
}
next_rune(t);
if r == quote {
break;
}
if r == '\\' {
scan_espace(t);
}
}
str := string(t.data[token.offset : t.offset]);
if !is_valid_string_literal(str, t.spec) {
err = Error.Invalid_String;
}
case ',': token.kind = Kind.Comma;
case ':': token.kind = Kind.Colon;
case '{': token.kind = Kind.Open_Brace;
case '}': token.kind = Kind.Close_Brace;
case '[': token.kind = Kind.Open_Bracket;
case ']': token.kind = Kind.Close_Bracket;
case '/':
err = Error.Illegal_Character;
if t.spec == Specification.JSON5 {
switch t.r {
case '/':
// Single-line comments
skip_to_next_line(t);
return get_token(t);
case '*':
// None-nested multi-line comments
for t.offset < len(t.data) {
next_rune(t);
if t.r == '*' {
next_rune(t);
if t.r == '/' {
next_rune(t);
return get_token(t);
}
}
}
err = Error.EOF;
}
}
case: err = Error.Illegal_Character;
}
token.text = string(t.data[token.offset : t.offset]);
return;
}
is_valid_number :: proc(str: string, spec: Specification) -> bool {
s := str;
if s == "" {
return false;
}
if s[0] == '-' {
s = s[1:];
if s == "" {
return false;
}
} else if spec == Specification.JSON5 {
if s[0] == '+' { // Allow positive sign
s = s[1:];
if s == "" {
return false;
}
}
}
switch s[0] {
case '0':
s = s[1:];
case '1'..'9':
s = s[1:];
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' do s = s[1:];
case '.':
if spec == Specification.JSON5 { // Allow leading decimal point
s = s[1:];
} else {
return false;
}
case:
return false;
}
if spec == Specification.JSON5 {
if len(s) == 1 && s[0] == '.' { // Allow trailing decimal point
return true;
}
}
if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
s = s[2:];
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' do s = s[1:];
}
if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
s = s[1:];
switch s[0] {
case '+', '-':
s = s[1:];
if s == "" {
return false;
}
}
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' do s = s[1:];
}
// The string should be empty now to be valid
return s == "";
}
is_valid_string_literal :: proc(str: string, spec: Specification) -> bool {
s := str;
if len(s) < 2 {
return false;
}
quote := s[0];
if s[0] != s[len(s)-1] {
return false;
}
if s[0] != '"' || s[len(s)-1] != '"' {
if spec == Specification.JSON5 {
if s[0] != '\'' || s[len(s)-1] != '\'' {
return false;
}
} else {
return false;
}
}
s = s[1 : len(s)-1];
i := 0;
for i < len(s) {
c := s[i];
switch {
case c == '\\':
i += 1;
if i >= len(s) {
return false;
}
switch s[i] {
case '"', '\'', '\\', '/', 'b', 'n', 'r', 't', 'f':
i += 1;
case 'u':
if i >= len(s) {
return false;
}
hex := s[i+1:];
if len(hex) < 4 {
return false;
}
hex = hex[:4];
i += 5;
for j := 0; j < 4; j += 1 {
c2 := hex[j];
switch c2 {
case '0'..'9', 'a'..'z', 'A'..'Z':
// Okay
case:
return false;
}
}
case: return false;
}
case c == quote, c < ' ':
return false;
case c < utf8.RUNE_SELF:
i += 1;
case:
r, width := utf8.decode_rune_in_string(s[i:]);
if r == utf8.RUNE_ERROR && width == 1 {
return false;
}
i += width;
}
}
if i == len(s) {
return true;
}
return true;
}
+73
View File
@@ -0,0 +1,73 @@
package json
Specification :: enum {
JSON,
JSON5,
}
Null :: distinct rawptr;
Integer :: i64;
Float :: f64;
Boolean :: bool;
String :: string;
Array :: distinct [dynamic]Value;
Object :: distinct map[string]Value;
Value :: struct {
pos, end: Pos,
value: union {
Null,
Integer,
Float,
Boolean,
String,
Array,
Object,
}
}
Pos :: struct {
offset: int,
line: int,
column: int,
}
Error :: enum {
None,
EOF, // Not necessarily an error
// Tokenizing Errors
Illegal_Character,
Invalid_Number,
String_Not_Terminated,
Invalid_String,
// Parsing Errors
Unexpected_Token,
Expected_String_For_Object_Key,
Duplicate_Object_Key,
Expected_Colon_After_Key,
}
destroy_value :: proc(value: Value) {
switch v in value.value {
case Object:
for key, elem in v {
delete(key);
destroy_value(elem);
}
delete(v);
case Array:
for elem in v do destroy_value(elem);
delete(v);
case String:
delete(v);
}
}
+123
View File
@@ -0,0 +1,123 @@
package json
import "core:mem"
// NOTE(bill): is_valid will not check for duplicate keys
is_valid :: proc(data: []byte, spec := Specification.JSON) -> bool {
p := make_parser(data, spec, mem.nil_allocator());
if p.spec == Specification.JSON5 {
return validate_value(&p);
}
return validate_object(&p);
}
validate_object_key :: proc(p: ^Parser) -> bool {
tok := p.curr_token;
if p.spec == Specification.JSON5 {
if tok.kind == Kind.String {
expect_token(p, Kind.String);
return true;
} else if tok.kind == Kind.Ident {
expect_token(p, Kind.Ident);
return true;
}
}
err := expect_token(p, Kind.String);
return err == Error.None;
}
validate_object :: proc(p: ^Parser) -> bool {
if err := expect_token(p, Kind.Open_Brace); err != Error.None {
return false;
}
for p.curr_token.kind != Kind.Close_Brace {
if !validate_object_key(p) {
return false;
}
if colon_err := expect_token(p, Kind.Colon); colon_err != Error.None {
return false;
}
if !validate_value(p) {
return false;
}
if p.spec == Specification.JSON5 {
// Allow trailing commas
if allow_token(p, Kind.Comma) {
continue;
}
} else {
// Disallow trailing commas
if allow_token(p, Kind.Comma) {
continue;
} else {
break;
}
}
}
if err := expect_token(p, Kind.Close_Brace); err != Error.None {
return false;
}
return true;
}
validate_array :: proc(p: ^Parser) -> bool {
if err := expect_token(p, Kind.Open_Bracket); err != Error.None {
return false;
}
for p.curr_token.kind != Kind.Close_Bracket {
if !validate_value(p) {
return false;
}
// Disallow trailing commas for the time being
if allow_token(p, Kind.Comma) {
continue;
} else {
break;
}
}
if err := expect_token(p, Kind.Close_Bracket); err != Error.None {
return false;
}
return true;
}
validate_value :: proc(p: ^Parser) -> bool {
token := p.curr_token;
using Kind;
switch token.kind {
case Null, False, True:
advance_token(p);
return true;
case Integer, Float:
advance_token(p);
return true;
case String:
advance_token(p);
return is_valid_string_literal(token.text, p.spec);
case Open_Brace:
return validate_object(p);
case Open_Bracket:
return validate_array(p);
case:
if p.spec == Specification.JSON5 {
switch token.kind {
case Infinity, NaN:
advance_token(p);
return true;
}
}
}
return false;
}
-1172
View File
File diff suppressed because it is too large Load Diff
+1611
View File
File diff suppressed because it is too large Load Diff
+62 -58
View File
@@ -1,65 +1,75 @@
proc crc32(data: []u8) -> u32 {
var result = ~u32(0);
package hash
import "core:mem"
adler32 :: proc(data: []byte) -> u32 {
ADLER_CONST :: 65521;
a, b: u32 = 1, 0;
for x in data {
a = (a + u32(x)) % ADLER_CONST;
b = (b + a) % ADLER_CONST;
}
return (b << 16) | a;
}
crc32 :: proc(data: []byte) -> u32 {
result := ~u32(0);
for b in data {
result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff];
}
return ~result;
}
proc crc64(data: []u8) -> u64 {
var result = ~u64(0);
crc64 :: proc(data: []byte) -> u64 {
result := ~u64(0);
for b in data {
result = result>>8 ~ _crc64_table[(result ~ u64(b)) & 0xff];
}
return ~result;
}
proc fnv32(data: []u8) -> u32 {
var h: u32 = 0x811c9dc5;
fnv32 :: proc(data: []byte) -> u32 {
h: u32 = 0x811c9dc5;
for b in data {
h = (h * 0x01000193) ~ u32(b);
}
return h;
}
proc fnv64(data: []u8) -> u64 {
var h: u64 = 0xcbf29ce484222325;
fnv64 :: proc(data: []byte) -> u64 {
h: u64 = 0xcbf29ce484222325;
for b in data {
h = (h * 0x100000001b3) ~ u64(b);
}
return h;
}
proc fnv32a(data: []u8) -> u32 {
var h: u32 = 0x811c9dc5;
fnv32a :: proc(data: []byte) -> u32 {
h: u32 = 0x811c9dc5;
for b in data {
h = (h ~ u32(b)) * 0x01000193;
}
return h;
}
proc fnv64a(data: []u8) -> u64 {
var h: u64 = 0xcbf29ce484222325;
fnv64a :: proc(data: []byte) -> u64 {
h: u64 = 0xcbf29ce484222325;
for b in data {
h = (h ~ u64(b)) * 0x100000001b3;
}
return h;
}
proc murmur32(data: []u8) -> u32 {
const (
c1_32: u32 = 0xcc9e2d51;
c2_32: u32 = 0x1b873593;
)
murmur32 :: proc(data: []byte) -> u32 {
c1_32: u32 : 0xcc9e2d51;
c2_32: u32 : 0x1b873593;
var (
h1: u32 = 0;
nblocks = len(data)/4;
p = &data[0];
p1 = p + 4*nblocks;
)
h1: u32 = 0;
nblocks := len(data)/4;
p := &data[0];
p1 := mem.ptr_offset(p, 4*nblocks);
for ; p < p1; p += 4 {
var k1 = ^u32(p)^;
for ; p < p1; p = mem.ptr_offset(p, 4) {
k1 := (cast(^u32)p)^;
k1 *= c1_32;
k1 = (k1 << 15) | (k1 >> 17);
@@ -70,9 +80,9 @@ proc murmur32(data: []u8) -> u32 {
h1 = h1*5 + 0xe6546b64;
}
var tail = data[nblocks*4 ..];
var k1: u32;
match len(tail)&3 {
tail := data[nblocks*4:];
k1: u32;
switch len(tail)&3 {
case 3:
k1 ~= u32(tail[2]) << 16;
fallthrough;
@@ -98,20 +108,18 @@ proc murmur32(data: []u8) -> u32 {
return h1;
}
proc murmur64(data: []u8) -> u64 {
const SEED = 0x9747b28c;
murmur64 :: proc(data: []byte) -> u64 {
SEED :: 0x9747b28c;
when size_of(int) == 8 {
const (
m = 0xc6a4a7935bd1e995;
r = 47;
)
m :: 0xc6a4a7935bd1e995;
r :: 47;
var h: u64 = SEED ~ (u64(len(data)) * m);
var data64 = slice_ptr(^u64(&data[0]), len(data)/size_of(u64));
h: u64 = SEED ~ (u64(len(data)) * m);
data64 := mem.slice_ptr(cast(^u64)&data[0], len(data)/size_of(u64));
for _, i in data64 {
var k = data64[i];
k := data64[i];
k *= m;
k ~= k>>r;
@@ -121,7 +129,7 @@ proc murmur64(data: []u8) -> u64 {
h *= m;
}
match len(data)&7 {
switch len(data)&7 {
case 7: h ~= u64(data[6]) << 48; fallthrough;
case 6: h ~= u64(data[5]) << 40; fallthrough;
case 5: h ~= u64(data[4]) << 32; fallthrough;
@@ -139,22 +147,18 @@ proc murmur64(data: []u8) -> u64 {
return h;
} else {
const (
m = 0x5bd1e995;
r = 24;
)
m :: 0x5bd1e995;
r :: 24;
var (
h1 = u32(SEED) ~ u32(len(data));
h2 = u32(SEED) >> 32;
data32 = slice_ptr(^u32(&data[0]), len(data)/size_of(u32));
len = len(data);
i = 0;
)
h1 := u32(SEED) ~ u32(len(data));
h2 := u32(SEED) >> 32;
data32 := mem.slice_ptr(cast(^u32)&data[0], len(data)/size_of(u32));
len := len(data);
i := 0;
for len >= 8 {
var k1, k2: u32;
k1 = data32[i]; i++;
k1, k2: u32;
k1 = data32[i]; i += 1;
k1 *= m;
k1 ~= k1>>r;
k1 *= m;
@@ -162,7 +166,7 @@ proc murmur64(data: []u8) -> u64 {
h1 ~= k1;
len -= 4;
k2 = data32[i]; i++;
k2 = data32[i]; i += 1;
k2 *= m;
k2 ~= k2>>r;
k2 *= m;
@@ -172,8 +176,8 @@ proc murmur64(data: []u8) -> u64 {
}
if len >= 4 {
var k1: u32;
k1 = data32[i]; i++;
k1: u32;
k1 = data32[i]; i += 1;
k1 *= m;
k1 ~= k1>>r;
k1 *= m;
@@ -183,8 +187,8 @@ proc murmur64(data: []u8) -> u64 {
}
// TODO(bill): Fix this
#no_bounds_check var data8 = slice_to_bytes(data32[i..])[0..<3];
match len {
#no_bounds_check data8 := mem.slice_to_bytes(data32[i:])[:3];
switch len {
case 3:
h2 ~= u32(data8[2]) << 16;
fallthrough;
@@ -210,7 +214,7 @@ proc murmur64(data: []u8) -> u64 {
}
var _crc32_table = [256]u32{
_crc32_table := [256]u32{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -276,7 +280,7 @@ var _crc32_table = [256]u32{
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
var _crc64_table = [256]u64{
_crc64_table := [256]u64{
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
+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) ---
+143
View File
@@ -0,0 +1,143 @@
package log
import "core:fmt";
import "core:strings";
import "core:os";
import "core:time";
Level_Headers := []string{
"[DEBUG] --- ",
"[INFO ] --- ",
"[WARN ] --- ",
"[ERROR] --- ",
"[FATAL] --- ",
};
Default_Console_Logger_Opts :: Options{
.Level,
.Terminal_Color,
.Short_File_Path,
.Line,
.Procedure,
} | Full_Timestamp_Opts;
Default_File_Logger_Opts :: Options{
.Level,
.Short_File_Path,
.Line,
.Procedure,
} | Full_Timestamp_Opts;
File_Console_Logger_Data :: struct {
lowest_level: Level,
file_handle: os.Handle,
ident : string,
}
create_file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "") -> Logger {
data := new(File_Console_Logger_Data);
data.lowest_level = lowest;
data.file_handle = h;
data.ident = ident;
return Logger{file_console_logger_proc, data, opt};
}
destroy_file_logger ::proc(log : ^Logger) {
data := cast(^File_Console_Logger_Data)log.data;
if data.file_handle != os.INVALID_HANDLE do os.close(data.file_handle);
free(data);
log^ = nil_logger();
}
create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "") -> Logger {
data := new(File_Console_Logger_Data);
data.lowest_level = lowest;
data.file_handle = os.INVALID_HANDLE;
data.ident = ident;
return Logger{file_console_logger_proc, data, opt};
}
destroy_console_logger ::proc(log : ^Logger) {
free(log.data);
log^ = nil_logger();
}
file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
data := cast(^File_Console_Logger_Data)logger_data;
if level < data.lowest_level do return;
h : os.Handle;
if(data.file_handle != os.INVALID_HANDLE) do h = data.file_handle;
else do h = level <= Level.Error ? context.stdout : context.stderr;
backing: [1024]byte; //NOTE(Hoej): 1024 might be too much for a header backing, unless somebody has really long paths.
buf := strings.builder_from_slice(backing[:]);
do_level_header(options, level, &buf);
when time.IS_SUPPORTED {
if Full_Timestamp_Opts & options != nil {
fmt.sbprint(&buf, "[");
t := time.now();
y, m, d := time.date(t);
h, min, s := time.clock(t);
if Option.Date in options do fmt.sbprintf(&buf, "%d-%02d-%02d ", y, m, d);
if Option.Time in options do fmt.sbprintf(&buf, "%02d:%02d:%02d", h, min, s);
fmt.sbprint(&buf, "] ");
}
}
do_location_header(options, &buf, location);
if data.ident != "" do fmt.sbprintf(&buf, "[%s] ", data.ident);
//TODO(Hoej): When we have better atomics and such, make this thread-safe
fmt.fprintf(h, "%s %s\n", strings.to_string(buf), text);
}
do_level_header :: proc(opts : Options, level : Level, str : ^strings.Builder) {
RESET :: "\x1b[0m";
RED :: "\x1b[31m";
YELLOW :: "\x1b[33m";
DARK_GREY :: "\x1b[90m";
col := RESET;
switch level {
case Level.Debug : col = DARK_GREY;
case Level.Info : col = RESET;
case Level.Warning : col = YELLOW;
case Level.Error, Level.Fatal : col = RED;
}
if .Level in opts {
if .Terminal_Color in opts do fmt.sbprint(str, col);
fmt.sbprint(str, Level_Headers[level]);
if .Terminal_Color in opts do fmt.sbprint(str, RESET);
}
}
do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := #caller_location) {
if Location_Header_Opts & opts != nil do fmt.sbprint(buf, "["); else do return;
file := location.file_path;
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;
file = location.file_path[last:];
}
if Location_File_Opts & opts != nil do fmt.sbprint(buf, file);
if .Procedure in opts {
if Location_File_Opts & opts != nil do fmt.sbprint(buf, ".");
fmt.sbprintf(buf, "%s()", location.procedure);
}
if .Line in opts {
if Location_File_Opts & opts != nil || .Procedure in opts do fmt.sbprint(buf, ":");
fmt.sbprint(buf, location.line);
}
fmt.sbprint(buf, "] ");
}
+94
View File
@@ -0,0 +1,94 @@
package log
import "core:fmt"
Level :: enum {
Debug,
Info,
Warning,
Error,
Fatal,
}
Option :: enum {
Level,
Date,
Time,
Short_File_Path,
Long_File_Path,
Line,
Procedure,
Terminal_Color
}
Options :: bit_set[Option];
Full_Timestamp_Opts :: Options{
.Date,
.Time
};
Location_Header_Opts :: Options{
.Short_File_Path,
.Long_File_Path,
.Line,
.Procedure,
};
Location_File_Opts :: Options{
.Short_File_Path,
.Long_File_Path
};
Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
Logger :: struct {
procedure: Logger_Proc,
data: rawptr,
options: Options,
}
Multi_Logger_Data :: struct {
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};
}
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 {
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) {
// Do nothing
}
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);
error :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Error, fmt_str=fmt_str, args=args, location=location);
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);
}
-396
View File
@@ -1,396 +0,0 @@
const (
TAU = 6.28318530717958647692528676655900576;
PI = 3.14159265358979323846264338327950288;
ONE_OVER_TAU = 0.636619772367581343075535053490057448;
ONE_OVER_PI = 0.159154943091895335768883763372514362;
E = 2.71828182845904523536;
SQRT_TWO = 1.41421356237309504880168872420969808;
SQRT_THREE = 1.73205080756887729352744634150587236;
SQRT_FIVE = 2.23606797749978969640917366873127623;
LOG_TWO = 0.693147180559945309417232121458176568;
LOG_TEN = 2.30258509299404568401799145468436421;
EPSILON = 1.19209290e-7;
τ = TAU;
π = PI;
)
type (
Vec2 [vector 2]f32;
Vec3 [vector 3]f32;
Vec4 [vector 4]f32;
// Column major
Mat2 [2][2]f32;
Mat3 [3][3]f32;
Mat4 [4][4]f32;
Complex complex64;
)
foreign __llvm_core {
proc sqrt(x: f32) -> f32 #link_name "llvm.sqrt.f32";
proc sqrt(x: f64) -> f64 #link_name "llvm.sqrt.f64";
proc sin (θ: f32) -> f32 #link_name "llvm.sin.f32";
proc sin (θ: f64) -> f64 #link_name "llvm.sin.f64";
proc cos (θ: f32) -> f32 #link_name "llvm.cos.f32";
proc cos (θ: f64) -> f64 #link_name "llvm.cos.f64";
proc pow (x, power: f32) -> f32 #link_name "llvm.pow.f32";
proc pow (x, power: f64) -> f64 #link_name "llvm.pow.f64";
proc fmuladd(a, b, c: f32) -> f32 #link_name "llvm.fmuladd.f32";
proc fmuladd(a, b, c: f64) -> f64 #link_name "llvm.fmuladd.f64";
}
proc tan (θ: f32) -> f32 #inline { return sin(θ)/cos(θ); }
proc tan (θ: f64) -> f64 #inline { return sin(θ)/cos(θ); }
proc lerp (a, b, t: f32) -> (x: f32) { return a*(1-t) + b*t; }
proc lerp (a, b, t: f64) -> (x: f64) { return a*(1-t) + b*t; }
proc unlerp(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); }
proc unlerp(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); }
proc sign(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
proc sign(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
proc copy_sign(x, y: f32) -> f32 {
var ix = transmute(u32, x);
var iy = transmute(u32, y);
ix &= 0x7fff_ffff;
ix |= iy & 0x8000_0000;
return transmute(f32, ix);
}
proc copy_sign(x, y: f64) -> f64 {
var ix = transmute(u64, x);
var iy = transmute(u64, y);
ix &= 0x7fff_ffff_ffff_ff;
ix |= iy & 0x8000_0000_0000_0000;
return transmute(f64, ix);
}
proc round (x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
proc round (x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
proc floor (x: f32) -> f32 { return x >= 0 ? f32(i64(x)) : f32(i64(x-0.5)); } // TODO: Get accurate versions
proc floor (x: f64) -> f64 { return x >= 0 ? f64(i64(x)) : f64(i64(x-0.5)); } // TODO: Get accurate versions
proc ceil (x: f32) -> f32 { return x < 0 ? f32(i64(x)) : f32(i64(x+1)); } // TODO: Get accurate versions
proc ceil (x: f64) -> f64 { return x < 0 ? f64(i64(x)) : f64(i64(x+1)); } // TODO: Get accurate versions
proc remainder(x, y: f32) -> f32 { return x - round(x/y) * y; }
proc remainder(x, y: f64) -> f64 { return x - round(x/y) * y; }
proc mod(x, y: f32) -> f32 {
var result: f32;
y = abs(y);
result = remainder(abs(x), y);
if sign(result) < 0 {
result += y;
}
return copy_sign(result, x);
}
proc mod(x, y: f64) -> f64 {
var result: f64;
y = abs(y);
result = remainder(abs(x), y);
if sign(result) < 0 {
result += y;
}
return copy_sign(result, x);
}
proc to_radians(degrees: f32) -> f32 { return degrees * TAU / 360; }
proc to_degrees(radians: f32) -> f32 { return radians * 360 / TAU; }
proc dot(a, b: Vec2) -> f32 { var c = a*b; return c.x + c.y; }
proc dot(a, b: Vec3) -> f32 { var c = a*b; return c.x + c.y + c.z; }
proc dot(a, b: Vec4) -> f32 { var c = a*b; return c.x + c.y + c.z + c.w; }
proc cross(x, y: Vec3) -> Vec3 {
var a = swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
var b = swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
return a - b;
}
proc mag(v: Vec2) -> f32 { return sqrt(dot(v, v)); }
proc mag(v: Vec3) -> f32 { return sqrt(dot(v, v)); }
proc mag(v: Vec4) -> f32 { return sqrt(dot(v, v)); }
proc norm(v: Vec2) -> Vec2 { return v / mag(v); }
proc norm(v: Vec3) -> Vec3 { return v / mag(v); }
proc norm(v: Vec4) -> Vec4 { return v / mag(v); }
proc norm0(v: Vec2) -> Vec2 {
var m = mag(v);
if m == 0 {
return 0;
}
return v / m;
}
proc norm0(v: Vec3) -> Vec3 {
var m = mag(v);
if m == 0 {
return 0;
}
return v / m;
}
proc norm0(v: Vec4) -> Vec4 {
var m = mag(v);
if m == 0 {
return 0;
}
return v / m;
}
proc mat4_identity() -> Mat4 {
return Mat4{
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1},
};
}
proc mat4_transpose(m: Mat4) -> Mat4 {
for j in 0..<4 {
for i in 0..<4 {
m[i][j], m[j][i] = m[j][i], m[i][j];
}
}
return m;
}
proc mul(a, b: Mat4) -> Mat4 {
var 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;
}
proc mul(m: Mat4, v: Vec4) -> Vec4 {
return Vec4{
m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z + m[3][2]*v.w,
m[0][3]*v.x + m[1][3]*v.y + m[2][3]*v.z + m[3][3]*v.w,
};
}
proc inverse(m: Mat4) -> Mat4 {
var o: Mat4;
var (
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);
var 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;
}
proc mat4_translate(v: Vec3) -> Mat4 {
var m = mat4_identity();
m[3][0] = v.x;
m[3][1] = v.y;
m[3][2] = v.z;
m[3][3] = 1;
return m;
}
proc mat4_rotate(v: Vec3, angle_radians: f32) -> Mat4 {
var (
c = cos(angle_radians);
s = sin(angle_radians);
a = norm(v);
t = a * (1-c);
rot = mat4_identity();
)
rot[0][0] = c + t.x*a.x;
rot[0][1] = 0 + t.x*a.y + s*a.z;
rot[0][2] = 0 + t.x*a.z - s*a.y;
rot[0][3] = 0;
rot[1][0] = 0 + t.y*a.x - s*a.z;
rot[1][1] = c + t.y*a.y;
rot[1][2] = 0 + t.y*a.z + s*a.x;
rot[1][3] = 0;
rot[2][0] = 0 + t.z*a.x + s*a.y;
rot[2][1] = 0 + t.z*a.y - s*a.x;
rot[2][2] = c + t.z*a.z;
rot[2][3] = 0;
return rot;
}
proc scale(m: Mat4, v: Vec3) -> Mat4 {
m[0][0] *= v.x;
m[1][1] *= v.y;
m[2][2] *= v.z;
return m;
}
proc scale(m: Mat4, s: f32) -> Mat4 {
m[0][0] *= s;
m[1][1] *= s;
m[2][2] *= s;
return m;
}
proc look_at(eye, centre, up: Vec3) -> Mat4 {
var (
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},
};
}
proc perspective(fovy, aspect, near, far: f32) -> Mat4 {
var (
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;
}
proc ortho3d(left, right, bottom, top, near, far: f32) -> Mat4 {
var m = mat4_identity();
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;
}
const (
F32_DIG = 6;
F32_EPSILON = 1.192092896e-07;
F32_GUARD = 0;
F32_MANT_DIG = 24;
F32_MAX = 3.402823466e+38;
F32_MAX_10_EXP = 38;
F32_MAX_EXP = 128;
F32_MIN = 1.175494351e-38;
F32_MIN_10_EXP = -37;
F32_MIN_EXP = -125;
F32_NORMALIZE = 0;
F32_RADIX = 2;
F32_ROUNDS = 1;
F64_DIG = 15; // # of decimal digits of precision
F64_EPSILON = 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0
F64_MANT_DIG = 53; // # of bits in mantissa
F64_MAX = 1.7976931348623158e+308; // max value
F64_MAX_10_EXP = 308; // max decimal exponent
F64_MAX_EXP = 1024; // max binary exponent
F64_MIN = 2.2250738585072014e-308; // min positive value
F64_MIN_10_EXP = -307; // min decimal exponent
F64_MIN_EXP = -1021; // min binary exponent
F64_RADIX = 2; // exponent radix
F64_ROUNDS = 1; // addition rounding: near
)
+260
View File
@@ -0,0 +1,260 @@
package bits
import "core:os"
U8_MIN :: 0;
U16_MIN :: 0;
U32_MIN :: 0;
U64_MIN :: 0;
U8_MAX :: 1 << 8 - 1;
U16_MAX :: 1 << 16 - 1;
U32_MAX :: 1 << 32 - 1;
U64_MAX :: 1 << 64 - 1;
I8_MIN :: - 1 << 7;
I16_MIN :: - 1 << 15;
I32_MIN :: - 1 << 31;
I64_MIN :: - 1 << 63;
I8_MAX :: 1 << 7 - 1;
I16_MAX :: 1 << 15 - 1;
I32_MAX :: 1 << 31 - 1;
I64_MAX :: 1 << 63 - 1;
@(default_calling_convention="none")
foreign {
@(link_name="llvm.ctpop.i8") count_ones8 :: proc(i: u8) -> u8 ---
@(link_name="llvm.ctpop.i16") count_ones16 :: proc(i: u16) -> u16 ---
@(link_name="llvm.ctpop.i32") count_ones32 :: proc(i: u32) -> u32 ---
@(link_name="llvm.ctpop.i64") count_ones64 :: proc(i: u64) -> u64 ---
@(link_name="llvm.ctlz.i8") leading_zeros8 :: proc(i: u8, is_zero_undef := false) -> u8 ---
@(link_name="llvm.ctlz.i16") leading_zeros16 :: proc(i: u16, is_zero_undef := false) -> u16 ---
@(link_name="llvm.ctlz.i32") leading_zeros32 :: proc(i: u32, is_zero_undef := false) -> u32 ---
@(link_name="llvm.ctlz.i64") leading_zeros64 :: proc(i: u64, is_zero_undef := false) -> u64 ---
@(link_name="llvm.cttz.i8") trailing_zeros8 :: proc(i: u8, is_zero_undef := false) -> u8 ---
@(link_name="llvm.cttz.i16") trailing_zeros16 :: proc(i: u16, is_zero_undef := false) -> u16 ---
@(link_name="llvm.cttz.i32") trailing_zeros32 :: proc(i: u32, is_zero_undef := false) -> u32 ---
@(link_name="llvm.cttz.i64") trailing_zeros64 :: proc(i: u64, is_zero_undef := false) -> u64 ---
@(link_name="llvm.bitreverse.i8") reverse_bits8 :: proc(i: u8) -> u8 ---
@(link_name="llvm.bitreverse.i16") reverse_bits16 :: proc(i: u16) -> u16 ---
@(link_name="llvm.bitreverse.i32") reverse_bits32 :: proc(i: u32) -> u32 ---
@(link_name="llvm.bitreverse.i64") reverse_bits64 :: proc(i: u64) -> u64 ---
@(link_name="llvm.bswap.i16") byte_swap_u16 :: proc(u16) -> u16 ---
@(link_name="llvm.bswap.i32") byte_swap_u32 :: proc(u32) -> u32 ---
@(link_name="llvm.bswap.i64") byte_swap_u64 :: proc(u64) -> u64 ---
@(link_name="llvm.bswap.i16") byte_swap_i16 :: proc(i16) -> i16 ---
@(link_name="llvm.bswap.i32") byte_swap_i32 :: proc(i32) -> i32 ---
@(link_name="llvm.bswap.i64") byte_swap_i64 :: proc(i64) -> i64 ---
@(link_name="llvm.bswap.i128") byte_swap_u128 :: proc(u128) -> u128 ---
@(link_name="llvm.bswap.i128") byte_swap_i128 :: proc(i128) -> i128 ---
}
byte_swap_uint :: proc(i: uint) -> uint {
when size_of(uint) == size_of(u32) {
return uint(byte_swap_u32(u32(i)));
} else {
return uint(byte_swap_u64(u64(i)));
}
}
byte_swap_int :: proc(i: int) -> int {
when size_of(int) == size_of(i32) {
return int(byte_swap_i32(i32(i)));
} else {
return int(byte_swap_i64(i64(i)));
}
}
byte_swap :: proc{
byte_swap_u16,
byte_swap_u32,
byte_swap_u64,
byte_swap_u128,
byte_swap_i16,
byte_swap_i32,
byte_swap_i64,
byte_swap_i128,
byte_swap_uint,
byte_swap_int,
};
count_zeros8 :: proc(i: u8) -> u8 { return 8 - count_ones8(i); }
count_zeros16 :: proc(i: u16) -> u16 { return 16 - count_ones16(i); }
count_zeros32 :: proc(i: u32) -> u32 { return 32 - count_ones32(i); }
count_zeros64 :: proc(i: u64) -> u64 { return 64 - count_ones64(i); }
rotate_left8 :: proc(i: u8, s: uint) -> u8 { return (i << s)|(i >> (8*size_of(u8) - s)); }
rotate_left16 :: proc(i: u16, s: uint) -> u16 { return (i << s)|(i >> (8*size_of(u16) - s)); }
rotate_left32 :: proc(i: u32, s: uint) -> u32 { return (i << s)|(i >> (8*size_of(u32) - s)); }
rotate_left64 :: proc(i: u64, s: uint) -> u64 { return (i << s)|(i >> (8*size_of(u64) - s)); }
rotate_right8 :: proc(i: u8, s: uint) -> u8 { return (i >> s)|(i << (8*size_of(u8) - s)); }
rotate_right16 :: proc(i: u16, s: uint) -> u16 { return (i >> s)|(i << (8*size_of(u16) - s)); }
rotate_right32 :: proc(i: u32, s: uint) -> u32 { return (i >> s)|(i << (8*size_of(u32) - s)); }
rotate_right64 :: proc(i: u64, s: uint) -> u64 { return (i >> s)|(i << (8*size_of(u64) - s)); }
from_be_u8 :: proc(i: u8) -> u8 { return i; }
from_be_u16 :: proc(i: u16) -> u16 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be_u32 :: proc(i: u32) -> u32 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be_u64 :: proc(i: u64) -> u64 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be_uint :: proc(i: uint) -> uint { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_le_u8 :: proc(i: u8) -> u8 { return i; }
from_le_u16 :: proc(i: u16) -> u16 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le_u32 :: proc(i: u32) -> u32 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le_u64 :: proc(i: u64) -> u64 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le_uint :: proc(i: uint) -> uint { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_be_u8 :: proc(i: u8) -> u8 { return i; }
to_be_u16 :: proc(i: u16) -> u16 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be_u32 :: proc(i: u32) -> u32 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be_u64 :: proc(i: u64) -> u64 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be_uint :: proc(i: uint) -> uint { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_le_u8 :: proc(i: u8) -> u8 { return i; }
to_le_u16 :: proc(i: u16) -> u16 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le_u32 :: proc(i: u32) -> u32 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le_u64 :: proc(i: u64) -> u64 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le_uint :: proc(i: uint) -> uint { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
@(default_calling_convention="none")
foreign {
@(link_name="llvm.uadd.with.overflow.i8") overflowing_add_u8 :: proc(lhs, rhs: u8) -> (u8, bool) ---
@(link_name="llvm.sadd.with.overflow.i8") overflowing_add_i8 :: proc(lhs, rhs: i8) -> (i8, bool) ---
@(link_name="llvm.uadd.with.overflow.i16") overflowing_add_u16 :: proc(lhs, rhs: u16) -> (u16, bool) ---
@(link_name="llvm.sadd.with.overflow.i16") overflowing_add_i16 :: proc(lhs, rhs: i16) -> (i16, bool) ---
@(link_name="llvm.uadd.with.overflow.i32") overflowing_add_u32 :: proc(lhs, rhs: u32) -> (u32, bool) ---
@(link_name="llvm.sadd.with.overflow.i32") overflowing_add_i32 :: proc(lhs, rhs: i32) -> (i32, bool) ---
@(link_name="llvm.uadd.with.overflow.i64") overflowing_add_u64 :: proc(lhs, rhs: u64) -> (u64, bool) ---
@(link_name="llvm.sadd.with.overflow.i64") overflowing_add_i64 :: proc(lhs, rhs: i64) -> (i64, bool) ---
}
overflowing_add_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
x, ok := overflowing_add_u32(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
x, ok := overflowing_add_u64(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
overflowing_add_int :: proc(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
x, ok := overflowing_add_i32(i32(lhs), i32(rhs));
return int(x), ok;
} else {
x, ok := overflowing_add_i64(i64(lhs), i64(rhs));
return int(x), ok;
}
}
overflowing_add :: proc{
overflowing_add_u8, overflowing_add_i8,
overflowing_add_u16, overflowing_add_i16,
overflowing_add_u32, overflowing_add_i32,
overflowing_add_u64, overflowing_add_i64,
overflowing_add_uint, overflowing_add_int,
};
@(default_calling_convention="none")
foreign {
@(link_name="llvm.usub.with.overflow.i8") overflowing_sub_u8 :: proc(lhs, rhs: u8) -> (u8, bool) ---
@(link_name="llvm.ssub.with.overflow.i8") overflowing_sub_i8 :: proc(lhs, rhs: i8) -> (i8, bool) ---
@(link_name="llvm.usub.with.overflow.i16") overflowing_sub_u16 :: proc(lhs, rhs: u16) -> (u16, bool) ---
@(link_name="llvm.ssub.with.overflow.i16") overflowing_sub_i16 :: proc(lhs, rhs: i16) -> (i16, bool) ---
@(link_name="llvm.usub.with.overflow.i32") overflowing_sub_u32 :: proc(lhs, rhs: u32) -> (u32, bool) ---
@(link_name="llvm.ssub.with.overflow.i32") overflowing_sub_i32 :: proc(lhs, rhs: i32) -> (i32, bool) ---
@(link_name="llvm.usub.with.overflow.i64") overflowing_sub_u64 :: proc(lhs, rhs: u64) -> (u64, bool) ---
@(link_name="llvm.ssub.with.overflow.i64") overflowing_sub_i64 :: proc(lhs, rhs: i64) -> (i64, bool) ---
}
overflowing_sub_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
x, ok := overflowing_sub_u32(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
x, ok := overflowing_sub_u64(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
overflowing_sub_int :: proc(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
x, ok := overflowing_sub_i32(i32(lhs), i32(rhs));
return int(x), ok;
} else {
x, ok := overflowing_sub_i64(i64(lhs), i64(rhs));
return int(x), ok;
}
}
overflowing_sub :: proc{
overflowing_sub_u8, overflowing_sub_i8,
overflowing_sub_u16, overflowing_sub_i16,
overflowing_sub_u32, overflowing_sub_i32,
overflowing_sub_u64, overflowing_sub_i64,
overflowing_sub_uint, overflowing_sub_int,
};
@(default_calling_convention="none")
foreign {
@(link_name="llvm.umul.with.overflow.i8") overflowing_mul_u8 :: proc(lhs, rhs: u8) -> (u8, bool) ---
@(link_name="llvm.smul.with.overflow.i8") overflowing_mul_i8 :: proc(lhs, rhs: i8) -> (i8, bool) ---
@(link_name="llvm.umul.with.overflow.i16") overflowing_mul_u16 :: proc(lhs, rhs: u16) -> (u16, bool) ---
@(link_name="llvm.smul.with.overflow.i16") overflowing_mul_i16 :: proc(lhs, rhs: i16) -> (i16, bool) ---
@(link_name="llvm.umul.with.overflow.i32") overflowing_mul_u32 :: proc(lhs, rhs: u32) -> (u32, bool) ---
@(link_name="llvm.smul.with.overflow.i32") overflowing_mul_i32 :: proc(lhs, rhs: i32) -> (i32, bool) ---
@(link_name="llvm.umul.with.overflow.i64") overflowing_mul_u64 :: proc(lhs, rhs: u64) -> (u64, bool) ---
@(link_name="llvm.smul.with.overflow.i64") overflowing_mul_i64 :: proc(lhs, rhs: i64) -> (i64, bool) ---
}
overflowing_mul_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
x, ok := overflowing_mul_u32(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
x, ok := overflowing_mul_u64(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
overflowing_mul_int :: proc(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
x, ok := overflowing_mul_i32(i32(lhs), i32(rhs));
return int(x), ok;
} else {
x, ok := overflowing_mul_i64(i64(lhs), i64(rhs));
return int(x), ok;
}
}
overflowing_mul :: proc{
overflowing_mul_u8, overflowing_mul_i8,
overflowing_mul_u16, overflowing_mul_i16,
overflowing_mul_u32, overflowing_mul_i32,
overflowing_mul_u64, overflowing_mul_i64,
overflowing_mul_uint, overflowing_mul_int,
};
is_power_of_two_u8 :: proc(i: u8) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two_i8 :: proc(i: i8) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two_u16 :: proc(i: u16) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two_i16 :: proc(i: i16) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two_u32 :: proc(i: u32) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two_i32 :: proc(i: i32) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two_u64 :: proc(i: u64) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two_i64 :: proc(i: i64) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two_uint :: proc(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two_int :: proc(i: int) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc{
is_power_of_two_u8, is_power_of_two_i8,
is_power_of_two_u16, is_power_of_two_i16,
is_power_of_two_u32, is_power_of_two_i32,
is_power_of_two_u64, is_power_of_two_i64,
is_power_of_two_uint, is_power_of_two_int,
};
+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;
}
+597
View File
@@ -0,0 +1,597 @@
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;
LN2 :: 0.693147180559945309417232121458176568;
LN10 :: 2.30258509299404568401799145468436421;
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'
RAD_PER_DEG :: TAU/360.0;
DEG_PER_RAD :: 360.0/TAU;
@(default_calling_convention="none")
foreign _ {
@(link_name="llvm.sqrt.f32")
sqrt_f32 :: proc(x: f32) -> f32 ---;
@(link_name="llvm.sqrt.f64")
sqrt_f64 :: proc(x: f64) -> f64 ---;
@(link_name="llvm.sin.f32")
sin_f32 :: proc(θ: f32) -> f32 ---;
@(link_name="llvm.sin.f64")
sin_f64 :: proc(θ: f64) -> f64 ---;
@(link_name="llvm.cos.f32")
cos_f32 :: proc(θ: f32) -> f32 ---;
@(link_name="llvm.cos.f64")
cos_f64 :: proc(θ: f64) -> f64 ---;
@(link_name="llvm.pow.f32")
pow_f32 :: proc(x, power: f32) -> f32 ---;
@(link_name="llvm.pow.f64")
pow_f64 :: proc(x, power: f64) -> f64 ---;
@(link_name="llvm.fmuladd.f32")
fmuladd_f32 :: proc(a, b, c: f32) -> f32 ---;
@(link_name="llvm.fmuladd.f64")
fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---;
@(link_name="llvm.log.f32")
ln_f32 :: proc(x: f32) -> f32 ---;
@(link_name="llvm.log.f64")
ln_f64 :: proc(x: f64) -> f64 ---;
@(link_name="llvm.exp.f32")
exp_f32 :: proc(x: f32) -> f32 ---;
@(link_name="llvm.exp.f64")
exp_f64 :: proc(x: f64) -> 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 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;
iy := transmute(u32)y;
ix &= 0x7fff_ffff;
ix |= iy & 0x8000_0000;
return transmute(f32)ix;
}
copy_sign_f64 :: proc(x, y: f64) -> f64 {
ix := transmute(u64)x;
iy := transmute(u64)y;
ix &= 0x7fff_ffff_ffff_ffff;
ix |= iy & 0x8000_0000_0000_0000;
return transmute(f64)ix;
}
copy_sign :: proc{copy_sign_f32, copy_sign_f64};
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;
}
if x < 0 {
d, fract := modf(-x);
if fract != 0.0 {
d = d + 1;
}
return -d;
}
d, _ := modf(x);
return d;
}
floor_f64 :: proc(x: f64) -> f64 {
if x == 0 || is_nan(x) || is_inf(x) {
return x;
}
if x < 0 {
d, fract := modf(-x);
if fract != 0.0 {
d = d + 1;
}
return -d;
}
d, _ := modf(x);
return d;
}
floor :: proc{floor_f32, floor_f64};
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 a;
}
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;
bias :: 127;
if x < 1 {
switch {
case x < 0:
int, frac = modf(-x);
return -int, -frac;
case x == 0:
return x, x;
}
return 0, x;
}
i := transmute(u32)x;
e := uint(i>>shift)&mask - bias;
if e < shift {
i &~= 1<<(shift-e) - 1;
}
int = transmute(f32)i;
frac = x - int;
return;
}
modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) {
shift :: 64 - 11 - 1;
mask :: 0x7ff;
bias :: 1023;
if x < 1 {
switch {
case x < 0:
int, frac = modf(-x);
return -int, -frac;
case x == 0:
return x, x;
}
return 0, x;
}
i := transmute(u64)x;
e := uint(i>>shift)&mask - bias;
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;
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_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};
is_power_of_two :: proc(x: int) -> bool {
return x > 0 && (x & (x-1)) == 0;
}
next_power_of_two :: proc(x: int) -> int {
k := x -1;
when size_of(int) == 8 {
k = k | (k >> 32);
}
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;
}
sum :: proc(x: $T/[]$E) -> (res: E)
where intrinsics.BuiltinProc_type_is_numeric(E) {
for i in x {
res += i;
}
return;
}
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];
}
}
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 dst[:N];
}
F32_DIG :: 6;
F32_EPSILON :: 1.192092896e-07;
F32_GUARD :: 0;
F32_MANT_DIG :: 24;
F32_MAX :: 3.402823466e+38;
F32_MAX_10_EXP :: 38;
F32_MAX_EXP :: 128;
F32_MIN :: 1.175494351e-38;
F32_MIN_10_EXP :: -37;
F32_MIN_EXP :: -125;
F32_NORMALIZE :: 0;
F32_RADIX :: 2;
F32_ROUNDS :: 1;
F64_DIG :: 15; // # of decimal digits of precision
F64_EPSILON :: 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0
F64_MANT_DIG :: 53; // # of bits in mantissa
F64_MAX :: 1.7976931348623158e+308; // max value
F64_MAX_10_EXP :: 308; // max decimal exponent
F64_MAX_EXP :: 1024; // max binary exponent
F64_MIN :: 2.2250738585072014e-308; // min positive value
F64_MIN_10_EXP :: -307; // min decimal exponent
F64_MIN_EXP :: -1021; // min binary exponent
F64_RADIX :: 2; // exponent radix
F64_ROUNDS :: 1; // addition rounding: near
+146
View File
@@ -0,0 +1,146 @@
package rand
import "core:math"
//
// Normal distribution
//
// "The Ziggurat Method for Generating Random Variables"
// Authors: George Marsaglia, Wai Wan Tsang
// Submitted: 2000-04-15. Published: 2000-10-02.
// https://www.jstatsoft.org/index.php/jss/article/view/v005i08/ziggurat.pdf [pdf]
// https://www.jstatsoft.org/article/view/v005i08 [web page]
//
// norm_float64 returns a normally distributed f64 in the range -max(f64) through +max(f64) inclusive,
// with a standard normal distribution with a mean of 0 and standard deviation of 1.
//
// sample = norm_float64() * std_dev + mean
//
norm_float64 :: proc(r: ^Rand = global_rand_ptr) -> f64 {
rn :: 3.442619855899;
@(static)
kn := [128]u32{
0x76ad2212, 0x00000000, 0x600f1b53, 0x6ce447a6, 0x725b46a2,
0x7560051d, 0x774921eb, 0x789a25bd, 0x799045c3, 0x7a4bce5d,
0x7adf629f, 0x7b5682a6, 0x7bb8a8c6, 0x7c0ae722, 0x7c50cce7,
0x7c8cec5b, 0x7cc12cd6, 0x7ceefed2, 0x7d177e0b, 0x7d3b8883,
0x7d5bce6c, 0x7d78dd64, 0x7d932886, 0x7dab0e57, 0x7dc0dd30,
0x7dd4d688, 0x7de73185, 0x7df81cea, 0x7e07c0a3, 0x7e163efa,
0x7e23b587, 0x7e303dfd, 0x7e3beec2, 0x7e46db77, 0x7e51155d,
0x7e5aabb3, 0x7e63abf7, 0x7e6c222c, 0x7e741906, 0x7e7b9a18,
0x7e82adfa, 0x7e895c63, 0x7e8fac4b, 0x7e95a3fb, 0x7e9b4924,
0x7ea0a0ef, 0x7ea5b00d, 0x7eaa7ac3, 0x7eaf04f3, 0x7eb3522a,
0x7eb765a5, 0x7ebb4259, 0x7ebeeafd, 0x7ec2620a, 0x7ec5a9c4,
0x7ec8c441, 0x7ecbb365, 0x7ece78ed, 0x7ed11671, 0x7ed38d62,
0x7ed5df12, 0x7ed80cb4, 0x7eda175c, 0x7edc0005, 0x7eddc78e,
0x7edf6ebf, 0x7ee0f647, 0x7ee25ebe, 0x7ee3a8a9, 0x7ee4d473,
0x7ee5e276, 0x7ee6d2f5, 0x7ee7a620, 0x7ee85c10, 0x7ee8f4cd,
0x7ee97047, 0x7ee9ce59, 0x7eea0eca, 0x7eea3147, 0x7eea3568,
0x7eea1aab, 0x7ee9e071, 0x7ee98602, 0x7ee90a88, 0x7ee86d08,
0x7ee7ac6a, 0x7ee6c769, 0x7ee5bc9c, 0x7ee48a67, 0x7ee32efc,
0x7ee1a857, 0x7edff42f, 0x7ede0ffa, 0x7edbf8d9, 0x7ed9ab94,
0x7ed7248d, 0x7ed45fae, 0x7ed1585c, 0x7ece095f, 0x7eca6ccb,
0x7ec67be2, 0x7ec22eee, 0x7ebd7d1a, 0x7eb85c35, 0x7eb2c075,
0x7eac9c20, 0x7ea5df27, 0x7e9e769f, 0x7e964c16, 0x7e8d44ba,
0x7e834033, 0x7e781728, 0x7e6b9933, 0x7e5d8a1a, 0x7e4d9ded,
0x7e3b737a, 0x7e268c2f, 0x7e0e3ff5, 0x7df1aa5d, 0x7dcf8c72,
0x7da61a1e, 0x7d72a0fb, 0x7d30e097, 0x7cd9b4ab, 0x7c600f1a,
0x7ba90bdc, 0x7a722176, 0x77d664e5,
};
@(static)
wn := [128]f32{
1.7290405e-09, 1.2680929e-10, 1.6897518e-10, 1.9862688e-10,
2.2232431e-10, 2.4244937e-10, 2.601613e-10, 2.7611988e-10,
2.9073963e-10, 3.042997e-10, 3.1699796e-10, 3.289802e-10,
3.4035738e-10, 3.5121603e-10, 3.616251e-10, 3.7164058e-10,
3.8130857e-10, 3.9066758e-10, 3.9975012e-10, 4.08584e-10,
4.1719309e-10, 4.2559822e-10, 4.338176e-10, 4.418672e-10,
4.497613e-10, 4.5751258e-10, 4.651324e-10, 4.7263105e-10,
4.8001775e-10, 4.87301e-10, 4.944885e-10, 5.015873e-10,
5.0860405e-10, 5.155446e-10, 5.2241467e-10, 5.2921934e-10,
5.359635e-10, 5.426517e-10, 5.4928817e-10, 5.5587696e-10,
5.624219e-10, 5.6892646e-10, 5.753941e-10, 5.818282e-10,
5.882317e-10, 5.946077e-10, 6.00959e-10, 6.072884e-10,
6.135985e-10, 6.19892e-10, 6.2617134e-10, 6.3243905e-10,
6.386974e-10, 6.449488e-10, 6.511956e-10, 6.5744005e-10,
6.6368433e-10, 6.699307e-10, 6.7618144e-10, 6.824387e-10,
6.8870465e-10, 6.949815e-10, 7.012715e-10, 7.075768e-10,
7.1389966e-10, 7.202424e-10, 7.266073e-10, 7.329966e-10,
7.394128e-10, 7.4585826e-10, 7.5233547e-10, 7.58847e-10,
7.653954e-10, 7.719835e-10, 7.7861395e-10, 7.852897e-10,
7.920138e-10, 7.987892e-10, 8.0561924e-10, 8.125073e-10,
8.194569e-10, 8.2647167e-10, 8.3355556e-10, 8.407127e-10,
8.479473e-10, 8.55264e-10, 8.6266755e-10, 8.7016316e-10,
8.777562e-10, 8.8545243e-10, 8.932582e-10, 9.0117996e-10,
9.09225e-10, 9.174008e-10, 9.2571584e-10, 9.341788e-10,
9.427997e-10, 9.515889e-10, 9.605579e-10, 9.697193e-10,
9.790869e-10, 9.88676e-10, 9.985036e-10, 1.0085882e-09,
1.0189509e-09, 1.0296151e-09, 1.0406069e-09, 1.0519566e-09,
1.063698e-09, 1.0758702e-09, 1.0885183e-09, 1.1016947e-09,
1.1154611e-09, 1.1298902e-09, 1.1450696e-09, 1.1611052e-09,
1.1781276e-09, 1.1962995e-09, 1.2158287e-09, 1.2369856e-09,
1.2601323e-09, 1.2857697e-09, 1.3146202e-09, 1.347784e-09,
1.3870636e-09, 1.4357403e-09, 1.5008659e-09, 1.6030948e-09,
};
@(static)
fn := [128]f32{
1.00000000, 0.9635997, 0.9362827, 0.9130436, 0.89228165,
0.87324303, 0.8555006, 0.8387836, 0.8229072, 0.8077383,
0.793177, 0.7791461, 0.7655842, 0.7524416, 0.73967725,
0.7272569, 0.7151515, 0.7033361, 0.69178915, 0.68049186,
0.6694277, 0.658582, 0.6479418, 0.63749546, 0.6272325,
0.6171434, 0.6072195, 0.5974532, 0.58783704, 0.5783647,
0.56903, 0.5598274, 0.5507518, 0.54179835, 0.5329627,
0.52424055, 0.5156282, 0.50712204, 0.49871865, 0.49041483,
0.48220766, 0.4740943, 0.46607214, 0.4581387, 0.45029163,
0.44252872, 0.43484783, 0.427247, 0.41972435, 0.41227803,
0.40490642, 0.39760786, 0.3903808, 0.3832238, 0.37613547,
0.36911446, 0.3621595, 0.35526937, 0.34844297, 0.34167916,
0.33497685, 0.3283351, 0.3217529, 0.3152294, 0.30876362,
0.30235484, 0.29600215, 0.28970486, 0.2834622, 0.2772735,
0.27113807, 0.2650553, 0.25902456, 0.2530453, 0.24711695,
0.241239, 0.23541094, 0.22963232, 0.2239027, 0.21822165,
0.21258877, 0.20700371, 0.20146611, 0.19597565, 0.19053204,
0.18513499, 0.17978427, 0.17447963, 0.1692209, 0.16400786,
0.15884037, 0.15371831, 0.14864157, 0.14361008, 0.13862377,
0.13368265, 0.12878671, 0.12393598, 0.119130544, 0.11437051,
0.10965602, 0.104987256, 0.10036444, 0.095787846, 0.0912578,
0.08677467, 0.0823389, 0.077950984, 0.073611505, 0.06932112,
0.06508058, 0.06089077, 0.056752663, 0.0526674, 0.048636295,
0.044660863, 0.040742867, 0.03688439, 0.033087887, 0.029356318,
0.025693292, 0.022103304, 0.018592102, 0.015167298, 0.011839478,
0.008624485, 0.005548995, 0.0026696292,
};
for {
j := i32(uint32(r));
i := j & 0x7f;
x := f64(j) * f64(wn[i]);
if u32(abs(j)) < kn[i] {
// 99% of the time this will be hit
return x;
}
if i == 0 {
for {
x = -math.ln(float64(r)) * (1.0/ rn);
y := -math.ln(float64(r));
if y+y >= x*x {
break;
}
}
return j > 0 ? rn + x : -rn - x;
}
if fn[i]+f32(float64(r))*(fn[i-1]-fn[i]) < f32(math.exp(-0.5*x*x)) {
return x;
}
}
return 0; // NOTE(bill): Will never be hit but this is here for sanity's sake
}
+152
View File
@@ -0,0 +1,152 @@
package rand
Rand :: struct {
state: u64,
inc: u64,
}
@(private, static)
_GLOBAL_SEED_DATA := 1234567890;
@(private, static)
global_rand := create(u64(uintptr(&_GLOBAL_SEED_DATA)));
@(private, static)
global_rand_ptr := &global_rand;
set_global_seed :: proc(seed: u64) {
init(global_rand_ptr, seed);
}
create :: proc(seed: u64) -> Rand {
r: Rand;
init(&r, seed);
return r;
}
init :: proc(r: ^Rand, seed: u64) {
r.state = 0;
r.inc = (seed << 1) | 1;
_random(r);
r.state += seed;
_random(r);
}
_random :: proc(r: ^Rand) -> u32 {
old_state := r.state;
r.state = old_state * 6364136223846793005 + (r.inc|1);
xor_shifted := u32(((old_state>>18) ~ old_state) >> 27);
rot := u32(old_state >> 59);
return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31));
}
uint32 :: proc(r: ^Rand = global_rand_ptr) -> u32 { return _random(r); }
uint64 :: proc(r: ^Rand = global_rand_ptr) -> u64 {
a := u64(_random(r));
b := u64(_random(r));
return (a<<32) | b;
}
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");
if n&(n-1) == 0 {
return int31(r) & (n-1);
}
max := i32((1<<31) - 1 - (1<<31)&u32(n));
v := int31(r);
for v > max {
v = int31(r);
}
return v % n;
}
int63_max :: proc(n: i64, r: ^Rand = global_rand_ptr) -> i64 {
if n <= 0 do panic("Invalid argument to int63_max");
if n&(n-1) == 0 {
return int63(r) & (n-1);
}
max := i64((1<<63) - 1 - (1<<63)&u64(n));
v := int63(r);
for v > max {
v = int63(r);
}
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 {
return int(int31_max(i32(n), r));
} else {
return int(int63_max(i64(n), r));
}
}
float64 :: proc(r: ^Rand = global_rand_ptr) -> f64 { return f64(int63_max(1<<53, r)) / (1 << 53); }
float32 :: proc(r: ^Rand = global_rand_ptr) -> f32 { return f32(float64(r)); }
float64_range :: proc(lo, hi: f64, r: ^Rand = global_rand_ptr) -> f64 { return (hi-lo)*float64(r) + lo; }
float32_range :: proc(lo, hi: f32, r: ^Rand = global_rand_ptr) -> f32 { return (hi-lo)*float32(r) + lo; }
read :: proc(p: []byte, r: ^Rand = global_rand_ptr) -> (n: int) {
pos := i8(0);
val := i64(0);
for n = 0; n < len(p); n += 1 {
if pos == 0 {
val = int63(r);
pos = 7;
}
p[n] = byte(val);
val >>= 8;
pos -= 1;
}
return;
}
// perm returns a slice of n ints in a pseudo-random permutation of integers in the range [0, n)
perm :: proc(n: int, r: ^Rand = global_rand_ptr) -> []int {
m := make([]int, n);
for i := 0; i < n; i += 1 {
j := int_max(i+1);
m[i] = m[j];
m[j] = i;
}
return m;
}
shuffle :: proc(array: $T/[]$E, r: ^Rand = global_rand_ptr) {
n := i64(len(array));
if n < 2 do return;
for i := i64(0); i < n; i += 1 {
j := int63_max(n, r);
array[i], array[j] = array[j], array[i];
}
}
-308
View File
@@ -1,308 +0,0 @@
import (
"fmt.odin";
"os.odin";
)
foreign __llvm_core {
proc swap(b: u16) -> u16 #link_name "llvm.bswap.i16";
proc swap(b: u32) -> u32 #link_name "llvm.bswap.i32";
proc swap(b: u64) -> u64 #link_name "llvm.bswap.i64";
}
proc set(data: rawptr, value: i32, len: int) -> rawptr {
return __mem_set(data, value, len);
}
proc zero(data: rawptr, len: int) -> rawptr {
return __mem_zero(data, len);
}
proc copy(dst, src: rawptr, len: int) -> rawptr {
return __mem_copy(dst, src, len);
}
proc copy_non_overlapping(dst, src: rawptr, len: int) -> rawptr {
return __mem_copy_non_overlapping(dst, src, len);
}
proc compare(a, b: []u8) -> int {
return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
}
proc kilobytes(x: int) -> int #inline { return (x) * 1024; }
proc megabytes(x: int) -> int #inline { return kilobytes(x) * 1024; }
proc gigabytes(x: int) -> int #inline { return megabytes(x) * 1024; }
proc terabytes(x: int) -> int #inline { return gigabytes(x) * 1024; }
proc is_power_of_two(x: int) -> bool {
if x <= 0 {
return false;
}
return (x & (x-1)) == 0;
}
proc align_forward(ptr: rawptr, align: int) -> rawptr {
assert(is_power_of_two(align));
var a = uint(align);
var p = uint(ptr);
var modulo = p & (a-1);
if modulo != 0 {
p += a - modulo;
}
return rawptr(p);
}
type AllocationHeader struct {
size: int,
}
proc allocation_header_fill(header: ^AllocationHeader, data: rawptr, size: int) {
header.size = size;
var ptr = ^int(header+1);
for var i = 0; rawptr(ptr) < data; i++ {
(ptr+i)^ = -1;
}
}
proc allocation_header(data: rawptr) -> ^AllocationHeader {
if data == nil {
return nil;
}
var p = ^int(data);
for (p-1)^ == -1 {
p = (p-1);
}
return ^AllocationHeader(p-1);
}
// Custom allocators
type (
Arena struct {
backing: Allocator,
offset: int,
memory: []u8,
temp_count: int,
}
ArenaTempMemory struct {
arena: ^Arena,
original_count: int,
}
)
proc init_arena_from_memory(using a: ^Arena, data: []u8) {
backing = Allocator{};
memory = data[0..<0];
temp_count = 0;
}
proc init_arena_from_context(using a: ^Arena, size: int) {
backing = context.allocator;
memory = make([]u8, size);
temp_count = 0;
}
proc free_arena(using a: ^Arena) {
if backing.procedure != nil {
push_allocator backing {
free(memory);
memory = nil;
offset = 0;
}
}
}
proc arena_allocator(arena: ^Arena) -> Allocator {
return Allocator{
procedure = arena_allocator_proc,
data = arena,
};
}
proc arena_allocator_proc(allocator_data: rawptr, mode: AllocatorMode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
using AllocatorMode;
var arena = ^Arena(allocator_data);
match mode {
case Alloc:
var total_size = size + alignment;
if arena.offset + total_size > len(arena.memory) {
fmt.fprintln(os.stderr, "Arena out of memory");
return nil;
}
#no_bounds_check var end = &arena.memory[arena.offset];
var ptr = align_forward(end, alignment);
arena.offset += total_size;
return zero(ptr, size);
case Free:
// NOTE(bill): Free all at once
// Use ArenaTempMemory if you want to free a block
case FreeAll:
arena.offset = 0;
case Resize:
return default_resize_align(old_memory, old_size, size, alignment);
}
return nil;
}
proc begin_arena_temp_memory(a: ^Arena) -> ArenaTempMemory {
var tmp: ArenaTempMemory;
tmp.arena = a;
tmp.original_count = len(a.memory);
a.temp_count++;
return tmp;
}
proc end_arena_temp_memory(using tmp: ArenaTempMemory) {
assert(len(arena.memory) >= original_count);
assert(arena.temp_count > 0);
arena.memory = arena.memory[0..<original_count];
arena.temp_count--;
}
proc align_of_type_info(type_info: ^TypeInfo) -> int {
proc prev_pow2(n: i64) -> i64 {
if n <= 0 {
return 0;
}
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
return n - (n >> 1);
}
const WORD_SIZE = size_of(int);
const MAX_ALIGN = size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
using TypeInfo;
match info in type_info {
case Named:
return align_of_type_info(info.base);
case Integer:
return info.size;
case Float:
return info.size;
case String:
return WORD_SIZE;
case Boolean:
return 1;
case Any:
return WORD_SIZE;
case Pointer:
return WORD_SIZE;
case Procedure:
return WORD_SIZE;
case Array:
return align_of_type_info(info.elem);
case DynamicArray:
return WORD_SIZE;
case Slice:
return WORD_SIZE;
case Vector:
var size = size_of_type_info(info.elem);
var count = int(max(prev_pow2(i64(info.count)), 1));
var total = size * count;
return clamp(total, 1, MAX_ALIGN);
case Tuple:
return info.align;
case Struct:
return info.align;
case Union:
return info.align;
case RawUnion:
return info.align;
case Enum:
return align_of_type_info(info.base);
case Map:
return align_of_type_info(info.generated_struct);
}
return 0;
}
proc align_formula(size, align: int) -> int {
var result = size + align-1;
return result - result%align;
}
proc size_of_type_info(type_info: ^TypeInfo) -> int {
const WORD_SIZE = size_of(int);
using TypeInfo;
match info in type_info {
case Named:
return size_of_type_info(info.base);
case Integer:
return info.size;
case Float:
return info.size;
case String:
return 2*WORD_SIZE;
case Boolean:
return 1;
case Any:
return 2*WORD_SIZE;
case Pointer:
return WORD_SIZE;
case Procedure:
return WORD_SIZE;
case Array:
var count = info.count;
if count == 0 {
return 0;
}
var size = size_of_type_info(info.elem);
var align = align_of_type_info(info.elem);
var alignment = align_formula(size, align);
return alignment*(count-1) + size;
case DynamicArray:
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
case Slice:
return 2*WORD_SIZE;
case Vector:
var count = info.count;
if count == 0 {
return 0;
}
var size = size_of_type_info(info.elem);
var align = align_of_type_info(info.elem);
var alignment = align_formula(size, align);
return alignment*(count-1) + size;
case Struct:
return info.size;
case Union:
return info.size;
case RawUnion:
return info.size;
case Enum:
return size_of_type_info(info.base);
case Map:
return size_of_type_info(info.generated_struct);
}
return 0;
}
+152
View File
@@ -0,0 +1,152 @@
package mem
import "core:runtime"
DEFAULT_ALIGNMENT :: 2*align_of(rawptr);
Allocator_Mode :: enum byte {
Alloc,
Free,
Free_All,
Resize,
}
Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64 = 0, location := #caller_location) -> rawptr;
Allocator :: struct {
procedure: Allocator_Proc,
data: rawptr,
}
alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
if size == 0 do return nil;
if allocator.procedure == nil do return nil;
return allocator.procedure(allocator.data, Allocator_Mode.Alloc, size, alignment, nil, 0, 0, loc);
}
free :: inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) {
if ptr == nil do return;
if allocator.procedure == nil do return;
allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0, loc);
}
free_all :: inline proc(allocator := context.allocator, loc := #caller_location) {
if allocator.procedure != nil {
allocator.procedure(allocator.data, Allocator_Mode.Free_All, 0, 0, nil, 0, 0, loc);
}
}
resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
if allocator.procedure == nil {
return nil;
}
if new_size == 0 {
free(ptr, allocator, loc);
return nil;
} else if ptr == nil {
return allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, 0, loc);
}
return allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0, loc);
}
delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) {
free(raw_data(str), allocator, loc);
}
delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) {
free((^byte)(str), allocator, loc);
}
delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) {
free(raw_data(array), array.allocator, loc);
}
delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) {
free(raw_data(array), allocator, loc);
}
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) {
raw := transmute(Raw_Map)m;
delete_slice(raw.hashes);
free(raw.entries.data, raw.entries.allocator, loc);
}
delete :: proc{
delete_string,
delete_cstring,
delete_dynamic_array,
delete_slice,
delete_map,
};
new :: inline proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> ^T {
ptr := (^T)(alloc(size_of(T), align_of(T), allocator, loc));
if ptr != nil do ptr^ = T{};
return ptr;
}
new_clone :: inline proc(data: $T, allocator := context.allocator, loc := #caller_location) -> ^T {
ptr := (^T)(alloc(size_of(T), align_of(T), allocator, loc));
if ptr != nil do ptr^ = data;
return ptr;
}
make_slice :: proc($T: typeid/[]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T {
runtime.make_slice_error_loc(loc, len);
data := alloc(size_of(E)*len, align_of(E), allocator, loc);
s := Raw_Slice{data, len};
return transmute(T)s;
}
make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> T {
return make_dynamic_array_len_cap(T, 0, 16, allocator, loc);
}
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T {
return make_dynamic_array_len_cap(T, len, len, allocator, loc);
}
make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, auto_cast len: int, auto_cast cap: int, allocator := context.allocator, loc := #caller_location) -> T {
runtime.make_dynamic_array_error_loc(loc, len, cap);
data := alloc(size_of(E)*cap, align_of(E), allocator, loc);
s := Raw_Dynamic_Array{data, len, cap, allocator};
return transmute(T)s;
}
make_map :: proc($T: typeid/map[$K]$E, auto_cast cap: int = 16, allocator := context.allocator, loc := #caller_location) -> T {
runtime.make_map_expr_error_loc(loc, cap);
context.allocator = allocator;
m: T;
reserve_map(&m, cap);
return m;
}
make :: proc{
make_slice,
make_dynamic_array,
make_dynamic_array_len,
make_dynamic_array_len_cap,
make_map,
};
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> rawptr {
if old_memory == nil do return alloc(new_size, alignment, allocator, loc);
if new_size == 0 {
free(old_memory, allocator, loc);
return nil;
}
if new_size == old_size do return old_memory;
new_memory := alloc(new_size, alignment, allocator, loc);
if new_memory == nil do return nil;
copy(new_memory, old_memory, min(old_size, new_size));;
free(old_memory, allocator, loc);
return new_memory;
}
+621
View File
@@ -0,0 +1,621 @@
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 {
return nil;
}
nil_allocator :: proc() -> Allocator {
return Allocator{
procedure = nil_allocator_proc,
data = nil,
};
}
// Custom allocators
Arena :: struct {
data: []byte,
offset: int,
peak_used: int,
temp_count: int,
}
Arena_Temp_Memory :: struct {
arena: ^Arena,
prev_offset: int,
}
init_arena :: proc(a: ^Arena, data: []byte) {
a.data = data;
a.offset = 0;
a.peak_used = 0;
a.temp_count = 0;
}
arena_allocator :: proc(arena: ^Arena) -> Allocator {
return Allocator{
procedure = arena_allocator_proc,
data = arena,
};
}
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
arena := cast(^Arena)allocator_data;
switch mode {
case .Alloc:
total_size := size + alignment;
if arena.offset + total_size > len(arena.data) {
return nil;
}
#no_bounds_check end := &arena.data[len(arena.data)];
ptr := align_forward(end, uintptr(alignment));
arena.offset += total_size;
arena.peak_used = max(arena.peak_used, arena.offset);
return zero(ptr, size);
case .Free:
// NOTE(bill): Free all at once
// Use Arena_Temp_Memory if you want to free a block
case .Free_All:
arena.offset = 0;
case .Resize:
return default_resize_align(old_memory, old_size, size, alignment, arena_allocator(arena));
}
return nil;
}
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
tmp: Arena_Temp_Memory;
tmp.arena = a;
tmp.prev_offset = a.offset;
a.temp_count += 1;
return tmp;
}
end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
assert(arena.offset >= prev_offset);
assert(arena.temp_count > 0);
arena.offset = prev_offset;
arena.temp_count -= 1;
}
Scratch_Allocator :: struct {
data: []byte,
curr_offset: int,
prev_offset: int,
backup_allocator: Allocator,
leaked_allocations: [dynamic]rawptr,
}
scratch_allocator_init :: proc(scratch: ^Scratch_Allocator, data: []byte, backup_allocator := context.allocator) {
scratch.data = data;
scratch.curr_offset = 0;
scratch.prev_offset = 0;
scratch.backup_allocator = backup_allocator;
}
scratch_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 {
scratch := (^Scratch_Allocator)(allocator_data);
if scratch.data == nil {
DEFAULT_SCRATCH_BACKING_SIZE :: 1<<22;
scratch_allocator_init(scratch, make([]byte, 1<<22));
}
switch mode {
case Allocator_Mode.Alloc:
switch {
case scratch.curr_offset+size <= len(scratch.data):
offset := align_forward_uintptr(uintptr(scratch.curr_offset), uintptr(alignment));
ptr := &scratch.data[offset];
zero(ptr, size);
scratch.prev_offset = int(offset);
scratch.curr_offset = int(offset) + size;
return ptr;
case size <= len(scratch.data):
offset := align_forward_uintptr(uintptr(0), uintptr(alignment));
ptr := &scratch.data[offset];
zero(ptr, size);
scratch.prev_offset = int(offset);
scratch.curr_offset = int(offset) + size;
return ptr;
}
// TODO(bill): Should leaks be notified about? Should probably use a logging system that is built into the context system
a := scratch.backup_allocator;
if a.procedure == nil {
a = context.allocator;
scratch.backup_allocator = a;
}
ptr := alloc(size, alignment, a, loc);
if scratch.leaked_allocations == nil {
scratch.leaked_allocations = make([dynamic]rawptr, a);
}
append(&scratch.leaked_allocations, ptr);
return ptr;
case Allocator_Mode.Free:
last_ptr := rawptr(&scratch.data[scratch.prev_offset]);
if old_memory == last_ptr {
full_size := scratch.curr_offset - scratch.prev_offset;
scratch.curr_offset = scratch.prev_offset;
zero(last_ptr, full_size);
return nil;
}
// NOTE(bill): It's scratch memory, don't worry about freeing
case Allocator_Mode.Free_All:
scratch.curr_offset = 0;
scratch.prev_offset = 0;
for ptr in scratch.leaked_allocations {
free(ptr, scratch.backup_allocator);
}
clear(&scratch.leaked_allocations);
case Allocator_Mode.Resize:
last_ptr := rawptr(&scratch.data[scratch.prev_offset]);
if old_memory == last_ptr && len(scratch.data)-scratch.prev_offset >= size {
scratch.curr_offset = scratch.prev_offset+size;
return old_memory;
}
return scratch_allocator_proc(allocator_data, Allocator_Mode.Alloc, size, alignment, old_memory, old_size, flags, loc);
}
return nil;
}
scratch_allocator :: proc(scratch: ^Scratch_Allocator) -> Allocator {
return Allocator{
procedure = scratch_allocator_proc,
data = scratch,
};
}
Stack_Allocation_Header :: struct {
prev_offset: int,
padding: int,
}
// Stack is a stack-like allocator which has a strict memory freeing order
Stack :: struct {
data: []byte,
prev_offset: int,
curr_offset: int,
peak_used: int,
}
init_stack :: proc(s: ^Stack, data: []byte) {
s.data = data;
s.prev_offset = 0;
s.curr_offset = 0;
s.peak_used = 0;
}
stack_allocator :: proc(stack: ^Stack) -> Allocator {
return Allocator{
procedure = stack_allocator_proc,
data = stack,
};
}
stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
s := cast(^Stack)allocator_data;
if s.data == nil {
return nil;
}
raw_alloc :: proc(s: ^Stack, size, alignment: int) -> rawptr {
curr_addr := uintptr(&s.data[0]) + uintptr(s.curr_offset);
padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Stack_Allocation_Header));
if s.curr_offset + padding + size > len(s.data) {
return nil;
}
s.prev_offset = s.curr_offset;
s.curr_offset += padding;
next_addr := curr_addr + uintptr(padding);
header := (^Stack_Allocation_Header)(next_addr - size_of(Stack_Allocation_Header));
header.padding = auto_cast padding;
header.prev_offset = auto_cast s.prev_offset;
s.curr_offset += size;
s.peak_used = max(s.peak_used, s.curr_offset);
return zero(rawptr(next_addr), size);
}
switch mode {
case .Alloc:
return raw_alloc(s, size, alignment);
case .Free:
if old_memory == nil {
return nil;
}
start := uintptr(&s.data[0]);
end := start + uintptr(len(s.data));
curr_addr := uintptr(old_memory);
if !(start <= curr_addr && curr_addr < end) {
panic("Out of bounds memory address passed to stack allocator (free)");
return nil;
}
if curr_addr >= start+uintptr(s.curr_offset) {
// NOTE(bill): Allow double frees
return nil;
}
header := (^Stack_Allocation_Header)(curr_addr - size_of(Stack_Allocation_Header));
old_offset := int(curr_addr - uintptr(header.padding) - uintptr(&s.data[0]));
if old_offset != int(header.prev_offset) {
panic("Out of order stack allocator free");
return nil;
}
s.curr_offset = int(old_offset);
s.prev_offset = int(header.prev_offset);
case .Free_All:
s.prev_offset = 0;
s.curr_offset = 0;
case .Resize:
if old_memory == nil {
return raw_alloc(s, size, alignment);
}
if size == 0 {
return nil;
}
start := uintptr(&s.data[0]);
end := start + uintptr(len(s.data));
curr_addr := uintptr(old_memory);
if !(start <= curr_addr && curr_addr < end) {
panic("Out of bounds memory address passed to stack allocator (resize)");
return nil;
}
if curr_addr >= start+uintptr(s.curr_offset) {
// NOTE(bill): Allow double frees
return nil;
}
if old_size == size {
return old_memory;
}
header := (^Stack_Allocation_Header)(curr_addr - size_of(Stack_Allocation_Header));
old_offset := int(curr_addr - uintptr(header.padding) - uintptr(&s.data[0]));
if old_offset != int(header.prev_offset) {
ptr := raw_alloc(s, size, alignment);
copy(ptr, old_memory, min(old_size, size));
return ptr;
}
old_memory_size := uintptr(s.curr_offset) - (curr_addr - start);
assert(old_memory_size == uintptr(old_size));
diff := size - old_size;
s.curr_offset += diff; // works for smaller sizes too
if diff > 0 {
zero(rawptr(curr_addr + uintptr(diff)), diff);
}
return old_memory;
}
return nil;
}
Small_Stack_Allocation_Header :: struct {
padding: u8,
}
// Small_Stack is a stack-like allocator which uses the smallest possible header but at the cost of non-strict memory freeing order
Small_Stack :: struct {
data: []byte,
offset: int,
peak_used: int,
}
init_small_stack :: proc(s: ^Small_Stack, data: []byte) {
s.data = data;
s.offset = 0;
s.peak_used = 0;
}
small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator {
return Allocator{
procedure = small_stack_allocator_proc,
data = stack,
};
}
small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
s := cast(^Small_Stack)allocator_data;
if s.data == nil {
return nil;
}
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);
padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Small_Stack_Allocation_Header));
if s.offset + padding + size > len(s.data) {
return nil;
}
s.offset += padding;
next_addr := curr_addr + uintptr(padding);
header := (^Small_Stack_Allocation_Header)(next_addr - size_of(Small_Stack_Allocation_Header));
header.padding = auto_cast padding;
s.offset += size;
s.peak_used = max(s.peak_used, s.offset);
return zero(rawptr(next_addr), size);
}
switch mode {
case .Alloc:
return raw_alloc(s, size, align);
case .Free:
if old_memory == nil {
return nil;
}
start := uintptr(&s.data[0]);
end := start + uintptr(len(s.data));
curr_addr := uintptr(old_memory);
if !(start <= curr_addr && curr_addr < end) {
panic("Out of bounds memory address passed to stack allocator (free)");
return nil;
}
if curr_addr >= start+uintptr(s.offset) {
// NOTE(bill): Allow double frees
return nil;
}
header := (^Small_Stack_Allocation_Header)(curr_addr - size_of(Small_Stack_Allocation_Header));
old_offset := int(curr_addr - uintptr(header.padding) - uintptr(&s.data[0]));
s.offset = int(old_offset);
case .Free_All:
s.offset = 0;
case .Resize:
if old_memory == nil {
return raw_alloc(s, size, align);
}
if size == 0 {
return nil;
}
start := uintptr(&s.data[0]);
end := start + uintptr(len(s.data));
curr_addr := uintptr(old_memory);
if !(start <= curr_addr && curr_addr < end) {
panic("Out of bounds memory address passed to stack allocator (resize)");
return nil;
}
if curr_addr >= start+uintptr(s.offset) {
// NOTE(bill): Treat as a double free
return nil;
}
if old_size == size {
return old_memory;
}
ptr := raw_alloc(s, size, align);
copy(ptr, old_memory, min(old_size, size));
return ptr;
}
return nil;
}
Dynamic_Pool :: struct {
block_size: int,
out_band_size: int,
alignment: int,
unused_blocks: [dynamic]rawptr,
used_blocks: [dynamic]rawptr,
out_band_allocations: [dynamic]rawptr,
current_block: rawptr,
current_pos: rawptr,
bytes_left: int,
block_allocator: Allocator,
}
DYNAMIC_POOL_BLOCK_SIZE_DEFAULT :: 65536;
DYNAMIC_POOL_OUT_OF_BAND_SIZE_DEFAULT :: 6554;
dynamic_pool_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 {
pool := (^Dynamic_Pool)(allocator_data);
switch mode {
case Allocator_Mode.Alloc:
return dynamic_pool_alloc(pool, size);
case Allocator_Mode.Free:
panic("Allocator_Mode.Free is not supported for a pool");
case Allocator_Mode.Free_All:
dynamic_pool_free_all(pool);
case Allocator_Mode.Resize:
panic("Allocator_Mode.Resize is not supported for a pool");
if old_size >= size {
return old_memory;
}
ptr := dynamic_pool_alloc(pool, size);
copy(ptr, old_memory, old_size);
return ptr;
}
return nil;
}
dynamic_pool_allocator :: proc(pool: ^Dynamic_Pool) -> Allocator {
return Allocator{
procedure = dynamic_pool_allocator_proc,
data = pool,
};
}
dynamic_pool_init :: proc(pool: ^Dynamic_Pool,
block_allocator := context.allocator,
array_allocator := context.allocator,
block_size := DYNAMIC_POOL_BLOCK_SIZE_DEFAULT,
out_band_size := DYNAMIC_POOL_OUT_OF_BAND_SIZE_DEFAULT,
alignment := 8) {
pool.block_size = block_size;
pool.out_band_size = out_band_size;
pool.alignment = alignment;
pool.block_allocator = block_allocator;
pool.out_band_allocations.allocator = array_allocator;
pool. unused_blocks.allocator = array_allocator;
pool. used_blocks.allocator = array_allocator;
}
dynamic_pool_destroy :: proc(using pool: ^Dynamic_Pool) {
dynamic_pool_free_all(pool);
delete(unused_blocks);
delete(used_blocks);
zero(pool, size_of(pool^));
}
dynamic_pool_alloc :: proc(using pool: ^Dynamic_Pool, bytes: int) -> rawptr {
cycle_new_block :: proc(using pool: ^Dynamic_Pool) {
if block_allocator.procedure == nil {
panic("You must call pool_init on a Pool before using it");
}
if current_block != nil {
append(&used_blocks, current_block);
}
new_block: rawptr;
if len(unused_blocks) > 0 {
new_block = pop(&unused_blocks);
} else {
new_block = block_allocator.procedure(block_allocator.data, Allocator_Mode.Alloc,
block_size, alignment,
nil, 0);
}
bytes_left = block_size;
current_pos = new_block;
current_block = new_block;
}
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,
nil, 0);
if memory != nil {
append(&out_band_allocations, (^byte)(memory));
}
return memory;
}
if bytes_left < n {
cycle_new_block(pool);
if current_block == nil {
return nil;
}
}
memory := current_pos;
current_pos = ptr_offset((^byte)(current_pos), n);
bytes_left -= n;
return memory;
}
dynamic_pool_reset :: proc(using pool: ^Dynamic_Pool) {
if current_block != nil {
append(&unused_blocks, current_block);
current_block = nil;
}
for block in used_blocks {
append(&unused_blocks, block);
}
clear(&used_blocks);
for a in out_band_allocations {
free(a, block_allocator);
}
clear(&out_band_allocations);
}
dynamic_pool_free_all :: proc(using pool: ^Dynamic_Pool) {
dynamic_pool_reset(pool);
for block in unused_blocks {
free(block, block_allocator);
}
clear(&unused_blocks);
}
+230
View File
@@ -0,0 +1,230 @@
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 ---;
@(link_name = "llvm.bswap.i64") swap64 :: proc(b: u64) -> u64 ---;
}
swap :: proc{swap16, swap32, swap64};
set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr {
if data == nil do return nil;
if len < 0 do return data;
foreign _ {
when size_of(rawptr) == 8 {
@(link_name="llvm.memset.p0i8.i64")
llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---;
} else {
@(link_name="llvm.memset.p0i8.i32")
llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---;
}
}
llvm_memset(data, byte(value), len, 1, false);
return data;
}
zero :: inline proc "contextless" (data: rawptr, len: int) -> rawptr {
return set(data, 0, len);
}
zero_item :: inline proc "contextless" (item: $P/^$T) {
set(item, 0, size_of(T));
}
zero_slice :: proc "contextless" (data: $T/[]$E) {
if n := len(data); n > 0 {
zero(&data[0], size_of(E)*n);
}
}
copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
return runtime.mem_copy(dst, src, len);
}
copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
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)));
}
compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int #no_bounds_check {
x := slice_ptr(a, n);
y := slice_ptr(b, n);
SU :: size_of(uintptr);
fast := n/SU + 1;
offset := (fast-1)*SU;
curr_block := 0;
if n < SU {
fast = 0;
}
la := slice_ptr((^uintptr)(a), fast);
lb := slice_ptr((^uintptr)(b), fast);
for /**/; curr_block < fast; curr_block += 1 {
if la[curr_block] ~ lb[curr_block] != 0 {
for pos := curr_block*SU; pos < n; pos += 1 {
if x[pos] ~ y[pos] != 0 {
return (int(x[pos]) - int(y[pos])) < 0 ? -1 : +1;
}
}
}
}
for /**/; offset < n; offset += 1 {
if x[offset] ~ y[offset] != 0 {
return (int(x[offset]) - int(y[offset])) < 0 ? -1 : +1;
}
}
return 0;
}
compare_ptrs :: inline proc "contextless" (a, b: rawptr, n: int) -> int {
return compare_byte_ptrs((^byte)(a), (^byte)(b), n);
}
ptr_offset :: inline proc "contextless" (ptr: $P/^$T, n: int) -> P {
new := int(uintptr(ptr)) + size_of(T)*n;
return P(uintptr(new));
}
ptr_sub :: inline proc "contextless" (a, b: $P/^$T) -> int {
return (int(uintptr(a)) - int(uintptr(b)))/size_of(T);
}
slice_ptr :: inline proc "contextless" (ptr: ^$T, len: int) -> []T {
assert(len >= 0);
slice := Raw_Slice{data = ptr, len = len};
return transmute([]T)slice;
}
slice_to_bytes :: inline proc "contextless" (slice: $E/[]$T) -> []byte {
s := transmute(Raw_Slice)slice;
s.len *= size_of(T);
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;
d := Raw_Dynamic_Array{
data = s.data,
len = 0,
cap = s.len,
allocator = nil_allocator(),
};
return transmute([dynamic]E)d;
}
ptr_to_bytes :: inline proc "contextless" (ptr: ^$T, len := 1) -> []byte {
assert(len >= 0);
return transmute([]byte)Raw_Slice{ptr, len*size_of(T)};
}
any_to_bytes :: inline proc "contextless" (val: any) -> []byte {
ti := type_info_of(val.id);
size := ti != nil ? ti.size : 0;
return transmute([]byte)Raw_Slice{val.data, size};
}
kilobytes :: inline proc "contextless" (x: int) -> int do return (x) * 1024;
megabytes :: inline proc "contextless" (x: int) -> int do return kilobytes(x) * 1024;
gigabytes :: inline proc "contextless" (x: int) -> int do return megabytes(x) * 1024;
terabytes :: inline proc "contextless" (x: int) -> int do return gigabytes(x) * 1024;
is_power_of_two :: inline proc(x: uintptr) -> bool {
if x <= 0 do return false;
return (x & (x-1)) == 0;
}
align_forward :: proc(ptr: rawptr, align: uintptr) -> rawptr {
assert(is_power_of_two(align));
a := uintptr(align);
p := uintptr(ptr);
modulo := p & (a-1);
if modulo != 0 do p += a - modulo;
return rawptr(p);
}
align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr {
assert(is_power_of_two(align));
a := uintptr(align);
p := uintptr(ptr);
modulo := p & (a-1);
if modulo != 0 do p += a - modulo;
return uintptr(p);
}
align_forward_int :: inline proc(ptr, align: int) -> int {
return int(align_forward_uintptr(uintptr(ptr), uintptr(align)));
}
align_forward_uint :: inline proc(ptr, align: uint) -> uint {
return uint(align_forward_uintptr(uintptr(ptr), uintptr(align)));
}
context_from_allocator :: proc(a: Allocator) -> type_of(context) {
context.allocator = a;
return context;
}
Fixed_Byte_Buffer :: distinct [dynamic]byte;
make_fixed_byte_buffer :: proc(backing: []byte) -> Fixed_Byte_Buffer {
s := transmute(Raw_Slice)backing;
d: Raw_Dynamic_Array;
d.data = s.data;
d.len = 0;
d.cap = s.len;
d.allocator = nil_allocator();
return transmute(Fixed_Byte_Buffer)d;
}
align_formula :: proc(size, align: int) -> int {
result := size + align-1;
return result - result%align;
}
calc_padding_with_header :: proc(ptr: uintptr, align: uintptr, header_size: int) -> int {
p := uintptr(ptr);
a := uintptr(align);
modulo := p & (a-1);
padding := uintptr(0);
if modulo != 0 do padding = a - modulo;
needed_space := uintptr(header_size);
if padding < needed_space {
needed_space -= padding;
if needed_space & (a-1) > 0 {
padding += align * (1+(needed_space/align));
} else {
padding += align * (needed_space/align);
}
}
return int(padding);
}
+57
View File
@@ -0,0 +1,57 @@
package mem
Raw_Any :: struct {
data: rawptr,
id: typeid,
}
Raw_String :: struct {
data: ^byte,
len: int,
}
Raw_Cstring :: struct {
data: ^byte,
}
Raw_Slice :: struct {
data: rawptr,
len: int,
}
Raw_Dynamic_Array :: struct {
data: rawptr,
len: int,
cap: int,
allocator: Allocator,
}
Raw_Map :: struct {
hashes: []int,
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 (transmute(Raw_String)s).data;
}
raw_slice_data :: inline proc(a: $T/[]$E) -> ^E {
return cast(^E)(transmute(Raw_Slice)a).data;
}
raw_dynamic_array_data :: inline proc(a: $T/[dynamic]$E) -> ^E {
return cast(^E)(transmute(Raw_Dynamic_Array)a).data;
}
raw_data :: proc{raw_string_data, raw_slice_data, raw_dynamic_array_data};
+627
View File
@@ -0,0 +1,627 @@
package odin_ast
import "core:odin/tokenizer"
Proc_Tag :: enum {
Bounds_Check,
No_Bounds_Check,
}
Proc_Tags :: distinct bit_set[Proc_Tag; u32];
Proc_Inlining :: enum u32 {
None = 0,
Inline = 1,
No_Inline = 2,
}
Proc_Calling_Convention :: enum i32 {
Invalid = 0,
Odin,
Contextless,
C_Decl,
Std_Call,
Fast_Call,
Foreign_Block_Default = -1,
}
Node_State_Flag :: enum {
Bounds_Check,
No_Bounds_Check,
}
Node_State_Flags :: distinct bit_set[Node_State_Flag];
Comment_Group :: struct {
list: []tokenizer.Token,
}
Node :: struct {
pos: tokenizer.Pos,
end: tokenizer.Pos,
derived: any,
state_flags: Node_State_Flags,
}
Expr :: struct {
using expr_base: Node,
}
Stmt :: struct {
using stmt_base: Node,
}
Decl :: struct {
using decl_base: Stmt,
}
// Expressions
Bad_Expr :: struct {
using node: Expr,
}
Ident :: struct {
using node: Expr,
name: string,
}
Implicit :: struct {
using node: Expr,
tok: tokenizer.Token,
}
Undef :: struct {
using node: Expr,
tok: tokenizer.Token_Kind,
}
Basic_Lit :: struct {
using node: Expr,
tok: tokenizer.Token,
}
Basic_Directive :: struct {
using node: Expr,
tok: tokenizer.Token,
name: string,
}
Ellipsis :: struct {
using node: Expr,
tok: tokenizer.Token_Kind,
expr: ^Expr,
}
Proc_Lit :: struct {
using node: Expr,
type: ^Proc_Type,
body: ^Stmt,
tags: Proc_Tags,
inlining: Proc_Inlining,
where_token: tokenizer.Token,
where_clauses: []^Expr,
}
Comp_Lit :: struct {
using node: Expr,
type: ^Expr,
open: tokenizer.Pos,
elems: []^Expr,
close: tokenizer.Pos,
}
Tag_Expr :: struct {
using node: Expr,
op: tokenizer.Token,
name: string,
expr: ^Expr,
}
Unary_Expr :: struct {
using node: Expr,
op: tokenizer.Token,
expr: ^Expr,
}
Binary_Expr :: struct {
using node: Expr,
left: ^Expr,
op: tokenizer.Token,
right: ^Expr,
}
Paren_Expr :: struct {
using node: Expr,
open: tokenizer.Pos,
expr: ^Expr,
close: tokenizer.Pos,
}
Selector_Expr :: struct {
using node: Expr,
expr: ^Expr,
field: ^Ident,
}
Implicit_Selector_Expr :: struct {
using node: Expr,
field: ^Ident,
}
Index_Expr :: struct {
using node: Expr,
expr: ^Expr,
open: tokenizer.Pos,
index: ^Expr,
close: tokenizer.Pos,
}
Deref_Expr :: struct {
using node: Expr,
expr: ^Expr,
op: tokenizer.Token,
}
Slice_Expr :: struct {
using node: Expr,
expr: ^Expr,
open: tokenizer.Pos,
low: ^Expr,
interval: tokenizer.Token,
high: ^Expr,
close: tokenizer.Pos,
}
Call_Expr :: struct {
using node: Expr,
inlining: Proc_Inlining,
expr: ^Expr,
open: tokenizer.Pos,
args: []^Expr,
ellipsis: tokenizer.Token,
close: tokenizer.Pos,
}
Field_Value :: struct {
using node: Expr,
field: ^Expr,
sep: tokenizer.Pos,
value: ^Expr,
}
Ternary_Expr :: struct {
using node: Expr,
cond: ^Expr,
op1: tokenizer.Token,
x: ^Expr,
op2: tokenizer.Token,
y: ^Expr,
}
Type_Assertion :: struct {
using node: Expr,
expr: ^Expr,
dot: tokenizer.Pos,
open: tokenizer.Pos,
type: ^Expr,
close: tokenizer.Pos,
}
Type_Cast :: struct {
using node: Expr,
tok: tokenizer.Token,
open: tokenizer.Pos,
type: ^Expr,
close: tokenizer.Pos,
expr: ^Expr,
}
Auto_Cast :: struct {
using node: Expr,
op: tokenizer.Token,
expr: ^Expr,
}
// Statements
Bad_Stmt :: struct {
using node: Stmt,
}
Empty_Stmt :: struct {
using node: Stmt,
semicolon: tokenizer.Pos, // Position of the following ';'
}
Expr_Stmt :: struct {
using node: Stmt,
expr: ^Expr,
}
Tag_Stmt :: struct {
using node: Stmt,
op: tokenizer.Token,
name: string,
stmt: ^Stmt,
}
Assign_Stmt :: struct {
using node: Stmt,
lhs: []^Expr,
op: tokenizer.Token,
rhs: []^Expr,
}
Block_Stmt :: struct {
using node: Stmt,
label: ^Expr,
open: tokenizer.Pos,
stmts: []^Stmt,
close: tokenizer.Pos,
}
If_Stmt :: struct {
using node: Stmt,
label: ^Expr,
if_pos: tokenizer.Pos,
init: ^Stmt,
cond: ^Expr,
body: ^Stmt,
else_stmt: ^Stmt,
}
When_Stmt :: struct {
using node: Stmt,
when_pos: tokenizer.Pos,
cond: ^Expr,
body: ^Stmt,
else_stmt: ^Stmt,
}
Return_Stmt :: struct {
using node: Stmt,
results: []^Expr,
}
Defer_Stmt :: struct {
using node: Stmt,
stmt: ^Stmt,
}
For_Stmt :: struct {
using node: Stmt,
label: ^Expr,
for_pos: tokenizer.Pos,
init: ^Stmt,
cond: ^Expr,
post: ^Stmt,
body: ^Stmt,
}
Range_Stmt :: struct {
using node: Stmt,
label: ^Expr,
for_pos: tokenizer.Pos,
val0: ^Expr,
val1: ^Expr,
in_pos: tokenizer.Pos,
expr: ^Expr,
body: ^Stmt,
}
Case_Clause :: struct {
using node: Stmt,
case_pos: tokenizer.Pos,
list: []^Expr,
terminator: tokenizer.Token,
body: []^Stmt,
}
Switch_Stmt :: struct {
using node: Stmt,
label: ^Expr,
switch_pos: tokenizer.Pos,
init: ^Stmt,
cond: ^Expr,
body: ^Stmt,
complete: bool,
}
Type_Switch_Stmt :: struct {
using node: Stmt,
label: ^Expr,
switch_pos: tokenizer.Pos,
tag: ^Stmt,
expr: ^Expr,
body: ^Stmt,
complete: bool,
}
Branch_Stmt :: struct {
using node: Stmt,
tok: tokenizer.Token,
label: ^Ident,
}
Using_Stmt :: struct {
using node: Stmt,
list: []^Expr,
}
// Declarations
Bad_Decl :: struct {
using node: Decl,
}
Value_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
names: []^Expr,
type: ^Expr,
values: []^Expr,
comment: ^Comment_Group,
is_using: bool,
is_mutable: bool,
}
Package_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
token: tokenizer.Token,
name: string,
comment: ^Comment_Group,
}
Import_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
is_using: bool,
import_tok: tokenizer.Token,
name: tokenizer.Token,
relpath: tokenizer.Token,
fullpath: string,
comment: ^Comment_Group,
}
Foreign_Block_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
tok: tokenizer.Token,
foreign_library: ^Expr,
body: ^Stmt,
}
Foreign_Import_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
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) -> (val: ^Expr) {
val = expr;
if expr == nil {
return;
}
for {
e, ok := val.derived.(Paren_Expr);
if !ok do break;
val = e.expr;
}
return;
}
Field_Flag :: enum {
Ellipsis,
Using,
No_Alias,
C_Vararg,
Auto_Cast,
In,
Results,
Tags,
Default_Parameters,
Typeid_Token,
}
Field_Flags :: distinct bit_set[Field_Flag];
Field_Flags_Struct :: Field_Flags{
.Using,
.Tags,
};
Field_Flags_Record_Poly_Params :: Field_Flags{
.Typeid_Token,
};
Field_Flags_Signature :: Field_Flags{
.Ellipsis,
.Using,
.No_Alias,
.C_Vararg,
.Auto_Cast,
.Default_Parameters,
};
Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token};
Field_Flags_Signature_Results :: Field_Flags_Signature;
Proc_Group :: struct {
using node: Expr,
tok: tokenizer.Token,
open: tokenizer.Pos,
args: []^Expr,
close: tokenizer.Pos,
}
Attribute :: struct {
using node: Node,
tok: tokenizer.Token_Kind,
open: tokenizer.Pos,
elems: []^Expr,
close: tokenizer.Pos,
}
Field :: struct {
using node: Node,
docs: ^Comment_Group,
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: tokenizer.Pos,
list: []^Field,
close: tokenizer.Pos,
}
// Types
Typeid_Type :: struct {
using node: Expr,
tok: tokenizer.Token_Kind,
specialization: ^Expr,
}
Helper_Type :: struct {
using node: Expr,
tok: tokenizer.Token_Kind,
type: ^Expr,
}
Distinct_Type :: struct {
using node: Expr,
tok: tokenizer.Token_Kind,
type: ^Expr,
}
Opaque_Type :: struct {
using node: Expr,
tok: tokenizer.Token_Kind,
type: ^Expr,
}
Poly_Type :: struct {
using node: Expr,
dollar: tokenizer.Pos,
type: ^Ident,
specialization: ^Expr,
}
Proc_Type :: struct {
using node: Expr,
tok: tokenizer.Token,
calling_convention: Proc_Calling_Convention,
params: ^Field_List,
arrow: tokenizer.Pos,
results: ^Field_List,
tags: Proc_Tags,
generic: bool,
diverging: bool,
}
Pointer_Type :: struct {
using node: Expr,
pointer: tokenizer.Pos,
elem: ^Expr,
}
Array_Type :: struct {
using node: Expr,
open: tokenizer.Pos,
len: ^Expr, // Ellipsis node for [?]T arrray types, nil for slice types
close: tokenizer.Pos,
elem: ^Expr,
}
Dynamic_Array_Type :: struct {
using node: Expr,
open: tokenizer.Pos,
dynamic_pos: tokenizer.Pos,
close: tokenizer.Pos,
elem: ^Expr,
}
Struct_Type :: struct {
using node: Expr,
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: 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: tokenizer.Pos,
base_type: ^Expr,
open: tokenizer.Pos,
fields: []^Expr,
close: tokenizer.Pos,
is_using: bool,
}
Bit_Field_Type :: struct {
using node: Expr,
tok_pos: tokenizer.Pos,
align: ^Expr,
open: tokenizer.Pos,
fields: []^Field_Value, // Field_Value with ':' rather than '='
close: tokenizer.Pos,
}
Bit_Set_Type :: struct {
using node: Expr,
tok_pos: tokenizer.Pos,
open: tokenizer.Pos,
elem: ^Expr,
underlying: ^Expr,
close: tokenizer.Pos,
}
Map_Type :: struct {
using node: Expr,
tok_pos: tokenizer.Pos,
key: ^Expr,
value: ^Expr,
}
+314
View File
@@ -0,0 +1,314 @@
package odin_ast
import "core:mem"
import "core:fmt"
import "core:odin/tokenizer"
new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
n := mem.new(T);
n.pos = pos;
n.end = end;
n.derived = n^;
base: ^Node = n; // dummy check
_ = base; // "Use" type to make -vet happy
return n;
}
clone :: proc{
clone_node,
clone_expr,
clone_stmt,
clone_decl,
clone_array,
clone_dynamic_array,
};
clone_array :: proc(array: $A/[]^$T) -> A {
if len(array) == 0 {
return nil;
}
res := make(A, len(array));
for elem, i in array {
res[i] = auto_cast clone(elem);
}
return res;
}
clone_dynamic_array :: proc(array: $A/[dynamic]^$T) -> A {
if len(array) == 0 {
return nil;
}
res := make(A, len(array));
for elem, i in array {
res[i] = auto_cast clone(elem);
}
return res;
}
clone_expr :: proc(node: ^Expr) -> ^Expr {
return cast(^Expr)clone_node(node);
}
clone_stmt :: proc(node: ^Stmt) -> ^Stmt {
return cast(^Stmt)clone_node(node);
}
clone_decl :: proc(node: ^Decl) -> ^Decl {
return cast(^Decl)clone_node(node);
}
clone_node :: proc(node: ^Node) -> ^Node {
if node == nil {
return nil;
}
size := size_of(Node);
align := align_of(Node);
ti := type_info_of(node.derived.id);
if ti != nil {
size = ti.size;
align = ti.align;
}
res := cast(^Node)mem.alloc(size, align);
src: rawptr = node;
if node.derived != nil {
src = node.derived.data;
}
mem.copy(res, src, size);
res.derived.data = rawptr(res);
switch n in node.derived {
case Bad_Expr:
case Ident:
case Implicit:
case Undef:
case Basic_Lit:
case Ellipsis:
r := cast(^Ellipsis)res;
r.expr = clone(r.expr);
case Proc_Lit:
r := cast(^Proc_Lit)res;
r.type = auto_cast clone(r.type);
r.body = clone(r.body);
case Comp_Lit:
r := cast(^Comp_Lit)res;
r.type = clone(r.type);
r.elems = clone(r.elems);
case Tag_Expr:
r := cast(^Tag_Expr)res;
r.expr = clone(r.expr);
case Unary_Expr:
r := cast(^Unary_Expr)res;
r.expr = clone(r.expr);
case Binary_Expr:
r := cast(^Binary_Expr)res;
r.left = clone(r.left);
r.right = clone(r.right);
case Paren_Expr:
r := cast(^Paren_Expr)res;
r.expr = clone(r.expr);
case Selector_Expr:
r := cast(^Selector_Expr)res;
r.expr = clone(r.expr);
r.field = auto_cast clone(r.field);
case Index_Expr:
r := cast(^Index_Expr)res;
r.expr = clone(r.expr);
r.index = clone(r.index);
case Deref_Expr:
r := cast(^Deref_Expr)res;
r.expr = clone(r.expr);
case Slice_Expr:
r := cast(^Slice_Expr)res;
r.expr = clone(r.expr);
r.low = clone(r.low);
r.high = clone(r.high);
case Call_Expr:
r := cast(^Call_Expr)res;
r.expr = clone(r.expr);
r.args = clone(r.args);
case Field_Value:
r := cast(^Field_Value)res;
r.field = clone(r.field);
r.value = clone(r.value);
case Ternary_Expr:
r := cast(^Ternary_Expr)res;
r.cond = clone(r.cond);
r.x = clone(r.x);
r.y = clone(r.y);
case Type_Assertion:
r := cast(^Type_Assertion)res;
r.expr = clone(r.expr);
r.type = clone(r.type);
case Type_Cast:
r := cast(^Type_Cast)res;
r.type = clone(r.type);
r.expr = clone(r.expr);
case Auto_Cast:
r := cast(^Auto_Cast)res;
r.expr = clone(r.expr);
case Bad_Stmt:
case Empty_Stmt:
case Expr_Stmt:
r := cast(^Expr_Stmt)res;
r.expr = clone(r.expr);
case Tag_Stmt:
r := cast(^Expr_Stmt)res;
r.expr = clone(r.expr);
case Assign_Stmt:
r := cast(^Assign_Stmt)res;
r.lhs = clone(r.lhs);
r.rhs = clone(r.rhs);
case Block_Stmt:
r := cast(^Block_Stmt)res;
r.label = auto_cast clone(r.label);
r.stmts = clone(r.stmts);
case If_Stmt:
r := cast(^If_Stmt)res;
r.label = auto_cast clone(r.label);
r.init = clone(r.init);
r.cond = clone(r.cond);
r.body = clone(r.body);
r.else_stmt = clone(r.else_stmt);
case When_Stmt:
r := cast(^When_Stmt)res;
r.cond = clone(r.cond);
r.body = clone(r.body);
r.else_stmt = clone(r.else_stmt);
case Return_Stmt:
r := cast(^Return_Stmt)res;
r.results = clone(r.results);
case Defer_Stmt:
r := cast(^Defer_Stmt)res;
r.stmt = clone(r.stmt);
case For_Stmt:
r := cast(^For_Stmt)res;
r.label = auto_cast clone(r.label);
r.init = clone(r.init);
r.cond = clone(r.cond);
r.post = clone(r.post);
r.body = clone(r.body);
case Range_Stmt:
r := cast(^Range_Stmt)res;
r.label = auto_cast clone(r.label);
r.val0 = clone(r.val0);
r.val1 = clone(r.val1);
r.expr = clone(r.expr);
r.body = clone(r.body);
case Case_Clause:
r := cast(^Case_Clause)res;
r.list = clone(r.list);
r.body = clone(r.body);
case Switch_Stmt:
r := cast(^Switch_Stmt)res;
r.label = auto_cast clone(r.label);
r.init = clone(r.init);
r.cond = clone(r.cond);
r.body = clone(r.body);
case Type_Switch_Stmt:
r := cast(^Type_Switch_Stmt)res;
r.label = auto_cast clone(r.label);
r.tag = clone(r.tag);
r.expr = clone(r.expr);
r.body = clone(r.body);
case Branch_Stmt:
r := cast(^Branch_Stmt)res;
r.label = auto_cast clone(r.label);
case Using_Stmt:
r := cast(^Using_Stmt)res;
r.list = clone(r.list);
case Bad_Decl:
case Value_Decl:
r := cast(^Value_Decl)res;
r.attributes = clone(r.attributes);
r.names = clone(r.names);
r.type = clone(r.type);
r.values = clone(r.values);
case Package_Decl:
case Import_Decl:
case Foreign_Block_Decl:
r := cast(^Foreign_Block_Decl)res;
r.attributes = clone(r.attributes);
r.foreign_library = clone(r.foreign_library);
r.body = clone(r.body);
case Foreign_Import_Decl:
r := cast(^Foreign_Import_Decl)res;
r.name = auto_cast clone(r.name);
case Proc_Group:
r := cast(^Proc_Group)res;
r.args = clone(r.args);
case Attribute:
r := cast(^Attribute)res;
r.elems = clone(r.elems);
case Field:
r := cast(^Field)res;
r.names = clone(r.names);
r.type = clone(r.type);
r.default_value = clone(r.default_value);
case Field_List:
r := cast(^Field_List)res;
r.list = clone(r.list);
case Typeid_Type:
r := cast(^Typeid_Type)res;
r.specialization = clone(r.specialization);
case Helper_Type:
r := cast(^Helper_Type)res;
r.type = clone(r.type);
case Distinct_Type:
r := cast(^Distinct_Type)res;
r.type = clone(r.type);
case Opaque_Type:
r := cast(^Opaque_Type)res;
r.type = clone(r.type);
case Poly_Type:
r := cast(^Poly_Type)res;
r.type = auto_cast clone(r.type);
r.specialization = clone(r.specialization);
case Proc_Type:
r := cast(^Proc_Type)res;
r.params = auto_cast clone(r.params);
r.results = auto_cast clone(r.results);
case Pointer_Type:
r := cast(^Pointer_Type)res;
r.elem = clone(r.elem);
case Array_Type:
r := cast(^Array_Type)res;
r.len = clone(r.len);
r.elem = clone(r.elem);
case Dynamic_Array_Type:
r := cast(^Dynamic_Array_Type)res;
r.elem = clone(r.elem);
case Struct_Type:
r := cast(^Struct_Type)res;
r.poly_params = auto_cast clone(r.poly_params);
r.align = clone(r.align);
r.fields = auto_cast clone(r.fields);
case Union_Type:
r := cast(^Union_Type)res;
r.poly_params = auto_cast clone(r.poly_params);
r.align = clone(r.align);
r.variants = clone(r.variants);
case Enum_Type:
r := cast(^Enum_Type)res;
r.base_type = clone(r.base_type);
r.fields = clone(r.fields);
case Bit_Field_Type:
r := cast(^Bit_Field_Type)res;
r.fields = clone(r.fields);
case Bit_Set_Type:
r := cast(^Bit_Set_Type)res;
r.elem = clone(r.elem);
r.underlying = clone(r.underlying);
case Map_Type:
r := cast(^Map_Type)res;
r.key = clone(r.key);
r.value = clone(r.value);
case:
fmt.panicf("Unhandled node kind: %T", n);
}
return res;
}
+40
View File
@@ -0,0 +1,40 @@
package odin_ast
import "core:odin/tokenizer"
Package_Kind :: enum {
Normal,
Runtime,
Init,
}
Package :: struct {
kind: Package_Kind,
id: int,
name: string,
fullpath: string,
files: []^File,
user_data: rawptr,
}
File :: struct {
id: int,
pkg: ^Package,
fullpath: string,
src: []byte,
pkg_decl: ^Package_Decl,
pkg_token: tokenizer.Token,
pkg_name: string,
decls: [dynamic]^Stmt,
imports: [dynamic]^Import_Decl,
directive_count: int,
comments: [dynamic]^Comment_Group,
syntax_warning_count: int,
syntax_error_count: int,
}
File diff suppressed because it is too large Load Diff
+335
View File
@@ -0,0 +1,335 @@
package odin_tokenizer
import "core:strings"
Token :: struct {
kind: Token_Kind,
text: string,
pos: Pos,
}
Pos :: struct {
file: string,
offset: int, // starting at 0
line: int, // starting at 1
column: int, // starting at 1
}
pos_compare :: proc(lhs, rhs: Pos) -> int {
if lhs.offset != rhs.offset {
return (lhs.offset < rhs.offset) ? -1 : +1;
}
if lhs.line != rhs.line {
return (lhs.line < rhs.line) ? -1 : +1;
}
if lhs.column != rhs.column {
return (lhs.column < rhs.column) ? -1 : +1;
}
return strings.compare(lhs.file, rhs.file);
}
Token_Kind :: enum u32 {
Invalid,
EOF,
Comment,
B_Literal_Begin,
Ident,
Integer,
Float,
Imag,
Rune,
String,
B_Literal_End,
B_Operator_Begin,
Eq,
Not,
Hash,
At,
Dollar,
Pointer,
Question,
Add,
Sub,
Mul,
Quo,
Mod,
Mod_Mod,
And,
Or,
Xor,
And_Not,
Shl,
Shr,
Cmp_And,
Cmp_Or,
B_Assign_Op_Begin,
Add_Eq,
Sub_Eq,
Mul_Eq,
Quo_Eq,
Mod_Eq,
Mod_Mod_Eq,
And_Eq,
Or_Eq,
Xor_Eq,
And_Not_Eq,
Shl_Eq,
Shr_Eq,
Cmp_And_Eq,
Cmp_Or_Eq,
B_Assign_Op_End,
Arrow_Right,
Arrow_Left,
Double_Arrow_Right,
Undef,
B_Comparison_Begin,
Cmp_Eq,
Not_Eq,
Lt,
Gt,
Lt_Eq,
Gt_Eq,
B_Comparison_End,
Open_Paren,
Close_Paren,
Open_Bracket,
Close_Bracket,
Open_Brace,
Close_Brace,
Colon,
Semicolon,
Period,
Comma,
Ellipsis,
Range_Half,
Back_Slash,
B_Operator_End,
B_Keyword_Begin,
Import,
Foreign,
Package,
Typeid,
When,
Where,
If,
Else,
For,
Switch,
In,
Notin,
Do,
Case,
Break,
Continue,
Fallthrough,
Defer,
Return,
Proc,
Macro,
Struct,
Union,
Enum,
Bit_Field,
Bit_Set,
Map,
Dynamic,
Auto_Cast,
Cast,
Transmute,
Distinct,
Opaque,
Using,
Inline,
No_Inline,
Context,
Size_Of,
Align_Of,
Offset_Of,
Type_Of,
Const,
B_Keyword_End,
COUNT,
B_Custom_Keyword_Begin = COUNT+1,
// ... Custom keywords
};
tokens := [Token_Kind.COUNT]string {
"Invalid",
"EOF",
"Comment",
"",
"identifier",
"integer",
"float",
"imaginary",
"rune",
"string",
"",
"",
"=",
"!",
"#",
"@",
"$",
"^",
"?",
"+",
"-",
"*",
"/",
"%",
"%%",
"&",
"|",
"~",
"&~",
"<<",
">>",
"&&",
"||",
"",
"+=",
"-=",
"*=",
"/=",
"%=",
"%%=",
"&=",
"|=",
"~=",
"&~=",
"<<=",
">>=",
"&&=",
"||=",
"",
"->",
"<-",
"=>",
"---",
"",
"==",
"!=",
"<",
">",
"<=",
">=",
"",
"(",
")",
"[",
"]",
"{",
"}",
":",
";",
".",
",",
"..",
"..<",
"\\",
"",
"",
"import",
"foreign",
"package",
"typeid",
"when",
"where",
"if",
"else",
"for",
"switch",
"in",
"notin",
"do",
"case",
"break",
"continue",
"fallthrough",
"defer",
"return",
"proc",
"macro",
"struct",
"union",
"enum",
"bit_field",
"bit_set",
"map",
"dynamic",
"auto_cast",
"cast",
"transmute",
"distinct",
"opaque",
"using",
"inline",
"no_inline",
"context",
"size_of",
"align_of",
"offset_of",
"type_of",
"const",
"",
};
custom_keyword_tokens: []string;
to_string :: proc(kind: Token_Kind) -> string {
if Token_Kind.Invalid <= kind && kind < Token_Kind.COUNT {
return tokens[kind];
}
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];
}
}
return "Invalid";
}
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:
return true;
case .In, .Notin:
return true;
}
return false;
}
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: Token_Kind) -> bool {
switch {
case Token_Kind.B_Keyword_Begin < kind && kind < Token_Kind.B_Keyword_End:
return true;
case Token_Kind.B_Custom_Keyword_Begin < kind:
return true;
}
return false;
}
+622
View File
@@ -0,0 +1,622 @@
package odin_tokenizer
import "core:fmt"
import "core:unicode/utf8"
Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any);
Tokenizer :: struct {
// Immutable data
path: string,
src: []byte,
err: Error_Handler,
// Tokenizing state
ch: rune,
offset: int,
read_offset: int,
line_offset: int,
line_count: int,
// Mutable data
error_count: int,
}
init :: proc(t: ^Tokenizer, src: []byte, path: string, err: Error_Handler = default_error_handler) {
t.src = src;
t.err = err;
t.ch = ' ';
t.offset = 0;
t.read_offset = 0;
t.line_offset = 0;
t.line_count = len(src) > 0 ? 1 : 0;
t.error_count = 0;
t.path = path;
advance_rune(t);
if t.ch == utf8.RUNE_BOM {
advance_rune(t);
}
}
@(private)
offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos {
line := t.line_count;
column := offset - t.line_offset + 1;
return Pos {
file = t.path,
offset = offset,
line = line,
column = column,
};
}
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) {
pos := offset_to_pos(t, offset);
if t.err != nil {
t.err(pos, msg, ..args);
}
t.error_count += 1;
}
advance_rune :: proc(using t: ^Tokenizer) {
if read_offset < len(src) {
offset = read_offset;
if ch == '\n' {
line_offset = offset;
line_count += 1;
}
r, w := rune(src[read_offset]), 1;
switch {
case r == 0:
error(t, t.offset, "illegal character NUL");
case r >= utf8.RUNE_SELF:
r, w = utf8.decode_rune(src[read_offset:]);
if r == utf8.RUNE_ERROR && w == 1 {
error(t, t.offset, "illegal UTF-8 encoding");
} else if r == utf8.RUNE_BOM && offset > 0 {
error(t, t.offset, "illegal byte order mark");
}
}
read_offset += w;
ch = r;
} else {
offset = len(src);
if ch == '\n' {
line_offset = offset;
line_count += 1;
}
ch = -1;
}
}
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;
}
skip_whitespace :: proc(t: ^Tokenizer) {
for t.ch == ' ' ||
t.ch == '\t' ||
t.ch == '\n' ||
t.ch == '\r' {
advance_rune(t);
}
}
is_letter :: proc(r: rune) -> bool {
if r < utf8.RUNE_SELF {
switch r {
case '_':
return true;
case 'A'..'Z', 'a'..'z':
return true;
}
}
// TODO(bill): Add unicode lookup tables
return false;
}
is_digit :: proc(r: rune) -> bool {
// TODO(bill): Add unicode lookup tables
return '0' <= r && r <= '9';
}
scan_comment :: proc(t: ^Tokenizer) -> string {
offset := t.offset-1;
next := -1;
general: {
if t.ch == '/' || t.ch == '!' { // // #! comments
advance_rune(t);
for t.ch != '\n' && t.ch >= 0 {
advance_rune(t);
}
next = t.offset;
if t.ch == '\n' {
next += 1;
}
break general;
}
/* style comment */
advance_rune(t);
for t.ch >= 0 {
ch := t.ch;
advance_rune(t);
if ch == '*' && t.ch == '/' {
advance_rune(t);
next = t.offset;
break general;
}
}
error(t, offset, "comment not terminated");
}
lit := t.src[offset : t.offset];
// NOTE(bill): Strip CR for line comments
for len(lit) > 2 && lit[1] == '/' && lit[len(lit)-1] == '\r' {
lit = lit[:len(lit)-1];
}
return string(lit);
}
scan_identifier :: proc(t: ^Tokenizer) -> string {
offset := t.offset;
for is_letter(t.ch) || is_digit(t.ch) {
advance_rune(t);
}
return string(t.src[offset : t.offset]);
}
scan_string :: proc(t: ^Tokenizer) -> string {
offset := t.offset-1;
for {
ch := t.ch;
if ch == '\n' || ch < 0 {
error(t, offset, "string literal was not terminated");
break;
}
advance_rune(t);
if ch == '"' {
break;
}
if ch == '\\' {
scan_escape(t);
}
}
return string(t.src[offset : t.offset]);
}
scan_raw_string :: proc(t: ^Tokenizer) -> string {
offset := t.offset-1;
for {
ch := t.ch;
if ch == '\n' || ch < 0 {
error(t, offset, "raw string literal was not terminated");
break;
}
advance_rune(t);
if ch == '`' {
break;
}
}
return string(t.src[offset : t.offset]);
}
digit_val :: proc(r: rune) -> int {
switch r {
case '0'..'9':
return int(r-'0');
case 'A'..'F':
return int(r-'A' + 10);
case 'a'..'f':
return int(r-'a' + 10);
}
return 16;
}
scan_escape :: proc(t: ^Tokenizer) -> bool {
offset := t.offset;
n: int;
base, max: u32;
switch t.ch {
case 'a', 'b', 'e', 'f', 'n', 't', 'v', '\\', '\'', '\"':
advance_rune(t);
return true;
case '0'..'7':
n, base, max = 3, 8, 255;
case 'x':
advance_rune(t);
n, base, max = 2, 16, 255;
case 'u':
advance_rune(t);
n, base, max = 4, 16, utf8.MAX_RUNE;
case 'U':
advance_rune(t);
n, base, max = 8, 16, utf8.MAX_RUNE;
case:
if t.ch < 0 {
error(t, offset, "escape sequence was not terminated");
} else {
error(t, offset, "unknown escape sequence");
}
return false;
}
x: u32;
for n > 0 {
d := u32(digit_val(t.ch));
for d >= base {
if t.ch < 0 {
error(t, t.offset, "escape sequence was not terminated");
} else {
error(t, t.offset, "illegal character %d in escape sequence", t.ch);
}
return false;
}
x = x*base + d;
advance_rune(t);
n -= 1;
}
if x > max || 0xd800 <= x && x <= 0xe000 {
error(t, offset, "escape sequence is an invalid Unicode code point");
return false;
}
return true;
}
scan_rune :: proc(t: ^Tokenizer) -> string {
offset := t.offset-1;
valid := true;
n := 0;
for {
ch := t.ch;
if ch == '\n' || ch < 0 {
if valid {
error(t, offset, "rune literal not terminated");
valid = false;
}
break;
}
advance_rune(t);
if ch == '\'' {
break;
}
n += 1;
if ch == '\\' {
if !scan_escape(t) {
valid = false;
}
}
}
if valid && n != 1 {
error(t, offset, "illegal rune literal");
}
return string(t.src[offset : t.offset]);
}
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) {
if t.ch == 'e' || t.ch == 'E' {
kind^ = .Float;
advance_rune(t);
if t.ch == '-' || t.ch == '+' {
advance_rune(t);
}
if digit_val(t.ch) < 10 {
scan_mantissa(t, 10);
} else {
error(t, t.offset, "illegal floating-point exponent");
}
}
// NOTE(bill): This needs to be here for sanity's sake
switch t.ch {
case 'i', 'j', 'k':
kind^ = .Imag;
advance_rune(t);
}
}
scan_fraction :: proc(t: ^Tokenizer, kind: ^Token_Kind) -> (early_exit: bool) {
if t.ch == '.' && peek_byte(t) == '.' {
return true;
}
if t.ch == '.' {
kind^ = .Float;
advance_rune(t);
scan_mantissa(t, 10);
}
return false;
}
offset := t.offset;
kind := Token_Kind.Integer;
seen_point := seen_decimal_point;
if seen_point {
offset -= 1;
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) {
prev := t.offset;
advance_rune(t);
scan_mantissa(t, base);
if t.offset - prev <= 1 {
kind^ = .Invalid;
error(t, t.offset, msg);
}
}
advance_rune(t);
switch t.ch {
case 'b': int_base(t, &kind, 2, "illegal binary integer");
case 'o': int_base(t, &kind, 8, "illegal octal integer");
case 'd': int_base(t, &kind, 10, "illegal decimal integer");
case 'z': int_base(t, &kind, 12, "illegal dozenal integer");
case 'x': int_base(t, &kind, 16, "illegal hexadecimal integer");
case 'h':
prev := t.offset;
advance_rune(t);
scan_mantissa(t, 16);
if t.offset - prev <= 1 {
kind = .Invalid;
error(t, t.offset, "illegal hexadecimal floating-point number");
} else {
sub := t.src[prev+1 : t.offset];
digit_count := 0;
for d in sub {
if d != '_' {
digit_count += 1;
}
}
switch digit_count {
case 8, 16: break;
case:
error(t, t.offset, "invalid hexadecimal floating-point number, expected 8 or 16 digits, got %d", digit_count);
}
}
case:
seen_point = false;
scan_mantissa(t, 10);
if t.ch == '.' {
seen_point = true;
if scan_fraction(t, &kind) {
return kind, string(t.src[offset : t.offset]);
}
}
scan_exponent(t, &kind);
return kind, string(t.src[offset : t.offset]);
}
}
}
scan_mantissa(t, 10);
if scan_fraction(t, &kind) {
return kind, string(t.src[offset : t.offset]);
}
scan_exponent(t, &kind);
return kind, string(t.src[offset : t.offset]);
}
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 {
if t.ch == '=' {
advance_rune(t);
return tok1;
}
if t.ch == ch2 {
advance_rune(t);
return tok2;
}
return tok0;
}
switch4 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2, tok3: Token_Kind) -> Token_Kind {
if t.ch == '=' {
advance_rune(t);
return tok1;
}
if t.ch == ch2 {
advance_rune(t);
if t.ch == '=' {
advance_rune(t);
return tok3;
}
return tok2;
}
return tok0;
}
skip_whitespace(t);
offset := t.offset;
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 = .Ident;
check_keyword: if len(lit) > 1 {
// TODO(bill): Maybe have a hash table lookup rather than this linear search
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 custom_keyword_tokens {
if lit == keyword {
kind = Token_Kind(i+1) + .B_Custom_Keyword_Begin;
break check_keyword;
}
}
}
case '0' <= ch && ch <= '9':
kind, lit = scan_number(t, false);
case:
advance_rune(t);
switch ch {
case -1:
kind = .EOF;
case '"':
kind = .String;
lit = scan_string(t);
case '\'':
kind = .Rune;
lit = scan_rune(t);
case '`':
kind = .String;
lit = scan_raw_string(t);
case '=':
if t.ch == '>' {
advance_rune(t);
kind = .Double_Arrow_Right;
} else {
kind = switch2(t, .Eq, .Cmp_Eq);
}
case '!': kind = switch2(t, .Not, .Not_Eq);
case '#':
kind = .Hash;
if t.ch == '!' {
kind = .Comment;
lit = scan_comment(t);
}
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 = .Arrow_Right;
} else if t.ch == '-' && peek_byte(t) == '-' {
advance_rune(t);
advance_rune(t);
kind = .Undef;
} else {
kind = switch2(t, .Sub, .Sub_Eq);
}
case '*': kind = switch2(t, .Mul, .Mul_Eq);
case '/':
if t.ch == '/' || t.ch == '*' {
kind = .Comment;
lit = scan_comment(t);
} else {
kind = switch2(t, .Quo, .Quo_Eq);
}
case '%': kind = switch4(t, .Mod, .Mod_Eq, '%', .Mod_Mod, .Mod_Mod_Eq);
case '&':
if t.ch == '~' {
advance_rune(t);
kind = switch2(t, .And_Not, .And_Not_Eq);
} else {
kind = switch3(t, .And, .And_Eq, '&', .Cmp_And);
}
case '|': kind = switch3(t, .Or, .Or_Eq, '|', .Cmp_Or);
case '~': kind = .Xor;
case '<':
if t.ch == '-' {
advance_rune(t);
kind = .Arrow_Left;
} else {
kind = switch4(t, .Lt, .Lt_Eq, '<', .Shl, .Shl_Eq);
}
case '>': kind = switch4(t, .Gt, .Gt_Eq, '>', .Shr,.Shr_Eq);
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 = .Period;
if t.ch == '.' {
advance_rune(t);
kind = .Ellipsis;
if t.ch == '<' {
advance_rune(t);
kind = .Range_Half;
}
}
}
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 = .Back_Slash;
case:
if ch != utf8.RUNE_BOM {
error(t, t.offset, "illegal character '%r': %d", ch, ch);
}
kind = .Invalid;
}
}
if lit == "" {
lit = string(t.src[offset : t.offset]);
}
return Token{kind, lit, pos};
}
-176
View File
@@ -1,176 +0,0 @@
foreign_system_library (
lib "opengl32.lib" when ODIN_OS == "windows";
lib "gl" when ODIN_OS == "linux";
)
import (
win32 "sys/windows.odin" when ODIN_OS == "windows";
"sys/wgl.odin" when ODIN_OS == "windows";
)
import_load "opengl_constants.odin";
foreign lib {
proc Clear (mask: u32) #link_name "glClear";
proc ClearColor (r, g, b, a: f32) #link_name "glClearColor";
proc Begin (mode: i32) #link_name "glBegin";
proc End () #link_name "glEnd";
proc Finish () #link_name "glFinish";
proc BlendFunc (sfactor, dfactor: i32) #link_name "glBlendFunc";
proc Enable (cap: i32) #link_name "glEnable";
proc Disable (cap: i32) #link_name "glDisable";
proc GenTextures (count: i32, result: ^u32) #link_name "glGenTextures";
proc DeleteTextures(count: i32, result: ^u32) #link_name "glDeleteTextures";
proc TexParameteri (target, pname, param: i32) #link_name "glTexParameteri";
proc TexParameterf (target: i32, pname: i32, param: f32) #link_name "glTexParameterf";
proc BindTexture (target: i32, texture: u32) #link_name "glBindTexture";
proc LoadIdentity () #link_name "glLoadIdentity";
proc Viewport (x, y, width, height: i32) #link_name "glViewport";
proc Ortho (left, right, bottom, top, near, far: f64) #link_name "glOrtho";
proc Color3f (r, g, b: f32) #link_name "glColor3f";
proc Vertex3f (x, y, z: f32) #link_name "glVertex3f";
proc GetError () -> i32 #link_name "glGetError";
proc GetString (name: i32) -> ^u8 #link_name "glGetString";
proc GetIntegerv (name: i32, v: ^i32) #link_name "glGetIntegerv";
proc TexCoord2f (x, y: f32) #link_name "glTexCoord2f";
proc TexImage2D (target, level, internal_format,
width, height, border,
format, type_: i32, pixels: rawptr) #link_name "glTexImage2D";
}
proc _string_data(s: string) -> ^u8 #inline { return &s[0]; }
var _libgl = win32.load_library_a(_string_data("opengl32.dll\x00"));
proc get_proc_address(name: string) -> rawptr {
if name[len(name)-1] == 0 {
name = name[0..<len(name)-1];
}
// NOTE(bill): null terminated
assert((&name[0] + len(name))^ == 0);
var res = wgl.get_proc_address(&name[0]);
if res == nil {
res = win32.get_proc_address(_libgl, &name[0]);
}
return rawptr(res);
}
var (
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
DeleteBuffers: proc(count: i32, buffers: ^u32) #cc_c;
BindBuffer: proc(target: i32, buffer: u32) #cc_c;
BindVertexArray: proc(buffer: u32) #cc_c;
DeleteVertexArrays: proc(count: i32, arrays: ^u32) #cc_c;
BindSampler: proc(position: i32, sampler: u32) #cc_c;
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c;
BufferSubData: proc(target: i32, offset, size: int, data: rawptr) #cc_c;
DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
MapBuffer: proc(target, access: i32) -> rawptr #cc_c;
UnmapBuffer: proc(target: i32) #cc_c;
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c;
EnableVertexAttribArray: proc(index: u32) #cc_c;
CreateShader: proc(shader_type: i32) -> u32 #cc_c;
ShaderSource: proc(shader: u32, count: u32, str: ^^u8, length: ^i32) #cc_c;
CompileShader: proc(shader: u32) #cc_c;
CreateProgram: proc() -> u32 #cc_c;
AttachShader: proc(program, shader: u32) #cc_c;
DetachShader: proc(program, shader: u32) #cc_c;
DeleteShader: proc(shader: u32) #cc_c;
LinkProgram: proc(program: u32) #cc_c;
UseProgram: proc(program: u32) #cc_c;
DeleteProgram: proc(program: u32) #cc_c;
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c;
GetProgramiv: proc(program: u32, pname: i32, params: ^i32) #cc_c;
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^u8) #cc_c;
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^u8) #cc_c;
ActiveTexture: proc(texture: i32) #cc_c;
GenerateMipmap: proc(target: i32) #cc_c;
SamplerParameteri: proc(sampler: u32, pname: i32, param: i32) #cc_c;
SamplerParameterf: proc(sampler: u32, pname: i32, param: f32) #cc_c;
SamplerParameteriv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterfv: proc(sampler: u32, pname: i32, params: ^f32) #cc_c;
SamplerParameterIiv: proc(sampler: u32, pname: i32, params: ^i32) #cc_c;
SamplerParameterIuiv: proc(sampler: u32, pname: i32, params: ^u32) #cc_c;
Uniform1i: proc(loc: i32, v0: i32) #cc_c;
Uniform2i: proc(loc: i32, v0, v1: i32) #cc_c;
Uniform3i: proc(loc: i32, v0, v1, v2: i32) #cc_c;
Uniform4i: proc(loc: i32, v0, v1, v2, v3: i32) #cc_c;
Uniform1f: proc(loc: i32, v0: f32) #cc_c;
Uniform2f: proc(loc: i32, v0, v1: f32) #cc_c;
Uniform3f: proc(loc: i32, v0, v1, v2: f32) #cc_c;
Uniform4f: proc(loc: i32, v0, v1, v2, v3: f32) #cc_c;
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
GetUniformLocation: proc(program: u32, name: ^u8) -> i32 #cc_c;
)
proc init() {
proc set_proc_address(p: rawptr, name: string) #inline {
var x = ^rawptr(p);
x^ = get_proc_address(name);
}
set_proc_address(&GenBuffers, "glGenBuffers\x00");
set_proc_address(&GenVertexArrays, "glGenVertexArrays\x00");
set_proc_address(&GenSamplers, "glGenSamplers\x00");
set_proc_address(&DeleteBuffers, "glDeleteBuffers\x00");
set_proc_address(&BindBuffer, "glBindBuffer\x00");
set_proc_address(&BindSampler, "glBindSampler\x00");
set_proc_address(&BindVertexArray, "glBindVertexArray\x00");
set_proc_address(&DeleteVertexArrays, "glDeleteVertexArrays\x00");
set_proc_address(&BufferData, "glBufferData\x00");
set_proc_address(&BufferSubData, "glBufferSubData\x00");
set_proc_address(&DrawArrays, "glDrawArrays\x00");
set_proc_address(&DrawElements, "glDrawElements\x00");
set_proc_address(&MapBuffer, "glMapBuffer\x00");
set_proc_address(&UnmapBuffer, "glUnmapBuffer\x00");
set_proc_address(&VertexAttribPointer, "glVertexAttribPointer\x00");
set_proc_address(&EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
set_proc_address(&CreateShader, "glCreateShader\x00");
set_proc_address(&ShaderSource, "glShaderSource\x00");
set_proc_address(&CompileShader, "glCompileShader\x00");
set_proc_address(&CreateProgram, "glCreateProgram\x00");
set_proc_address(&AttachShader, "glAttachShader\x00");
set_proc_address(&DetachShader, "glDetachShader\x00");
set_proc_address(&DeleteShader, "glDeleteShader\x00");
set_proc_address(&LinkProgram, "glLinkProgram\x00");
set_proc_address(&UseProgram, "glUseProgram\x00");
set_proc_address(&DeleteProgram, "glDeleteProgram\x00");
set_proc_address(&GetShaderiv, "glGetShaderiv\x00");
set_proc_address(&GetProgramiv, "glGetProgramiv\x00");
set_proc_address(&GetShaderInfoLog, "glGetShaderInfoLog\x00");
set_proc_address(&GetProgramInfoLog, "glGetProgramInfoLog\x00");
set_proc_address(&ActiveTexture, "glActiveTexture\x00");
set_proc_address(&GenerateMipmap, "glGenerateMipmap\x00");
set_proc_address(&Uniform1i, "glUniform1i\x00");
set_proc_address(&UniformMatrix4fv, "glUniformMatrix4fv\x00");
set_proc_address(&GetUniformLocation, "glGetUniformLocation\x00");
set_proc_address(&SamplerParameteri, "glSamplerParameteri\x00");
set_proc_address(&SamplerParameterf, "glSamplerParameterf\x00");
set_proc_address(&SamplerParameteriv, "glSamplerParameteriv\x00");
set_proc_address(&SamplerParameterfv, "glSamplerParameterfv\x00");
set_proc_address(&SamplerParameterIiv, "glSamplerParameterIiv\x00");
set_proc_address(&SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
}
File diff suppressed because it is too large Load Diff
-49
View File
@@ -1,49 +0,0 @@
import_load (
"os_windows.odin" when ODIN_OS == "windows";
"os_x.odin" when ODIN_OS == "osx";
"os_linux.odin" when ODIN_OS == "linux";
)
proc write_string(fd: Handle, str: string) -> (int, Errno) {
return write(fd, []u8(str));
}
proc read_entire_file(name: string) -> ([]u8, bool) {
var fd, err = open(name, O_RDONLY, 0);
if err != 0 {
return nil, false;
}
defer close(fd);
var length: i64;
if length, err = file_size(fd); err != 0 {
return nil, false;
}
if length == 0 {
return nil, true;
}
var data = make([]u8, length);
if data == nil {
return nil, false;
}
var bytes_read, read_err = read(fd, data);
if read_err != 0 {
free(data);
return nil, false;
}
return data[0..<bytes_read], true;
}
proc write_entire_file(name: string, data: []u8) -> bool {
var fd, err = open(name, O_WRONLY, 0);
if err != 0 {
return false;
}
defer close(fd);
var bytes_written, write_err = write(fd, data);
return write_err != 0;
}
+154
View File
@@ -0,0 +1,154 @@
package os
import "core:mem"
import "core:strconv"
import "core:unicode/utf8"
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
return write(fd, cast([]byte)str);
}
write_byte :: proc(fd: Handle, b: byte) -> (int, Errno) {
return write(fd, []byte{b});
}
write_rune :: proc(fd: Handle, r: rune) -> (int, Errno) {
if r < utf8.RUNE_SELF {
return write_byte(fd, byte(r));
}
b, n := utf8.encode_rune(r);
return write(fd, b[:n]);
}
write_encoded_rune :: proc(fd: Handle, r: rune) {
write_byte(fd, '\'');
switch r {
case '\a': write_string(fd, "\\a");
case '\b': write_string(fd, "\\b");
case '\e': write_string(fd, "\\e");
case '\f': write_string(fd, "\\f");
case '\n': write_string(fd, "\\n");
case '\r': write_string(fd, "\\r");
case '\t': write_string(fd, "\\t");
case '\v': write_string(fd, "\\v");
case:
if r < 32 {
write_string(fd, "\\x");
b: [2]byte;
s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil);
switch len(s) {
case 0: write_string(fd, "00");
case 1: write_rune(fd, '0');
case 2: write_string(fd, s);
}
} else {
write_rune(fd, r);
}
}
write_byte(fd, '\'');
}
file_size_from_path :: proc(path: string) -> i64 {
fd, err := open(path, O_RDONLY, 0);
if err != 0 {
return -1;
}
defer close(fd);
length: i64;
if length, err = file_size(fd); err != 0 {
return -1;
}
return length;
}
read_entire_file :: proc(name: string) -> (data: []byte, success: bool) {
fd, err := open(name, O_RDONLY, 0);
if err != 0 {
return nil, false;
}
defer close(fd);
length: i64;
if length, err = file_size(fd); err != 0 {
return nil, false;
}
if length <= 0 {
return nil, true;
}
data = make([]byte, int(length));
if data == nil {
return nil, false;
}
bytes_read, read_err := read(fd, data);
if read_err != 0 {
delete(data);
return nil, false;
}
return data[0:bytes_read], true;
}
write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (success: bool) {
flags: int = O_WRONLY|O_CREATE;
if truncate {
flags |= O_TRUNC;
}
fd, err := open(name, flags, 0);
if err != 0 {
return false;
}
defer close(fd);
_, write_err := write(fd, data);
return write_err == 0;
}
write_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
s := transmute([]byte)mem.Raw_Slice{data, len};
return write(fd, s);
}
read_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
s := transmute([]byte)mem.Raw_Slice{data, len};
return read(fd, s);
}
heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
switch mode {
case .Alloc:
return heap_alloc(size);
case .Free:
heap_free(old_memory);
return nil;
case .Free_All:
// NOTE(bill): Does nothing
case .Resize:
if old_memory == nil {
return heap_alloc(size);
}
ptr := heap_resize(old_memory, size);
assert(ptr != nil);
return ptr;
}
return nil;
}
heap_allocator :: proc() -> mem.Allocator {
return mem.Allocator{
procedure = heap_allocator_proc,
data = nil,
};
}
+4
View File
@@ -0,0 +1,4 @@
package os;
ARCH :: "x86";
ENDIAN :: "little";
+4
View File
@@ -0,0 +1,4 @@
package os;
ARCH :: "amd64";
ENDIAN :: "little";
+294
View File
@@ -0,0 +1,294 @@
package os
foreign import dl "system:dl"
foreign import libc "system:c"
import "core:runtime"
import "core:strings"
OS :: "darwin";
Handle :: distinct i32;
File_Time :: distinct u64;
Errno :: distinct int;
INVALID_HANDLE :: ~Handle(0);
O_RDONLY :: 0x00000;
O_WRONLY :: 0x00001;
O_RDWR :: 0x00002;
O_CREATE :: 0x00040;
O_EXCL :: 0x00080;
O_NOCTTY :: 0x00100;
O_TRUNC :: 0x00200;
O_NONBLOCK :: 0x00800;
O_APPEND :: 0x00400;
O_SYNC :: 0x01000;
O_ASYNC :: 0x02000;
O_CLOEXEC :: 0x80000;
SEEK_SET :: 0;
SEEK_CUR :: 1;
SEEK_END :: 2;
SEEK_DATA :: 3;
SEEK_HOLE :: 4;
SEEK_MAX :: SEEK_HOLE;
// NOTE(zangent): These are OS specific!
// Do not mix these up!
RTLD_LAZY :: 0x1;
RTLD_NOW :: 0x2;
RTLD_LOCAL :: 0x4;
RTLD_GLOBAL :: 0x8;
RTLD_NODELETE :: 0x80;
RTLD_NOLOAD :: 0x10;
RTLD_FIRST :: 0x100;
// "Argv" arguments converted to Odin strings
args := _alloc_command_line_arguments();
_File_Time :: struct {
seconds: i64,
nanoseconds: i64,
}
Stat :: struct {
device_id: i32, // ID of device containing file
mode: u16, // Mode of the file
nlink: u16, // Number of hard links
serial: u64, // File serial number
uid: u32, // User ID of the file's owner
gid: u32, // Group ID of the file's group
rdev: i32, // Device ID, if device
last_access: File_Time, // Time of last access
modified: File_Time, // Time of last modification
status_change: File_Time, // Time of last status change
created: File_Time, // Time of creation
size: i64, // Size of the file, in bytes
blocks: i64, // Number of blocks allocated for the file
block_size: i32, // Optimal blocksize for I/O
flags: u32, // User-defined flags for the file
gen_num: u32, // File generation number ..?
_spare: i32, // RESERVED
_reserve1,
_reserve2: i64, // RESERVED
};
// File type
S_IFMT :: 0o170000; // Type of file mask
S_IFIFO :: 0o010000; // Named pipe (fifo)
S_IFCHR :: 0o020000; // Character special
S_IFDIR :: 0o040000; // Directory
S_IFBLK :: 0o060000; // Block special
S_IFREG :: 0o100000; // Regular
S_IFLNK :: 0o120000; // Symbolic link
S_IFSOCK :: 0o140000; // Socket
// File mode
// Read, write, execute/search by owner
S_IRWXU :: 0o0700; // RWX mask for owner
S_IRUSR :: 0o0400; // R for owner
S_IWUSR :: 0o0200; // W for owner
S_IXUSR :: 0o0100; // X for owner
// Read, write, execute/search by group
S_IRWXG :: 0o0070; // RWX mask for group
S_IRGRP :: 0o0040; // R for group
S_IWGRP :: 0o0020; // W for group
S_IXGRP :: 0o0010; // X for group
// Read, write, execute/search by others
S_IRWXO :: 0o0007; // RWX mask for other
S_IROTH :: 0o0004; // R for other
S_IWOTH :: 0o0002; // W for other
S_IXOTH :: 0o0001; // X for other
S_ISUID :: 0o4000; // Set user id on execution
S_ISGID :: 0o2000; // Set group id on execution
S_ISVTX :: 0o1000; // Directory restrcted delete
S_ISLNK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK;
S_ISREG :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG;
S_ISDIR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR;
S_ISCHR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR;
S_ISBLK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK;
S_ISFIFO :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO;
S_ISSOCK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK;
R_OK :: 4; // Test for read permission
W_OK :: 2; // Test for write permission
X_OK :: 1; // Test for execute permission
F_OK :: 0; // Test for file existance
foreign libc {
@(link_name="open") _unix_open :: proc(path: cstring, flags: int, #c_vararg mode: ..any) -> Handle ---;
@(link_name="close") _unix_close :: proc(handle: Handle) ---;
@(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---;
@(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---;
@(link_name="lseek") _unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int ---;
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---;
@(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^Stat) -> int ---;
@(link_name="access") _unix_access :: proc(path: cstring, mask: int) -> int ---;
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---;
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---;
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---;
@(link_name="exit") _unix_exit :: proc(status: int) ---;
}
foreign dl {
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: int) -> rawptr ---;
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---;
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---;
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---;
}
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
cstr := strings.clone_to_cstring(path);
handle := _unix_open(cstr, flags, mode);
delete(cstr);
if handle == -1 {
return INVALID_HANDLE, 1;
}
return handle, 0;
}
close :: proc(fd: Handle) {
_unix_close(fd);
}
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
assert(fd != -1);
bytes_written := _unix_write(fd, &data[0], len(data));
if(bytes_written == -1) {
return 0, 1;
}
return bytes_written, 0;
}
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
assert(fd != -1);
bytes_read := _unix_read(fd, &data[0], len(data));
if bytes_read == -1 {
return 0, 1;
}
return bytes_read, 0;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
assert(fd != -1);
final_offset := i64(_unix_lseek(fd, int(offset), whence));
if final_offset == -1 {
return 0, 1;
}
return final_offset, 0;
}
file_size :: proc(fd: Handle) -> (i64, Errno) {
prev, _ := seek(fd, 0, SEEK_CUR);
size, err := seek(fd, 0, SEEK_END);
seek(fd, prev, SEEK_SET);
return i64(size), err;
}
// NOTE(bill): Uses startup to initialize it
stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE);
stdout: Handle = 1; // get_std_handle(win32.STD_OUTPUT_HANDLE);
stderr: Handle = 2; // get_std_handle(win32.STD_ERROR_HANDLE);
/* TODO(zangent): Implement these!
last_write_time :: proc(fd: Handle) -> File_Time {}
last_write_time_by_name :: proc(name: string) -> File_Time {}
*/
is_path_separator :: proc(r: rune) -> bool {
return r == '/';
}
stat :: inline proc(path: string) -> (Stat, bool) {
s: Stat;
cstr := strings.clone_to_cstring(path);
defer delete(cstr);
ret_int := _unix_stat(cstr, &s);
return s, ret_int==0;
}
access :: inline proc(path: string, mask: int) -> bool {
cstr := strings.clone_to_cstring(path);
defer delete(cstr);
return _unix_access(cstr, mask) == 0;
}
heap_alloc :: inline proc(size: int) -> rawptr {
assert(size > 0);
return _unix_calloc(1, size);
}
heap_resize :: inline proc(ptr: rawptr, new_size: int) -> rawptr {
return _unix_realloc(ptr, new_size);
}
heap_free :: inline proc(ptr: rawptr) {
_unix_free(ptr);
}
getenv :: proc(name: string) -> (string, bool) {
path_str := strings.clone_to_cstring(name);
defer delete(path_str);
cstr := _unix_getenv(path_str);
if cstr == nil {
return "", false;
}
return string(cstr), true;
}
exit :: inline proc(code: int) -> ! {
_unix_exit(code);
}
current_thread_id :: proc "contextless" () -> int {
// return int(_unix_gettid());
return 0;
}
dlopen :: inline proc(filename: string, flags: int) -> rawptr {
cstr := strings.clone_to_cstring(filename);
defer delete(cstr);
handle := _unix_dlopen(cstr, flags);
return handle;
}
dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
assert(handle != nil);
cstr := strings.clone_to_cstring(symbol);
defer delete(cstr);
proc_handle := _unix_dlsym(handle, cstr);
return proc_handle;
}
dlclose :: inline proc(handle: rawptr) -> bool {
assert(handle != nil);
return _unix_dlclose(handle) == 0;
}
dlerror :: proc() -> string {
return string(_unix_dlerror());
}
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__));
for arg, i in runtime.args__ {
res[i] = string(arg);
}
return res;
}
File diff suppressed because it is too large Load Diff
+400
View File
@@ -0,0 +1,400 @@
package os
foreign import dl "system:dl"
foreign import libc "system:c"
import "core:runtime"
import "core:strings"
OS :: "linux";
Handle :: distinct i32;
File_Time :: distinct u64;
Errno :: distinct i32;
Syscall :: distinct int;
INVALID_HANDLE :: ~Handle(0);
ERROR_NONE: Errno : 0;
EPERM: Errno : 1;
ENOENT: Errno : 2;
EINTR: Errno : 4;
EIO: Errno : 5;
ENXIO: Errno : 6;
EBADF: Errno : 9;
EAGAIN: Errno : 11;
EWOULDBLOCK: Errno : EAGAIN;
ENOMEM: Errno : 12;
EACCES: Errno : 13;
EFAULT: Errno : 14;
EEXIST: Errno : 17;
ENODEV: Errno : 19;
ENOTDIR: Errno : 20;
EISDIR: Errno : 21;
EINVAL: Errno : 22;
ENFILE: Errno : 23;
EMFILE: Errno : 24;
ETXTBSY: Errno : 26;
EFBIG: Errno : 27;
ENOSPC: Errno : 28;
ESPIPE: Errno : 29;
EROFS: Errno : 30;
EPIPE: Errno : 32;
ENAMETOOLONG: Errno : 36;
ELOOP: Errno : 40;
EOVERFLOW: Errno : 75;
EDESTADDRREQ: Errno : 89;
EOPNOTSUPP: Errno : 95;
EDQUOT: Errno : 122;
O_RDONLY :: 0x00000;
O_WRONLY :: 0x00001;
O_RDWR :: 0x00002;
O_CREATE :: 0x00040;
O_EXCL :: 0x00080;
O_NOCTTY :: 0x00100;
O_TRUNC :: 0x00200;
O_NONBLOCK :: 0x00800;
O_APPEND :: 0x00400;
O_SYNC :: 0x01000;
O_ASYNC :: 0x02000;
O_CLOEXEC :: 0x80000;
SEEK_SET :: 0;
SEEK_CUR :: 1;
SEEK_END :: 2;
SEEK_DATA :: 3;
SEEK_HOLE :: 4;
SEEK_MAX :: SEEK_HOLE;
// NOTE(zangent): These are OS specific!
// Do not mix these up!
RTLD_LAZY :: 0x001;
RTLD_NOW :: 0x002;
RTLD_BINDING_MASK :: 0x3;
RTLD_GLOBAL :: 0x100;
// "Argv" arguments converted to Odin strings
args := _alloc_command_line_arguments();
_File_Time :: struct {
seconds: i64,
nanoseconds: i64,
}
Stat :: struct {
device_id: u64, // ID of device containing file
serial: u64, // File serial number
nlink: u64, // Number of hard links
mode: u32, // Mode of the file
uid: u32, // User ID of the file's owner
gid: u32, // Group ID of the file's group
_padding: i32, // 32 bits of padding
rdev: u64, // Device ID, if device
size: i64, // Size of the file, in bytes
block_size: i64, // Optimal bllocksize for I/O
blocks: i64, // Number of 512-byte blocks allocated
last_access: _File_Time, // Time of last access
modified: _File_Time, // Time of last modification
status_change: _File_Time, // Time of last status change
_reserve1,
_reserve2,
_reserve3: i64,
};
// File type
S_IFMT :: 0o170000; // Type of file mask
S_IFIFO :: 0o010000; // Named pipe (fifo)
S_IFCHR :: 0o020000; // Character special
S_IFDIR :: 0o040000; // Directory
S_IFBLK :: 0o060000; // Block special
S_IFREG :: 0o100000; // Regular
S_IFLNK :: 0o120000; // Symbolic link
S_IFSOCK :: 0o140000; // Socket
// File mode
// Read, write, execute/search by owner
S_IRWXU :: 0o0700; // RWX mask for owner
S_IRUSR :: 0o0400; // R for owner
S_IWUSR :: 0o0200; // W for owner
S_IXUSR :: 0o0100; // X for owner
// Read, write, execute/search by group
S_IRWXG :: 0o0070; // RWX mask for group
S_IRGRP :: 0o0040; // R for group
S_IWGRP :: 0o0020; // W for group
S_IXGRP :: 0o0010; // X for group
// Read, write, execute/search by others
S_IRWXO :: 0o0007; // RWX mask for other
S_IROTH :: 0o0004; // R for other
S_IWOTH :: 0o0002; // W for other
S_IXOTH :: 0o0001; // X for other
S_ISUID :: 0o4000; // Set user id on execution
S_ISGID :: 0o2000; // Set group id on execution
S_ISVTX :: 0o1000; // Directory restrcted delete
S_ISLNK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK;
S_ISREG :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG;
S_ISDIR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR;
S_ISCHR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR;
S_ISBLK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK;
S_ISFIFO :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO;
S_ISSOCK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK;
F_OK :: 0; // Test for file existance
X_OK :: 1; // Test for execute permission
W_OK :: 2; // Test for write permission
R_OK :: 4; // Test for read permission
TimeSpec :: struct {
tv_sec : i64, /* seconds */
tv_nsec : i64, /* nanoseconds */
};
CLOCK_REALTIME :: 0;
CLOCK_MONOTONIC :: 1;
CLOCK_PROCESS_CPUTIME_ID :: 2;
CLOCK_THREAD_CPUTIME_ID :: 3;
CLOCK_MONOTONIC_RAW :: 4;
CLOCK_REALTIME_COARSE :: 5;
CLOCK_MONOTONIC_COARSE :: 6;
CLOCK_BOOTTIME :: 7;
CLOCK_REALTIME_ALARM :: 8;
CLOCK_BOOTTIME_ALARM :: 9;
SYS_GETTID: Syscall : 186;
foreign libc {
@(link_name="__errno_location") __errno_location :: proc() -> ^int ---;
@(link_name="syscall") syscall :: proc(number: Syscall, #c_vararg args: ..any) -> int ---;
@(link_name="open") _unix_open :: proc(path: cstring, flags: int, #c_vararg mode: ..any) -> Handle ---;
@(link_name="close") _unix_close :: proc(fd: Handle) -> int ---;
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
@(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 ---;
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---;
@(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^Stat) -> int ---;
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^Stat) -> int ---;
@(link_name="access") _unix_access :: proc(path: cstring, mask: int) -> int ---;
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---;
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---;
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---;
@(link_name="clock_gettime") _unix_clock_gettime :: proc(clock_id: u64, timespec: ^TimeSpec) ---;
@(link_name="nanosleep") _unix_nanosleep :: proc(requested: ^TimeSpec, remaining: ^TimeSpec) -> int ---;
@(link_name="sleep") _unix_sleep :: proc(seconds: u64) -> int ---;
@(link_name="exit") _unix_exit :: proc(status: int) -> ! ---;
}
foreign dl {
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: int) -> rawptr ---;
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---;
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---;
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---;
}
is_path_separator :: proc(r: rune) -> bool {
return r == '/';
}
get_last_error :: proc() -> int {
return __errno_location()^;
}
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
cstr := strings.clone_to_cstring(path);
handle := _unix_open(cstr, flags, mode);
delete(cstr);
if handle == -1 {
return INVALID_HANDLE, Errno(get_last_error());
}
return handle, ERROR_NONE;
}
close :: proc(fd: Handle) -> Errno {
result := _unix_close(fd);
if result == -1 {
return Errno(get_last_error());
}
return ERROR_NONE;
}
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
bytes_read := _unix_read(fd, &data[0], len(data));
if bytes_read == -1 {
return -1, Errno(get_last_error());
}
return bytes_read, ERROR_NONE;
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
bytes_written := _unix_write(fd, &data[0], len(data));
if bytes_written == -1 {
return -1, Errno(get_last_error());
}
return bytes_written, ERROR_NONE;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
res := _unix_seek(fd, offset, i32(whence));
if res == -1 {
return -1, Errno(get_last_error());
}
return res, ERROR_NONE;
}
file_size :: proc(fd: Handle) -> (i64, Errno) {
s, err := fstat(fd);
if err != ERROR_NONE {
return -1, err;
}
return s.size, ERROR_NONE;
}
// NOTE(bill): Uses startup to initialize it
stdin: Handle = 0;
stdout: Handle = 1;
stderr: Handle = 2;
/* TODO(zangent): Implement these!
last_write_time :: proc(fd: Handle) -> File_Time {}
last_write_time_by_name :: proc(name: string) -> File_Time {}
*/
last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
s, err := fstat(fd);
if err != ERROR_NONE {
return 0, err;
}
return File_Time(s.modified.nanoseconds), ERROR_NONE;
}
last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
s, err := stat(name);
if err != ERROR_NONE {
return 0, err;
}
return File_Time(s.modified.nanoseconds), ERROR_NONE;
}
stat :: inline proc(path: string) -> (Stat, Errno) {
cstr := strings.clone_to_cstring(path);
defer delete(cstr);
s: Stat;
result := _unix_stat(cstr, &s);
if result == -1 {
return s, Errno(get_last_error());
}
return s, ERROR_NONE;
}
fstat :: inline proc(fd: Handle) -> (Stat, Errno) {
s: Stat;
result := _unix_fstat(fd, &s);
if result == -1 {
return s, Errno(get_last_error());
}
return s, ERROR_NONE;
}
access :: inline proc(path: string, mask: int) -> (bool, Errno) {
cstr := strings.clone_to_cstring(path);
defer delete(cstr);
result := _unix_access(cstr, mask);
if result == -1 {
return false, Errno(get_last_error());
}
return true, ERROR_NONE;
}
heap_alloc :: proc(size: int) -> rawptr {
assert(size >= 0);
return _unix_calloc(1, size);
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
return _unix_realloc(ptr, new_size);
}
heap_free :: proc(ptr: rawptr) {
_unix_free(ptr);
}
getenv :: proc(name: string) -> (string, bool) {
path_str := strings.clone_to_cstring(name);
defer delete(path_str);
cstr := _unix_getenv(path_str);
if cstr == nil {
return "", false;
}
return string(cstr), true;
}
exit :: proc(code: int) -> ! {
_unix_exit(code);
}
clock_gettime :: proc(clock_id: u64) -> TimeSpec {
ts : TimeSpec;
_unix_clock_gettime(clock_id, &ts);
return ts;
}
sleep :: proc(seconds: u64) -> int {
return _unix_sleep(seconds);
}
nanosleep :: proc(nanoseconds: i64) -> int {
assert(nanoseconds <= 999999999);
requested, remaining : TimeSpec;
requested = TimeSpec{tv_nsec = nanoseconds};
return _unix_nanosleep(&requested, &remaining);
}
current_thread_id :: proc "contextless" () -> int {
return syscall(SYS_GETTID);
}
dlopen :: inline proc(filename: string, flags: int) -> rawptr {
cstr := strings.clone_to_cstring(filename);
defer delete(cstr);
handle := _unix_dlopen(cstr, flags);
return handle;
}
dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
assert(handle != nil);
cstr := strings.clone_to_cstring(symbol);
defer delete(cstr);
proc_handle := _unix_dlsym(handle, cstr);
return proc_handle;
}
dlclose :: inline proc(handle: rawptr) -> bool {
assert(handle != nil);
return _unix_dlclose(handle) == 0;
}
dlerror :: proc() -> string {
return string(_unix_dlerror());
}
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__));
for arg, i in runtime.args__ {
res[i] = string(arg);
}
return res;
}
+325
View File
@@ -0,0 +1,325 @@
// +build windows
package os
import "core:sys/win32"
OS :: "windows";
Handle :: distinct uintptr;
File_Time :: distinct u64;
Errno :: distinct int;
INVALID_HANDLE :: ~Handle(0);
O_RDONLY :: 0x00000;
O_WRONLY :: 0x00001;
O_RDWR :: 0x00002;
O_CREATE :: 0x00040;
O_EXCL :: 0x00080;
O_NOCTTY :: 0x00100;
O_TRUNC :: 0x00200;
O_NONBLOCK :: 0x00800;
O_APPEND :: 0x00400;
O_SYNC :: 0x01000;
O_ASYNC :: 0x02000;
O_CLOEXEC :: 0x80000;
ERROR_NONE: Errno : 0;
ERROR_FILE_NOT_FOUND: Errno : 2;
ERROR_PATH_NOT_FOUND: Errno : 3;
ERROR_ACCESS_DENIED: Errno : 5;
ERROR_INVALID_HANDLE: Errno : 6;
ERROR_NO_MORE_FILES: Errno : 18;
ERROR_HANDLE_EOF: Errno : 38;
ERROR_NETNAME_DELETED: Errno : 64;
ERROR_FILE_EXISTS: Errno : 80;
ERROR_BROKEN_PIPE: Errno : 109;
ERROR_BUFFER_OVERFLOW: Errno : 111;
ERROR_INSUFFICIENT_BUFFER: Errno : 122;
ERROR_MOD_NOT_FOUND: Errno : 126;
ERROR_PROC_NOT_FOUND: Errno : 127;
ERROR_DIR_NOT_EMPTY: Errno : 145;
ERROR_ALREADY_EXISTS: Errno : 183;
ERROR_ENVVAR_NOT_FOUND: Errno : 203;
ERROR_MORE_DATA: Errno : 234;
ERROR_OPERATION_ABORTED: Errno : 995;
ERROR_IO_PENDING: Errno : 997;
ERROR_NOT_FOUND: Errno : 1168;
ERROR_PRIVILEGE_NOT_HELD: Errno : 1314;
WSAEACCES: Errno : 10013;
WSAECONNRESET: Errno : 10054;
// Windows reserves errors >= 1<<29 for application use
ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
// "Argv" arguments converted to Odin strings
args := _alloc_command_line_arguments();
is_path_separator :: proc(r: rune) -> bool {
return r == '/' || r == '\\';
}
open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
if len(path) == 0 do return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
access: u32;
switch mode & (O_RDONLY|O_WRONLY|O_RDWR) {
case O_RDONLY: access = win32.FILE_GENERIC_READ;
case O_WRONLY: access = win32.FILE_GENERIC_WRITE;
case O_RDWR: access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE;
}
if mode&O_CREATE != 0 {
access |= win32.FILE_GENERIC_WRITE;
}
if mode&O_APPEND != 0 {
access &~= win32.FILE_GENERIC_WRITE;
access |= win32.FILE_APPEND_DATA;
}
share_mode := u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE);
sa: ^win32.Security_Attributes = nil;
sa_inherit := win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = true};
if mode&O_CLOEXEC == 0 {
sa = &sa_inherit;
}
create_mode: u32;
switch {
case mode&(O_CREATE|O_EXCL) == (O_CREATE | O_EXCL):
create_mode = win32.CREATE_NEW;
case mode&(O_CREATE|O_TRUNC) == (O_CREATE | O_TRUNC):
create_mode = win32.CREATE_ALWAYS;
case mode&O_CREATE == O_CREATE:
create_mode = win32.OPEN_ALWAYS;
case mode&O_TRUNC == O_TRUNC:
create_mode = win32.TRUNCATE_EXISTING;
case:
create_mode = win32.OPEN_EXISTING;
}
wide_path := win32.utf8_to_wstring(path);
handle := Handle(win32.create_file_w(wide_path, access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
if handle != INVALID_HANDLE do return handle, ERROR_NONE;
err := Errno(win32.get_last_error());
return INVALID_HANDLE, err;
}
close :: proc(fd: Handle) -> Errno {
if win32.close_handle(win32.Handle(fd)) == 0 {
return Errno(win32.get_last_error());
}
return ERROR_NONE;
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
if len(data) == 0 do return 0, ERROR_NONE;
single_write_length: i32;
total_write: i64;
length := i64(len(data));
for total_write < length {
remaining := length - total_write;
MAX :: 1<<31-1;
to_write: i32 = min(i32(remaining), MAX);
e := win32.write_file(win32.Handle(fd), &data[total_write], to_write, &single_write_length, nil);
if single_write_length <= 0 || !e {
err := Errno(win32.get_last_error());
return int(total_write), err;
}
total_write += i64(single_write_length);
}
return int(total_write), ERROR_NONE;
}
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
if len(data) == 0 do return 0, ERROR_NONE;
single_read_length: i32;
total_read: i64;
length := i64(len(data));
for total_read < length {
remaining := length - total_read;
MAX :: 1<<32-1;
to_read: u32 = min(u32(remaining), MAX);
e := win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
if single_read_length <= 0 || !e {
err := Errno(win32.get_last_error());
return int(total_read), err;
}
total_read += i64(single_read_length);
}
return int(total_read), ERROR_NONE;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
w: u32;
switch whence {
case 0: w = win32.FILE_BEGIN;
case 1: w = win32.FILE_CURRENT;
case 2: w = win32.FILE_END;
}
hi := i32(offset>>32);
lo := i32(offset);
ft := win32.get_file_type(win32.Handle(fd));
if ft == win32.FILE_TYPE_PIPE do return 0, ERROR_FILE_IS_PIPE;
dw_ptr := win32.set_file_pointer(win32.Handle(fd), lo, &hi, w);
if dw_ptr == win32.INVALID_SET_FILE_POINTER {
err := Errno(win32.get_last_error());
return 0, err;
}
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
}
file_size :: proc(fd: Handle) -> (i64, Errno) {
length: i64;
err: Errno;
if !win32.get_file_size_ex(win32.Handle(fd), &length) {
err = Errno(win32.get_last_error());
}
return length, err;
}
// NOTE(bill): Uses startup to initialize it
stdin := get_std_handle(win32.STD_INPUT_HANDLE);
stdout := get_std_handle(win32.STD_OUTPUT_HANDLE);
stderr := get_std_handle(win32.STD_ERROR_HANDLE);
get_std_handle :: proc(h: int) -> Handle {
fd := win32.get_std_handle(i32(h));
win32.set_handle_information(fd, win32.HANDLE_FLAG_INHERIT, 0);
return Handle(fd);
}
last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
file_info: win32.By_Handle_File_Information;
if !win32.get_file_information_by_handle(win32.Handle(fd), &file_info) {
return 0, Errno(win32.get_last_error());
}
lo := File_Time(file_info.last_write_time.lo);
hi := File_Time(file_info.last_write_time.hi);
return lo | hi << 32, ERROR_NONE;
}
last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
data: win32.File_Attribute_Data;
wide_path := win32.utf8_to_wstring(name);
if !win32.get_file_attributes_ex_w(wide_path, win32.GetFileExInfoStandard, &data) {
return 0, Errno(win32.get_last_error());
}
l := File_Time(data.last_write_time.lo);
h := File_Time(data.last_write_time.hi);
return l | h << 32, ERROR_NONE;
}
heap_alloc :: proc(size: int) -> rawptr {
return win32.heap_alloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, size);
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
if new_size == 0 {
heap_free(ptr);
return nil;
}
if ptr == nil do return heap_alloc(new_size);
return win32.heap_realloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
}
heap_free :: proc(ptr: rawptr) {
if ptr == nil do return;
win32.heap_free(win32.get_process_heap(), 0, ptr);
}
exit :: proc(code: int) -> ! {
win32.exit_process(u32(code));
}
current_thread_id :: proc "contextless" () -> int {
return int(win32.get_current_thread_id());
}
_alloc_command_line_arguments :: proc() -> []string {
arg_count: i32;
arg_list_ptr := win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count);
arg_list := make([]string, int(arg_count));
for _, i in arg_list {
wc_str := (^win32.Wstring)(uintptr(arg_list_ptr) + size_of(win32.Wstring)*uintptr(i))^;
olen := win32.wide_char_to_multi_byte(win32.CP_UTF8, 0, wc_str, -1,
nil, 0, nil, nil);
buf := make([]byte, int(olen));
n := win32.wide_char_to_multi_byte(win32.CP_UTF8, 0, wc_str, -1,
cstring(&buf[0]), olen, nil, nil);
if n > 0 {
n -= 1;
}
arg_list[i] = string(buf[:n]);
}
return arg_list;
}
get_windows_version_ansi :: proc() -> win32.OS_Version_Info_Ex_A {
osvi : win32.OS_Version_Info_Ex_A;
osvi.os_version_info_size = size_of(win32.OS_Version_Info_Ex_A);
win32.get_version(&osvi);
return osvi;
}
is_windows_xp :: proc() -> bool {
osvi := get_windows_version_ansi();
return (osvi.major_version == 5 && osvi.minor_version == 1);
}
is_windows_vista :: proc() -> bool {
osvi := get_windows_version_ansi();
return (osvi.major_version == 6 && osvi.minor_version == 0);
}
is_windows_7 :: proc() -> bool {
osvi := get_windows_version_ansi();
return (osvi.major_version == 6 && osvi.minor_version == 1);
}
is_windows_8 :: proc() -> bool {
osvi := get_windows_version_ansi();
return (osvi.major_version == 6 && osvi.minor_version == 2);
}
is_windows_8_1 :: proc() -> bool {
osvi := get_windows_version_ansi();
return (osvi.major_version == 6 && osvi.minor_version == 3);
}
is_windows_10 :: proc() -> bool {
osvi := get_windows_version_ansi();
return (osvi.major_version == 10 && osvi.minor_version == 0);
}
-281
View File
@@ -1,281 +0,0 @@
foreign_system_library (
dl "dl";
libc "c";
)
import "strings.odin";
type (
Handle i32;
FileTime u64;
Errno i32;
)
const (
O_RDONLY = 0x00000;
O_WRONLY = 0x00001;
O_RDWR = 0x00002;
O_CREAT = 0x00040;
O_EXCL = 0x00080;
O_NOCTTY = 0x00100;
O_TRUNC = 0x00200;
O_NONBLOCK = 0x00800;
O_APPEND = 0x00400;
O_SYNC = 0x01000;
O_ASYNC = 0x02000;
O_CLOEXEC = 0x80000;
)
const (
SEEK_SET = 0;
SEEK_CUR = 1;
SEEK_END = 2;
SEEK_DATA = 3;
SEEK_HOLE = 4;
SEEK_MAX = SEEK_HOLE;
)
const (
// NOTE(zangent): These are OS specific!
// Do not mix these up!
RTLD_LAZY = 0x001;
RTLD_NOW = 0x002;
RTLD_BINDING_MASK = 0x3;
RTLD_GLOBAL = 0x100;
)
// "Argv" arguments converted to Odin strings
var args = _alloc_command_line_arguments();
type _FileTime struct #ordered {
seconds: i64,
nanoseconds: i32,
reserved: i32,
}
// Translated from
// https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/+/jb-dev/sysroot/usr/include/bits/stat.h
// Validity is not guaranteed.
type Stat struct #ordered {
device_id: u64, // ID of device containing file
serial: u64, // File serial number
nlink: u32, // Number of hard links
mode: u32, // Mode of the file
uid: u32, // User ID of the file's owner
gid: u32, // Group ID of the file's group
_padding: i32, // 32 bits of padding
rdev: u64, // Device ID, if device
size: i64, // Size of the file, in bytes
block_size: i64, // Optimal bllocksize for I/O
blocks: i64, // Number of 512-byte blocks allocated
last_access: _FileTime, // Time of last access
modified: _FileTime, // Time of last modification
status_change: _FileTime, // Time of last status change
_reserve1,
_reserve2,
_reserve3: i64,
serial_numbe: u64, // File serial number...? Maybe.
_reserve4: i64,
};
// File type
const (
S_IFMT = 0170000; // Type of file mask
S_IFIFO = 0010000; // Named pipe (fifo)
S_IFCHR = 0020000; // Character special
S_IFDIR = 0040000; // Directory
S_IFBLK = 0060000; // Block special
S_IFREG = 0100000; // Regular
S_IFLNK = 0120000; // Symbolic link
S_IFSOCK = 0140000; // Socket
// File mode
// Read, write, execute/search by owner
S_IRWXU = 0000700; // RWX mask for owner
S_IRUSR = 0000400; // R for owner
S_IWUSR = 0000200; // W for owner
S_IXUSR = 0000100; // X for owner
// Read, write, execute/search by group
S_IRWXG = 0000070; // RWX mask for group
S_IRGRP = 0000040; // R for group
S_IWGRP = 0000020; // W for group
S_IXGRP = 0000010; // X for group
// Read, write, execute/search by others
S_IRWXO = 0000007; // RWX mask for other
S_IROTH = 0000004; // R for other
S_IWOTH = 0000002; // W for other
S_IXOTH = 0000001; // X for other
S_ISUID = 0004000; // Set user id on execution
S_ISGID = 0002000; // Set group id on execution
S_ISVTX = 0001000; // Directory restrcted delete
)
proc S_ISLNK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFLNK; }
proc S_ISREG (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFREG; }
proc S_ISDIR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFDIR; }
proc S_ISCHR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFCHR; }
proc S_ISBLK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFBLK; }
proc S_ISFIFO(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFIFO; }
proc S_ISSOCK(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFSOCK;}
const (
R_OK = 4; // Test for read permission
W_OK = 2; // Test for write permission
X_OK = 1; // Test for execute permission
F_OK = 0; // Test for file existance
)
foreign libc {
proc _unix_open (path: ^u8, mode: int) -> Handle #link_name "open";
proc _unix_close (fd: Handle) -> i32 #link_name "close";
proc _unix_read (fd: Handle, buf: rawptr, size: int) -> int #link_name "read";
proc _unix_write (fd: Handle, buf: rawptr, size: int) -> int #link_name "write";
proc _unix_seek (fd: Handle, offset: i64, whence: i32) -> i64 #link_name "lseek64";
proc _unix_gettid() -> u64 #link_name "gettid";
proc _unix_stat (path: ^u8, stat: ^Stat) -> i32 #link_name "stat";
proc _unix_access(path: ^u8, mask: int) -> i32 #link_name "access";
proc _unix_malloc (size: int) -> rawptr #link_name "malloc";
proc _unix_free (ptr: rawptr) #link_name "free";
proc _unix_realloc(ptr: rawptr, size: int) -> rawptr #link_name "realloc";
proc _unix_getenv (^u8) -> ^u8 #link_name "getenv";
proc _unix_exit(status: int) #link_name "exit";
}
foreign dl {
proc _unix_dlopen (filename: ^u8, flags: int) -> rawptr #link_name "dlopen";
proc _unix_dlsym (handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym";
proc _unix_dlclose(handle: rawptr) -> int #link_name "dlclose";
proc _unix_dlerror() -> ^u8 #link_name "dlerror";
}
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
proc open_simple(path: string, mode: int) -> (Handle, Errno) {
var cstr = strings.new_c_string(path);
var handle = _unix_open(cstr, mode);
free(cstr);
if(handle == -1) {
return 0, 1;
}
return handle, 0;
}
// NOTE(zangent): This is here for compatability reasons. Should this be here?
proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
return open_simple(path, mode);
}
proc close(fd: Handle) {
_unix_close(fd);
}
proc read(fd: Handle, data: []u8) -> (int, Errno) {
var sz = _unix_read(fd, &data[0], len(data));
return sz, 0;
}
proc write(fd: Handle, data: []u8) -> (int, Errno) {
var sz = _unix_write(fd, &data[0], len(data));
return sz, 0;
}
proc seek(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
var res = _unix_seek(fd, offset, i32(whence));
return res, 0;
}
proc file_size(fd: Handle) -> (i64, Errno) {
var prev, _ = seek(fd, 0, SEEK_CUR);
var size, err = seek(fd, 0, SEEK_END);
seek(fd, prev, SEEK_SET);
return size, err;
}
// NOTE(bill): Uses startup to initialize it
var (
stdin: Handle = 0;
stdout: Handle = 1;
stderr: Handle = 2;
)
/* TODO(zangent): Implement these!
proc last_write_time(fd: Handle) -> FileTime {}
proc last_write_time_by_name(name: string) -> FileTime {}
*/
proc stat(path: string) -> (Stat, int) #inline {
var s: Stat;
var cstr = strings.new_c_string(path);
defer free(cstr);
var ret_int = _unix_stat(cstr, &s);
return s, int(ret_int);
}
proc access(path: string, mask: int) -> bool #inline {
var cstr = strings.new_c_string(path);
defer free(cstr);
return _unix_access(cstr, mask) == 0;
}
proc heap_alloc(size: int) -> rawptr {
assert(size > 0);
return _unix_malloc(size);
}
proc heap_resize(ptr: rawptr, new_size: int) -> rawptr {
return _unix_realloc(ptr, new_size);
}
proc heap_free(ptr: rawptr) {
_unix_free(ptr);
}
proc getenv(name: string) -> (string, bool) {
var path_str = strings.new_c_string(name);
var cstr: ^u8 = _unix_getenv(path_str);
free(path_str);
if(cstr == nil) {
return "", false;
}
return strings.to_odin_string(cstr), true;
}
proc exit(code: int) {
_unix_exit(code);
}
proc current_thread_id() -> int {
// return int(_unix_gettid());
return 0;
}
proc dlopen(filename: string, flags: int) -> rawptr #inline {
var cstr = strings.new_c_string(filename);
var handle = _unix_dlopen(cstr, flags);
free(cstr);
return handle;
}
proc dlsym(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
assert(handle != nil);
var cstr = strings.new_c_string(symbol);
var proc_handle = _unix_dlsym(handle, cstr);
free(cstr);
return proc_handle;
}
proc dlclose(handle: rawptr) -> bool #inline {
assert(handle != nil);
return _unix_dlclose(handle) == 0;
}
proc dlerror() -> string {
return strings.to_odin_string(_unix_dlerror());
}
proc _alloc_command_line_arguments() -> []string {
// TODO(bill):
return nil;
}
-345
View File
@@ -1,345 +0,0 @@
import win32 "sys/windows.odin";
type (
Handle int;
FileTime u64;
)
const INVALID_HANDLE: Handle = -1;
const (
O_RDONLY = 0x00000;
O_WRONLY = 0x00001;
O_RDWR = 0x00002;
O_CREAT = 0x00040;
O_EXCL = 0x00080;
O_NOCTTY = 0x00100;
O_TRUNC = 0x00200;
O_NONBLOCK = 0x00800;
O_APPEND = 0x00400;
O_SYNC = 0x01000;
O_ASYNC = 0x02000;
O_CLOEXEC = 0x80000;
)
type Errno int;
const (
ERROR_NONE: Errno = 0;
ERROR_FILE_NOT_FOUND = 2;
ERROR_PATH_NOT_FOUND = 3;
ERROR_ACCESS_DENIED = 5;
ERROR_NO_MORE_FILES = 18;
ERROR_HANDLE_EOF = 38;
ERROR_NETNAME_DELETED = 64;
ERROR_FILE_EXISTS = 80;
ERROR_BROKEN_PIPE = 109;
ERROR_BUFFER_OVERFLOW = 111;
ERROR_INSUFFICIENT_BUFFER = 122;
ERROR_MOD_NOT_FOUND = 126;
ERROR_PROC_NOT_FOUND = 127;
ERROR_DIR_NOT_EMPTY = 145;
ERROR_ALREADY_EXISTS = 183;
ERROR_ENVVAR_NOT_FOUND = 203;
ERROR_MORE_DATA = 234;
ERROR_OPERATION_ABORTED = 995;
ERROR_IO_PENDING = 997;
ERROR_NOT_FOUND = 1168;
ERROR_PRIVILEGE_NOT_HELD = 1314;
WSAEACCES = 10013;
WSAECONNRESET = 10054;
// Windows reserves errors >= 1<<29 for application use
ERROR_FILE_IS_PIPE = 1<<29 + 0;
)
// "Argv" arguments converted to Odin strings
var args = _alloc_command_line_arguments();
proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
if len(path) == 0 {
return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
}
var access: u32;
match mode & (O_RDONLY|O_WRONLY|O_RDWR) {
case O_RDONLY: access = win32.FILE_GENERIC_READ;
case O_WRONLY: access = win32.FILE_GENERIC_WRITE;
case O_RDWR: access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE;
}
if mode&O_CREAT != 0 {
access |= win32.FILE_GENERIC_WRITE;
}
if mode&O_APPEND != 0 {
access &~= win32.FILE_GENERIC_WRITE;
access |= win32.FILE_APPEND_DATA;
}
var share_mode = u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE);
var sa: ^win32.Security_Attributes = nil;
var sa_inherit = win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = 1};
if mode&O_CLOEXEC == 0 {
sa = &sa_inherit;
}
var create_mode: u32;
match {
case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
create_mode = win32.CREATE_NEW;
case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
create_mode = win32.CREATE_ALWAYS;
case mode&O_CREAT == O_CREAT:
create_mode = win32.OPEN_ALWAYS;
case mode&O_TRUNC == O_TRUNC:
create_mode = win32.TRUNCATE_EXISTING;
case:
create_mode = win32.OPEN_EXISTING;
}
var buf: [300]u8;
copy(buf[..], []u8(path));
var handle = Handle(win32.create_file_a(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
if handle != INVALID_HANDLE {
return handle, ERROR_NONE;
}
var err = win32.get_last_error();
return INVALID_HANDLE, Errno(err);
}
proc close(fd: Handle) {
win32.close_handle(win32.Handle(fd));
}
proc write(fd: Handle, data: []u8) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
}
var single_write_length: i32;
var total_write: i64;
var length = i64(len(data));
for total_write < length {
var remaining = length - total_write;
var to_read: i32;
const MAX = 1<<31-1;
if remaining <= MAX {
to_read = i32(remaining);
} else {
to_read = MAX;
}
var e = win32.write_file(win32.Handle(fd), &data[total_write], to_read, &single_write_length, nil);
if single_write_length <= 0 || e == win32.FALSE {
var err = win32.get_last_error();
return int(total_write), Errno(e);
}
total_write += i64(single_write_length);
}
return int(total_write), ERROR_NONE;
}
proc read(fd: Handle, data: []u8) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
}
var single_read_length: i32;
var total_read: i64;
var length = i64(len(data));
for total_read < length {
var remaining = length - total_read;
var to_read: u32;
const MAX = 1<<32-1;
if remaining <= MAX {
to_read = u32(remaining);
} else {
to_read = MAX;
}
var e = win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
if single_read_length <= 0 || e == win32.FALSE {
var err = win32.get_last_error();
return int(total_read), Errno(e);
}
total_read += i64(single_read_length);
}
return int(total_read), ERROR_NONE;
}
proc seek(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
var w: u32;
match whence {
case 0: w = win32.FILE_BEGIN;
case 1: w = win32.FILE_CURRENT;
case 2: w = win32.FILE_END;
}
var hi = i32(offset>>32);
var lo = i32(offset);
var ft = win32.get_file_type(win32.Handle(fd));
if ft == win32.FILE_TYPE_PIPE {
return 0, ERROR_FILE_IS_PIPE;
}
var dw_ptr = win32.set_file_pointer(win32.Handle(fd), lo, &hi, w);
if dw_ptr == win32.INVALID_SET_FILE_POINTER {
var err = win32.get_last_error();
return 0, Errno(err);
}
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
}
proc file_size(fd: Handle) -> (i64, Errno) {
var length: i64;
var err: Errno;
if win32.get_file_size_ex(win32.Handle(fd), &length) == 0 {
err = Errno(win32.get_last_error());
}
return length, err;
}
// NOTE(bill): Uses startup to initialize it
var stdin = get_std_handle(win32.STD_INPUT_HANDLE);
var stdout = get_std_handle(win32.STD_OUTPUT_HANDLE);
var stderr = get_std_handle(win32.STD_ERROR_HANDLE);
proc get_std_handle(h: int) -> Handle {
var fd = win32.get_std_handle(i32(h));
win32.set_handle_information(fd, win32.HANDLE_FLAG_INHERIT, 0);
return Handle(fd);
}
proc last_write_time(fd: Handle) -> FileTime {
var file_info: win32.ByHandleFileInformation;
win32.get_file_information_by_handle(win32.Handle(fd), &file_info);
var lo = FileTime(file_info.last_write_time.lo);
var hi = FileTime(file_info.last_write_time.hi);
return lo | hi << 32;
}
proc last_write_time_by_name(name: string) -> FileTime {
var last_write_time: win32.Filetime;
var data: win32.FileAttributeData;
var buf: [1024]u8;
assert(len(buf) > len(name));
copy(buf[..], []u8(name));
if win32.get_file_attributes_ex_a(&buf[0], win32.GetFileExInfoStandard, &data) != 0 {
last_write_time = data.last_write_time;
}
var l = FileTime(last_write_time.lo);
var h = FileTime(last_write_time.hi);
return l | h << 32;
}
proc heap_alloc(size: int) -> rawptr {
return win32.heap_alloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, size);
}
proc heap_resize(ptr: rawptr, new_size: int) -> rawptr {
if new_size == 0 {
heap_free(ptr);
return nil;
}
if ptr == nil {
return heap_alloc(new_size);
}
return win32.heap_realloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
}
proc heap_free(ptr: rawptr) {
if ptr == nil {
return;
}
win32.heap_free(win32.get_process_heap(), 0, ptr);
}
proc exit(code: int) {
win32.exit_process(u32(code));
}
proc current_thread_id() -> int {
return int(win32.get_current_thread_id());
}
proc _alloc_command_line_arguments() -> []string {
proc alloc_ucs2_to_utf8(wstr: ^u16) -> string {
var wstr_len = 0;
for (wstr+wstr_len)^ != 0 {
wstr_len++;
}
var len = 2*wstr_len-1;
var buf = make([]u8, len+1);
var str = slice_ptr(wstr, wstr_len+1);
var i, j = 0, 0;
for str[j] != 0 {
match {
case str[j] < 0x80:
if i+1 > len {
return "";
}
buf[i] = u8(str[j]); i++;
j++;
case str[j] < 0x800:
if i+2 > len {
return "";
}
buf[i] = u8(0xc0 + (str[j]>>6)); i++;
buf[i] = u8(0x80 + (str[j]&0x3f)); i++;
j++;
case 0xd800 <= str[j] && str[j] < 0xdc00:
if i+4 > len {
return "";
}
var c = rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000;
buf[i] = u8(0xf0 + (c >> 18)); i++;
buf[i] = u8(0x80 + ((c >> 12) & 0x3f)); i++;
buf[i] = u8(0x80 + ((c >> 6) & 0x3f)); i++;
buf[i] = u8(0x80 + ((c ) & 0x3f)); i++;
j += 2;
case 0xdc00 <= str[j] && str[j] < 0xe000:
return "";
case:
if i+3 > len {
return "";
}
buf[i] = 0xe0 + u8 (str[j] >> 12); i++;
buf[i] = 0x80 + u8((str[j] >> 6) & 0x3f); i++;
buf[i] = 0x80 + u8((str[j] ) & 0x3f); i++;
j++;
}
}
return string(buf[0..<i]);
}
var arg_count: i32;
var arg_list_ptr = win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count);
var arg_list = make([]string, arg_count);
for _, i in arg_list {
arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^);
}
return arg_list;
}
-292
View File
@@ -1,292 +0,0 @@
foreign_system_library (
dl "dl";
libc "c";
)
import "strings.odin";
type (
Handle i32;
FileTime u64;
Errno int;
AddressSize int;
)
const (
O_RDONLY = 0x00000;
O_WRONLY = 0x00001;
O_RDWR = 0x00002;
O_CREAT = 0x00040;
O_EXCL = 0x00080;
O_NOCTTY = 0x00100;
O_TRUNC = 0x00200;
O_NONBLOCK = 0x00800;
O_APPEND = 0x00400;
O_SYNC = 0x01000;
O_ASYNC = 0x02000;
O_CLOEXEC = 0x80000;
)
const (
SEEK_SET = 0;
SEEK_CUR = 1;
SEEK_END = 2;
SEEK_DATA = 3;
SEEK_HOLE = 4;
SEEK_MAX = SEEK_HOLE;
)
const (
// NOTE(zangent): These are OS specific!
// Do not mix these up!
RTLD_LAZY = 0x1;
RTLD_NOW = 0x2;
RTLD_LOCAL = 0x4;
RTLD_GLOBAL = 0x8;
RTLD_NODELETE = 0x80;
RTLD_NOLOAD = 0x10;
RTLD_FIRST = 0x100;
)
var args: [dynamic]string;
type _FileTime struct #ordered {
seconds: i64,
nanoseconds: i64
}
type Stat struct #ordered {
device_id : i32, // ID of device containing file
mode : u16, // Mode of the file
nlink : u16, // Number of hard links
serial : u64, // File serial number
uid : u32, // User ID of the file's owner
gid : u32, // Group ID of the file's group
rdev : i32, // Device ID, if device
last_access : FileTime, // Time of last access
modified : FileTime, // Time of last modification
status_change : FileTime, // Time of last status change
created : FileTime, // Time of creation
size : i64, // Size of the file, in bytes
blocks : i64, // Number of blocks allocated for the file
block_size: i32, // Optimal blocksize for I/O
flags : u32, // User-defined flags for the file
gen_num : u32, // File generation number ...?
_spare : i32, // RESERVED
_reserve1,
_reserve2 : i64, // RESERVED
};
// File type
const (
S_IFMT = 0170000; // Type of file mask
S_IFIFO = 0010000; // Named pipe (fifo)
S_IFCHR = 0020000; // Character special
S_IFDIR = 0040000; // Directory
S_IFBLK = 0060000; // Block special
S_IFREG = 0100000; // Regular
S_IFLNK = 0120000; // Symbolic link
S_IFSOCK = 0140000; // Socket
// File mode
// Read, write, execute/search by owner
S_IRWXU = 0000700; // RWX mask for owner
S_IRUSR = 0000400; // R for owner
S_IWUSR = 0000200; // W for owner
S_IXUSR = 0000100; // X for owner
// Read, write, execute/search by group
S_IRWXG = 0000070; // RWX mask for group
S_IRGRP = 0000040; // R for group
S_IWGRP = 0000020; // W for group
S_IXGRP = 0000010; // X for group
// Read, write, execute/search by others
S_IRWXO = 0000007; // RWX mask for other
S_IROTH = 0000004; // R for other
S_IWOTH = 0000002; // W for other
S_IXOTH = 0000001; // X for other
S_ISUID = 0004000; // Set user id on execution
S_ISGID = 0002000; // Set group id on execution
S_ISVTX = 0001000; // Directory restrcted delete
)
proc S_ISLNK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFLNK; }
proc S_ISREG (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFREG; }
proc S_ISDIR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFDIR; }
proc S_ISCHR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFCHR; }
proc S_ISBLK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFBLK; }
proc S_ISFIFO(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFIFO; }
proc S_ISSOCK(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFSOCK;}
const (
R_OK = 4; // Test for read permission
W_OK = 2; // Test for write permission
X_OK = 1; // Test for execute permission
F_OK = 0; // Test for file existance
)
foreign libc {
proc unix_open (path: ^u8, mode: int) -> Handle #link_name "open";
proc unix_close (handle: Handle) #link_name "close";
proc unix_read (handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "read";
proc unix_write (handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "write";
proc unix_lseek (fs: Handle, offset: AddressSize, whence: int) -> AddressSize #link_name "lseek";
proc unix_gettid() -> u64 #link_name "gettid";
proc unix_stat (path: ^u8, stat: ^Stat) -> int #link_name "stat";
proc unix_access(path: ^u8, mask: int) -> int #link_name "access";
proc unix_malloc (size: int) -> rawptr #link_name "malloc";
proc unix_free (ptr: rawptr) #link_name "free";
proc unix_realloc(ptr: rawptr, size: int) -> rawptr #link_name "realloc";
proc unix_getenv (^u8) -> ^u8 #link_name "getenv";
proc unix_exit(status: int) #link_name "exit";
}
foreign dl {
proc unix_dlopen (filename: ^u8, flags: int) -> rawptr #link_name "dlopen";
proc unix_dlsym (handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym";
proc unix_dlclose(handle: rawptr) -> int #link_name "dlclose";
proc unix_dlerror() -> ^u8 #link_name "dlerror";
}
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
proc open_simple(path: string, mode: int) -> (Handle, Errno) {
var cstr = strings.new_c_string(path);
var handle = unix_open(cstr, mode);
free(cstr);
if(handle == -1) {
return 0, 1;
}
return handle, 0;
}
// NOTE(zangent): This is here for compatability reasons. Should this be here?
proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
return open_simple(path, mode);
}
proc close(fd: Handle) {
unix_close(fd);
}
proc write(fd: Handle, data: []u8) -> (AddressSize, Errno) {
assert(fd != -1);
var bytes_written = unix_write(fd, &data[0], len(data));
if(bytes_written == -1) {
return 0, 1;
}
return bytes_written, 0;
}
proc read(fd: Handle, data: []u8) -> (AddressSize, Errno) {
assert(fd != -1);
var bytes_read = unix_read(fd, &data[0], len(data));
if(bytes_read == -1) {
return 0, 1;
}
return bytes_read, 0;
}
proc seek(fd: Handle, offset: AddressSize, whence: int) -> (AddressSize, Errno) {
assert(fd != -1);
var final_offset = unix_lseek(fd, offset, whence);
if(final_offset == -1) {
return 0, 1;
}
return final_offset, 0;
}
proc file_size(fd: Handle) -> (i64, Errno) {
var prev, _ = seek(fd, 0, SEEK_CUR);
var size, err = seek(fd, 0, SEEK_END);
seek(fd, prev, SEEK_SET);
return size, err;
}
// NOTE(bill): Uses startup to initialize it
var (
stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE);
stdout: Handle = 1; // get_std_handle(win32.STD_OUTPUT_HANDLE);
stderr: Handle = 2; // get_std_handle(win32.STD_ERROR_HANDLE);
)
/* TODO(zangent): Implement these!
proc last_write_time(fd: Handle) -> FileTime {}
proc last_write_time_by_name(name: string) -> FileTime {}
*/
proc stat(path: string) -> (Stat, bool) #inline {
var s: Stat;
var cstr = strings.new_c_string(path);
defer free(cstr);
var ret_int = unix_stat(cstr, &s);
return s, ret_int==0;
}
proc access(path: string, mask: int) -> bool #inline {
var cstr = strings.new_c_string(path);
defer free(cstr);
return unix_access(cstr, mask) == 0;
}
proc heap_alloc(size: int) -> rawptr #inline {
assert(size > 0);
return unix_malloc(size);
}
proc heap_resize(ptr: rawptr, new_size: int) -> rawptr #inline {
return unix_realloc(ptr, new_size);
}
proc heap_free(ptr: rawptr) #inline {
unix_free(ptr);
}
proc getenv(name: string) -> (string, bool) {
var path_str = strings.new_c_string(name);
var cstr: ^u8 = unix_getenv(path_str);
free(path_str);
if(cstr == nil) {
return "", false;
}
return strings.to_odin_string(cstr), true;
}
proc exit(code: int) #inline {
unix_exit(code);
}
proc current_thread_id() -> int {
// return cast(int) unix_gettid();
return 0;
}
proc dlopen(filename: string, flags: int) -> rawptr #inline {
var cstr = strings.new_c_string(filename);
var handle = unix_dlopen(cstr, flags);
free(cstr);
return handle;
}
proc dlsym(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
assert(handle != nil);
var cstr = strings.new_c_string(symbol);
var proc_handle = unix_dlsym(handle, cstr);
free(cstr);
return proc_handle;
}
proc dlclose(handle: rawptr) -> bool #inline {
assert(handle != nil);
return unix_dlclose(handle) == 0;
}
proc dlerror() -> string {
return strings.to_odin_string(unix_dlerror());
}
-29
View File
@@ -1,29 +0,0 @@
type (
Any struct #ordered {
data: rawptr,
type_info: ^TypeInfo,
};
String struct #ordered {
data: ^u8,
len: int,
};
Slice struct #ordered {
data: rawptr,
len: int,
cap: int,
};
DynamicArray struct #ordered {
data: rawptr,
len: int,
cap: int,
allocator: Allocator,
};
DynamicMap struct #ordered {
hashes: [dynamic]int,
entries: DynamicArray,
};
)
+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;
}
+490
View File
@@ -0,0 +1,490 @@
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;
if (a == nil && b != nil) ||
(a != nil && b == nil) {
return false;
}
switch {
case a.size != b.size, a.align != b.align:
return false;
}
switch x in a.variant {
case rt.Type_Info_Named:
y, ok := b.variant.(rt.Type_Info_Named);
if !ok do return false;
return x.base == y.base;
case rt.Type_Info_Integer:
y, ok := b.variant.(rt.Type_Info_Integer);
if !ok do return false;
return x.signed == y.signed;
case rt.Type_Info_Rune:
_, ok := b.variant.(rt.Type_Info_Rune);
return ok;
case rt.Type_Info_Float:
_, ok := b.variant.(rt.Type_Info_Float);
return ok;
case rt.Type_Info_Complex:
_, ok := b.variant.(rt.Type_Info_Complex);
return ok;
case rt.Type_Info_String:
_, ok := b.variant.(rt.Type_Info_String);
return ok;
case rt.Type_Info_Boolean:
_, ok := b.variant.(rt.Type_Info_Boolean);
return ok;
case rt.Type_Info_Any:
_, ok := b.variant.(rt.Type_Info_Any);
return ok;
case rt.Type_Info_Pointer:
y, ok := b.variant.(rt.Type_Info_Pointer);
if !ok do return false;
return are_types_identical(x.elem, y.elem);
case rt.Type_Info_Procedure:
y, ok := b.variant.(rt.Type_Info_Procedure);
if !ok do return false;
switch {
case x.variadic != y.variadic,
x.convention != y.convention:
return false;
}
return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results);
case rt.Type_Info_Array:
y, ok := b.variant.(rt.Type_Info_Array);
if !ok do return false;
if x.count != y.count do return false;
return are_types_identical(x.elem, y.elem);
case rt.Type_Info_Dynamic_Array:
y, ok := b.variant.(rt.Type_Info_Dynamic_Array);
if !ok do return false;
return are_types_identical(x.elem, y.elem);
case rt.Type_Info_Slice:
y, ok := b.variant.(rt.Type_Info_Slice);
if !ok do return false;
return are_types_identical(x.elem, y.elem);
case rt.Type_Info_Tuple:
y, ok := b.variant.(rt.Type_Info_Tuple);
if !ok do return false;
if len(x.types) != len(y.types) do return false;
for _, i in x.types {
xt, yt := x.types[i], y.types[i];
if !are_types_identical(xt, yt) {
return false;
}
}
return true;
case rt.Type_Info_Struct:
y, ok := b.variant.(rt.Type_Info_Struct);
if !ok do return false;
switch {
case len(x.types) != len(y.types),
x.is_packed != y.is_packed,
x.is_raw_union != y.is_raw_union,
x.custom_align != y.custom_align:
return false;
}
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;
case rt.Type_Info_Union:
y, ok := b.variant.(rt.Type_Info_Union);
if !ok do return false;
if len(x.variants) != len(y.variants) do return false;
for _, i in x.variants {
xv, yv := x.variants[i], y.variants[i];
if !are_types_identical(xv, yv) do return false;
}
return true;
case rt.Type_Info_Enum:
// NOTE(bill): Should be handled above
return false;
case rt.Type_Info_Map:
y, ok := b.variant.(rt.Type_Info_Map);
if !ok do return false;
return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value);
case rt.Type_Info_Bit_Field:
y, ok := b.variant.(rt.Type_Info_Bit_Field);
if !ok do return false;
if len(x.names) != len(y.names) do return false;
for _, i in x.names {
xb, yb := x.bits[i], y.bits[i];
xo, yo := x.offsets[i], y.offsets[i];
xn, yn := x.names[i], y.names[i];
if xb != yb do return false;
if xo != yo do return false;
if xn != yn do return false;
}
return true;
case rt.Type_Info_Bit_Set:
y, ok := b.variant.(rt.Type_Info_Bit_Set);
if !ok do return false;
return x.elem == y.elem && x.lower == y.lower && x.upper == y.upper;
case rt.Type_Info_Opaque:
y, ok := b.variant.(rt.Type_Info_Opaque);
if !ok do return false;
return x.elem == y.elem;
}
return false;
}
is_signed :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
switch i in rt.type_info_base(info).variant {
case rt.Type_Info_Integer: return i.signed;
case rt.Type_Info_Float: return true;
}
return false;
}
is_integer :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Integer);
return ok;
}
is_rune :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Rune);
return ok;
}
is_float :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Float);
return ok;
}
is_complex :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Complex);
return ok;
}
is_any :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Any);
return ok;
}
is_string :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_String);
return ok;
}
is_boolean :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Boolean);
return ok;
}
is_pointer :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Pointer);
return ok;
}
is_procedure :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Procedure);
return ok;
}
is_array :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Array);
return ok;
}
is_dynamic_array :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Dynamic_Array);
return ok;
}
is_dynamic_map :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Map);
return ok;
}
is_slice :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Slice);
return ok;
}
is_tuple :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Tuple);
return ok;
}
is_struct :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
s, ok := rt.type_info_base(info).variant.(rt.Type_Info_Struct);
return ok && !s.is_raw_union;
}
is_raw_union :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
s, ok := rt.type_info_base(info).variant.(rt.Type_Info_Struct);
return ok && s.is_raw_union;
}
is_union :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Union);
return ok;
}
is_enum :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Enum);
return ok;
}
is_opaque :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Opaque);
return ok;
}
is_simd_vector :: proc(info: ^rt.Type_Info) -> bool {
if info == nil do return false;
_, 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, ')');
}
}
}
File diff suppressed because it is too large Load Diff
+759
View File
@@ -0,0 +1,759 @@
package runtime
import "core:os"
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;
}
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;
}
i -= 1; a[i] = digits[u % b];
os.write(fd, a[i:]);
}
print_i64 :: proc(fd: os.Handle, x: i64) {
digits := "0123456789";
b :: i64(10);
u := x;
neg := u < 0;
u = abs(u);
a: [129]byte;
i := len(a);
for u >= b {
i -= 1; a[i] = digits[u % b];
u /= b;
}
i -= 1; a[i] = digits[u % b];
if neg {
i -= 1; a[i] = '-';
}
os.write(fd, a[i:]);
}
print_caller_location :: proc(fd: os.Handle, using loc: Source_Code_Location) {
os.write_string(fd, file_path);
os.write_byte(fd, '(');
print_u64(fd, u64(line));
os.write_byte(fd, ':');
print_u64(fd, u64(column));
os.write_byte(fd, ')');
}
print_typeid :: proc(fd: os.Handle, id: typeid) {
ti := type_info_of(id);
print_type(fd, ti);
}
print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
if ti == nil {
os.write_string(fd, "nil");
return;
}
switch info in ti.variant {
case Type_Info_Named:
os.write_string(fd, info.name);
case Type_Info_Integer:
switch ti.id {
case int: os.write_string(fd, "int");
case uint: os.write_string(fd, "uint");
case uintptr: os.write_string(fd, "uintptr");
case:
os.write_byte(fd, info.signed ? 'i' : 'u');
print_u64(fd, u64(8*ti.size));
}
case Type_Info_Rune:
os.write_string(fd, "rune");
case Type_Info_Float:
os.write_byte(fd, 'f');
print_u64(fd, u64(8*ti.size));
case Type_Info_Complex:
os.write_string(fd, "complex");
print_u64(fd, u64(8*ti.size));
case Type_Info_String:
os.write_string(fd, "string");
case Type_Info_Boolean:
switch ti.id {
case bool: os.write_string(fd, "bool");
case:
os.write_byte(fd, 'b');
print_u64(fd, u64(8*ti.size));
}
case Type_Info_Any:
os.write_string(fd, "any");
case Type_Info_Type_Id:
os.write_string(fd, "typeid");
case Type_Info_Pointer:
if info.elem == nil {
os.write_string(fd, "rawptr");
} else {
os.write_string(fd, "^");
print_type(fd, info.elem);
}
case Type_Info_Procedure:
os.write_string(fd, "proc");
if info.params == nil {
os.write_string(fd, "()");
} else {
t := info.params.variant.(Type_Info_Tuple);
os.write_string(fd, "(");
for t, i in t.types {
if i > 0 do os.write_string(fd, ", ");
print_type(fd, t);
}
os.write_string(fd, ")");
}
if info.results != nil {
os.write_string(fd, " -> ");
print_type(fd, info.results);
}
case Type_Info_Tuple:
count := len(info.names);
if count != 1 do os.write_string(fd, "(");
for name, i in info.names {
if i > 0 do os.write_string(fd, ", ");
t := info.types[i];
if len(name) > 0 {
os.write_string(fd, name);
os.write_string(fd, ": ");
}
print_type(fd, t);
}
if count != 1 do os.write_string(fd, ")");
case Type_Info_Array:
os.write_string(fd, "[");
print_u64(fd, u64(info.count));
os.write_string(fd, "]");
print_type(fd, info.elem);
case Type_Info_Dynamic_Array:
os.write_string(fd, "[dynamic]");
print_type(fd, info.elem);
case Type_Info_Slice:
os.write_string(fd, "[]");
print_type(fd, info.elem);
case Type_Info_Map:
os.write_string(fd, "map[");
print_type(fd, info.key);
os.write_byte(fd, ']');
print_type(fd, info.value);
case Type_Info_Struct:
os.write_string(fd, "struct ");
if info.is_packed do os.write_string(fd, "#packed ");
if info.is_raw_union do os.write_string(fd, "#raw_union ");
if info.custom_align {
os.write_string(fd, "#align ");
print_u64(fd, u64(ti.align));
os.write_byte(fd, ' ');
}
os.write_byte(fd, '{');
for name, i in info.names {
if i > 0 do os.write_string(fd, ", ");
os.write_string(fd, name);
os.write_string(fd, ": ");
print_type(fd, info.types[i]);
}
os.write_byte(fd, '}');
case Type_Info_Union:
os.write_string(fd, "union {");
for variant, i in info.variants {
if i > 0 do os.write_string(fd, ", ");
print_type(fd, variant);
}
os.write_string(fd, "}");
case Type_Info_Enum:
os.write_string(fd, "enum ");
print_type(fd, info.base);
os.write_string(fd, " {");
for name, i in info.names {
if i > 0 do os.write_string(fd, ", ");
os.write_string(fd, name);
}
os.write_string(fd, "}");
case Type_Info_Bit_Field:
os.write_string(fd, "bit_field ");
if ti.align != 1 {
os.write_string(fd, "#align ");
print_u64(fd, u64(ti.align));
os.write_byte(fd, ' ');
}
os.write_string(fd, " {");
for name, i in info.names {
if i > 0 do os.write_string(fd, ", ");
os.write_string(fd, name);
os.write_string(fd, ": ");
print_u64(fd, u64(info.bits[i]));
}
os.write_string(fd, "}");
case Type_Info_Bit_Set:
os.write_string(fd, "bit_set[");
switch elem in type_info_base(info.elem).variant {
case Type_Info_Enum:
print_type(fd, info.elem);
case Type_Info_Rune:
os.write_encoded_rune(fd, rune(info.lower));
os.write_string(fd, "..");
os.write_encoded_rune(fd, rune(info.upper));
case:
print_i64(fd, info.lower);
os.write_string(fd, "..");
print_i64(fd, info.upper);
}
if info.underlying != nil {
os.write_string(fd, "; ");
print_type(fd, info.underlying);
}
os.write_byte(fd, ']');
case Type_Info_Opaque:
os.write_string(fd, "opaque ");
print_type(fd, info.elem);
case Type_Info_Simd_Vector:
if info.is_x86_mmx {
os.write_string(fd, "intrinsics.x86_mmx");
} else {
os.write_string(fd, "intrinsics.vector(");
print_u64(fd, u64(info.count));
os.write_string(fd, ", ");
print_type(fd, info.elem);
os.write_byte(fd, ')');
}
}
}
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;
case len(a) == 0: return true;
case &a[0] == &b[0]: return true;
}
return string_cmp(a, b) == 0;
}
string_cmp :: proc "contextless" (a, b: string) -> int {
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); }
string_lt :: inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) < 0; }
string_gt :: inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) > 0; }
string_le :: inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) <= 0; }
string_ge :: inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0; }
cstring_len :: proc "contextless" (s: cstring) -> int {
p0 := uintptr((^byte)(s));
p := p0;
for p != 0 && (^byte)(p)^ != 0 {
p += 1;
}
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)Raw_String{ptr, n};
}
complex64_eq :: inline proc "contextless" (a, b: complex64) -> bool { return real(a) == real(b) && imag(a) == imag(b); }
complex64_ne :: inline proc "contextless" (a, b: complex64) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
complex128_eq :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) == real(b) && imag(a) == imag(b); }
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) {
if 0 <= index && index < count do return;
handle_error :: proc "contextless" (file: string, line, column: int, index, count: int) {
fd := os.stderr;
print_caller_location(fd, Source_Code_Location{file, line, column, "", 0});
os.write_string(fd, " Index ");
print_i64(fd, i64(index));
os.write_string(fd, " is out of bounds range 0:");
print_i64(fd, i64(count));
os.write_byte(fd, '\n');
debug_trap();
}
handle_error(file, line, column, index, count);
}
slice_handle_error :: proc "contextless" (file: string, line, column: int, lo, hi: int, len: int) {
fd := os.stderr;
print_caller_location(fd, Source_Code_Location{file, line, column, "", 0});
os.write_string(fd, " Invalid slice indices: ");
print_i64(fd, i64(lo));
os.write_string(fd, ":");
print_i64(fd, i64(hi));
os.write_string(fd, ":");
print_i64(fd, i64(len));
os.write_byte(fd, '\n');
debug_trap();
}
slice_expr_error_hi :: proc "contextless" (file: string, line, column: int, hi: int, len: int) {
if 0 <= hi && hi <= len do return;
slice_handle_error(file, line, column, 0, hi, len);
}
slice_expr_error_lo_hi :: proc "contextless" (file: string, line, column: int, lo, hi: int, len: int) {
if 0 <= lo && lo <= len && lo <= hi && hi <= len do return;
slice_handle_error(file, line, column, lo, hi, len);
}
dynamic_array_expr_error :: proc "contextless" (file: string, line, column: int, low, high, max: int) {
if 0 <= low && low <= high && high <= max do return;
handle_error :: proc "contextless" (file: string, line, column: int, low, high, max: int) {
fd := os.stderr;
print_caller_location(fd, Source_Code_Location{file, line, column, "", 0});
os.write_string(fd, " Invalid dynamic array values: ");
print_i64(fd, i64(low));
os.write_string(fd, ":");
print_i64(fd, i64(high));
os.write_string(fd, ":");
print_i64(fd, i64(max));
os.write_byte(fd, '\n');
debug_trap();
}
handle_error(file, line, column, low, high, max);
}
type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: int, from, to: typeid) {
if ok do return;
handle_error :: proc "contextless" (file: string, line, column: int, from, to: typeid) {
fd := os.stderr;
print_caller_location(fd, Source_Code_Location{file, line, column, "", 0});
os.write_string(fd, " Invalid type assertion from ");
print_typeid(fd, from);
os.write_string(fd, " to ");
print_typeid(fd, to);
os.write_byte(fd, '\n');
debug_trap();
}
handle_error(file, line, column, from, to);
}
string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) {
// 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) {
bounds_check_error(file_path, int(line), int(column), index, count);
}
slice_expr_error_hi_loc :: inline proc "contextless" (using loc := #caller_location, hi: int, len: int) {
slice_expr_error_hi(file_path, int(line), int(column), hi, len);
}
slice_expr_error_lo_hi_loc :: inline proc "contextless" (using loc := #caller_location, lo, hi: int, len: int) {
slice_expr_error_lo_hi(file_path, int(line), int(column), lo, hi, len);
}
dynamic_array_expr_error_loc :: inline proc "contextless" (using loc := #caller_location, low, high, max: int) {
dynamic_array_expr_error(file_path, int(line), int(column), low, high, max);
}
make_slice_error_loc :: inline proc "contextless" (loc := #caller_location, len: int) {
if 0 <= len do return;
handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) {
fd := os.stderr;
print_caller_location(fd, loc);
os.write_string(fd, " Invalid slice length for make: ");
print_i64(fd, i64(len));
os.write_byte(fd, '\n');
debug_trap();
}
handle_error(loc, len);
}
make_dynamic_array_error_loc :: inline proc "contextless" (using loc := #caller_location, len, cap: int) {
if 0 <= len && len <= cap do return;
handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) {
fd := os.stderr;
print_caller_location(fd, loc);
os.write_string(fd, " Invalid dynamic array parameters for make: ");
print_i64(fd, i64(len));
os.write_byte(fd, ':');
print_i64(fd, i64(cap));
os.write_byte(fd, '\n');
debug_trap();
}
handle_error(loc, len, cap);
}
make_map_expr_error_loc :: inline proc "contextless" (loc := #caller_location, cap: int) {
if 0 <= cap do return;
handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) {
fd := os.stderr;
print_caller_location(fd, loc);
os.write_string(fd, " Invalid map capacity for make: ");
print_i64(fd, i64(cap));
os.write_byte(fd, '\n');
debug_trap();
}
handle_error(loc, cap);
}
@(default_calling_convention = "c")
foreign {
@(link_name="llvm.sqrt.f32") _sqrt_f32 :: proc(x: f32) -> f32 ---
@(link_name="llvm.sqrt.f64") _sqrt_f64 :: proc(x: f64) -> f64 ---
}
abs_f32 :: inline proc "contextless" (x: f32) -> f32 {
foreign {
@(link_name="llvm.fabs.f32") _abs :: proc "c" (x: f32) -> f32 ---
}
return _abs(x);
}
abs_f64 :: inline proc "contextless" (x: f64) -> f64 {
foreign {
@(link_name="llvm.fabs.f64") _abs :: proc "c" (x: f64) -> f64 ---
}
return _abs(x);
}
min_f32 :: proc(a, b: f32) -> f32 {
foreign {
@(link_name="llvm.minnum.f32") _min :: proc "c" (a, b: f32) -> f32 ---
}
return _min(a, b);
}
min_f64 :: proc(a, b: f64) -> f64 {
foreign {
@(link_name="llvm.minnum.f64") _min :: proc "c" (a, b: f64) -> f64 ---
}
return _min(a, b);
}
max_f32 :: proc(a, b: f32) -> f32 {
foreign {
@(link_name="llvm.maxnum.f32") _max :: proc "c" (a, b: f32) -> f32 ---
}
return _max(a, b);
}
max_f64 :: proc(a, b: f64) -> f64 {
foreign {
@(link_name="llvm.maxnum.f64") _max :: proc "c" (a, b: f64) -> f64 ---
}
return _max(a, b);
}
abs_complex64 :: inline proc "contextless" (x: complex64) -> f32 {
r, i := real(x), imag(x);
return _sqrt_f32(r*r + i*i);
}
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 "contextless" (n, m: complex64) -> complex64 {
e, f: f32;
if abs(real(m)) >= abs(imag(m)) {
ratio := imag(m) / real(m);
denom := real(m) + ratio*imag(m);
e = (real(n) + imag(n)*ratio) / denom;
f = (imag(n) - real(n)*ratio) / denom;
} else {
ratio := real(m) / imag(m);
denom := imag(m) + ratio*real(m);
e = (real(n)*ratio + imag(n)) / denom;
f = (imag(n)*ratio - real(n)) / denom;
}
return complex(e, f);
}
quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 {
e, f: f64;
if abs(real(m)) >= abs(imag(m)) {
ratio := imag(m) / real(m);
denom := real(m) + ratio*imag(m);
e = (real(n) + imag(n)*ratio) / denom;
f = (imag(n) - real(n)*ratio) / denom;
} else {
ratio := real(m) / imag(m);
denom := imag(m) + ratio*real(m);
e = (real(n)*ratio + imag(n)) / denom;
f = (imag(n)*ratio - real(n)) / denom;
}
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);
}
+202
View File
@@ -0,0 +1,202 @@
package runtime
@(default_calling_convention="none")
foreign {
@(link_name="llvm.cttz.i8") _ctz_u8 :: proc(i: u8, is_zero_undef := false) -> u8 ---
@(link_name="llvm.cttz.i16") _ctz_u16 :: proc(i: u16, is_zero_undef := false) -> u16 ---
@(link_name="llvm.cttz.i32") _ctz_u32 :: proc(i: u32, is_zero_undef := false) -> u32 ---
@(link_name="llvm.cttz.i64") _ctz_u64 :: proc(i: u64, is_zero_undef := false) -> u64 ---
}
_ctz :: proc{
_ctz_u8,
_ctz_u16,
_ctz_u32,
_ctz_u64,
};
@(default_calling_convention="none")
foreign {
@(link_name="llvm.ctlz.i8") _clz_u8 :: proc(i: u8, is_zero_undef := false) -> u8 ---
@(link_name="llvm.ctlz.i16") _clz_u16 :: proc(i: u16, is_zero_undef := false) -> u16 ---
@(link_name="llvm.ctlz.i32") _clz_u32 :: proc(i: u32, is_zero_undef := false) -> u32 ---
@(link_name="llvm.ctlz.i64") _clz_u64 :: proc(i: u64, is_zero_undef := false) -> u64 ---
}
_clz :: proc{
_clz_u8,
_clz_u16,
_clz_u32,
_clz_u64,
};
udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
n := transmute([2]u64)a;
d := transmute([2]u64)b;
q, r: [2]u64 = ---, ---;
sr: u32 = 0;
low :: ODIN_ENDIAN == "big" ? 1 : 0;
high :: 1 - low;
U64_BITS :: 8*size_of(u64);
U128_BITS :: 8*size_of(u128);
// Special Cases
if n[high] == 0 {
if d[high] == 0 {
if rem != nil {
rem^ = u128(n[low] % d[low]);
}
return u128(n[low] / d[low]);
}
if rem != nil {
rem^ = u128(n[low]);
}
return 0;
}
if d[low] == 0 {
if d[high] == 0 {
if rem != nil {
rem^ = u128(n[high] % d[low]);
}
return u128(n[high] / d[low]);
}
if n[low] == 0 {
if rem != nil {
r[high] = n[high] % d[high];
r[low] = 0;
rem^ = transmute(u128)r;
}
return u128(n[high] / d[high]);
}
if d[high] & (d[high]-1) == 0 {
if rem != nil {
r[low] = n[low];
r[high] = n[high] & (d[high] - 1);
rem^ = transmute(u128)r;
}
return u128(n[high] >> _ctz(d[high]));
}
sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high])));
if sr > U64_BITS - 2 {
if rem != nil {
rem^ = a;
}
return 0;
}
sr += 1;
q[low] = 0;
q[high] = n[low] << u64(U64_BITS - sr);
r[high] = n[high] >> sr;
r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr);
} else {
if d[high] == 0 {
if d[low] & (d[low] - 1) == 0 {
if rem != nil {
rem^ = u128(n[low] & (d[low] - 1));
}
if d[low] == 1 {
return a;
}
sr = u32(_ctz(d[low]));
q[high] = n[high] >> sr;
q[low] = (n[high] << (U64_BITS-sr)) | (n[low] >> sr);
return transmute(u128)q;
}
sr = 1 + U64_BITS + u32(_clz(d[low])) - u32(_clz(n[high]));
switch {
case sr == U64_BITS:
q[low] = 0;
q[high] = n[low];
r[high] = 0;
r[low] = n[high];
case sr < U64_BITS:
q[low] = 0;
q[high] = n[low] << (U64_BITS - sr);
r[high] = n[high] >> sr;
r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr);
case:
q[low] = n[low] << (U128_BITS - sr);
q[high] = (n[high] << (U128_BITS - sr)) | (n[low] >> (sr - U64_BITS));
r[high] = 0;
r[low] = n[high] >> (sr - U64_BITS);
}
} else {
sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high])));
if sr > U64_BITS - 1 {
if rem != nil {
rem^ = a;
}
return 0;
}
sr += 1;
q[low] = 0;
if sr == U64_BITS {
q[high] = n[low];
r[high] = 0;
r[low] = n[high];
} else {
r[high] = n[high] >> sr;
r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr);
q[high] = n[low] << (U64_BITS - sr);
}
}
}
carry: u32 = 0;
r_all: u128 = ---;
for ; sr > 0; sr -= 1 {
r[high] = (r[high] << 1) | (r[low] >> (U64_BITS - 1));
r[low] = (r[low] << 1) | (q[high] >> (U64_BITS - 1));
q[high] = (q[high] << 1) | (q[low] >> (U64_BITS - 1));
q[low] = (q[low] << 1) | u64(carry);
r_all = transmute(u128)r;
s := i128(b - r_all - 1) >> (U128_BITS - 1);
carry = u32(s & 1);
r_all -= b & transmute(u128)s;
r = transmute([2]u64)r_all;
}
q_all := ((transmute(u128)q) << 1) | u128(carry);
if rem != nil {
rem^ = r_all;
}
return q_all;
}
@(link_name="__umodti3")
umodti3 :: proc "c" (a, b: i128) -> i128 {
s_a := a >> (128 - 1);
s_b := b >> (128 - 1);
an := (a ~ s_a) - s_a;
bn := (b ~ s_b) - s_b;
r: u128 = ---;
_ = udivmod128(transmute(u128)an, transmute(u128)bn, &r);
return (transmute(i128)r ~ s_a) - s_a;
}
@(link_name="__udivmodti4")
udivmodti4 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
return udivmod128(a, b, rem);
}
@(link_name="__udivti3")
udivti3 :: proc "c" (a, b: u128) -> u128 {
return udivmodti4(a, b, nil);
}
+50
View File
@@ -0,0 +1,50 @@
package runtime
foreign import kernel32 "system:Kernel32.lib"
@(link_name="memcpy")
memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
foreign kernel32 {
RtlCopyMemory :: proc "c" (dst, src: rawptr, len: int) ---
}
RtlCopyMemory(dst, src, len);
return dst;
}
@(link_name="memmove")
memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
foreign kernel32 {
RtlMoveMemory :: proc "c" (dst, src: rawptr, len: int) ---
}
RtlMoveMemory(dst, src, len);
return dst;
}
@(link_name="memset")
memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr {
foreign kernel32 {
RtlFillMemory :: proc "c" (dst: rawptr, len: int, fill: byte) ---
}
RtlFillMemory(ptr, len, byte(val));
return ptr;
}
// @(link_name="memcmp")
// memcmp :: proc "c" (dst, src: rawptr, len: int) -> i32 {
// if dst == nil || src == nil {
// return 0;
// }
// if dst == src {
// return 0;
// }
// d, s := uintptr(dst), uintptr(src);
// n := uintptr(len);
// for i := uintptr(0); i < n; i += 1 {
// x, y := (^byte)(d+i)^, (^byte)(s+i)^;
// if x != y {
// return x < y ? -1 : +1;
// }
// }
// return 0;
// }
+226
View File
@@ -0,0 +1,226 @@
package sort
import "core:mem"
import "intrinsics"
bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
assert(f != nil);
count := len(array);
init_j, last_j := 0, count-1;
for {
init_swap, prev_swap := -1, -1;
for j in init_j..<last_j {
if f(array[j], array[j+1]) > 0 {
array[j], array[j+1] = array[j+1], array[j];
prev_swap = j;
if init_swap == -1 do init_swap = j;
}
}
if prev_swap == -1 do return;
init_j = max(init_swap-1, 0);
last_j = prev_swap;
}
}
bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
count := len(array);
init_j, last_j := 0, count-1;
for {
init_swap, prev_swap := -1, -1;
for j in init_j..<last_j {
if array[j] > array[j+1] {
array[j], array[j+1] = array[j+1], array[j];
prev_swap = j;
if init_swap == -1 do init_swap = j;
}
}
if prev_swap == -1 do return;
init_j = max(init_swap-1, 0);
last_j = prev_swap;
}
}
quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
assert(f != nil);
a := array;
n := len(a);
if n < 2 do return;
p := a[n/2];
i, j := 0, n-1;
loop: for {
for f(a[i], p) < 0 do i += 1;
for f(p, a[j]) < 0 do j -= 1;
if i >= j do break loop;
a[i], a[j] = a[j], a[i];
i += 1;
j -= 1;
}
quick_sort_proc(a[0:i], f);
quick_sort_proc(a[i:n], f);
}
quick_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
a := array;
n := len(a);
if n < 2 do return;
p := a[n/2];
i, j := 0, n-1;
loop: for {
for a[i] < p do i += 1;
for p < a[j] do j -= 1;
if i >= j do break loop;
a[i], a[j] = a[j], a[i];
i += 1;
j -= 1;
}
quick_sort(a[0:i]);
quick_sort(a[i:n]);
}
_log2 :: proc(x: int) -> int {
res := 0;
for n := x; n != 0; n >>= 1 do res += 1;
return res;
}
merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
merge_slices :: proc(arr1, arr2, out: A, f: proc(T, T) -> int) {
N1, N2 := len(arr1), len(arr2);
i, j := 0, 0;
for k in 0..<N1+N2 {
if j == N2 || i < N1 && j < N2 && f(arr1[i], arr2[j]) < 0 {
out[k] = arr1[i];
i += 1;
} else {
out[k] = arr2[j];
j += 1;
}
}
}
assert(f != nil);
arr1 := array;
N := len(arr1);
arr2 := make([]T, N);
defer free(arr2);
a, b, m, M := N/2, N, 1, _log2(N);
for i in 0..M {
for j in 0..<a {
k := 2*j*m;
merge_slices(arr1[k:k+m], arr1[k+m:k+m+m], arr2[k:], f);
}
if N-b > m {
k := 2*a*m;
merge_slices(arr1[k:k+m], arr1[k+m : k+m+(N-b)&(m-1)], arr2[k:], f);
} else {
copy(arr2[b:N], arr1[b:N]);
}
arr1, arr2 = arr2, arr1;
m <<= 1;
a >>= 1;
b = a << uint(i) << 2;
}
if M & 1 == 0 do copy(arr2, arr1);
}
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;
for k in 0..<N1+N2 {
if j == N2 || i < N1 && j < N2 && arr1[i] < arr2[j] {
out[k] = arr1[i];
i += 1;
} else {
out[k] = arr2[j];
j += 1;
}
}
}
arr1 := array;
N := len(arr1);
arr2 := make([]T, N);
defer free(arr2);
a, b, m, M := N/2, N, 1, _log2(N);
for i in 0..M {
for j in 0..<a {
k := 2*j*m;
merge_slices(arr1[k:k+m], arr1[k+m:k+m+m], arr2[k:]);
}
if N-b > m {
k := 2*a*m;
merge_slices(arr1[k:k+m], arr1[k+m : k+m+(N-b)&(m-1)], arr2[k:]);
} else {
copy(arr2[b:N], arr1[b:N]);
}
arr1, arr2 = arr2, arr1;
m <<= 1;
a >>= 1;
b = a << uint(i) << 2;
}
if M & 1 == 0 do copy(arr2, arr1);
}
compare_bools :: proc(a, b: bool) -> int {
switch {
case !a && b: return -1;
case a && !b: return +1;
}
return 0;
}
compare_ints :: proc(a, b: int) -> int {
switch delta := a - b; {
case delta < 0: return -1;
case delta > 0: return +1;
}
return 0;
}
compare_f32s :: proc(a, b: f32) -> int {
switch delta := a - b; {
case delta < 0: return -1;
case delta > 0: return +1;
}
return 0;
}
compare_f64s :: proc(a, b: f64) -> int {
switch delta := a - b; {
case delta < 0: return -1;
case delta > 0: return +1;
}
return 0;
}
compare_strings :: proc(a, b: string) -> int {
return mem.compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
}
-500
View File
@@ -1,500 +0,0 @@
import . "decimal.odin";
type IntFlag enum {
Prefix = 1<<0,
Plus = 1<<1,
Space = 1<<2,
}
proc parse_bool(s: string) -> (result: bool, ok: bool) {
match s {
case "1", "t", "T", "true", "TRUE", "True":
return true, true;
case "0", "f", "F", "false", "FALSE", "False":
return false, true;
}
return false, false;
}
proc _digit_value(r: rune) -> int {
var ri = int(r);
var v: int = 16;
match r {
case '0'..'9': v = ri-'0';
case 'a'..'z': v = ri-'a'+10;
case 'A'..'Z': v = ri-'A'+10;
}
return v;
}
proc parse_i128(s: string) -> i128 {
var neg = false;
if len(s) > 1 {
match s[0] {
case '-':
neg = true;
s = s[1..];
case '+':
s = s[1..];
}
}
var base: i128 = 10;
if len(s) > 2 && s[0] == '0' {
match s[1] {
case 'b': base = 2; s = s[2..];
case 'o': base = 8; s = s[2..];
case 'd': base = 10; s = s[2..];
case 'z': base = 12; s = s[2..];
case 'x': base = 16; s = s[2..];
}
}
var value: i128;
for r in s {
if r == '_' {
continue;
}
var v = i128(_digit_value(r));
if v >= base {
break;
}
value *= base;
value += v;
}
return neg ? -value : value;
}
proc parse_u128(s: string) -> u128 {
var neg = false;
if len(s) > 1 && s[0] == '+' {
s = s[1..];
}
var base = u128(10);
if len(s) > 2 && s[0] == '0' {
match s[1] {
case 'b': base = 2; s = s[2..];
case 'o': base = 8; s = s[2..];
case 'd': base = 10; s = s[2..];
case 'z': base = 12; s = s[2..];
case 'x': base = 16; s = s[2..];
}
}
var value: u128;
for r in s {
if r == '_' {
continue;
}
var v = u128(_digit_value(r));
if v >= base {
break;
}
value *= base;
value += u128(v);
}
return neg ? -value : value;
}
proc parse_int(s: string) -> int {
return int(parse_i128(s));
}
proc parse_uint(s: string, base: int) -> uint {
return uint(parse_u128(s));
}
proc parse_f64(s: string) -> f64 {
var i = 0;
var sign: f64 = 1;
match s[i] {
case '-': i++; sign = -1;
case '+': i++;
}
var value: f64 = 0;
for ; i < len(s); i++ {
var r = rune(s[i]);
if r == '_' {
continue;
}
var v = _digit_value(r);
if v >= 10 {
break;
}
value *= 10;
value += f64(v);
}
if s[i] == '.' {
var pow10: f64 = 10;
i++;
for ; i < len(s); i++ {
var r = rune(s[i]);
if r == '_' {
continue;
}
var v = _digit_value(r);
if v >= 10 {
break;
}
value += f64(v)/pow10;
pow10 *= 10;
}
}
var frac = false;
var scale: f64 = 1;
if s[i] == 'e' || s[i] == 'E' {
i++;
match s[i] {
case '-': i++; frac = true;
case '+': i++;
}
var exp: u32 = 0;
for ; i < len(s); i++ {
var r = rune(s[i]);
if r == '_' {
continue;
}
var d = u32(_digit_value(r));
if d >= 10 {
break;
}
exp = exp * 10 + d;
}
if exp > 308 { exp = 308; }
for exp >= 50 { scale *= 1e50; exp -= 50; }
for exp >= 8 { scale *= 1e8; exp -= 8; }
for exp > 0 { scale *= 10; exp -= 1; }
}
return sign * (frac ? (value/scale) : (value*scale));
}
proc append_bool(buf: []u8, b: bool) -> string {
var s = b ? "true" : "false";
append(buf, ..[]u8(s));
return string(buf);
}
proc append_uint(buf: []u8, u: u64, base: int) -> string {
return append_bits(buf, u128(u), base, false, 8*size_of(uint), digits, 0);
}
proc append_int(buf: []u8, i: i64, base: int) -> string {
return append_bits(buf, u128(i), base, true, 8*size_of(int), digits, 0);
}
proc itoa(buf: []u8, i: int) -> string { return append_int(buf, i64(i), 10); }
proc append_float(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string {
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
}
type DecimalSlice struct {
digits: []u8,
count: int,
decimal_point: int,
neg: bool,
}
type Float_Info struct {
mantbits: uint,
expbits: uint,
bias: int,
}
var (
_f16_info = Float_Info{10, 5, -15};
_f32_info = Float_Info{23, 8, -127};
_f64_info = Float_Info{52, 11, -1023};
)
proc generic_ftoa(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
var bits: u64;
var flt: ^Float_Info;
match bit_size {
case 32:
bits = u64(transmute(u32, f32(val)));
flt = &_f32_info;
case 64:
bits = transmute(u64, val);
flt = &_f64_info;
case:
panic("strconv: invalid bit_size");
}
var neg = bits>>(flt.expbits+flt.mantbits) != 0;
var exp = int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
var mant = bits & (u64(1) << flt.mantbits - 1);
match exp {
case 1<<flt.expbits - 1:
var s: string;
if mant != 0 {
s = "NaN";
} else if neg {
s = "-Inf";
} else {
s = "+Inf";
}
append(buf, ..[]u8(s));
return buf;
case 0: // denormalized
exp++;
case:
mant |= u64(1) << flt.mantbits;
}
exp += flt.bias;
var d_: Decimal;
var d = &d_;
assign(d, mant);
shift(d, exp - int(flt.mantbits));
var digs: DecimalSlice;
var shortest = prec < 0;
if shortest {
round_shortest(d, mant, exp, flt);
digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
match fmt {
case 'e', 'E': prec = digs.count-1;
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
case 'g', 'G': prec = digs.count;
}
} else {
match fmt {
case 'e', 'E': round(d, prec+1);
case 'f', 'F': round(d, d.decimal_point+prec);
case 'g', 'G':
if prec == 0 {
prec = 1;
}
round(d, prec);
}
digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
}
return format_digits(buf, shortest, neg, digs, prec, fmt);
}
proc format_digits(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: u8) -> []u8 {
match fmt {
case 'f', 'F':
append(buf, neg ? '-' : '+');
// integer, padded with zeros when needed
if digs.decimal_point > 0 {
var m = min(digs.count, digs.decimal_point);
append(buf, ..digs.digits[0..<m]);
for ; m < digs.decimal_point; m++ {
append(buf, '0');
}
} else {
append(buf, '0');
}
// fractional part
if prec > 0 {
append(buf, '.');
for i in 0..<prec {
var c: u8 = '0';
if var j = digs.decimal_point + i; 0 <= j && j < digs.count {
c = digs.digits[j];
}
append(buf, c);
}
}
return buf;
case 'e', 'E':
panic("strconv: e/E float printing is not yet supported");
return buf; // TODO
case 'g', 'G':
panic("strconv: g/G float printing is not yet supported");
return buf; // TODO
}
var c: [2]u8;
c[0] = '%';
c[1] = fmt;
append(buf, ..c[..]);
return buf;
}
proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
if mant == 0 { // If mantissa is zero, the number is zero
d.count = 0;
return;
}
/*
10^(dp-nd) > 2^(exp-mantbits)
log2(10) * (dp-nd) > exp-mantbits
log(2) >~ 0.332
332*(dp-nd) >= 100*(exp-mantbits)
*/
var minexp = flt.bias+1;
if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - int(flt.mantbits)) {
// Number is already its shortest
return;
}
var upper_: Decimal; var upper = &upper_;
assign(upper, 2*mant - 1);
shift(upper, exp - int(flt.mantbits) - 1);
var mantlo: u64;
var explo: int;
if mant > 1<<flt.mantbits || exp == minexp {
mantlo = mant-1;
explo = exp;
} else {
mantlo = 2*mant - 1;
explo = exp-1;
}
var lower_: Decimal; var lower = &lower_;
assign(lower, 2*mantlo + 1);
shift(lower, explo - int(flt.mantbits) - 1);
var inclusive = mant%2 == 0;
for i in 0..<d.count {
var l: u8 = '0'; // lower digit
if i < lower.count {
l = lower.digits[i];
}
var m = d.digits[i]; // middle digit
var u: u8 = '0'; // upper digit
if i < upper.count {
u = upper.digits[i];
}
var ok_round_down = l != m || inclusive && i+1 == lower.count;
var ok_round_up = m != u && (inclusive || m+1 < u || i+1 < upper.count);
if (ok_round_down && ok_round_up) {
round(d, i+1);
return;
}
if (ok_round_down) {
round_down(d, i+1);
return;
}
if (ok_round_up) {
round_up(d, i+1);
return;
}
}
}
const MAX_BASE = 32;
var digits = "0123456789abcdefghijklmnopqrstuvwxyz";
proc is_integer_negative(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
var neg = false;
if is_signed {
match bit_size {
case 8:
var i = i8(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
case 16:
var i = i16(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
case 32:
var i = i32(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
case 64:
var i = i64(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
case 128:
var i = i128(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
case:
panic("is_integer_negative: Unknown integer size");
}
}
return u, neg;
}
proc append_bits(buf: []u8, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: IntFlag) -> string {
if base < 2 || base > MAX_BASE {
panic("strconv: illegal base passed to append_bits");
}
var neg: bool;
var a: [129]u8;
var i = len(a);
u, neg = is_integer_negative(u, is_signed, bit_size);
var b = u128(base);
for u >= b {
i--; a[i] = digits[uint(u % b)];
u /= b;
}
i--; a[i] = digits[uint(u % b)];
if flags&IntFlag.Prefix != 0 {
var ok = true;
match base {
case 2: i--; a[i] = 'b';
case 8: i--; a[i] = 'o';
case 10: i--; a[i] = 'd';
case 12: i--; a[i] = 'z';
case 16: i--; a[i] = 'x';
case: ok = false;
}
if ok {
i--; a[i] = '0';
}
}
if neg {
i--; a[i] = '-';
} else if flags&IntFlag.Plus != 0 {
i--; a[i] = '+';
} else if flags&IntFlag.Space != 0 {
i--; a[i] = ' ';
}
append(buf, ..a[i..]);
return string(buf);
}
+264
View File
@@ -0,0 +1,264 @@
// Multiple precision decimal numbers
// NOTE: This is only for floating point printing and nothing else
package strconv_decimal
Decimal :: struct {
digits: [384]byte, // big-endian digits
count: int,
decimal_point: int,
neg, trunc: bool,
}
decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
digit_zero :: proc(buf: []byte) -> int {
for _, i in buf do buf[i] = '0';
return len(buf);
}
n := 10 + a.count + abs(a.decimal_point);
// TODO(bill): make this work with a buffer that's not big enough
assert(len(buf) >= n);
b := buf[0:n];
if a.count == 0 {
b[0] = '0';
return string(b[0:1]);
}
w := 0;
if a.decimal_point <= 0 {
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(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(b[w:], a.digits[0:a.count]);
w += digit_zero(b[w : w+a.decimal_point-a.count]);
}
return string(b[0:w]);
}
// trim trailing zeros
trim :: proc(a: ^Decimal) {
for a.count > 0 && a.digits[a.count-1] == '0' {
a.count -= 1;
}
if a.count == 0 {
a.decimal_point = 0;
}
}
assign :: proc(a: ^Decimal, idx: u64) {
buf: [64]byte;
n := 0;
for i := idx; i > 0; {
j := i/10;
i -= 10*j;
buf[n] = byte('0'+i);
n += 1;
i = j;
}
a.count = 0;
for n -= 1; n >= 0; n -= 1 {
a.digits[a.count] = buf[n];
a.count += 1;
}
a.decimal_point = a.count;
trim(a);
}
shift_right :: proc(a: ^Decimal, k: uint) {
r := 0; // read index
w := 0; // write index
n: uint;
for ; n>>k == 0; r += 1 {
if r >= a.count {
if n == 0 {
// Just in case
a.count = 0;
return;
}
for n>>k == 0 {
n = n * 10;
r += 1;
}
break;
}
c := uint(a.digits[r]);
n = n*10 + c - '0';
}
a.decimal_point -= r-1;
mask: uint = (1<<k) - 1;
for ; r < a.count; r += 1 {
c := uint(a.digits[r]);
dig := n>>k;
n &= mask;
a.digits[w] = byte('0' + dig);
w += 1;
n = n*10 + c - '0';
}
for n > 0 {
dig := n>>k;
n &= mask;
if w < len(a.digits) {
a.digits[w] = byte('0' + dig);
w += 1;
} else if dig > 0 {
a.trunc = true;
}
n *= 10;
}
a.count = w;
trim(a);
}
shift_left :: proc(a: ^Decimal, k: uint) {
// NOTE(bill): used to determine buffer size required for the decimal from the binary shift
// 'k' means `1<<k` == `2^k` which equates to roundup(k*log10(2)) digits required
log10_2 :: 0.301029995663981195213738894724493026768189881462108541310;
capacity := int(f64(k)*log10_2 + 1);
r := a.count; // read index
w := a.count+capacity; // write index
d := len(a.digits);
n: uint;
for r -= 1; r >= 0; r -= 1 {
n += (uint(a.digits[r]) - '0') << k;
quo := n/10;
rem := n - 10*quo;
w -= 1;
if w < d {
a.digits[w] = byte('0' + rem);
} else if rem != 0 {
a.trunc = true;
}
n = quo;
}
for n > 0 {
quo := n/10;
rem := n - 10*quo;
w -= 1;
if w < d {
a.digits[w] = byte('0' + rem);
} else if rem != 0 {
a.trunc = true;
}
n = quo;
}
// NOTE(bill): Remove unused buffer size
assert(w >= 0);
capacity -= w;
a.count = min(a.count+capacity, d);
a.decimal_point += capacity;
trim(a);
}
shift :: proc(a: ^Decimal, i: int) {
uint_size :: 8*size_of(uint);
max_shift :: uint_size-4;
switch k := i; {
case a.count == 0:
// no need to update
case k > 0:
for k > max_shift {
shift_left(a, max_shift);
k -= max_shift;
}
shift_left(a, uint(k));
case k < 0:
for k < -max_shift {
shift_right(a, max_shift);
k += max_shift;
}
shift_right(a, uint(-k));
}
}
can_round_up :: proc(a: ^Decimal, nd: int) -> bool {
if nd < 0 || nd >= a.count { return false ; }
if a.digits[nd] == '5' && nd+1 == a.count {
if a.trunc do return true;
return nd > 0 && (a.digits[nd-1]-'0')%2 != 0;
}
return a.digits[nd] >= '5';
}
round :: proc(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
if can_round_up(a, nd) {
round_up(a, nd);
} else {
round_down(a, nd);
}
}
round_up :: proc(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
for i := nd-1; i >= 0; i -= 1 {
if c := a.digits[i]; c < '9' {
a.digits[i] += 1;
a.count = i+1;
return;
}
}
// Number is just 9s
a.digits[0] = '1';
a.count = 1;
a.decimal_point += 1;
}
round_down :: proc(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
a.count = nd;
trim(a);
}
// Extract integer part, rounded appropriately. There are no guarantees about overflow.
rounded_integer :: proc(a: ^Decimal) -> u64 {
if a.decimal_point > 20 {
return 0xffff_ffff_ffff_ffff;
}
i: int = 0;
n: u64 = 0;
m := min(a.decimal_point, a.count);
for ; i < m; i += 1 {
n = n*10 + u64(a.digits[i]-'0');
}
for ; i < a.decimal_point; i += 1 {
n *= 10;
}
if can_round_up(a, a.decimal_point) {
n += 1;
}
return n;
}
+439
View File
@@ -0,0 +1,439 @@
package strconv
using import "decimal"
Int_Flag :: enum {
Prefix,
Plus,
Space,
}
Int_Flags :: bit_set[Int_Flag];
Decimal_Slice :: struct {
digits: []byte,
count: int,
decimal_point: int,
neg: bool,
}
Float_Info :: struct {
mantbits: uint,
expbits: uint,
bias: int,
}
_f16_info := Float_Info{10, 5, -15};
_f32_info := Float_Info{23, 8, -127};
_f64_info := Float_Info{52, 11, -1023};
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int) -> []byte {
bits: u64;
flt: ^Float_Info;
switch bit_size {
case 32:
bits = u64(transmute(u32)f32(val));
flt = &_f32_info;
case 64:
bits = transmute(u64)val;
flt = &_f64_info;
case:
panic("strconv: invalid bit_size");
}
neg := bits>>(flt.expbits+flt.mantbits) != 0;
exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
mant := bits & (u64(1) << flt.mantbits - 1);
switch exp {
case 1<<flt.expbits - 1:
s: string;
if mant != 0 {
s = "NaN";
} else if neg {
s = "-Inf";
} else {
s = "+Inf";
}
n := copy(buf, cast([]byte)s);
return buf[:n];
case 0: // denormalized
exp += 1;
case:
mant |= u64(1) << flt.mantbits;
}
exp += flt.bias;
d_: Decimal;
d := &d_;
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);
digs = Decimal_Slice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
switch fmt {
case 'e', 'E': prec = digs.count-1;
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
case 'g', 'G': prec = digs.count;
}
} else {
switch fmt {
case 'e', 'E': round(d, prec+1);
case 'f', 'F': round(d, d.decimal_point+prec);
case 'g', 'G':
if prec == 0 {
prec = 1;
}
round(d, prec);
}
digs = Decimal_Slice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
}
return format_digits(buf, shortest, neg, digs, prec, fmt);
}
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) {
buf.n += copy(buf.b[buf.n:], bytes);
}
b := Buffer{b = buf};
prec := precision;
switch fmt {
case 'f', 'F':
add_bytes(&b, neg ? '-' : '+');
// integer, padded with zeros when needed
if digs.decimal_point > 0 {
m := min(digs.count, digs.decimal_point);
add_bytes(&b, ..digs.digits[0:m]);
for ; m < digs.decimal_point; m += 1 {
add_bytes(&b, '0');
}
} else {
add_bytes(&b, '0');
}
// fractional part
if prec > 0 {
add_bytes(&b, '.');
for i in 0..<prec {
c: byte = '0';
if j := digs.decimal_point + i; 0 <= j && j < digs.count {
c = digs.digits[j];
}
add_bytes(&b, c);
}
}
return to_bytes(b);
case 'e', 'E':
add_bytes(&b, neg ? '-' : '+');
ch := byte('0');
if digs.count != 0 {
ch = digs.digits[0];
}
add_bytes(&b, ch);
if prec > 0 {
add_bytes(&b, '.');
i := 1;
m := min(digs.count, prec+1);
if i < m {
add_bytes(&b, ..digs.digits[i:m]);
i = m;
}
for ; i <= prec; i += 1 {
add_bytes(&b, '0');
}
}
add_bytes(&b, fmt);
exp := digs.decimal_point-1;
if digs.count == 0 {
// Zero has exponent of 0
exp = 0;
}
ch = '+';
if exp < 0 {
ch = '-';
exp = -exp;
}
add_bytes(&b, ch);
switch {
case exp < 10: add_bytes(&b, '0', byte(exp)+'0'); // add prefix 0
case exp < 100: add_bytes(&b, byte(exp/10)+'0', byte(exp%10)+'0');
case: add_bytes(&b, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0');
}
return to_bytes(b);
case 'g', 'G':
eprec := prec;
if eprec > digs.count && digs.count >= digs.decimal_point {
eprec = digs.count;
}
if shortest {
eprec = 6;
}
exp := digs.decimal_point - 1;
if exp < -4 || exp >= eprec {
if prec > digs.count {
prec = digs.count;
}
return format_digits(buf, shortest, neg, digs, prec-1, fmt+'e'-'g'); // keep the same case
}
if prec > digs.decimal_point {
prec = digs.count;
}
return format_digits(buf, shortest, neg, digs, max(prec-digs.decimal_point, 0), 'f');
case:
add_bytes(&b, '%', fmt);
return to_bytes(b);
}
}
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
if mant == 0 { // If mantissa is zero, the number is zero
d.count = 0;
return;
}
/*
10^(dp-nd) > 2^(exp-mantbits)
log2(10) * (dp-nd) > exp-mantbits
log(2) >~ 0.332
332*(dp-nd) >= 100*(exp-mantbits)
*/
minexp := flt.bias+1;
if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - int(flt.mantbits)) {
// Number is already its shortest
return;
}
upper_: Decimal; upper := &upper_;
assign(upper, 2*mant - 1);
shift(upper, exp - int(flt.mantbits) - 1);
mantlo: u64;
explo: int;
if mant > 1<<flt.mantbits || exp == minexp {
mantlo = mant-1;
explo = exp;
} else {
mantlo = 2*mant - 1;
explo = exp-1;
}
lower_: Decimal; lower := &lower_;
assign(lower, 2*mantlo + 1);
shift(lower, explo - int(flt.mantbits) - 1);
inclusive := mant%2 == 0;
for i in 0..<d.count {
l: byte = '0'; // lower digit
if i < lower.count {
l = lower.digits[i];
}
m := d.digits[i]; // middle digit
u: byte = '0'; // upper digit
if i < upper.count {
u = upper.digits[i];
}
ok_round_down := l != m || inclusive && i+1 == lower.count;
ok_round_up := m != u && (inclusive || m+1 < u || i+1 < upper.count);
if ok_round_down && ok_round_up {
round(d, i+1);
return;
}
if ok_round_down {
round_down(d, i+1);
return;
}
if ok_round_up {
round_up(d, i+1);
return;
}
}
}
MAX_BASE :: 32;
digits := "0123456789abcdefghijklmnopqrstuvwxyz";
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:
i := i8(u);
neg = i < 0;
u = u64(abs(i64(i)));
case 16:
i := i16(u);
neg = i < 0;
u = u64(abs(i64(i)));
case 32:
i := i32(u);
neg = i < 0;
u = u64(abs(i64(i)));
case 64:
i := i64(u);
neg = i < 0;
u = u64(abs(i64(i)));
case:
panic("is_integer_negative: Unknown integer size");
}
}
return;
}
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");
}
a: [129]byte;
i := len(a);
u, neg := is_integer_negative(x, is_signed, bit_size);
b := u64(base);
for u >= b {
i-=1; a[i] = digits[u % b];
u /= b;
}
i-=1; a[i] = digits[u % b];
if .Prefix in flags {
ok := true;
switch base {
case 2: i-=1; a[i] = 'b';
case 8: i-=1; a[i] = 'o';
case 10: i-=1; a[i] = 'd';
case 12: i-=1; a[i] = 'z';
case 16: i-=1; a[i] = 'x';
case: ok = false;
}
if ok {
i-=1; a[i] = '0';
}
}
switch {
case neg:
i-=1; a[i] = '-';
case .Plus in flags:
i-=1; a[i] = '+';
case .Space in flags:
i-=1; a[i] = ' ';
}
out := a[i:];
copy(buf, out);
return string(buf[0:len(out)]);
}
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:
i := i8(u);
neg = i < 0;
u = u128(abs(i128(i)));
case 16:
i := i16(u);
neg = i < 0;
u = u128(abs(i128(i)));
case 32:
i := i32(u);
neg = i < 0;
u = u128(abs(i128(i)));
case 64:
i := i64(u);
neg = i < 0;
u = u128(abs(i128(i)));
case 128:
i := i128(u);
neg = i < 0;
u = u128(abs(i128(i)));
case:
panic("is_integer_negative: Unknown integer size");
}
}
return;
}
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");
}
a: [140]byte;
i := len(a);
u, neg := is_integer_negative_128(x, is_signed, bit_size);
b := u128(base);
for u >= b {
i-=1; a[i] = digits[u % b];
u /= b;
}
i-=1; a[i] = digits[u % b];
if .Prefix in flags {
ok := true;
switch base {
case 2: i-=1; a[i] = 'b';
case 8: i-=1; a[i] = 'o';
case 10: i-=1; a[i] = 'd';
case 12: i-=1; a[i] = 'z';
case 16: i-=1; a[i] = 'x';
case: ok = false;
}
if ok {
i-=1; a[i] = '0';
}
}
switch {
case neg:
i-=1; a[i] = '-';
case .Plus in flags:
i-=1; a[i] = '+';
case .Space in flags:
i-=1; a[i] = ' ';
}
out := a[i:];
copy(buf, out);
return string(buf[0:len(out)]);
}
+308
View File
@@ -0,0 +1,308 @@
package strconv
import "core:unicode/utf8"
parse_bool :: proc(s: string) -> (result: bool = false, ok: bool) {
switch s {
case "1", "t", "T", "true", "TRUE", "True":
return true, true;
case "0", "f", "F", "false", "FALSE", "False":
return false, true;
}
return;
}
_digit_value :: proc(r: rune) -> int {
ri := int(r);
v: int = 16;
switch r {
case '0'..'9': v = ri-'0';
case 'a'..'z': v = ri-'a'+10;
case 'A'..'Z': v = ri-'A'+10;
}
return v;
}
parse_i64 :: proc(str: string) -> i64 {
s := str;
neg := false;
if len(s) > 1 {
switch s[0] {
case '-':
neg = true;
s = s[1:];
case '+':
s = s[1:];
}
}
base: i64 = 10;
if len(s) > 2 && s[0] == '0' {
switch s[1] {
case 'b': base = 2; s = s[2:];
case 'o': base = 8; s = s[2:];
case 'd': base = 10; s = s[2:];
case 'z': base = 12; s = s[2:];
case 'x': base = 16; s = s[2:];
}
}
value: i64;
for r in s {
if r == '_' {
continue;
}
v := i64(_digit_value(r));
if v >= base {
break;
}
value *= base;
value += v;
}
if neg do return -value;
return value;
}
parse_u64 :: proc(str: string) -> u64 {
s := str;
neg := false;
if len(s) > 1 && s[0] == '+' {
s = s[1:];
}
base := u64(10);
if len(s) > 2 && s[0] == '0' {
switch s[1] {
case 'b': base = 2; s = s[2:];
case 'o': base = 8; s = s[2:];
case 'd': base = 10; s = s[2:];
case 'z': base = 12; s = s[2:];
case 'x': base = 16; s = s[2:];
}
}
value: u64;
for r in s {
if r == '_' do continue;
v := u64(_digit_value(r));
if v >= base do break;
value *= base;
value += u64(v);
}
if neg do return -value;
return value;
}
parse_int :: proc(s: string) -> int {
return int(parse_i64(s));
}
parse_uint :: proc(s: string, base: int) -> uint {
return uint(parse_u64(s));
}
parse_f32 :: proc(s: string) -> f32 {
return f32(parse_f64(s));
}
parse_f64 :: proc(s: string) -> f64 {
if s == "" {
return 0;
}
i := 0;
sign: f64 = 1;
switch s[i] {
case '-': i += 1; sign = -1;
case '+': i += 1;
}
value: f64 = 0;
for ; i < len(s); i += 1 {
r := rune(s[i]);
if r == '_' do continue;
v := _digit_value(r);
if v >= 10 do break;
value *= 10;
value += f64(v);
}
if i < len(s) && s[i] == '.' {
pow10: f64 = 10;
i += 1;
for ; i < len(s); i += 1 {
r := rune(s[i]);
if r == '_' do continue;
v := _digit_value(r);
if v >= 10 do break;
value += f64(v)/pow10;
pow10 *= 10;
}
}
frac := false;
scale: f64 = 1;
if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
i += 1;
if i < len(s) {
switch s[i] {
case '-': i += 1; frac = true;
case '+': i += 1;
}
exp: u32 = 0;
for ; i < len(s); i += 1 {
r := rune(s[i]);
if r == '_' do continue;
d := u32(_digit_value(r));
if d >= 10 do break;
exp = exp * 10 + d;
}
if exp > 308 { exp = 308; }
for exp >= 50 { scale *= 1e50; exp -= 50; }
for exp >= 8 { scale *= 1e8; exp -= 8; }
for exp > 0 { scale *= 10; exp -= 1; }
}
}
if frac do return sign * (value/scale);
return sign * (value*scale);
}
append_bool :: proc(buf: []byte, b: bool) -> string {
n := 0;
if b do n = copy(buf, cast([]byte)"true");
else do n = copy(buf, cast([]byte)"false");
return string(buf[:n]);
}
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
return append_bits(buf, u64(u), base, false, 8*size_of(uint), digits, nil);
}
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil);
}
itoa :: proc(buf: []byte, i: int) -> string {
return append_int(buf, i64(i), 10);
}
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, str: string) -> string {
write_byte :: inline proc(buf: []byte, i: ^int, bytes: ..byte) {
if i^ >= len(buf) do return;
n := copy(buf[i^:], bytes[:]);
i^ += n;
}
if buf == nil {
return "";
}
c :: '"';
i := 0;
s := str;
write_byte(buf, &i, c);
for width := 0; len(s) > 0; s = s[width:] {
r := rune(s[0]);
width = 1;
if r >= utf8.RUNE_SELF {
r, width = utf8.decode_rune_in_string(s);
}
if width == 1 && r == utf8.RUNE_ERROR {
write_byte(buf, &i, '\\', 'x');
write_byte(buf, &i, digits[s[0]>>4]);
write_byte(buf, &i, digits[s[0]&0xf]);
}
if i < len(buf) {
x := quote_rune(buf[i:], r);
i += len(x);
}
}
write_byte(buf, &i, c);
return string(buf[:i]);
}
quote_rune :: proc(buf: []byte, r: rune) -> string {
write_byte :: inline proc(buf: []byte, i: ^int, bytes: ..byte) {
if i^ < len(buf) {
n := copy(buf[i^:], bytes[:]);
i^ += n;
}
}
write_string :: inline proc(buf: []byte, i: ^int, s: string) {
if i^ < len(buf) {
n := copy(buf[i^:], cast([]byte)s);
i^ += n;
}
}
write_rune :: inline proc(buf: []byte, i: ^int, r: rune) {
if i^ < len(buf) {
b, w := utf8.encode_rune(r);
n := copy(buf[i^:], b[:w]);
i^ += n;
}
}
if buf == nil {
return "";
}
i := 0;
write_byte(buf, &i, '\'');
switch r {
case '\a': write_string(buf, &i, "\\a");
case '\b': write_string(buf, &i, "\\b");
case '\e': write_string(buf, &i, "\\e");
case '\f': write_string(buf, &i, "\\f");
case '\n': write_string(buf, &i, "\\n");
case '\r': write_string(buf, &i, "\\r");
case '\t': write_string(buf, &i, "\\t");
case '\v': write_string(buf, &i, "\\v");
case:
if r < 32 {
write_string(buf, &i, "\\x");
b: [2]byte;
s := append_bits(b[:], u64(r), 16, true, 64, digits, nil);
switch len(s) {
case 0: write_string(buf, &i, "00");
case 1: write_rune(buf, &i, '0');
case 2: write_string(buf, &i, s);
}
} else {
write_rune(buf, &i, r);
}
}
write_byte(buf, &i, '\'');
return string(buf[:i]);
}
-21
View File
@@ -1,21 +0,0 @@
proc new_string(s: string) -> string {
var c = make([]u8, len(s)+1);
copy(c, []u8(s));
c[len(s)] = 0;
return string(c[0..<len(s)]);
}
proc new_c_string(s: string) -> ^u8 {
var c = make([]u8, len(s)+1);
copy(c, []u8(s));
c[len(s)] = 0;
return &c[0];
}
proc to_odin_string(c: ^u8) -> string {
var len = 0;
for (c+len)^ != 0 {
len++;
}
return string(slice_ptr(c, len));
}
+217
View File
@@ -0,0 +1,217 @@
package strings
import "core:mem"
import "core:unicode/utf8"
import "core:strconv"
Builder :: struct {
buf: [dynamic]byte,
}
make_builder :: proc(allocator := context.allocator) -> Builder {
return Builder{make([dynamic]byte, allocator)};
}
destroy_builder :: proc(b: ^Builder) {
delete(b.buf);
clear(&b.buf);
}
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{
data = s.data,
len = 0,
cap = s.len,
allocator = mem.nil_allocator(),
};
return transmute(Builder)d;
}
to_string :: proc(b: Builder) -> string {
return string(b.buf[:]);
}
builder_len :: proc(b: Builder) -> int {
return len(b.buf);
}
builder_cap :: proc(b: Builder) -> int {
return cap(b.buf);
}
write_byte :: proc(b: ^Builder, x: byte) {
append(&b.buf, x);
}
write_rune :: proc(b: ^Builder, r: rune) -> int {
if r < utf8.RUNE_SELF {
write_byte(b, byte(r));
return 1;
}
s, n := utf8.encode_rune(r);
write_bytes(b, s[:n]);
return n;
}
write_string :: proc(b: ^Builder, s: string) {
write_bytes(b, cast([]byte)s);
}
write_bytes :: proc(b: ^Builder, x: []byte) {
append(&b.buf, ..x);
}
@(private, static)
DIGITS_LOWER := "0123456789abcdefx";
write_quoted_string :: proc(b: ^Builder, str: string, quote: byte = '"') {
write_byte(b, quote);
for width, s := 0, str; len(s) > 0; s = s[width:] {
r := rune(s[0]);
width = 1;
if r >= utf8.RUNE_SELF {
r, width = utf8.decode_rune_in_string(s);
}
if width == 1 && r == utf8.RUNE_ERROR {
write_byte(b, '\\');
write_byte(b, 'x');
write_byte(b, DIGITS_LOWER[s[0]>>4]);
write_byte(b, DIGITS_LOWER[s[0]&0xf]);
continue;
}
write_escaped_rune(b, r, quote);
}
write_byte(b, quote);
}
write_encoded_rune :: proc(b: ^Builder, r: rune, write_quote := true) {
if write_quote do write_byte(b, '\'');
switch r {
case '\a': write_string(b, `\a"`);
case '\b': write_string(b, `\b"`);
case '\e': write_string(b, `\e"`);
case '\f': write_string(b, `\f"`);
case '\n': write_string(b, `\n"`);
case '\r': write_string(b, `\r"`);
case '\t': write_string(b, `\t"`);
case '\v': write_string(b, `\v"`);
case:
if r < 32 {
write_string(b, `\x`);
buf: [2]byte;
s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil);
switch len(s) {
case 0: write_string(b, "00");
case 1: write_byte(b, '0');
case 2: write_string(b, s);
}
} else {
write_rune(b, r);
}
}
if write_quote do write_byte(b, '\'');
}
write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) {
is_printable :: proc(r: rune) -> bool {
if r <= 0xff {
switch r {
case 0x20..0x7e:
return true;
case 0xa1..0xff: // ¡ through ÿ except for the soft hyphen
return r != 0xad; //
}
}
// TODO(bill): A proper unicode library will be needed!
return false;
}
if html_safe {
switch r {
case '<', '>', '&':
write_byte(b, '\\');
write_byte(b, 'u');
for s := 12; s >= 0; s -= 4 {
write_byte(b, DIGITS_LOWER[r>>uint(s) & 0xf]);
}
return;
}
}
if r == rune(quote) || r == '\\' {
write_byte(b, '\\');
write_byte(b, byte(r));
return;
} else if is_printable(r) {
write_encoded_rune(b, r, false);
return;
}
switch r {
case '\a': write_string(b, `\a`);
case '\b': write_string(b, `\b`);
case '\e': write_string(b, `\e`);
case '\f': write_string(b, `\f`);
case '\n': write_string(b, `\n`);
case '\r': write_string(b, `\r`);
case '\t': write_string(b, `\t`);
case '\v': write_string(b, `\v`);
case:
switch c := r; {
case c < ' ':
write_byte(b, '\\');
write_byte(b, 'x');
write_byte(b, DIGITS_LOWER[byte(c)>>4]);
write_byte(b, DIGITS_LOWER[byte(c)&0xf]);
case c > utf8.MAX_RUNE:
c = 0xfffd;
fallthrough;
case c < 0x10000:
write_byte(b, '\\');
write_byte(b, 'u');
for s := 12; s >= 0; s -= 4 {
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[c>>uint(s) & 0xf]);
}
}
}
}
write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) {
buf: [32]byte;
s := strconv.append_bits(buf[:], u64(i), base, false, 64, strconv.digits, nil);
write_string(b, s);
}
write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) {
buf: [32]byte;
s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil);
write_string(b, s);
}
write_uint :: proc(b: ^Builder, i: uint, base: int = 10) {
write_u64(b, u64(i), base);
}
write_int :: proc(b: ^Builder, i: int, base: int = 10) {
write_i64(b, i64(i), base);
}
+845
View File
@@ -0,0 +1,845 @@
package strings
import "core:mem"
import "core:unicode/utf8"
clone :: proc(s: string, allocator := context.allocator) -> string {
c := make([]byte, len(s)+1, allocator);
copy(c, cast([]byte)s);
c[len(s)] = 0;
return string(c[:len(s)]);
}
clone_to_cstring :: proc(s: string, allocator := context.allocator) -> cstring {
c := make([]byte, len(s)+1, allocator);
copy(c, cast([]byte)s);
c[len(s)] = 0;
return cstring(&c[0]);
}
@(deprecated="Please use 'strings.clone'")
new_string :: proc(s: string, allocator := context.allocator) -> string {
c := make([]byte, len(s)+1, allocator);
copy(c, cast([]byte)s);
c[len(s)] = 0;
return string(c[:len(s)]);
}
@(deprecated="Please use 'strings.clone_to_cstring'")
new_cstring :: proc(s: string, allocator := context.allocator) -> cstring {
c := make([]byte, len(s)+1, allocator);
copy(c, cast([]byte)s);
c[len(s)] = 0;
return cstring(&c[0]);
}
@(deprecated="Please use a standard cast for cstring to string")
to_odin_string :: proc(str: cstring) -> string {
return string(str);
}
string_from_ptr :: proc(ptr: ^byte, len: int) -> string {
return transmute(string)mem.Raw_String{ptr, len};
}
compare :: proc(lhs, rhs: string) -> int {
return mem.compare(cast([]byte)lhs, cast([]byte)rhs);
}
contains_rune :: proc(s: string, r: rune) -> int {
for c, offset in s {
if c == r do return offset;
}
return -1;
}
contains :: proc(s, substr: string) -> bool {
return index(s, substr) >= 0;
}
contains_any :: proc(s, chars: string) -> bool {
return index_any(s, chars) >= 0;
}
rune_count :: proc(s: string) -> int {
return utf8.rune_count_in_string(s);
}
equal_fold :: proc(u, v: string) -> bool {
s, t := u, v;
loop: for s != "" && t != "" {
sr, tr: rune;
if s[0] < utf8.RUNE_SELF {
sr, s = rune(s[0]), s[1:];
} else {
r, size := utf8.decode_rune_in_string(s);
sr, s = r, s[size:];
}
if t[0] < utf8.RUNE_SELF {
tr, t = rune(t[0]), t[1:];
} else {
r, size := utf8.decode_rune_in_string(t);
tr, t = r, t[size:];
}
if tr == sr { // easy case
continue loop;
}
if tr < sr {
tr, sr = sr, tr;
}
if tr < utf8.RUNE_SELF {
switch sr {
case 'A'..'Z':
if tr == (sr+'a')-'A' {
continue loop;
}
}
return false;
}
// TODO(bill): Unicode folding
return false;
}
return s == t;
}
has_prefix :: proc(s, prefix: string) -> bool {
return len(s) >= len(prefix) && s[0:len(prefix)] == prefix;
}
has_suffix :: proc(s, suffix: string) -> bool {
return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix;
}
join :: proc(a: []string, sep: string, allocator := context.allocator) -> string {
if len(a) == 0 {
return "";
}
n := len(sep) * (len(a) - 1);
for s in a {
n += len(s);
}
b := make([]byte, n, allocator);
i := copy(b, cast([]byte)a[0]);
for s in a[1:] {
i += copy(b[i:], cast([]byte)sep);
i += copy(b[i:], cast([]byte)s);
}
return string(b);
}
concatenate :: proc(a: []string, allocator := context.allocator) -> string {
if len(a) == 0 {
return "";
}
n := 0;
for s in a {
n += len(s);
}
b := make([]byte, n, allocator);
i := 0;
for s in a {
i += copy(b[i:], cast([]byte)s);
}
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;
}
return -1;
}
// Returns i1 if c is not present
last_index_byte :: proc(s: string, c: byte) -> int {
for i := len(s)-1; i >= 0; i -= 1 {
if s[i] == c do return i;
}
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:
return 0;
case n == 1:
return index_byte(s, substr[0]);
case n == len(s):
if s == substr {
return 0;
}
return -1;
case n > len(s):
return -1;
}
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;
}
}
return -1;
}
index_any :: proc(s, chars: string) -> int {
if chars == "" {
return -1;
}
// TODO(bill): Optimize
for r, i in s {
for c in chars {
if r == c {
return i;
}
}
}
return -1;
}
last_index_any :: proc(s, chars: string) -> int {
if chars == "" {
return -1;
}
for i := len(s); i > 0; {
r, w := utf8.decode_last_rune_in_string(s[:i]);
i -= w;
for c in chars {
if r == c {
return i;
}
}
}
return -1;
}
count :: proc(s, substr: string) -> int {
if len(substr) == 0 { // special case
return rune_count(s) + 1;
}
if len(substr) == 1 {
c := substr[0];
switch len(s) {
case 0:
return 0;
case 1:
return int(s[0] == c);
}
n := 0;
for i := 0; i < len(s); i += 1 {
if s[i] == c {
n += 1;
}
}
return n;
}
// TODO(bill): Use a non-brute for approach
n := 0;
str := s;
for {
i := index(str, substr);
if i == -1 {
return n;
}
n += 1;
str = str[i+len(substr):];
}
return n;
}
repeat :: proc(s: string, count: int, allocator := context.allocator) -> string {
if count < 0 {
panic("strings: negative repeat count");
} else if count > 0 && (len(s)*count)/count != len(s) {
panic("strings: repeat count will cause an overflow");
}
b := make([]byte, len(s)*count, allocator);
i := copy(b, cast([]byte)s);
for i < len(b) { // 2^N trick to reduce the need to copy
copy(b[i:], b[:i]);
i *= 2;
}
return string(b);
}
replace_all :: proc(s, old, new: string, allocator := context.allocator) -> (output: string, was_allocation: bool) {
return replace(s, old, new, -1, allocator);
}
// if n < 0, no limit on the number of replacements
replace :: proc(s, old, new: string, n: int, allocator := context.allocator) -> (output: string, was_allocation: bool) {
if old == new || n == 0 {
was_allocation = false;
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 {
byte_count = m;
}
t := make([]byte, len(s) + byte_count*(len(new) - len(old)), allocator);
was_allocation = true;
w := 0;
start := 0;
for i := 0; i < byte_count; i += 1 {
j := start;
if len(old) == 0 {
if i > 0 {
_, width := utf8.decode_rune_in_string(s[start:]);
j += width;
}
} else {
j += index(s[start:], old);
}
w += copy(t[w:], cast([]byte)s[start:j]);
w += copy(t[w:], cast([]byte)new);
start = j + len(old);
}
w += copy(t[w:], cast([]byte)s[start:]);
output = string(t[0:w]);
return;
}
is_ascii_space :: proc(r: rune) -> bool {
switch r {
case '\t', '\n', '\v', '\f', '\r', ' ':
return true;
}
return false;
}
is_space :: proc(r: rune) -> bool {
if r < 0x2000 {
switch r {
case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xa0, 0x1680:
return true;
}
} else {
if r <= 0x200a {
return true;
}
switch r {
case 0x2028, 0x2029, 0x202f, 0x205f, 0x3000:
return true;
}
}
return false;
}
is_null :: proc(r: rune) -> bool {
return r == 0x0000;
}
index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> int {
for r, i in s {
if p(r) == truth {
return i;
}
}
return -1;
}
index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr, truth := true) -> int {
for r, i in s {
if p(state, r) == truth {
return i;
}
}
return -1;
}
last_index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> int {
// TODO(bill): Probably use Rabin-Karp Search
for i := len(s); i > 0; {
r, size := utf8.decode_last_rune_in_string(s[:i]);
i -= size;
if p(r) == truth {
return i;
}
}
return -1;
}
last_index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr, truth := true) -> int {
// TODO(bill): Probably use Rabin-Karp Search
for i := len(s); i > 0; {
r, size := utf8.decode_last_rune_in_string(s[:i]);
i -= size;
if p(state, r) == truth {
return i;
}
}
return -1;
}
trim_left_proc :: proc(s: string, p: proc(rune) -> bool) -> string {
i := index_proc(s, p, false);
if i == -1 {
return "";
}
return s[i:];
}
index_rune :: proc(s: string, r: rune) -> int {
switch {
case 0 <= r && r < utf8.RUNE_SELF:
return index_byte(s, byte(r));
case r == utf8.RUNE_ERROR:
for c, i in s {
if c == utf8.RUNE_ERROR {
return i;
}
}
return -1;
case !utf8.valid_rune(r):
return -1;
}
b, w := utf8.encode_rune(r);
return index(s, string(b[:w]));
}
trim_left_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr) -> string {
i := index_proc_with_state(s, p, state, false);
if i == -1 {
return "";
}
return s[i:];
}
trim_right_proc :: proc(s: string, p: proc(rune) -> bool) -> string {
i := last_index_proc(s, p, false);
if i >= 0 && s[i] >= utf8.RUNE_SELF {
_, w := utf8.decode_rune_in_string(s[i:]);
i += w;
} else {
i += 1;
}
return s[0:i];
}
trim_right_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr) -> string {
i := last_index_proc_with_state(s, p, state, false);
if i >= 0 && s[i] >= utf8.RUNE_SELF {
_, w := utf8.decode_rune_in_string(s[i:]);
i += w;
} else {
i += 1;
}
return s[0:i];
}
is_in_cutset :: proc(state: rawptr, r: rune) -> bool {
if state == nil {
return false;
}
cutset := (^string)(state)^;
for c in cutset {
if r == c {
return true;
}
}
return false;
}
trim_left :: proc(s: string, cutset: string) -> string {
if s == "" || cutset == "" {
return s;
}
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;
}
state := cutset;
return trim_right_proc_with_state(s, is_in_cutset, &state);
}
trim :: proc(s: string, cutset: string) -> string {
return trim_right(trim_left(s, cutset), cutset);
}
trim_left_space :: proc(s: string) -> string {
return trim_left_proc(s, is_space);
}
trim_right_space :: proc(s: string) -> string {
return trim_right_proc(s, is_space);
}
trim_space :: proc(s: string) -> string {
return trim_right_space(trim_left_space(s));
}
trim_left_null :: proc(s: string) -> string {
return trim_left_proc(s, is_null);
}
trim_right_null :: proc(s: string) -> string {
return trim_right_proc(s, is_null);
}
trim_null :: proc(s: string) -> string {
return trim_right_null(trim_left_null(s));
}
// scrub scruvs invalid utf-8 characters and replaces them with the replacement string
// Adjacent invalid bytes are only replaced once
scrub :: proc(s: string, replacement: string, allocator := context.allocator) -> string {
str := s;
b := make_builder(allocator);;
grow_builder(&b, len(str));
has_error := false;
cursor := 0;
origin := str;
for len(str) > 0 {
r, w := utf8.decode_rune_in_string(str);
if r == utf8.RUNE_ERROR {
if !has_error {
has_error = true;
write_string(&b, origin[:cursor]);
}
} else if has_error {
has_error = false;
write_string(&b, replacement);
origin = origin[cursor:];
cursor = 0;
}
cursor += w;
str = str[w:];
}
return to_string(b);
}
reverse :: proc(s: string, allocator := context.allocator) -> string {
str := s;
n := len(str);
buf := make([]byte, n);
i := 0;
for len(str) > 0 {
_, w := utf8.decode_rune_in_string(str);
copy(buf[i:], cast([]byte)str[:w]);
str = str[w:];
}
return string(buf);
}
expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) -> string {
if tab_size <= 0 {
panic("tab size must be positive");
}
if s == "" {
return "";
}
b := make_builder(allocator);
str := s;
column: int;
for len(str) > 0 {
r, w := utf8.decode_rune_in_string(str);
if r == '\t' {
expand := tab_size - column%tab_size;
for i := 0; i < expand; i += 1 {
write_byte(&b, ' ');
}
column += expand;
} else {
if r == '\n' {
column = 0;
} else {
column += w;
}
write_rune(&b, r);
}
str = str[w:];
}
return to_string(b);
}
partition :: proc(str, sep: string) -> (head, match, tail: string) {
i := index(str, sep);
if i == -1 {
head = str;
return;
}
head = str[:i];
match = str[i:i+len(sep)];
tail = str[i+len(sep):];
return;
}
center_justify :: centre_justify; // NOTE(bill): Because Americans exist
// centre_justify returns a string with a pad string at boths sides if the str's rune length is smaller than length
centre_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
n := rune_count(str);
if n >= length || pad == "" {
return clone(str, allocator);
}
remains := length-1;
pad_len := rune_count(pad);
b := make_builder(allocator);
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad));
write_pad_string(&b, pad, pad_len, remains/2);
write_string(&b, str);
write_pad_string(&b, pad, pad_len, (remains+1)/2);
return to_string(b);
}
// left_justify returns a string with a pad string at left side if the str's rune length is smaller than length
left_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
n := rune_count(str);
if n >= length || pad == "" {
return clone(str, allocator);
}
remains := length-1;
pad_len := rune_count(pad);
b := make_builder(allocator);
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad));
write_string(&b, str);
write_pad_string(&b, pad, pad_len, remains);
return to_string(b);
}
// right_justify returns a string with a pad string at right side if the str's rune length is smaller than length
right_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
n := rune_count(str);
if n >= length || pad == "" {
return clone(str, allocator);
}
remains := length-1;
pad_len := rune_count(pad);
b := make_builder(allocator);
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad));
write_pad_string(&b, pad, pad_len, remains);
write_string(&b, str);
return to_string(b);
}
@private
write_pad_string :: proc(b: ^Builder, pad: string, pad_len, remains: int) {
repeats := remains / pad_len;
for i := 0; i < repeats; i += 1 {
write_string(b, pad);
}
n := remains % pad_len;
p := pad;
for i := 0; i < n; i += 1 {
r, w := utf8.decode_rune_in_string(p);
write_rune(b, r);
p = p[w:];
}
}
-4
View File
@@ -1,4 +0,0 @@
import_load (
"sync_windows.odin" when ODIN_OS == "windows";
"sync_linux.odin" when ODIN_OS == "linux";
)
+211
View File
@@ -0,0 +1,211 @@
package sync
import "intrinsics"
Ordering :: enum {
Relaxed, // Monotonic
Release,
Acquire,
Acquire_Release,
Sequentially_Consistent,
}
strongest_failure_ordering :: inline proc "contextless" (order: Ordering) -> Ordering {
#complete switch order {
case .Relaxed: return .Relaxed;
case .Release: return .Relaxed;
case .Acquire: return .Acquire;
case .Acquire_Release: return .Acquire;
case .Sequentially_Consistent: return .Sequentially_Consistent;
}
return .Relaxed;
}
fence :: inline proc "contextless" ($order: Ordering) {
#complete switch order {
case .Relaxed: panic("there is no such thing as a relaxed fence");
case .Release: intrinsics.atomic_fence_rel();
case .Acquire: intrinsics.atomic_fence_acq();
case .Acquire_Release: intrinsics.atomic_fence_acqrel();
case .Sequentially_Consistent: intrinsics.atomic_fence();
case: panic("unknown order");
}
}
atomic_store :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) {
#complete switch order {
case .Relaxed: intrinsics.atomic_store_relaxed(dst, val);
case .Release: intrinsics.atomic_store_rel(dst, val);
case .Sequentially_Consistent: intrinsics.atomic_store(dst, val);
case .Acquire: panic("there is not such thing as an acquire store");
case .Acquire_Release: panic("there is not such thing as an acquire/release store");
case: panic("unknown order");
}
}
atomic_load :: inline proc "contextless" (dst: ^$T, $order: Ordering) -> T {
#complete switch order {
case .Relaxed: return intrinsics.atomic_load_relaxed(dst);
case .Acquire: return intrinsics.atomic_load_acq(dst);
case .Sequentially_Consistent: return intrinsics.atomic_load(dst);
case .Release: panic("there is no such thing as a release load");
case .Acquire_Release: panic("there is no such thing as an acquire/release load");
}
panic("unknown order");
return T{};
}
atomic_swap :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T {
#complete switch order {
case .Relaxed: return intrinsics.atomic_xchg_relaxed(dst, val);
case .Release: return intrinsics.atomic_xchg_rel(dst, val);
case .Acquire: return intrinsics.atomic_xchg_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_xchg_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_xchg(dst, val);
}
panic("unknown order");
return T{};
}
atomic_compare_exchange :: inline proc "contextless" (dst: ^$T, old, new: T, $success, $failure: Ordering) -> (val: T, ok: bool) {
switch failure {
case .Relaxed:
switch success {
case .Relaxed: return intrinsics.atomic_cxchg_relaxed(dst, old, new);
case .Acquire: return intrinsics.atomic_cxchg_acq_failrelaxed(dst, old, new);
case .Acquire_Release: return intrinsics.atomic_cxchg_acqrel_failrelaxed(dst, old, new);
case .Sequentially_Consistent: return intrinsics.atomic_cxchg_failrelaxed(dst, old, new);
case .Release: return intrinsics.atomic_cxchg_rel(dst, old, new);
case: panic("an unknown ordering combination");
}
case .Acquire:
switch success {
case .Release: return intrinsics.atomic_cxchg_acqrel(dst, old, new);
case .Acquire: return intrinsics.atomic_cxchg_acq(dst, old, new);
case: panic("an unknown ordering combination");
}
case .Sequentially_Consistent:
switch success {
case .Sequentially_Consistent: return intrinsics.atomic_cxchg(dst, old, new);
case: panic("an unknown ordering combination");
}
case .Acquire_Release:
panic("there is not such thing as an acquire/release failure ordering");
case .Release:
switch success {
case .Acquire: return instrinsics.atomic_cxchg_failacq(dst, old, new);
case: panic("an unknown ordering combination");
}
}
return T{}, false;
}
atomic_compare_exchange_weak :: inline proc "contextless" (dst: ^$T, old, new: T, $success, $failure: Ordering) -> (val: T, ok: bool) {
switch failure {
case .Relaxed:
switch success {
case .Relaxed: return intrinsics.atomic_cxchgweak_relaxed(dst, old, new);
case .Acquire: return intrinsics.atomic_cxchgweak_acq_failrelaxed(dst, old, new);
case .Acquire_Release: return intrinsics.atomic_cxchgweak_acqrel_failrelaxed(dst, old, new);
case .Sequentially_Consistent: return intrinsics.atomic_cxchgweak_failrelaxed(dst, old, new);
case .Release: return intrinsics.atomic_cxchgweak_rel(dst, old, new);
case: panic("an unknown ordering combination");
}
case .Acquire:
switch success {
case .Release: return intrinsics.atomic_cxchgweak_acqrel(dst, old, new);
case .Acquire: return intrinsics.atomic_cxchgweak_acq(dst, old, new);
case: panic("an unknown ordering combination");
}
case .Sequentially_Consistent:
switch success {
case .Sequentially_Consistent: return intrinsics.atomic_cxchgweak(dst, old, new);
case: panic("an unknown ordering combination");
}
case .Acquire_Release:
panic("there is not such thing as an acquire/release failure ordering");
case .Release:
switch success {
case .Acquire: return intrinsics.atomic_cxchgweak_failacq(dst, old, new);
case: panic("an unknown ordering combination");
}
}
return T{}, false;
}
atomic_add :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T {
#complete switch order {
case .Relaxed: return intrinsics.atomic_add_relaxed(dst, val);
case .Release: return intrinsics.atomic_add_rel(dst, val);
case .Acquire: return intrinsics.atomic_add_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_add_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_add(dst, val);
}
panic("unknown order");
return T{};
}
atomic_sub :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T {
#complete switch order {
case .Relaxed: return intrinsics.atomic_sub_relaxed(dst, val);
case .Release: return intrinsics.atomic_sub_rel(dst, val);
case .Acquire: return intrinsics.atomic_sub_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_sub_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_sub(dst, val);
}
panic("unknown order");
return T{};
}
atomic_and :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T {
#complete switch order {
case .Relaxed: return intrinsics.atomic_and_relaxed(dst, val);
case .Release: return intrinsics.atomic_and_rel(dst, val);
case .Acquire: return intrinsics.atomic_and_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_and_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_and(dst, val);
}
panic("unknown order");
return T{};
}
atomic_nand :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T {
#complete switch order {
case .Relaxed: return intrinsics.atomic_nand_relaxed(dst, val);
case .Release: return intrinsics.atomic_nand_rel(dst, val);
case .Acquire: return intrinsics.atomic_nand_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_nand_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_nand(dst, val);
}
panic("unknown order");
return T{};
}
atomic_or :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T {
#complete switch order {
case .Relaxed: return intrinsics.atomic_or_relaxed(dst, val);
case .Release: return intrinsics.atomic_or_rel(dst, val);
case .Acquire: return intrinsics.atomic_or_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_or_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_or(dst, val);
}
panic("unknown order");
return T{};
}
atomic_xor :: inline proc "contextless" (dst: ^$T, val: T, $order: Ordering) -> T {
#complete switch order {
case .Relaxed: return intrinsics.atomic_xor_relaxed(dst, val);
case .Release: return intrinsics.atomic_xor_rel(dst, val);
case .Acquire: return intrinsics.atomic_xor_acq(dst, val);
case .Acquire_Release: return intrinsics.atomic_xor_acqrel(dst, val);
case .Sequentially_Consistent: return intrinsics.atomic_xor(dst, val);
}
panic("unknown order");
return T{};
}
@@ -1,69 +1,71 @@
import (
"atomics.odin";
"os.odin";
)
package sync
type Semaphore struct {
/*
import "core:atomics"
import "core:os"
Semaphore :: struct {
// _handle: win32.Handle,
}
type Mutex struct {
Mutex :: struct {
_semaphore: Semaphore,
_counter: i32,
_owner: i32,
_recursion: i32,
}
proc current_thread_id() -> i32 {
current_thread_id :: proc() -> i32 {
return i32(os.current_thread_id());
}
proc semaphore_init(s: ^Semaphore) {
semaphore_init :: proc(s: ^Semaphore) {
// s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
}
proc semaphore_destroy(s: ^Semaphore) {
semaphore_destroy :: proc(s: ^Semaphore) {
// win32.CloseHandle(s._handle);
}
proc semaphore_post(s: ^Semaphore, count: int) {
semaphore_post :: proc(s: ^Semaphore, count: int) {
// win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
}
proc semaphore_release(s: ^Semaphore) #inline {
semaphore_release :: inline proc(s: ^Semaphore) {
semaphore_post(s, 1);
}
proc semaphore_wait(s: ^Semaphore) {
semaphore_wait :: proc(s: ^Semaphore) {
// win32.WaitForSingleObject(s._handle, win32.INFINITE);
}
proc mutex_init(m: ^Mutex) {
mutex_init :: proc(m: ^Mutex) {
atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore);
m._recursion = 0;
}
proc mutex_destroy(m: ^Mutex) {
mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(&m._semaphore);
}
proc mutex_lock(m: ^Mutex) {
var thread_id = current_thread_id();
mutex_lock :: proc(m: ^Mutex) {
thread_id := current_thread_id();
if atomics.fetch_add(&m._counter, 1) > 0 {
if thread_id != atomics.load(&m._owner) {
semaphore_wait(&m._semaphore);
}
}
atomics.store(&m._owner, thread_id);
m._recursion++;
m._recursion += 1;
}
proc mutex_try_lock(m: ^Mutex) -> bool {
var thread_id = current_thread_id();
mutex_try_lock :: proc(m: ^Mutex) -> bool {
thread_id := current_thread_id();
if atomics.load(&m._owner) == thread_id {
atomics.fetch_add(&m._counter, 1);
} else {
var expected: i32 = 0;
expected: i32 = 0;
if atomics.load(&m._counter) != 0 {
return false;
}
@@ -72,15 +74,15 @@ proc mutex_try_lock(m: ^Mutex) -> bool {
}
atomics.store(&m._owner, thread_id);
}
m._recursion++;
m._recursion += 1;
return true;
}
proc mutex_unlock(m: ^Mutex) {
var recursion: i32;
var thread_id = current_thread_id();
mutex_unlock :: proc(m: ^Mutex) {
recursion: i32;
thread_id := current_thread_id();
assert(thread_id == atomics.load(&m._owner));
m._recursion--;
m._recursion -= 1;
recursion = m._recursion;
if recursion == 0 {
atomics.store(&m._owner, thread_id);
@@ -93,3 +95,4 @@ proc mutex_unlock(m: ^Mutex) {
}
}
*/
+111
View File
@@ -0,0 +1,111 @@
package sync
import "core:sys/win32"
foreign {
@(link_name="llvm.x86.sse2.pause")
yield_processor :: proc() ---
}
Semaphore :: struct {
_handle: win32.Handle,
}
Mutex :: struct {
_critical_section: win32.Critical_Section,
}
Condition :: struct {
event: win32.Handle,
}
Ticket_Mutex :: struct {
ticket: u64,
serving: u64,
}
current_thread_id :: proc() -> i32 {
return i32(win32.get_current_thread_id());
}
semaphore_init :: proc(s: ^Semaphore) {
s._handle = win32.create_semaphore_w(nil, 0, 1<<31-1, nil);
}
semaphore_destroy :: proc(s: ^Semaphore) {
win32.close_handle(s._handle);
}
semaphore_post :: proc(s: ^Semaphore, count: int) {
win32.release_semaphore(s._handle, i32(count), nil);
}
semaphore_release :: inline proc(s: ^Semaphore) {
semaphore_post(s, 1);
}
semaphore_wait :: proc(s: ^Semaphore) {
result := win32.wait_for_single_object(s._handle, win32.INFINITE);
assert(result != win32.WAIT_FAILED);
}
mutex_init :: proc(m: ^Mutex, spin_count := 0) {
win32.initialize_critical_section_and_spin_count(&m._critical_section, u32(spin_count));
}
mutex_destroy :: proc(m: ^Mutex) {
win32.delete_critical_section(&m._critical_section);
}
mutex_lock :: proc(m: ^Mutex) {
win32.enter_critical_section(&m._critical_section);
}
mutex_try_lock :: proc(m: ^Mutex) -> bool {
return bool(win32.try_enter_critical_section(&m._critical_section));
}
mutex_unlock :: proc(m: ^Mutex) {
win32.leave_critical_section(&m._critical_section);
}
condition_init :: proc(using c: ^Condition) {
event = win32.create_event_w(nil, false, false, nil);
assert(event != nil);
}
condition_signal :: proc(using c: ^Condition) {
ok := win32.set_event(event);
assert(bool(ok));
}
condition_wait_for :: proc(using c: ^Condition) {
result := win32.wait_for_single_object(event, win32.INFINITE);
assert(result != win32.WAIT_FAILED);
}
condition_destroy :: proc(using c: ^Condition) {
if event != nil {
win32.close_handle(event);
}
}
ticket_mutex_init :: proc(m: ^Ticket_Mutex) {
atomic_store(&m.ticket, 0, Ordering.Relaxed);
atomic_store(&m.serving, 0, Ordering.Relaxed);
}
ticket_mutex_lock :: inline proc(m: ^Ticket_Mutex) {
ticket := atomic_add(&m.ticket, 1, Ordering.Relaxed);
for ticket != m.serving {
yield_processor();
}
}
ticket_mutex_unlock :: inline proc(m: ^Ticket_Mutex) {
atomic_add(&m.serving, 1, Ordering.Relaxed);
}
-93
View File
@@ -1,93 +0,0 @@
import (
win32 "sys/windows.odin" when ODIN_OS == "windows";
"atomics.odin";
)
type Semaphore struct {
_handle: win32.Handle,
}
type Mutex struct {
_semaphore: Semaphore,
_counter: i32,
_owner: i32,
_recursion: i32,
}
proc current_thread_id() -> i32 {
return i32(win32.get_current_thread_id());
}
proc semaphore_init(s: ^Semaphore) {
s._handle = win32.create_semaphore_a(nil, 0, 1<<31-1, nil);
}
proc semaphore_destroy(s: ^Semaphore) {
win32.close_handle(s._handle);
}
proc semaphore_post(s: ^Semaphore, count: int) {
win32.release_semaphore(s._handle, i32(count), nil);
}
proc semaphore_release(s: ^Semaphore) #inline { semaphore_post(s, 1); }
proc semaphore_wait(s: ^Semaphore) {
win32.wait_for_single_object(s._handle, win32.INFINITE);
}
proc mutex_init(m: ^Mutex) {
atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore);
m._recursion = 0;
}
proc mutex_destroy(m: ^Mutex) {
semaphore_destroy(&m._semaphore);
}
proc mutex_lock(m: ^Mutex) {
var thread_id = current_thread_id();
if atomics.fetch_add(&m._counter, 1) > 0 {
if thread_id != atomics.load(&m._owner) {
semaphore_wait(&m._semaphore);
}
}
atomics.store(&m._owner, thread_id);
m._recursion++;
}
proc mutex_try_lock(m: ^Mutex) -> bool {
var thread_id = current_thread_id();
if atomics.load(&m._owner) == thread_id {
atomics.fetch_add(&m._counter, 1);
} else {
var expected: i32 = 0;
if atomics.load(&m._counter) != 0 {
return false;
}
if atomics.compare_exchange(&m._counter, expected, 1) == 0 {
return false;
}
atomics.store(&m._owner, thread_id);
}
m._recursion++;
return true;
}
proc mutex_unlock(m: ^Mutex) {
var recursion: i32;
var thread_id = current_thread_id();
assert(thread_id == atomics.load(&m._owner));
m._recursion--;
recursion = m._recursion;
if recursion == 0 {
atomics.store(&m._owner, thread_id);
}
if atomics.fetch_add(&m._counter, -1) > 1 {
if recursion == 0 {
semaphore_release(&m._semaphore);
}
}
}
-90
View File
@@ -1,90 +0,0 @@
foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
import . "windows.odin";
const (
CONTEXT_MAJOR_VERSION_ARB = 0x2091;
CONTEXT_MINOR_VERSION_ARB = 0x2092;
CONTEXT_FLAGS_ARB = 0x2094;
CONTEXT_PROFILE_MASK_ARB = 0x9126;
CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x0002;
CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001;
CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002;
)
type (
Hglrc Handle;
ColorRef u32;
LayerPlaneDescriptor struct {
size: u16,
version: u16,
flags: u32,
pixel_type: u8,
color_bits: u8,
red_bits: u8,
red_shift: u8,
green_bits: u8,
green_shift: u8,
blue_bits: u8,
blue_shift: u8,
alpha_bits: u8,
alpha_shift: u8,
accum_bits: u8,
accum_red_bits: u8,
accum_green_bits: u8,
accum_blue_bits: u8,
accum_alpha_bits: u8,
depth_bits: u8,
stencil_bits: u8,
aux_buffers: u8,
layer_type: u8,
reserved: u8,
transparent: ColorRef,
}
PointFloat struct {
x, y: f32,
}
Glyph_MetricsFloat struct {
black_box_x: f32,
black_box_y: f32,
glyph_origin: PointFloat,
cell_inc_x: f32,
cell_inc_y: f32,
}
)
type (
CreateContextAttribsARBType proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
ChoosePixelFormatARBType proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c;
SwapIntervalEXTType proc(interval: i32) -> bool #cc_c;
GetExtensionsStringARBType proc(Hdc) -> ^u8 #cc_c;
)
var (
create_context_attribs_arb: CreateContextAttribsARBType;
choose_pixel_format_arb: ChoosePixelFormatARBType;
swap_interval_ext: SwapIntervalEXTType;
get_extensions_string_arb: GetExtensionsStringARBType;
)
foreign opengl32 {
proc create_context (hdc: Hdc) -> Hglrc #link_name "wglCreateContext";
proc make_current (hdc: Hdc, hglrc: Hglrc) -> Bool #link_name "wglMakeCurrent";
proc get_proc_address (c_str: ^u8) -> Proc #link_name "wglGetProcAddress";
proc delete_context (hglrc: Hglrc) -> Bool #link_name "wglDeleteContext";
proc copy_context (src, dst: Hglrc, mask: u32) -> Bool #link_name "wglCopyContext";
proc create_layer_context (hdc: Hdc, layer_plane: i32) -> Hglrc #link_name "wglCreateLayerContext";
proc describe_layer_plane (hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^LayerPlaneDescriptor) -> Bool #link_name "wglDescribeLayerPlane";
proc get_current_context () -> Hglrc #link_name "wglGetCurrentContext";
proc get_current_dc () -> Hdc #link_name "wglGetCurrentDC";
proc get_layer_palette_entries(hdc: Hdc, layer_plane, start, entries: i32, cr: ^ColorRef) -> i32 #link_name "wglGetLayerPaletteEntries";
proc realize_layer_palette (hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool #link_name "wglRealizeLayerPalette";
proc set_layer_palette_entries(hdc: Hdc, layer_plane, start, entries: i32, cr: ^ColorRef) -> i32 #link_name "wglSetLayerPaletteEntries";
proc share_lists (hglrc1, hglrc2: Hglrc) -> Bool #link_name "wglShareLists";
proc swap_layer_buffers (hdc: Hdc, planes: u32) -> Bool #link_name "wglSwapLayerBuffers";
proc use_font_bitmaps (hdc: Hdc, first, count, list_base: u32) -> Bool #link_name "wglUseFontBitmaps";
proc use_font_outlines (hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_MetricsFloat) -> Bool #link_name "wglUseFontOutlines";
}
+188
View File
@@ -0,0 +1,188 @@
// +build windows
package win32
foreign import "system:comdlg32.lib"
import "core:strings"
OFN_Hook_Proc :: #type proc "stdcall" (hdlg: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Uint_Ptr;
Open_File_Name_A :: struct {
struct_size: u32,
hwnd_owner: Hwnd,
instance: Hinstance,
filter: cstring,
custom_filter: cstring,
max_cust_filter: u32,
filter_index: u32,
file: cstring,
max_file: u32,
file_title: cstring,
max_file_title: u32,
initial_dir: cstring,
title: cstring,
flags: u32,
file_offset: u16,
file_extension: u16,
def_ext: cstring,
cust_data: Lparam,
hook: OFN_Hook_Proc,
template_name: cstring,
pv_reserved: rawptr,
dw_reserved: u32,
flags_ex: u32,
}
Open_File_Name_W :: struct {
struct_size: u32,
hwnd_owner: Hwnd,
instance: Hinstance,
filter: Wstring,
custom_filter: Wstring,
max_cust_filter: u32,
filter_index: u32,
file: Wstring,
max_file: u32,
file_title: Wstring,
max_file_title: u32,
initial_dir: Wstring,
title: Wstring,
flags: u32,
file_offset: u16,
file_extension: u16,
def_ext: Wstring,
cust_data: Lparam,
hook: OFN_Hook_Proc,
template_name: Wstring,
pv_reserved: rawptr,
dw_reserved: u32,
flags_ex: u32,
}
@(default_calling_convention = "c")
foreign comdlg32 {
@(link_name="GetOpenFileNameA") get_open_file_name_a :: proc(arg1: ^Open_File_Name_A) -> Bool ---
@(link_name="GetOpenFileNameW") get_open_file_name_w :: proc(arg1: ^Open_File_Name_W) -> Bool ---
@(link_name="GetSaveFileNameA") get_save_file_name_a :: proc(arg1: ^Open_File_Name_A) -> Bool ---
@(link_name="GetSaveFileNameW") get_save_file_name_w :: proc(arg1: ^Open_File_Name_W) -> Bool ---
@(link_name="CommDlgExtendedError") comm_dlg_extended_error :: proc() -> u32 ---
}
OPEN_TITLE :: "Select file to open";
OPEN_FLAGS :: u32(OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST);
OPEN_FLAGS_MULTI :: u32(OPEN_FLAGS | OFN_ALLOWMULTISELECT | OFN_EXPLORER);
SAVE_TITLE :: "Select file to save";
SAVE_FLAGS :: u32(OFN_OVERWRITEPROMPT | OFN_EXPLORER);
SAVE_EXT :: "txt";
Open_Save_Mode :: enum {
Open = 0,
Save = 1,
}
_open_file_dialog :: proc(title: string, dir: string,
filters: []string, default_filter: u32,
flags: u32, default_ext: string,
mode: Open_Save_Mode, allocator := context.temp_allocator) -> (path: string, ok: bool = true) {
file_buf := make([]u16, MAX_PATH_WIDE, allocator);
// 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;
filter: string;
filter = strings.join(filters, "\u0000", context.temp_allocator);
filter = strings.concatenate({filter, "\u0000"}, context.temp_allocator);
ofn := Open_File_Name_W{
struct_size = size_of(Open_File_Name_W),
file = Wstring(&file_buf[0]),
max_file = MAX_PATH_WIDE,
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(clamp(default_filter, 1, filter_len / 2)),
def_ext = utf8_to_wstring(default_ext, context.temp_allocator),
flags = u32(flags),
};
switch mode {
case .Open:
ok = bool(get_open_file_name_w(&ofn));
case .Save:
ok = bool(get_save_file_name_w(&ofn));
case:
ok = false;
}
if !ok {
delete(file_buf);
return "", false;
}
file_name := utf16_to_utf8(file_buf[:], allocator);
path = strings.trim_right_null(file_name);
return;
}
select_file_to_open :: proc(title := OPEN_TITLE, dir := ".",
filters := []string{"All Files", "*.*"}, default_filter := u32(1),
flags := OPEN_FLAGS, allocator := context.temp_allocator) -> (path: string, ok: bool) {
path, ok = _open_file_dialog(title, dir, filters, default_filter, flags, "", Open_Save_Mode.Open, allocator);
return;
}
select_file_to_save :: proc(title := SAVE_TITLE, dir := ".",
filters := []string{"All Files", "*.*"}, default_filter := u32(1),
flags := SAVE_FLAGS, default_ext := SAVE_EXT,
allocator := context.temp_allocator) -> (path: string, ok: bool) {
path, ok = _open_file_dialog(title, dir, filters, default_filter, flags, default_ext, Open_Save_Mode.Save, allocator);
return;
}
// 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.
OFN_CREATEPROMPT :: 0x00002000;
OFN_DONTADDTORECENT :: 0x02000000;
OFN_ENABLEHOOK :: 0x00000020;
OFN_ENABLEINCLUDENOTIFY :: 0x00400000;
OFN_ENABLESIZING :: 0x00800000;
OFN_ENABLETEMPLATE :: 0x00000040;
OFN_ENABLETEMPLATEHANDLE :: 0x00000080;
OFN_EXPLORER :: 0x00080000;
OFN_EXTENSIONDIFFERENT :: 0x00000400;
OFN_FILEMUSTEXIST :: 0x00001000;
OFN_FORCESHOWHIDDEN :: 0x10000000;
OFN_HIDEREADONLY :: 0x00000004;
OFN_LONGNAMES :: 0x00200000;
OFN_NOCHANGEDIR :: 0x00000008;
OFN_NODEREFERENCELINKS :: 0x00100000;
OFN_NOLONGNAMES :: 0x00040000;
OFN_NONETWORKBUTTON :: 0x00020000;
OFN_NOREADONLYRETURN :: 0x00008000;
OFN_NOTESTFILECREATE :: 0x00010000;
OFN_NOVALIDATE :: 0x00000100;
OFN_OVERWRITEPROMPT :: 0x00000002;
OFN_PATHMUSTEXIST :: 0x00000800;
OFN_READONLY :: 0x00000001;
OFN_SHAREAWARE :: 0x00004000;
OFN_SHOWHELP :: 0x00000010;
CDERR_DIALOGFAILURE :: 0x0000FFFF;
CDERR_GENERALCODES :: 0x00000000;
CDERR_STRUCTSIZE :: 0x00000001;
CDERR_INITIALIZATION :: 0x00000002;
CDERR_NOTEMPLATE :: 0x00000003;
CDERR_NOHINSTANCE :: 0x00000004;
CDERR_LOADSTRFAILURE :: 0x00000005;
CDERR_FINDRESFAILURE :: 0x00000006;
CDERR_LOADRESFAILURE :: 0x00000007;
CDERR_LOCKRESFAILURE :: 0x00000008;
CDERR_MEMALLOCFAILURE :: 0x00000009;
CDERR_MEMLOCKFAILURE :: 0x0000000A;
CDERR_NOHOOK :: 0x0000000B;
CDERR_REGISTERMSGFAIL :: 0x0000000C;
+14
View File
@@ -0,0 +1,14 @@
package win32
import "core:strings";
foreign {
@(link_name="_wgetcwd") _get_cwd_wide :: proc(buffer: Wstring, buf_len: int) -> ^Wstring ---
}
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 := utf16_to_utf8(buffer[:], allocator);
return strings.trim_right_null(file);
}
+23
View File
@@ -0,0 +1,23 @@
// +build windows
package win32
foreign import "system:gdi32.lib"
@(default_calling_convention = "std")
foreign gdi32 {
@(link_name="GetStockObject") get_stock_object :: proc(fn_object: i32) -> Hgdiobj ---;
@(link_name="StretchDIBits")
stretch_dibits :: proc(hdc: Hdc,
x_dst, y_dst, width_dst, height_dst: i32,
x_src, y_src, width_src, header_src: i32,
bits: rawptr, bits_info: ^Bitmap_Info,
usage: u32,
rop: u32) -> i32 ---;
@(link_name="SetPixelFormat") set_pixel_format :: proc(hdc: Hdc, pixel_format: i32, pfd: ^Pixel_Format_Descriptor) -> Bool ---;
@(link_name="ChoosePixelFormat") choose_pixel_format :: proc(hdc: Hdc, pfd: ^Pixel_Format_Descriptor) -> i32 ---;
@(link_name="SwapBuffers") swap_buffers :: proc(hdc: Hdc) -> Bool ---;
}
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
// +build windows
package win32
import "core:strings";
call_external_process :: proc(program, command_line: string) -> bool {
si := Startup_Info{ cb=size_of(Startup_Info) };
pi := Process_Information{};
return cast(bool)create_process_w(
utf8_to_wstring(program),
utf8_to_wstring(command_line),
nil,
nil,
Bool(false),
u32(0x10),
nil,
nil,
&si,
&pi
);
}
open_website :: proc(url: string) -> bool {
p :: "C:\\Windows\\System32\\cmd.exe";
arg := []string{"/C", "start", url};
args := strings.join(arg, " ", context.temp_allocator);
return call_external_process(p, args);
}
+221
View File
@@ -0,0 +1,221 @@
// +build windows
package win32
foreign import "system:kernel32.lib"
@(default_calling_convention = "std")
foreign kernel32 {
@(link_name="CreateProcessA") create_process_a :: proc(application_name, command_line: cstring,
process_attributes, thread_attributes: ^Security_Attributes,
inherit_handle: Bool, creation_flags: u32, environment: rawptr,
current_direcotry: cstring, startup_info: ^Startup_Info,
process_information: ^Process_Information) -> Bool ---;
@(link_name="CreateProcessW") create_process_w :: proc(application_name, command_line: Wstring,
process_attributes, thread_attributes: ^Security_Attributes,
inherit_handle: Bool, creation_flags: u32, environment: rawptr,
current_direcotry: cstring, startup_info: ^Startup_Info,
process_information: ^Process_Information) -> Bool ---;
@(link_name="GetExitCodeProcess") get_exit_code_process :: proc(process: Handle, exit: ^u32) -> Bool ---;
@(link_name="ExitProcess") exit_process :: proc(exit_code: u32) ---;
@(link_name="GetModuleHandleA") get_module_handle_a :: proc(module_name: cstring) -> Hmodule ---;
@(link_name="GetModuleHandleW") get_module_handle_w :: proc(module_name: Wstring) -> Hmodule ---;
@(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: 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) ---;
@(link_name="GetCommandLineA") get_command_line_a :: proc() -> cstring ---;
@(link_name="GetCommandLineW") get_command_line_w :: proc() -> Wstring ---;
@(link_name="GetSystemMetrics") get_system_metrics :: proc(index: i32) -> i32 ---;
@(link_name="GetVersionExA") get_version :: proc(osvi: ^OS_Version_Info_Ex_A) ---;
@(link_name="GetCurrentThreadId") get_current_thread_id :: proc() -> u32 ---;
@(link_name="GetSystemTimeAsFileTime") get_system_time_as_file_time :: proc(system_time_as_file_time: ^Filetime) ---;
@(link_name="FileTimeToLocalFileTime") file_time_to_local_file_time :: proc(file_time: ^Filetime, local_file_time: ^Filetime) -> Bool ---;
@(link_name="FileTimeToSystemTime") file_time_to_system_time :: proc(file_time: ^Filetime, system_time: ^Systemtime) -> Bool ---;
@(link_name="SystemTimeToFileTime") system_time_to_file_time :: proc(system_time: ^Systemtime, file_time: ^Filetime) -> Bool ---;
@(link_name="GetStdHandle") get_std_handle :: proc(h: i32) -> Handle ---;
@(link_name="CreateFileA")
create_file_a :: proc(filename: cstring, desired_access, share_module: u32,
security: rawptr,
creation, flags_and_attribs: u32, template_file: Handle) -> Handle ---;
@(link_name="CreateFileW")
create_file_w :: proc(filename: Wstring, desired_access, share_module: u32,
security: rawptr,
creation, flags_and_attribs: u32, template_file: Handle) -> Handle ---;
@(link_name="ReadFile") read_file :: proc(h: Handle, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> Bool ---;
@(link_name="WriteFile") write_file :: proc(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool ---;
@(link_name="GetFileSizeEx") get_file_size_ex :: proc(file_handle: Handle, file_size: ^i64) -> Bool ---;
@(link_name="GetFileInformationByHandle") get_file_information_by_handle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool ---;
@(link_name="CreateDirectoryA") create_directory_a :: proc(path: cstring, security_attributes: ^Security_Attributes) -> Bool ---;
@(link_name="CreateDirectoryW") create_directory_w :: proc(path: Wstring, security_attributes: ^Security_Attributes) -> Bool ---;
@(link_name="GetFileType") get_file_type :: proc(file_handle: Handle) -> u32 ---;
@(link_name="SetFilePointer") set_file_pointer :: proc(file_handle: Handle, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 ---;
@(link_name="SetHandleInformation") set_handle_information :: proc(obj: Handle, mask, flags: u32) -> Bool ---;
@(link_name="FindFirstFileA") find_first_file_a :: proc(file_name: cstring, data: ^Find_Data_A) -> Handle ---;
@(link_name="FindNextFileA") find_next_file_a :: proc(file: Handle, data: ^Find_Data_A) -> Bool ---;
@(link_name="FindFirstFileW") find_first_file_w :: proc(file_name: Wstring, data: ^Find_Data_W) -> Handle ---;
@(link_name="FindNextFileW") find_next_file_w :: proc(file: Handle, data: ^Find_Data_W) -> Bool ---;
@(link_name="FindClose") find_close :: proc(file: Handle) -> Bool ---;
@(link_name="MoveFileExA") move_file_ex_a :: proc(existing, new: cstring, flags: u32) -> Bool ---;
@(link_name="DeleteFileA") delete_file_a :: proc(file_name: cstring) -> Bool ---;
@(link_name="CopyFileA") copy_file_a :: proc(existing, new: cstring, fail_if_exists: Bool) -> Bool ---;
@(link_name="MoveFileExW") move_file_ex_w :: proc(existing, new: Wstring, flags: u32) -> Bool ---;
@(link_name="DeleteFileW") delete_file_w :: proc(file_name: Wstring) -> Bool ---;
@(link_name="CopyFileW") copy_file_w :: proc(existing, new: Wstring, fail_if_exists: Bool) -> Bool ---;
@(link_name="HeapAlloc") heap_alloc :: proc(h: Handle, flags: u32, bytes: int) -> rawptr ---;
@(link_name="HeapReAlloc") heap_realloc :: proc(h: Handle, flags: u32, memory: rawptr, bytes: int) -> rawptr ---;
@(link_name="HeapFree") heap_free :: proc(h: Handle, flags: u32, memory: rawptr) -> Bool ---;
@(link_name="GetProcessHeap") get_process_heap :: proc() -> Handle ---;
@(link_name="LocalAlloc") local_alloc :: proc(flags: u32, bytes: int) -> rawptr ---;
@(link_name="LocalReAlloc") local_realloc :: proc(mem: rawptr, bytes: int, flags: uint) -> rawptr ---;
@(link_name="LocalFree") local_free :: proc(mem: rawptr) -> rawptr ---;
@(link_name="FindFirstChangeNotificationA") find_first_change_notification_a :: proc(path: cstring, watch_subtree: Bool, filter: u32) -> Handle ---;
@(link_name="FindNextChangeNotification") find_next_change_notification :: proc(h: Handle) -> Bool ---;
@(link_name="FindCloseChangeNotification") find_close_change_notification :: proc(h: Handle) -> Bool ---;
@(link_name="ReadDirectoryChangesW") read_directory_changes_w :: proc(dir: Handle, buf: rawptr, buf_length: u32,
watch_subtree: Bool, notify_filter: u32,
bytes_returned: ^u32, overlapped: ^Overlapped,
completion: rawptr) -> Bool ---;
@(link_name="WideCharToMultiByte") wide_char_to_multi_byte :: proc(code_page: u32, flags: u32,
wchar_str: Wstring, wchar: i32,
multi_str: cstring, multi: i32,
default_char: cstring, used_default_char: ^Bool) -> i32 ---;
@(link_name="MultiByteToWideChar") multi_byte_to_wide_char :: proc(code_page: u32, flags: u32,
mb_str: cstring, mb: i32,
wc_str: Wstring, wc: i32) -> i32 ---;
@(link_name="CreateSemaphoreA") create_semaphore_a :: proc(attributes: ^Security_Attributes, initial_count, maximum_count: i32, name: cstring) -> Handle ---;
@(link_name="CreateSemaphoreW") create_semaphore_w :: proc(attributes: ^Security_Attributes, initial_count, maximum_count: i32, name: cstring) -> Handle ---;
@(link_name="ReleaseSemaphore") release_semaphore :: proc(semaphore: Handle, release_count: i32, previous_count: ^i32) -> Bool ---;
@(link_name="WaitForSingleObject") wait_for_single_object :: proc(handle: Handle, milliseconds: u32) -> u32 ---;
}
// @(default_calling_convention = "c")
foreign kernel32 {
@(link_name="GetLastError") get_last_error :: proc() -> i32 ---;
@(link_name="CloseHandle") close_handle :: proc(h: Handle) -> i32 ---;
@(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: cstring) -> u32 ---;
@(link_name="GetFileAttributesW") get_file_attributes_w :: proc(filename: Wstring) -> u32 ---;
@(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: cstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---;
@(link_name="GetFileAttributesExW") get_file_attributes_ex_w :: proc(filename: Wstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---;
@(link_name="CompareFileTime") compare_file_time :: proc(a, b: ^Filetime) -> i32 ---;
}
@(default_calling_convention = "c")
foreign kernel32 {
@(link_name="InterlockedCompareExchange") interlocked_compare_exchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 ---;
@(link_name="InterlockedExchange") interlocked_exchange :: proc(dst: ^i32, desired: i32) -> i32 ---;
@(link_name="InterlockedExchangeAdd") interlocked_exchange_add :: proc(dst: ^i32, desired: i32) -> i32 ---;
@(link_name="InterlockedAnd") interlocked_and :: proc(dst: ^i32, desired: i32) -> i32 ---;
@(link_name="InterlockedOr") interlocked_or :: proc(dst: ^i32, desired: i32) -> i32 ---;
@(link_name="InterlockedCompareExchange64") interlocked_compare_exchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 ---;
@(link_name="InterlockedExchange64") interlocked_exchange64 :: proc(dst: ^i64, desired: i64) -> i64 ---;
@(link_name="InterlockedExchangeAdd64") interlocked_exchange_add64 :: proc(dst: ^i64, desired: i64) -> i64 ---;
@(link_name="InterlockedAnd64") interlocked_and64 :: proc(dst: ^i64, desired: i64) -> i64 ---;
@(link_name="InterlockedOr64") interlocked_or64 :: proc(dst: ^i64, desired: i64) -> i64 ---;
}
@(default_calling_convention = "std")
foreign kernel32 {
@(link_name="_mm_pause") mm_pause :: proc() ---;
@(link_name="ReadWriteBarrier") read_write_barrier :: proc() ---;
@(link_name="WriteBarrier") write_barrier :: proc() ---;
@(link_name="ReadBarrier") read_barrier :: proc() ---;
@(link_name="CreateThread")
create_thread :: proc(thread_attributes: ^Security_Attributes, stack_size: int, start_routine: rawptr,
parameter: rawptr, creation_flags: u32, thread_id: ^u32) -> Handle ---;
@(link_name="ResumeThread") resume_thread :: proc(thread: Handle) -> u32 ---;
@(link_name="GetThreadPriority") get_thread_priority :: proc(thread: Handle) -> i32 ---;
@(link_name="SetThreadPriority") set_thread_priority :: proc(thread: Handle, priority: i32) -> Bool ---;
@(link_name="GetExitCodeThread") get_exit_code_thread :: proc(thread: Handle, exit_code: ^u32) -> Bool ---;
@(link_name="TerminateThread") terminate_thread :: proc(thread: Handle, exit_code: u32) -> Bool ---;
@(link_name="InitializeCriticalSection") initialize_critical_section :: proc(critical_section: ^Critical_Section) ---;
@(link_name="InitializeCriticalSectionAndSpinCount") initialize_critical_section_and_spin_count :: proc(critical_section: ^Critical_Section, spin_count: u32) ---;
@(link_name="DeleteCriticalSection") delete_critical_section :: proc(critical_section: ^Critical_Section) ---;
@(link_name="SetCriticalSectionSpinCount") set_critical_section_spin_count :: proc(critical_section: ^Critical_Section, spin_count: u32) -> u32 ---;
@(link_name="TryEnterCriticalSection") try_enter_critical_section :: proc(critical_section: ^Critical_Section) -> Bool ---;
@(link_name="EnterCriticalSection") enter_critical_section :: proc(critical_section: ^Critical_Section) ---;
@(link_name="LeaveCriticalSection") leave_critical_section :: proc(critical_section: ^Critical_Section) ---;
@(link_name="CreateEventA") create_event_a :: proc(event_attributes: ^Security_Attributes, manual_reset, initial_state: Bool, name: cstring) -> Handle ---;
@(link_name="CreateEventW") create_event_w :: proc(event_attributes: ^Security_Attributes, manual_reset, initial_state: Bool, name: Wstring) -> Handle ---;
@(link_name="PulseEvent") pulse_event :: proc(event: Handle) -> Bool ---;
@(link_name="SetEvent") set_event :: proc(event: Handle) -> Bool ---;
@(link_name="ResetEvent") reset_event :: proc(event: Handle) -> Bool ---;
@(link_name="LoadLibraryA") load_library_a :: proc(c_str: cstring) -> Hmodule ---;
@(link_name="LoadLibraryW") load_library_w :: proc(c_str: Wstring) -> Hmodule ---;
@(link_name="FreeLibrary") free_library :: proc(h: Hmodule) -> Bool ---;
@(link_name="GetProcAddress") get_proc_address :: proc(h: Hmodule, c_str: cstring) -> rawptr ---;
}
Memory_Basic_Information :: struct {
base_address: rawptr,
allocation_base: rawptr,
allocation_protect: u32,
region_size: uint,
state: u32,
protect: u32,
type: u32,
}
@(default_calling_convention = "std")
foreign kernel32 {
@(link_name="VirtualAlloc") virtual_alloc :: proc(address: rawptr, size: uint, allocation_type: u32, protect: u32) -> rawptr ---
@(link_name="VirtualAllocEx") virtual_alloc_ex :: proc(process: Handle, address: rawptr, size: uint, allocation_type: u32, protect: u32) -> rawptr ---
@(link_name="VirtualFree") virtual_free :: proc(address: rawptr, size: uint, free_type: u32) -> Bool ---
@(link_name="VirtualLock") virtual_lock :: proc(address: rawptr, size: uint) -> Bool ---
@(link_name="VirtualProtect") virtual_protect :: proc(address: rawptr, size: uint, new_protect: u32, old_protect: ^u32) -> Bool ---
@(link_name="VirtualQuery") virtual_query :: proc(address: rawptr, buffer: ^Memory_Basic_Information, length: uint) -> uint ---
}
MEM_COMMIT :: 0x00001000;
MEM_RESERVE :: 0x00002000;
MEM_DECOMMIT :: 0x00004000;
MEM_RELEASE :: 0x00008000;
MEM_RESET :: 0x00080000;
MEM_RESET_UNDO :: 0x01000000;
MEM_LARGE_PAGES :: 0x20000000;
MEM_PHYSICAL :: 0x00400000;
MEM_TOP_DOWN :: 0x00100000;
MEM_WRITE_WATCH :: 0x00200000;
PAGE_NOACCESS :: 0x01;
PAGE_READONLY :: 0x02;
PAGE_READWRITE :: 0x04;
PAGE_WRITECOPY :: 0x08;
PAGE_EXECUTE :: 0x10;
PAGE_EXECUTE_READ :: 0x20;
PAGE_EXECUTE_READWRITE :: 0x40;
PAGE_EXECUTE_WRITECOPY :: 0x80;
+18
View File
@@ -0,0 +1,18 @@
// +build windows
package win32
foreign import "system:ole32.lib"
//objbase.h
Com_Init :: enum {
Multi_Threaded = 0x0,
Apartment_Threaded = 0x2,
Disable_OLE1_DDE = 0x4,
Speed_Over_Memory = 0x8,
};
@(default_calling_convention = "std")
foreign ole32 {
@(link_name ="CoInitializeEx") com_init_ex :: proc(reserved: rawptr, co_init: Com_Init) ->Hresult ---;
@(link_name = "CoUninitialize") com_shutdown :: proc() ---;
}
+9
View File
@@ -0,0 +1,9 @@
// +build windows
package win32
foreign import "system:shell32.lib"
@(default_calling_convention = "std")
foreign shell32 {
@(link_name="CommandLineToArgvW") command_line_to_argv_w :: proc(cmd_list: Wstring, num_args: ^i32) -> ^Wstring ---;
}

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