Compare commits

..

241 Commits

Author SHA1 Message Date
Ginger Bill 19bde275a3 Add files in core 2017-05-01 15:30:16 +01:00
Ginger Bill 634ee450f4 v0.2.1 2017-05-01 15:28:26 +01:00
Ginger Bill 750d7256fc Unary expression for vector (fix) 2017-05-01 15:27:21 +01:00
Ginger Bill fae5df2ed8 Fix IR vector arith conv bug 2017-05-01 15:05:56 +01:00
Ginger Bill 01d9161772 Fix value conversion with enum value on for in. 2017-05-01 10:10:07 +01:00
Ginger Bill aceabb2f2f for in iteration of Enum Type (request from issue #58) 2017-05-01 10:02:25 +01:00
Ginger Bill 04f5fff7fa Improve vector math; Make bprint* return string 2017-05-01 00:38:26 +01:00
Ginger Bill dc5587eae2 Fix statement parsing of unary: & and ^ 2017-04-30 17:20:37 +01:00
Ginger Bill 7057034b75 v0.2.0 2017-04-30 16:28:13 +01:00
Ginger Bill 1430ca30a3 Fix subtype polymorphism implicit conversion 2017-04-30 16:22:24 +01:00
Ginger Bill e63393e394 Add type assertion for any 2017-04-30 15:29:46 +01:00
Ginger Bill 784f3ecf7e Syntax change: cast(T)x => T(x); union_cast(T)x => x.(T); transmute(T)x => transmute(T, x); y:=^x => y:=&x;
Sorry for all the code breaking in this commit :(
2017-04-30 15:09:36 +01:00
Ginger Bill 54ea70df98 Fix issues #50 and #55 2017-04-29 20:06:29 +01:00
Ginger Bill c7575164cc Revert to previous demo 2017-04-28 11:03:19 +01:00
Ginger Bill 99125dc743 Fix issue #51; begin work on atomic types 2017-04-28 11:01:46 +01:00
Ginger Bill b78e970698 Fix issue #48 dependency issue 2017-04-26 23:51:13 +01:00
Ginger Bill 5b8be25938 fmt.String_Buffer, Fix issue #44, Tweak overloading rules 2017-04-26 19:43:17 +01:00
Ginger Bill 29efdc5fc1 Fix initialization of global any types 2017-04-25 15:02:35 +01:00
Ginger Bill a80872b60d Fix checking if a procedure terminates for for loops. 2017-04-25 09:46:30 +01:00
Ginger Bill 822bb51b55 Swap memory layout of any 2017-04-23 18:03:29 +01:00
Ginger Bill c2fa79012e Fix find_using_index_expr 2017-04-23 11:04:22 +01:00
Ginger Bill 3fd37c6dc5 Internal change: IntervalExpr is now a BinaryExpr 2017-04-22 10:10:49 +01:00
Ginger Bill 0ea815db49 Fix constant bounds checking for slicing 2017-04-22 09:40:32 +01:00
Ginger Bill 91ed51ff5c Continue work on custom SSA; Fix double declaration in when statements 2017-04-21 17:56:29 +01:00
Ginger Bill 4d0afc55c3 Making slicing a little more robust 2017-04-21 10:03:27 +01:00
Ginger Bill 9a1566d665 Interval expressions for match statements 2017-04-21 00:13:20 +01:00
Ginger Bill a713e33007 Change interval syntax: .. open range, ..< half-closed range 2017-04-20 23:22:45 +01:00
Ginger Bill c5411a25a9 Change Union representation for LLVM IR; fix dynamic array size 2017-04-19 18:58:23 +01:00
Ginger Bill 95692fda52 Fix bug with union literal checking crashing the compiler 2017-04-18 21:20:41 +01:00
Ginger Bill 813a028ed0 Fix procedure calls from non-regular addressing modes 2017-04-17 22:17:16 +01:00
Ginger Bill 0c22081e5f Fix error printing for basic directives 2017-04-17 19:58:43 +01:00
Ginger Bill 6d9fadf351 Make the ABI changes only affect windows
TODO: decide upon rules for *nix systems
2017-04-17 12:01:04 +01:00
Ginger Bill a213061f33 Change tag checking order 2017-04-16 23:08:48 +01:00
Ginger Bill d1a0a46141 Fix issue #37 for procedure literal scopes 2017-04-16 22:48:29 +01:00
Ginger Bill 187b186112 Add #require_results for procedures 2017-04-16 22:30:48 +01:00
Ginger Bill 5041a35b95 Fix ir printing of constant slices 2017-04-16 22:07:26 +01:00
Ginger Bill 92d4fcedee Update ir type aggregate rules for transmute 2017-04-16 16:44:45 +01:00
Ginger Bill c69df7cd3a Exit program if there were syntax errors 2017-04-16 16:38:05 +01:00
Ginger Bill 67d8f48553 Calling convention, change from bitcast to transmute 2017-04-16 16:28:39 +01:00
Ginger Bill b4a339f2e3 Call convention, pass by pointer: pointers are 16 byte aligned 2017-04-16 10:54:05 +01:00
Ginger Bill 0d7bf58b60 Revert to the old demo 2017-04-16 10:40:24 +01:00
Ginger Bill abb9930725 IR emit C ABI compatible types for calling conventions (Only for x86/amd64 like processors at the moment) 2017-04-16 10:38:42 +01:00
Ginger Bill 169310a9f6 Fix non-ascii function parameters in LLVM IR 2017-04-15 23:14:14 +01:00
Ginger Bill 23a0a6de4b Add parse_int; Fix union bugs with size, alignment, and recursive definition checking 2017-04-14 21:47:59 +01:00
Ginger Bill 0d2dbee84e Fix addressing mode rules for match in statements 2017-04-13 22:42:36 +01:00
Ginger Bill d8d22e34dd Fix fmt for type; remove dead stuff 2017-04-13 19:29:17 +01:00
Ginger Bill 627ee002e8 Fix: map key not getting transferred on rehash 2017-04-11 23:11:05 +01:00
Ginger Bill 8e73d1ce1f Fix map bug which removed N values from the beginning 2017-04-11 22:43:33 +01:00
Ginger Bill b53d16d1d5 Remove debug text 2017-04-11 21:24:10 +01:00
Ginger Bill f5819eafa9 Fix map assignment bug due to growth 2017-04-11 21:13:21 +01:00
Ginger Bill 5916e71d4f Fix slicing bug on dynamic arrays 2017-04-11 16:00:49 +01:00
Ginger Bill 913b9b6447 Remove odin.exe 2017-04-10 22:30:38 +01:00
Ginger Bill 8e55bb2a6c Fix append crash when pointer is passed 2017-04-10 21:09:04 +01:00
root 98d493504b Fix segfault with heap allocation 2017-04-10 20:48:56 +01:00
Ginger Bill 3a3202fbc6 Change code to match original MSVC 2017-04-10 13:27:09 +01:00
Ginger Bill aaf355e750 Basic Linux Build! 2017-04-09 22:33:32 +01:00
gingerBill 0683d2b4f4 Merge pull request #33 from zangent/master
Base of *nix port
2017-04-09 22:01:22 +01:00
Ginger Bill d7fdd3d7b8 Add raw.odin
Forgot to do this in the previous commit, whoops :P
2017-04-09 11:45:41 +01:00
Ginger Bill 83ebb24015 Move to Raw_* types to raw.odin; Add size and align members to Type_Info 2017-04-07 14:05:28 +01:00
Ginger Bill 70f9cacdce Fix cast to any of untyped constants 2017-04-07 09:55:19 +01:00
Zachary Pierson 6b33b254e9 Merged from upstream, fixed 'args' name colission 2017-04-06 18:14:42 -05:00
Zachary Pierson c0019cc305 Merge https://github.com/gingerBill/Odin 2017-04-06 17:50:23 -05:00
Ginger Bill c067a1f0ec Fix ir bugs: global variable names, untyped to any assignment 2017-04-06 11:12:11 +01:00
Zachary Pierson 63345cd0d8 Bridged a bugfix from os_windows to other os's. 2017-04-04 18:51:36 -05:00
Zachary Pierson e41d6261c2 Merge https://github.com/gingerBill/Odin 2017-04-04 18:46:05 -05:00
Ginger Bill 3e80411d37 Fix issue #31; Removed down_cast 2017-04-04 21:54:55 +01:00
Zachary Pierson f952c7c747 Merge https://github.com/gingerBill/Odin 2017-04-03 00:08:00 -05:00
Zachary Pierson 642256f9ba I accidentally left debug stuff (like abs paths) in! Whoops! 2017-04-02 18:46:31 -05:00
Zachary Pierson c9c82da1f3 It's terrible, but I added _some_ form of launch args support for Linux/macOS 2017-04-02 18:42:58 -05:00
Ginger Bill 382a5ca6a2 Update and regression test old demos 2017-04-02 22:03:52 +01:00
Ginger Bill 96e8bb5b6f Add website to README.md 2017-04-02 20:20:14 +01:00
Ginger Bill 22afac2b90 Update README.md with latest demo 2017-04-02 20:10:56 +01:00
Ginger Bill 01da0d1377 Fix make for dynamic arrays 2017-04-02 18:28:45 +01:00
Ginger Bill 8ce58573df len, cap, make; remove .count, .capacity, new_slice 2017-04-02 18:16:45 +01:00
Zachary Pierson ce0d874efd Merge https://github.com/gingerBill/Odin 2017-04-02 03:29:51 -05:00
Ginger Bill 2c8b99337b Fix conj 2017-04-01 22:55:33 +01:00
Ginger Bill 5008e2c88b Add Quaternions: quaternion128, quaternion256 2017-04-01 22:41:23 +01:00
Ginger Bill 90fc9abeae Fix constant conversion for complex numbers from integers 2017-04-01 12:12:08 +01:00
Ginger Bill dc303cde21 Complex numbers: complex64 complex128 2017-04-01 12:07:41 +01:00
Zachary Pierson 24b33374b7 Reverted the main proc changed, after a chat with Bill about better solutions. 2017-03-31 05:31:45 -05:00
Zachary Pierson 3315dc7f25 Literally just a commit to revert a previous one. 2017-03-31 05:30:09 -05:00
Zachary Pierson 77b3295de5 Added checking for params and return values in main 2017-03-30 01:21:05 -05:00
Zachary Pierson 1349aa6f2c Merge https://github.com/gingerBill/Odin, cleaned up a bit, fixed the object file version message on macOS 2017-03-30 00:26:46 -05:00
Ginger Bill a75ccb6fbc v0.1.3 2017-03-27 20:32:36 +01:00
Zachary Pierson 7a28827602 Forgot to include stdio.h since Win32 won't resolve it otherwise. 2017-03-21 19:30:54 -05:00
Zachary Pierson c61015b1fe Updated shell.bat for Visual Studio 2017 2017-03-21 19:17:41 -05:00
Zac Pierson e935f8e2ff Fixed os_linux and os_x read_entire_file function not null-terminating data. 2017-03-21 16:00:11 -05:00
Zac Pierson 690c682847 Remember kids, always test your code. There was a variable name colission in dlsym D: 2017-03-21 14:57:09 -05:00
Zac Pierson f541dd40db Fixed some memory leaks and made os_* use strings.odin 2017-03-21 14:54:29 -05:00
Zac Pierson c7bb861d3c Merge https://github.com/gingerBill/Odin
"Fixed" a proc overload bug. Still needs a *real* fix.
2017-03-21 14:16:42 -05:00
Ginger Bill 188b290dd5 Update version number 2017-03-19 21:03:56 +00:00
Ginger Bill c6ff961088 Add base 12 in strconv.odin 2017-03-19 21:03:29 +00:00
Ginger Bill c26990c22d Multiple type cases for match in 2017-03-19 20:55:39 +00:00
Ginger Bill c34d839f9f Add named branches for match statements 2017-03-19 17:36:08 +00:00
Ginger Bill 5562364a98 Add branch labels for loops; using list 2017-03-19 16:59:11 +00:00
Ginger Bill 32150e401e Update gb.h 2017-03-17 12:30:59 +00:00
Ginger Bill aaec8bf423 windows.odin TYPE_NAME to Type_Name; More SSA work and SSA printing for debugging 2017-03-12 16:42:51 +00:00
Ginger Bill 0fcbda951a Finally fix signed integer conversion and printing 2017-03-10 10:34:25 +00:00
Ginger Bill e2734a2dc6 Begin work on the custom backend 2017-03-05 21:22:33 +00:00
Ginger Bill 5adfbec847 Refactoring of code: remove make prefix on many procedures 2017-03-05 15:03:01 +00:00
Ginger Bill 4ef4605d6d Move files to misc 2017-03-03 11:20:22 +00:00
Ginger Bill 2aa402f462 Cleanup root directory 2017-03-03 11:19:12 +00:00
Ginger Bill 00f6bee454 Update README.md 2017-03-03 11:15:34 +00:00
Ginger Bill 6e1864d21c Remove all binaries 2017-03-03 11:13:05 +00:00
Ginger Bill fb2d611dcd Update llvm binaries to latest version; Update utf8proc; 2017-03-03 11:09:37 +00:00
Zac Pierson d890731716 Merge https://github.com/gingerBill/Odin 2017-03-02 15:41:19 -06:00
Ginger Bill 9e8c9be1ea Allow pointers to append; Fix strconv stuff; new_slice allows for capacity 2017-03-02 19:24:34 +00:00
Zachary Pierson 231ea8b026 Merge https://github.com/gingerBill/Odin 2017-02-27 23:25:47 -06:00
Ginger Bill 9bc37f4400 fmt.odin uses ^[]byte rather than custom Buffer type 2017-02-26 15:34:02 +00:00
Ginger Bill f29e303ce7 Slices now have a capacity. 2017-02-26 15:14:08 +00:00
Ginger Bill 3c9143957c Ellipsis is now just ..; Remove half-closed range operator and treat all of them as half-closed; slice expression uses ..; 2017-02-26 14:19:03 +00:00
Ginger Bill 18b3c0b2fc Fix fmt integer width printing 2017-02-26 09:42:24 +00:00
Ginger Bill c59f6b7d0b ++ -- statements; add strconv.odin (and replace some of the fmt procs); Fix ~ on 64 bit constants; Fix integer casts from smaller to larger size 2017-02-26 00:44:26 +00:00
Zachary Pierson 5bbdb3a3a3 Merge https://github.com/gingerBill/Odin 2017-02-25 02:07:58 -06:00
Ginger Bill 67ed8a9a4a Fix Tuple type info bug
Caused by not having type safe tagged unions :P (Silly C)
2017-02-24 22:56:34 +00:00
Zachary Pierson 27aa07307b Merge https://github.com/gingerBill/Odin 2017-02-24 15:53:56 -06:00
Ginger Bill 4cc4d604bc Add core/strings.odin 2017-02-24 21:11:05 +00:00
Ginger Bill eec709c545 Fix fmt.odin printing enums 2017-02-24 20:55:35 +00:00
Ginger Bill 9b2f5c359a v0.1.1 2017-02-24 19:48:18 +00:00
Ginger Bill a982c51c30 Fix minor bugs in IR for slices 2017-02-23 22:22:56 +00:00
Zac Pierson 20b9f1ff59 Added getenv to the *nix stdlib. 2017-02-23 15:29:41 -06:00
Zac Pierson 561c583b3f Merge https://github.com/gingerBill/Odin 2017-02-22 10:57:30 -06:00
Ginger Bill 047c0e4bcc A decent union type with common fields and variants 2017-02-21 21:21:54 +00:00
Zac Pierson 8d5896ab7e Merge https://github.com/gingerBill/Odin 2017-02-20 10:14:52 -06:00
Ginger Bill a94dfdf21d Begin changing union syntax 2017-02-19 19:55:19 +00:00
Ginger Bill c0d5237b75 Unexported struct fields on selectors 2017-02-19 12:47:02 +00:00
Ginger Bill 6fdcbefe5d Unexported struct fields 2017-02-19 12:38:49 +00:00
Ginger Bill 3cec2550d9 delete for maps 2017-02-19 11:50:42 +00:00
Ginger Bill 758dd9ba16 Fix overloading bug due to #import .; Add sys/wgl.odin 2017-02-19 11:35:33 +00:00
Ginger Bill 0c37aa9ea0 Fix overloading bug due to comparison of named types 2017-02-18 22:19:35 +00:00
Ginger Bill 9ff474f387 Named return values but do not affect other declarations 2017-02-18 12:02:11 +00:00
Ginger Bill d2f9d20833 Change ternary expression precedence 2017-02-18 10:41:48 +00:00
Zac Pierson 802b1a70f8 Fixed an error in function naming in os_linux 2017-02-15 11:20:11 -06:00
Zac Pierson aaa4dd5c36 Merge https://github.com/gingerBill/odin 2017-02-15 10:21:38 -06:00
Ginger Bill 71100ed427 Ternary expression (removed if and block expression) 2017-02-14 19:26:32 +00:00
Ginger Bill 3ecf3505fd Ignore previous silly commit :P I shouldn't have move it 2017-02-14 17:34:02 +00:00
Ginger Bill daa1cd55a1 Move error handling for casting 2017-02-14 17:33:11 +00:00
Ginger Bill 2722de65b7 Prevent cast on pointer to union types 2017-02-14 17:24:56 +00:00
Ginger Bill 8b5e3428a1 Optional ok for union_cast (similar to map indices) 2017-02-14 16:37:24 +00:00
Ginger Bill d1f65097c4 Fix immutable rules; add some general documentation
immutable is still a little weird and not completely what you'd expect. Maybe just not having it is better.
2017-02-14 15:19:29 +00:00
Ginger Bill 74d15ab84b Reimplement immutable with different rules. 2017-02-14 12:35:50 +00:00
Ginger Bill 763cd2649d Fix index assignment rules for indirection 2017-02-14 12:21:02 +00:00
Zachary Pierson 9d19ee7e4c Changed standard libraries for MacOS and Linux to be closer to os_windows. 2017-02-12 18:25:58 -06:00
Zachary Pierson 8df3175f10 Updated Linux standard library to convert c strs 2017-02-12 17:22:27 -06:00
Zachary Pierson ebb10e5597 One of the warning flags was misspelled. Oops! 2017-02-12 16:09:21 -06:00
Zachary Pierson 047f883078 Updated warning removal list, and made system_exec_command_line_app in main.c return the exit code. 2017-02-12 16:08:09 -06:00
Zachary Pierson 320c22e08a Merge https://github.com/gingerBill/Odin 2017-02-12 16:04:13 -06:00
Ginger Bill bd27c24fab Use a global to store the build context information 2017-02-12 21:27:13 +00:00
Ginger Bill 282f8bb06f Fix issue #23 2017-02-12 11:41:06 +00:00
Ginger Bill b9ed546ce0 Record type field names 2017-02-12 11:31:04 +00:00
Zachary Pierson a9398bf30f Tested MacOS. If a commit doesn't follow in 15 minutes, Linux works too! 2017-02-12 00:21:25 -06:00
Zachary Pierson 7829421085 Fixed Windows (updated gb.h) | Need to test on MacOS and Linux now! 2017-02-11 23:52:56 -06:00
Zachary Pierson c50aabd916 Merging from gingerBill's master 2017-02-11 23:35:07 -06:00
Zachary Pierson 3f3122bccc Temporary fix for an Odin bug. 2017-02-11 18:54:54 -06:00
Zachary Pierson fc1a006de1 Added support for reading files on MacOS and Linux 2017-02-11 17:24:47 -06:00
Ginger Bill e1fdd675ce v0.1.0
Added:
 * Dynamic Arrays `[...]Type`
 * Dynamic Maps   `map[Key]Value`
 * Dynamic array and map literals
 * Custom struct alignemnt `struct #align 8 { bar: i8 }`
 * Allow `_` in numbers
 * Variadic `append`
 * fmt.sprint*
 * Entities prefixes with an underscore do not get exported on imports
 * Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps
 * enum types have an implict `names` field, a []string of all the names in that enum

Removed:
 * Maybe/option types
 * immutable variables
 * Remove `type` keyword and other "reserved" keywords
 * `compile_assert` and `assert`return the value of the condition for semantic reasons

Changed:
 * thread_local -> #thread_local
 * #include -> #load
 * Files only get checked if they are actually used
 * match x in y {} // For type match statements
 * Version numbering now starts from 0.1.0 and uses the convention:
 	- major.minor.patch

Fixes:
 * Many fmt.* fixes

To come very Soon™:
 * Linux and OS X builds (unofficial ones do exist already)
2017-02-11 21:20:57 +00:00
Zachary Pierson 754b368140 Added dynamic library loading to Linux and MacOS's standard libraries. 2017-02-11 15:09:53 -06:00
Zachary Pierson a49e888ce6 Merge https://github.com/gingerBill/Odin 2017-02-11 13:48:16 -06:00
Ginger Bill 4306345ff1 Dynamic array syntax [...]Type; make entities private with a prefix of _; fix extension checking 2017-02-11 17:33:23 +00:00
Ginger Bill 346aa5f71c Only check files that have been truly imported. 2017-02-11 15:50:24 +00:00
Zac Pierson 99c663d9f3 Questioning whether MacOS libraries should be .dylib or .so 2017-02-11 01:10:03 -06:00
Zachary Pierson afac95e092 Oh, I left math.odin open when I merged gingerBill's changes. Oops. Updated to his version. 2017-02-11 00:33:12 -06:00
Zachary Pierson 05486f9fa3 I'm not sure what I changed here, to be honest. I've ctrl-z'd everything, but git's still complaining. 2017-02-11 00:30:04 -06:00
Zachary Pierson cad46ae51c Merge https://github.com/gingerBill/Odin 2017-02-10 23:41:23 -06:00
Zachary Pierson 3424b2badd Added ability to use -framework on MacOS 2017-02-10 23:33:30 -06:00
Ginger Bill 73d6a55f5c Remove need for type keyword 2017-02-10 16:12:14 +00:00
Ginger Bill f18ae89931 Remove Maybe type; Enum names 2017-02-10 14:59:18 +00:00
Zachary Pierson 3445a28c4a Code quality upkeep. Fixed a broken thread finding assembly instruction in gb.h 2017-02-09 01:40:45 -06:00
Zac Pierson 7f6b83d50c Fixed gb.h - the file handle for /proc/cpuinfo is needed to read chars. 2017-02-08 11:59:54 -06:00
Zac Pierson 72d4bfb32a Merge https://github.com/gingerBill/Odin 2017-02-08 11:50:33 -06:00
Zachary Pierson 37f7630a9e Updated README.md to reflect Linux's dependancy on clang for now. 2017-02-07 23:33:36 -06:00
Zachary Pierson 73c5c5d5d3 Linker on MacOS and GNU/Linux now includes foreign_system_libraries. Fixed foreign_system_library not respecting 'when' condition. 2017-02-07 23:21:52 -06:00
Zac Pierson 584869730a Linux can build now! Woo! 2017-02-07 15:07:20 -06:00
Zachary Pierson 90ab448bca Modified the test program to see where the compiler inserted the code. 2017-02-07 12:26:15 -06:00
Ginger Bill 454d0b5cf5 Fix global maps and initialize the preload types before 2017-02-07 18:13:37 +00:00
Zachary Pierson 8becbdc1b2 Added a very basic Linux standard library shamelessly stolen from the MacOS one.
Made Linux (almost) work. The generated binaries segfault, but it's so close I can almost taste it.
2017-02-07 00:28:21 -06:00
Zachary Pierson eeeb90c441 MacOS is able to run Hello World! 2017-02-06 21:47:58 -06:00
Ginger Bill 219ca0ac46 Map type info and fmt printing 2017-02-07 00:10:58 +00:00
Ginger Bill 5796c41357 map immutable fields: count, capacity, allocator 2017-02-06 22:53:48 +00:00
Ginger Bill 8cfae17535 map literals 2017-02-06 22:19:32 +00:00
Zac Pierson 6efd400c98 Updated build script in an attempt to track down a segfault. It's not helping, though. 2017-02-06 15:45:51 -06:00
Ginger Bill df78b8ad3e Make checking map key exists optional 2017-02-06 21:31:27 +00:00
Ginger Bill f11d73ffaa map string keys and for iterator 2017-02-06 20:54:51 +00:00
Ginger Bill c126339090 dynamic map insertion and lookup 2017-02-06 20:23:51 +00:00
Zac Pierson 5cfa4ba580 Added Linux functions throughout the code, but it segfaults. 2017-02-06 12:26:41 -06:00
Ginger Bill 9f2d9b596d Nearly implement dynamics map, missing insertion 2017-02-06 01:21:23 +00:00
Ginger Bill 00c7489157 Begin writing dynamic map procs and fix using bug in IR 2017-02-05 23:52:01 +00:00
Ginger Bill b1562edccf Add types.odin; Begin work on map 2017-02-05 18:17:55 +00:00
Ginger Bill 2a5b674d33 Custom struct alignment 2017-02-05 15:19:30 +00:00
Ginger Bill 7944b7714f Add build guards around compiling part of the code. 2017-02-01 21:00:32 +00:00
Ginger Bill 205f4664f8 Update code from OSX merge to be consistent with the rest of the code
Remove some dead code whilst I was here too :P
2017-02-01 20:59:14 +00:00
gingerBill c6133587d1 Merge pull request #16 from zhiayang/master
Basic, but sketchy, but somewhat usable, non-windows support
2017-02-01 20:31:57 +00:00
zhiayang 5516e80ab7 Merge branch 'master' of https://github.com/zhiayang/Odin 2017-02-02 04:21:42 +08:00
zhiayang 864310e3da oh boy, basic osx/unix support 2017-02-02 04:20:33 +08:00
Ginger Bill 4e7082a68d Change internals of context; Disable immutable 2017-02-01 17:52:55 +00:00
Ginger Bill 502e63b9c5 Remove dead code 2017-01-30 23:10:44 +00:00
Ginger Bill 34150385d8 Change vector memory layout and operations; for in vector. 2017-01-30 22:31:34 +00:00
Ginger Bill 0ca1b4612c Allow _ in floats 2017-01-29 23:13:50 +00:00
Ginger Bill 9e143a38ce sprint*, variadic append works correctly now. 2017-01-29 21:29:10 +00:00
Ginger Bill 43be91bca3 Variadic append 2017-01-29 20:48:08 +00:00
Ginger Bill 984e36a151 Dynamic arrays 2017-01-29 20:15:16 +00:00
Ginger Bill ec9c8fb8a4 Update README.md 2017-01-29 14:45:12 +00:00
Ginger Bill 3e79ec4aef Fix untyped to any assignments. Fixed crash when arguments with no value are passed 2017-01-29 14:27:55 +00:00
gingerBill 3e257ef8d0 Merge pull request #12 from thebirk/windows-odin-correction
Changed #foreign user32 to gdi32 where this was wrong.
2017-01-28 23:25:55 +00:00
thebirk 626f91f307 Changed #foreign user32 to gdi32 where this was wrong. 2017-01-28 23:23:02 +01:00
Ginger Bill e86c990b75 Overloaded free; 3 dotted ellipsis 2017-01-28 20:16:18 +00:00
Ginger Bill 31aacd5bf4 Fix parsing for block/if expression within if/for/etc. statements 2017-01-27 23:02:55 +00:00
Ginger Bill 92453369c5 Remove while loop and readd c-style for loops i.e. all loops are just for 2017-01-27 17:43:42 +00:00
Ginger Bill 832009f33a in keyword for for and match type 2017-01-27 16:34:58 +00:00
Ginger Bill d3d3bfd455 Fix utf8 stuff, Allow _ in numbers, Begin writing next demo code. 2017-01-27 12:43:01 +00:00
Ginger Bill ce3582fd89 Remove case sensitivity for libraries on windows 2017-01-26 20:06:22 +00:00
Ginger Bill e3e16f5d05 Library names - Only link with used foreign libraries 2017-01-26 20:00:16 +00:00
Ginger Bill f47f25f942 Fix pointer differences (issue #11); remove #dll_import 2017-01-26 17:39:44 +00:00
Ginger Bill e85458919c Basic float printing 2017-01-26 15:38:35 +00:00
Ginger Bill b59a052e32 Change casting syntax: cast(T)x transmute(T)x et al. 2017-01-25 19:19:25 +00:00
Ginger Bill 12498b2d39 Fix issue #8 - https://github.com/gingerBill/Odin/issues/8 2017-01-20 11:23:46 +00:00
Ginger Bill 6d93aa429f Fix issue #10 2017-01-20 00:21:40 +00:00
Ginger Bill 3f023509a7 using immutable thread_local on variable declarations 2017-01-19 20:03:10 +00:00
Ginger Bill 563b1e2b28 immutable field prefix 2017-01-19 19:02:44 +00:00
Ginger Bill 4603d2525e Closed range ... (both inclusive); Type comparisons with == and != 2017-01-19 11:29:15 +00:00
Ginger Bill 2af9fb79dc Change cast syntax, int(x), []byte(s), (^int)(p) 2017-01-17 23:36:07 +00:00
Ginger Bill 367d307dc4 Fix conversion of untyped integers to pointers 2017-01-17 20:27:14 +00:00
Ginger Bill cb59c1cf08 Comma for all field separators; Overloaded procedures follow exportation rules 2017-01-17 18:47:38 +00:00
Ginger Bill 383f5b55ad Best viable overloading procedure algorithm; no_alias; call expr style casts 2017-01-17 15:20:11 +00:00
Ginger Bill 6dc6b6f8aa Err on ambiguous overloaded calls 2017-01-15 20:43:28 +00:00
Ginger Bill ac736aa4ec Procedure overloading 2017-01-15 19:55:04 +00:00
Ginger Bill 6fe25badf0 Bug fix: comparisons with shifts 2017-01-15 12:00:13 +00:00
Ginger Bill c29d433e38 Handle enums correctly with printf 2017-01-08 23:19:50 +00:00
Ginger Bill ff473e8342 "Old style" enums
name and value information
`count`, `min_value`, `max_value` constants
2017-01-08 20:24:12 +00:00
Ginger Bill 659e5359b2 fmt.printf - Go style due to runtime type safety 2017-01-08 01:10:55 +00:00
Ginger Bill d9ce0b9da0 File reorganization for checker system. 2017-01-07 12:01:52 +00:00
Ginger Bill 703e1aa2bc Fix core library; Disable adding entity definitions for blank identifiers 2017-01-07 11:44:42 +00:00
Ginger Bill b1e35b6da3 Fix array pointer as iterators; Remove stack allocations in startup_runtime 2017-01-06 15:47:07 +00:00
Ginger Bill fc1af0a04b Fix build error caused by invalid iterator types in for 2017-01-05 23:50:44 +00:00
Ginger Bill 4afb3f8fa4 Fix line comments at the end of file 2017-01-05 22:35:32 +00:00
Ginger Bill 207b252f23 Fix checking termination of a procedure 2017-01-05 22:32:19 +00:00
Ginger Bill 1356dfeec2 Fix SUBSYSTEM for link.exe 2017-01-05 21:58:24 +00:00
Ginger Bill d025791462 v0.0.5a 2017-01-05 21:46:09 +00:00
Ginger Bill b07ee9ec23 Fix problem with odin build 2017-01-05 21:43:36 +00:00
Ginger Bill 915b5cdab7 Rename llir -> ir 2017-01-04 11:24:32 +00:00
Ginger Bill c8f99b360f Fix init_arena_from_context 2017-01-03 20:35:47 +00:00
83 changed files with 33217 additions and 20694 deletions
+9 -3
View File
@@ -251,7 +251,13 @@ paket-files/
# Project Specific
# - Windows
*.sln
!misc/llvm-bim/lli.exe
!misc/llvm-bim/opt.exe
builds
builds/
bin/
*.exe
# - Linux/MacOS
odin
odin.dSYM
+40 -25
View File
@@ -1,8 +1,8 @@
<img src="logo-slim.png" alt="Odin logo" height="74">
<img src="misc/logo-slim.png" alt="Odin logo" height="74">
# The Odin Programming Language
Odin is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
* simplicity
* high performance
* built for modern systems
@@ -10,6 +10,8 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
* metaprogramming
* designed for good programmers
Website: [https://odin.handmade.network/](https://odin.handmade.network/)
## Demonstrations:
* First Talk & Demo
- [Talk](https://youtu.be/TMCkT-uASaE?t=338)
@@ -18,39 +20,52 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
* [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)
* [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)
## Requirements to build and run
* Windows
* x86-64
* MSVC 2015 installed (C99 support)
* Requires MSVC's link.exe as the linker
- run `vcvarsall.bat` to setup the path
- Windows
* x86-64
* MSVC 2015 installed (C99 support)
* [LLVM binaries](https://github.com/gingerBill/Odin/releases/tag/llvm-4.0-windows) for `opt.exe` and `llc.exe`
* Requires MSVC's link.exe as the linker
* run `vcvarsall.bat` to setup the path
- MacOS
* x86-64
* LLVM explicitly installed (`brew install llvm`)
* XCode installed (for the linker)
- GNU/Linux
* x86-64
* Build tools (ld)
* LLVM installed
* Clang installed (temporary - this is calling the linker for now)
## Warnings
* This is still highly in development and the language's design is quite volatile.
* Syntax is definitely not fixed
* Syntax is not fixed.
## Roadmap
Not in any particular order
Not in any particular order and not be implemented
* Custom backend to replace LLVM
- Improve SSA design to accommodate for lowering to a "bytecode"
- SSA optimizations
- COFF generation
- linker
* Type safe "macros"
* Documentation generator for "Entities"
* Multiple architecture support
* Inline assembly
* Linking options
- Executable
- Static/Dynamic Library
* Debug information
* 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:
* Command Line Tooling
* Compiler Internals:
- Big numbers library
- Multithreading for performance increase
-200
View File
@@ -1,200 +0,0 @@
This file is a list of the people responsible for ensuring that patches for a
particular part of LLVM are reviewed, either by themself or by someone else.
They are also the gatekeepers for their part of LLVM, with the final word on
what goes in or not.
The list is sorted by surname and formatted to allow easy grepping and
beautification by scripts. The fields are: name (N), email (E), web-address
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
(S). Each entry should contain at least the (N), (E) and (D) fields.
N: Joe Abbey
E: jabbey@arxan.com
D: LLVM Bitcode (lib/Bitcode/* include/llvm/Bitcode/*)
N: Owen Anderson
E: resistor@mac.com
D: SelectionDAG (lib/CodeGen/SelectionDAG/*)
N: Rafael Avila de Espindola
E: rafael.espindola@gmail.com
D: Gold plugin (tools/gold/*)
N: Justin Bogner
E: mail@justinbogner.com
D: InstrProfiling and related parts of ProfileData
N: Chandler Carruth
E: chandlerc@gmail.com
E: chandlerc@google.com
D: Config, ADT, Support, inlining & related passes, SROA/mem2reg & related passes, CMake, library layering
N: Evan Cheng
E: evan.cheng@apple.com
D: parts of code generator not covered by someone else
N: Eric Christopher
E: echristo@gmail.com
D: Debug Information, autotools/configure/make build, inline assembly
N: Greg Clayton
E: gclayton@apple.com
D: LLDB
N: Marshall Clow
E: mclow.lists@gmail.com
D: libc++
N: Peter Collingbourne
E: peter@pcc.me.uk
D: llgo
N: Quentin Colombet
E: qcolombet@apple.com
D: Register allocators
N: Duncan P. N. Exon Smith
E: dexonsmith@apple.com
D: Branch weights and BlockFrequencyInfo
N: Hal Finkel
E: hfinkel@anl.gov
D: BBVectorize, the loop reroller, alias analysis and the PowerPC target
N: Dan Gohman
E: sunfish@mozilla.com
D: WebAssembly Backend (lib/Target/WebAssembly/*)
N: Renato Golin
E: renato.golin@linaro.org
D: ARM Linux support
N: Venkatraman Govindaraju
E: venkatra@cs.wisc.edu
D: Sparc Backend (lib/Target/Sparc/*)
N: Tobias Grosser
E: tobias@grosser.es
D: Polly
N: James Grosbach
E: grosbach@apple.com
D: MC layer
N: Justin Holewinski
E: jholewinski@nvidia.com
D: NVPTX Target (lib/Target/NVPTX/*)
N: Lang Hames
E: lhames@gmail.com
D: MCJIT, RuntimeDyld and JIT event listeners
N: Galina Kistanova
E: gkistanova@gmail.com
D: LLVM Buildbot
N: Anton Korobeynikov
E: anton@korobeynikov.info
D: Exception handling, Windows codegen, ARM EABI
N: Benjamin Kramer
E: benny.kra@gmail.com
D: DWARF Parser
N: Sergei Larin
E: slarin@codeaurora.org
D: VLIW Instruction Scheduling, Packetization
N: Chris Lattner
E: sabre@nondot.org
W: http://nondot.org/~sabre/
D: Everything not covered by someone else
N: David Majnemer
E: david.majnemer@gmail.com
D: IR Constant Folder, InstCombine
N: Dylan McKay
E: dylanmckay34@gmail.com
D: AVR Backend
N: Tim Northover
E: t.p.northover@gmail.com
D: AArch64 backend, misc ARM backend
N: Diego Novillo
E: dnovillo@google.com
D: SampleProfile and related parts of ProfileData
N: Jakob Olesen
E: stoklund@2pi.dk
D: TableGen
N: Richard Osborne
E: richard@xmos.com
D: XCore Backend
N: Krzysztof Parzyszek
E: kparzysz@codeaurora.org
D: Hexagon Backend
N: Paul Robinson
E: paul_robinson@playstation.sony.com
D: Sony PlayStation®4 support
N: Chad Rosier
E: mcrosier@codeaurora.org
D: Fast-Isel
N: Nadav Rotem
E: nrotem@apple.com
D: X86 Backend, Loop Vectorizer
N: Daniel Sanders
E: daniel.sanders@imgtec.com
D: MIPS Backend (lib/Target/Mips/*)
N: Duncan Sands
E: baldrick@free.fr
D: DragonEgg
N: Kostya Serebryany
E: kcc@google.com
D: AddressSanitizer, ThreadSanitizer (LLVM parts)
N: Michael Spencer
E: bigcheesegs@gmail.com
D: Windows parts of Support, Object, ar, nm, objdump, ranlib, size
N: Alexei Starovoitov
E: alexei.starovoitov@gmail.com
D: BPF backend
N: Tom Stellard
E: thomas.stellard@amd.com
E: mesa-dev@lists.freedesktop.org
D: Release manager for the 3.5 and 3.6 branches, R600 Backend, libclc
N: Evgeniy Stepanov
E: eugenis@google.com
D: MemorySanitizer (LLVM part)
N: Andrew Trick
E: atrick@apple.com
D: IndVar Simplify, Loop Strength Reduction, Instruction Scheduling
N: Ulrich Weigand
E: uweigand@de.ibm.com
D: SystemZ Backend
N: Bill Wendling
E: isanbard@gmail.com
D: libLTO, IR Linker
N: Peter Zotov
E: whitequark@whitequark.org
D: OCaml bindings
N: Andrey Churbanov
E: andrey.churbanov@intel.com
D: OpenMP runtime library
-467
View File
@@ -1,467 +0,0 @@
This file is a partial list of people who have contributed to the LLVM
project. If you have contributed a patch or made some other contribution to
LLVM, please submit a patch to this file to add yourself, and it will be
done!
The list is sorted by surname and formatted to allow easy grepping and
beautification by scripts. The fields are: name (N), email (E), web-address
(W), PGP key ID and fingerprint (P), description (D), snail-mail address
(S), and (I) IRC handle.
N: Vikram Adve
E: vadve@cs.uiuc.edu
W: http://www.cs.uiuc.edu/~vadve/
D: The Sparc64 backend, provider of much wisdom, and motivator for LLVM
N: Owen Anderson
E: resistor@mac.com
D: LCSSA pass and related LoopUnswitch work
D: GVNPRE pass, DataLayout refactoring, random improvements
N: Henrik Bach
D: MingW Win32 API portability layer
N: Aaron Ballman
E: aaron@aaronballman.com
D: __declspec attributes, Windows support, general bug fixing
N: Nate Begeman
E: natebegeman@mac.com
D: PowerPC backend developer
D: Target-independent code generator and analysis improvements
N: Daniel Berlin
E: dberlin@dberlin.org
D: ET-Forest implementation.
D: Sparse bitmap
N: David Blaikie
E: dblaikie@gmail.com
D: General bug fixing/fit & finish, mostly in Clang
N: Neil Booth
E: neil@daikokuya.co.uk
D: APFloat implementation.
N: Misha Brukman
E: brukman+llvm@uiuc.edu
W: http://misha.brukman.net
D: Portions of X86 and Sparc JIT compilers, PowerPC backend
D: Incremental bitcode loader
N: Cameron Buschardt
E: buschard@uiuc.edu
D: The `mem2reg' pass - promotes values stored in memory to registers
N: Brendon Cahoon
E: bcahoon@codeaurora.org
D: Loop unrolling with run-time trip counts.
N: Chandler Carruth
E: chandlerc@gmail.com
E: chandlerc@google.com
D: Hashing algorithms and interfaces
D: Inline cost analysis
D: Machine block placement pass
D: SROA
N: Casey Carter
E: ccarter@uiuc.edu
D: Fixes to the Reassociation pass, various improvement patches
N: Evan Cheng
E: evan.cheng@apple.com
D: ARM and X86 backends
D: Instruction scheduler improvements
D: Register allocator improvements
D: Loop optimizer improvements
D: Target-independent code generator improvements
N: Dan Villiom Podlaski Christiansen
E: danchr@gmail.com
E: danchr@cs.au.dk
W: http://villiom.dk
D: LLVM Makefile improvements
D: Clang diagnostic & driver tweaks
S: Aarhus, Denmark
N: Jeff Cohen
E: jeffc@jolt-lang.org
W: http://jolt-lang.org
D: Native Win32 API portability layer
N: John T. Criswell
E: criswell@uiuc.edu
D: Original Autoconf support, documentation improvements, bug fixes
N: Anshuman Dasgupta
E: adasgupt@codeaurora.org
D: Deterministic finite automaton based infrastructure for VLIW packetization
N: Stefanus Du Toit
E: stefanus.du.toit@intel.com
D: Bug fixes and minor improvements
N: Rafael Avila de Espindola
E: rafael.espindola@gmail.com
D: The ARM backend
N: Dave Estes
E: cestes@codeaurora.org
D: AArch64 machine description for Cortex-A53
N: Alkis Evlogimenos
E: alkis@evlogimenos.com
D: Linear scan register allocator, many codegen improvements, Java frontend
N: Hal Finkel
E: hfinkel@anl.gov
D: Basic-block autovectorization, PowerPC backend improvements
N: Eric Fiselier
E: eric@efcs.ca
D: LIT patches and documentation.
N: Ryan Flynn
E: pizza@parseerror.com
D: Miscellaneous bug fixes
N: Brian Gaeke
E: gaeke@uiuc.edu
W: http://www.students.uiuc.edu/~gaeke/
D: Portions of X86 static and JIT compilers; initial SparcV8 backend
D: Dynamic trace optimizer
D: FreeBSD/X86 compatibility fixes, the llvm-nm tool
N: Nicolas Geoffray
E: nicolas.geoffray@lip6.fr
W: http://www-src.lip6.fr/homepages/Nicolas.Geoffray/
D: PPC backend fixes for Linux
N: Louis Gerbarg
E: lgg@apple.com
D: Portions of the PowerPC backend
N: Saem Ghani
E: saemghani@gmail.com
D: Callgraph class cleanups
N: Mikhail Glushenkov
E: foldr@codedgers.com
D: Author of llvmc2
N: Dan Gohman
E: sunfish@mozilla.com
D: Miscellaneous bug fixes
D: WebAssembly Backend
N: David Goodwin
E: david@goodwinz.net
D: Thumb-2 code generator
N: David Greene
E: greened@obbligato.org
D: Miscellaneous bug fixes
D: Register allocation refactoring
N: Gabor Greif
E: ggreif@gmail.com
D: Improvements for space efficiency
N: James Grosbach
E: grosbach@apple.com
I: grosbach
D: SjLj exception handling support
D: General fixes and improvements for the ARM back-end
D: MCJIT
D: ARM integrated assembler and assembly parser
D: Led effort for the backend formerly known as ARM64
N: Lang Hames
E: lhames@gmail.com
D: PBQP-based register allocator
N: Gordon Henriksen
E: gordonhenriksen@mac.com
D: Pluggable GC support
D: C interface
D: Ocaml bindings
N: Raul Fernandes Herbster
E: raul@dsc.ufcg.edu.br
D: JIT support for ARM
N: Paolo Invernizzi
E: arathorn@fastwebnet.it
D: Visual C++ compatibility fixes
N: Patrick Jenkins
E: patjenk@wam.umd.edu
D: Nightly Tester
N: Dale Johannesen
E: dalej@apple.com
D: ARM constant islands improvements
D: Tail merging improvements
D: Rewrite X87 back end
D: Use APFloat for floating point constants widely throughout compiler
D: Implement X87 long double
N: Brad Jones
E: kungfoomaster@nondot.org
D: Support for packed types
N: Rod Kay
E: rkay@auroraux.org
D: Author of LLVM Ada bindings
N: Eric Kidd
W: http://randomhacks.net/
D: llvm-config script
N: Anton Korobeynikov
E: asl@math.spbu.ru
D: Mingw32 fixes, cross-compiling support, stdcall/fastcall calling conv.
D: x86/linux PIC codegen, aliases, regparm/visibility attributes
D: Switch lowering refactoring
N: Sumant Kowshik
E: kowshik@uiuc.edu
D: Author of the original C backend
N: Benjamin Kramer
E: benny.kra@gmail.com
D: Miscellaneous bug fixes
N: Sundeep Kushwaha
E: sundeepk@codeaurora.org
D: Implemented DFA-based target independent VLIW packetizer
N: Christopher Lamb
E: christopher.lamb@gmail.com
D: aligned load/store support, parts of noalias and restrict support
D: vreg subreg infrastructure, X86 codegen improvements based on subregs
D: address spaces
N: Jim Laskey
E: jlaskey@apple.com
D: Improvements to the PPC backend, instruction scheduling
D: Debug and Dwarf implementation
D: Auto upgrade mangler
D: llvm-gcc4 svn wrangler
N: Chris Lattner
E: sabre@nondot.org
W: http://nondot.org/~sabre/
D: Primary architect of LLVM
N: Tanya Lattner (Tanya Brethour)
E: tonic@nondot.org
W: http://nondot.org/~tonic/
D: The initial llvm-ar tool, converted regression testsuite to dejagnu
D: Modulo scheduling in the SparcV9 backend
D: Release manager (1.7+)
N: Sylvestre Ledru
E: sylvestre@debian.org
W: http://sylvestre.ledru.info/
W: http://llvm.org/apt/
D: Debian and Ubuntu packaging
D: Continuous integration with jenkins
N: Andrew Lenharth
E: alenhar2@cs.uiuc.edu
W: http://www.lenharth.org/~andrewl/
D: Alpha backend
D: Sampling based profiling
N: Nick Lewycky
E: nicholas@mxc.ca
D: PredicateSimplifier pass
N: Tony Linthicum, et. al.
E: tlinth@codeaurora.org
D: Backend for Qualcomm's Hexagon VLIW processor.
N: Bruno Cardoso Lopes
E: bruno.cardoso@gmail.com
I: bruno
W: http://brunocardoso.cc
D: Mips backend
D: Random ARM integrated assembler and assembly parser improvements
D: General X86 AVX1 support
N: Duraid Madina
E: duraid@octopus.com.au
W: http://kinoko.c.u-tokyo.ac.jp/~duraid/
D: IA64 backend, BigBlock register allocator
N: John McCall
E: rjmccall@apple.com
D: Clang semantic analysis and IR generation
N: Michael McCracken
E: michael.mccracken@gmail.com
D: Line number support for llvmgcc
N: Vladimir Merzliakov
E: wanderer@rsu.ru
D: Test suite fixes for FreeBSD
N: Scott Michel
E: scottm@aero.org
D: Added STI Cell SPU backend.
N: Kai Nacke
E: kai@redstar.de
D: Support for implicit TLS model used with MS VC runtime
D: Dumping of Win64 EH structures
N: Takumi Nakamura
E: geek4civic@gmail.com
E: chapuni@hf.rim.or.jp
D: Cygwin and MinGW support.
D: Win32 tweaks.
S: Yokohama, Japan
N: Edward O'Callaghan
E: eocallaghan@auroraux.org
W: http://www.auroraux.org
D: Add Clang support with various other improvements to utils/NewNightlyTest.pl
D: Fix and maintain Solaris & AuroraUX support for llvm, various build warnings
D: and error clean ups.
N: Morten Ofstad
E: morten@hue.no
D: Visual C++ compatibility fixes
N: Jakob Stoklund Olesen
E: stoklund@2pi.dk
D: Machine code verifier
D: Blackfin backend
D: Fast register allocator
D: Greedy register allocator
N: Richard Osborne
E: richard@xmos.com
D: XCore backend
N: Devang Patel
E: dpatel@apple.com
D: LTO tool, PassManager rewrite, Loop Pass Manager, Loop Rotate
D: GCC PCH Integration (llvm-gcc), llvm-gcc improvements
D: Optimizer improvements, Loop Index Split
N: Ana Pazos
E: apazos@codeaurora.org
D: Fixes and improvements to the AArch64 backend
N: Wesley Peck
E: peckw@wesleypeck.com
W: http://wesleypeck.com/
D: MicroBlaze backend
N: Francois Pichet
E: pichet2000@gmail.com
D: MSVC support
N: Vladimir Prus
W: http://vladimir_prus.blogspot.com
E: ghost@cs.msu.su
D: Made inst_iterator behave like a proper iterator, LowerConstantExprs pass
N: Kalle Raiskila
E: kalle.rasikila@nokia.com
D: Some bugfixes to CellSPU
N: Xerxes Ranby
E: xerxes@zafena.se
D: Cmake dependency chain and various bug fixes
N: Alex Rosenberg
E: alexr@leftfield.org
I: arosenberg
D: ARM calling conventions rewrite, hard float support
N: Chad Rosier
E: mcrosier@codeaurora.org
I: mcrosier
D: AArch64 fast instruction selection pass
D: Fixes and improvements to the ARM fast-isel pass
D: Fixes and improvements to the AArch64 backend
N: Nadav Rotem
E: nrotem@apple.com
D: X86 code generation improvements, Loop Vectorizer.
N: Roman Samoilov
E: roman@codedgers.com
D: MSIL backend
N: Duncan Sands
E: baldrick@free.fr
I: baldrick
D: Ada support in llvm-gcc
D: Dragonegg plugin
D: Exception handling improvements
D: Type legalizer rewrite
N: Ruchira Sasanka
E: sasanka@uiuc.edu
D: Graph coloring register allocator for the Sparc64 backend
N: Arnold Schwaighofer
E: arnold.schwaighofer@gmail.com
D: Tail call optimization for the x86 backend
N: Shantonu Sen
E: ssen@apple.com
D: Miscellaneous bug fixes
N: Anand Shukla
E: ashukla@cs.uiuc.edu
D: The `paths' pass
N: Michael J. Spencer
E: bigcheesegs@gmail.com
D: Shepherding Windows COFF support into MC.
D: Lots of Windows stuff.
N: Reid Spencer
E: rspencer@reidspencer.com
W: http://reidspencer.com/
D: Lots of stuff, see: http://wiki.llvm.org/index.php/User:Reid
N: Alp Toker
E: alp@nuanti.com
W: http://atoker.com/
D: C++ frontend next generation standards implementation
N: Craig Topper
E: craig.topper@gmail.com
D: X86 codegen and disassembler improvements. AVX2 support.
N: Edwin Torok
E: edwintorok@gmail.com
D: Miscellaneous bug fixes
N: Adam Treat
E: manyoso@yahoo.com
D: C++ bugs filed, and C++ front-end bug fixes.
N: Lauro Ramos Venancio
E: lauro.venancio@indt.org.br
D: ARM backend improvements
D: Thread Local Storage implementation
N: Bill Wendling
I: wendling
E: isanbard@gmail.com
D: Release manager, IR Linker, LTO
D: Bunches of stuff
N: Bob Wilson
E: bob.wilson@acm.org
D: Advanced SIMD (NEON) support in the ARM backend.
-70
View File
@@ -1,70 +0,0 @@
==============================================================================
LLVM Release License
==============================================================================
University of Illinois/NCSA
Open Source License
Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign.
All rights reserved.
Developed by:
LLVM Team
University of Illinois at Urbana-Champaign
http://llvm.org
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimers in the
documentation and/or other materials provided with the distribution.
* Neither the names of the LLVM Team, University of Illinois at
Urbana-Champaign, nor the names of its contributors may be used to
endorse or promote products derived from this Software without specific
prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.
==============================================================================
Copyrights and Licenses for Third Party Software Distributed with LLVM:
==============================================================================
The LLVM software contains code written by third parties. Such software will
have its own individual LICENSE.TXT file in the directory in which it appears.
This file will describe the copyrights, license, and restrictions which apply
to that code.
The disclaimer of warranty in the University of Illinois Open Source License
applies to all code in the LLVM Distribution, and nothing in any of the
other licenses gives permission to use the names of the LLVM Team or the
University of Illinois to endorse or promote products derived from this
Software.
The following pieces of software have additional or alternate copyrights,
licenses, and/or restrictions:
Program Directory
------- ---------
Autoconf llvm/autoconf
llvm/projects/ModuleMaker/autoconf
Google Test llvm/utils/unittest/googletest
OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex}
pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT}
ARM contributions llvm/lib/Target/ARM/LICENSE.TXT
md5 contributions llvm/lib/Support/MD5.cpp llvm/include/llvm/Support/MD5.h
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+6 -4
View File
@@ -4,8 +4,7 @@
set exe_name=odin.exe
:: Debug = 0, Release = 1
set release_mode=1
set release_mode=0
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
if %release_mode% EQU 0 ( rem Debug
@@ -46,8 +45,11 @@ del *.ilk > NUL 2> NUL
cl %compiler_settings% "src\main.c" ^
/link %linker_settings% -OUT:%exe_name% ^
&& odin run code/demo.odin
rem && odin build_dll code/example.odin ^
rem && odin run code/demo.odin
rem && odin build code/metagen.odin ^
rem && call "code\metagen.exe" "src\ast_nodes.metagen"
rem && odin run code/Jaze/src/main.odin
del *.obj > NUL 2> NUL
:end_of_build
Executable
+24
View File
@@ -0,0 +1,24 @@
#!/bin/bash
release_mode=0
warnings_to_disable="-std=c11 -Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined"
libraries="-pthread -ldl -lm"
other_args=""
compiler="clang"
if [ "$release_mode" -eq "0" ]; then
other_args="${other_args} -g -fno-inline-functions"
fi
if [[ "$(uname)" == "Darwin" ]]; then
# Set compiler to clang on MacOS
# MacOS provides a symlink to clang called gcc, but it's nice to be explicit here.
compiler="clang"
other_args="${other_args} -liconv"
fi
${compiler} src/main.c ${warnings_to_disable} ${libraries} ${other_args} -o odin
./odin run code/demo.odin
+10 -52
View File
@@ -1,60 +1,18 @@
#import "fmt.odin";
main :: proc() {
{
Byte_Size :: enum f64 {
_, // Ignore first value
KB = 1<<(10*iota),
MB,
GB,
TB,
PB,
}
immutable program := "+ + * - /";
accumulator := 0;
using Byte_Size;
fmt.println(KB, MB, GB, TB, PB);
}
{
x := if 1 < 2 {
y := 123;
give y-2;
} else {
give 0;
};
x += {
x := 2;
give x;
};
fmt.println("x =", x);
}
{
list := []int{1, 4, 7, 3, 7, 2, 1};
for value : list {
fmt.println(value);
}
for val, idx : 12 ..< 17 {
fmt.println(val, idx);
}
msg := "Hellope";
for value : msg {
fmt.println(value);
for token in program {
match token {
case '+': accumulator += 1;
case '-': accumulator -= 1;
case '*': accumulator *= 2;
case '/': accumulator /= 2;
default: // Ignore everything else
}
}
{
i := 0;
while i < 2 {
i += 1;
}
// Idiom to emulate C-style for loops
while x := 0; x < 2 {
defer x += 1;
// Body of code
// ++ and -- have been removed
}
}
fmt.printf("The program \"%s\" calculates the value %d\n", program, accumulator);
}
+46 -39
View File
@@ -1,4 +1,5 @@
#import "win32.odin" when ODIN_OS == "windows";
#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";
@@ -12,11 +13,11 @@ time_now :: proc() -> f64 {
counter: i64;
win32.QueryPerformanceCounter(^counter);
result := counter as f64 / win32_perf_count_freq as f64;
result := cast(f64)counter / cast(f64)win32_perf_count_freq;
return result;
}
win32_print_last_error :: proc() {
err_code := win32.GetLastError() as int;
err_code := cast(int)win32.GetLastError();
if err_code != 0 {
fmt.println("GetLastError: %", err_code);
}
@@ -24,42 +25,42 @@ win32_print_last_error :: proc() {
// Yuk!
to_c_string :: proc(s: string) -> []u8 {
c_str := new_slice(u8, s.count+1);
copy(c_str, s as []byte);
c_str[s.count] = 0;
c_str := make([]u8, len(s)+1);
copy(c_str, cast([]byte)s);
c_str[len(s)] = 0;
return c_str;
}
Window :: struct {
width, height: int;
wc: win32.WNDCLASSEXA;
dc: win32.HDC;
hwnd: win32.HWND;
opengl_context, rc: win32.HGLRC;
c_title: []u8;
width, height: int,
wc: win32.WndClassExA,
dc: win32.Hdc,
hwnd: win32.Hwnd,
opengl_context, rc: wgl.Hglrc,
c_title: []u8,
}
make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) -> (Window, bool) {
make_window :: proc(title: string, msg, height: int, window_proc: win32.Wnd_Proc) -> (Window, bool) {
using win32;
w: Window;
w.width, w.height = msg, height;
class_name := "Win32-Odin-Window\x00";
c_class_name := class_name.data;
if title[title.count-1] != 0 {
c_class_name := ^class_name[0];
if title[len(title)-1] != 0 {
w.c_title = to_c_string(title);
} else {
w.c_title = title as []u8;
w.c_title = cast([]u8)title;
}
instance := GetModuleHandleA(nil);
w.wc = WNDCLASSEXA{
size = size_of(WNDCLASSEXA) as u32,
w.wc = WndClassExA{
size = size_of(WndClassExA),
style = CS_VREDRAW | CS_HREDRAW,
instance = instance as HINSTANCE,
instance = cast(Hinstance)instance,
class_name = c_class_name,
wnd_proc = window_proc,
};
@@ -70,10 +71,10 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
}
w.hwnd = CreateWindowExA(0,
c_class_name, w.c_title.data,
c_class_name, ^w.c_title[0],
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT,
w.width as i32, w.height as i32,
cast(i32)w.width, cast(i32)w.height,
nil, nil, instance, nil);
if w.hwnd == nil {
@@ -85,7 +86,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
{
pfd := PIXELFORMATDESCRIPTOR{
size = size_of(PIXELFORMATDESCRIPTOR) as u32,
size = size_of(PIXELFORMATDESCRIPTOR),
version = 1,
flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
pixel_type = PFD_TYPE_RGBA,
@@ -97,19 +98,20 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
};
SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), nil);
w.opengl_context = wglCreateContext(w.dc);
wglMakeCurrent(w.dc, w.opengl_context);
w.opengl_context = wgl.CreateContext(w.dc);
wgl.MakeCurrent(w.dc, w.opengl_context);
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,
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
};
wglCreateContextAttribsARB := wglGetProcAddress(("wglCreateContextAttribsARB\x00" as string).data) as wglCreateContextAttribsARBType;
w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0]);
wglMakeCurrent(w.dc, w.rc);
wgl_str := "wglCreateContextAttribsARB\x00";
wglCreateContextAttribsARB := cast(wgl.Create_Context_Attribs_ARB_Type)wgl.GetProcAddress(^wgl_str[0]);
w.rc = wglCreateContextAttribsARB(w.dc, nil, ^attribs[0]);
wgl.MakeCurrent(w.dc, w.rc);
SwapBuffers(w.dc);
}
@@ -117,7 +119,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
}
destroy_window :: proc(w: ^Window) {
free(w.c_title.data);
free(w.c_title);
}
display_window :: proc(w: ^Window) {
@@ -129,7 +131,7 @@ run :: proc() {
using win32;
using math;
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
win32_proc :: proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline {
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
os.exit(0);
return 0;
@@ -137,7 +139,7 @@ run :: proc() {
return DefWindowProcA(hwnd, msg, wparam, lparam);
}
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc);
window, window_success := make_window("Odin Language Demo", 854, 480, cast(Wnd_Proc)win32_proc);
if !window_success {
return;
}
@@ -153,10 +155,10 @@ run :: proc() {
for running {
curr_time := time_now();
dt := (curr_time - prev_time) as f32;
dt := cast(f32)(curr_time - prev_time);
prev_time = curr_time;
msg: MSG;
msg: Msg;
for PeekMessageA(^msg, nil, 0, 0, PM_REMOVE) > 0 {
if msg.message == WM_QUIT {
running = false;
@@ -178,7 +180,7 @@ run :: proc() {
if is_key_down(Key_Code.UP) { v[1] += 1; }
if is_key_down(Key_Code.DOWN) { v[1] -= 1; }
v = vec2_norm0(v);
v = norm(v);
pos += v * Vec2{SPEED * dt};
}
@@ -188,8 +190,8 @@ run :: proc() {
gl.Clear(gl.COLOR_BUFFER_BIT);
gl.LoadIdentity();
gl.Ortho(0, window.width as f64,
0, window.height as f64, 0, 1);
gl.Ortho(0, cast(f64)window.width,
0, cast(f64)window.height, 0, 1);
draw_rect :: proc(x, y, w, h: f32) {
gl.Begin(gl.TRIANGLES);
@@ -207,9 +209,14 @@ run :: proc() {
draw_rect(pos.x, pos.y, 50, 50);
display_window(^window);
ms_to_sleep := (16 - 1000*dt) as i32;
ms_to_sleep := cast(i32)(16 - 1000*dt);
if ms_to_sleep > 0 {
win32.Sleep(ms_to_sleep);
}
}
}
main :: proc() {
run();
}
+86 -86
View File
@@ -1,10 +1,10 @@
#import "fmt.odin"
#import "fmt.odin";
#foreign_system_library "Ws2_32" when ODIN_OS == "windows"
#foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows";
SOCKET :: type uint
INVALID_SOCKET :: ~(0 as SOCKET)
SOCKET :: #type uint;
INVALID_SOCKET :: ~(cast(SOCKET)0);
AF :: enum i32 {
UNSPEC = 0, // unspecified
@@ -35,111 +35,111 @@ AF :: enum i32 {
SIP = 24, // Simple Internet Protocol
PIP = 25, // Help Identify PIP packets
MAX = 26,
}
};
SOCK_STREAM :: 1
SOCKET_ERROR :: -1
IPPROTO_TCP :: 6
AI_PASSIVE :: 0x0020
SOMAXCONN :: 128
SOCK_STREAM :: 1;
SOCKET_ERROR :: -1;
IPPROTO_TCP :: 6;
AI_PASSIVE :: 0x0020;
SOMAXCONN :: 128;
SD_RECEIVE :: 0
SD_SEND :: 1
SD_BOTH :: 2
SD_RECEIVE :: 0;
SD_SEND :: 1;
SD_BOTH :: 2;
WSADESCRIPTION_LEN :: 256
WSASYS_STATUS_LEN :: 128
WSADESCRIPTION_LEN :: 256;
WSASYS_STATUS_LEN :: 128;
WSADATA :: struct #ordered {
version: i16
high_version: i16
version: i16,
high_version: i16,
// NOTE(bill): This is x64 ordering
max_sockets: u16
max_udp_dg: u16
vendor_info: ^byte
description: [WSADESCRIPTION_LEN+1]byte
system_status: [WSASYS_STATUS_LEN+1]byte
max_sockets: u16,
max_udp_dg: u16,
vendor_info: ^byte,
description: [WSADESCRIPTION_LEN+1]byte,
system_status: [WSASYS_STATUS_LEN+1]byte,
}
addrinfo :: struct #ordered {
flags: i32
family: i32
socktype: i32
protocol: i32
addrlen: uint
canonname: ^u8
addr: ^sockaddr
next: ^addrinfo
flags: i32,
family: i32,
socktype: i32,
protocol: i32,
addrlen: uint,
canonname: ^u8,
addr: ^sockaddr,
next: ^addrinfo,
}
sockaddr :: struct #ordered {
family: u16
data: [14]byte
family: u16,
data: [14]byte,
}
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign #dll_import
WSACleanup :: proc() -> i32 #foreign #dll_import
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign #dll_import
freeaddrinfo :: proc(ai: ^addrinfo) #foreign #dll_import
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign #dll_import
closesocket :: proc(s: SOCKET) -> i32 #foreign #dll_import
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign #dll_import
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign #dll_import
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign #dll_import
recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import
send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign #dll_import
WSAGetLastError :: proc() -> i32 #foreign #dll_import
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign ws2;
WSACleanup :: proc() -> i32 #foreign ws2;
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign ws2;
freeaddrinfo :: proc(ai: ^addrinfo) #foreign ws2;
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign ws2;
closesocket :: proc(s: SOCKET) -> i32 #foreign ws2;
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign ws2;
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign ws2;
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign ws2;
recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2;
send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2;
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign ws2;
WSAGetLastError :: proc() -> i32 #foreign ws2;
to_c_string :: proc(s: string) -> ^byte {
c_str := new_slice(byte, s.count+1)
assert(c_str.data != nil)
copy(c_str, s as []byte)
c_str[s.count] = 0
return c_str.data
c_str := new_slice(byte, s.count+1);
assert(c_str.data != nil);
copy(c_str, cast([]byte)s);
c_str[s.count] = 0;
return c_str.data;
}
run :: proc() {
wsa: WSADATA
res: ^addrinfo = nil
hints: addrinfo
s, client: SOCKET
wsa: WSADATA;
res: ^addrinfo = nil;
hints: addrinfo;
s, client: SOCKET;
if WSAStartup(2 | (2 << 8), ^wsa) != 0 {
fmt.println("WSAStartup failed: ", WSAGetLastError())
return
fmt.println("WSAStartup failed: ", WSAGetLastError());
return;
}
defer WSACleanup()
defer WSACleanup();
hints.family = AF.INET as i32
hints.socktype = SOCK_STREAM
hints.protocol = IPPROTO_TCP
hints.flags = AI_PASSIVE
hints.family = cast(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
fmt.println("getaddrinfo failed: ", WSAGetLastError());
return;
}
defer freeaddrinfo(res)
defer freeaddrinfo(res);
s = socket(res.family, res.socktype, res.protocol)
s = socket(res.family, res.socktype, res.protocol);
if s == INVALID_SOCKET {
fmt.println("socket failed: ", WSAGetLastError())
return
fmt.println("socket failed: ", WSAGetLastError());
return;
}
defer closesocket(s)
defer closesocket(s);
bind(s, res.addr, res.addrlen as i32)
listen(s, SOMAXCONN)
bind(s, res.addr, cast(i32)res.addrlen);
listen(s, SOMAXCONN);
client = accept(s, nil, 0)
client = accept(s, nil, 0);
if client == INVALID_SOCKET {
fmt.println("socket failed: ", WSAGetLastError())
return
fmt.println("socket failed: ", WSAGetLastError());
return;
}
defer closesocket(client)
defer closesocket(client);
html :=
`HTTP/1.1 200 OK
@@ -154,27 +154,27 @@ Content-type: text/html
<h1 style="color: orange;">Odin Server Demo</h1>
</body>
</html>
`
`;
buf: [1024]byte
buf: [1024]byte;
for {
bytes := recv(client, ^buf[0], buf.count as i32, 0)
bytes := recv(client, ^buf[0], cast(i32)buf.count, 0);
if bytes > 0 {
// fmt.println(buf[:bytes] as string)
bytes_sent := send(client, html.data, (html.count-1) as i32, 0)
bytes_sent := send(client, html.data, cast(i32)(html.count-1), 0);
if bytes_sent == SOCKET_ERROR {
fmt.println("send failed: ", WSAGetLastError())
return
fmt.println("send failed: ", WSAGetLastError());
return;
}
break
break;
} else if bytes == 0 {
fmt.println("Connection closing...")
break
fmt.println("Connection closing...");
break;
} else {
fmt.println("recv failed: ", WSAGetLastError())
return
fmt.println("recv failed: ", WSAGetLastError());
return;
}
}
shutdown(client, SD_SEND)
shutdown(client, SD_SEND);
}
+104 -101
View File
@@ -1,83 +1,86 @@
#import "fmt.odin"
#import "os.odin"
#import "mem.odin"
// #import "http_test.odin" as ht
// #import "game.odin" as game
// #import "punity.odin" as pn
#import "fmt.odin";
#import "os.odin";
#import "mem.odin";
// #import "http_test.odin" as ht;
// #import "game.odin" as game;
// #import "punity.odin" as pn;
main :: proc() {
// struct_padding()
// bounds_checking()
// type_introspection()
// any_type()
// crazy_introspection()
// namespaces_and_files()
// miscellany()
// ht.run()
// game.run()
// {
// init :: proc(c: ^pn.Core) {}
// step :: proc(c: ^pn.Core) {}
struct_padding();
bounds_checking();
type_introspection();
any_type();
crazy_introspection();
namespaces_and_files();
miscellany();
// pn.run(init, step)
// }
/*
ht.run();
game.run();
{
init :: proc(c: ^pn.Core) {}
step :: proc(c: ^pn.Core) {}
pn.run(init, step);
}
*/
}
struct_padding :: proc() {
{
A :: struct {
a: u8
b: u32
c: u16
a: u8,
b: u32,
c: u16,
}
B :: struct {
a: [7]u8
b: [3]u16
c: u8
d: u16
a: [7]u8,
b: [3]u16,
c: u8,
d: u16,
}
fmt.println("size_of(A):", size_of(A))
fmt.println("size_of(B):", size_of(B))
fmt.println("size_of(A):", size_of(A));
fmt.println("size_of(B):", size_of(B));
// n.b. http://cbloomrants.blogspot.co.uk/2012/07/07-23-12-structs-are-not-what-you-want.html
}
{
A :: struct #ordered {
a: u8
b: u32
c: u16
a: u8,
b: u32,
c: u16,
}
B :: struct #ordered {
a: [7]u8
b: [3]u16
c: u8
d: u16
a: [7]u8,
b: [3]u16,
c: u8,
d: u16,
}
fmt.println("size_of(A):", size_of(A))
fmt.println("size_of(B):", size_of(B))
fmt.println("size_of(A):", size_of(A));
fmt.println("size_of(B):", size_of(B));
// C-style structure layout
}
{
A :: struct #packed {
a: u8
b: u32
c: u16
a: u8,
b: u32,
c: u16,
}
B :: struct #packed {
a: [7]u8
b: [3]u16
c: u8
d: u16
a: [7]u8,
b: [3]u16,
c: u8,
d: u16,
}
fmt.println("size_of(A):", size_of(A))
fmt.println("size_of(B):", size_of(B))
fmt.println("size_of(A):", size_of(A));
fmt.println("size_of(B):", size_of(B));
// Useful for explicit layout
}
@@ -119,7 +122,7 @@ struct_padding :: proc() {
}
bounds_checking :: proc() {
x: [4]int
x: [4]int;
// x[-1] = 0; // Compile Time
// x[4] = 0; // Compile Time
@@ -132,9 +135,9 @@ bounds_checking :: proc() {
// Works for arrays, strings, slices, and related procedures & operations
{
base: [10]int
s := base[2:6]
a, b := -1, 6
base: [10]int;
s := base[2..6];
a, b := -1, 6;
#no_bounds_check {
s[a] = 0;
@@ -154,69 +157,69 @@ bounds_checking :: proc() {
type_introspection :: proc() {
{
info: ^Type_Info
x: int
info: ^Type_Info;
x: int;
info = type_info(int) // by type
info = type_info_of_val(x) // by value
info = type_info(int); // by type
info = type_info_of_val(x); // by value
// See: runtime.odin
match type i : info {
match i in info {
case Type_Info.Integer:
fmt.println("integer!")
fmt.println("integer!");
case Type_Info.Float:
fmt.println("float!")
fmt.println("float!");
default:
fmt.println("potato!")
fmt.println("potato!");
}
// Unsafe cast
integer_info := info as ^Type_Info.Integer
integer_info := cast(^Type_Info.Integer)cast(rawptr)info;
}
{
Vector2 :: struct { x, y: f32 }
Vector3 :: struct { x, y, z: f32 }
v1: Vector2
v2: Vector3
v3: Vector3
v1: Vector2;
v2: Vector3;
v3: Vector3;
t1 := type_info_of_val(v1)
t2 := type_info_of_val(v2)
t3 := type_info_of_val(v3)
t1 := type_info_of_val(v1);
t2 := type_info_of_val(v2);
t3 := type_info_of_val(v3);
fmt.println()
fmt.print("Type of v1 is:\n\t", t1)
fmt.println();
fmt.print("Type of v1 is:\n\t", t1);
fmt.println()
fmt.print("Type of v2 is:\n\t", t2)
fmt.println();
fmt.print("Type of v2 is:\n\t", t2);
fmt.println("\n")
fmt.println("t1 == t2:", t1 == t2)
fmt.println("t2 == t3:", t2 == t3)
fmt.println("\n");
fmt.println("t1 == t2:", t1 == t2);
fmt.println("t2 == t3:", t2 == t3);
}
}
any_type :: proc() {
a: any
a: any;
x: int = 123
y: f64 = 6.28
z: string = "Yo-Yo Ma"
x: int = 123;
y: f64 = 6.28;
z: string = "Yo-Yo Ma";
// All types can be implicit cast to `any`
a = x
a = y
a = z
a = a // This the "identity" type, it doesn't get converted
a = x;
a = y;
a = z;
a = a; // This the "identity" type, it doesn't get converted
a = 123 // Literals are copied onto the stack first
a = 123; // Literals are copied onto the stack first
// any has two members
// data - rawptr to the data
// type_info - pointer to the type info
fmt.println(x, y, z)
fmt.println(x, y, z);
// See: fmt.odin
// For variadic any procedures in action
}
@@ -232,15 +235,15 @@ crazy_introspection :: proc() {
TOMATO,
}
s: string
s = enum_to_string(Fruit.PEACH)
fmt.println(s)
s: string;
// s = enum_to_string(Fruit.PEACH);
fmt.println(s);
f := Fruit.GRAPE
s = enum_to_string(f)
fmt.println(s)
f := Fruit.GRAPE;
// s = enum_to_string(f);
fmt.println(s);
fmt.println(f)
fmt.println(f);
// See: runtime.odin
}
@@ -259,15 +262,15 @@ crazy_introspection :: proc() {
TOMATO,
}
fruit_ti := type_info(Fruit)
name := (fruit_ti as ^Type_Info.Named).name // Unsafe casts
info := type_info_base(fruit_ti) as ^Type_Info.Enum // Unsafe casts
fruit_ti := type_info(Fruit);
name := (union_cast(^Type_Info.Named)fruit_ti).name; // Unsafe casts
info, _ := union_cast(^Type_Info.Enum)type_info_base(fruit_ti); // Unsafe casts
fmt.printf("% :: enum % {\n", name, info.base);
for i := 0; i < info.values.count; i++ {
fmt.printf("\t%\t= %,\n", info.names[i], info.values[i])
fmt.printf("%s :: enum %T {\n", name, info.base);
for i := 0; i < len(info.values); i++ {
fmt.printf("\t%s\t= %v,\n", info.names[i], info.values[i]);
}
fmt.printf("}\n")
fmt.printf("}\n");
// NOTE(bill): look at that type-safe printf!
}
@@ -275,10 +278,10 @@ crazy_introspection :: proc() {
{
Vector3 :: struct {x, y, z: f32}
a := Vector3{x = 1, y = 4, z = 9}
fmt.println(a)
b := Vector3{x = 9, y = 3, z = 1}
fmt.println(b)
a := Vector3{x = 1, y = 4, z = 9};
fmt.println(a);
b := Vector3{x = 9, y = 3, z = 1};
fmt.println(b);
// NOTE(bill): See fmt.odin
}
File diff suppressed because it is too large Load Diff
+17 -17
View File
@@ -1,14 +1,14 @@
#import "fmt.odin"
#import "utf8.odin"
#import "hash.odin"
#import "mem.odin"
#import "fmt.odin";
#import "utf8.odin";
#import "hash.odin";
#import "mem.odin";
main :: proc() {
{ // New Standard Library stuff
s := "Hello"
s := "Hello";
fmt.println(s,
utf8.valid_string(s),
hash.murmur64(s.data, s.count))
hash.murmur64(cast([]byte)s));
// utf8.odin
// hash.odin
@@ -19,15 +19,15 @@ main :: proc() {
}
{
arena: mem.Arena
mem.init_arena_from_context(^arena, mem.megabytes(16)) // Uses default allocator
defer mem.free_arena(^arena)
arena: mem.Arena;
mem.init_arena_from_context(^arena, mem.megabytes(16)); // Uses default allocator
defer mem.free_arena(^arena);
push_allocator mem.arena_allocator(^arena) {
x := new(int)
x^ = 1337
x := new(int);
x^ = 1337;
fmt.println(x^)
fmt.println(x^);
}
/*
@@ -48,14 +48,14 @@ main :: proc() {
// You can also "push" a context
c := current_context() // Create copy of the allocator
c.allocator = mem.arena_allocator(^arena)
c := context; // Create copy of the allocator
c.allocator = mem.arena_allocator(^arena);
push_context c {
x := new(int)
x^ = 365
x := new(int);
x^ = 365;
fmt.println(x^)
fmt.println(x^);
}
}
+284
View File
@@ -0,0 +1,284 @@
#import "fmt.odin";
#import "utf8.odin";
// #import "atomic.odin";
// #import "hash.odin";
// #import "math.odin";
// #import "mem.odin";
// #import "opengl.odin";
// #import "os.odin";
// #import "sync.odin";
// #import win32 "sys/windows.odin";
main :: proc() {
// syntax();
procedure_overloading();
}
syntax :: proc() {
// Cyclic type checking
// Uncomment to see the error
// A :: struct {b: B};
// B :: struct {a: A};
x: int;
y := cast(f32)x;
z := transmute(u32)y;
// down_cast, union_cast are similar too
// Basic directives
fmt.printf("Basic directives = %s(%d): %s\n", #file, #line, #procedure);
// NOTE: new and improved `printf`
// TODO: It does need accurate float printing
// record fields use the same syntax a procedure signatures
Thing1 :: struct {
x: f32,
y: int,
z: ^[]int,
};
Thing2 :: struct {x: f32, y: int, z: ^[]int};
// Slice interals are now just a `ptr+len+cap`
slice: []int; compile_assert(size_of_val(slice) == 3*size_of(int));
// Helper type - Help the reader understand what it is quicker
My_Int :: #type int;
My_Proc :: #type proc(int) -> f32;
// All declarations with : are either variable or constant
// To make these declarations syntactically consistent
v_variable := 123;
c_constant :: 123;
c_type1 :: int;
c_type2 :: []int;
c_proc :: proc() { /* code here */ };
/*
x += 1;
x -= 1;
// ++ and -- have been removed
// x++;
// x--;
// Question: Should they be added again?
// They were removed as they are redundant and statements, not expressions
// like in C/C++
*/
// You can now build files as a `.dll`
// `odin build_dll demo.odin`
// New vector syntax
u, v: [vector 3]f32;
v[0] = 123;
v.x = 123; // valid for all vectors with count 1 to 4
// Next part
prefixes();
}
Prefix_Type :: struct {x: int, y: f32, z: rawptr};
#thread_local my_tls: Prefix_Type;
prefixes :: proc() {
using var: Prefix_Type;
immutable const := Prefix_Type{1, 2, nil};
var.x = 123;
x = 123;
// const.x = 123; // const is immutable
foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) {
// int_ptr = nil; // Not valid
// int_ptr^ = 123; // Not valid
}
// Same as C99's `restrict`
bar :: proc(no_alias a, b: ^int) {
// Assumes a never equals b so it can perform optimizations with that fact
}
when_statements();
}
when_statements :: proc() {
X :: 123 + 12;
Y :: X/5;
COND :: Y > 0;
when COND {
fmt.println("Y > 0");
} else {
fmt.println("Y <= 0");
}
when false {
this_code_does_not_exist(123, 321);
but_its_syntax_is_valid();
x :: ^^^^int;
}
foreign_procedures();
}
#foreign_system_library win32_user "user32.lib" when ODIN_OS == "windows";
// NOTE: This is done on purpose for two reasons:
// * Makes it clear where the platform specific stuff is
// * Removes the need to solve the travelling salesman problem when importing files :P
foreign_procedures :: proc() {
ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user;
show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user "ShowWindow";
// NOTE: If that library doesn't get used, it doesn't get linked with
// NOTE: There is not link checking yet to see if that procedure does come from that library
// See sys/windows.odin for more examples
special_expressions();
}
special_expressions :: proc() {
/*
// Block expression
x := {
a: f32 = 123;
b := a-123;
c := b/a;
give c;
}; // semicolon is required as it's an expression
y := if x < 50 {
give x;
} else {
// TODO: Type cohesion is not yet finished
give 123;
}; // semicolon is required as it's an expression
*/
// This is allows for inline blocks of code and will be a useful feature to have when
// macros will be implemented into the language
loops();
}
loops :: proc() {
// The C-style for loop
for i := 0; i < 123; i += 1 {
break;
}
for i := 0; i < 123; {
break;
}
for false {
break;
}
for {
break;
}
for i in 0..123 { // 123 exclusive
}
for i in 0..123-1 { // 122 inclusive
}
for val, idx in 12..16 {
fmt.println(val, idx);
}
primes := [..]int{2, 3, 5, 7, 11, 13, 17, 19};
for p in primes {
fmt.println(p);
}
// Pointers to arrays, slices, or strings are allowed
for _ in ^primes {
// ignore the value and just iterate across it
}
name := "你好,世界";
fmt.println(name);
for r in name {
compile_assert(type_of_val(r) == rune);
fmt.printf("%r\n", r);
}
when false {
for i, size := 0; i < name.count; i += size {
r: rune;
r, size = utf8.decode_rune(name[i..]);
fmt.printf("%r\n", r);
}
}
procedure_overloading();
}
procedure_overloading :: proc() {
THINGF :: 14451.1;
THINGI :: 14451;
foo :: proc() {
fmt.printf("Zero args\n");
}
foo :: proc(i: int) {
fmt.printf("int arg, i=%d\n", i);
}
foo :: proc(f: f64) {
i := cast(int)f;
fmt.printf("f64 arg, f=%d\n", i);
}
foo();
foo(THINGF);
// foo(THINGI); // 14451 is just a number so it could go to either procedures
foo(cast(int)THINGI);
foo :: proc(x: ^i32) -> (int, int) {
fmt.println("^int");
return 123, cast(int)(x^);
}
foo :: proc(x: rawptr) {
fmt.println("rawptr");
}
a: i32 = 123;
b: f32;
c: rawptr;
fmt.println(foo(^a));
foo(^b);
foo(c);
// foo(nil); // nil could go to numerous types thus the ambiguity
f: proc();
f = foo; // The correct `foo` to chosen
f();
// See math.odin and atomic.odin for more examples
}
+167 -160
View File
@@ -1,34 +1,35 @@
#import "win32.odin"
#import "fmt.odin"
#import "os.odin"
#import win32 "sys/windows.odin";
#import "fmt.odin";
#import "os.odin";
#import "mem.odin";
CANVAS_WIDTH :: 128
CANVAS_HEIGHT :: 128
CANVAS_SCALE :: 3
FRAME_TIME :: 1.0/30.0
WINDOW_TITLE :: "Punity\x00"
CANVAS_WIDTH :: 128;
CANVAS_HEIGHT :: 128;
CANVAS_SCALE :: 3;
FRAME_TIME :: 1.0/30.0;
WINDOW_TITLE :: "Punity\x00";
_ := compile_assert(CANVAS_WIDTH % 16 == 0)
_ := compile_assert(CANVAS_WIDTH % 16 == 0);
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE;
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE;
STACK_CAPACITY :: 1<<20
STORAGE_CAPACITY :: 1<<20
STACK_CAPACITY :: 1<<20;
STORAGE_CAPACITY :: 1<<20;
DRAW_LIST_RESERVE :: 128
DRAW_LIST_RESERVE :: 128;
MAX_KEYS :: 256
MAX_KEYS :: 256;
Core :: struct {
stack: ^Bank
storage: ^Bank
stack: ^Bank,
storage: ^Bank,
running: bool
key_modifiers: u32
key_states: [MAX_KEYS]byte
key_deltas: [MAX_KEYS]byte
running: bool,
key_modifiers: u32,
key_states: [MAX_KEYS]byte,
key_deltas: [MAX_KEYS]byte,
perf_frame,
perf_frame_inner,
@@ -36,70 +37,66 @@ Core :: struct {
perf_audio,
perf_blit,
perf_blit_cvt,
perf_blit_gdi: Perf_Span
perf_blit_gdi: Perf_Span,
frame: i64
frame: i64,
canvas: Canvas
draw_list: ^Draw_List
canvas: Canvas,
draw_list: ^Draw_List,
}
Perf_Span :: struct {
stamp: f64
delta: f32
stamp: f64,
delta: f32,
}
Bank :: struct {
memory: []byte
cursor: int
memory: []byte,
cursor: int,
}
Bank_State :: struct {
state: Bank
bank: ^Bank
state: Bank,
bank: ^Bank,
}
Color :: raw_union {
using channels: struct{ a, b, g, r: byte; }
rgba: u32
using channels: struct{a, b, g, r: byte},
rgba: u32,
}
Palette :: struct {
colors: [256]Color
colors_count: byte
colors: [256]Color,
colors_count: byte,
}
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
using minmax: struct {min_x, min_y, max_x, max_y: int},
using pos: struct {left, top, right, bottom: int},
e: [4]int,
}
Bitmap :: struct {
pixels: []byte
width: int
height: int
pixels: []byte,
width: int,
height: int,
}
Font :: struct {
using bitmap: Bitmap
char_width: int
char_height: int
using bitmap: Bitmap,
char_width: int,
char_height: int,
}
Canvas :: struct {
using bitmap: ^Bitmap
palette: Palette
translate_x: int
translate_y: int
clip: Rect
font: ^Font
using bitmap: ^Bitmap,
palette: Palette,
translate_x: int,
translate_y: int,
clip: Rect,
font: ^Font,
}
DrawFlag :: enum {
@@ -109,12 +106,9 @@ DrawFlag :: enum {
MASK = 1<<2,
}
Draw_Item :: struct {}
Draw_List :: struct {
Item :: struct {
}
items: []Item
items: []Draw_Item,
}
Key :: enum {
@@ -268,112 +262,112 @@ Key :: enum {
BACKSLASH = 92, /* \ */
RIGHT_BRACKET = 93, /* ] */
GRAVE_ACCENT = 96, /* ` */
}
};
key_down :: proc(k: Key) -> bool {
return _core.key_states[k] != 0
return _core.key_states[k] != 0;
}
key_pressed :: proc(k: Key) -> bool {
return (_core.key_deltas[k] != 0) && key_down(k)
return (_core.key_deltas[k] != 0) && key_down(k);
}
win32_perf_count_freq := win32.GetQueryPerformanceFrequency()
win32_perf_count_freq := win32.GetQueryPerformanceFrequency();
time_now :: proc() -> f64 {
assert(win32_perf_count_freq != 0)
assert(win32_perf_count_freq != 0);
counter: i64
win32.QueryPerformanceCounter(^counter)
result := counter as f64 / win32_perf_count_freq as f64
return result
counter: i64;
win32.QueryPerformanceCounter(^counter);
result := cast(f64)counter / cast(f64)win32_perf_count_freq;
return result;
}
_core: Core
_core: Core;
run :: proc(user_init, user_step: proc(c: ^Core)) {
using win32
using win32;
_core.running = true
_core.running = true;
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline #stdcall {
win32_proc :: proc(hwnd: win32.HWND, msg: u32, wparam: win32.WPARAM, lparam: win32.LPARAM) -> win32.LRESULT #no_inline #cc_c {
win32_app_key_mods :: proc() -> u32 {
mods: u32 = 0
mods: u32 = 0;
if is_key_down(Key_Code.SHIFT) {
mods |= Key.MOD_SHIFT as u32
mods |= cast(u32)Key.MOD_SHIFT;
}
if is_key_down(Key_Code.CONTROL) {
mods |= Key.MOD_CONTROL as u32
mods |= cast(u32)Key.MOD_CONTROL;
}
if is_key_down(Key_Code.MENU) {
mods |= Key.MOD_ALT as u32
mods |= cast(u32)Key.MOD_ALT;
}
if is_key_down(Key_Code.LWIN) || is_key_down(Key_Code.RWIN) {
mods |= Key.MOD_SUPER as u32
mods |= cast(u32)Key.MOD_SUPER;
}
return mods
return mods;
}
match msg {
case WM_KEYDOWN:
_core.key_modifiers = win32_app_key_mods()
_core.key_modifiers = win32_app_key_mods();
if wparam < MAX_KEYS {
_core.key_states[wparam] = 1
_core.key_deltas[wparam] = 1
_core.key_states[wparam] = 1;
_core.key_deltas[wparam] = 1;
}
return 0
return 0;
case WM_KEYUP:
_core.key_modifiers = win32_app_key_mods()
_core.key_modifiers = win32_app_key_mods();
if wparam < MAX_KEYS {
_core.key_states[wparam] = 0
_core.key_deltas[wparam] = 1
_core.key_states[wparam] = 0;
_core.key_deltas[wparam] = 1;
}
return 0
return 0;
case WM_CLOSE:
PostQuitMessage(0)
_core.running = false
return 0
PostQuitMessage(0);
_core.running = false;
return 0;
}
return DefWindowProcA(hwnd, msg, wparam, lparam)
return DefWindowProcA(hwnd, msg, wparam, lparam);
}
window_class := WNDCLASSEXA{
class_name = ("Punity\x00" as string).data, // C-style string
size = size_of(WNDCLASSEXA) as u32,
class_name = (cast(string)"Punity\x00").data, // C-style string
size = size_of(WNDCLASSEXA),
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
instance = GetModuleHandleA(nil) as HINSTANCE,
instance = cast(HINSTANCE)GetModuleHandleA(nil),
wnd_proc = win32_proc,
// wnd_proc = DefWindowProcA,
background = GetStockObject(BLACK_BRUSH) as HBRUSH,
}
background = cast(HBRUSH)GetStockObject(BLACK_BRUSH),
};
if RegisterClassExA(^window_class) == 0 {
fmt.fprintln(os.stderr, "RegisterClassExA failed")
return
fmt.fprintln(os.stderr, "RegisterClassExA failed");
return;
}
screen_width := GetSystemMetrics(SM_CXSCREEN)
screen_height := GetSystemMetrics(SM_CYSCREEN)
screen_width := GetSystemMetrics(SM_CXSCREEN);
screen_height := GetSystemMetrics(SM_CYSCREEN);
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
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;
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
assert(AdjustWindowRect(^rc, style, 0) != 0)
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
assert(AdjustWindowRect(^rc, style, 0) != 0);
wt := WINDOW_TITLE
wt := WINDOW_TITLE;
win32_window := CreateWindowExA(0,
window_class.class_name,
@@ -382,101 +376,114 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
rc.left, rc.top,
rc.right-rc.left, rc.bottom-rc.top,
nil, nil, window_class.instance,
nil)
nil);
if win32_window == nil {
fmt.fprintln(os.stderr, "CreateWindowExA failed")
return
fmt.fprintln(os.stderr, "CreateWindowExA failed");
return;
}
window_bmi: BITMAPINFO
window_bmi.size = size_of(BITMAPINFO.HEADER) as u32
window_bmi.width = CANVAS_WIDTH
window_bmi.height = CANVAS_HEIGHT
window_bmi.planes = 1
window_bmi.bit_count = 32
window_bmi.compression = BI_RGB
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)
user_init(^_core);
ShowWindow(win32_window, SW_SHOW);
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT);
defer free(window_buffer);
ShowWindow(win32_window, SW_SHOW)
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT)
assert(window_buffer.data != nil)
defer free(window_buffer.data)
for i := 0; i < window_buffer.count; i++ {
window_buffer[i] = 0xff00ff
for i := 0; i < window_buffer.count; i += 1 {
window_buffer[i] = 0xff00ff;
}
prev_time, curr_time,dt: f64
prev_time = time_now()
curr_time = time_now()
total_time : f64 = 0
offset_x := 0
offset_y := 0
dt: f64;
prev_time := time_now();
curr_time := time_now();
total_time : f64 = 0;
offset_x := 0;
offset_y := 0;
message: MSG
message: MSG;
for _core.running {
curr_time = time_now()
dt = curr_time - prev_time
prev_time = curr_time
total_time += dt
curr_time = time_now();
dt = curr_time - prev_time;
prev_time = curr_time;
total_time += dt;
offset_x += 1
offset_y += 2
offset_x += 1;
offset_y += 2;
{
data: [128]byte
buf := data[:0]
fmt.bprintf(^buf, "Punity: % ms\x00", dt*1000)
win32.SetWindowTextA(win32_window, buf.data)
data: [128]byte;
buf: fmt.Buffer;
buf.data = data[:];
fmt.bprintf(^buf, "Punity: %.4f ms\x00", dt*1000);
win32.SetWindowTextA(win32_window, ^buf[0]);
}
for y := 0; y < CANVAS_HEIGHT; y++ {
for x := 0; x < CANVAS_WIDTH; x++ {
g := (x % 32) * 8
b := (y % 32) * 8
window_buffer[x + y*CANVAS_WIDTH] = (g << 8 | b) as u32
for y := 0; y < CANVAS_HEIGHT; y += 1 {
for x := 0; x < CANVAS_WIDTH; x += 1 {
g := (x % 32) * 8;
b := (y % 32) * 8;
window_buffer[x + y*CANVAS_WIDTH] = cast(u32)(g << 8 | b);
}
}
_core.key_deltas = nil
mem.zero(^_core.key_deltas[0], size_of_val(_core.key_deltas));
for PeekMessageA(^message, nil, 0, 0, PM_REMOVE) != 0 {
if message.message == WM_QUIT {
_core.running = false
_core.running = false;
}
TranslateMessage(^message)
DispatchMessageA(^message)
TranslateMessage(^message);
DispatchMessageA(^message);
}
user_step(^_core)
user_step(^_core);
dc := GetDC(win32_window)
dc := GetDC(win32_window);
StretchDIBits(dc,
0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
window_buffer.data,
^window_bmi,
DIB_RGB_COLORS,
SRCCOPY)
ReleaseDC(win32_window, dc)
SRCCOPY);
ReleaseDC(win32_window, dc);
{
delta := time_now() - prev_time
ms := ((FRAME_TIME - delta) * 1000) as i32
delta := time_now() - prev_time;
ms := cast(i32)((FRAME_TIME - delta) * 1000);
if ms > 0 {
win32.Sleep(ms)
win32.Sleep(ms);
}
}
_core.frame++
_core.frame += 1;
}
}
main :: proc() {
user_init :: proc(c: ^Core) {
}
user_step :: proc(c: ^Core) {
}
run(user_init, user_step);
}
+3 -3
View File
@@ -5,10 +5,10 @@ thing :: proc() {
}*/
#import "fmt.odin" as format
#import "fmt.odin";
thing :: proc() {
format.println("Hello2!")
main :: proc() {
fmt.println("hello, world!");
}
+573 -146
View File
@@ -2,8 +2,8 @@
#import "os.odin";
#import "fmt.odin";
#import "mem.odin";
#import "utf8.odin";
#import "raw.odin";
// IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a
// #shared_global_scope due to the internals of the compiler.
@@ -13,77 +13,97 @@
// IMPORTANT NOTE(bill): Do not change the order of any of this data
// The compiler relies upon this _exact_ order
Type_Info_Member :: struct #ordered {
name: string; // can be empty if tuple
type_info: ^Type_Info;
offset: int; // offsets are not used in tuples
Type_Info_Enum_Value :: raw_union {
f: f64,
i: i64,
}
// NOTE(bill): This must match the compiler's
Calling_Convention :: enum {
ODIN = 0,
C = 1,
STD = 2,
FAST = 3,
}
Type_Info_Record :: struct #ordered {
fields: []Type_Info_Member;
size: int; // in bytes
align: int; // in bytes
packed: bool;
ordered: bool;
types: []^Type_Info,
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,
}
Type_Info :: union {
Named: struct #ordered {
name: string;
base: ^Type_Info; // This will _not_ be a Type_Info.Named
};
Integer: struct #ordered {
size: int; // in bytes
signed: bool;
};
Float: struct #ordered {
size: int; // in bytes
};
Any: struct #ordered {};
String: struct #ordered {};
Boolean: struct #ordered {};
Pointer: struct #ordered {
elem: ^Type_Info; // nil -> rawptr
};
Maybe: struct #ordered {
elem: ^Type_Info;
};
Procedure: struct #ordered {
params: ^Type_Info; // Type_Info.Tuple
results: ^Type_Info; // Type_Info.Tuple
variadic: bool;
};
Array: struct #ordered {
elem: ^Type_Info;
elem_size: int;
count: int;
};
Slice: struct #ordered {
elem: ^Type_Info;
elem_size: int;
};
Vector: struct #ordered {
elem: ^Type_Info;
elem_size: int;
count: int;
align: int;
};
Tuple: Type_Info_Record;
Struct: Type_Info_Record;
Union: Type_Info_Record;
Raw_Union: Type_Info_Record;
Enum: struct #ordered {
base: ^Type_Info;
names: []string;
// TODO(bill): store values some how. Maybe using a raw_union
};
size: int,
align: int,
Named{name: string, base: ^Type_Info},
Integer{signed: bool},
Float{},
Complex{},
Quaternion{},
String{},
Boolean{},
Any{},
Pointer{
elem: ^Type_Info, // nil -> rawptr
},
Atomic{elem: ^Type_Info},
Procedure{
params: ^Type_Info, // Type_Info.Tuple
results: ^Type_Info, // Type_Info.Tuple
variadic: bool,
convention: Calling_Convention,
},
Array{
elem: ^Type_Info,
elem_size: int,
count: int,
},
Dynamic_Array{elem: ^Type_Info, elem_size: int},
Slice {elem: ^Type_Info, elem_size: int},
Vector {elem: ^Type_Info, elem_size, count: int},
Tuple {using record: Type_Info_Record}, // Only really used for procedures
Struct {using record: Type_Info_Record},
Raw_Union {using record: Type_Info_Record},
Union{
common_fields: struct {
types: []^Type_Info,
names: []string,
offsets: []int, // offsets may not be used in tuples
},
variant_names: []string,
variant_types: []^Type_Info,
},
Enum{
base: ^Type_Info,
names: []string,
values: []Type_Info_Enum_Value,
},
Map{
key: ^Type_Info,
value: ^Type_Info,
generated_struct: ^Type_Info,
count: int, // == 0 if dynamic
},
}
// NOTE(bill): only the ones that are needed (not all types)
// This will be set by the compiler
__type_table: []Type_Info;
__argv__: ^^byte;
__argc__: i32;
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
if info == nil {
return nil;
}
base := info;
match type i : base {
match i in base {
case Type_Info.Named:
base = i.base;
}
@@ -91,50 +111,52 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
}
assume :: proc(cond: bool) #foreign "llvm.assume"
__debug_trap :: proc() #foreign "llvm.debugtrap"
__trap :: proc() #foreign "llvm.trap"
read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
bit_reverse64 :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
fmuladd32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
fmuladd64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
type_info_base_without_enum :: proc(info: ^Type_Info) -> ^Type_Info {
if info == nil {
return nil;
}
base := info;
match i in base {
case Type_Info.Named:
base = i.base;
case Type_Info.Enum:
base = i.base;
}
return base;
}
assume :: proc(cond: bool) #foreign __llvm_core "llvm.assume";
__debug_trap :: proc() #foreign __llvm_core "llvm.debugtrap";
__trap :: proc() #foreign __llvm_core "llvm.trap";
read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter";
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
Allocator_Mode :: enum u8 {
ALLOC = iota,
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) -> rawptr;
Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
Allocator :: struct #ordered {
procedure: Allocator_Proc;
data: rawptr;
procedure: Allocator_Proc,
data: rawptr,
}
Context :: struct #ordered {
thread_id: int;
thread_id: int,
allocator: Allocator;
allocator: Allocator,
user_data: rawptr;
user_index: int;
user_data: rawptr,
user_index: int,
}
#thread_local __context: Context;
@@ -144,7 +166,7 @@ DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
__check_context :: proc() {
c := ^__context;
c := &__context;
if c.allocator.procedure == nil {
c.allocator = default_allocator();
@@ -162,13 +184,21 @@ alloc_align :: proc(size, alignment: int) -> rawptr #inline {
return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
}
free :: proc(ptr: rawptr) #inline {
__check_context();
a := context.allocator;
if ptr != nil {
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
free_ptr_with_allocator :: proc(a: Allocator, ptr: rawptr) #inline {
if ptr == nil {
return;
}
if a.procedure == nil {
return;
}
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
}
free_ptr :: proc(ptr: rawptr) #inline {
__check_context();
free_ptr_with_allocator(context.allocator, ptr);
}
free_all :: proc() #inline {
__check_context();
a := context.allocator;
@@ -204,7 +234,7 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment:
return nil;
}
mem.copy(new_memory, old_memory, min(old_size, new_size));;
__mem_copy(new_memory, old_memory, min(old_size, new_size));;
free(old_memory);
return new_memory;
}
@@ -215,46 +245,21 @@ default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
using Allocator_Mode;
when false {
match mode {
case ALLOC:
total_size := size + alignment + size_of(mem.AllocationHeader);
ptr := os.heap_alloc(total_size);
header := ptr as ^mem.AllocationHeader;
ptr = mem.align_forward(header+1, alignment);
mem.allocation_header_fill(header, ptr, size);
return mem.zero(ptr, size);
match mode {
case ALLOC:
return os.heap_alloc(size);
case FREE:
os.heap_free(mem.allocation_header(old_memory));
return nil;
case FREE:
os.heap_free(old_memory);
return nil;
case FREE_ALL:
// NOTE(bill): Does nothing
case FREE_ALL:
// NOTE(bill): Does nothing
case RESIZE:
total_size := size + alignment + size_of(mem.AllocationHeader);
ptr := os.heap_resize(mem.allocation_header(old_memory), total_size);
header := ptr as ^mem.AllocationHeader;
ptr = mem.align_forward(header+1, alignment);
mem.allocation_header_fill(header, ptr, size);
return mem.zero(ptr, size);
}
} else {
match mode {
case ALLOC:
return os.heap_alloc(size);
case FREE:
os.heap_free(old_memory);
return nil;
case FREE_ALL:
// NOTE(bill): Does nothing
case RESIZE:
return os.heap_resize(old_memory, size);
}
case RESIZE:
ptr := os.heap_resize(old_memory, size);
assert(ptr != nil);
return ptr;
}
return nil;
@@ -275,20 +280,21 @@ default_allocator :: proc() -> Allocator {
__string_eq :: proc(a, b: string) -> bool {
if a.count != b.count {
if len(a) != len(b) {
return false;
}
if a.data == b.data {
if len(a) == 0 {
return true;
}
return mem.compare(a.data, b.data, a.count) == 0;
if &a[0] == &b[0] {
return true;
}
return __string_cmp(a, b) == 0;
}
__string_cmp :: proc(a, b: string) -> int {
return mem.compare(a.data, b.data, min(a.count, b.count));
return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
}
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }
@@ -298,39 +304,460 @@ __string_le :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) <=
__string_ge :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) >= 0; }
__complex64_eq :: proc(a, b: complex64) -> bool #inline { return real(a) == real(b) && imag(a) == imag(b); }
__complex64_ne :: proc(a, b: complex64) -> bool #inline { return real(a) != real(b) || imag(a) != imag(b); }
__complex128_eq :: proc(a, b: complex128) -> bool #inline { return real(a) == real(b) && imag(a) == imag(b); }
__complex128_ne :: proc(a, b: complex128) -> bool #inline { return real(a) != real(b) || imag(a) != imag(b); }
__quaternion128_eq :: proc(a, b: quaternion128) -> bool #inline {
return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b);
}
__quaternion128_ne :: proc(a, b: quaternion128) -> bool #inline {
return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b);
}
__quaternion256_eq :: proc(a, b: quaternion256) -> bool #inline {
return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b);
}
__quaternion256_ne :: proc(a, b: quaternion256) -> bool #inline {
return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b);
}
__assert :: proc(file: string, line, column: int, msg: string) #inline {
fmt.fprintf(os.stderr, "%(%:%) Runtime assertion: %\n",
fmt.fprintf(os.stderr, "%s(%d:%d) Runtime assertion: %s\n",
file, line, column, msg);
__debug_trap();
}
__panic :: proc(file: string, line, column: int, msg: string) #inline {
fmt.fprintf(os.stderr, "%s(%d:%d) Panic: %s\n",
file, line, column, msg);
__debug_trap();
}
__bounds_check_error :: proc(file: string, line, column: int, index, count: int) {
if 0 <= index && index < count {
return;
}
fmt.fprintf(os.stderr, "%(%:%) Index % is out of bounds range [0, %)\n",
fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..<%d\n",
file, line, column, index, count);
__debug_trap();
}
__slice_expr_error :: proc(file: string, line, column: int, low, high: int) {
if 0 <= low && low <= high {
__slice_expr_error :: proc(file: string, line, column: int, low, high, max: int) {
if 0 <= low && low <= high && high <= max {
return;
}
fmt.fprintf(os.stderr, "%(%:%) Invalid slice indices: [%:%]\n",
file, line, column, low, high);
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..<%d..<%d]\n",
file, line, column, low, high, max);
__debug_trap();
}
__substring_expr_error :: proc(file: string, line, column: int, low, high: int) {
if 0 <= low && low <= high {
return;
}
fmt.fprintf(os.stderr, "%(%:%) Invalid substring indices: [%:%]\n",
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d..<%d]\n",
file, line, column, low, high);
__debug_trap();
}
__type_assertion_check :: proc(ok: bool, file: string, line, column: int, from, to: ^Type_Info) {
if !ok {
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid type_assertion from %T to %T\n",
file, line, column, from, to);
__debug_trap();
}
}
__string_decode_rune :: proc(s: string) -> (rune, int) #inline {
return utf8.decode_rune(s);
}
__mem_set :: proc(data: rawptr, value: i32, len: int) -> rawptr {
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memset.p0i8.i64";
llvm_memset_64bit(data, byte(value), len, 1, false);
return data;
}
__mem_zero :: proc(data: rawptr, len: int) -> rawptr {
return __mem_set(data, 0, len);
}
__mem_copy :: proc(dst, src: rawptr, len: int) -> rawptr {
// NOTE(bill): This _must_ be implemented like C's memmove
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memmove.p0i8.p0i8.i64";
llvm_memmove_64bit(dst, src, len, 1, false);
return dst;
}
__mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr {
// NOTE(bill): This _must_ be implemented like C's memcpy
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memcpy.p0i8.p0i8.i64";
llvm_memcpy_64bit(dst, src, len, 1, false);
return dst;
}
__mem_compare :: proc(a, b: ^byte, n: int) -> int {
for i in 0..<n {
match {
case (a+i)^ < (b+i)^:
return -1;
case (a+i)^ > (b+i)^:
return +1;
}
}
return 0;
}
__sqrt_f32 :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32";
__sqrt_f64 :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64";
__abs_complex64 :: proc(x: complex64) -> f32 #inline {
r, i := real(x), imag(x);
return __sqrt_f32(r*r + i*i);
}
__abs_complex128 :: proc(x: complex128) -> f64 #inline {
r, i := real(x), imag(x);
return __sqrt_f64(r*r + i*i);
}
__abs_quaternion128 :: proc(x: quaternion128) -> f32 #inline {
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 :: proc(x: quaternion256) -> f64 #inline {
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
return __sqrt_f64(r*r + i*i + j*j + k*k);
}
__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int) {
array := ^raw.Dynamic_Array(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;
}
}
__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int) -> bool {
array := ^raw.Dynamic_Array(array_);
if cap <= array.cap {
return true;
}
__check_context();
if array.allocator.procedure == nil {
array.allocator = context.allocator;
}
assert(array.allocator.procedure != nil);
old_size := array.cap * elem_size;
new_size := cap * elem_size;
allocator := array.allocator;
new_data := allocator.procedure(allocator.data, Allocator_Mode.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;
}
__dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int) -> bool {
array := ^raw.Dynamic_Array(array_);
ok := __dynamic_array_reserve(array_, elem_size, elem_align, len);
if ok {
array.len = len;
}
return ok;
}
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
items: rawptr, item_count: int) -> int {
array := ^raw.Dynamic_Array(array_);
if item_count <= 0 || items == nil {
return array.len;
}
ok := true;
if array.cap <= array.len+item_count {
cap := 2 * array.cap + max(8, item_count);
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
}
if !ok {
// TODO(bill): Better error handling for failed reservation
return array.len;
}
data := ^byte(array.data);
assert(data != nil);
__mem_copy(data + (elem_size*array.len), items, elem_size * item_count);
array.len += item_count;
return array.len;
}
__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int) -> int {
array := ^raw.Dynamic_Array(array_);
ok := true;
if array.cap <= array.len+1 {
cap := 2 * array.cap + max(8, 1);
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
}
if !ok {
// TODO(bill): Better error handling for failed reservation
return array.len;
}
data := ^byte(array.data);
assert(data != nil);
__mem_zero(data + (elem_size*array.len), elem_size);
array.len++;
return array.len;
}
__slice_append :: proc(slice_: rawptr, elem_size, elem_align: int,
items: rawptr, item_count: int) -> int {
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 {
data := ^byte(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
__default_hash :: proc(data: []byte) -> u64 {
fnv64a :: proc(data: []byte) -> u64 {
h: u64 = 0xcbf29ce484222325;
for b in data {
h = (h ~ u64(b)) * 0x100000001b3;
}
return h;
}
return fnv64a(data);
}
__default_hash_string :: proc(s: string) -> u64 {
return __default_hash([]byte(s));
}
__INITIAL_MAP_CAP :: 16;
__Map_Key :: struct #ordered {
hash: u64,
str: string,
}
__Map_Find_Result :: struct #ordered {
hash_index: int,
entry_prev: int,
entry_index: int,
}
__Map_Entry_Header :: struct #ordered {
key: __Map_Key,
next: int,
/*
value: Value_Type,
*/
}
__Map_Header :: struct #ordered {
m: ^raw.Dynamic_Map,
is_key_string: bool,
entry_size: int,
entry_align: int,
value_offset: int,
value_size: int,
}
__dynamic_map_reserve :: proc(using header: __Map_Header, cap: int) {
__dynamic_array_reserve(&m.hashes, size_of(int), align_of(int), cap);
__dynamic_array_reserve(&m.entries, entry_size, entry_align, cap);
}
__dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
new_header: __Map_Header = header;
nm: raw.Dynamic_Map;
new_header.m = &nm;
header_hashes := ^raw.Dynamic_Array(&header.m.hashes);
nm_hashes := ^raw.Dynamic_Array(&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 i := 0; i < m.entries.len; i++ {
if len(nm.hashes) == 0 {
__dynamic_map_grow(new_header);
}
entry_header := __dynamic_map_get_entry(header, i);
data := ^byte(entry_header);
fr := __dynamic_map_find(new_header, entry_header.key);
j := __dynamic_map_add_entry(new_header, entry_header.key);
if fr.entry_prev < 0 {
nm.hashes[fr.hash_index] = j;
} else {
e := __dynamic_map_get_entry(new_header, fr.entry_prev);
e.next = j;
}
e := __dynamic_map_get_entry(new_header, j);
e.next = fr.entry_index;
ndata := ^byte(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;
}
__dynamic_map_get :: proc(h: __Map_Header, key: __Map_Key) -> rawptr {
index := __dynamic_map_find(h, key).entry_index;
if index >= 0 {
data := ^byte(__dynamic_map_get_entry(h, index));
val := data + h.value_offset;
return val;
}
return nil;
}
__dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr) {
index: int;
assert(value != nil);
if len(m.hashes) == 0 {
__dynamic_map_reserve(h, __INITIAL_MAP_CAP);
__dynamic_map_grow(h);
}
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 {
entry := __dynamic_map_get_entry(h, fr.entry_prev);
entry.next = index;
} else {
m.hashes[fr.hash_index] = index;
}
}
{
e := __dynamic_map_get_entry(h, index);
e.key = key;
val := ^byte(e) + value_offset;
__mem_copy(val, value, value_size);
}
if __dynamic_map_full(h) {
__dynamic_map_grow(h);
}
}
__dynamic_map_grow :: proc(using h: __Map_Header) {
new_count := max(2*m.entries.cap + 8, __INITIAL_MAP_CAP);
__dynamic_map_rehash(h, new_count);
}
__dynamic_map_full :: proc(using h: __Map_Header) -> bool {
return int(0.75 * f64(len(m.hashes))) <= m.entries.cap;
}
__dynamic_map_hash_equal :: proc(h: __Map_Header, a, b: __Map_Key) -> bool {
if a.hash == b.hash {
if h.is_key_string {
return a.str == b.str;
}
return true;
}
return false;
}
__dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_Result {
fr := __Map_Find_Result{-1, -1, -1};
if len(m.hashes) > 0 {
fr.hash_index = int(key.hash % u64(len(m.hashes)));
fr.entry_index = m.hashes[fr.hash_index];
for fr.entry_index >= 0 {
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;
}
__dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int {
prev := m.entries.len;
c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align);
if c != prev {
end := __dynamic_map_get_entry(h, c-1);
end.key = key;
end.next = -1;
}
return prev;
}
__dynamic_map_delete :: proc(using h: __Map_Header, key: __Map_Key) {
fr := __dynamic_map_find(h, key);
if fr.entry_index >= 0 {
__dynamic_map_erase(h, fr);
}
}
__dynamic_map_get_entry :: proc(using h: __Map_Header, index: int) -> ^__Map_Entry_Header {
data := ^byte(m.entries.data) + index*entry_size;
return ^__Map_Entry_Header(data);
}
__dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
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);
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;
}
}
-101
View File
@@ -1,101 +0,0 @@
// TODO(bill): Use assembly instead here to implement atomics
// Inline vs external file?
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
yield_thread :: proc() { win32._mm_pause(); }
mfence :: proc() { win32.ReadWriteBarrier(); }
sfence :: proc() { win32.WriteBarrier(); }
lfence :: proc() { win32.ReadBarrier(); }
load32 :: proc(a: ^i32) -> i32 {
return a^;
}
store32 :: proc(a: ^i32, value: i32) {
a^ = value;
}
compare_exchange32 :: proc(a: ^i32, expected, desired: i32) -> i32 {
return win32.InterlockedCompareExchange(a, desired, expected);
}
exchanged32 :: proc(a: ^i32, desired: i32) -> i32 {
return win32.InterlockedExchange(a, desired);
}
fetch_add32 :: proc(a: ^i32, operand: i32) -> i32 {
return win32.InterlockedExchangeAdd(a, operand);
}
fetch_and32 :: proc(a: ^i32, operand: i32) -> i32 {
return win32.InterlockedAnd(a, operand);
}
fetch_or32 :: proc(a: ^i32, operand: i32) -> i32 {
return win32.InterlockedOr(a, operand);
}
spin_lock32 :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange32(a, 1, 0);
counter := 0;
while old_value != 0 && (time_out < 0 || counter < time_out) {
counter += 1;
yield_thread();
old_value = compare_exchange32(a, 1, 0);
mfence();
}
return old_value == 0;
}
spin_unlock32 :: proc(a: ^i32) {
store32(a, 0);
mfence();
}
try_acquire_lock32 :: proc(a: ^i32) -> bool {
yield_thread();
old_value := compare_exchange32(a, 1, 0);
mfence();
return old_value == 0;
}
load64 :: proc(a: ^i64) -> i64 {
return a^;
}
store64 :: proc(a: ^i64, value: i64) {
a^ = value;
}
compare_exchange64 :: proc(a: ^i64, expected, desired: i64) -> i64 {
return win32.InterlockedCompareExchange64(a, desired, expected);
}
exchanged64 :: proc(a: ^i64, desired: i64) -> i64 {
return win32.InterlockedExchange64(a, desired);
}
fetch_add64 :: proc(a: ^i64, operand: i64) -> i64 {
return win32.InterlockedExchangeAdd64(a, operand);
}
fetch_and64 :: proc(a: ^i64, operand: i64) -> i64 {
return win32.InterlockedAnd64(a, operand);
}
fetch_or64 :: proc(a: ^i64, operand: i64) -> i64 {
return win32.InterlockedOr64(a, operand);
}
spin_lock64 :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange64(a, 1, 0);
counter := 0;
while old_value != 0 && (time_out < 0 || counter < time_out) {
counter += 1;
yield_thread();
old_value = compare_exchange64(a, 1, 0);
mfence();
}
return old_value == 0;
}
spin_unlock64 :: proc(a: ^i64) {
store64(a, 0);
mfence();
}
try_acquire_lock64 :: proc(a: ^i64) -> bool {
yield_thread();
old_value := compare_exchange64(a, 1, 0);
mfence();
return old_value == 0;
}
+100
View File
@@ -0,0 +1,100 @@
// TODO(bill): Use assembly instead here to implement atomics
// Inline vs external file?
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
yield_thread :: proc() { win32.mm_pause(); }
mfence :: proc() { win32.ReadWriteBarrier(); }
sfence :: proc() { win32.WriteBarrier(); }
lfence :: proc() { win32.ReadBarrier(); }
load :: proc(a: ^i32) -> i32 {
return a^;
}
store :: proc(a: ^i32, value: i32) {
a^ = value;
}
compare_exchange :: proc(a: ^i32, expected, desired: i32) -> i32 {
return win32.InterlockedCompareExchange(a, desired, expected);
}
exchanged :: proc(a: ^i32, desired: i32) -> i32 {
return win32.InterlockedExchange(a, desired);
}
fetch_add :: proc(a: ^i32, operand: i32) -> i32 {
return win32.InterlockedExchangeAdd(a, operand);
}
fetch_and :: proc(a: ^i32, operand: i32) -> i32 {
return win32.InterlockedAnd(a, operand);
}
fetch_or :: proc(a: ^i32, operand: i32) -> i32 {
return win32.InterlockedOr(a, operand);
}
spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange(a, 1, 0);
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;
}
spin_unlock :: proc(a: ^i32) {
store(a, 0);
mfence();
}
try_acquire_lock :: proc(a: ^i32) -> bool {
yield_thread();
old_value := compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}
load :: proc(a: ^i64) -> i64 {
return a^;
}
store :: proc(a: ^i64, value: i64) {
a^ = value;
}
compare_exchange :: proc(a: ^i64, expected, desired: i64) -> i64 {
return win32.InterlockedCompareExchange64(a, desired, expected);
}
exchanged :: proc(a: ^i64, desired: i64) -> i64 {
return win32.InterlockedExchange64(a, desired);
}
fetch_add :: proc(a: ^i64, operand: i64) -> i64 {
return win32.InterlockedExchangeAdd64(a, operand);
}
fetch_and :: proc(a: ^i64, operand: i64) -> i64 {
return win32.InterlockedAnd64(a, operand);
}
fetch_or :: proc(a: ^i64, operand: i64) -> i64 {
return win32.InterlockedOr64(a, operand);
}
spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange(a, 1, 0);
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;
}
spin_unlock :: proc(a: ^i64) {
store(a, 0);
mfence();
}
try_acquire_lock :: proc(a: ^i64) -> bool {
yield_thread();
old_value := compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}
+257
View File
@@ -0,0 +1,257 @@
// #import "fmt.odin";
// Multiple precision decimal numbers
// NOTE: This is only for floating point printing and nothing else
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 {
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);
buf = buf[0..<n];
if a.count == 0 {
buf[0] = '0';
return string(buf[0..<1]);
}
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
trim :: proc(a: ^Decimal) {
for a.count > 0 && a.digits[a.count-1] == '0' {
a.count--;
}
if a.count == 0 {
a.decimal_point = 0;
}
}
assign :: proc(a: ^Decimal, i: u64) {
buf: [32]byte;
n := 0;
for i > 0 {
j := i/10;
i -= 10*j;
buf[n] = byte('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);
}
uint_size :: 8*size_of(uint);
max_shift :: uint_size-4;
shift_right :: proc(a: ^Decimal, k: uint) {
r := 0; // read index
w := 0; // write index
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;
}
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++ {
c := uint(a.digits[r]);
dig := n>>k;
n &= mask;
a.digits[w] = byte('0' + dig);
w++;
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++;
} else if dig > 0 {
a.trunc = true;
}
n *= 10;
}
a.count = w;
trim(a);
}
shift_left :: proc(a: ^Decimal, k: uint) {
delta := int(k/4);
r := a.count; // read index
w := a.count+delta; // write index
n: uint;
for r--; r >= 0; r-- {
n += (uint(a.digits[r]) - '0') << k;
quo := n/10;
rem := n - 10*quo;
w--;
if w < len(a.digits) {
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--;
if 0 <= w && w < len(a.digits) {
a.digits[w] = byte('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);
}
shift :: proc(a: ^Decimal, k: int) {
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));
}
}
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 {
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-- {
if 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++;
}
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;
n: u64 = 0;
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;
}
+1099 -477
View File
File diff suppressed because it is too large Load Diff
+103 -64
View File
@@ -1,77 +1,112 @@
crc32 :: proc(data: rawptr, len: int) -> u32 {
result := ~(0 as u32);
s := slice_ptr(data as ^u8, len);
for i : 0..<len {
b := s[i] as u32;
result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff];
crc32 :: proc(data: []byte) -> u32 {
result := ~u32(0);
for b in data {
result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff];
}
return ~result;
}
crc64 :: proc(data: rawptr, len: int) -> u64 {
result := ~(0 as u64);
s := slice_ptr(data as ^u8, len);
for i : 0..<len {
b := s[i] as u64;
result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff];
crc64 :: proc(data: []byte) -> u64 {
result := ~u64(0);
for b in data {
result = result>>8 ~ _crc64_table[(result ~ u64(b)) & 0xff];
}
return ~result;
}
fnv32 :: proc(data: rawptr, len: int) -> u32 {
s := slice_ptr(data as ^u8, len);
fnv32 :: proc(data: []byte) -> u32 {
h: u32 = 0x811c9dc5;
for i : 0..<len {
h = (h * 0x01000193) ~ s[i] as u32;
for b in data {
h = (h * 0x01000193) ~ u32(b);
}
return h;
}
fnv64 :: proc(data: rawptr, len: int) -> u64 {
s := slice_ptr(data as ^u8, len);
fnv64 :: proc(data: []byte) -> u64 {
h: u64 = 0xcbf29ce484222325;
for i : 0..<len {
h = (h * 0x100000001b3) ~ s[i] as u64;
for b in data {
h = (h * 0x100000001b3) ~ u64(b);
}
return h;
}
fnv32a :: proc(data: rawptr, len: int) -> u32 {
s := slice_ptr(data as ^u8, len);
fnv32a :: proc(data: []byte) -> u32 {
h: u32 = 0x811c9dc5;
for i : 0..<len {
h = (h ~ s[i] as u32) * 0x01000193;
for b in data {
h = (h ~ u32(b)) * 0x01000193;
}
return h;
}
fnv64a :: proc(data: rawptr, len: int) -> u64 {
s := slice_ptr(data as ^u8, len);
h :u64 = 0xcbf29ce484222325;
for i : 0..<len {
h = (h ~ s[i] as u64) * 0x100000001b3;
fnv64a :: proc(data: []byte) -> u64 {
h: u64 = 0xcbf29ce484222325;
for b in data {
h = (h ~ u64(b)) * 0x100000001b3;
}
return h;
}
murmur32 :: proc(data: []byte) -> u32 {
c1_32: u32 : 0xcc9e2d51;
c2_32: u32 : 0x1b873593;
murmur64 :: proc(data_: rawptr, len: int) -> u64 {
h1: u32 = 0;
nblocks := len(data)/4;
p := &data[0];
p1 := p + 4*nblocks;
for ; p < p1; p += 4 {
k1 := ^u32(p)^;
k1 *= c1_32;
k1 = (k1 << 15) | (k1 >> 17);
k1 *= c2_32;
h1 ~= k1;
h1 = (h1 << 13) | (h1 >> 19);
h1 = h1*5 + 0xe6546b64;
}
tail := data[nblocks*4 ..];
k1: u32;
match len(tail)&3 {
case 3:
k1 ~= u32(tail[2]) << 16;
fallthrough;
case 2:
k1 ~= u32(tail[2]) << 8;
fallthrough;
case 1:
k1 ~= u32(tail[0]);
k1 *= c1_32;
k1 = (k1 << 15) | (k1 >> 17) ;
k1 *= c2_32;
h1 ~= k1;
}
h1 ~= u32(len(data));
h1 ~= h1 >> 16;
h1 *= 0x85ebca6b;
h1 ~= h1 >> 13;
h1 *= 0xc2b2ae35;
h1 ~= h1 >> 16;
return h1;
}
murmur64 :: proc(data: []byte) -> u64 {
SEED :: 0x9747b28c;
when size_of(int) == 8 {
m :: 0xc6a4a7935bd1e995;
r :: 47;
h: u64 = SEED ~ (len as u64 * m);
h: u64 = SEED ~ (u64(len(data)) * m);
data64 := slice_ptr(^u64(&data[0]), len(data)/size_of(u64));
data := slice_ptr(data_ as ^u64, len/size_of(u64));
data2 := slice_ptr(data_ as ^u8, len);
for i : 0 ..< data.count {
k := data[i];
for _, i in data64 {
k := data64[i];
k *= m;
k ~= k>>r;
@@ -81,15 +116,15 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
h *= m;
}
match len & 7 {
case 7: h ~= data2[6] as u64 << 48; fallthrough;
case 6: h ~= data2[5] as u64 << 40; fallthrough;
case 5: h ~= data2[4] as u64 << 32; fallthrough;
case 4: h ~= data2[3] as u64 << 24; fallthrough;
case 3: h ~= data2[2] as u64 << 16; fallthrough;
case 2: h ~= data2[1] as u64 << 8; fallthrough;
match 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;
case 4: h ~= u64(data[3]) << 24; fallthrough;
case 3: h ~= u64(data[2]) << 16; fallthrough;
case 2: h ~= u64(data[1]) << 8; fallthrough;
case 1:
h ~= data2[0] as u64;
h ~= u64(data[0]);
h *= m;
}
@@ -102,15 +137,16 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
m :: 0x5bd1e995;
r :: 24;
h1: u32 = SEED as u32 ~ len as u32;
h2: u32 = SEED >> 32;
h1 := u32(SEED) ~ u32(len(data));
h2 := u32(SEED) >> 32;
data := slice_ptr(data_ as ^u32, len/size_of(u32));
data32 := slice_ptr(cast(^u32)&data[0], len(data)/size_of(u32));
len := len(data);
i := 0;
while len >= 8 {
for len >= 8 {
k1, k2: u32;
k1 = data[i]; i += 1;
k1 = data32[i]; i++;
k1 *= m;
k1 ~= k1>>r;
k1 *= m;
@@ -118,7 +154,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
h1 ~= k1;
len -= 4;
k2 = data[i]; i += 1;
k2 = data32[i]; i++;
k2 *= m;
k2 ~= k2>>r;
k2 *= m;
@@ -129,7 +165,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
if len >= 4 {
k1: u32;
k1 = data[i]; i += 1;
k1 = data32[i]; i++;
k1 *= m;
k1 ~= k1>>r;
k1 *= m;
@@ -138,13 +174,17 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
len -= 4;
}
data8 := slice_ptr((data.data+i) as ^u8, 3); // NOTE(bill): This is unsafe
// TODO(bill): Fix this
#no_bounds_check data8 := slice_to_bytes(data32[i..])[0..<3];
match len {
case 3: h2 ~= data8[2] as u32 << 16; fallthrough;
case 2: h2 ~= data8[1] as u32 << 8; fallthrough;
case 3:
h2 ~= u32(data8[2]) << 16;
fallthrough;
case 2:
h2 ~= u32(data8[1]) << 8;
fallthrough;
case 1:
h2 ~= data8[0] as u32;
h2 ~= u32(data8[0]);
h2 *= m;
}
@@ -157,14 +197,13 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
h2 ~= h1>>19;
h2 *= m;
h := (h1 as u64)<<32 | h2 as u64;
h := cast(u64)(h1)<<32 | cast(u64)(h2);
return h;
}
}
__CRC32_TABLE := [256]u32{
immutable _crc32_table := [256]u32{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -230,7 +269,7 @@ __CRC32_TABLE := [256]u32{
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
__CRC64_TABLE := [256]u64{
immutable _crc64_table := [256]u64{
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
+110 -94
View File
@@ -20,67 +20,87 @@ Vec2 :: [vector 2]f32;
Vec3 :: [vector 3]f32;
Vec4 :: [vector 4]f32;
Mat2 :: [2]Vec2;
Mat3 :: [3]Vec3;
Mat4 :: [4]Vec4;
// Column major
Mat2 :: [2][2]f32;
Mat3 :: [3][3]f32;
Mat4 :: [4][4]f32;
sqrt32 :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
sqrt64 :: proc(x: f64) -> f64 #foreign "llvm.sqrt.f64"
Complex :: complex64;
Quat :: quaternion128;
sin32 :: proc(x: f32) -> f32 #foreign "llvm.sin.f32"
sin64 :: proc(x: f64) -> f64 #foreign "llvm.sin.f64"
sqrt :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32";
sqrt :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64";
cos32 :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
cos64 :: proc(x: f64) -> f64 #foreign "llvm.cos.f64"
sin :: proc(θ: f32) -> f32 #foreign __llvm_core "llvm.sin.f32";
sin :: proc(θ: f64) -> f64 #foreign __llvm_core "llvm.sin.f64";
tan32 :: proc(x: f32) -> f32 #inline { return sin32(x)/cos32(x); }
tan64 :: proc(x: f64) -> f64 #inline { return sin64(x)/cos64(x); }
cos :: proc(θ: f32) -> f32 #foreign __llvm_core "llvm.cos.f32";
cos :: proc(θ: f64) -> f64 #foreign __llvm_core "llvm.cos.f64";
lerp32 :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
lerp64 :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
tan :: proc(θ: f32) -> f32 #inline { return sin(θ)/cos(θ); }
tan :: proc(θ: f64) -> f64 #inline { return sin(θ)/cos(θ); }
sign32 :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
sign64 :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
pow :: proc(x, power: f32) -> f32 #foreign __llvm_core "llvm.pow.f32";
pow :: proc(x, power: f64) -> f64 #foreign __llvm_core "llvm.pow.f64";
lerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
copy_sign32 :: proc(x, y: f32) -> f32 {
ix := x transmute u32;
iy := y transmute u32;
ix &= 0x7fffffff;
ix |= iy & 0x80000000;
return ix transmute f32;
}
round32 :: proc(x: f32) -> f32 {
if x >= 0 {
return floor32(x + 0.5);
}
return ceil32(x - 0.5);
}
floor32 :: proc(x: f32) -> f32 {
if x >= 0 {
return x as int as f32;
}
return (x-0.5) as int as f32;
}
ceil32 :: proc(x: f32) -> f32 {
if x < 0 {
return x as int as f32;
}
return ((x as int)+1) as f32;
sign :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
sign :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16";
bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32";
bit_reverse :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bitreverse.i64";
fmuladd :: proc(a, b, c: f32) -> f32 #foreign __llvm_core "llvm.fmuladd.f32";
fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64";
copy_sign :: proc(x, y: f32) -> f32 {
ix := transmute(u32, x);
iy := transmute(u32, y);
ix &= 0x7fff_ffff;
ix |= iy & 0x8000_0000;
return transmute(f32, ix);
}
remainder32 :: proc(x, y: f32) -> f32 {
return x - round32(x/y) * y;
copy_sign :: proc(x, y: f64) -> f64 {
ix := transmute(u64, x);
iy := transmute(u64, y);
ix &= 0x7fff_ffff_ffff_ff;
ix |= iy & 0x8000_0000_0000_0000;
return transmute(f64, ix);
}
fmod32 :: proc(x, y: f32) -> f32 {
round :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
round :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
floor :: proc(x: f32) -> f32 { return x >= 0 ? f32(i64(x)) : f32(i64(x-0.5)); } // TODO: Get accurate versions
floor :: proc(x: f64) -> f64 { return x >= 0 ? f64(i64(x)) : f64(i64(x-0.5)); } // TODO: Get accurate versions
ceil :: proc(x: f32) -> f32 { return x < 0 ? f32(i64(x)) : f32(i64(x+1)); } // TODO: Get accurate versions
ceil :: proc(x: f64) -> f64 { return x < 0 ? f64(i64(x)) : f64(i64(x+1)); } // TODO: Get accurate versions
remainder :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
remainder :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
mod :: proc(x, y: f32) -> f32 {
y = abs(y);
result := remainder32(abs(x), y);
if sign32(result) < 0 {
result := remainder(abs(x), y);
if sign(result) < 0 {
result += y;
}
return copy_sign32(result, x);
return copy_sign(result, x);
}
mod :: proc(x, y: f64) -> f64 {
y = abs(y);
result := remainder(abs(x), y);
if sign(result) < 0 {
result += y;
}
return copy_sign(result, x);
}
@@ -89,48 +109,47 @@ to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
dot :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y; }
dot :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
dot :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
dot2 :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y; }
dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
cross3 :: proc(x, y: Vec3) -> Vec3 {
cross :: proc(x, y: Vec3) -> Vec3 {
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
return a - b;
}
vec2_mag :: proc(v: Vec2) -> f32 { return sqrt32(dot2(v, v)); }
vec3_mag :: proc(v: Vec3) -> f32 { return sqrt32(dot3(v, v)); }
vec4_mag :: proc(v: Vec4) -> f32 { return sqrt32(dot4(v, v)); }
mag :: proc(v: Vec2) -> f32 { return sqrt(dot(v, v)); }
mag :: proc(v: Vec3) -> f32 { return sqrt(dot(v, v)); }
mag :: proc(v: Vec4) -> f32 { return sqrt(dot(v, v)); }
vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; }
vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; }
vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; }
norm :: proc(v: Vec2) -> Vec2 { return v / mag(v); }
norm :: proc(v: Vec3) -> Vec3 { return v / mag(v); }
norm :: proc(v: Vec4) -> Vec4 { return v / mag(v); }
vec2_norm0 :: proc(v: Vec2) -> Vec2 {
m := vec2_mag(v);
norm0 :: proc(v: Vec2) -> Vec2 {
m := mag(v);
if m == 0 {
return Vec2{0};
return 0;
}
return v / Vec2{m};
return v / m;
}
vec3_norm0 :: proc(v: Vec3) -> Vec3 {
m := vec3_mag(v);
norm0 :: proc(v: Vec3) -> Vec3 {
m := mag(v);
if m == 0 {
return Vec3{0};
return 0;
}
return v / Vec3{m};
return v / m;
}
vec4_norm0 :: proc(v: Vec4) -> Vec4 {
m := vec4_mag(v);
norm0 :: proc(v: Vec4) -> Vec4 {
m := mag(v);
if m == 0 {
return Vec4{0};
return 0;
}
return v / Vec4{m};
return v / m;
}
@@ -145,18 +164,18 @@ mat4_identity :: proc() -> Mat4 {
}
mat4_transpose :: proc(m: Mat4) -> Mat4 {
for j : 0..<4 {
for i : 0..<4 {
for j in 0..<4 {
for i in 0..<4 {
m[i][j], m[j][i] = m[j][i], m[i][j];
}
}
return m;
}
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
mul :: proc(a, b: Mat4) -> Mat4 {
c: Mat4;
for j : 0..<4 {
for i : 0..<4 {
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] +
@@ -166,7 +185,7 @@ mat4_mul :: proc(a, b: Mat4) -> Mat4 {
return c;
}
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
mul :: proc(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,
@@ -175,7 +194,7 @@ mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
};
}
mat4_inverse :: proc(m: Mat4) -> Mat4 {
inverse :: proc(m: Mat4) -> Mat4 {
o: Mat4;
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
@@ -254,10 +273,10 @@ mat4_translate :: proc(v: Vec3) -> Mat4 {
}
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
c := cos32(angle_radians);
s := sin32(angle_radians);
c := cos(angle_radians);
s := sin(angle_radians);
a := vec3_norm(v);
a := norm(v);
t := a * Vec3{1-c};
rot := mat4_identity();
@@ -280,14 +299,14 @@ mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
return rot;
}
mat4_scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
m[0][0] *= v.x;
m[1][1] *= v.y;
m[2][2] *= v.z;
return m;
}
mat4_scalef :: proc(m: Mat4, s: f32) -> Mat4 {
scale :: proc(m: Mat4, s: f32) -> Mat4 {
m[0][0] *= s;
m[1][1] *= s;
m[2][2] *= s;
@@ -295,23 +314,23 @@ mat4_scalef :: proc(m: Mat4, s: f32) -> Mat4 {
}
mat4_look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
f := vec3_norm(centre - eye);
s := vec3_norm(cross3(f, up));
u := cross3(s, f);
look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
f := norm(centre - eye);
s := norm(cross(f, up));
u := cross(s, f);
m: Mat4;
m[0] = Vec4{+s.x, +s.y, +s.z, 0};
m[1] = Vec4{+u.x, +u.y, +u.z, 0};
m[2] = Vec4{-f.x, -f.y, -f.z, 0};
m[3] = Vec4{dot3(s, eye), dot3(u, eye), dot3(f, eye), 1};
m[0] = [4]f32{+s.x, +s.y, +s.z, 0};
m[1] = [4]f32{+u.x, +u.y, +u.z, 0};
m[2] = [4]f32{-f.x, -f.y, -f.z, 0};
m[3] = [4]f32{dot(s, eye), dot(u, eye), dot(f, eye), 1};
return m;
}
mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
m: Mat4;
tan_half_fovy := tan32(0.5 * fovy);
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);
@@ -321,7 +340,7 @@ mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
}
mat4_ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
m := mat4_identity();
m[0][0] = +2.0 / (right - left);
m[1][1] = +2.0 / (top - bottom);
@@ -361,6 +380,3 @@ 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
+73 -114
View File
@@ -1,71 +1,33 @@
#import "fmt.odin";
#import "os.odin";
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
llvm_memset_64bit(data, value as byte, len, 1, false);
return data;
swap :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bswap.i16";
swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32";
swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64";
set :: proc(data: rawptr, value: i32, len: int) -> rawptr {
return __mem_set(data, value, len);
}
zero :: proc(data: rawptr, len: int) -> rawptr #link_name "__mem_zero" {
return set(data, 0, len);
zero :: proc(data: rawptr, len: int) -> rawptr {
return __mem_zero(data, len);
}
copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
// NOTE(bill): This _must_ implemented like C's memmove
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
llvm_memmove_64bit(dst, src, len, 1, false);
return dst;
copy :: proc(dst, src: rawptr, len: int) -> rawptr {
return __mem_copy(dst, src, len);
}
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
// NOTE(bill): This _must_ implemented like C's memcpy
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
llvm_memcpy_64bit(dst, src, len, 1, false);
return dst;
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr {
return __mem_copy_non_overlapping(dst, src, len);
}
compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
// Translation of http://mgronhol.github.io/fast-strcmp/
a := slice_ptr(dst as ^byte, n);
b := slice_ptr(src as ^byte, n);
fast := n/size_of(int) + 1;
offset := (fast-1)*size_of(int);
curr_block := 0;
if n <= size_of(int) {
fast = 0;
}
la := slice_ptr(^a[0] as ^int, fast);
lb := slice_ptr(^b[0] as ^int, fast);
for _ : curr_block ..< fast {
if (la[curr_block] ~ lb[curr_block]) != 0 {
for pos : curr_block*size_of(int) ..< n {
if (a[pos] ~ b[pos]) != 0 {
return a[pos] as int - b[pos] as int;
}
}
}
}
for _ : offset ..< n {
if (a[offset] ~ b[offset]) != 0 {
return a[offset] as int - b[offset] as int;
}
}
return 0;
compare :: proc(a, b: []byte) -> int {
return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
}
kilobytes :: proc(x: int) -> int #inline { return (x) * 1024; }
megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024; }
gigabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; }
terabytes :: proc(x: int) -> int #inline { return terabytes(x) * 1024; }
gigabytes :: proc(x: int) -> int #inline { return megabytes(x) * 1024; }
terabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; }
is_power_of_two :: proc(x: int) -> bool {
if x <= 0 {
@@ -77,36 +39,38 @@ is_power_of_two :: proc(x: int) -> bool {
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
assert(is_power_of_two(align));
a := align as uint;
p := ptr as uint;
a := uint(align);
p := uint(ptr);
modulo := p & (a-1);
if modulo != 0 {
p += a - modulo;
}
return p as rawptr;
return rawptr(p);
}
Allocation_Header :: struct {
size: int;
size: int,
}
allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) {
header.size = size;
ptr := (header+1) as ^int;
ptr := ^int(header+1);
while i := 0; ptr as rawptr < data {
for i := 0; rawptr(ptr) < data; i++ {
(ptr+i)^ = -1;
i += 1;
}
}
allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
p := data as ^int;
while (p-1)^ == -1 {
if data == nil {
return nil;
}
p := ^int(data);
for (p-1)^ == -1 {
p = (p-1);
}
return (p as ^Allocation_Header)-1;
return ^Allocation_Header(p-1);
}
@@ -115,15 +79,15 @@ allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
// Custom allocators
Arena :: struct {
backing: Allocator;
offset: int;
memory: []byte;
temp_count: int;
backing: Allocator,
offset: int,
memory: []byte,
temp_count: int,
}
Arena_Temp_Memory :: struct {
arena: ^Arena;
original_count: int;
arena: ^Arena,
original_count: int,
}
@@ -132,21 +96,21 @@ Arena_Temp_Memory :: struct {
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
backing = Allocator{};
memory = data[:0];
memory = data[0..<0];
temp_count = 0;
}
init_arena_from_context :: proc(using a: ^Arena, size: int) {
backing = context.allocator;
memory = new_slice(byte, 0, size);
memory = make([]byte, size);
temp_count = 0;
}
free_arena :: proc(using a: ^Arena) {
if backing.procedure != nil {
push_allocator backing {
free(memory.data);
memory = memory[0:0];
free(memory);
memory = nil;
offset = 0;
}
}
@@ -163,18 +127,18 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
using Allocator_Mode;
arena := allocator_data as ^Arena;
arena := ^Arena(allocator_data);
match mode {
case ALLOC:
total_size := size + alignment;
if arena.offset + total_size > arena.memory.count {
if arena.offset + total_size > len(arena.memory) {
fmt.fprintln(os.stderr, "Arena out of memory");
return nil;
}
#no_bounds_check end := ^arena.memory[arena.offset];
#no_bounds_check end := &arena.memory[arena.offset];
ptr := align_forward(end, alignment);
arena.offset += total_size;
@@ -197,16 +161,16 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
tmp: Arena_Temp_Memory;
tmp.arena = a;
tmp.original_count = a.memory.count;
a.temp_count += 1;
tmp.original_count = len(a.memory);
a.temp_count++;
return tmp;
}
end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
assert(arena.memory.count >= original_count);
assert(len(arena.memory) >= original_count);
assert(arena.temp_count > 0);
arena.memory.count = original_count;
arena.temp_count -= 1;
arena.memory = arena.memory[0..<original_count];
arena.temp_count--;
}
@@ -232,8 +196,7 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
WORD_SIZE :: size_of(int);
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
using Type_Info;
match type info : type_info {
match info in type_info {
case Named:
return align_of_type_info(info.base);
case Integer:
@@ -244,27 +207,35 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
return WORD_SIZE;
case Boolean:
return 1;
case Any:
return WORD_SIZE;
case Pointer:
return WORD_SIZE;
case Maybe:
return max(align_of_type_info(info.elem), 1);
case Procedure:
return WORD_SIZE;
case Array:
return align_of_type_info(info.elem);
case Dynamic_Array:
return WORD_SIZE;
case Slice:
return WORD_SIZE;
case Vector:
size := size_of_type_info(info.elem);
count := max(prev_pow2(info.count as i64), 1) as int;
count := int(max(prev_pow2(i64(info.count)), 1));
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 Raw_Union:
return info.align;
case Enum:
return align_of_type_info(info.base);
case Map:
return align_of_type_info(info.generated_struct);
}
return 0;
@@ -278,23 +249,21 @@ align_formula :: proc(size, align: int) -> int {
size_of_type_info :: proc(type_info: ^Type_Info) -> int {
WORD_SIZE :: size_of(int);
using Type_Info;
match type info : type_info {
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 Any:
return 2*WORD_SIZE;
case String:
return 2*WORD_SIZE;
case Boolean:
return 1;
case Any:
return 2*WORD_SIZE;
case Pointer:
return WORD_SIZE;
case Maybe:
return size_of_type_info(info.elem) + 1;
case Procedure:
return WORD_SIZE;
case Array:
@@ -306,39 +275,29 @@ size_of_type_info :: proc(type_info: ^Type_Info) -> int {
align := align_of_type_info(info.elem);
alignment := align_formula(size, align);
return alignment*(count-1) + size;
case Dynamic_Array:
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
case Slice:
return 3*WORD_SIZE;
return 2*WORD_SIZE;
case Vector:
is_bool :: proc(type_info: ^Type_Info) -> bool {
match type info : type_info {
case Named:
return is_bool(info.base);
case Boolean:
return true;
}
return false;
}
count := info.count;
if count == 0 {
return 0;
}
bit_size := 8*size_of_type_info(info.elem);
if is_bool(info.elem) {
// NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
// Silly LLVM spec
bit_size = 1;
}
total_size_in_bits := bit_size * count;
total_size := (total_size_in_bits+7)/8;
return total_size;
size := size_of_type_info(info.elem);
align := align_of_type_info(info.elem);
alignment := align_formula(size, align);
return alignment*(count-1) + size;
case Struct:
return info.size;
case Union:
return info.size;
case Raw_Union:
return info.size;
case Enum:
return size_of_type_info(info.base);
case Map:
return size_of_type_info(info.generated_struct);
}
return 0;
+126 -114
View File
@@ -1,154 +1,166 @@
#foreign_system_library "opengl32" when ODIN_OS == "windows";
#foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
#foreign_system_library lib "gl" when ODIN_OS == "linux";
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
#include "opengl_constants.odin";
#import "sys/wgl.odin" when ODIN_OS == "windows";
#load "opengl_constants.odin";
Clear :: proc(mask: u32) #foreign "glClear"
ClearColor :: proc(r, g, b, a: f32) #foreign "glClearColor"
Begin :: proc(mode: i32) #foreign "glBegin"
End :: proc() #foreign "glEnd"
Finish :: proc() #foreign "glFinish"
BlendFunc :: proc(sfactor, dfactor: i32) #foreign "glBlendFunc"
Enable :: proc(cap: i32) #foreign "glEnable"
Disable :: proc(cap: i32) #foreign "glDisable"
GenTextures :: proc(count: i32, result: ^u32) #foreign "glGenTextures"
DeleteTextures:: proc(count: i32, result: ^u32) #foreign "glDeleteTextures"
TexParameteri :: proc(target, pname, param: i32) #foreign "glTexParameteri"
TexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign "glTexParameterf"
BindTexture :: proc(target: i32, texture: u32) #foreign "glBindTexture"
LoadIdentity :: proc() #foreign "glLoadIdentity"
Viewport :: proc(x, y, width, height: i32) #foreign "glViewport"
Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign "glOrtho"
Color3f :: proc(r, g, b: f32) #foreign "glColor3f"
Vertex3f :: proc(x, y, z: f32) #foreign "glVertex3f"
Clear :: proc(mask: u32) #foreign lib "glClear";
ClearColor :: proc(r, g, b, a: f32) #foreign lib "glClearColor";
Begin :: proc(mode: i32) #foreign lib "glBegin";
End :: proc() #foreign lib "glEnd";
Finish :: proc() #foreign lib "glFinish";
BlendFunc :: proc(sfactor, dfactor: i32) #foreign lib "glBlendFunc";
Enable :: proc(cap: i32) #foreign lib "glEnable";
Disable :: proc(cap: i32) #foreign lib "glDisable";
GenTextures :: proc(count: i32, result: ^u32) #foreign lib "glGenTextures";
DeleteTextures:: proc(count: i32, result: ^u32) #foreign lib "glDeleteTextures";
TexParameteri :: proc(target, pname, param: i32) #foreign lib "glTexParameteri";
TexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign lib "glTexParameterf";
BindTexture :: proc(target: i32, texture: u32) #foreign lib "glBindTexture";
LoadIdentity :: proc() #foreign lib "glLoadIdentity";
Viewport :: proc(x, y, width, height: i32) #foreign lib "glViewport";
Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign lib "glOrtho";
Color3f :: proc(r, g, b: f32) #foreign lib "glColor3f";
Vertex3f :: proc(x, y, z: f32) #foreign lib "glVertex3f";
GetError :: proc() -> i32 #foreign lib "glGetError";
GetString :: proc(name: i32) -> ^byte #foreign lib "glGetString";
GetIntegerv :: proc(name: i32, v: ^i32) #foreign lib "glGetIntegerv";
TexCoord2f :: proc(x, y: f32) #foreign lib "glTexCoord2f";
TexImage2D :: proc(target, level, internal_format,
width, height, border,
format, _type: i32, pixels: rawptr) #foreign "glTexImage2D"
GetError :: proc() -> i32 #foreign "glGetError"
GetString :: proc(name: i32) -> ^byte #foreign "glGetString"
GetIntegerv :: proc(name: i32, v: ^i32) #foreign "glGetIntegerv"
format, type: i32, pixels: rawptr) #foreign lib "glTexImage2D";
_string_data :: proc(s: string) -> ^u8 #inline { return &s[0]; }
_libgl := win32.LoadLibraryA(("opengl32.dll\x00" as string).data);
_libgl := win32.LoadLibraryA(_string_data("opengl32.dll\x00"));
GetProcAddress :: proc(name: string) -> proc() #cc_c {
assert(name[name.count-1] == 0);
res := win32.wglGetProcAddress(name.data);
if name[len(name)-1] == 0 {
name = name[0..<len(name)-1];
}
// NOTE(bill): null terminated
assert((&name[0] + len(name))^ == 0);
res := wgl.GetProcAddress(&name[0]);
if res == nil {
res = win32.GetProcAddress(_libgl, name.data);
res = win32.GetProcAddress(_libgl, &name[0]);
}
return res;
}
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
BindBuffer: proc(target: i32, buffer: u32) #cc_c;
BindVertexArray: proc(buffer: 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;
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;
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;
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;
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;
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: ^^byte, 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;
CreateShader: proc(shader_type: i32) -> u32 #cc_c;
ShaderSource: proc(shader: u32, count: u32, str: ^^byte, 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: ^byte) #cc_c;
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte) #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: ^byte) #cc_c;
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^byte) #cc_c;
ActiveTexture: proc(texture: i32) #cc_c;
GenerateMipmap: proc(target: i32) #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;
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;
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: ^byte) -> i32 #cc_c;
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
init :: proc() {
set_proc_address :: proc(p: rawptr, name: string) #inline { (p as ^(proc() #cc_c))^ = GetProcAddress(name); }
set_proc_address :: proc(p: rawptr, name: string) #inline {
x := ^(proc() #cc_c)(p);
x^ = GetProcAddress(name);
}
set_proc_address(^GenBuffers, "glGenBuffers\x00");
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
set_proc_address(^GenSamplers, "glGenSamplers\x00");
set_proc_address(^BindBuffer, "glBindBuffer\x00");
set_proc_address(^BindSampler, "glBindSampler\x00");
set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
set_proc_address(^BufferData, "glBufferData\x00");
set_proc_address(^BufferSubData, "glBufferSubData\x00");
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(&BufferData, "glBufferData\x00");
set_proc_address(&BufferSubData, "glBufferSubData\x00");
set_proc_address(^DrawArrays, "glDrawArrays\x00");
set_proc_address(^DrawElements, "glDrawElements\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(&MapBuffer, "glMapBuffer\x00");
set_proc_address(&UnmapBuffer, "glUnmapBuffer\x00");
set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00");
set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\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(&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(&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(&ActiveTexture, "glActiveTexture\x00");
set_proc_address(&GenerateMipmap, "glGenerateMipmap\x00");
set_proc_address(^Uniform1i, "glUniform1i\x00");
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00");
set_proc_address(&Uniform1i, "glUniform1i\x00");
set_proc_address(&UniformMatrix4fv, "glUniformMatrix4fv\x00");
set_proc_address(^GetUniformLocation, "glGetUniformLocation\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");
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");
}
+3 -2
View File
@@ -1,2 +1,3 @@
#include "os_windows.odin" when ODIN_OS == "windows"
#load "os_windows.odin" when ODIN_OS == "windows";
#load "os_x.odin" when ODIN_OS == "osx";
#load "os_linux.odin" when ODIN_OS == "linux";
+303
View File
@@ -0,0 +1,303 @@
#import "fmt.odin";
#import "strings.odin";
Handle :: i32;
File_Time :: u64;
Errno :: i32;
// INVALID_HANDLE: Handle : -1;
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;
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
immutable args := _alloc_command_line_arguments();
_File_Time :: 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.
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: _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,
serial_numbe: u64, // File serial number...? Maybe.
_reserve4: i64,
};
// File type
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
S_ISLNK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFLNK; }
S_ISREG :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFREG; }
S_ISDIR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFDIR; }
S_ISCHR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFCHR; }
S_ISBLK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFBLK; }
S_ISFIFO :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFIFO; }
S_ISSOCK :: proc(m: u32) -> bool #inline {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_system_library dl "dl";
#foreign_system_library libc "c";
_unix_open :: proc(path: ^u8, mode: int) -> Handle #foreign libc "open";
_unix_close :: proc(fd: Handle) -> i32 #foreign libc "close";
_unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int #foreign libc "read";
_unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int #foreign libc "write";
_unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 #foreign libc "lseek64";
_unix_gettid :: proc() -> u64 #foreign libc "gettid";
_unix_stat :: proc(path: ^u8, stat: ^Stat) -> i32 #foreign libc "stat";
_unix_access :: proc(path: ^u8, mask: int) -> i32 #foreign libc "access";
_unix_malloc :: proc(size: int) -> rawptr #foreign libc "malloc";
_unix_free :: proc(ptr: rawptr) #foreign libc "free";
_unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #foreign libc "realloc";
_unix_getenv :: proc(^u8) -> ^u8 #foreign libc "getenv";
_unix_exit :: proc(status: int) #foreign libc "exit";
_unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #foreign dl "dlopen";
_unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #foreign dl "dlsym";
_unix_dlclose :: proc(handle: rawptr) -> int #foreign dl "dlclose";
_unix_dlerror :: proc() -> ^u8 #foreign dl "dlerror";
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
cstr := strings.new_c_string(path);
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?
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
return open_simple(path, mode);
}
close :: proc(fd: Handle) {
_unix_close(fd);
}
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
sz := _unix_read(fd, &data[0], len(data));
return sz, 0;
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
sz := _unix_write(fd, &data[0], len(data));
return sz, 0;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
res := _unix_seek(fd, offset, i32(whence));
return res, 0;
}
// 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 {}
*/
stat :: proc(path: string) -> (Stat, int) #inline {
s: Stat;
cstr := strings.new_c_string(path);
defer free(cstr);
ret_int := _unix_stat(cstr, &s);
return s, int(ret_int);
}
access :: proc(path: string, mask: int) -> bool #inline {
cstr := strings.new_c_string(path);
defer free(cstr);
return _unix_access(cstr, mask) == 0;
}
read_entire_file :: proc(name: string) -> ([]byte, bool) {
fd: Handle;
err: Errno;
size: i64;
fd, err = open_simple(name, O_RDONLY);
if(err != 0) {
fmt.println("Failed to open file.");
return nil, false;
}
defer close(fd);
// We have a file
size, err = seek(fd, 0, SEEK_END);
if(err != 0) {
fmt.println("Failed to seek to end of file.");
return nil, false;
}
_, err = seek(fd, 0, SEEK_SET);
if(err != 0) {
fmt.println("Failed to seek to beginning of file.");
return nil, false;
}
// We have a file size!
data := make([]u8, size+1);
if data == nil {
fmt.println("Failed to allocate file buffer.");
return nil, false;
}
read(fd, data);
data[size] = 0;
return data, true;
}
heap_alloc :: proc(size: int) -> rawptr {
assert(size > 0);
return _unix_malloc(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.new_c_string(name);
cstr: ^u8 = _unix_getenv(path_str);
free(path_str);
if(cstr == nil) {
return "", false;
}
return strings.to_odin_string(cstr), true;
}
exit :: proc(code: int) {
_unix_exit(code);
}
current_thread_id :: proc() -> int {
// return int(_unix_gettid());
return 0;
}
dlopen :: proc(filename: string, flags: int) -> rawptr #inline {
cstr := strings.new_c_string(filename);
handle := _unix_dlopen(cstr, flags);
free(cstr);
return handle;
}
dlsym :: proc(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
assert(handle != nil);
cstr := strings.new_c_string(symbol);
proc_handle := _unix_dlsym(handle, cstr);
free(cstr);
return proc_handle;
}
dlclose :: proc(handle: rawptr) -> bool #inline {
assert(handle != nil);
return _unix_dlclose(handle) == 0;
}
dlerror :: proc() -> string {
return strings.to_odin_string(_unix_dlerror());
}
_alloc_command_line_arguments :: proc() -> []string {
// TODO(bill):
return nil;
}
+191 -110
View File
@@ -1,12 +1,11 @@
#import win32 "sys/windows.odin";
#import "fmt.odin";
#import fmt "fmt.odin";
Handle :: uint;
Handle :: int;
File_Time :: u64;
Error :: int;
Errno :: int;
INVALID_HANDLE: Handle : ~(0 as Handle);
INVALID_HANDLE: Handle : -1;
O_RDONLY :: 0x00000;
@@ -22,132 +21,142 @@ O_SYNC :: 0x01000;
O_ASYNC :: 0x02000;
O_CLOEXEC :: 0x80000;
ERROR_NONE: Error : 0;
ERROR_FILE_NOT_FOUND: Error : 2;
ERROR_PATH_NOT_FOUND: Error : 3;
ERROR_ACCESS_DENIED: Error : 5;
ERROR_NO_MORE_FILES: Error : 18;
ERROR_HANDLE_EOF: Error : 38;
ERROR_NETNAME_DELETED: Error : 64;
ERROR_FILE_EXISTS: Error : 80;
ERROR_BROKEN_PIPE: Error : 109;
ERROR_BUFFER_OVERFLOW: Error : 111;
ERROR_INSUFFICIENT_BUFFER: Error : 122;
ERROR_MOD_NOT_FOUND: Error : 126;
ERROR_PROC_NOT_FOUND: Error : 127;
ERROR_DIR_NOT_EMPTY: Error : 145;
ERROR_ALREADY_EXISTS: Error : 183;
ERROR_ENVVAR_NOT_FOUND: Error : 203;
ERROR_MORE_DATA: Error : 234;
ERROR_OPERATION_ABORTED: Error : 995;
ERROR_IO_PENDING: Error : 997;
ERROR_NOT_FOUND: Error : 1168;
ERROR_PRIVILEGE_NOT_HELD: Error : 1314;
WSAEACCES: Error : 10013;
WSAECONNRESET: Error : 10054;
ERROR_NONE: Errno : 0;
ERROR_FILE_NOT_FOUND: Errno : 2;
ERROR_PATH_NOT_FOUND: Errno : 3;
ERROR_ACCESS_DENIED: Errno : 5;
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: Error : 1<<29 + 0;
ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
// "Argv" arguments converted to Odin strings
immutable args := _alloc_command_line_arguments();
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Error) {
using win32;
if path.count == 0 {
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
if len(path) == 0 {
return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
}
access: u32;
match mode & (O_RDONLY|O_WRONLY|O_RDWR) {
case O_RDONLY: access = FILE_GENERIC_READ;
case O_WRONLY: access = FILE_GENERIC_WRITE;
case O_RDWR: access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
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 |= FILE_GENERIC_WRITE;
access |= win32.FILE_GENERIC_WRITE;
}
if mode&O_APPEND != 0 {
access &~= FILE_GENERIC_WRITE;
access |= FILE_APPEND_DATA;
access &~= win32.FILE_GENERIC_WRITE;
access |= win32.FILE_APPEND_DATA;
}
share_mode := (FILE_SHARE_READ|FILE_SHARE_WRITE) as u32;
sa: ^SECURITY_ATTRIBUTES = nil;
sa_inherit := SECURITY_ATTRIBUTES{length = size_of(SECURITY_ATTRIBUTES), inherit_handle = 1};
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 = 1};
if mode&O_CLOEXEC == 0 {
sa = ^sa_inherit;
sa = &sa_inherit;
}
create_mode: u32;
match {
case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
create_mode = CREATE_NEW;
create_mode = win32.CREATE_NEW;
case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
create_mode = CREATE_ALWAYS;
create_mode = win32.CREATE_ALWAYS;
case mode&O_CREAT == O_CREAT:
create_mode = OPEN_ALWAYS;
create_mode = win32.OPEN_ALWAYS;
case mode&O_TRUNC == O_TRUNC:
create_mode = TRUNCATE_EXISTING;
create_mode = win32.TRUNCATE_EXISTING;
default:
create_mode = OPEN_EXISTING;
create_mode = win32.OPEN_EXISTING;
}
buf: [300]byte;
copy(buf[:], path as []byte);
copy(buf[..], []byte(path));
handle := CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil) as Handle;
if handle == INVALID_HANDLE {
handle := Handle(win32.CreateFileA(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
if handle != INVALID_HANDLE {
return handle, ERROR_NONE;
}
err := GetLastError();
return INVALID_HANDLE, err as Error;
err := win32.GetLastError();
return INVALID_HANDLE, Errno(err);
}
close :: proc(fd: Handle) {
win32.CloseHandle(fd as win32.HANDLE);
win32.CloseHandle(win32.Handle(fd));
}
write :: proc(fd: Handle, data: []byte) -> (int, Error) {
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
return write(fd, []byte(str));
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
}
bytes_written: i32;
e := win32.WriteFile(fd as win32.HANDLE, data.data, data.count as i32, ^bytes_written, nil);
if e != 0 {
return 0, e as Error;
}
return bytes_written as int, ERROR_NONE;
}
read :: proc(fd: Handle, data: []byte) -> (int, Error) {
bytes_read: i32;
e := win32.ReadFile(fd as win32.HANDLE, data.data, data.count as u32, ^bytes_read, nil);
if e != win32.FALSE {
e := win32.WriteFile(win32.Handle(fd), &data[0], i32(len(data)), &bytes_written, nil);
if e == win32.FALSE {
err := win32.GetLastError();
return 0, err as Error;
return 0, Errno(err);
}
return bytes_read as int, ERROR_NONE;
return int(bytes_written), ERROR_NONE;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
using win32;
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
}
bytes_read: i32;
e := win32.ReadFile(win32.Handle(fd), &data[0], u32(len(data)), &bytes_read, nil);
if e == win32.FALSE {
err := win32.GetLastError();
return 0, Errno(err);
}
return int(bytes_read), ERROR_NONE;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
w: u32;
match whence {
case 0: w = FILE_BEGIN;
case 1: w = FILE_CURRENT;
case 2: w = FILE_END;
case 0: w = win32.FILE_BEGIN;
case 1: w = win32.FILE_CURRENT;
case 2: w = win32.FILE_END;
}
hi := (offset>>32) as i32;
lo := offset as i32;
ft := GetFileType(fd as HANDLE);
if ft == FILE_TYPE_PIPE {
hi := i32(offset>>32);
lo := i32(offset);
ft := win32.GetFileType(win32.Handle(fd));
if ft == win32.FILE_TYPE_PIPE {
return 0, ERROR_FILE_IS_PIPE;
}
dw_ptr := SetFilePointer(fd as HANDLE, lo, ^hi, w);
if dw_ptr == INVALID_SET_FILE_POINTER {
err := GetLastError();
return 0, err as Error;
dw_ptr := win32.SetFilePointer(win32.Handle(fd), lo, &hi, w);
if dw_ptr == win32.INVALID_SET_FILE_POINTER {
err := win32.GetLastError();
return 0, Errno(err);
}
return (hi as i64)<<32 + (dw_ptr as i64), ERROR_NONE;
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
}
@@ -158,9 +167,9 @@ stderr := get_std_handle(win32.STD_ERROR_HANDLE);
get_std_handle :: proc(h: int) -> Handle {
fd := win32.GetStdHandle(h as i32);
fd := win32.GetStdHandle(i32(h));
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
return fd as Handle;
return Handle(fd);
}
@@ -169,38 +178,35 @@ get_std_handle :: proc(h: int) -> Handle {
last_write_time :: proc(fd: Handle) -> File_Time {
file_info: win32.BY_HANDLE_FILE_INFORMATION;
win32.GetFileInformationByHandle(fd as win32.HANDLE, ^file_info);
lo := file_info.last_write_time.lo as File_Time;
hi := file_info.last_write_time.hi as File_Time;
file_info: win32.By_Handle_File_Information;
win32.GetFileInformationByHandle(win32.Handle(fd), &file_info);
lo := File_Time(file_info.last_write_time.lo);
hi := File_Time(file_info.last_write_time.hi);
return lo | hi << 32;
}
last_write_time_by_name :: proc(name: string) -> File_Time {
last_write_time: win32.FILETIME;
data: win32.FILE_ATTRIBUTE_DATA;
last_write_time: win32.Filetime;
data: win32.File_Attribute_Data;
buf: [1024]byte;
assert(buf.count > name.count);
assert(len(buf) > len(name));
copy(buf[:], name as []byte);
copy(buf[..], []byte(name));
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
if win32.GetFileAttributesExA(&buf[0], win32.GetFileExInfoStandard, &data) != 0 {
last_write_time = data.last_write_time;
}
l := last_write_time.lo as File_Time;
h := last_write_time.hi as File_Time;
l := File_Time(last_write_time.lo);
h := File_Time(last_write_time.hi);
return l | h << 32;
}
read_entire_file :: proc(name: string) -> ([]byte, bool) {
buf: [300]byte;
copy(buf[:], name as []byte);
copy(buf[..], []byte(name));
fd, err := open(name, O_RDONLY, 0);
if err != ERROR_NONE {
@@ -209,36 +215,39 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
defer close(fd);
length: i64;
file_size_ok := win32.GetFileSizeEx(fd as win32.HANDLE, ^length) != 0;
if !file_size_ok {
if ok := win32.GetFileSizeEx(win32.Handle(fd), &length) != 0; !ok {
return nil, false;
}
data := new_slice(u8, length);
if data.data == nil {
if length == 0 {
return nil, true;
}
data := make([]byte, length);
if data == nil {
return nil, false;
}
single_read_length: i32;
total_read: i64;
while total_read < length {
for total_read < length {
remaining := length - total_read;
to_read: u32;
MAX :: 1<<32-1;
if remaining <= MAX {
to_read = remaining as u32;
to_read = u32(remaining);
} else {
to_read = MAX;
}
win32.ReadFile(fd as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil);
win32.ReadFile(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
if single_read_length <= 0 {
free(data.data);
free(data);
return nil, false;
}
total_read += single_read_length as i64;
total_read += i64(single_read_length);
}
return data, true;
@@ -250,23 +259,95 @@ heap_alloc :: proc(size: int) -> rawptr {
return win32.HeapAlloc(win32.GetProcessHeap(), 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 {
return heap_alloc(new_size);
}
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
}
heap_free :: proc(ptr: rawptr) {
if ptr == nil {
return;
}
win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
}
exit :: proc(code: int) {
win32.ExitProcess(code as u32);
win32.ExitProcess(u32(code));
}
current_thread_id :: proc() -> int {
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
return GetCurrentThreadId() as int;
return int(win32.GetCurrentThreadId());
}
_alloc_command_line_arguments :: proc() -> []string {
alloc_ucs2_to_utf8 :: proc(wstr: ^u16) -> string {
wstr_len := 0;
for (wstr+wstr_len)^ != 0 {
wstr_len++;
}
len := 2*wstr_len-1;
buf := make([]byte, len+1);
str := slice_ptr(wstr, wstr_len+1);
i, j := 0, 0;
for str[j] != 0 {
match {
case str[j] < 0x80:
if i+1 > len {
return "";
}
buf[i] = byte(str[j]); i++;
j++;
case str[j] < 0x800:
if i+2 > len {
return "";
}
buf[i] = byte(0xc0 + (str[j]>>6)); i++;
buf[i] = byte(0x80 + (str[j]&0x3f)); i++;
j++;
case 0xd800 <= str[j] && str[j] < 0xdc00:
if i+4 > len {
return "";
}
c := rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000;
buf[i] = byte(0xf0 + (c >> 18)); i++;
buf[i] = byte(0x80 + ((c >> 12) & 0x3f)); i++;
buf[i] = byte(0x80 + ((c >> 6) & 0x3f)); i++;
buf[i] = byte(0x80 + ((c ) & 0x3f)); i++;
j += 2;
case 0xdc00 <= str[j] && str[j] < 0xe000:
return "";
default:
if i+3 > len {
return "";
}
buf[i] = 0xe0 + byte (str[j] >> 12); i++;
buf[i] = 0x80 + byte((str[j] >> 6) & 0x3f); i++;
buf[i] = 0x80 + byte((str[j] ) & 0x3f); i++;
j++;
}
}
return string(buf[0..<i]);
}
arg_count: i32;
arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count);
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;
}
+312
View File
@@ -0,0 +1,312 @@
#import "fmt.odin";
#import "strings.odin";
Handle :: i32;
File_Time :: u64;
Errno :: int;
// TODO(zangent): Find out how to make this work on x64 and x32.
AddressSize :: i64;
// INVALID_HANDLE: Handle : -1;
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;
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;
args: [dynamic]string;
FileTime :: struct #ordered {
seconds: i64,
nanoseconds: i64
}
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
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
S_ISLNK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFLNK; }
S_ISREG :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFREG; }
S_ISDIR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFDIR; }
S_ISCHR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFCHR; }
S_ISBLK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFBLK; }
S_ISFIFO :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFIFO; }
S_ISSOCK :: proc(m: u32) -> bool #inline {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_system_library dl "dl";
#foreign_system_library libc "c";
unix_open :: proc(path: ^u8, mode: int) -> Handle #foreign libc "open";
unix_close :: proc(handle: Handle) #foreign libc "close";
unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> AddressSize #foreign libc "read";
unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> AddressSize #foreign libc "write";
unix_lseek :: proc(fs: Handle, offset: AddressSize, whence: int) -> AddressSize #foreign libc "lseek";
unix_gettid :: proc() -> u64 #foreign libc "gettid";
unix_stat :: proc(path: ^u8, stat: ^Stat) -> int #foreign libc "stat";
unix_access :: proc(path: ^u8, mask: int) -> int #foreign libc "access";
unix_malloc :: proc(size: int) -> rawptr #foreign libc "malloc";
unix_free :: proc(ptr: rawptr) #foreign libc "free";
unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #foreign libc "realloc";
unix_getenv :: proc(^u8) -> ^u8 #foreign libc "getenv";
unix_exit :: proc(status: int) #foreign libc "exit";
unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #foreign dl "dlopen";
unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #foreign dl "dlsym";
unix_dlclose :: proc(handle: rawptr) -> int #foreign dl "dlclose";
unix_dlerror :: proc() -> ^u8 #foreign dl "dlerror";
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
cstr := strings.new_c_string(path);
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?
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
return open_simple(path, mode);
}
close :: proc(fd: Handle) {
unix_close(fd);
}
write :: proc(fd: Handle, data: []byte) -> (AddressSize, 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: []byte) -> (AddressSize, 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: AddressSize, whence: int) -> (AddressSize, Errno) {
assert(fd != -1);
final_offset := unix_lseek(fd, offset, whence);
if(final_offset == -1) {
return 0, 1;
}
return final_offset, 0;
}
// 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 {}
*/
stat :: proc(path: string) -> (Stat, bool) #inline {
s: Stat;
cstr := strings.new_c_string(path);
defer free(cstr);
ret_int := unix_stat(cstr, &s);
return s, ret_int==0;
}
access :: proc(path: string, mask: int) -> bool #inline {
cstr := strings.new_c_string(path);
defer free(cstr);
return unix_access(cstr, mask) == 0;
}
read_entire_file :: proc(name: string) -> ([]byte, bool) {
handle, err := open_simple(name, O_RDONLY);
if(err != 0) {
fmt.println("Failed to open file.");
return nil, false;
}
defer(close(handle));
// We have a file!
size: AddressSize;
size, err = seek(handle, 0, SEEK_END);
if(err != 0) {
fmt.println("Failed to seek to end of file.");
return nil, false;
}
_, err = seek(handle, 0, SEEK_SET);
if(err != 0) {
fmt.println("Failed to seek to beginning of file.");
return nil, false;
}
// We have a file size!
data := make([]u8, size+1);
if data == nil {
fmt.println("Failed to allocate file buffer.");
return nil, false;
}
read(handle, data);
data[size] = 0;
return data, true;
}
heap_alloc :: proc(size: int) -> rawptr #inline {
assert(size > 0);
return unix_malloc(size);
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr #inline {
return unix_realloc(ptr, new_size);
}
heap_free :: proc(ptr: rawptr) #inline {
unix_free(ptr);
}
getenv :: proc(name: string) -> (string, bool) {
path_str := strings.new_c_string(name);
cstr: ^u8 = unix_getenv(path_str);
free(path_str);
if(cstr == nil) {
return "", false;
}
return strings.to_odin_string(cstr), true;
}
exit :: proc(code: int) #inline {
unix_exit(code);
}
current_thread_id :: proc() -> int {
// return cast(int) unix_gettid();
return 0;
}
dlopen :: proc(filename: string, flags: int) -> rawptr #inline {
cstr := strings.new_c_string(filename);
handle := unix_dlopen(cstr, flags);
free(cstr);
return handle;
}
dlsym :: proc(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
assert(handle != nil);
cstr := strings.new_c_string(symbol);
proc_handle := unix_dlsym(handle, cstr);
free(cstr);
return proc_handle;
}
dlclose :: proc(handle: rawptr) -> bool #inline {
assert(handle != nil);
return unix_dlclose(handle) == 0;
}
dlerror :: proc() -> string {
return strings.to_odin_string(unix_dlerror());
}
+27
View File
@@ -0,0 +1,27 @@
Any :: struct #ordered {
data: rawptr,
type_info: ^Type_Info,
}
String :: struct #ordered {
data: ^byte,
len: int,
};
Slice :: struct #ordered {
data: rawptr,
len: int,
cap: int,
};
Dynamic_Array :: struct #ordered {
data: rawptr,
len: int,
cap: int,
allocator: Allocator,
};
Dynamic_Map :: struct #ordered {
hashes: [dynamic]int,
entries: Dynamic_Array,
};
+380
View File
@@ -0,0 +1,380 @@
#import . "decimal.odin";
#import "math.odin";
Int_Flag :: enum {
PREFIX = 1<<0,
PLUS = 1<<1,
SPACE = 1<<2,
}
parse_bool :: proc(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;
}
_digit_value :: proc(r: rune) -> (int) {
ri := int(r);
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;
}
parse_i64 :: proc(s: string, base: int) -> i64 {
result: i64;
for r in s {
v := _digit_value(r);
if v >= base {
break;
}
result *= i64(base);
result += i64(v);
}
return result;
}
parse_u64 :: proc(s: string, base: int) -> u64 {
result: u64;
for r in s {
v := _digit_value(r);
if v >= base {
break;
}
result *= u64(base);
result += u64(v);
}
return result;
}
parse_int :: proc(s: string, base: int) -> int {
return int(parse_i64(s, base));
}
parse_uint :: proc(s: string, base: int) -> uint {
return uint(parse_u64(s, base));
}
append_bool :: proc(buf: []byte, b: bool) -> string {
s := b ? "true" : "false";
append(buf, ..[]byte(s));
return string(buf);
}
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
return append_bits(buf, u, base, false, 8*size_of(uint), digits, 0);
}
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, 0);
}
itoa :: proc(buf: []byte, i: int) -> string { return append_int(buf, i64(i), 10); }
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
}
Decimal_Slice :: struct {
digits: []byte,
count: int,
decimal_point: int,
neg: bool,
}
Float_Info :: struct {
mantbits: uint,
expbits: uint,
bias: int,
}
f32_info := Float_Info{23, 8, -127};
f64_info := Float_Info{52, 11, -1023};
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte {
bits: u64;
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;
default:
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);
match exp {
case 1<<flt.expbits - 1:
s: string;
if mant != 0 {
s = "NaN";
} else if neg {
s = "-Inf";
} else {
s = "+Inf";
}
append(buf, ..[]byte(s));
return buf;
case 0: // denormalized
exp++;
default:
mant |= u64(1) << flt.mantbits;
}
exp += flt.bias;
d_: Decimal;
d := &d_;
assign(d, mant);
shift(d, exp - int(flt.mantbits));
digs: Decimal_Slice;
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};
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 = 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, prec: int, fmt: byte) -> []byte {
match fmt {
case 'f', 'F':
append(buf, neg ? '-' : '+');
// integer, padded with zeros when needed
if digs.decimal_point > 0 {
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 {
c: byte = '0';
if 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
}
c: [2]byte;
c[0] = '%';
c[1] = fmt;
append(buf, ..c[..]);
return buf;
}
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;
immutable digits := "0123456789abcdefghijklmnopqrstuvwxyz";
is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) {
neg := false;
if is_signed {
match bit_size {
case 8:
i := i8(u);
neg = i < 0;
if neg { i = -i; }
u = u64(i);
case 16:
i := i16(u);
neg = i < 0;
if neg { i = -i; }
u = u64(i);
case 32:
i := i32(u);
neg = i < 0;
if neg { i = -i; }
u = u64(i);
case 64:
i := i64(u);
neg = i < 0;
if neg { i = -i; }
u = u64(i);
default:
panic("is_integer_negative: Unknown integer size");
}
}
return u, neg;
}
append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> string {
is_pow2 :: proc(x: i64) -> bool {
if (x <= 0) {
return false;
}
return x&(x-1) == 0;
}
if base < 2 || base > MAX_BASE {
panic("strconv: illegal base passed to append_bits");
}
a: [65]byte;
i := len(a);
neg: bool;
u, neg = is_integer_negative(u, is_signed, bit_size);
for b := u64(base); u >= b; {
i--;
q := u / b;
a[i] = digits[uint(u-q*b)];
u = q;
}
i--;
a[i] = digits[uint(u)];
if flags&Int_Flag.PREFIX != 0 {
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';
default: ok = false;
}
if ok {
i--;
a[i] = '0';
}
}
if neg {
i--; a[i] = '-';
} else if flags&Int_Flag.PLUS != 0 {
i--; a[i] = '+';
} else if flags&Int_Flag.SPACE != 0 {
i--; a[i] = ' ';
}
append(buf, ..a[i..]);
return string(buf);
}
+14
View File
@@ -0,0 +1,14 @@
new_c_string :: proc(s: string) -> ^byte {
c := make([]byte, len(s)+1);
copy(c, []byte(s));
c[len(s)] = 0;
return &c[0];
}
to_odin_string :: proc(c: ^byte) -> string {
len := 0;
for (c+len)^ != 0 {
len++;
}
return string(slice_ptr(c, len));
}
+2 -91
View File
@@ -1,91 +1,2 @@
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
#import "atomic.odin";
Semaphore :: struct {
handle: win32.HANDLE;
}
Mutex :: struct {
semaphore: Semaphore;
counter: i32;
owner: i32;
recursion: i32;
}
current_thread_id :: proc() -> i32 {
return win32.GetCurrentThreadId() as i32;
}
semaphore_init :: proc(s: ^Semaphore) {
s.handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
}
semaphore_destroy :: proc(s: ^Semaphore) {
win32.CloseHandle(s.handle);
}
semaphore_post :: proc(s: ^Semaphore, count: int) {
win32.ReleaseSemaphore(s.handle, count as i32, nil);
}
semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
semaphore_wait :: proc(s: ^Semaphore) {
win32.WaitForSingleObject(s.handle, win32.INFINITE);
}
mutex_init :: proc(m: ^Mutex) {
atomic.store32(^m.counter, 0);
atomic.store32(^m.owner, current_thread_id());
semaphore_init(^m.semaphore);
m.recursion = 0;
}
mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(^m.semaphore);
}
mutex_lock :: proc(m: ^Mutex) {
thread_id := current_thread_id();
if atomic.fetch_add32(^m.counter, 1) > 0 {
if thread_id != atomic.load32(^m.owner) {
semaphore_wait(^m.semaphore);
}
}
atomic.store32(^m.owner, thread_id);
m.recursion += 1;
}
mutex_try_lock :: proc(m: ^Mutex) -> bool {
thread_id := current_thread_id();
if atomic.load32(^m.owner) == thread_id {
atomic.fetch_add32(^m.counter, 1);
} else {
expected: i32 = 0;
if atomic.load32(^m.counter) != 0 {
return false;
}
if atomic.compare_exchange32(^m.counter, expected, 1) == 0 {
return false;
}
atomic.store32(^m.owner, thread_id);
}
m.recursion += 1;
return true;
}
mutex_unlock :: proc(m: ^Mutex) {
recursion: i32;
thread_id := current_thread_id();
assert(thread_id == atomic.load32(^m.owner));
m.recursion -= 1;
recursion = m.recursion;
if recursion == 0 {
atomic.store32(^m.owner, thread_id);
}
if atomic.fetch_add32(^m.counter, -1) > 1 {
if recursion == 0 {
semaphore_release(^m.semaphore);
}
}
}
#load "sync_windows.odin" when ODIN_OS == "windows";
#load "sync_linux.odin" when ODIN_OS == "linux";
+93
View File
@@ -0,0 +1,93 @@
#import "atomics.odin";
#import "os.odin";
Semaphore :: struct {
// _handle: win32.Handle,
}
Mutex :: struct {
_semaphore: Semaphore,
_counter: i32,
_owner: i32,
_recursion: i32,
}
current_thread_id :: proc() -> i32 {
return i32(os.current_thread_id());
}
semaphore_init :: proc(s: ^Semaphore) {
// s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
}
semaphore_destroy :: proc(s: ^Semaphore) {
// win32.CloseHandle(s._handle);
}
semaphore_post :: proc(s: ^Semaphore, count: int) {
// win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
}
semaphore_release :: proc(s: ^Semaphore) #inline {
semaphore_post(s, 1);
}
semaphore_wait :: proc(s: ^Semaphore) {
// win32.WaitForSingleObject(s._handle, win32.INFINITE);
}
mutex_init :: proc(m: ^Mutex) {
atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore);
m._recursion = 0;
}
mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(&m._semaphore);
}
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++;
}
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 {
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;
}
mutex_unlock :: proc(m: ^Mutex) {
recursion: i32;
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);
}
}
}
+91
View File
@@ -0,0 +1,91 @@
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
#import "atomics.odin";
Semaphore :: struct {
_handle: win32.Handle,
}
Mutex :: struct {
_semaphore: Semaphore,
_counter: i32,
_owner: i32,
_recursion: i32,
}
current_thread_id :: proc() -> i32 {
return i32(win32.GetCurrentThreadId());
}
semaphore_init :: proc(s: ^Semaphore) {
s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
}
semaphore_destroy :: proc(s: ^Semaphore) {
win32.CloseHandle(s._handle);
}
semaphore_post :: proc(s: ^Semaphore, count: int) {
win32.ReleaseSemaphore(s._handle, i32(count), nil);
}
semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
semaphore_wait :: proc(s: ^Semaphore) {
win32.WaitForSingleObject(s._handle, win32.INFINITE);
}
mutex_init :: proc(m: ^Mutex) {
atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore);
m._recursion = 0;
}
mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(&m._semaphore);
}
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++;
}
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 {
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;
}
mutex_unlock :: proc(m: ^Mutex) {
recursion: i32;
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);
}
}
}
+82
View File
@@ -0,0 +1,82 @@
#foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
#import . "windows.odin";
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;
Hglrc :: Handle;
Color_Ref :: u32;
Layer_Plane_Descriptor :: struct #ordered {
size: u16,
version: u16,
flags: u32,
pixel_type: byte,
color_bits: byte,
red_bits: byte,
red_shift: byte,
green_bits: byte,
green_shift: byte,
blue_bits: byte,
blue_shift: byte,
alpha_bits: byte,
alpha_shift: byte,
accum_bits: byte,
accum_red_bits: byte,
accum_green_bits: byte,
accum_blue_bits: byte,
accum_alpha_bits: byte,
depth_bits: byte,
stencil_bits: byte,
aux_buffers: byte,
layer_type: byte,
reserved: byte,
transparent: Color_Ref,
}
Point_Float :: struct #ordered {
x, y: f32,
}
Glyph_Metrics_Float :: struct #ordered {
black_box_x: f32,
black_box_y: f32,
glyph_origin: Point_Float,
cell_inc_x: f32,
cell_inc_y: f32,
}
CreateContextAttribsARB_Type :: #type proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
ChoosePixelFormatARB_Type :: #type proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c;
SwapIntervalEXT_Type :: #type proc(interval : i32) -> bool #cc_c;
GetExtensionsStringARB_Type :: #type proc(Hdc) -> ^byte #cc_c;
CreateContextAttribsARB: CreateContextAttribsARB_Type;
ChoosePixelFormatARB: ChoosePixelFormatARB_Type;
SwapIntervalEXT: SwapIntervalEXT_Type;
GetExtensionsStringARB: GetExtensionsStringARB_Type;
CreateContext :: proc(hdc: Hdc) -> Hglrc #foreign opengl32 "wglCreateContext";
MakeCurrent :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool #foreign opengl32 "wglMakeCurrent";
GetProcAddress :: proc(c_str: ^u8) -> Proc #foreign opengl32 "wglGetProcAddress";
DeleteContext :: proc(hglrc: Hglrc) -> Bool #foreign opengl32 "wglDeleteContext";
CopyContext :: proc(src, dst: Hglrc, mask: u32) -> Bool #foreign opengl32 "wglCopyContext";
CreateLayerContext :: proc(hdc: Hdc, layer_plane: i32) -> Hglrc #foreign opengl32 "wglCreateLayerContext";
DescribeLayerPlane :: proc(hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^Layer_Plane_Descriptor) -> Bool #foreign opengl32 "wglDescribeLayerPlane";
GetCurrentContext :: proc() -> Hglrc #foreign opengl32 "wglGetCurrentContext";
GetCurrentDC :: proc() -> Hdc #foreign opengl32 "wglGetCurrentDC";
GetLayerPaletteEntries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #foreign opengl32 "wglGetLayerPaletteEntries";
RealizeLayerPalette :: proc(hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool #foreign opengl32 "wglRealizeLayerPalette";
SetLayerPaletteEntries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #foreign opengl32 "wglSetLayerPaletteEntries";
ShareLists :: proc(hglrc1, hglrc2: Hglrc) -> Bool #foreign opengl32 "wglShareLists";
SwapLayerBuffers :: proc(hdc: Hdc, planes: u32) -> Bool #foreign opengl32 "wglSwapLayerBuffers";
UseFontBitmaps :: proc(hdc: Hdc, first, count, list_base: u32) -> Bool #foreign opengl32 "wglUseFontBitmaps";
UseFontOutlines :: proc(hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_Metrics_Float) -> Bool #foreign opengl32 "wglUseFontOutlines";
+255 -183
View File
@@ -1,28 +1,30 @@
#foreign_system_library "user32" when ODIN_OS == "windows";
#foreign_system_library "gdi32" when ODIN_OS == "windows";
#foreign_system_library "kernel32.lib" when ODIN_OS == "windows";
#foreign_system_library "user32.lib" when ODIN_OS == "windows";
#foreign_system_library "gdi32.lib" when ODIN_OS == "windows";
#foreign_system_library "winmm.lib" when ODIN_OS == "windows";
#foreign_system_library "shell32.lib" when ODIN_OS == "windows";
HANDLE :: rawptr;
HWND :: HANDLE;
HDC :: HANDLE;
HINSTANCE :: HANDLE;
HICON :: HANDLE;
HCURSOR :: HANDLE;
HMENU :: HANDLE;
HBRUSH :: HANDLE;
HGDIOBJ :: HANDLE;
HMODULE :: HANDLE;
WPARAM :: uint;
LPARAM :: int;
LRESULT :: int;
ATOM :: i16;
BOOL :: i32;
WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT;
Handle :: rawptr;
Hwnd :: Handle;
Hdc :: Handle;
Hinstance :: Handle;
Hicon :: Handle;
Hcursor :: Handle;
Hmenu :: Handle;
Hbrush :: Handle;
Hgdiobj :: Handle;
Hmodule :: Handle;
Wparam :: uint;
Lparam :: int;
Lresult :: int;
Bool :: i32;
Wnd_Proc :: #type proc(Hwnd, u32, Wparam, Lparam) -> Lresult #cc_c;
INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE;
INVALID_HANDLE :: Handle(~int(0));
FALSE: BOOL : 0;
TRUE: BOOL : 1;
FALSE: Bool : 0;
TRUE: Bool : 1;
CS_VREDRAW :: 0x0001;
CS_HREDRAW :: 0x0002;
@@ -38,15 +40,23 @@ WS_CAPTION :: 0x00C00000;
WS_VISIBLE :: 0x10000000;
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
WM_DESTROY :: 0x0002;
WM_CLOSE :: 0x0010;
WM_QUIT :: 0x0012;
WM_KEYDOWN :: 0x0100;
WM_KEYUP :: 0x0101;
WM_DESTROY :: 0x0002;
WM_SIZE :: 0x0005;
WM_CLOSE :: 0x0010;
WM_ACTIVATEAPP :: 0x001C;
WM_QUIT :: 0x0012;
WM_KEYDOWN :: 0x0100;
WM_KEYUP :: 0x0101;
WM_SIZING :: 0x0214;
WM_MOUSEWHEEL :: 0x020A;
WM_SYSKEYDOWN :: 0x0104;
WM_WINDOWPOSCHANGED :: 0x0047;
WM_SETCURSOR :: 0x0020;
WM_CHAR :: 0x0102;
PM_REMOVE :: 1;
COLOR_BACKGROUND :: 1 as HBRUSH;
COLOR_BACKGROUND :: Hbrush(int(1));
BLACK_BRUSH :: 4;
SM_CXSCREEN :: 0;
@@ -55,62 +65,68 @@ SM_CYSCREEN :: 1;
SW_SHOW :: 5;
POINT :: struct #ordered {
x, y: i32;
Point :: struct #ordered {
x, y: i32,
}
WNDCLASSEXA :: struct #ordered {
size, style: u32;
wnd_proc: WNDPROC;
cls_extra, wnd_extra: i32;
instance: HINSTANCE;
icon: HICON;
cursor: HCURSOR;
background: HBRUSH;
menu_name, class_name: ^u8;
sm: HICON;
WndClassExA :: struct #ordered {
size, style: u32,
wnd_proc: Wnd_Proc,
cls_extra, wnd_extra: i32,
instance: Hinstance,
icon: Hicon,
cursor: Hcursor,
background: Hbrush,
menu_name, class_name: ^u8,
sm: Hicon,
}
MSG :: struct #ordered {
hwnd: HWND;
message: u32;
wparam: WPARAM;
lparam: LPARAM;
time: u32;
pt: POINT;
Msg :: struct #ordered {
hwnd: Hwnd,
message: u32,
wparam: Wparam,
lparam: Lparam,
time: u32,
pt: Point,
}
RECT :: struct #ordered {
left: i32;
top: i32;
right: i32;
bottom: i32;
Rect :: struct #ordered {
left: i32,
top: i32,
right: i32,
bottom: i32,
}
FILETIME :: struct #ordered {
lo, hi: u32;
Filetime :: struct #ordered {
lo, hi: u32,
}
BY_HANDLE_FILE_INFORMATION :: struct #ordered {
file_attributes: u32;
Systemtime :: struct #ordered {
year, month: u16,
day_of_week, day: u16,
hour, minute, second, millisecond: u16,
}
By_Handle_File_Information :: struct #ordered {
file_attributes: u32,
creation_time,
last_access_time,
last_write_time: FILETIME;
last_write_time: Filetime,
volume_serial_number,
file_size_high,
file_size_low,
number_of_links,
file_index_high,
file_index_low: u32;
file_index_low: u32,
}
FILE_ATTRIBUTE_DATA :: struct #ordered {
file_attributes: u32;
File_Attribute_Data :: struct #ordered {
file_attributes: u32,
creation_time,
last_access_time,
last_write_time: FILETIME;
last_write_time: Filetime,
file_size_high,
file_size_low: u32;
file_size_low: u32,
}
GET_FILEEX_INFO_LEVELS :: i32;
@@ -118,73 +134,84 @@ GET_FILEEX_INFO_LEVELS :: i32;
GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0;
GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1;
GetLastError :: proc() -> i32 #foreign #dll_import
ExitProcess :: proc(exit_code: u32) #foreign #dll_import
GetDesktopWindow :: proc() -> HWND #foreign #dll_import
GetCursorPos :: proc(p: ^POINT) -> i32 #foreign #dll_import
ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign #dll_import
GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign #dll_import
GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign #dll_import
PostQuitMessage :: proc(exit_code: i32) #foreign #dll_import
SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign #dll_import
GetLastError :: proc() -> i32 #foreign kernel32;
ExitProcess :: proc(exit_code: u32) #foreign kernel32;
GetDesktopWindow :: proc() -> Hwnd #foreign user32;
GetCursorPos :: proc(p: ^Point) -> i32 #foreign user32;
ScreenToClient :: proc(h: Hwnd, p: ^Point) -> i32 #foreign user32;
GetModuleHandleA :: proc(module_name: ^u8) -> Hinstance #foreign kernel32;
GetStockObject :: proc(fn_object: i32) -> Hgdiobj #foreign gdi32;
PostQuitMessage :: proc(exit_code: i32) #foreign user32;
SetWindowTextA :: proc(hwnd: Hwnd, c_string: ^u8) -> Bool #foreign user32;
QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign #dll_import
QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign #dll_import
QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign kernel32;
QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign kernel32;
Sleep :: proc(ms: i32) -> i32 #foreign #dll_import
Sleep :: proc(ms: i32) -> i32 #foreign kernel32;
OutputDebugStringA :: proc(c_str: ^u8) #foreign #dll_import
OutputDebugStringA :: proc(c_str: ^u8) #foreign kernel32;
RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign #dll_import
RegisterClassExA :: proc(wc: ^WndClassExA) -> i16 #foreign user32;
CreateWindowExA :: proc(ex_style: u32,
class_name, title: ^u8,
style: u32,
x, y, w, h: i32,
parent: HWND, menu: HMENU, instance: HINSTANCE,
param: rawptr) -> HWND #foreign #dll_import
parent: Hwnd, menu: Hmenu, instance: Hinstance,
param: rawptr) -> Hwnd #foreign user32;
ShowWindow :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign #dll_import
TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign #dll_import
DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign #dll_import
UpdateWindow :: proc(hwnd: HWND) -> BOOL #foreign #dll_import
PeekMessageA :: proc(msg: ^MSG, hwnd: HWND,
msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign #dll_import
ShowWindow :: proc(hwnd: Hwnd, cmd_show: i32) -> Bool #foreign user32;
TranslateMessage :: proc(msg: ^Msg) -> Bool #foreign user32;
DispatchMessageA :: proc(msg: ^Msg) -> Lresult #foreign user32;
UpdateWindow :: proc(hwnd: Hwnd) -> Bool #foreign user32;
PeekMessageA :: proc(msg: ^Msg, hwnd: Hwnd,
msg_filter_min, msg_filter_max, remove_msg: u32) -> Bool #foreign user32;
DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign #dll_import
DefWindowProcA :: proc(hwnd: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Lresult #foreign user32;
AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign #dll_import
GetActiveWindow :: proc() -> HWND #foreign #dll_import
AdjustWindowRect :: proc(rect: ^Rect, style: u32, menu: Bool) -> Bool #foreign user32;
GetActiveWindow :: proc() -> Hwnd #foreign user32;
DestroyWindow :: proc(wnd: Hwnd) -> Bool #foreign user32;
DescribePixelFormat :: proc(dc: Hdc, pixel_format: i32, bytes : u32, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32;
GetQueryPerformanceFrequency :: proc() -> i64 {
r: i64;
QueryPerformanceFrequency(^r);
QueryPerformanceFrequency(&r);
return r;
}
GetCommandLineA :: proc() -> ^u8 #foreign #dll_import
GetSystemMetrics :: proc(index: i32) -> i32 #foreign #dll_import
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
GetCommandLineA :: proc() -> ^u8 #foreign kernel32;
GetCommandLineW :: proc() -> ^u16 #foreign kernel32;
GetSystemMetrics :: proc(index: i32) -> i32 #foreign kernel32;
GetCurrentThreadId :: proc() -> u32 #foreign kernel32;
CommandLineToArgvW :: proc(cmd_list: ^u16, num_args: ^i32) -> ^^u16 #foreign shell32;
timeGetTime :: proc() -> u32 #foreign winmm;
GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^Filetime) #foreign kernel32;
FileTimeToLocalFileTime :: proc(file_time: ^Filetime, local_file_time: ^Filetime) -> Bool #foreign kernel32;
FileTimeToSystemTime :: proc(file_time: ^Filetime, system_time: ^Systemtime) -> Bool #foreign kernel32;
SystemTimeToFileTime :: proc(system_time: ^Systemtime, file_time: ^Filetime) -> Bool #foreign kernel32;
// File Stuff
CloseHandle :: proc(h: HANDLE) -> i32 #foreign #dll_import
GetStdHandle :: proc(h: i32) -> HANDLE #foreign #dll_import
CloseHandle :: proc(h: Handle) -> i32 #foreign kernel32;
GetStdHandle :: proc(h: i32) -> Handle #foreign kernel32;
CreateFileA :: proc(filename: ^u8, desired_access, share_mode: u32,
security: rawptr,
creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign #dll_import
ReadFile :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign #dll_import
WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> i32 #foreign #dll_import
creation, flags_and_attribs: u32, template_file: Handle) -> Handle #foreign kernel32;
ReadFile :: proc(h: Handle, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> Bool #foreign kernel32;
WriteFile :: proc(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool #foreign kernel32;
GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign #dll_import
GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign #dll_import
GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign #dll_import
GetFileSizeEx :: proc(file_handle: Handle, file_size: ^i64) -> Bool #foreign kernel32;
GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool #foreign kernel32;
GetFileInformationByHandle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool #foreign kernel32;
GetFileType :: proc(file_handle: HANDLE) -> u32 #foreign #dll_import
SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign #dll_import
GetFileType :: proc(file_handle: Handle) -> u32 #foreign kernel32;
SetFilePointer :: proc(file_handle: Handle, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign kernel32;
SetHandleInformation :: proc(obj: HANDLE, mask, flags: u32) -> BOOL #foreign #dll_import
SetHandleInformation :: proc(obj: Handle, mask, flags: u32) -> Bool #foreign kernel32;
HANDLE_FLAG_INHERIT :: 1;
HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
@@ -217,13 +244,13 @@ TRUNCATE_EXISTING :: 5;
FILE_ATTRIBUTE_READONLY :: 0x00000001;
FILE_ATTRIBUTE_HIDDEN :: 0x00000002;
FILE_ATTRIBUTE_SYSTEM :: 0x00000004;
FILE_ATTRIBUTE_DIRECTORY :: 0x00000010;
FILE_ATTRIBUTE_DIRectORY :: 0x00000010;
FILE_ATTRIBUTE_ARCHIVE :: 0x00000020;
FILE_ATTRIBUTE_DEVICE :: 0x00000040;
FILE_ATTRIBUTE_NORMAL :: 0x00000080;
FILE_ATTRIBUTE_TEMPORARY :: 0x00000100;
FILE_ATTRIBUTE_SPARSE_FILE :: 0x00000200;
FILE_ATTRIBUTE_REPARSE_POINT :: 0x00000400;
FILE_ATTRIBUTE_REPARSE_Point :: 0x00000400;
FILE_ATTRIBUTE_COMPRESSED :: 0x00000800;
FILE_ATTRIBUTE_OFFLINE :: 0x00001000;
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED :: 0x00002000;
@@ -233,95 +260,154 @@ FILE_TYPE_DISK :: 0x0001;
FILE_TYPE_CHAR :: 0x0002;
FILE_TYPE_PIPE :: 0x0003;
INVALID_SET_FILE_POINTER :: ~(0 as u32);
INVALID_SET_FILE_POINTER :: ~u32(0);
HeapAlloc :: proc (h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign #dll_import
HeapReAlloc :: proc (h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign #dll_import
HeapFree :: proc (h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign #dll_import
GetProcessHeap :: proc () -> HANDLE #foreign #dll_import
HeapAlloc :: proc (h: Handle, flags: u32, bytes: int) -> rawptr #foreign kernel32;
HeapReAlloc :: proc (h: Handle, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign kernel32;
HeapFree :: proc (h: Handle, flags: u32, memory: rawptr) -> Bool #foreign kernel32;
GetProcessHeap :: proc () -> Handle #foreign kernel32;
HEAP_ZERO_MEMORY :: 0x00000008;
// Synchronization
SECURITY_ATTRIBUTES :: struct #ordered {
length: u32;
security_descriptor: rawptr;
inherit_handle: BOOL;
Security_Attributes :: struct #ordered {
length: u32,
security_descriptor: rawptr,
inherit_handle: Bool,
}
INFINITE :: 0xffffffff;
CreateSemaphoreA :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign #dll_import
ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign #dll_import
WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign #dll_import
CreateSemaphoreA :: proc(attributes: ^Security_Attributes, initial_count, maximum_count: i32, name: ^byte) -> Handle #foreign kernel32;
ReleaseSemaphore :: proc(semaphore: Handle, release_count: i32, previous_count: ^i32) -> Bool #foreign kernel32;
WaitForSingleObject :: proc(handle: Handle, milliseconds: u32) -> u32 #foreign kernel32;
InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign
InterlockedExchange :: proc(dst: ^i32, desired: i32) -> i32 #foreign
InterlockedExchangeAdd :: proc(dst: ^i32, desired: i32) -> i32 #foreign
InterlockedAnd :: proc(dst: ^i32, desired: i32) -> i32 #foreign
InterlockedOr :: proc(dst: ^i32, desired: i32) -> i32 #foreign
InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign kernel32;
InterlockedExchange :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
InterlockedExchangeAdd :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
InterlockedAnd :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
InterlockedOr :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
InterlockedCompareExchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #foreign
InterlockedExchange64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
InterlockedCompareExchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #foreign kernel32;
InterlockedExchange64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
_mm_pause :: proc() #foreign
ReadWriteBarrier :: proc() #foreign
WriteBarrier :: proc() #foreign
ReadBarrier :: proc() #foreign
mm_pause :: proc() #foreign kernel32 "_mm_pause";
ReadWriteBarrier :: proc() #foreign kernel32;
WriteBarrier :: proc() #foreign kernel32;
ReadBarrier :: proc() #foreign kernel32;
// GDI
BITMAPINFOHEADER :: struct #ordered {
size: u32;
width, height: i32;
planes, bit_count: i16;
compression: u32;
size_image: u32;
x_pels_per_meter: i32;
y_pels_per_meter: i32;
clr_used: u32;
clr_important: u32;
Hmonitor :: Handle;
GWL_STYLE :: -16;
Hwnd_TOP :: Hwnd(uint(0));
MONITOR_DEFAULTTONULL :: 0x00000000;
MONITOR_DEFAULTTOPRIMARY :: 0x00000001;
MONITOR_DEFAULTTONEAREST :: 0x00000002;
SWP_FRAMECHANGED :: 0x0020;
SWP_NOOWNERZORDER :: 0x0200;
SWP_NOZORDER :: 0x0004;
SWP_NOSIZE :: 0x0001;
SWP_NOMOVE :: 0x0002;
Monitor_Info :: struct #ordered {
size: u32,
monitor: Rect,
work: Rect,
flags: u32,
}
BITMAPINFO :: struct #ordered {
using header: BITMAPINFOHEADER;
colors: [1]RGBQUAD;
Window_Placement :: struct #ordered {
length: u32,
flags: u32,
show_cmd: u32,
min_pos: Point,
max_pos: Point,
normal_pos: Rect,
}
GetMonitorInfoA :: proc(monitor: Hmonitor, mi: ^Monitor_Info) -> Bool #foreign user32;
MonitorFromWindow :: proc(wnd: Hwnd, flags : u32) -> Hmonitor #foreign user32;
SetWindowPos :: proc(wnd: Hwnd, wndInsertAfter: Hwnd, x, y, width, height: i32, flags: u32) #foreign user32 "SetWindowPos";
GetWindowPlacement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool #foreign user32;
SetWindowPlacement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool #foreign user32;
GetWindowRect :: proc(wnd: Hwnd, rect: ^Rect) -> Bool #foreign user32;
GetWindowLongPtrA :: proc(wnd: Hwnd, index: i32) -> i64 #foreign user32;
SetWindowLongPtrA :: proc(wnd: Hwnd, index: i32, new: i64) -> i64 #foreign user32;
GetWindowText :: proc(wnd: Hwnd, str: ^byte, maxCount: i32) -> i32 #foreign user32;
HIWORD :: proc(wParam: Wparam) -> u16 { return u16((u32(wParam) >> 16) & 0xffff); }
HIWORD :: proc(lParam: Lparam) -> u16 { return u16((u32(lParam) >> 16) & 0xffff); }
LOWORD :: proc(wParam: Wparam) -> u16 { return u16(wParam); }
LOWORD :: proc(lParam: Lparam) -> u16 { return u16(lParam); }
Bitmap_Info_Header :: struct #ordered {
size: u32,
width, height: i32,
planes, bit_count: i16,
compression: u32,
size_image: u32,
x_pels_per_meter: i32,
y_pels_per_meter: i32,
clr_used: u32,
clr_important: u32,
}
Bitmap_Info :: struct #ordered {
using header: Bitmap_Info_Header,
colors: [1]Rgb_Quad,
}
RGBQUAD :: struct #ordered {
blue, green, red, reserved: byte;
}
Rgb_Quad :: struct #ordered { blue, green, red, reserved: byte }
BI_RGB :: 0;
DIB_RGB_COLORS :: 0x00;
SRCCOPY: u32 : 0x00cc0020;
StretchDIBits :: proc (hdc: HDC,
StretchDIBits :: 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: ^BITMAPINFO,
bits: rawptr, bits_info: ^Bitmap_Info,
usage: u32,
rop: u32) -> i32 #foreign #dll_import
rop: u32) -> i32 #foreign gdi32;
LoadLibraryA :: proc (c_str: ^u8) -> HMODULE #foreign
FreeLibrary :: proc (h: HMODULE) #foreign
GetProcAddress :: proc (h: HMODULE, c_str: ^u8) -> PROC #foreign
GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign
LoadLibraryA :: proc (c_str: ^u8) -> Hmodule #foreign kernel32;
FreeLibrary :: proc (h: Hmodule) #foreign kernel32;
GetProcAddress :: proc (h: Hmodule, c_str: ^u8) -> Proc #foreign kernel32;
GetClientRect :: proc(hwnd: Hwnd, rect: ^Rect) -> Bool #foreign user32;
// Windows OpenGL
PFD_TYPE_RGBA :: 0;
@@ -346,15 +432,11 @@ PFD_DEPTH_DONTCARE :: 0x20000000;
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
PFD_STEREO_DONTCARE :: 0x80000000;
HGLRC :: HANDLE;
PROC :: type proc() #cc_c;
wglCreateContextAttribsARBType :: proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
PIXELFORMATDESCRIPTOR :: struct #ordered {
size,
version,
flags: u32;
flags: u32,
pixel_type,
color_bits,
@@ -375,36 +457,27 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
stencil_bits,
aux_buffers,
layer_type,
reserved: byte;
reserved: byte,
layer_mask,
visible_mask,
damage_mask: u32;
damage_mask: u32,
}
GetDC :: proc(h: HANDLE) -> HDC #foreign
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import
ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll_import
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign #dll_import
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign #dll_import
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092;
WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126;
WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001;
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002;
wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign #dll_import
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign #dll_import
wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign #dll_import
wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign #dll_import
GetDC :: proc(h: Hwnd) -> Hdc #foreign user32;
SetPixelFormat :: proc(hdc: Hdc, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR) -> Bool #foreign gdi32;
ChoosePixelFormat :: proc(hdc: Hdc, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32;
SwapBuffers :: proc(hdc: Hdc) -> Bool #foreign gdi32;
ReleaseDC :: proc(wnd: Hwnd, hdc: Hdc) -> i32 #foreign user32;
Proc :: #type proc() #cc_c;
GetKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
is_key_down :: proc(key: Key_Code) -> bool #inline { return GetAsyncKeyState(key as i32) < 0; }
GetKeyState :: proc(v_key: i32) -> i16 #foreign user32;
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign user32;
is_key_down :: proc(key: Key_Code) -> bool #inline { return GetAsyncKeyState(i32(key)) < 0; }
Key_Code :: enum i32 {
LBUTTON = 0x01,
@@ -541,7 +614,7 @@ Key_Code :: enum i32 {
RCONTROL = 0xA3,
LMENU = 0xA4,
RMENU = 0xA5,
PROCESSKEY = 0xE5,
ProcESSKEY = 0xE5,
ATTN = 0xF6,
CRSEL = 0xF7,
EXSEL = 0xF8,
@@ -552,4 +625,3 @@ Key_Code :: enum i32 {
PA1 = 0xFD,
OEM_CLEAR = 0xFE,
}
+98
View File
@@ -0,0 +1,98 @@
is_signed :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Integer: return i.signed;
case Type_Info.Float: return true;
}
return false;
}
is_integer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Integer);
return ok;
}
is_float :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Float);
return ok;
}
is_complex :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Complex);
return ok;
}
is_any :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Any);
return ok;
}
is_string :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.String);
return ok;
}
is_boolean :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Boolean);
return ok;
}
is_pointer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Pointer);
return ok;
}
is_procedure :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Procedure);
return ok;
}
is_array :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Array);
return ok;
}
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Dynamic_Array);
return ok;
}
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Map);
return ok;
}
is_slice :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Slice);
return ok;
}
is_vector :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Vector);
return ok;
}
is_tuple :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Tuple);
return ok;
}
is_struct :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Struct);
return ok;
}
is_union :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Union);
return ok;
}
is_raw_union :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Raw_Union);
return ok;
}
is_enum :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Enum);
return ok;
}
+58
View File
@@ -0,0 +1,58 @@
REPLACEMENT_CHAR :: '\uFFFD';
MAX_RUNE :: '\U0010FFFF';
_surr1 :: 0xd800;
_surr2 :: 0xdc00;
_surr3 :: 0xe000;
_surr_self :: 0x10000;
is_surrogate :: proc(r: rune) -> bool {
return _surr1 <= r && r < _surr3;
}
decode_surrogate_pair :: proc(r1, r2: rune) -> rune {
if _surr1 <= r1 && r1 < _surr2 && _surr2 <= r2 && r2 < _surr3 {
return (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self;
}
return REPLACEMENT_CHAR;
}
encode_surrogate_pair :: proc(r: rune) -> (r1, r2: rune) {
if r < _surr_self || r > MAX_RUNE {
return REPLACEMENT_CHAR, REPLACEMENT_CHAR;
}
r -= _surr_self;
return _surr1 + (r>>10)&0x3ff, _surr2 + r&0x3ff;
}
encode :: proc(d: []u16, s: []rune) {
n := len(s);
for r in s {
if r >= _surr_self {
n++;
}
}
max_n := min(len(d), n);
n = 0;
for r in s {
match r {
case 0..<_surr1, _surr3..<_surr_self:
d[n] = u16(r);
n++;
case _surr_self..MAX_RUNE:
r1, r2 := encode_surrogate_pair(r);
d[n] = u16(r1);
d[n+1] = u16(r2);
n += 2;
default:
d[n] = u16(REPLACEMENT_CHAR);
n++;
}
}
}
+110 -56
View File
@@ -1,18 +1,36 @@
RUNE_ERROR :: '\ufffd';
RUNE_SELF :: 0x80;
RUNE_BOM :: 0xfeff;
RUNE_EOF :: ~(0 as rune);
RUNE_EOF :: ~rune(0);
MAX_RUNE :: '\U0010ffff';
UTF_MAX :: 4;
SURROGATE_MIN :: 0xd800;
SURROGATE_MAX :: 0xdfff;
Accept_Range :: struct {
lo, hi: u8;
}
T1 :: 0b0000_0000;
TX :: 0b1000_0000;
T2 :: 0b1100_0000;
T3 :: 0b1110_0000;
T4 :: 0b1111_0000;
T5 :: 0b1111_1000;
accept_ranges := [5]Accept_Range{
MASKX :: 0b0011_1111;
MASK2 :: 0b0001_1111;
MASK3 :: 0b0000_1111;
MASK4 :: 0b0000_0111;
RUNE1_MAX :: 1<<7 - 1;
RUNE2_MAX :: 1<<11 - 1;
RUNE3_MAX :: 1<<16 - 1;
// The default lowest and highest continuation byte.
LOCB :: 0b1000_0000;
HICB :: 0b1011_1111;
Accept_Range :: struct { lo, hi: u8 }
immutable accept_ranges := [5]Accept_Range{
{0x80, 0xbf},
{0xa0, 0xbf},
{0x80, 0x9f},
@@ -20,7 +38,7 @@ accept_ranges := [5]Accept_Range{
{0x80, 0x8f},
};
accept_sizes := [256]byte{
immutable accept_sizes := [256]byte{
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
@@ -42,15 +60,15 @@ accept_sizes := [256]byte{
encode_rune :: proc(r: rune) -> ([4]byte, int) {
buf: [4]byte;
i := r as u32;
i := u32(r);
mask: byte : 0x3f;
if i <= 1<<7-1 {
buf[0] = r as byte;
buf[0] = byte(r);
return buf, 1;
}
if i <= 1<<11-1 {
buf[0] = 0xc0 | (r>>6) as byte;
buf[1] = 0x80 | (r) as byte & mask;
buf[0] = 0xc0 | byte(r>>6);
buf[1] = 0x80 | byte(r) & mask;
return buf, 2;
}
@@ -61,64 +79,98 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) {
}
if i <= 1<<16-1 {
buf[0] = 0xe0 | (r>>12) as byte;
buf[1] = 0x80 | (r>>6) as byte & mask;
buf[2] = 0x80 | (r) as byte & mask;
buf[0] = 0xe0 | byte(r>>12);
buf[1] = 0x80 | byte(r>>6) & mask;
buf[2] = 0x80 | byte(r) & mask;
return buf, 3;
}
buf[0] = 0xf0 | (r>>18) as byte;
buf[1] = 0x80 | (r>>12) as byte & mask;
buf[2] = 0x80 | (r>>6) as byte & mask;
buf[3] = 0x80 | (r) as byte & mask;
buf[0] = 0xf0 | byte(r>>18);
buf[1] = 0x80 | byte(r>>12) & mask;
buf[2] = 0x80 | byte(r>>6) & mask;
buf[3] = 0x80 | byte(r) & mask;
return buf, 4;
}
decode_rune :: proc(s: string) -> (rune, int) {
n := s.count;
decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune([]byte(s)); }
decode_rune :: proc(s: []byte) -> (rune, int) {
n := len(s);
if n < 1 {
return RUNE_ERROR, 0;
}
b0 := s[0];
x := accept_sizes[b0];
if x >= 0xf0 {
mask := (x as rune << 31) >> 31; // all zeros or all ones
return (b0 as rune) &~ mask | RUNE_ERROR&mask, 1;
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;
}
size := x & 7;
ar := accept_ranges[x>>4];
if n < size as int {
sz := x & 7;
accept := accept_ranges[x>>4];
if n < int(sz) {
return RUNE_ERROR, 1;
}
b1 := s[1];
if b1 < ar.lo || ar.hi < b1 {
if b1 < accept.lo || accept.hi < b1 {
return RUNE_ERROR, 1;
}
MASK_X :: 0b00111111;
MASK_2 :: 0b00011111;
MASK_3 :: 0b00001111;
MASK_4 :: 0b00000111;
if size == 2 {
return (b0&MASK_2) as rune <<6 | (b1&MASK_X) as rune, 2;
if sz == 2 {
return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2;
}
b2 := s[2];
if b2 < 0x80 || 0xbf < b2 {
if b2 < LOCB || HICB < b2 {
return RUNE_ERROR, 1;
}
if size == 3 {
return (b0&MASK_3) as rune <<12 | (b1&MASK_X) as rune <<6 | (b2&MASK_X) as rune, 3;
if sz == 3 {
return rune(s0&MASK3)<<12 | rune(b1&MASKX)<<6 | rune(b2&MASKX), 3;
}
b3 := s[3];
if b3 < 0x80 || 0xbf < b3 {
if b3 < LOCB || HICB < b3 {
return RUNE_ERROR, 1;
}
return (b0&MASK_4) as rune <<18 | (b1&MASK_X) as rune <<12 | (b3&MASK_X) as rune <<6 | (b3&MASK_X) as rune, 4;
return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4;
}
decode_last_rune :: proc(s: string) -> (rune, int) #inline { return decode_last_rune([]byte(s)); }
decode_last_rune :: proc(s: []byte) -> (rune, int) {
r: rune;
size: int;
start, end, limit: int;
end = len(s);
if end == 0 {
return RUNE_ERROR, 0;
}
start = end-1;
r = rune(s[start]);
if r < RUNE_SELF {
return r, 1;
}
limit = max(end - UTF_MAX, 0);
start--;
for start >= limit {
if rune_start(s[start]) {
break;
}
start--;
}
start = max(start, 0);
r, size = decode_rune(s[start..<end]);
if start+size != end {
return RUNE_ERROR, 1;
}
return r, size;
}
valid_rune :: proc(r: rune) -> bool {
if r < 0 {
return false;
@@ -131,19 +183,18 @@ valid_rune :: proc(r: rune) -> bool {
}
valid_string :: proc(s: string) -> bool {
n := s.count;
i := 0;
while i < n {
n := len(s);
for i := 0; i < n; {
si := s[i];
if si < RUNE_SELF { // ascii
i += 1;
i++;
continue;
}
x := accept_sizes[si];
if x == 0xf1 {
return false;
}
size := (x & 7) as int;
size := int(x & 7);
if i+size > n {
return false;
}
@@ -164,25 +215,28 @@ valid_string :: proc(s: string) -> bool {
return true;
}
rune_count :: proc(s: string) -> int {
rune_start :: proc(b: byte) -> bool #inline { return b&0xc0 != 0x80; }
rune_count :: proc(s: string) -> int #inline { return rune_count([]byte(s)); }
rune_count :: proc(s: []byte) -> int {
count := 0;
n := s.count;
i := 0;
while i < n {
defer count += 1;
n := len(s);
for i := 0; i < n; {
defer count++;
si := s[i];
if si < RUNE_SELF { // ascii
i += 1;
i++;
continue;
}
x := accept_sizes[si];
if x == 0xf1 {
i += 1;
i++;
continue;
}
size := (x & 7) as int;
size := int(x & 7);
if i+size > n {
i += 1;
i++;
continue;
}
ar := accept_ranges[x>>4];
+11
View File
@@ -0,0 +1,11 @@
@echo off
setlocal EnableDelayedExpansion
set file_input=%1
set name=%1
FOR %%f IN (name) do (
FOR %%g in (!%%f!) do set "%%f=%%~ng"
)
call clang -O2 -c %file_input% -o %name%.o ^
&& call ar %name%.o -rcs %name%.lib
View File

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 246 KiB

View File
+1 -2
View File
@@ -1,8 +1,7 @@
@echo off
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
set _NO_DEBUG_HEAP=1
set path=w:\Odin\misc;%path%
View File
-4
View File
@@ -1,4 +0,0 @@
@echo off
rem call clang -c -emit-llvm -DGB_IMPLEMENTATION -DGB_DEF=GB_DLL_EXPORT ..\src\gb\gb.h
+2 -8
View File
@@ -87,14 +87,8 @@ void array__set_capacity(void *ptr, isize capacity, isize element_size) {
x->count = capacity;
}
{
// TODO(bill): Resize rather than copy and delete
void *new_data = gb_alloc(x->allocator, element_size*capacity);
gb_memmove(new_data, x->e, element_size*x->count);
gb_free(x->allocator, x->e);
x->capacity = capacity;
x->e = new_data;
}
x->e = gb_resize(x->allocator, x->e, element_size*x->capacity, element_size*capacity);
x->capacity = capacity;
}
-173
View File
@@ -1,173 +0,0 @@
typedef struct BuildContext {
String ODIN_OS; // target operating system
String ODIN_ARCH; // target architecture
String ODIN_VENDOR; // compiler vendor
String ODIN_VERSION; // compiler version
String ODIN_ROOT; // Odin ROOT
i64 word_size;
i64 max_align;
String llc_flags;
String link_flags;
bool is_dll;
} BuildContext;
// TODO(bill): OS dependent versions for the BuildContext
// join_path
// is_dir
// is_file
// is_abs_path
// has_subdir
String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
String odin_root_dir(void) {
String path = global_module_path;
Array(wchar_t) path_buf;
isize len, i;
gbTempArenaMemory tmp;
wchar_t *text;
if (global_module_path_set) {
return global_module_path;
}
array_init_count(&path_buf, heap_allocator(), 300);
len = 0;
for (;;) {
len = GetModuleFileNameW(NULL, &path_buf.e[0], path_buf.count);
if (len == 0) {
return make_string(NULL, 0);
}
if (len < path_buf.count) {
break;
}
array_resize(&path_buf, 2*path_buf.count + 300);
}
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
GetModuleFileNameW(NULL, text, len);
path = string16_to_string(heap_allocator(), make_string16(text, len));
for (i = path.len-1; i >= 0; i--) {
u8 c = path.text[i];
if (c == '/' || c == '\\') {
break;
}
path.len--;
}
global_module_path = path;
global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
array_free(&path_buf);
return path;
}
String path_to_fullpath(gbAllocator a, String s) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
String16 string16 = string_to_string16(string_buffer_allocator, s);
String result = {0};
DWORD len = GetFullPathNameW(string16.text, 0, NULL, NULL);
if (len != 0) {
wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
GetFullPathNameW(string16.text, len, text, NULL);
text[len] = 0;
result = string16_to_string(a, make_string16(text, len));
}
gb_temp_arena_memory_end(tmp);
return result;
}
String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
String res = {0};
isize str_len = base_dir.len+path.len;
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
isize i = 0;
gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len;
gb_memmove(str+i, path.text, path.len);
str[str_len] = '\0';
res = path_to_fullpath(a, make_string(str, str_len));
gb_free(heap_allocator(), str);
return res;
}
String get_fullpath_core(gbAllocator a, String path) {
String module_dir = odin_root_dir();
String res = {0};
char core[] = "core/";
isize core_len = gb_size_of(core)-1;
isize str_len = module_dir.len + core_len + path.len;
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
gb_memmove(str, module_dir.text, module_dir.len);
gb_memmove(str+module_dir.len, core, core_len);
gb_memmove(str+module_dir.len+core_len, path.text, path.len);
str[str_len] = '\0';
res = path_to_fullpath(a, make_string(str, str_len));
gb_free(heap_allocator(), str);
return res;
}
String get_filepath_extension(String path) {
isize dot = 0;
bool seen_slash = false;
for (isize i = path.len-1; i >= 0; i--) {
u8 c = path.text[i];
if (c == '/' || c == '\\') {
seen_slash = true;
}
if (c == '.') {
if (seen_slash) {
return str_lit("");
}
dot = i;
break;
}
}
return make_string(path.text, dot);
}
void init_build_context(BuildContext *bc) {
bc->ODIN_VENDOR = str_lit("odin");
bc->ODIN_VERSION = str_lit("0.0.5");
bc->ODIN_ROOT = odin_root_dir();
#if defined(GB_SYSTEM_WINDOWS)
bc->ODIN_OS = str_lit("windows");
bc->ODIN_ARCH = str_lit("amd64");
#else
#error Implement system
#endif
if (str_eq(bc->ODIN_ARCH, str_lit("amd64"))) {
bc->word_size = 8;
bc->max_align = 16;
bc->llc_flags = str_lit("-march=x86-64 ");
bc->link_flags = str_lit("/machine:x64 ");
} else if (str_eq(bc->ODIN_ARCH, str_lit("x86"))) {
bc->word_size = 4;
bc->max_align = 8;
bc->llc_flags = str_lit("-march=x86 ");
bc->link_flags = str_lit("/machine:x86 ");
}
}
+328
View File
@@ -0,0 +1,328 @@
// This stores the information for the specify architecture of this build
typedef struct BuildContext {
// Constants
String ODIN_OS; // target operating system
String ODIN_ARCH; // target architecture
String ODIN_ENDIAN; // target endian
String ODIN_VENDOR; // compiler vendor
String ODIN_VERSION; // compiler version
String ODIN_ROOT; // Odin ROOT
// In bytes
i64 word_size; // Size of a pointer, must be >= 4
i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
String llc_flags;
String link_flags;
bool is_dll;
} BuildContext;
gb_global BuildContext build_context = {0};
// TODO(bill): OS dependent versions for the BuildContext
// join_path
// is_dir
// is_file
// is_abs_path
// has_subdir
String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
#if defined(GB_SYSTEM_WINDOWS)
String odin_root_dir(void) {
String path = global_module_path;
Array(wchar_t) path_buf;
isize len, i;
gbTempArenaMemory tmp;
wchar_t *text;
if (global_module_path_set) {
return global_module_path;
}
array_init_count(&path_buf, heap_allocator(), 300);
len = 0;
for (;;) {
len = GetModuleFileNameW(NULL, &path_buf.e[0], path_buf.count);
if (len == 0) {
return make_string(NULL, 0);
}
if (len < path_buf.count) {
break;
}
array_resize(&path_buf, 2*path_buf.count + 300);
}
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
GetModuleFileNameW(NULL, text, len);
path = string16_to_string(heap_allocator(), make_string16(text, len));
for (i = path.len-1; i >= 0; i--) {
u8 c = path.text[i];
if (c == '/' || c == '\\') {
break;
}
path.len--;
}
global_module_path = path;
global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
array_free(&path_buf);
return path;
}
#elif defined(GB_SYSTEM_OSX)
#include <mach-o/dyld.h>
String odin_root_dir(void) {
String path = global_module_path;
Array(char) path_buf;
isize len, i;
gbTempArenaMemory tmp;
wchar_t *text;
if (global_module_path_set) {
return global_module_path;
}
array_init_count(&path_buf, heap_allocator(), 300);
len = 0;
for (;;) {
int sz = path_buf.count;
int res = _NSGetExecutablePath(&path_buf.e[0], &sz);
if(res == 0) {
len = sz;
break;
} else {
array_resize(&path_buf, sz + 1);
}
}
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
gb_memmove(text, &path_buf.e[0], len);
path = make_string(text, len);
for (i = path.len-1; i >= 0; i--) {
u8 c = path.text[i];
if (c == '/' || c == '\\') {
break;
}
path.len--;
}
global_module_path = path;
global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
// array_free(&path_buf);
return path;
}
#else
// NOTE: Linux / Unix is unfinished and not tested very well.
#include <sys/stat.h>
String odin_root_dir(void) {
String path = global_module_path;
Array(char) path_buf;
isize len, i;
gbTempArenaMemory tmp;
u8 *text;
if (global_module_path_set) {
return global_module_path;
}
array_init_count(&path_buf, heap_allocator(), 300);
len = 0;
for (;;) {
// This is not a 100% reliable system, but for the purposes
// of this compiler, it should be _good enough_.
// That said, there's no solid 100% method on Linux to get the program's
// path without checking this link. Sorry.
len = readlink("/proc/self/exe", &path_buf.e[0], path_buf.count);
if(len == 0) {
return make_string(NULL, 0);
}
if (len < path_buf.count) {
break;
}
array_resize(&path_buf, 2*path_buf.count + 300);
}
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
gb_memmove(text, &path_buf.e[0], len);
path = make_string(text, len);
for (i = path.len-1; i >= 0; i--) {
u8 c = path.text[i];
if (c == '/' || c == '\\') {
break;
}
path.len--;
}
global_module_path = path;
global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
array_free(&path_buf);
return path;
}
#endif
#if defined(GB_SYSTEM_WINDOWS)
String path_to_fullpath(gbAllocator a, String s) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
String16 string16 = string_to_string16(string_buffer_allocator, s);
String result = {0};
DWORD len = GetFullPathNameW(string16.text, 0, NULL, NULL);
if (len != 0) {
wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
GetFullPathNameW(string16.text, len, text, NULL);
text[len] = 0;
result = string16_to_string(a, make_string16(text, len));
}
gb_temp_arena_memory_end(tmp);
return result;
}
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
String path_to_fullpath(gbAllocator a, String s) {
char *p = realpath(cast(char *)s.text, 0);
if(p == NULL) return make_string_c("");
return make_string_c(p);
}
#else
#error Implement system
#endif
String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
String res = {0};
isize str_len = base_dir.len+path.len;
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
isize i = 0;
gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len;
gb_memmove(str+i, path.text, path.len);
str[str_len] = '\0';
res = path_to_fullpath(a, make_string(str, str_len));
gb_free(heap_allocator(), str);
return res;
}
String get_fullpath_core(gbAllocator a, String path) {
String module_dir = odin_root_dir();
String res = {0};
char core[] = "core/";
isize core_len = gb_size_of(core)-1;
isize str_len = module_dir.len + core_len + path.len;
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
gb_memmove(str, module_dir.text, module_dir.len);
gb_memmove(str+module_dir.len, core, core_len);
gb_memmove(str+module_dir.len+core_len, path.text, path.len);
str[str_len] = '\0';
res = path_to_fullpath(a, make_string(str, str_len));
gb_free(heap_allocator(), str);
return res;
}
void init_build_context(void) {
BuildContext *bc = &build_context;
bc->ODIN_VENDOR = str_lit("odin");
bc->ODIN_VERSION = str_lit("0.2.1");
bc->ODIN_ROOT = odin_root_dir();
#if defined(GB_SYSTEM_WINDOWS)
bc->ODIN_OS = str_lit("windows");
bc->ODIN_ARCH = str_lit("amd64");
bc->ODIN_ENDIAN = str_lit("little");
#elif defined(GB_SYSTEM_OSX)
bc->ODIN_OS = str_lit("osx");
bc->ODIN_ARCH = str_lit("amd64");
bc->ODIN_ENDIAN = str_lit("little");
#else
bc->ODIN_OS = str_lit("linux");
bc->ODIN_ARCH = str_lit("amd64");
bc->ODIN_ENDIAN = str_lit("little");
#endif
// NOTE(zangent): The linker flags to set the build architecture are different
// across OSs. It doesn't make sense to allocate extra data on the heap
// here, so I just #defined the linker flags to keep things concise.
#if defined(GB_SYSTEM_WINDOWS)
#define LINK_FLAG_X64 "/machine:x64"
#define LINK_FLAG_X86 "/machine:x86"
#elif defined(GB_SYSTEM_OSX)
// NOTE(zangent): MacOS systems are x64 only, so ld doesn't have
// an architecture option. All compilation done on MacOS must be x64.
GB_ASSERT(str_eq(bc->ODIN_ARCH, str_lit("amd64")));
#define LINK_FLAG_X64 ""
#define LINK_FLAG_X86 ""
#else
// Linux, but also BSDs and the like.
// NOTE(zangent): When clang is swapped out with ld as the linker,
// the commented flags here should be used. Until then, we'll have
// to use alternative build flags made for clang.
/*
#define LINK_FLAG_X64 "-m elf_x86_64"
#define LINK_FLAG_X86 "-m elf_i386"
*/
#define LINK_FLAG_X64 "-arch x86-64"
#define LINK_FLAG_X86 "-arch x86"
#endif
if (str_eq(bc->ODIN_ARCH, str_lit("amd64"))) {
bc->word_size = 8;
bc->max_align = 16;
bc->llc_flags = str_lit("-march=x86-64 ");
bc->link_flags = str_lit(LINK_FLAG_X64 " ");
} else if (str_eq(bc->ODIN_ARCH, str_lit("x86"))) {
bc->word_size = 4;
bc->max_align = 8;
bc->llc_flags = str_lit("-march=x86 ");
bc->link_flags = str_lit(LINK_FLAG_X86 " ");
}
#undef LINK_FLAG_X64
#undef LINK_FLAG_X86
}
+164 -152
View File
@@ -1,21 +1,21 @@
bool check_is_terminating(AstNode *node);
void check_stmt (Checker *c, AstNode *node, u32 flags);
void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags);
// NOTE(bill): `content_name` is for debugging and error messages
Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid ||
e->type == t_invalid) {
operand->type == t_invalid ||
e->type == t_invalid) {
if (operand->mode == Addressing_Builtin) {
gbString expr_str = expr_to_string(operand->expr);
// TODO(bill): is this a good enough error message?
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
error_node(operand->expr,
"Cannot assign builtin procedure `%s` in %.*s",
expr_str,
LIT(context_name));
"Cannot assign builtin procedure `%s` in %.*s",
expr_str,
LIT(context_name));
operand->mode = Addressing_Invalid;
@@ -40,6 +40,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
}
t = default_type(t);
}
GB_ASSERT(is_type_typed(t));
e->type = t;
}
@@ -60,23 +61,9 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation
Array(Operand) operands;
ArrayOperand operands = {0};
array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count);
for_array(i, inits) {
AstNode *rhs = inits.e[i];
Operand o = {0};
check_multi_expr(c, &o, rhs);
if (o.type->kind != Type_Tuple) {
array_add(&operands, o);
} else {
TypeTuple *tuple = &o.type->Tuple;
for (isize j = 0; j < tuple->variable_count; j++) {
o.type = tuple->variables[j]->type;
array_add(&operands, o);
}
}
}
check_unpack_arguments(c, lhs_count, &operands, inits, true);
isize rhs_count = operands.count;
for_array(i, operands) {
@@ -85,104 +72,21 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
}
}
isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) {
check_init_variable(c, lhs[i], &operands.e[i], context_name);
}
if (rhs_count > 0 && lhs_count != rhs_count) {
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
}
#if 0
if (lhs[0]->kind == Entity_Variable &&
lhs[0]->Variable.is_let) {
if (lhs_count != rhs_count) {
error(lhs[0]->token, "`let` variables must be initialized, `%td` = `%td`", lhs_count, rhs_count);
}
}
#endif
gb_temp_arena_memory_end(tmp);
}
void check_var_decl_node(Checker *c, AstNodeValueDecl *vd) {
GB_ASSERT(vd->is_var == true);
isize entity_count = vd->names.count;
isize entity_index = 0;
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
for_array(i, vd->names) {
AstNode *name = vd->names.e[i];
Entity *entity = NULL;
if (name->kind == AstNode_Ident) {
Token token = name->Ident;
String str = token.string;
Entity *found = NULL;
// NOTE(bill): Ignore assignments to `_`
if (str_ne(str, str_lit("_"))) {
found = current_scope_lookup_entity(c->context.scope, str);
}
if (found == NULL) {
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
add_entity_definition(&c->info, name, entity);
} else {
TokenPos pos = found->token.pos;
error(token,
"Redeclaration of `%.*s` in this scope\n"
"\tat %.*s(%td:%td)",
LIT(str), LIT(pos.file), pos.line, pos.column);
entity = found;
}
} else {
error_node(name, "A variable declaration must be an identifier");
}
if (entity == NULL) {
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
}
entities[entity_index++] = entity;
}
Type *init_type = NULL;
if (vd->type) {
init_type = check_type_extra(c, vd->type, NULL);
if (init_type == NULL) {
init_type = t_invalid;
}
}
for (isize i = 0; i < entity_count; i++) {
Entity *e = entities[i];
GB_ASSERT(e != NULL);
if (e->flags & EntityFlag_Visited) {
e->type = t_invalid;
continue;
}
e->flags |= EntityFlag_Visited;
if (e->type == NULL) {
e->type = init_type;
}
}
check_arity_match(c, vd);
check_init_variables(c, entities, entity_count, vd->values, str_lit("variable declaration"));
for_array(i, vd->names) {
if (entities[i] != NULL) {
add_entity(c, c->context.scope, vd->names.e[i], entities[i]);
}
}
}
void check_init_constant(Checker *c, Entity *e, Operand *operand) {
if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid ||
e->type == t_invalid) {
operand->type == t_invalid ||
e->type == t_invalid) {
if (e->type == NULL) {
e->type = t_invalid;
}
@@ -249,9 +153,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
}
e->flags |= EntityFlag_Visited;
c->context.iota = e->Constant.value;
e->Constant.value = (ExactValue){0};
if (type_expr) {
Type *t = check_type(c, type_expr);
if (!is_type_constant_type(t)) {
@@ -259,7 +160,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
error_node(type_expr, "Invalid constant type `%s`", str);
gb_string_free(str);
e->type = t_invalid;
c->context.iota = (ExactValue){0};
return;
}
e->type = t;
@@ -270,9 +170,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
check_expr_or_type(c, &operand, init);
}
if (operand.mode == Addressing_Type) {
c->context.iota = (ExactValue){0};
e->Constant.value = (ExactValue){0};
e->kind = Entity_TypeName;
DeclInfo *d = c->context.decl;
@@ -282,10 +179,10 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
}
check_init_constant(c, e, &operand);
c->context.iota = (ExactValue){0};
if (operand.mode == Addressing_Invalid) {
error(e->token, "Illegal cyclic declaration");
if (operand.mode == Addressing_Invalid ||
base_type(operand.type) == t_invalid) {
error(e->token, "Invalid declaration type");
}
}
@@ -329,29 +226,30 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
return true;
}
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
GB_ASSERT(e->type == NULL);
if (d->proc_decl->kind != AstNode_ProcLit) {
if (d->proc_lit->kind != AstNode_ProcLit) {
// TOOD(bill): Better error message
error_node(d->proc_decl, "Expected a procedure to check");
error_node(d->proc_lit, "Expected a procedure to check");
return;
}
Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
e->type = proc_type;
ast_node(pd, ProcLit, d->proc_decl);
ast_node(pd, ProcLit, d->proc_lit);
check_open_scope(c, pd->type);
check_procedure_type(c, proc_type, pd->type);
bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
bool is_export = (pd->tags & ProcTag_export) != 0;
bool is_inline = (pd->tags & ProcTag_inline) != 0;
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
bool is_export = (pd->tags & ProcTag_export) != 0;
bool is_inline = (pd->tags & ProcTag_inline) != 0;
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
bool is_require_results = (pd->tags & ProcTag_require_results) != 0;
if ((d->scope->is_file || d->scope->is_global) &&
str_eq(e->token.string, str_lit("main"))) {
if (d->scope->is_file && str_eq(e->token.string, str_lit("main"))) {
if (proc_type != NULL) {
TypeProc *pt = &proc_type->Proc;
if (pt->param_count != 0 ||
@@ -379,24 +277,52 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
}
if (proc_type->Proc.calling_convention != ProcCC_Odin) {
error_node(d->proc_decl, "An internal procedure may only have the Odin calling convention");
proc_type->Proc.calling_convention = ProcCC_Odin;
}
d->scope = c->context.scope;
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
}
if (proc_type != NULL && is_type_proc(proc_type)) {
TypeProc *tp = &proc_type->Proc;
if (tp->result_count == 0 && is_require_results) {
error_node(pd->type, "`#require_results` is not needed on a procedure with no results");
} else {
tp->require_results = is_require_results;
}
}
if (is_foreign) {
MapEntity *fp = &c->info.foreign_procs;
MapEntity *fp = &c->info.foreigns;
String name = e->token.string;
if (pd->foreign_name.len > 0) {
name = pd->foreign_name;
}
AstNode *foreign_library = d->proc_lit->ProcLit.foreign_library;
if (foreign_library == NULL) {
error(e->token, "#foreign procedures must declare which library they are from");
} else if (foreign_library->kind != AstNode_Ident) {
error_node(foreign_library, "#foreign library names must be an identifier");
} else {
String name = foreign_library->Ident.string;
Entity *found = scope_lookup_entity(c->context.scope, name);
if (found == NULL) {
if (str_eq(name, str_lit("_"))) {
error_node(foreign_library, "`_` cannot be used as a value type");
} else {
error_node(foreign_library, "Undeclared name: %.*s", LIT(name));
}
} else if (found->kind != Entity_LibraryName) {
error_node(foreign_library, "`_` cannot be used as a library name");
} else {
// TODO(bill): Extra stuff to do with library names?
e->Procedure.foreign_library = found;
add_entity_use(c, foreign_library, found);
}
}
e->Procedure.is_foreign = true;
e->Procedure.foreign_name = name;
@@ -408,10 +334,10 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
Type *this_type = base_type(e->type);
Type *other_type = base_type(f->type);
if (!are_signatures_similar_enough(this_type, other_type)) {
error_node(d->proc_decl,
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
error_node(d->proc_lit,
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else {
map_entity_set(fp, key, e);
@@ -423,7 +349,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
}
if (is_link_name || is_export) {
MapEntity *fp = &c->info.foreign_procs;
MapEntity *fp = &c->info.foreigns;
e->Procedure.link_name = name;
@@ -433,10 +359,10 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
Entity *f = *found;
TokenPos pos = f->token.pos;
// TODO(bill): Better error message?
error_node(d->proc_decl,
"Non unique linking name for procedure `%.*s`\n"
"\tother at %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
error_node(d->proc_lit,
"Non unique linking name for procedure `%.*s`\n"
"\tother at %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
} else {
map_entity_set(fp, key, e);
}
@@ -487,6 +413,67 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
}
void check_alias_decl(Checker *c, Entity *e, AstNode *expr, Type *named_type) {
GB_ASSERT(e->type == NULL);
GB_ASSERT(e->kind == Entity_Alias);
if (e->flags & EntityFlag_Visited) {
e->type = t_invalid;
return;
}
e->flags |= EntityFlag_Visited;
e->type = t_invalid;
expr = unparen_expr(expr);
if (expr->kind == AstNode_Alias) {
error_node(expr, "#alias of an #alias is not allowed");
return;
}
Operand operand = {0};
check_expr_or_type(c, &operand, expr);
if (operand.mode != Addressing_Type) {
error_node(expr, "#alias declarations only allow types");
return;
}
e->kind = Entity_TypeName;
e->TypeName.is_type_alias = true;
e->type = NULL;
DeclInfo *d = c->context.decl;
d->type_expr = expr;
check_type_decl(c, e, d->type_expr, named_type);
// Operand o = {0};
// Entity *f = NULL;
// if (expr->kind == AstNode_Ident) {
// f = check_ident(c, &o, expr, NULL, NULL, true);
// } else if (expr->kind == AstNode_SelectorExpr) {
// f = check_selector(c, &o, expr, NULL);
// } else {
// check_expr_or_type(c, &o, expr);
// }
// if (o.mode == Addressing_Invalid) {
// return;
// }
// switch (o.mode) {
// case Addressing_Type:
// e->type = o.type;
// // e->kind = Entity_TypeName;
// // e->TypeName.is_type_alias = true;
// e->Alias.kind = EntityAlias_Type;
// e->Alias.original = f;
// break;
// default:
// error_node(expr, "#alias declarations only allow types");
// e->kind = Entity_Invalid;
// e->type = t_invalid;
// break;
// }
}
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
if (e->type != NULL) {
return;
@@ -510,17 +497,20 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
c->context.decl = d;
switch (e->kind) {
case Entity_Constant:
check_const_decl(c, e, d->type_expr, d->init_expr, named_type);
break;
case Entity_Variable:
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
break;
case Entity_Constant:
check_const_decl(c, e, d->type_expr, d->init_expr, named_type);
break;
case Entity_TypeName:
check_type_decl(c, e, d->type_expr, named_type);
break;
case Entity_Alias:
check_alias_decl(c, e, d->init_expr, named_type);
break;
case Entity_Procedure:
check_proc_decl(c, e, d);
check_proc_lit(c, e, d);
break;
}
@@ -532,9 +522,18 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
GB_ASSERT(body->kind == AstNode_BlockStmt);
String proc_name = {0};
if (token.kind == Token_Ident) {
proc_name = token.string;
} else {
// TODO(bill): Better name
proc_name = str_lit("(anonymous-procedure)");
}
CheckerContext old_context = c->context;
c->context.scope = decl->scope;
c->context.decl = decl;
c->context.proc_name = proc_name;
GB_ASSERT(type->kind == Type_Proc);
if (type->Proc.param_count > 0) {
@@ -542,9 +541,10 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
for (isize i = 0; i < params->variable_count; i++) {
Entity *e = params->variables[i];
GB_ASSERT(e->kind == Entity_Variable);
if (!(e->flags & EntityFlag_Anonymous)) {
if (!(e->flags & EntityFlag_Using)) {
continue;
}
bool is_immutable = e->Variable.is_immutable;
String name = e->token.string;
Type *t = base_type(type_deref(e->type));
if (is_type_struct(t) || is_type_raw_union(t)) {
@@ -554,6 +554,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
Entity *f = (*found)->elements.entries.e[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
uvar->Variable.is_immutable = is_immutable;
Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != NULL) {
error(e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
@@ -571,11 +572,14 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
push_procedure(c, type);
{
ast_node(bs, BlockStmt, body);
// TODO(bill): Check declarations first (except mutable variable declarations)
check_stmt_list(c, bs->stmts, 0);
check_stmt_list(c, bs->stmts, Stmt_CheckScopeDecls);
if (type->Proc.result_count > 0) {
if (!check_is_terminating(body)) {
error(bs->close, "Missing return statement at the end of the procedure");
if (token.kind == Token_Ident) {
error(bs->close, "Missing return statement at the end of the procedure `%.*s`", LIT(token.string));
} else {
error(bs->close, "Missing return statement at the end of the procedure");
}
}
}
}
@@ -583,8 +587,16 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
check_scope_usage(c, c->context.scope);
c->context = old_context;
if (decl->parent != NULL) {
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
for_array(i, decl->deps.entries) {
HashKey key = decl->deps.entries.e[i].key;
Entity *e = cast(Entity *)key.ptr;
map_bool_set(&decl->parent->deps, key, true);
}
}
}
+6354
View File
File diff suppressed because it is too large Load Diff
+1624
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-4771
View File
File diff suppressed because it is too large Load Diff
-1312
View File
File diff suppressed because it is too large Load Diff
-1680
View File
File diff suppressed because it is too large Load Diff
+114
View File
@@ -1,17 +1,124 @@
#if defined(GB_SYSTEM_UNIX)
// Required for intrinsics on GCC
#include <xmmintrin.h>
#endif
#define GB_NO_DEFER
#define GB_IMPLEMENTATION
#include "gb/gb.h"
#include <math.h>
gbAllocator heap_allocator(void) {
return gb_heap_allocator();
}
#include "unicode.c"
#include "string.c"
#include "array.c"
gb_global String global_module_path = {0};
gb_global bool global_module_path_set = false;
gb_global gbScratchMemory scratch_memory = {0};
void init_scratch_memory(isize size) {
void *memory = gb_alloc(heap_allocator(), size);
gb_scratch_memory_init(&scratch_memory, memory, size);
}
gbAllocator scratch_allocator(void) {
return gb_scratch_allocator(&scratch_memory);
}
typedef struct DynamicArenaBlock DynamicArenaBlock;
typedef struct DynamicArena DynamicArena;
struct DynamicArenaBlock {
DynamicArenaBlock *prev;
DynamicArenaBlock *next;
u8 * start;
isize count;
isize capacity;
gbVirtualMemory vm;
};
struct DynamicArena {
DynamicArenaBlock *start_block;
DynamicArenaBlock *current_block;
isize block_size;
};
DynamicArenaBlock *add_dynamic_arena_block(DynamicArena *a) {
GB_ASSERT(a != NULL);
GB_ASSERT(a->block_size > 0);
gbVirtualMemory vm = gb_vm_alloc(NULL, a->block_size);
DynamicArenaBlock *block = cast(DynamicArenaBlock *)vm.data;
u8 *start = cast(u8 *)gb_align_forward(cast(u8 *)(block + 1), GB_DEFAULT_MEMORY_ALIGNMENT);
u8 *end = cast(u8 *)vm.data + vm.size;
block->vm = vm;
block->start = start;
block->count = 0;
block->capacity = end-start;
if (a->current_block != NULL) {
a->current_block->next = block;
block->prev = a->current_block;
}
a->current_block = block;
return block;
}
void init_dynamic_arena(DynamicArena *a, isize block_size) {
isize size = gb_size_of(DynamicArenaBlock) + block_size;
size = cast(isize)gb_align_forward(cast(void *)cast(uintptr)size, GB_DEFAULT_MEMORY_ALIGNMENT);
a->block_size = size;
a->start_block = add_dynamic_arena_block(a);
}
void destroy_dynamic_arena(DynamicArena *a) {
DynamicArenaBlock *b = a->current_block;
while (b != NULL) {
gbVirtualMemory vm = b->vm;
b = b->prev;
gb_vm_free(b->vm);
}
}
GB_ALLOCATOR_PROC(dynamic_arena_allocator_proc) {
DynamicArena *a = cast(DynamicArena *)allocator_data;
void *ptr = NULL;
switch (type) {
case gbAllocation_Alloc: {
} break;
case gbAllocation_Free: {
} break;
case gbAllocation_Resize: {
} break;
case gbAllocation_FreeAll:
GB_PANIC("free_all is not supported by this allocator");
break;
}
return ptr;
}
gbAllocator dynamic_arena_allocator(DynamicArena *a) {
gbAllocator allocator = {dynamic_arena_allocator_proc, a};
return allocator;
}
i64 next_pow2(i64 n) {
if (n <= 0) {
@@ -92,6 +199,10 @@ i16 f32_to_f16(f32 value) {
}
}
f64 gb_sqrt(f64 x) {
return sqrt(x);
}
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
@@ -119,6 +230,9 @@ i16 f32_to_f16(f32 value) {
//
////////////////////////////////////////////////////////////////
typedef Array(i32) Array_i32;
typedef Array(isize) Array_isize;
#define MAP_TYPE String
#define MAP_PROC map_string_
+111 -31
View File
@@ -1,8 +1,8 @@
typedef struct Scope Scope;
typedef struct Checker Checker;
typedef struct Type Type;
typedef enum BuiltinProcId BuiltinProcId;
typedef enum ImplicitValueId ImplicitValueId;
// typedef enum BuiltinProcId BuiltinProcId;
#define ENTITY_KINDS \
ENTITY_KIND(Invalid) \
@@ -12,14 +12,16 @@ typedef enum ImplicitValueId ImplicitValueId;
ENTITY_KIND(Procedure) \
ENTITY_KIND(Builtin) \
ENTITY_KIND(ImportName) \
ENTITY_KIND(LibraryName) \
ENTITY_KIND(Alias) \
ENTITY_KIND(Nil) \
ENTITY_KIND(ImplicitValue) \
ENTITY_KIND(Count)
ENTITY_KIND(Label)
typedef enum EntityKind {
#define ENTITY_KIND(k) GB_JOIN2(Entity_, k),
ENTITY_KINDS
#undef ENTITY_KIND
Entity_Count,
} EntityKind;
String const entity_strings[] = {
@@ -31,15 +33,35 @@ String const entity_strings[] = {
typedef enum EntityFlag {
EntityFlag_Visited = 1<<0,
EntityFlag_Used = 1<<1,
EntityFlag_Anonymous = 1<<2,
EntityFlag_Using = 1<<2,
EntityFlag_Field = 1<<3,
EntityFlag_Param = 1<<4,
EntityFlag_VectorElem = 1<<5,
EntityFlag_Ellipsis = 1<<6,
EntityFlag_NoAlias = 1<<7,
EntityFlag_TypeField = 1<<8,
EntityFlag_Value = 1<<9,
} EntityFlag;
// Zero value means the overloading process is not yet done
typedef enum OverloadKind {
Overload_Unknown,
Overload_No,
Overload_Yes,
} OverloadKind;
typedef enum EntityAliasKind {
EntityAlias_Invalid,
EntityAlias_Type,
EntityAlias_Entity,
} EntityAliasKind;
// An Entity is a named "thing" in the language
typedef struct Entity Entity;
struct Entity {
EntityKind kind;
u64 id;
u32 flags;
Token token;
Scope * scope;
@@ -58,16 +80,21 @@ struct Entity {
i32 field_index;
i32 field_src_index;
bool is_immutable;
bool is_thread_local;
} Variable;
i32 TypeName;
struct {
bool is_foreign;
String foreign_name;
String link_name;
u64 tags;
bool is_type_alias;
} TypeName;
struct {
bool is_foreign;
String foreign_name;
Entity * foreign_library;
String link_name;
u64 tags;
OverloadKind overload_kind;
} Procedure;
struct {
BuiltinProcId id;
i32 id;
} Builtin;
struct {
String path;
@@ -75,18 +102,51 @@ struct Entity {
Scope *scope;
bool used;
} ImportName;
struct {
String path;
String name;
bool used;
} LibraryName;
struct {
EntityAliasKind kind;
Entity * original;
} Alias;
i32 Nil;
struct {
// TODO(bill): Should this be a user-level construct rather than compiler-level?
ImplicitValueId id;
Entity * backing;
} ImplicitValue;
String name;
AstNode *node;
} Label;
};
};
gb_global Entity *e_context = NULL;
Entity *e_iota = NULL;
bool is_entity_kind_exported(EntityKind kind) {
switch (kind) {
case Entity_Builtin:
case Entity_ImportName:
case Entity_LibraryName:
case Entity_Nil:
return false;
}
return true;
}
bool is_entity_exported(Entity *e) {
// TODO(bill): Determine the actual exportation rules for imports of entities
GB_ASSERT(e != NULL);
if (!is_entity_kind_exported(e->kind)) {
return false;
}
String name = e->token.string;
if (name.len == 0) {
return false;
}
return name.text[0] != '_';
}
gb_global u64 global_entity_id = 0;
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
Entity *entity = gb_alloc_item(a, Entity);
@@ -94,19 +154,22 @@ Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token,
entity->scope = scope;
entity->token = token;
entity->type = type;
entity->id = ++global_entity_id;
return entity;
}
Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *type) {
Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *type, bool is_immutable) {
Entity *entity = alloc_entity(a, Entity_Variable, scope, token, type);
entity->Variable.is_immutable = is_immutable;
return entity;
}
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
GB_ASSERT(parent != NULL);
token.pos = parent->token.pos;
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
entity->using_parent = parent;
entity->flags |= EntityFlag_Anonymous;
entity->flags |= EntityFlag_Using;
return entity;
}
@@ -122,25 +185,25 @@ Entity *make_entity_type_name(gbAllocator a, Scope *scope, Token token, Type *ty
return entity;
}
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous) {
Entity *entity = make_entity_variable(a, scope, token, type);
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, bool is_immutable) {
Entity *entity = make_entity_variable(a, scope, token, type, is_immutable);
entity->flags |= EntityFlag_Used;
entity->flags |= EntityFlag_Anonymous*(anonymous != 0);
if (is_using) entity->flags |= EntityFlag_Using;
entity->flags |= EntityFlag_Param;
return entity;
}
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous, i32 field_src_index) {
Entity *entity = make_entity_variable(a, scope, token, type);
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, i32 field_src_index) {
Entity *entity = make_entity_variable(a, scope, token, type, false);
entity->Variable.field_src_index = field_src_index;
entity->Variable.field_index = field_src_index;
if (is_using) entity->flags |= EntityFlag_Using;
entity->flags |= EntityFlag_Field;
entity->flags |= EntityFlag_Anonymous*(anonymous != 0);
return entity;
}
Entity *make_entity_vector_elem(gbAllocator a, Scope *scope, Token token, Type *type, i32 field_src_index) {
Entity *entity = make_entity_variable(a, scope, token, type);
Entity *entity = make_entity_variable(a, scope, token, type, false);
entity->Variable.field_src_index = field_src_index;
entity->Variable.field_index = field_src_index;
entity->flags |= EntityFlag_Field;
@@ -154,7 +217,7 @@ Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *si
return entity;
}
Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type, BuiltinProcId id) {
Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type, i32 id) {
Entity *entity = alloc_entity(a, Entity_Builtin, scope, token, type);
entity->Builtin.id = id;
return entity;
@@ -169,22 +232,39 @@ Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *
return entity;
}
Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type *type,
String path, String name) {
Entity *entity = alloc_entity(a, Entity_LibraryName, scope, token, type);
entity->LibraryName.path = path;
entity->LibraryName.name = name;
return entity;
}
Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type,
EntityAliasKind kind, Entity *original) {
Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type);
entity->Alias.kind = kind;
entity->Alias.original = original;
return entity;
}
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
Token token = make_token_ident(name);
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type);
return entity;
}
Entity *make_entity_implicit_value(gbAllocator a, String name, Type *type, ImplicitValueId id) {
Token token = make_token_ident(name);
Entity *entity = alloc_entity(a, Entity_ImplicitValue, NULL, token, type);
entity->ImplicitValue.id = id;
Entity *make_entity_label(gbAllocator a, Scope *scope, Token token, Type *type,
AstNode *node) {
Entity *entity = alloc_entity(a, Entity_Label, scope, token, type);
entity->Label.node = node;
return entity;
}
Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
token.string = str_lit("_");
return make_entity_variable(a, scope, token, NULL);
return make_entity_variable(a, scope, token, NULL, false);
}
+468 -64
View File
@@ -5,6 +5,14 @@
typedef struct AstNode AstNode;
typedef struct Complex128 {
f64 real, imag;
} Complex128;
typedef struct Quaternion256 {
f64 real, imag, jmag, kmag;
} Quaternion256;
typedef enum ExactValueKind {
ExactValue_Invalid,
@@ -12,6 +20,8 @@ typedef enum ExactValueKind {
ExactValue_String,
ExactValue_Integer,
ExactValue_Float,
ExactValue_Complex,
ExactValue_Quaternion,
ExactValue_Pointer,
ExactValue_Compound, // TODO(bill): Is this good enough?
@@ -21,12 +31,14 @@ typedef enum ExactValueKind {
typedef struct ExactValue {
ExactValueKind kind;
union {
bool value_bool;
String value_string;
i64 value_integer; // NOTE(bill): This must be an integer and not a pointer
f64 value_float;
i64 value_pointer;
AstNode *value_compound;
bool value_bool;
String value_string;
i64 value_integer; // NOTE(bill): This must be an integer and not a pointer
f64 value_float;
i64 value_pointer;
Complex128 value_complex;
Quaternion256 value_quaternion;
AstNode * value_compound;
};
} ExactValue;
@@ -35,78 +47,206 @@ HashKey hash_exact_value(ExactValue v) {
}
ExactValue make_exact_value_compound(AstNode *node) {
ExactValue exact_value_compound(AstNode *node) {
ExactValue result = {ExactValue_Compound};
result.value_compound = node;
return result;
}
ExactValue make_exact_value_bool(bool b) {
ExactValue exact_value_bool(bool b) {
ExactValue result = {ExactValue_Bool};
result.value_bool = (b != 0);
return result;
}
ExactValue make_exact_value_string(String string) {
ExactValue exact_value_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
ExactValue result = {ExactValue_String};
result.value_string = string;
return result;
}
ExactValue make_exact_value_integer_from_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
ExactValue result = {ExactValue_Integer};
i32 base = 10;
if (string.len > 2 && string.text[0] == '0') {
switch (string.text[1]) {
case 'b': base = 2; break;
case 'o': base = 8; break;
case 'd': base = 10; break;
case 'x': base = 16; break;
}
}
result.value_integer = gb_str_to_i64(cast(char *)string.text, NULL, base);
return result;
}
ExactValue make_exact_value_integer(i64 i) {
ExactValue exact_value_integer(i64 i) {
ExactValue result = {ExactValue_Integer};
result.value_integer = i;
return result;
}
ExactValue make_exact_value_float_from_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
ExactValue result = {ExactValue_Float};
result.value_float = gb_str_to_f64(cast(char *)string.text, NULL);
return result;
}
ExactValue make_exact_value_float(f64 f) {
ExactValue exact_value_float(f64 f) {
ExactValue result = {ExactValue_Float};
result.value_float = f;
return result;
}
ExactValue make_exact_value_pointer(i64 ptr) {
ExactValue exact_value_complex(f64 real, f64 imag) {
ExactValue result = {ExactValue_Complex};
result.value_complex.real = real;
result.value_complex.imag = imag;
return result;
}
ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
ExactValue result = {ExactValue_Quaternion};
result.value_quaternion.real = real;
result.value_quaternion.imag = imag;
result.value_quaternion.jmag = jmag;
result.value_quaternion.kmag = kmag;
return result;
}
ExactValue exact_value_pointer(i64 ptr) {
ExactValue result = {ExactValue_Pointer};
result.value_pointer = ptr;
return result;
}
ExactValue make_exact_value_from_basic_literal(Token token) {
ExactValue exact_value_integer_from_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
i32 base = 10;
bool has_prefix = false;
if (string.len > 2 && string.text[0] == '0') {
switch (string.text[1]) {
case 'b': base = 2; has_prefix = true; break;
case 'o': base = 8; has_prefix = true; break;
case 'd': base = 10; has_prefix = true; break;
case 'z': base = 12; has_prefix = true; break;
case 'x': base = 16; has_prefix = true; break;
}
}
u8 *text = string.text;
isize len = string.len;
if (has_prefix) {
text += 2;
len -= 2;
}
i64 result = 0;
for (isize i = 0; i < len; i++) {
Rune r = cast(Rune)text[i];
if (r == '_') {
continue;
}
i64 v = 0;
v = digit_value(r);
if (v >= base) {
break;
}
result *= base;
result += v;
}
return exact_value_integer(result);
}
f64 float_from_string(String string) {
isize i = 0;
u8 *str = string.text;
isize len = string.len;
f64 sign = 1.0;
if (str[i] == '-') {
sign = -1.0;
i++;
} else if (*str == '+') {
i++;
}
f64 value = 0.0;
for (; i < len; i++) {
Rune r = cast(Rune)str[i];
if (r == '_') {
continue;
}
i64 v = digit_value(r);
if (v >= 10) {
break;
}
value *= 10.0;
value += v;
}
if (str[i] == '.') {
f64 pow10 = 10.0;
i++;
for (; i < string.len; i++) {
Rune r = cast(Rune)str[i];
if (r == '_') {
continue;
}
i64 v = digit_value(r);
if (v >= 10) {
break;
}
value += v/pow10;
pow10 *= 10.0;
}
}
bool frac = false;
f64 scale = 1.0;
if ((str[i] == 'e') || (str[i] == 'E')) {
i++;
if (str[i] == '-') {
frac = true;
i++;
} else if (str[i] == '+') {
i++;
}
u32 exp = 0;
for (; i < len; i++) {
Rune r = cast(Rune)str[i];
if (r == '_') {
continue;
}
u32 d = cast(u32)digit_value(r);
if (d >= 10) {
break;
}
exp = exp * 10 + d;
}
if (exp > 308) exp = 308;
while (exp >= 50) { scale *= 1e50; exp -= 50; }
while (exp >= 8) { scale *= 1e8; exp -= 8; }
while (exp > 0) { scale *= 10.0; exp -= 1; }
}
return sign * (frac ? (value / scale) : (value * scale));
}
ExactValue exact_value_float_from_string(String string) {
return exact_value_float(float_from_string(string));
}
ExactValue exact_value_from_basic_literal(Token token) {
switch (token.kind) {
case Token_String: return make_exact_value_string(token.string);
case Token_Integer: return make_exact_value_integer_from_string(token.string);
case Token_Float: return make_exact_value_float_from_string(token.string);
case Token_String: return exact_value_string(token.string);
case Token_Integer: return exact_value_integer_from_string(token.string);
case Token_Float: return exact_value_float_from_string(token.string);
case Token_Imag: {
String str = token.string;
Rune last_rune = cast(Rune)str.text[str.len-1];
str.len--; // Ignore the `i|j|k`
f64 imag = float_from_string(str);
switch (last_rune) {
case 'i': return exact_value_complex(0, imag);
case 'j': return exact_value_quaternion(0, 0, imag, 0);
case 'k': return exact_value_quaternion(0, 0, 0, imag);
}
}
case Token_Rune: {
Rune r = GB_RUNE_INVALID;
gb_utf8_decode(token.string.text, token.string.len, &r);
// gb_printf("%.*s rune: %d\n", LIT(token.string), r);
return make_exact_value_integer(r);
return exact_value_integer(r);
}
default:
GB_PANIC("Invalid token for basic literal");
@@ -125,12 +265,12 @@ ExactValue exact_value_to_integer(ExactValue v) {
i64 i = cast(i64)v.value_float;
f64 f = cast(f64)i;
if (f == v.value_float) {
return make_exact_value_integer(i);
return exact_value_integer(i);
}
} break;
case ExactValue_Pointer:
return make_exact_value_integer(cast(i64)cast(intptr)v.value_pointer);
return exact_value_integer(cast(i64)cast(intptr)v.value_pointer);
}
ExactValue r = {ExactValue_Invalid};
return r;
@@ -139,7 +279,7 @@ ExactValue exact_value_to_integer(ExactValue v) {
ExactValue exact_value_to_float(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return make_exact_value_float(cast(i64)v.value_integer);
return exact_value_float(cast(i64)v.value_integer);
case ExactValue_Float:
return v;
}
@@ -147,6 +287,128 @@ ExactValue exact_value_to_float(ExactValue v) {
return r;
}
ExactValue exact_value_to_complex(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_complex(cast(i64)v.value_integer, 0);
case ExactValue_Float:
return exact_value_complex(v.value_float, 0);
case ExactValue_Complex:
return v;
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_to_quaternion(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(cast(i64)v.value_integer, 0, 0, 0);
case ExactValue_Float:
return exact_value_quaternion(v.value_float, 0, 0, 0);
case ExactValue_Complex:
return exact_value_quaternion(v.value_complex.real, v.value_complex.imag, 0, 0);
case ExactValue_Quaternion:
return v;
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_real(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
return v;
case ExactValue_Complex:
return exact_value_float(v.value_complex.real);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.real);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_imag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
return exact_value_integer(0);
case ExactValue_Complex:
return exact_value_float(v.value_complex.imag);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.imag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
return exact_value_integer(0);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.jmag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
return exact_value_integer(0);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.kmag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_make_imag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_complex(0, exact_value_to_float(v).value_float);
case ExactValue_Float:
return exact_value_complex(0, v.value_float);
default:
GB_PANIC("Expected an integer or float type for `exact_value_make_imag`");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_make_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
case ExactValue_Float:
return exact_value_quaternion(0, 0, v.value_float, 0);
default:
GB_PANIC("Expected an integer or float type for `exact_value_make_jmag`");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_make_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
case ExactValue_Float:
return exact_value_quaternion(0, 0, 0, v.value_float);
default:
GB_PANIC("Expected an integer or float type for `exact_value_make_kmag`");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) {
switch (op) {
@@ -155,6 +417,8 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
case ExactValue_Invalid:
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
case ExactValue_Quaternion:
return v;
}
} break;
@@ -173,6 +437,18 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
i.value_float = -i.value_float;
return i;
}
case ExactValue_Complex: {
f64 real = v.value_complex.real;
f64 imag = v.value_complex.imag;
return exact_value_complex(-real, -imag);
}
case ExactValue_Quaternion: {
f64 real = v.value_quaternion.real;
f64 imag = v.value_quaternion.imag;
f64 jmag = v.value_quaternion.jmag;
f64 kmag = v.value_quaternion.kmag;
return exact_value_quaternion(-real, -imag, -jmag, -kmag);
}
}
} break;
@@ -182,8 +458,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
case ExactValue_Invalid:
return v;
case ExactValue_Integer:
i = v.value_integer;
i = ~i;
i = ~v.value_integer;
break;
default:
goto failure;
@@ -191,17 +466,19 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
// NOTE(bill): unsigned integers will be negative and will need to be
// limited to the types precision
if (precision > 0)
// IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored
if (0 < precision && precision < 64) {
i &= ~((~0ll)<<precision);
}
return make_exact_value_integer(i);
return exact_value_integer(i);
} break;
case Token_Not: {
switch (v.kind) {
case ExactValue_Invalid: return v;
case ExactValue_Bool:
return make_exact_value_bool(!v.value_bool);
return exact_value_bool(!v.value_bool);
}
} break;
}
@@ -225,8 +502,12 @@ i32 exact_value_order(ExactValue v) {
return 2;
case ExactValue_Float:
return 3;
case ExactValue_Pointer:
case ExactValue_Complex:
return 4;
case ExactValue_Quaternion:
return 5;
case ExactValue_Pointer:
return 6;
default:
GB_PANIC("How'd you get here? Invalid Value.kind");
@@ -247,6 +528,8 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Bool:
case ExactValue_String:
case ExactValue_Complex:
case ExactValue_Quaternion:
return;
case ExactValue_Integer:
@@ -255,18 +538,32 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
return;
case ExactValue_Float:
// TODO(bill): Is this good enough?
*x = make_exact_value_float(cast(f64)x->value_integer);
*x = exact_value_float(cast(f64)x->value_integer);
return;
case ExactValue_Complex:
*x = exact_value_complex(cast(f64)x->value_integer, 0);
return;
case ExactValue_Quaternion:
*x = exact_value_quaternion(cast(f64)x->value_integer, 0, 0, 0);
return;
}
break;
case ExactValue_Float:
if (y->kind == ExactValue_Float)
switch (y->kind) {
case ExactValue_Float:
return;
case ExactValue_Complex:
*x = exact_value_to_complex(*x);
return;
case ExactValue_Quaternion:
*x = exact_value_to_quaternion(*x);
return;
}
break;
}
compiler_error("How'd you get here? Invalid ExactValueKind");
compiler_error("match_exact_values: How'd you get here? Invalid ExactValueKind %d", x->kind);
}
// TODO(bill): Allow for pointer arithmetic? Or are pointer slices good enough?
@@ -279,10 +576,10 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
case ExactValue_Bool:
switch (op) {
case Token_CmpAnd: return make_exact_value_bool(x.value_bool && y.value_bool);
case Token_CmpOr: return make_exact_value_bool(x.value_bool || y.value_bool);
case Token_And: return make_exact_value_bool(x.value_bool & y.value_bool);
case Token_Or: return make_exact_value_bool(x.value_bool | y.value_bool);
case Token_CmpAnd: return exact_value_bool(x.value_bool && y.value_bool);
case Token_CmpOr: return exact_value_bool(x.value_bool || y.value_bool);
case Token_And: return exact_value_bool(x.value_bool & y.value_bool);
case Token_Or: return exact_value_bool(x.value_bool | y.value_bool);
default: goto error;
}
break;
@@ -295,7 +592,7 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
case Token_Add: c = a + b; break;
case Token_Sub: c = a - b; break;
case Token_Mul: c = a * b; break;
case Token_Quo: return make_exact_value_float(fmod(cast(f64)a, cast(f64)b));
case Token_Quo: return exact_value_float(fmod(cast(f64)a, cast(f64)b));
case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division
case Token_Mod: c = a % b; break;
case Token_And: c = a & b; break;
@@ -307,23 +604,102 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
default: goto error;
}
return make_exact_value_integer(c);
return exact_value_integer(c);
} break;
case ExactValue_Float: {
f64 a = x.value_float;
f64 b = y.value_float;
switch (op) {
case Token_Add: return make_exact_value_float(a + b);
case Token_Sub: return make_exact_value_float(a - b);
case Token_Mul: return make_exact_value_float(a * b);
case Token_Quo: return make_exact_value_float(a / b);
case Token_Add: return exact_value_float(a + b);
case Token_Sub: return exact_value_float(a - b);
case Token_Mul: return exact_value_float(a * b);
case Token_Quo: return exact_value_float(a / b);
default: goto error;
}
} break;
case ExactValue_Complex: {
y = exact_value_to_complex(y);
f64 a = x.value_complex.real;
f64 b = x.value_complex.imag;
f64 c = y.value_complex.real;
f64 d = y.value_complex.imag;
f64 real = 0;
f64 imag = 0;
switch (op) {
case Token_Add:
real = a + c;
imag = b + d;
break;
case Token_Sub:
real = a - c;
imag = b - d;
break;
case Token_Mul:
real = (a*c - b*d);
imag = (b*c + a*d);
break;
case Token_Quo: {
f64 s = c*c + d*d;
real = (a*c + b*d)/s;
imag = (b*c - a*d)/s;
} break;
default: goto error;
}
return exact_value_complex(real, imag);
} break;
case ExactValue_Quaternion: {
y = exact_value_to_quaternion(y);
f64 a = x.value_quaternion.real;
f64 b = x.value_quaternion.imag;
f64 c = x.value_quaternion.jmag;
f64 d = x.value_quaternion.kmag;
f64 e = x.value_quaternion.real;
f64 f = x.value_quaternion.imag;
f64 g = x.value_quaternion.jmag;
f64 h = x.value_quaternion.kmag;
f64 real = 0;
f64 imag = 0;
f64 jmag = 0;
f64 kmag = 0;
switch (op) {
case Token_Add:
real = a + e;
imag = b + f;
jmag = c + g;
kmag = d + h;
break;
case Token_Sub:
real = a - e;
imag = b - f;
jmag = c - g;
kmag = d - h;
break;
case Token_Mul:
real = a*f + b*e + c*h - d*g;
imag = a*g - b*h + c*e + d*f;
jmag = a*h + b*g - c*f + d*e;
kmag = a*e - b*f - c*g - d*h;
break;
case Token_Quo: {
f64 s = e*e + f*f + g*g + h*h;
real = (+a*e + b*f + c*g + d*h)/s;
imag = (-a*f + b*e - c*h + d*h)/s;
jmag = (-a*g + b*h + c*e - d*f)/s;
kmag = (-a*h - b*g + c*f + d*e)/s;
} break;
default: goto error;
}
return exact_value_quaternion(real, imag, jmag, kmag);
} break;
}
error:
; // MSVC accepts this??? apparently you cannot declare variables immediately after labels...
ExactValue error_value = {0};
// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
return error_value;
@@ -380,6 +756,34 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
}
} break;
case ExactValue_Complex: {
f64 a = x.value_complex.real;
f64 b = x.value_complex.imag;
f64 c = y.value_complex.real;
f64 d = y.value_complex.imag;
switch (op) {
case Token_CmpEq: return cmp_f64(a, c) == 0 && cmp_f64(b, d) == 0;
case Token_NotEq: return cmp_f64(a, c) != 0 || cmp_f64(b, d) != 0;
}
} break;
case ExactValue_Quaternion: {
f64 a = x.value_quaternion.real;
f64 b = x.value_quaternion.imag;
f64 c = x.value_quaternion.jmag;
f64 d = x.value_quaternion.kmag;
f64 e = y.value_quaternion.real;
f64 f = y.value_quaternion.imag;
f64 g = y.value_quaternion.jmag;
f64 h = y.value_quaternion.kmag;
switch (op) {
case Token_CmpEq: return cmp_f64(a, e) == 0 && cmp_f64(b, f) == 0 && cmp_f64(c, g) == 0 && cmp_f64(d, h) == 0;
case Token_NotEq: return cmp_f64(a, e) != 0 || cmp_f64(b, f) != 0 || cmp_f64(c, g) != 0 || cmp_f64(d, h) != 0;
}
} break;
case ExactValue_String: {
String a = x.value_string;
String b = y.value_string;
+538 -169
View File
File diff suppressed because it is too large Load Diff
+7853
View File
File diff suppressed because it is too large Load Diff
+125 -128
View File
@@ -1,93 +1,90 @@
// Optimizations for the LLIR code
// Optimizations for the IR code
void llir_opt_add_operands(llirValueArray *ops, llirInstr *i) {
void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
switch (i->kind) {
case llirInstr_Comment:
case irInstr_Comment:
break;
case llirInstr_Local:
case irInstr_Local:
break;
case llirInstr_ZeroInit:
case irInstr_ZeroInit:
array_add(ops, i->ZeroInit.address);
break;
case llirInstr_Store:
case irInstr_Store:
array_add(ops, i->Store.address);
array_add(ops, i->Store.value);
break;
case llirInstr_Load:
case irInstr_Load:
array_add(ops, i->Load.address);
break;
case llirInstr_ArrayElementPtr:
case irInstr_ArrayElementPtr:
array_add(ops, i->ArrayElementPtr.address);
array_add(ops, i->ArrayElementPtr.elem_index);
break;
case llirInstr_StructElementPtr:
case irInstr_StructElementPtr:
array_add(ops, i->StructElementPtr.address);
break;
case llirInstr_PtrOffset:
case irInstr_PtrOffset:
array_add(ops, i->PtrOffset.address);
array_add(ops, i->PtrOffset.offset);
break;
case llirInstr_ArrayExtractValue:
array_add(ops, i->ArrayExtractValue.address);
break;
case llirInstr_StructExtractValue:
case irInstr_StructExtractValue:
array_add(ops, i->StructExtractValue.address);
break;
case llirInstr_Conv:
case irInstr_Conv:
array_add(ops, i->Conv.value);
break;
case llirInstr_Jump:
case irInstr_Jump:
break;
case llirInstr_If:
case irInstr_If:
array_add(ops, i->If.cond);
break;
case llirInstr_Return:
case irInstr_Return:
if (i->Return.value != NULL) {
array_add(ops, i->Return.value);
}
break;
case llirInstr_Select:
case irInstr_Select:
array_add(ops, i->Select.cond);
break;
case llirInstr_Phi:
case irInstr_Phi:
for_array(j, i->Phi.edges) {
array_add(ops, i->Phi.edges.e[j]);
}
break;
case llirInstr_Unreachable:
case irInstr_Unreachable:
break;
case llirInstr_UnaryOp:
case irInstr_UnaryOp:
array_add(ops, i->UnaryOp.expr);
break;
case llirInstr_BinaryOp:
case irInstr_BinaryOp:
array_add(ops, i->BinaryOp.left);
array_add(ops, i->BinaryOp.right);
break;
case llirInstr_Call:
case irInstr_Call:
array_add(ops, i->Call.value);
for (isize j = 0; j < i->Call.arg_count; j++) {
array_add(ops, i->Call.args[j]);
}
break;
case llirInstr_VectorExtractElement:
array_add(ops, i->VectorExtractElement.vector);
array_add(ops, i->VectorExtractElement.index);
// case irInstr_VectorExtractElement:
// array_add(ops, i->VectorExtractElement.vector);
// array_add(ops, i->VectorExtractElement.index);
// break;
// case irInstr_VectorInsertElement:
// array_add(ops, i->VectorInsertElement.vector);
// array_add(ops, i->VectorInsertElement.elem);
// array_add(ops, i->VectorInsertElement.index);
// break;
// case irInstr_VectorShuffle:
// array_add(ops, i->VectorShuffle.vector);
// break;
case irInstr_StartupRuntime:
break;
case llirInstr_VectorInsertElement:
array_add(ops, i->VectorInsertElement.vector);
array_add(ops, i->VectorInsertElement.elem);
array_add(ops, i->VectorInsertElement.index);
break;
case llirInstr_VectorShuffle:
array_add(ops, i->VectorShuffle.vector);
break;
case llirInstr_StartupRuntime:
break;
case llirInstr_BoundsCheck:
case irInstr_BoundsCheck:
array_add(ops, i->BoundsCheck.index);
array_add(ops, i->BoundsCheck.len);
break;
case llirInstr_SliceBoundsCheck:
case irInstr_SliceBoundsCheck:
array_add(ops, i->SliceBoundsCheck.low);
array_add(ops, i->SliceBoundsCheck.high);
break;
@@ -98,26 +95,26 @@ void llir_opt_add_operands(llirValueArray *ops, llirInstr *i) {
void llir_opt_block_replace_pred(llirBlock *b, llirBlock *from, llirBlock *to) {
void ir_opt_block_replace_pred(irBlock *b, irBlock *from, irBlock *to) {
for_array(i, b->preds) {
llirBlock *pred = b->preds.e[i];
irBlock *pred = b->preds.e[i];
if (pred == from) {
b->preds.e[i] = to;
}
}
}
void llir_opt_block_replace_succ(llirBlock *b, llirBlock *from, llirBlock *to) {
void ir_opt_block_replace_succ(irBlock *b, irBlock *from, irBlock *to) {
for_array(i, b->succs) {
llirBlock *succ = b->succs.e[i];
irBlock *succ = b->succs.e[i];
if (succ == from) {
b->succs.e[i] = to;
}
}
}
bool llir_opt_block_has_phi(llirBlock *b) {
return b->instrs.e[0]->Instr.kind == llirInstr_Phi;
bool ir_opt_block_has_phi(irBlock *b) {
return b->instrs.e[0]->Instr.kind == irInstr_Phi;
}
@@ -129,11 +126,11 @@ bool llir_opt_block_has_phi(llirBlock *b) {
llirValueArray llir_get_block_phi_nodes(llirBlock *b) {
llirValueArray phis = {0};
irValueArray ir_get_block_phi_nodes(irBlock *b) {
irValueArray phis = {0};
for_array(i, b->instrs) {
llirInstr *instr = &b->instrs.e[i]->Instr;
if (instr->kind != llirInstr_Phi) {
irInstr *instr = &b->instrs.e[i]->Instr;
if (instr->kind != irInstr_Phi) {
phis = b->instrs;
phis.count = i;
return phis;
@@ -142,15 +139,15 @@ llirValueArray llir_get_block_phi_nodes(llirBlock *b) {
return phis;
}
void llir_remove_pred(llirBlock *b, llirBlock *p) {
llirValueArray phis = llir_get_block_phi_nodes(b);
void ir_remove_pred(irBlock *b, irBlock *p) {
irValueArray phis = ir_get_block_phi_nodes(b);
isize i = 0;
for_array(j, b->preds) {
llirBlock *pred = b->preds.e[j];
irBlock *pred = b->preds.e[j];
if (pred != p) {
b->preds.e[i] = b->preds.e[j];
for_array(k, phis) {
llirInstrPhi *phi = &phis.e[k]->Instr.Phi;
irInstrPhi *phi = &phis.e[k]->Instr.Phi;
phi->edges.e[i] = phi->edges.e[j];
}
i++;
@@ -158,16 +155,16 @@ void llir_remove_pred(llirBlock *b, llirBlock *p) {
}
b->preds.count = i;
for_array(k, phis) {
llirInstrPhi *phi = &phis.e[k]->Instr.Phi;
irInstrPhi *phi = &phis.e[k]->Instr.Phi;
phi->edges.count = i;
}
}
void llir_remove_dead_blocks(llirProcedure *proc) {
void ir_remove_dead_blocks(irProcedure *proc) {
isize j = 0;
for_array(i, proc->blocks) {
llirBlock *b = proc->blocks.e[i];
irBlock *b = proc->blocks.e[i];
if (b == NULL) {
continue;
}
@@ -178,34 +175,34 @@ void llir_remove_dead_blocks(llirProcedure *proc) {
proc->blocks.count = j;
}
void llir_mark_reachable(llirBlock *b) {
void ir_mark_reachable(irBlock *b) {
isize const WHITE = 0;
isize const BLACK = -1;
b->index = BLACK;
for_array(i, b->succs) {
llirBlock *succ = b->succs.e[i];
irBlock *succ = b->succs.e[i];
if (succ->index == WHITE) {
llir_mark_reachable(succ);
ir_mark_reachable(succ);
}
}
}
void llir_remove_unreachable_blocks(llirProcedure *proc) {
void ir_remove_unreachable_blocks(irProcedure *proc) {
isize const WHITE = 0;
isize const BLACK = -1;
for_array(i, proc->blocks) {
proc->blocks.e[i]->index = WHITE;
}
llir_mark_reachable(proc->blocks.e[0]);
ir_mark_reachable(proc->blocks.e[0]);
for_array(i, proc->blocks) {
llirBlock *b = proc->blocks.e[i];
irBlock *b = proc->blocks.e[i];
if (b->index == WHITE) {
for_array(j, b->succs) {
llirBlock *c = b->succs.e[j];
irBlock *c = b->succs.e[j];
if (c->index == BLACK) {
llir_remove_pred(c, b);
ir_remove_pred(c, b);
}
}
// NOTE(bill): Mark as empty but don't actually free it
@@ -213,26 +210,26 @@ void llir_remove_unreachable_blocks(llirProcedure *proc) {
proc->blocks.e[i] = NULL;
}
}
llir_remove_dead_blocks(proc);
ir_remove_dead_blocks(proc);
}
bool llir_opt_block_fusion(llirProcedure *proc, llirBlock *a) {
bool ir_opt_block_fusion(irProcedure *proc, irBlock *a) {
if (a->succs.count != 1) {
return false;
}
llirBlock *b = a->succs.e[0];
irBlock *b = a->succs.e[0];
if (b->preds.count != 1) {
return false;
}
if (llir_opt_block_has_phi(b)) {
if (ir_opt_block_has_phi(b)) {
return false;
}
array_pop(&a->instrs); // Remove branch at end
for_array(i, b->instrs) {
array_add(&a->instrs, b->instrs.e[i]);
llir_set_instr_parent(b->instrs.e[i], a);
ir_set_instr_parent(b->instrs.e[i], a);
}
array_clear(&a->succs);
@@ -242,28 +239,28 @@ bool llir_opt_block_fusion(llirProcedure *proc, llirBlock *a) {
// Fix preds links
for_array(i, b->succs) {
llir_opt_block_replace_pred(b->succs.e[i], b, a);
ir_opt_block_replace_pred(b->succs.e[i], b, a);
}
proc->blocks.e[b->index] = NULL;
return true;
}
void llir_opt_blocks(llirProcedure *proc) {
llir_remove_unreachable_blocks(proc);
void ir_opt_blocks(irProcedure *proc) {
ir_remove_unreachable_blocks(proc);
#if 1
bool changed = true;
while (changed) {
changed = false;
for_array(i, proc->blocks) {
llirBlock *b = proc->blocks.e[i];
irBlock *b = proc->blocks.e[i];
if (b == NULL) {
continue;
}
GB_ASSERT(b->index == i);
GB_ASSERT_MSG(b->index == i, "%d, %td", b->index, i);
if (llir_opt_block_fusion(proc, b)) {
if (ir_opt_block_fusion(proc, b)) {
changed = true;
}
// TODO(bill): other simple block optimizations
@@ -271,25 +268,25 @@ void llir_opt_blocks(llirProcedure *proc) {
}
#endif
llir_remove_dead_blocks(proc);
ir_remove_dead_blocks(proc);
}
void llir_opt_build_referrers(llirProcedure *proc) {
void ir_opt_build_referrers(irProcedure *proc) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
llirValueArray ops = {0}; // NOTE(bill): Act as a buffer
irValueArray ops = {0}; // NOTE(bill): Act as a buffer
array_init_reserve(&ops, proc->module->tmp_allocator, 64); // HACK(bill): This _could_ overflow the temp arena
for_array(i, proc->blocks) {
llirBlock *b = proc->blocks.e[i];
irBlock *b = proc->blocks.e[i];
for_array(j, b->instrs) {
llirValue *instr = b->instrs.e[j];
irValue *instr = b->instrs.e[j];
array_clear(&ops);
llir_opt_add_operands(&ops, &instr->Instr);
ir_opt_add_operands(&ops, &instr->Instr);
for_array(k, ops) {
llirValue *op = ops.e[k];
irValue *op = ops.e[k];
if (op == NULL) {
continue;
}
llirValueArray *refs = llir_value_referrers(op);
irValueArray *refs = ir_value_referrers(op);
if (refs != NULL) {
array_add(refs, instr);
}
@@ -308,36 +305,36 @@ void llir_opt_build_referrers(llirProcedure *proc) {
// State of Lengauer-Tarjan algorithm
// Based on this paper: http://jgaa.info/accepted/2006/GeorgiadisTarjanWerneck2006.10.1.pdf
typedef struct llirLTState {
typedef struct irLTState {
isize count;
// NOTE(bill): These are arrays
llirBlock **sdom; // Semidominator
llirBlock **parent; // Parent in DFS traversal of CFG
llirBlock **ancestor;
} llirLTState;
irBlock **sdom; // Semidominator
irBlock **parent; // Parent in DFS traversal of CFG
irBlock **ancestor;
} irLTState;
// §2.2 - bottom of page
void llir_lt_link(llirLTState *lt, llirBlock *p, llirBlock *q) {
void ir_lt_link(irLTState *lt, irBlock *p, irBlock *q) {
lt->ancestor[q->index] = p;
}
i32 llir_lt_depth_first_search(llirLTState *lt, llirBlock *p, i32 i, llirBlock **preorder) {
i32 ir_lt_depth_first_search(irLTState *lt, irBlock *p, i32 i, irBlock **preorder) {
preorder[i] = p;
p->dom.pre = i++;
lt->sdom[p->index] = p;
llir_lt_link(lt, NULL, p);
ir_lt_link(lt, NULL, p);
for_array(index, p->succs) {
llirBlock *q = p->succs.e[index];
irBlock *q = p->succs.e[index];
if (lt->sdom[q->index] == NULL) {
lt->parent[q->index] = p;
i = llir_lt_depth_first_search(lt, q, i, preorder);
i = ir_lt_depth_first_search(lt, q, i, preorder);
}
}
return i;
}
llirBlock *llir_lt_eval(llirLTState *lt, llirBlock *v) {
llirBlock *u = v;
irBlock *ir_lt_eval(irLTState *lt, irBlock *v) {
irBlock *u = v;
for (;
lt->ancestor[v->index] != NULL;
v = lt->ancestor[v->index]) {
@@ -348,16 +345,16 @@ llirBlock *llir_lt_eval(llirLTState *lt, llirBlock *v) {
return u;
}
typedef struct llirDomPrePost {
typedef struct irDomPrePost {
i32 pre, post;
} llirDomPrePost;
} irDomPrePost;
llirDomPrePost llir_opt_number_dom_tree(llirBlock *v, i32 pre, i32 post) {
llirDomPrePost result = {pre, post};
irDomPrePost ir_opt_number_dom_tree(irBlock *v, i32 pre, i32 post) {
irDomPrePost result = {pre, post};
v->dom.pre = pre++;
for_array(i, v->dom.children) {
result = llir_opt_number_dom_tree(v->dom.children.e[i], result.pre, result.post);
result = ir_opt_number_dom_tree(v->dom.children.e[i], result.pre, result.post);
}
v->dom.post = post++;
@@ -367,35 +364,35 @@ llirDomPrePost llir_opt_number_dom_tree(llirBlock *v, i32 pre, i32 post) {
}
// NOTE(bill): Requires `llir_opt_blocks` to be called before this
void llir_opt_build_dom_tree(llirProcedure *proc) {
// NOTE(bill): Requires `ir_opt_blocks` to be called before this
void ir_opt_build_dom_tree(irProcedure *proc) {
// Based on this paper: http://jgaa.info/accepted/2006/GeorgiadisTarjanWerneck2006.10.1.pdf
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
isize n = proc->blocks.count;
llirBlock **buf = gb_alloc_array(proc->module->tmp_allocator, llirBlock *, 5*n);
irBlock **buf = gb_alloc_array(proc->module->tmp_allocator, irBlock *, 5*n);
llirLTState lt = {0};
irLTState lt = {0};
lt.count = n;
lt.sdom = &buf[0*n];
lt.parent = &buf[1*n];
lt.ancestor = &buf[2*n];
llirBlock **preorder = &buf[3*n];
llirBlock **buckets = &buf[4*n];
llirBlock *root = proc->blocks.e[0];
irBlock **preorder = &buf[3*n];
irBlock **buckets = &buf[4*n];
irBlock *root = proc->blocks.e[0];
// Step 1 - number vertices
i32 pre_num = llir_lt_depth_first_search(&lt, root, 0, preorder);
i32 pre_num = ir_lt_depth_first_search(&lt, root, 0, preorder);
gb_memmove(buckets, preorder, n*gb_size_of(preorder[0]));
for (i32 i = n-1; i > 0; i--) {
llirBlock *w = preorder[i];
irBlock *w = preorder[i];
// Step 3 - Implicitly define idom for nodes
for (llirBlock *v = buckets[i]; v != w; v = buckets[v->dom.pre]) {
llirBlock *u = llir_lt_eval(&lt, v);
for (irBlock *v = buckets[i]; v != w; v = buckets[v->dom.pre]) {
irBlock *u = ir_lt_eval(&lt, v);
if (lt.sdom[u->index]->dom.pre < i) {
v->dom.idom = u;
} else {
@@ -406,14 +403,14 @@ void llir_opt_build_dom_tree(llirProcedure *proc) {
// Step 2 - Compute all sdoms
lt.sdom[w->index] = lt.parent[w->index];
for_array(pred_index, w->preds) {
llirBlock *v = w->preds.e[pred_index];
llirBlock *u = llir_lt_eval(&lt, v);
irBlock *v = w->preds.e[pred_index];
irBlock *u = ir_lt_eval(&lt, v);
if (lt.sdom[u->index]->dom.pre < lt.sdom[w->index]->dom.pre) {
lt.sdom[w->index] = lt.sdom[u->index];
}
}
llir_lt_link(&lt, lt.parent[w->index], w);
ir_lt_link(&lt, lt.parent[w->index], w);
if (lt.parent[w->index] == lt.sdom[w->index]) {
w->dom.idom = lt.parent[w->index];
@@ -424,13 +421,13 @@ void llir_opt_build_dom_tree(llirProcedure *proc) {
}
// The rest of Step 3
for (llirBlock *v = buckets[0]; v != root; v = buckets[v->dom.pre]) {
for (irBlock *v = buckets[0]; v != root; v = buckets[v->dom.pre]) {
v->dom.idom = root;
}
// Step 4 - Explicitly define idom for nodes (in preorder)
for (isize i = 1; i < n; i++) {
llirBlock *w = preorder[i];
irBlock *w = preorder[i];
if (w == root) {
w->dom.idom = NULL;
} else {
@@ -449,32 +446,32 @@ void llir_opt_build_dom_tree(llirProcedure *proc) {
}
}
llir_opt_number_dom_tree(root, 0, 0);
ir_opt_number_dom_tree(root, 0, 0);
gb_temp_arena_memory_end(tmp);
}
void llir_opt_mem2reg(llirProcedure *proc) {
// TODO(bill): llir_opt_mem2reg
void ir_opt_mem2reg(irProcedure *proc) {
// TODO(bill): ir_opt_mem2reg
}
void llir_opt_tree(llirGen *s) {
void ir_opt_tree(irGen *s) {
s->opt_called = true;
for_array(member_index, s->module.procs) {
llirProcedure *proc = s->module.procs.e[member_index];
irProcedure *proc = s->module.procs.e[member_index];
if (proc->blocks.count == 0) { // Prototype/external procedure
continue;
}
llir_opt_blocks(proc);
#if 1
llir_opt_build_referrers(proc);
llir_opt_build_dom_tree(proc);
ir_opt_blocks(proc);
#if 0
ir_opt_build_referrers(proc);
ir_opt_build_dom_tree(proc);
// TODO(bill): llir optimization
// TODO(bill): ir optimization
// [ ] cse (common-subexpression) elim
// [ ] copy elim
// [ ] dead code elim
@@ -485,10 +482,10 @@ void llir_opt_tree(llirGen *s) {
// [ ] lift/mem2reg
// [ ] lift/mem2reg
llir_opt_mem2reg(proc);
ir_opt_mem2reg(proc);
#endif
GB_ASSERT(proc->blocks.count > 0);
llir_number_proc_registers(proc);
ir_number_proc_registers(proc);
}
}
+1776
View File
File diff suppressed because it is too large Load Diff
-5794
View File
File diff suppressed because it is too large Load Diff
-1515
View File
File diff suppressed because it is too large Load Diff
+235 -40
View File
@@ -2,21 +2,23 @@
extern "C" {
#endif
#define USE_CUSTOM_BACKEND false
#include "common.c"
#include "timings.c"
#include "unicode.c"
#include "build.c"
#include "build_settings.c"
#include "tokenizer.c"
#include "parser.c"
// #include "printer.c"
#include "checker/checker.c"
#include "llir.c"
#include "llir_opt.c"
#include "llir_print.c"
#include "checker.c"
#include "ssa.c"
#include "ir.c"
#include "ir_opt.c"
#include "ir_print.c"
// #include "vm.c"
#if defined(GB_SYSTEM_WINDOWS)
// NOTE(bill): `name` is used in debugging and profiling modes
i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
PROCESS_INFORMATION pi = {0};
char cmd_line[4096] = {0};
@@ -58,6 +60,56 @@ i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
gb_temp_arena_memory_end(tmp);
return exit_code;
}
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
char cmd_line[4096] = {0};
isize cmd_len;
va_list va;
String cmd;
i32 exit_code = 0;
va_start(va, fmt);
cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
va_end(va);
cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
exit_code = system(&cmd_line[0]);
// pid_t pid = fork();
// int status = 0;
// if(pid == 0) {
// // in child, pid == 0.
// int ret = execvp(cmd.text, (char* const*) cmd.text);
// if(ret == -1) {
// gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
// // we're in the child, so returning won't do us any good -- just quit.
// exit(-1);
// }
// // unreachable
// abort();
// } else {
// // wait for child to finish, then we can continue cleanup
// int s = 0;
// waitpid(pid, &s, 0);
// status = WEXITSTATUS(s);
// }
// exit_code = status;
return exit_code;
}
#endif
void print_usage_line(i32 indent, char *fmt, ...) {
while (indent --> 0) {
@@ -91,14 +143,15 @@ int main(int argc, char **argv) {
timings_init(&timings, str_lit("Total Time"), 128);
// defer (timings_destroy(&timings));
init_string_buffer_memory();
init_scratch_memory(gb_megabytes(10));
init_global_error_collector();
#if 1
BuildContext build_context = {0};
init_build_context(&build_context);
init_build_context();
init_universal_scope(&build_context);
init_universal_scope();
char *init_filename = NULL;
bool run_output = false;
@@ -158,39 +211,52 @@ int main(int argc, char **argv) {
#endif
#if 1
llirGen llir = {0};
if (!llir_gen_init(&llir, &checker, &build_context)) {
#if USE_CUSTOM_BACKEND
if (global_error_collector.count != 0) {
return 1;
}
// defer (ssa_gen_destroy(&llir));
if (checker.parser->total_token_count < 2) {
return 1;
}
if (!ssa_generate(&parser, &checker.info)) {
return 1;
}
#else
irGen ir_gen = {0};
if (!ir_gen_init(&ir_gen, &checker)) {
return 1;
}
// defer (ssa_gen_destroy(&ir_gen));
timings_start_section(&timings, str_lit("llvm ir gen"));
llir_gen_tree(&llir);
ir_gen_tree(&ir_gen);
timings_start_section(&timings, str_lit("llvm ir opt tree"));
llir_opt_tree(&llir);
ir_opt_tree(&ir_gen);
timings_start_section(&timings, str_lit("llvm ir print"));
print_llvm_ir(&llir);
print_llvm_ir(&ir_gen);
// prof_print_all();
#if 1
#if 1
timings_start_section(&timings, str_lit("llvm-opt"));
char const *output_name = llir.output_file.filename;
isize base_name_len = gb_path_extension(output_name)-1 - output_name;
String output = make_string(cast(u8 *)output_name, base_name_len);
String output_name = ir_gen.output_name;
String output_base = ir_gen.output_base;
int base_name_len = output_base.len;
i32 optimization_level = 0;
optimization_level = gb_clamp(optimization_level, 0, 3);
i32 exit_code = 0;
#if defined(GB_SYSTEM_WINDOWS)
// For more passes arguments: http://llvm.org/docs/Passes.html
exit_code = win32_exec_command_line_app("llvm-opt", false,
"%.*sbin/opt %s -o %.*s.bc "
exit_code = system_exec_command_line_app("llvm-opt", false,
"\"%.*sbin/opt\" \"%.*s\".ll -o \"%.*s\".bc "
"-mem2reg "
"-memcpyopt "
"-die "
@@ -199,21 +265,44 @@ int main(int argc, char **argv) {
// "-S "
"",
LIT(build_context.ODIN_ROOT),
output_name, LIT(output));
LIT(output_base), LIT(output_base));
if (exit_code != 0) {
return exit_code;
}
#else
// NOTE(zangent): This is separate because it seems that LLVM tools are packaged
// with the Windows version, while they will be system-provided on MacOS and GNU/Linux
exit_code = system_exec_command_line_app("llvm-opt", false,
"opt \"%.*s\".ll -o \"%.*s\".bc "
"-mem2reg "
"-memcpyopt "
"-die "
#if defined(GB_SYSTEM_OSX)
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
// make sure to also change the `macosx_version_min` param passed to `llc`
"-mtriple=x86_64-apple-macosx10.8 "
#endif
// "-dse "
// "-dce "
// "-S "
"",
LIT(output_base), LIT(output_base));
if (exit_code != 0) {
return exit_code;
}
#endif
#if 1
#if defined(GB_SYSTEM_WINDOWS)
timings_start_section(&timings, str_lit("llvm-llc"));
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
exit_code = win32_exec_command_line_app("llvm-llc", false,
"%.*sbin/llc %.*s.bc -filetype=obj -O%d "
exit_code = system_exec_command_line_app("llvm-llc", false,
"\"%.*sbin/llc\" \"%.*s.bc\" -filetype=obj -O%d "
"%.*s "
// "-debug-pass=Arguments "
"",
LIT(build_context.ODIN_ROOT),
LIT(output),
LIT(output_base),
optimization_level,
LIT(build_context.llc_flags));
if (exit_code != 0) {
@@ -222,13 +311,14 @@ int main(int argc, char **argv) {
timings_start_section(&timings, str_lit("msvc-link"));
gbString lib_str = gb_string_make(heap_allocator(), "Kernel32.lib");
gbString lib_str = gb_string_make(heap_allocator(), "");
// defer (gb_string_free(lib_str));
char lib_str_buf[1024] = {0};
for_array(i, checker.info.foreign_libraries) {
String lib = checker.info.foreign_libraries.e[i];
for_array(i, ir_gen.module.foreign_library_paths) {
String lib = ir_gen.module.foreign_library_paths.e[i];
// gb_printf_err("Linking lib: %.*s\n", LIT(lib));
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" %.*s.lib", LIT(lib));
" \"%.*s\"", LIT(lib));
lib_str = gb_string_appendc(lib_str, lib_str_buf);
}
@@ -237,16 +327,18 @@ int main(int argc, char **argv) {
if (build_context.is_dll) {
output_ext = "dll";
link_settings = "/DLL";
} else {
link_settings = "/ENTRY:mainCRTStartup";
}
exit_code = win32_exec_command_line_app("msvc-link", true,
"link %.*s.obj -OUT:%.*s.%s %s "
exit_code = system_exec_command_line_app("msvc-link", true,
"link \"%.*s\".obj -OUT:\"%.*s.%s\" %s "
"/defaultlib:libcmt "
"/nologo /incremental:no /opt:ref /subsystem:WINDOWS "
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
" %.*s "
" %s "
"",
LIT(output), LIT(output), output_ext,
LIT(output_base), LIT(output_base), output_ext,
lib_str, LIT(build_context.link_flags),
link_settings
);
@@ -257,14 +349,117 @@ int main(int argc, char **argv) {
// timings_print_all(&timings);
if (run_output) {
win32_exec_command_line_app("odin run", false, "%.*s.exe", cast(int)base_name_len, output_name);
system_exec_command_line_app("odin run", false, "%.*s.exe", LIT(output_base));
}
#else
// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
timings_start_section(&timings, str_lit("llvm-llc"));
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
exit_code = system_exec_command_line_app("llc", false,
"llc \"%.*s.bc\" -filetype=obj -O%d "
"%.*s "
// "-debug-pass=Arguments "
"",
LIT(output_base),
optimization_level,
LIT(build_context.llc_flags));
if (exit_code != 0) {
return exit_code;
}
timings_start_section(&timings, str_lit("ld-link"));
gbString lib_str = gb_string_make(heap_allocator(), "");
// defer (gb_string_free(lib_str));
char lib_str_buf[1024] = {0};
for_array(i, ir_gen.module.foreign_library_paths) {
String lib = ir_gen.module.foreign_library_paths.e[i];
// NOTE(zangent): Sometimes, you have to use -framework on MacOS.
// This allows you to specify '-f' in a #foreign_system_library,
// without having to implement any new syntax specifically for MacOS.
#if defined(GB_SYSTEM_OSX)
isize len;
if(lib.len > 2 && lib.text[0] == '-' && lib.text[1] == 'f') {
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
} else {
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" -l%.*s ", LIT(lib));
}
#else
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" -l%.*s ", LIT(lib));
#endif
lib_str = gb_string_appendc(lib_str, lib_str_buf);
}
// Unlike the Win32 linker code, the output_ext includes the dot, because
// typically executable files on *NIX systems don't have extensions.
char *output_ext = "";
char *link_settings = "";
char *linker;
if (build_context.is_dll) {
// Shared libraries are .dylib on MacOS and .so on Linux.
// TODO(zangent): Is that statement entirely truthful?
#if defined(GB_SYSTEM_OSX)
output_ext = ".dylib";
#else
output_ext = ".so";
#endif
link_settings = "-shared";
} else {
// TODO: Do I need anything here?
link_settings = "";
}
#if defined(GB_SYSTEM_OSX)
linker = "ld";
#else
// TODO(zangent): Figure out how to make ld work on Linux.
// It probably has to do with including the entire CRT, but
// that's quite a complicated issue to solve while remaining distro-agnostic.
// Clang can figure out linker flags for us, and that's good enough _for now_.
linker = "clang -Wno-unused-command-line-argument";
#endif
exit_code = system_exec_command_line_app("ld-link", true,
"%s \"%.*s\".o -o \"%.*s%s\" %s "
"-lc -lm "
" %.*s "
" %s "
#if defined(GB_SYSTEM_OSX)
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
// make sure to also change the `mtriple` param passed to `opt`
" -macosx_version_min 10.8.0 "
// This points the linker to where the entry point is
" -e _main "
#endif
, linker, LIT(output_base), LIT(output_base), output_ext,
lib_str, LIT(build_context.link_flags),
link_settings
);
if (exit_code != 0) {
return exit_code;
}
// timings_print_all(&timings);
if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base));
}
#endif
#endif
#endif
#endif
return 0;
}
+5
View File
@@ -6,6 +6,9 @@
#define MAP_NAME MapString
#include "map.c"
*/
// A `Map` is an unordered hash table which can allow for a key to point to multiple values
// with the use of the `multi_*` procedures.
// TODO(bill): I should probably allow the `multi_*` stuff to be #ifdefed out
#ifndef MAP_UTIL_STUFF
#define MAP_UTIL_STUFF
@@ -320,6 +323,7 @@ void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
if (h->hashes.count == 0) {
_J2(MAP_PROC,grow)(h);
}
// Make
fr = _J2(MAP_PROC,_find)(h, key);
i = _J2(MAP_PROC,_add_entry)(h, key);
if (fr.entry_prev < 0) {
@@ -329,6 +333,7 @@ void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
}
h->entries.e[i].next = fr.entry_index;
h->entries.e[i].value = value;
// Grow if needed
if (_J2(MAP_PROC,_full)(h)) {
_J2(MAP_PROC,grow)(h);
}
+1401 -993
View File
File diff suppressed because it is too large Load Diff
+2636
View File
File diff suppressed because it is too large Load Diff
+276
View File
@@ -0,0 +1,276 @@
#define SSA_OPS \
SSA_OP(Invalid)\
\
SSA_OP(Unknown)\
\
SSA_OP(Comment) /* Does nothing */\
\
SSA_OP(SP) /* Stack Pointer */\
SSA_OP(SB) /* Stack Base */\
\
SSA_OP(Local)\
SSA_OP(Global)\
SSA_OP(Proc)\
\
SSA_OP(Load)\
SSA_OP(Store)\
SSA_OP(Move)\
SSA_OP(LoadReg)\
SSA_OP(StoreReg)\
SSA_OP(Zero) /* Zero initialize */\
\
SSA_OP(ArrayIndex) /* Index for a fixed array */\
SSA_OP(PtrIndex) /* Index for a struct/tuple/etc */\
SSA_OP(PtrOffset)\
SSA_OP(ValueIndex) /* Extract for a value from a register */\
\
SSA_OP(Phi)\
SSA_OP(Copy)\
\
/* TODO(bill): calling conventions */\
SSA_OP(CallOdin)\
SSA_OP(CallC)\
SSA_OP(CallStd)\
SSA_OP(CallFast)\
\
SSA_OP(BoundsCheck)\
SSA_OP(SliceBoundsCheck)\
\
/* Built in operations/procedures */\
SSA_OP(Bswap16)\
SSA_OP(Bswap32)\
SSA_OP(Bswap64)\
\
SSA_OP(Assume)\
SSA_OP(DebugTrap)\
SSA_OP(Trap)\
SSA_OP(ReadCycleCounter)\
\
\
SSA_OP(ConstBool)\
SSA_OP(ConstString)\
SSA_OP(ConstSlice)\
SSA_OP(ConstNil)\
SSA_OP(Const8)\
SSA_OP(Const16)\
SSA_OP(Const32)\
SSA_OP(Const64)\
SSA_OP(Const32F)\
SSA_OP(Const64F)\
\
/* These should be all the operations I could possibly need for the mean time */\
SSA_OP(Add8)\
SSA_OP(Add16)\
SSA_OP(Add32)\
SSA_OP(Add64)\
SSA_OP(AddPtr)\
SSA_OP(Add32F)\
SSA_OP(Add64F)\
SSA_OP(Sub8)\
SSA_OP(Sub16)\
SSA_OP(Sub32)\
SSA_OP(Sub64)\
SSA_OP(SubPtr)\
SSA_OP(Sub32F)\
SSA_OP(Sub64F)\
SSA_OP(Mul8)\
SSA_OP(Mul16)\
SSA_OP(Mul32)\
SSA_OP(Mul64)\
SSA_OP(Mul32F)\
SSA_OP(Mul64F)\
SSA_OP(Div8)\
SSA_OP(Div8U)\
SSA_OP(Div16)\
SSA_OP(Div16U)\
SSA_OP(Div32)\
SSA_OP(Div32U)\
SSA_OP(Div64)\
SSA_OP(Div64U)\
SSA_OP(Div32F)\
SSA_OP(Div64F)\
SSA_OP(Mod8)\
SSA_OP(Mod8U)\
SSA_OP(Mod16)\
SSA_OP(Mod16U)\
SSA_OP(Mod32)\
SSA_OP(Mod32U)\
SSA_OP(Mod64)\
SSA_OP(Mod64U)\
\
SSA_OP(And8)\
SSA_OP(And16)\
SSA_OP(And32)\
SSA_OP(And64)\
SSA_OP(Or8)\
SSA_OP(Or16)\
SSA_OP(Or32)\
SSA_OP(Or64)\
SSA_OP(Xor8)\
SSA_OP(Xor16)\
SSA_OP(Xor32)\
SSA_OP(Xor64)\
SSA_OP(AndNot8)\
SSA_OP(AndNot16)\
SSA_OP(AndNot32)\
SSA_OP(AndNot64)\
\
SSA_OP(Lsh8x8)\
SSA_OP(Lsh8x16)\
SSA_OP(Lsh8x32)\
SSA_OP(Lsh8x64)\
SSA_OP(Lsh16x8)\
SSA_OP(Lsh16x16)\
SSA_OP(Lsh16x32)\
SSA_OP(Lsh16x64)\
SSA_OP(Lsh32x8)\
SSA_OP(Lsh32x16)\
SSA_OP(Lsh32x32)\
SSA_OP(Lsh32x64)\
SSA_OP(Lsh64x8)\
SSA_OP(Lsh64x16)\
SSA_OP(Lsh64x32)\
SSA_OP(Lsh64x64)\
SSA_OP(Rsh8x8)\
SSA_OP(Rsh8x16)\
SSA_OP(Rsh8x32)\
SSA_OP(Rsh8x64)\
SSA_OP(Rsh16x8)\
SSA_OP(Rsh16x16)\
SSA_OP(Rsh16x32)\
SSA_OP(Rsh16x64)\
SSA_OP(Rsh32x8)\
SSA_OP(Rsh32x16)\
SSA_OP(Rsh32x32)\
SSA_OP(Rsh32x64)\
SSA_OP(Rsh64x8)\
SSA_OP(Rsh64x16)\
SSA_OP(Rsh64x32)\
SSA_OP(Rsh64x64)\
SSA_OP(Rsh8Ux8)\
SSA_OP(Rsh8Ux16)\
SSA_OP(Rsh8Ux32)\
SSA_OP(Rsh8Ux64)\
SSA_OP(Rsh16Ux8)\
SSA_OP(Rsh16Ux16)\
SSA_OP(Rsh16Ux32)\
SSA_OP(Rsh16Ux64)\
SSA_OP(Rsh32Ux8)\
SSA_OP(Rsh32Ux16)\
SSA_OP(Rsh32Ux32)\
SSA_OP(Rsh32Ux64)\
SSA_OP(Rsh64Ux8)\
SSA_OP(Rsh64Ux16)\
SSA_OP(Rsh64Ux32)\
SSA_OP(Rsh64Ux64)\
\
SSA_OP(Eq8)\
SSA_OP(Eq16)\
SSA_OP(Eq32)\
SSA_OP(Eq64)\
SSA_OP(EqPtr)\
SSA_OP(Eq32F)\
SSA_OP(Eq64F)\
SSA_OP(Ne8)\
SSA_OP(Ne16)\
SSA_OP(Ne32)\
SSA_OP(Ne64)\
SSA_OP(NePtr)\
SSA_OP(Ne32F)\
SSA_OP(Ne64F)\
SSA_OP(Lt8)\
SSA_OP(Lt16)\
SSA_OP(Lt32)\
SSA_OP(Lt64)\
SSA_OP(LtPtr)\
SSA_OP(Lt32F)\
SSA_OP(Lt64F)\
SSA_OP(Gt8)\
SSA_OP(Gt16)\
SSA_OP(Gt32)\
SSA_OP(Gt64)\
SSA_OP(GtPtr)\
SSA_OP(Gt32F)\
SSA_OP(Gt64F)\
SSA_OP(Le8)\
SSA_OP(Le16)\
SSA_OP(Le32)\
SSA_OP(Le64)\
SSA_OP(LePtr)\
SSA_OP(Le32F)\
SSA_OP(Le64F)\
SSA_OP(Ge8)\
SSA_OP(Ge16)\
SSA_OP(Ge32)\
SSA_OP(Ge64)\
SSA_OP(GePtr)\
SSA_OP(Ge32F)\
SSA_OP(Ge64F)\
\
SSA_OP(NotB)\
SSA_OP(EqB)\
SSA_OP(NeB)\
\
SSA_OP(Neg8)\
SSA_OP(Neg16)\
SSA_OP(Neg32)\
SSA_OP(Neg64)\
SSA_OP(Neg32F)\
SSA_OP(Neg64F)\
\
SSA_OP(Not8)\
SSA_OP(Not16)\
SSA_OP(Not32)\
SSA_OP(Not64)\
\
SSA_OP(SignExt8to16)\
SSA_OP(SignExt8to32)\
SSA_OP(SignExt8to64)\
SSA_OP(SignExt16to32)\
SSA_OP(SignExt16to64)\
SSA_OP(SignExt32to64)\
SSA_OP(ZeroExt8to16)\
SSA_OP(ZeroExt8to32)\
SSA_OP(ZeroExt8to64)\
SSA_OP(ZeroExt16to32)\
SSA_OP(ZeroExt16to64)\
SSA_OP(ZeroExt32to64)\
SSA_OP(Trunc16to8)\
SSA_OP(Trunc32to8)\
SSA_OP(Trunc32to16)\
SSA_OP(Trunc64to8)\
SSA_OP(Trunc64to16)\
SSA_OP(Trunc64to32)\
\
SSA_OP(Cvt32to32F)\
SSA_OP(Cvt32to64F)\
SSA_OP(Cvt64to32F)\
SSA_OP(Cvt64to64F)\
SSA_OP(Cvt32Fto32)\
SSA_OP(Cvt32Fto64)\
SSA_OP(Cvt64Fto32)\
SSA_OP(Cvt64Fto64)\
SSA_OP(Cvt32Fto64F)\
SSA_OP(Cvt64Fto32F)\
SSA_OP(Cvt32Uto32F)\
SSA_OP(Cvt32Uto64F)\
SSA_OP(Cvt32Fto32U)\
SSA_OP(Cvt64Fto32U)\
SSA_OP(Cvt64Uto32F)\
SSA_OP(Cvt64Uto64F)\
SSA_OP(Cvt32Fto64U)\
SSA_OP(Cvt64Fto64U)\
enum ssaOp {
#define SSA_OP(k) GB_JOIN2(ssaOp_, k),
SSA_OPS
#undef SSA_OP
};
typedef enum ssaOp ssaOp;
String const ssa_op_strings[] = {
#define SSA_OP(k) {cast(u8 *)#k, gb_size_of(#k)-1},
SSA_OPS
#undef SSA_OP
};
+92 -17
View File
@@ -15,8 +15,11 @@ typedef struct String {
} String;
// NOTE(bill): used for printf style arguments
#define LIT(x) ((int)(x).len), (x).text
#define STR_LIT(c_str) {cast(u8 *)c_str, gb_size_of(c_str)-1}
#define str_lit(c_str) (String){cast(u8 *)c_str, gb_size_of(c_str)-1}
// NOTE(bill): String16 is only used for Windows due to its file directories
typedef struct String16 {
wchar_t *text;
isize len;
@@ -46,7 +49,6 @@ gb_inline String make_string_c(char *text) {
return make_string(cast(u8 *)cast(void *)text, gb_strlen(text));
}
#define str_lit(c_str) make_string(cast(u8 *)c_str, gb_size_of(c_str)-1)
@@ -144,16 +146,37 @@ gb_inline isize string_extension_position(String str) {
return dot_pos;
}
String string_trim_whitespace(String str) {
while (str.len > 0 && rune_is_whitespace(str.text[str.len-1])) {
str.len--;
}
while (str.len > 0 && rune_is_whitespace(str.text[0])) {
str.text++;
str.len--;
}
return str;
}
gb_inline bool string_has_extension(String str, String ext) {
if (str.len > ext.len+1) {
u8 *s = str.text+str.len - ext.len-1;
if (s[0] == '.') {
s++;
return gb_memcompare(s, ext.text, ext.len) == 0;
}
str = string_trim_whitespace(str);
if (str.len <= ext.len+1) {
return false;
}
return false;
isize len = str.len;
for (isize i = len-1; i >= 0; i--) {
if (str.text[i] == '.') {
break;
}
len--;
}
if (len == 0) {
return false;
}
u8 *s = str.text + len;
return gb_memcompare(s, ext.text, ext.len) == 0;
}
bool string_contains_char(String s, u8 c) {
@@ -165,6 +188,63 @@ bool string_contains_char(String s, u8 c) {
return false;
}
String filename_from_path(String s) {
isize i = string_extension_position(s);
if (i > 0) {
isize j = 0;
s.len = i;
for (j = i-1; j >= 0; j--) {
if (s.text[j] == '/' ||
s.text[j] == '\\') {
break;
}
}
s.text += j+1;
s.len = i-j-1;
}
return make_string(NULL, 0);
}
#if defined(GB_SYSTEM_WINDOWS)
int convert_multibyte_to_widechar(char *multibyte_input, int input_length, wchar_t *output, int output_size) {
return MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, multibyte_input, input_length, output, output_size);
}
int convert_widechar_to_multibyte(wchar_t *widechar_input, int input_length, char *output, int output_size) {
return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, NULL, NULL);
}
#elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX)
#include <iconv.h>
int convert_multibyte_to_widechar(char *multibyte_input, usize input_length, wchar_t *output, usize output_size) {
iconv_t conv = iconv_open("WCHAR_T", "UTF-8");
size_t result = iconv(conv, cast(char **)&multibyte_input, &input_length, cast(char **)&output, &output_size);
iconv_close(conv);
return (int) result;
}
int convert_widechar_to_multibyte(wchar_t* widechar_input, usize input_length, char* output, usize output_size) {
iconv_t conv = iconv_open("UTF-8", "WCHAR_T");
size_t result = iconv(conv, (char**) &widechar_input, &input_length, (char**) &output, &output_size);
iconv_close(conv);
return (int) result;
}
#else
#error Implement system
#endif
// TODO(bill): Make this non-windows specific
String16 string_to_string16(gbAllocator a, String s) {
int len, len1;
@@ -174,16 +254,14 @@ String16 string_to_string16(gbAllocator a, String s) {
return make_string16(NULL, 0);
}
len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
cast(char *)s.text, s.len, NULL, 0);
len = convert_multibyte_to_widechar(cast(char *)s.text, s.len, NULL, 0);
if (len == 0) {
return make_string16(NULL, 0);
}
text = gb_alloc_array(a, wchar_t, len+1);
len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
cast(char *)s.text, s.len, text, len);
len1 = convert_multibyte_to_widechar(cast(char *)s.text, s.len, text, len);
if (len1 == 0) {
gb_free(a, text);
return make_string16(NULL, 0);
@@ -201,16 +279,14 @@ String string16_to_string(gbAllocator a, String16 s) {
return make_string(NULL, 0);
}
len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
s.text, s.len, NULL, 0, NULL, NULL);
len = convert_widechar_to_multibyte(s.text, s.len, NULL, 0);
if (len == 0) {
return make_string(NULL, 0);
}
text = gb_alloc_array(a, u8, len+1);
len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
s.text, s.len, cast(char *)text, len, NULL, NULL);
len1 = convert_widechar_to_multibyte(s.text, s.len, cast(char *)text, len);
if (len1 == 0) {
gb_free(a, text);
return make_string(NULL, 0);
@@ -236,7 +312,6 @@ String string16_to_string(gbAllocator a, String16 s) {
bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *tail_string) {
u8 c;
+38
View File
@@ -11,6 +11,7 @@ typedef struct Timings {
} Timings;
#if defined(GB_SYSTEM_WINDOWS)
u64 win32_time_stamp_time_now(void) {
LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
@@ -27,9 +28,44 @@ u64 win32_time_stamp__freq(void) {
return win32_perf_count_freq.QuadPart;
}
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
#include <time.h>
u64 unix_time_stamp_time_now(void) {
struct timespec ts;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
return (ts.tv_sec * 1000000000) + ts.tv_nsec;
}
u64 unix_time_stamp__freq(void) {
gb_local_persist u64 freq = 0;
if (freq == 0) {
struct timespec ts;
clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts);
// that would be an absurd resolution (or lack thereof)
GB_ASSERT(ts.tv_sec == 0);
freq = cast(u64) ((1.0 / ts.tv_nsec) * 1000000000.0);
GB_ASSERT(freq != 0);
}
return freq;
}
#else
#error Implement system
#endif
u64 time_stamp_time_now(void) {
#if defined(GB_SYSTEM_WINDOWS)
return win32_time_stamp_time_now();
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
return unix_time_stamp_time_now();
#else
#error time_stamp_time_now
#endif
@@ -38,6 +74,8 @@ u64 time_stamp_time_now(void) {
u64 time_stamp__freq(void) {
#if defined(GB_SYSTEM_WINDOWS)
return win32_time_stamp__freq();
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
return unix_time_stamp__freq();
#else
#error time_stamp__freq
#endif
+190 -190
View File
@@ -1,113 +1,119 @@
#define TOKEN_KINDS \
TOKEN_KIND(Token_Invalid, "Invalid"), \
TOKEN_KIND(Token_EOF, "EOF"), \
TOKEN_KIND(Token_EOF, "EOF"), \
TOKEN_KIND(Token_Comment, "Comment"), \
\
TOKEN_KIND(Token__LiteralBegin, "_LiteralBegin"), \
TOKEN_KIND(Token_Ident, "identifier"), \
TOKEN_KIND(Token_Integer, "integer"), \
TOKEN_KIND(Token_Float, "float"), \
TOKEN_KIND(Token_Rune, "rune"), \
TOKEN_KIND(Token_String, "string"), \
TOKEN_KIND(Token__LiteralEnd, "_LiteralEnd"), \
TOKEN_KIND(Token_Ident, "identifier"), \
TOKEN_KIND(Token_Integer, "integer"), \
TOKEN_KIND(Token_Float, "float"), \
TOKEN_KIND(Token_Imag, "imaginary"), \
TOKEN_KIND(Token_Rune, "rune"), \
TOKEN_KIND(Token_String, "string"), \
TOKEN_KIND(Token__LiteralEnd, "_LiteralEnd"), \
\
TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
TOKEN_KIND(Token_Eq, "="), \
TOKEN_KIND(Token_Not, "!"), \
TOKEN_KIND(Token_Hash, "#"), \
TOKEN_KIND(Token_At, "@"), \
TOKEN_KIND(Token_Pointer, "^"), \
TOKEN_KIND(Token_Maybe, "?"), \
TOKEN_KIND(Token_Add, "+"), \
TOKEN_KIND(Token_Sub, "-"), \
TOKEN_KIND(Token_Mul, "*"), \
TOKEN_KIND(Token_Quo, "/"), \
TOKEN_KIND(Token_Mod, "%"), \
TOKEN_KIND(Token_And, "&"), \
TOKEN_KIND(Token_Or, "|"), \
TOKEN_KIND(Token_Xor, "~"), \
TOKEN_KIND(Token_AndNot, "&~"), \
TOKEN_KIND(Token_Shl, "<<"), \
TOKEN_KIND(Token_Shr, ">>"), \
\
TOKEN_KIND(Token_as, "as"), \
TOKEN_KIND(Token_transmute, "transmute"), \
TOKEN_KIND(Token_down_cast, "down_cast"), \
TOKEN_KIND(Token_union_cast, "union_cast"), \
TOKEN_KIND(Token_Eq, "="), \
TOKEN_KIND(Token_Not, "!"), \
TOKEN_KIND(Token_Hash, "#"), \
TOKEN_KIND(Token_At, "@"), \
TOKEN_KIND(Token_Dollar, "$"), \
TOKEN_KIND(Token_Pointer, "^"), \
TOKEN_KIND(Token_Question, "?"), \
TOKEN_KIND(Token_Add, "+"), \
TOKEN_KIND(Token_Sub, "-"), \
TOKEN_KIND(Token_Mul, "*"), \
TOKEN_KIND(Token_Quo, "/"), \
TOKEN_KIND(Token_Mod, "%"), \
TOKEN_KIND(Token_And, "&"), \
TOKEN_KIND(Token_Or, "|"), \
TOKEN_KIND(Token_Xor, "~"), \
TOKEN_KIND(Token_AndNot, "&~"), \
TOKEN_KIND(Token_Shl, "<<"), \
TOKEN_KIND(Token_Shr, ">>"), \
\
TOKEN_KIND(Token_CmpAnd, "&&"), \
TOKEN_KIND(Token_CmpOr, "||"), \
TOKEN_KIND(Token_CmpOr, "||"), \
\
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
TOKEN_KIND(Token_AddEq, "+="), \
TOKEN_KIND(Token_SubEq, "-="), \
TOKEN_KIND(Token_MulEq, "*="), \
TOKEN_KIND(Token_QuoEq, "/="), \
TOKEN_KIND(Token_ModEq, "%="), \
TOKEN_KIND(Token_AndEq, "&="), \
TOKEN_KIND(Token_OrEq, "|="), \
TOKEN_KIND(Token_XorEq, "~="), \
TOKEN_KIND(Token_AndNotEq, "&~="), \
TOKEN_KIND(Token_ShlEq, "<<="), \
TOKEN_KIND(Token_ShrEq, ">>="), \
TOKEN_KIND(Token_CmpAndEq, "&&="), \
TOKEN_KIND(Token_CmpOrEq, "||="), \
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
TOKEN_KIND(Token_AddEq, "+="), \
TOKEN_KIND(Token_SubEq, "-="), \
TOKEN_KIND(Token_MulEq, "*="), \
TOKEN_KIND(Token_QuoEq, "/="), \
TOKEN_KIND(Token_ModEq, "%="), \
TOKEN_KIND(Token_AndEq, "&="), \
TOKEN_KIND(Token_OrEq, "|="), \
TOKEN_KIND(Token_XorEq, "~="), \
TOKEN_KIND(Token_AndNotEq, "&~="), \
TOKEN_KIND(Token_ShlEq, "<<="), \
TOKEN_KIND(Token_ShrEq, ">>="), \
TOKEN_KIND(Token_CmpAndEq, "&&="), \
TOKEN_KIND(Token_CmpOrEq, "||="), \
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
TOKEN_KIND(Token_ArrowRight, "->"), \
TOKEN_KIND(Token_ArrowLeft, "<-"), \
TOKEN_KIND(Token_ArrowLeft, "<-"), \
TOKEN_KIND(Token_Inc, "++"), \
TOKEN_KIND(Token_Dec, "--"), \
\
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
TOKEN_KIND(Token_CmpEq, "=="), \
TOKEN_KIND(Token_NotEq, "!="), \
TOKEN_KIND(Token_Lt, "<"), \
TOKEN_KIND(Token_Gt, ">"), \
TOKEN_KIND(Token_LtEq, "<="), \
TOKEN_KIND(Token_GtEq, ">="), \
TOKEN_KIND(Token_Lt, "<"), \
TOKEN_KIND(Token_Gt, ">"), \
TOKEN_KIND(Token_LtEq, "<="), \
TOKEN_KIND(Token_GtEq, ">="), \
TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
\
TOKEN_KIND(Token_OpenParen, "("), \
TOKEN_KIND(Token_CloseParen, ")"), \
TOKEN_KIND(Token_OpenBracket, "["), \
TOKEN_KIND(Token_CloseBracket, "]"), \
TOKEN_KIND(Token_OpenBrace, "{"), \
TOKEN_KIND(Token_CloseBrace, "}"), \
TOKEN_KIND(Token_Colon, ":"), \
TOKEN_KIND(Token_Semicolon, ";"), \
TOKEN_KIND(Token_Period, "."), \
TOKEN_KIND(Token_Comma, ","), \
TOKEN_KIND(Token_Ellipsis, "..."), \
TOKEN_KIND(Token_Interval, "..<"), \
TOKEN_KIND(Token_OpenParen, "("), \
TOKEN_KIND(Token_CloseParen, ")"), \
TOKEN_KIND(Token_OpenBracket, "["), \
TOKEN_KIND(Token_CloseBracket, "]"), \
TOKEN_KIND(Token_OpenBrace, "{"), \
TOKEN_KIND(Token_CloseBrace, "}"), \
TOKEN_KIND(Token_Colon, ":"), \
TOKEN_KIND(Token_Semicolon, ";"), \
TOKEN_KIND(Token_Period, "."), \
TOKEN_KIND(Token_Comma, ","), \
TOKEN_KIND(Token_Ellipsis, ".."), \
TOKEN_KIND(Token_HalfClosed, "..<"), \
TOKEN_KIND(Token_BackSlash, "\\"), \
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
\
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_type, "type"), \
TOKEN_KIND(Token_proc, "proc"), \
TOKEN_KIND(Token_macro, "macro"), \
TOKEN_KIND(Token_match, "match"), \
TOKEN_KIND(Token_break, "break"), \
TOKEN_KIND(Token_continue, "continue"), \
TOKEN_KIND(Token_fallthrough, "fallthrough"), \
TOKEN_KIND(Token_case, "case"), \
TOKEN_KIND(Token_default, "default"), \
TOKEN_KIND(Token_then, "then"), \
TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_else, "else"), \
TOKEN_KIND(Token_while, "while"), \
TOKEN_KIND(Token_for, "for"), \
TOKEN_KIND(Token_when, "when"), \
TOKEN_KIND(Token_range, "range"), \
TOKEN_KIND(Token_defer, "defer"), \
TOKEN_KIND(Token_return, "return"), \
TOKEN_KIND(Token_give, "give"), \
TOKEN_KIND(Token_struct, "struct"), \
TOKEN_KIND(Token_union, "union"), \
TOKEN_KIND(Token_raw_union, "raw_union"), \
TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_vector, "vector"), \
TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_asm, "asm"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
TOKEN_KIND(Token_push_context, "push_context"), \
TOKEN_KIND(Token_when, "when"), \
TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_else, "else"), \
TOKEN_KIND(Token_for, "for"), \
TOKEN_KIND(Token_in, "in"), \
TOKEN_KIND(Token_match, "match"), \
TOKEN_KIND(Token_default, "default"), \
TOKEN_KIND(Token_case, "case"), \
TOKEN_KIND(Token_break, "break"), \
TOKEN_KIND(Token_continue, "continue"), \
TOKEN_KIND(Token_fallthrough, "fallthrough"), \
TOKEN_KIND(Token_defer, "defer"), \
TOKEN_KIND(Token_return, "return"), \
TOKEN_KIND(Token_give, "give"), \
TOKEN_KIND(Token_proc, "proc"), \
TOKEN_KIND(Token_macro, "macro"), \
TOKEN_KIND(Token_struct, "struct"), \
TOKEN_KIND(Token_union, "union"), \
TOKEN_KIND(Token_raw_union, "raw_union"), \
TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_vector, "vector"), \
TOKEN_KIND(Token_static, "static"), \
TOKEN_KIND(Token_dynamic, "dynamic"), \
TOKEN_KIND(Token_map, "map"), \
TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_no_alias, "no_alias"), \
TOKEN_KIND(Token_immutable, "immutable"), \
TOKEN_KIND(Token_context, "context"), \
TOKEN_KIND(Token_push_context, "push_context"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
TOKEN_KIND(Token_asm, "asm"), \
TOKEN_KIND(Token_yield, "yield"), \
TOKEN_KIND(Token_await, "await"), \
TOKEN_KIND(Token_atomic, "atomic"), \
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
TOKEN_KIND(Token_Count, "")
@@ -146,7 +152,6 @@ bool token_pos_eq(TokenPos a, TokenPos b) {
return token_pos_cmp(a, b) == 0;
}
// NOTE(bill): Text is UTF-8, thus why u8 and not char
typedef struct Token {
TokenKind kind;
String string;
@@ -164,8 +169,8 @@ Token make_token_ident(String s) {
typedef struct ErrorCollector {
TokenPos prev;
i64 count;
i64 warning_count;
i64 count;
i64 warning_count;
gbMutex mutex;
} ErrorCollector;
@@ -198,6 +203,8 @@ void error_va(Token token, char *fmt, va_list va) {
gb_printf_err("%.*s(%td:%td) %s\n",
LIT(token.pos.file), token.pos.line, token.pos.column,
gb_bprintf_va(fmt, va));
} else if (token.pos.line == 0) {
gb_printf_err("Error: %s\n", gb_bprintf_va(fmt, va));
}
gb_mutex_unlock(&global_error_collector.mutex);
@@ -212,11 +219,30 @@ void syntax_error_va(Token token, char *fmt, va_list va) {
gb_printf_err("%.*s(%td:%td) Syntax Error: %s\n",
LIT(token.pos.file), token.pos.line, token.pos.column,
gb_bprintf_va(fmt, va));
} else if (token.pos.line == 0) {
gb_printf_err("Error: %s\n", gb_bprintf_va(fmt, va));
}
gb_mutex_unlock(&global_error_collector.mutex);
}
void syntax_warning_va(Token token, char *fmt, va_list va) {
gb_mutex_lock(&global_error_collector.mutex);
global_error_collector.warning_count++;
// NOTE(bill): Duplicate error, skip it
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
global_error_collector.prev = token.pos;
gb_printf_err("%.*s(%td:%td) Syntax Warning: %s\n",
LIT(token.pos.file), token.pos.line, token.pos.column,
gb_bprintf_va(fmt, va));
} else if (token.pos.line == 0) {
gb_printf_err("Warning: %s\n", gb_bprintf_va(fmt, va));
}
gb_mutex_unlock(&global_error_collector.mutex);
}
void warning(Token token, char *fmt, ...) {
va_list va;
@@ -239,6 +265,13 @@ void syntax_error(Token token, char *fmt, ...) {
va_end(va);
}
void syntax_warning(Token token, char *fmt, ...) {
va_list va;
va_start(va, fmt);
syntax_warning_va(token, fmt, va);
va_end(va);
}
void compiler_error(char *fmt, ...) {
va_list va;
@@ -254,20 +287,20 @@ void compiler_error(char *fmt, ...) {
gb_inline bool token_is_literal(Token t) {
return gb_is_between(t.kind, Token__LiteralBegin+1, Token__LiteralEnd-1);
gb_inline bool token_is_literal(TokenKind t) {
return gb_is_between(t, Token__LiteralBegin+1, Token__LiteralEnd-1);
}
gb_inline bool token_is_operator(Token t) {
return gb_is_between(t.kind, Token__OperatorBegin+1, Token__OperatorEnd-1);
gb_inline bool token_is_operator(TokenKind t) {
return gb_is_between(t, Token__OperatorBegin+1, Token__OperatorEnd-1);
}
gb_inline bool token_is_keyword(Token t) {
return gb_is_between(t.kind, Token__KeywordBegin+1, Token__KeywordEnd-1);
gb_inline bool token_is_keyword(TokenKind t) {
return gb_is_between(t, Token__KeywordBegin+1, Token__KeywordEnd-1);
}
gb_inline bool token_is_comparison(Token t) {
return gb_is_between(t.kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1);
gb_inline bool token_is_comparison(TokenKind t) {
return gb_is_between(t, Token__ComparisonBegin+1, Token__ComparisonEnd-1);
}
gb_inline bool token_is_shift(Token t) {
return t.kind == Token_Shl || t.kind == Token_Shr;
gb_inline bool token_is_shift(TokenKind t) {
return t == Token_Shl || t == Token_Shr;
}
gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); }
@@ -382,7 +415,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
TokenizerInitError err = TokenizerInit_None;
char *c_str = gb_alloc_array(heap_allocator(), char, fullpath.len+1);
memcpy(c_str, fullpath.text, fullpath.len);
gb_memcopy(c_str, fullpath.text, fullpath.len);
c_str[fullpath.len] = '\0';
// TODO(bill): Memory map rather than copy contents
@@ -453,15 +486,11 @@ gb_inline i32 digit_value(Rune r) {
}
gb_inline void scan_mantissa(Tokenizer *t, i32 base) {
// TODO(bill): Allow for underscores in numbers as a number separator
// TODO(bill): Is this a good idea?
// while (digit_value(t->curr_rune) < base || t->curr_rune == '_')
while (digit_value(t->curr_rune) < base) {
while (digit_value(t->curr_rune) < base || t->curr_rune == '_') {
advance_to_next_rune(t);
}
}
Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
Token token = {0};
token.kind = Token_Integer;
@@ -497,6 +526,12 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} else if (t->curr_rune == 'z') { // Dozenal
advance_to_next_rune(t);
scan_mantissa(t, 12);
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} else if (t->curr_rune == 'x') { // Hexadecimal
advance_to_next_rune(t);
scan_mantissa(t, 16);
@@ -513,12 +548,12 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
}
}
token.string.len = t->curr - token.string.text;
return token;
goto end;
}
scan_mantissa(t, 10);
fraction:
if (t->curr_rune == '.') {
// HACK(bill): This may be inefficient
@@ -543,6 +578,13 @@ exponent:
scan_mantissa(t, 10);
}
switch (t->curr_rune) {
case 'i': case 'j': case 'k':
token.kind = Token_Imag;
advance_to_next_rune(t);
break;
}
end:
token.string.len = t->curr - token.string.text;
return token;
@@ -577,20 +619,22 @@ bool scan_escape(Tokenizer *t, Rune quote) {
advance_to_next_rune(t);
len = 8; base = 16; max = GB_RUNE_MAX;
} else {
if (t->curr_rune < 0)
if (t->curr_rune < 0) {
tokenizer_err(t, "Escape sequence was not terminated");
else
} else {
tokenizer_err(t, "Unknown escape sequence");
}
return false;
}
while (len --> 0) {
u32 d = cast(u32)digit_value(t->curr_rune);
if (d >= base) {
if (t->curr_rune < 0)
if (t->curr_rune < 0) {
tokenizer_err(t, "Escape sequence was not terminated");
else
} else {
tokenizer_err(t, "Illegal character %d in escape sequence", t->curr_rune);
}
return false;
}
@@ -717,20 +761,10 @@ Token tokenizer_get_token(Tokenizer *t) {
// NOTE(bill): All keywords are > 1
if (token.string.len > 1) {
if (str_eq(token.string, token_strings[Token_as])) {
token.kind = Token_as;
} else if (str_eq(token.string, token_strings[Token_transmute])) {
token.kind = Token_transmute;
} else if (str_eq(token.string, token_strings[Token_down_cast])) {
token.kind = Token_down_cast;
} else if (str_eq(token.string, token_strings[Token_union_cast])) {
token.kind = Token_union_cast;
} else {
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
if (str_eq(token.string, token_strings[k])) {
token.kind = cast(TokenKind)k;
break;
}
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
if (str_eq(token.string, token_strings[k])) {
token.kind = cast(TokenKind)k;
break;
}
}
}
@@ -832,74 +866,42 @@ Token tokenizer_get_token(Tokenizer *t) {
case '.':
token.kind = Token_Period; // Default
if (gb_is_between(t->curr_rune, '0', '9')) { // Might be a number
token = scan_number_to_token(t, true);
} else if (t->curr_rune == '.') { // Could be an ellipsis
if (t->curr_rune == '.') { // Could be an ellipsis
advance_to_next_rune(t);
if (t->curr_rune == '.') {
token.kind = Token_Ellipsis;
if (t->curr_rune == '<') {
advance_to_next_rune(t);
token.kind = Token_Ellipsis;
} else if (t->curr_rune == '<') {
advance_to_next_rune(t);
token.kind = Token_Interval;
token.kind = Token_HalfClosed;
}
}
break;
case '#':
token.kind = Token_Hash;
break;
case '@':
token.kind = Token_At;
break;
case '^':
token.kind = Token_Pointer;
break;
case '?':
token.kind = Token_Maybe;
break;
case ';':
token.kind = Token_Semicolon;
break;
case ',':
token.kind = Token_Comma;
break;
case ':':
token.kind = Token_Colon;
break;
case '(':
token.kind = Token_OpenParen;
break;
case ')':
token.kind = Token_CloseParen;
break;
case '[':
token.kind = Token_OpenBracket;
break;
case ']':
token.kind = Token_CloseBracket;
break;
case '{':
token.kind = Token_OpenBrace;
break;
case '}':
token.kind = Token_CloseBrace;
break;
case '#': token.kind = Token_Hash; break;
case '@': token.kind = Token_At; break;
case '$': token.kind = Token_Dollar; break;
case '?': token.kind = Token_Question; break;
case '^': token.kind = Token_Pointer; break;
case ';': token.kind = Token_Semicolon; break;
case ',': token.kind = Token_Comma; break;
case ':': token.kind = Token_Colon; break;
case '(': token.kind = Token_OpenParen; break;
case ')': token.kind = Token_CloseParen; break;
case '[': token.kind = Token_OpenBracket; break;
case ']': token.kind = Token_CloseBracket; break;
case '{': token.kind = Token_OpenBrace; break;
case '}': token.kind = Token_CloseBrace; break;
case '\\': token.kind = Token_BackSlash; break;
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break;
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break;
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
case '+':
token.kind = token_kind_variant2(t, Token_Add, Token_AddEq);
break;
case '-':
token.kind = token_kind_variant3(t, Token_Sub, Token_SubEq, '>', Token_ArrowRight);
break;
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break;
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break;
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Dec, '>', Token_ArrowRight); break;
case '/': {
if (t->curr_rune == '/') {
while (t->curr_rune != '\n') {
while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) {
advance_to_next_rune(t);
}
token.kind = Token_Comment;
@@ -936,9 +938,7 @@ Token tokenizer_get_token(Tokenizer *t) {
token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
}
break;
case '>':
token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq);
break;
case '>': token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); break;
case '&':
token.kind = Token_And;
+2220
View File
File diff suppressed because it is too large Load Diff
+1 -25
View File
@@ -6,6 +6,7 @@
#pragma warning(pop)
bool rune_is_letter(Rune r) {
if ((r < 0x80 && gb_char_is_alpha(cast(char)r)) ||
r == '_') {
@@ -39,28 +40,3 @@ bool rune_is_whitespace(Rune r) {
}
return false;
}
bool is_string_an_identifier(String s) {
isize offset = 0;
if (s.len < 1) {
return false;
}
while (offset < s.len) {
bool ok = false;
Rune r = -1;
isize size = gb_utf8_decode(s.text+offset, s.len-offset, &r);
if (offset == 0) {
ok = rune_is_letter(r);
} else {
ok = rune_is_letter(r) || rune_is_digit(r);
}
if (!ok) {
return false;
}
offset += size;
}
return offset == s.len;
}
+66 -44
View File
@@ -166,24 +166,24 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_encode_char(utf8proc_int32_t uc, ut
if (uc < 0x00) {
return 0;
} else if (uc < 0x80) {
dst[0] = uc;
dst[0] = (utf8proc_uint8_t) uc;
return 1;
} else if (uc < 0x800) {
dst[0] = 0xC0 + (uc >> 6);
dst[1] = 0x80 + (uc & 0x3F);
dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6));
dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 2;
// Note: we allow encoding 0xd800-0xdfff here, so as not to change
// the API, however, these are actually invalid in UTF-8
} else if (uc < 0x10000) {
dst[0] = 0xE0 + (uc >> 12);
dst[1] = 0x80 + ((uc >> 6) & 0x3F);
dst[2] = 0x80 + (uc & 0x3F);
dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12));
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 3;
} else if (uc < 0x110000) {
dst[0] = 0xF0 + (uc >> 18);
dst[1] = 0x80 + ((uc >> 12) & 0x3F);
dst[2] = 0x80 + ((uc >> 6) & 0x3F);
dst[3] = 0x80 + (uc & 0x3F);
dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18));
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F));
dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 4;
} else return 0;
}
@@ -193,28 +193,28 @@ static utf8proc_ssize_t unsafe_encode_char(utf8proc_int32_t uc, utf8proc_uint8_t
if (uc < 0x00) {
return 0;
} else if (uc < 0x80) {
dst[0] = uc;
dst[0] = (utf8proc_uint8_t)uc;
return 1;
} else if (uc < 0x800) {
dst[0] = 0xC0 + (uc >> 6);
dst[1] = 0x80 + (uc & 0x3F);
dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6));
dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 2;
} else if (uc == 0xFFFF) {
dst[0] = 0xFF;
dst[0] = (utf8proc_uint8_t)0xFF;
return 1;
} else if (uc == 0xFFFE) {
dst[0] = 0xFE;
dst[0] = (utf8proc_uint8_t)0xFE;
return 1;
} else if (uc < 0x10000) {
dst[0] = 0xE0 + (uc >> 12);
dst[1] = 0x80 + ((uc >> 6) & 0x3F);
dst[2] = 0x80 + (uc & 0x3F);
dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12));
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 3;
} else if (uc < 0x110000) {
dst[0] = 0xF0 + (uc >> 18);
dst[1] = 0x80 + ((uc >> 12) & 0x3F);
dst[2] = 0x80 + ((uc >> 6) & 0x3F);
dst[3] = 0x80 + (uc & 0x3F);
dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18));
dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F));
dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 4;
} else return 0;
}
@@ -383,7 +383,7 @@ UTF8PROC_DLLEXPORT int utf8proc_charwidth(utf8proc_int32_t c) {
}
UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t c) {
return (utf8proc_category_t)utf8proc_get_property(c)->category;
return utf8proc_get_property(c)->category;
}
UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
@@ -391,11 +391,9 @@ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
return s[utf8proc_category(c)];
}
#define utf8proc_decompose_lump(replacement_uc) \
return utf8proc_decompose_char((utf8proc_int32_t)(replacement_uc), dst, bufsize, \
(utf8proc_option_t)((utf8proc_int32_t)options & ~UTF8PROC_LUMP), last_boundclass)
return utf8proc_decompose_char((replacement_uc), dst, bufsize, \
options & ~UTF8PROC_LUMP, last_boundclass)
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) {
const utf8proc_property_t *property;
@@ -458,12 +456,12 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc,
category == UTF8PROC_CATEGORY_ME) return 0;
}
if (options & UTF8PROC_CASEFOLD) {
if ((utf8proc_int16_t)property->casefold_seqindex != UINT16_MAX) {
if (property->casefold_seqindex != UINT16_MAX) {
return seqindex_write_char_decomposed(property->casefold_seqindex, dst, bufsize, options, last_boundclass);
}
}
if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) {
if ((utf8proc_int16_t)property->decomp_seqindex != UINT16_MAX &&
if (property->decomp_seqindex != UINT16_MAX &&
(!property->decomp_type || (options & UTF8PROC_COMPAT))) {
return seqindex_write_char_decomposed(property->decomp_seqindex, dst, bufsize, options, last_boundclass);
}
@@ -485,6 +483,14 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc,
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options
) {
return utf8proc_decompose_custom(str, strlen, buffer, bufsize, options, NULL, NULL);
}
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options,
utf8proc_custom_func custom_func, void *custom_data
) {
/* strlen will be ignored, if UTF8PROC_NULLTERM is set in options */
utf8proc_ssize_t wpos = 0;
@@ -511,6 +517,9 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
rpos += utf8proc_iterate(str + rpos, strlen - rpos, &uc);
if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8;
}
if (custom_func != NULL) {
uc = custom_func(uc, custom_data); /* user-specified custom mapping */
}
decomp_result = utf8proc_decompose_char(
uc, buffer + wpos, (bufsize > wpos) ? (bufsize - wpos) : 0, options,
&boundclass
@@ -545,9 +554,8 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
return wpos;
}
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
/* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored
ASSERT: 'buffer' has one spare byte of free space at the end! */
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
/* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored */
if (options & (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS | UTF8PROC_STRIPCC)) {
utf8proc_ssize_t rpos;
utf8proc_ssize_t wpos = 0;
@@ -621,7 +629,7 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
starter_property = unsafe_get_property(*starter);
}
if (starter_property->comb_index < 0x8000 &&
(utf8proc_int16_t)current_property->comb_index != UINT16_MAX &&
current_property->comb_index != UINT16_MAX &&
current_property->comb_index >= 0x8000) {
int sidx = starter_property->comb_index;
int idx = (current_property->comb_index & 0x3FFF) - utf8proc_combinations[sidx];
@@ -655,6 +663,14 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
}
length = wpos;
}
return length;
}
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
/* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored
ASSERT: 'buffer' has one spare byte of free space at the end! */
length = utf8proc_normalize_utf32(buffer, length, options);
if (length < 0) return length;
{
utf8proc_ssize_t rpos, wpos = 0;
utf8proc_int32_t uc;
@@ -676,15 +692,22 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options
) {
return utf8proc_map_custom(str, strlen, dstptr, options, NULL, NULL);
}
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options,
utf8proc_custom_func custom_func, void *custom_data
) {
utf8proc_int32_t *buffer;
utf8proc_ssize_t result;
*dstptr = NULL;
result = utf8proc_decompose(str, strlen, NULL, 0, options);
result = utf8proc_decompose_custom(str, strlen, NULL, 0, options, custom_func, custom_data);
if (result < 0) return result;
buffer = (utf8proc_int32_t *) malloc(result * sizeof(utf8proc_int32_t) + 1);
if (!buffer) return UTF8PROC_ERROR_NOMEM;
result = utf8proc_decompose(str, strlen, buffer, result, options);
result = utf8proc_decompose_custom(str, strlen, buffer, result, options, custom_func, custom_data);
if (result < 0) {
free(buffer);
return result;
@@ -705,29 +728,28 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_DECOMPOSE));
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_DECOMPOSE);
return retval;
}
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_COMPOSE));
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_COMPOSE);
return retval;
}
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT));
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT);
return retval;
}
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval;
utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_COMPOSE | UTF8PROC_COMPAT));
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
UTF8PROC_COMPOSE | UTF8PROC_COMPAT);
return retval;
}
+81 -25
View File
@@ -71,14 +71,15 @@
/** The MAJOR version number (increased when backwards API compatibility is broken). */
#define UTF8PROC_VERSION_MAJOR 2
/** The MINOR version number (increased when new functionality is added in a backwards-compatible manner). */
#define UTF8PROC_VERSION_MINOR 0
#define UTF8PROC_VERSION_MINOR 1
/** The PATCH version (increased for fixes that do not change the API). */
#define UTF8PROC_VERSION_PATCH 2
#define UTF8PROC_VERSION_PATCH 0
/** @} */
#include <stdlib.h>
#include <sys/types.h>
#ifdef _MSC_VER
#if defined(_MSC_VER) && _MSC_VER < 1800
// MSVC prior to 2013 lacked stdbool.h and inttypes.h
typedef signed char utf8proc_int8_t;
typedef unsigned char utf8proc_uint8_t;
typedef short utf8proc_int16_t;
@@ -93,12 +94,18 @@ typedef int utf8proc_ssize_t;
typedef unsigned int utf8proc_size_t;
# endif
# ifndef __cplusplus
// emulate C99 bool
typedef unsigned char utf8proc_bool;
// enum {false, true};
# ifndef __bool_true_false_are_defined
# define false 0
# define true 1
# define __bool_true_false_are_defined 1
# endif
# else
typedef bool utf8proc_bool;
# endif
#else
# include <stddef.h>
# include <stdbool.h>
# include <inttypes.h>
typedef int8_t utf8proc_int8_t;
@@ -108,22 +115,12 @@ typedef uint16_t utf8proc_uint16_t;
typedef int32_t utf8proc_int32_t;
typedef uint32_t utf8proc_uint32_t;
typedef size_t utf8proc_size_t;
typedef ssize_t utf8proc_ssize_t;
typedef ptrdiff_t utf8proc_ssize_t;
typedef bool utf8proc_bool;
#endif
#include <limits.h>
#ifdef _WIN32
# ifdef UTF8PROC_EXPORTS
# define UTF8PROC_DLLEXPORT __declspec(dllexport)
# else
# define UTF8PROC_DLLEXPORT /*__declspec(dllimport)*/
# endif
#elif __GNUC__ >= 4
# define UTF8PROC_DLLEXPORT __attribute__ ((visibility("default")))
#else
# define UTF8PROC_DLLEXPORT
#endif
#define UTF8PROC_DLLEXPORT
#ifdef __cplusplus
extern "C" {
@@ -134,7 +131,7 @@ extern "C" {
#endif
#ifndef UINT16_MAX
# define UINT16_MAX ~(utf8proc_uint16_t)0
# define UINT16_MAX 65535U
#endif
/**
@@ -373,6 +370,13 @@ typedef enum {
UTF8PROC_BOUNDCLASS_E_BASE_GAZ = 18, /**< E_BASE + GLUE_AFTER_ZJW */
} utf8proc_boundclass_t;
/**
* Function pointer type passed to @ref utf8proc_map_custom and
* @ref utf8proc_decompose_custom, which is used to specify a user-defined
* mapping of codepoints to be applied in conjunction with other mappings.
*/
typedef utf8proc_int32_t (*utf8proc_custom_func)(utf8proc_int32_t codepoint, void *data);
/**
* Array containing the byte lengths of a UTF-8 encoded codepoint based
* on the first byte.
@@ -480,6 +484,7 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(
* `buffer` (which must contain at least `bufsize` entries). In case of
* success, the number of codepoints written is returned; in case of an
* error, a negative error code is returned (@ref utf8proc_errmsg).
* See @ref utf8proc_decompose_custom to supply additional transformations.
*
* If the number of written codepoints would be bigger than `bufsize`, the
* required buffer size is returned, while the buffer will be overwritten with
@@ -491,8 +496,20 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
);
/**
* Reencodes the sequence of `length` codepoints pointed to by `buffer`
* UTF-8 data in-place (i.e., the result is also stored in `buffer`).
* The same as @ref utf8proc_decompose, but also takes a `custom_func` mapping function
* that is called on each codepoint in `str` before any other transformations
* (along with a `custom_data` pointer that is passed through to `custom_func`).
* The `custom_func` argument is ignored if it is `NULL`. See also @ref utf8proc_map_custom.
*/
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options,
utf8proc_custom_func custom_func, void *custom_data
);
/**
* Normalizes the sequence of `length` codepoints pointed to by `buffer`
* in-place (i.e., the result is also stored in `buffer`).
*
* @param buffer the (native-endian UTF-32) unicode codepoints to re-encode.
* @param length the length (in codepoints) of the buffer.
@@ -507,9 +524,37 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
* the unicode versioning stability
*
* @return
* In case of success, the length (in bytes) of the resulting UTF-8 string is
* In case of success, the length (in codepoints) of the normalized UTF-32 string is
* returned; otherwise, a negative error code is returned (@ref utf8proc_errmsg).
*
* @warning The entries of the array pointed to by `str` have to be in the
* range `0x0000` to `0x10FFFF`. Otherwise, the program might crash!
*/
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options);
/**
* Reencodes the sequence of `length` codepoints pointed to by `buffer`
* UTF-8 data in-place (i.e., the result is also stored in `buffer`).
* Can optionally normalize the UTF-32 sequence prior to UTF-8 conversion.
*
* @param buffer the (native-endian UTF-32) unicode codepoints to re-encode.
* @param length the length (in codepoints) of the buffer.
* @param options a bitwise or (`|`) of one or more of the following flags:
* - @ref UTF8PROC_NLF2LS - convert LF, CRLF, CR and NEL into LS
* - @ref UTF8PROC_NLF2PS - convert LF, CRLF, CR and NEL into PS
* - @ref UTF8PROC_NLF2LF - convert LF, CRLF, CR and NEL into LF
* - @ref UTF8PROC_STRIPCC - strip or convert all non-affected control characters
* - @ref UTF8PROC_COMPOSE - try to combine decomposed codepoints into composite
* codepoints
* - @ref UTF8PROC_STABLE - prohibit combining characters that would violate
* the unicode versioning stability
* - @ref UTF8PROC_CHARBOUND - insert 0xFF bytes before each grapheme cluster
*
* @return
* In case of success, the length (in bytes) of the resulting nul-terminated
* UTF-8 string is returned; otherwise, a negative error code is returned
* (@ref utf8proc_errmsg).
*
* @warning The amount of free space pointed to by `buffer` must
* exceed the amount of the input data by one byte, and the
* entries of the array pointed to by `str` have to be in the
@@ -595,7 +640,8 @@ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t codepoi
* in any case the result will be NULL terminated (though it might
* contain NULL characters with the string if `str` contained NULL
* characters). Other flags in the `options` field are passed to the
* functions defined above, and regarded as described.
* functions defined above, and regarded as described. See also
* @ref utfproc_map_custom to supply a custom codepoint transformation.
*
* In case of success the length of the new string is returned,
* otherwise a negative error code is returned.
@@ -607,6 +653,17 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options
);
/**
* Like @ref utf8proc_map, but also takes a `custom_func` mapping function
* that is called on each codepoint in `str` before any other transformations
* (along with a `custom_data` pointer that is passed through to `custom_func`).
* The `custom_func` argument is ignored if it is `NULL`.
*/
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options,
utf8proc_custom_func custom_func, void *custom_data
);
/** @name Unicode normalization
*
* Returns a pointer to newly allocated memory of a NFD, NFC, NFKD or NFKC
@@ -619,9 +676,9 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str);
/** NFC normalization (@ref UTF8PROC_COMPOSE). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str);
/** NFD normalization (@ref UTF8PROC_DECOMPOSE and @ref UTF8PROC_COMPAT). */
/** NFKD normalization (@ref UTF8PROC_DECOMPOSE and @ref UTF8PROC_COMPAT). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str);
/** NFD normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT). */
/** NFKC normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str);
/** @} */
@@ -630,4 +687,3 @@ UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str);
#endif
#endif
+10 -15
View File
@@ -1,7 +1,4 @@
#pragma warning(push)
#pragma warning(disable: 4838)
const utf8proc_uint16_t utf8proc_sequences[] = {
static const utf8proc_uint16_t utf8proc_sequences[] = {
97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119,
@@ -1179,7 +1176,7 @@ const utf8proc_uint16_t utf8proc_sequences[] = {
56603, 55354, 56604, 55354, 56605, 55354, 56606, 55354,
56607, 55354, 56608, 55354, 56609, };
const utf8proc_uint16_t utf8proc_stage1table[] = {
static const utf8proc_uint16_t utf8proc_stage1table[] = {
0, 256, 512, 768, 1024, 1280, 1536,
1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
@@ -1726,7 +1723,7 @@ const utf8proc_uint16_t utf8proc_stage1table[] = {
18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432,
38656, };
const utf8proc_uint16_t utf8proc_stage2table[] = {
static const utf8proc_uint16_t utf8proc_stage2table[] = {
1, 2, 2, 2, 2, 2, 2,
2, 2, 3, 4, 3, 5, 6, 2,
2, 2, 2, 2, 2, 2, 2, 2,
@@ -5899,7 +5896,7 @@ const utf8proc_uint16_t utf8proc_stage2table[] = {
540, 540, 540, 1180, 0, 0, 0, 0,
0, 1154, 1154, 1154, 1154, 1154, 1154, 1154,
1154, 1154, 1154, 0, 0, 0, 0, 1103,
1158, 0, 0, 0, 0, 0, 0, 0,
1103, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -6593,7 +6590,7 @@ const utf8proc_uint16_t utf8proc_stage2table[] = {
3984, 3984, 3984, 3984, 3984, 3984, 3984, 0,
0, };
const utf8proc_property_t utf8proc_properties[] = {
static const utf8proc_property_t utf8proc_properties[] = {
{0, 0, 0, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false,false,false,false, 0, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL},
{UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL},
@@ -7850,7 +7847,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_MN, 122, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND},
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9525, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NOBREAK, 1335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NOBREAK, 1335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_MN, 216, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND},
{UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -10478,7 +10475,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1470, UINT16_MAX, 1470, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1478, UINT16_MAX, 1478, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5132, UINT16_MAX, 5132, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1480, UINT16_MAX, 1480, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1480, UINT16_MAX, 1480, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5133, UINT16_MAX, 5133, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5134, UINT16_MAX, 5134, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1482, UINT16_MAX, 1482, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -12168,7 +12165,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6787, UINT16_MAX, 6787, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6789, UINT16_MAX, 6789, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6791, UINT16_MAX, 6791, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6793, UINT16_MAX, 6793, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6793, UINT16_MAX, 6793, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6795, UINT16_MAX, 6795, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6797, UINT16_MAX, 6797, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6799, UINT16_MAX, 6799, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -12204,7 +12201,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9104, UINT16_MAX, 9104, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9106, UINT16_MAX, 9106, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9108, UINT16_MAX, 9108, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9110, UINT16_MAX, 9110, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9110, UINT16_MAX, 9110, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9112, UINT16_MAX, 9112, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9114, UINT16_MAX, 9114, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9116, UINT16_MAX, 9116, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -13423,7 +13420,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7975, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
};
const utf8proc_uint16_t utf8proc_combinations[] = {
static const utf8proc_uint16_t utf8proc_combinations[] = {
0, 46, 192, 193, 194, 195, 196, 197, 0,
256, 258, 260, 550, 461, 0, 0, 512,
514, 0, 0, 0, 0, 0, 0, 0,
@@ -14386,5 +14383,3 @@ const utf8proc_uint16_t utf8proc_combinations[] = {
72, 75,
1, 53694, 1, 53696,
};
#pragma warning(pop)