Compare commits

..

366 Commits

Author SHA1 Message Date
Ginger Bill 5df854fcef Fixed demo 2017-06-27 15:58:53 +01:00
Ginger Bill 260089431e Write demo for v0.5.0 2017-06-26 21:34:54 +01:00
Ginger Bill d0d8da8c08 Revert demo 2017-06-26 19:42:32 +01:00
Ginger Bill d1365b3466 Fix poly-procs for variadic calls 2017-06-26 19:24:04 +01:00
Ginger Bill c949ca2a5c Allow for named arguments for polymorphic procedures 2017-06-26 18:20:24 +01:00
Ginger Bill d974b29f67 Reduce excessive node cloning on para-poly checking and fix scope bug 2017-06-26 14:39:51 +01:00
Ginger Bill cc7316bb35 Fix IR printing for para-poly procedures 2017-06-26 14:16:16 +01:00
Ginger Bill a0d8dcd974 Remove let 2017-06-26 13:59:15 +01:00
Ginger Bill c642e326ce Undef value --- (for setting a value to be uninitialized/undefined) 2017-06-26 11:57:26 +01:00
Ginger Bill 362a118782 Remove "overloading" bug of para-poly-procs 2017-06-25 23:41:46 +01:00
Ginger Bill 3ab481df17 new as a user-level procedure 2017-06-25 22:31:30 +01:00
Ginger Bill 4e7150b470 Allow nested para-poly procedures 2017-06-25 22:29:23 +01:00
Ginger Bill 1ced92be47 Rudimentary para-poly procedures 2017-06-25 22:15:30 +01:00
Ginger Bill 15dbea6899 Generic procedures generate types on use 2017-06-25 19:41:07 +01:00
Ginger Bill c4081393c1 Fix typo for some built-in procedures 2017-06-25 17:36:10 +01:00
Ginger Bill 1d81b73df9 Basic command line flags: e.g. -opt=0 2017-06-24 22:58:50 +01:00
Ginger Bill 18f885efab expand_to_tuple 2017-06-24 20:39:37 +01:00
Ginger Bill bba088bee7 Use UTF-8 command line on windows 2017-06-24 11:42:49 +01:00
Ginger Bill 6cbb6bef0b Wrap hashing functions 2017-06-22 16:14:02 +01:00
Ginger Bill 8744c60563 Clean up code for return statements, slightly 2017-06-22 13:47:50 +01:00
Ginger Bill 8197c02dcf Default result values for procedure types; Named result values in return statements 2017-06-22 01:14:45 +01:00
Ginger Bill 9faf0020cc Amend Checker API 2017-06-21 21:46:27 +01:00
Ginger Bill 53075e2570 Update old demos 2017-06-21 21:20:26 +01:00
Ginger Bill 264ca00db7 Merge branch 'master' of https://github.com/gingerBill/Odin 2017-06-21 17:49:05 +01:00
Ginger Bill 6b65ef6d88 Fix compilation bug on Linux 2017-06-21 17:48:50 +01:00
Ginger Bill 5957d7f7be Implicit Parameter Passing based context system (replacing Thread Local Storage (TLS) approach) 2017-06-20 12:38:05 +01:00
Ginger Bill 35c102137f Compiler compiles for x86 (doesn't work properly) 2017-06-19 18:49:11 +01:00
Ginger Bill 5427d14416 Code will compile as 32 bit but will causes errors in the linker on Windows 2017-06-19 15:55:09 +01:00
Ginger Bill 178236d1ff Barebones layout for the documentation declarations 2017-06-18 23:41:13 +01:00
Ginger Bill 736c880ba9 Add docs.cpp 2017-06-18 23:18:15 +01:00
Ginger Bill 126f7aa892 Begin work on documentation generation 2017-06-18 23:16:57 +01:00
Ginger Bill 2957f007e3 Fix #location for anonymous procedures 2017-06-18 17:35:27 +01:00
Ginger Bill 04501c93fe Implement assert and panic in user side code
Removes 2 more built-in procedures!
2017-06-18 17:25:28 +01:00
Ginger Bill 4236519b84 #location(..) and #call_location 2017-06-18 14:36:06 +01:00
Ginger Bill e4944b4f2e Fix error reporting for foreign blocks 2017-06-17 20:03:52 +01:00
Ginger Bill 2deb2f8eeb Declaration grouping uses () rather than {}; Fix some problem with compilation on *nix 2017-06-17 12:01:53 +01:00
Ginger Bill 3fa398ec43 Add extra check for bodiless procedures 2017-06-15 21:36:29 +01:00
Ginger Bill 1851674b50 Code use API rather than raw CheckerInfo; begin work on generic procedures 2017-06-15 18:11:58 +01:00
Ginger Bill c5ef5279d4 Add foreign variables 2017-06-15 14:42:08 +01:00
Ginger Bill d3c24d159f Merge size_of and size_of_val et al. 2017-06-15 12:25:53 +01:00
Ginger Bill 23f9f9064e Add CheckerInfo API functions 2017-06-15 12:14:56 +01:00
Ginger Bill a134307dcd Fix issue #72 - 128-bit literal corruption 2017-06-14 14:58:48 +01:00
Ginger Bill c3b510c2d9 C-style c_varargs (Not heavily tested) 2017-06-13 21:00:42 +01:00
Ginger Bill e7fc24e48c Fix compilation error for Invalid EntityKind 2017-06-13 18:04:22 +01:00
Ginger Bill 6a88dc322a Declaration grouping uses braces rather than parentheses 2017-06-13 15:04:23 +01:00
Ginger Bill 6b464e3558 Update README.md 2017-06-12 21:41:14 +01:00
Ginger Bill 76b0c7b765 "Revert" to older demo 2017-06-12 21:27:53 +01:00
Ginger Bill 91857e8f16 Remove redundant paths in parsing 2017-06-12 21:25:47 +01:00
Ginger Bill ccda456c0a foreign blocks for procedures 2017-06-12 21:21:18 +01:00
Ginger Bill 83bad13e9e Update default field value syntax; Use more declaration groupings 2017-06-12 18:38:27 +01:00
Ginger Bill e6a206a430 Check for empty generic declaration list 2017-06-12 16:58:25 +01:00
Ginger Bill f52a1e4ded Fix IR bug for TypeSpec 2017-06-12 16:47:07 +01:00
Ginger Bill a8e458339b foreign_library allow for Pascal-style grouping 2017-06-12 16:26:51 +01:00
Ginger Bill 6b5e9aec8e Pascal style declaration grouping with () 2017-06-12 15:42:21 +01:00
Ginger Bill 2ab0d97573 import and import_load as keywords; Fix procedure literal call trick 2017-06-12 14:19:12 +01:00
Ginger Bill 0c05fc1432 Prefix type and let to replace immutable 2017-06-12 12:56:47 +01:00
Ginger Bill 33eeb58521 Prefix proc syntax 2017-06-12 12:34:55 +01:00
Ginger Bill 8fafdb185c Remove := with var and :: with const 2017-06-12 11:48:12 +01:00
Ginger Bill c2c935ba81 Fix trailing default argument checking 2017-06-11 20:52:54 +01:00
Ginger Bill 2d73c8868b Make default arguments for records invalid syntax 2017-06-11 19:01:36 +01:00
gingerBill b95bb1286b Merge pull request #70 from ThisDrunkDane/master
Add some WM_*, some WS_* and map_virtual_key
2017-06-11 18:54:30 +01:00
Mikkel Hjortshoej 4237c8ec30 Merge branch 'master' of github.com:gingerBill/Odin 2017-06-11 19:53:44 +02:00
Ginger Bill 49b4b39055 Minor change for overloaded procedures 2017-06-11 18:53:20 +01:00
Mikkel Hjortshoej bf15fea135 Merge branch 'master' of github.com:gingerBill/Odin 2017-06-11 19:47:57 +02:00
Mikkel Hjortshoej 47c03e376d Merge branch 'master' of github.com:gingerBill/Odin 2017-06-11 19:47:05 +02:00
Ginger Bill 1cabfac36c Update README.md 2017-06-11 18:46:59 +01:00
Mikkel Hjortshoej 8e32276283 Added a bunch of VM_* and map_virtual_key 2017-06-11 19:46:55 +02:00
Ginger Bill 366b306df0 Default parameters for procedures 2017-06-11 18:38:30 +01:00
Ginger Bill 4bf1f798f5 Allow for ignoring named procedural call arguments with _ 2017-06-11 17:41:55 +01:00
Ginger Bill b2fdb69b4d Named procedure calls 2017-06-11 12:01:40 +01:00
Ginger Bill af2736daec Fix bit field bug 2017-06-08 16:29:05 +01:00
Ginger Bill 5cad7d44a6 Use templated Map for extra type safety 2017-06-08 13:26:48 +01:00
Ginger Bill 2b96be0ae8 Remove unnecessary typedef usage 2017-06-08 13:08:39 +01:00
Ginger Bill 2a89d8021c Use templated Array with bounds checking 2017-06-08 12:54:52 +01:00
Ginger Bill 13deb4706c Update String to use overloading 2017-06-08 12:37:07 +01:00
Ginger Bill 9b61adb97d Build as C++ 2017-06-08 12:03:40 +01:00
Ginger Bill 333924cce1 v0.3 Release 2017-06-08 11:35:22 +01:00
Ginger Bill 574b82c0c7 v0.3.0 2017-06-07 22:09:16 +01:00
Ginger Bill f60c772c11 Make rune a basic type and not an alias; Remove byte 2017-06-06 23:54:33 +01:00
Ginger Bill 107740ca5e Fix issue #69 for fmt.printf padding 2017-06-06 10:02:53 +01:00
gingerBill 88b990eb63 Merge pull request #53 from ghost/master
Fix link time error about missing -fPIC flag
2017-06-06 09:47:40 +01:00
Ginger Bill d2e7d730ac Fix key generation for constant strings in IR 2017-06-05 23:06:15 +01:00
Ginger Bill 817e4b663e Add murmurhash3.c 2017-06-05 22:52:56 +01:00
Ginger Bill 214bb73454 Merge branch 'master' of https://github.com/gingerBill/Odin 2017-06-05 18:01:57 +01:00
Ginger Bill eba2c74bff Allow 128 bit map keys 2017-06-05 18:01:41 +01:00
gingerBill 7c5e6c808b Merge pull request #68 from ThisDrunkDane/master
Added extra sys/windows.odin stuff
2017-06-05 15:18:04 +01:00
Ginger Bill ebe5beaafd Allow using on bit fields 2017-06-04 11:53:33 +01:00
Ginger Bill 029a6095d9 Fix enum printing bug 2017-06-04 00:20:16 +01:00
Ginger Bill 2c0e59ae06 bit_field; Lexical sugar operators ≠ ≤ ≥
Example below:
// See: https://en.wikipedia.org/wiki/Bit_field
BoxProps :: bit_field {
	opaque        : 1,
	fill_colour   : 3,
	_             : 4,
	show_border   : 1,
	border_colour : 3,
	border_style  : 2,
	_             : 2,
	width         : 4,
	height        : 4,
	_             : 8,
}
2017-06-03 22:27:23 +01:00
Ginger Bill 9d1a4c304a Remove Quat from math.odin 2017-06-01 15:12:54 +01:00
Ginger Bill 13b8a1e348 Remove quaternion128 and quaternion256 as core types 2017-06-01 14:52:33 +01:00
Ginger Bill 0d4945dc87 Implement u128/i128 features; Add bits.odin 2017-06-01 14:23:46 +01:00
Mikkel Hjortshoej e0b9c4a275 Added extra sys/windows.odin stuff
- Added PM_NOREMOVE
	- Added PM_NOYIELD
	- Added get_message_a
	- Added post_message_a
2017-06-01 00:05:33 +02:00
Ginger Bill fec6df65b3 Use 128-bit integers for ExactValue integers 2017-05-30 15:23:01 +01:00
Ginger Bill 78494e84d5 Remove some asserts in timings.c 2017-05-29 19:41:13 +01:00
Ginger Bill 60d7c833c0 Fix unary expression type check 2017-05-28 21:56:40 +01:00
Ginger Bill 98dbbf11f3 Fix procedure overloading distinguishing 2017-05-28 18:51:42 +01:00
Ginger Bill f4924e39d4 Fix printing of struct literals with custom alignment 2017-05-28 16:11:19 +01:00
Ginger Bill 826e05c96e Convert windows.odin to the new naming convention 2017-05-28 16:08:29 +01:00
Ginger Bill d3f63e5903 Change label syntax for for and match from #label name to name: 2017-05-28 15:01:39 +01:00
Ginger Bill 80c034ec7c Change naming convention from Ada_Like to RustLike
Naming Conventions:
In general, PascalCase for types and snake_case for values

Import Name:        snake_case (but prefer single word)
Types:              PascalCase
Union Variants:     PascalCase
Enum Values:        PascalCase
Procedures:         snake_case
Local Variables:    snake_case
Constant Variables: SCREAMING_SNAKE_CASE
2017-05-28 14:47:11 +01:00
Ginger Bill b41f09b730 Experimental try for ABI for return values on windows
It's all done by reverse engineering it. I may be wrong...
2017-05-28 14:11:00 +01:00
Ginger Bill 06185e1769 Try a different ABI type for return values on Windows 2017-05-28 01:07:52 +01:00
Ginger Bill f8fa7fe380 Fix bug with too many field values in a structure literal. 2017-05-27 20:57:48 +01:00
Ginger Bill 45dbe8d354 default: to case:; no_alias to #no_alias 2017-05-27 11:47:21 +01:00
Ginger Bill ddb99dd638 Fix interval loop constant bug; Fix ir edge checking; Fix vector arithmetic with scalars 2017-05-22 23:29:09 +01:00
Ginger Bill 41aa4e606b Optional main for DLL; access struct elements by "index" 2017-05-17 21:23:52 +01:00
Ginger Bill e025a828ca Fix issue #66 2017-05-14 10:32:48 +01:00
Ginger Bill 807e17207a Merge branch 'master' of https://github.com/gingerBill/Odin 2017-05-13 16:09:04 +01:00
Ginger Bill 3e18f5f057 Fix Ternary Operator IR bug 2017-05-13 16:08:50 +01:00
gingerBill 9637cc5690 Add #ordered to the "raw" types in raw.odin 2017-05-12 16:04:05 +01:00
Ginger Bill ded99a2cab Fix issue with os.file_size on *nix 2017-05-12 10:29:55 +01:00
Ginger Bill 45eecc0905 Reimplement #ordered again 2017-05-12 10:27:14 +01:00
Ginger Bill 87f1a62ca4 Fix alignment for normal structures to match LLVM 2017-05-10 22:51:35 +01:00
Ginger Bill c6d531df95 Add %% operator (divisor modulo) 2017-05-09 16:21:31 +01:00
Ginger Bill 8677c81da7 Fix ir bug; allow formatting options for arrays & et al. 2017-05-09 12:05:17 +01:00
Ginger Bill 5595daf5a3 Revert demo.odin 2017-05-09 10:01:50 +01:00
Ginger Bill 64b5afd820 Fix issue #63 for block comments not terminating at an EOF 2017-05-09 10:01:10 +01:00
Ginger Bill 7692061eef Add XOR for booleans 2017-05-07 20:52:20 +01:00
Ginger Bill f7f2272c50 Fix fmt_float precision 2017-05-07 11:42:27 +01:00
Ginger Bill 03fbdc3f75 Fix IR printing bug with global unicode identifiers 2017-05-06 23:02:47 +01:00
Ginger Bill ea6a4859ed Merge branch 'master' of https://github.com/gingerBill/Odin 2017-05-06 20:56:18 +01:00
Ginger Bill 615fa82d1f Fix using issue #62 2017-05-06 20:55:09 +01:00
gingerBill b60b310121 Merge pull request #61 from ThisDrunkDane/master
Fix constant casing and add several win32 functions, structure and constants
2017-05-05 21:00:58 +01:00
Mikkel Hjortshoej c7f7e562a0 Add following win32 functions
- ShowCursor
	- GetFileAttributesA
	- FindFirstFileA
	- FindNextFileA
	- FindClose

Add following win32 constants
	- MAX_PATH
	- INVALID_FILE_ATTRIBUTES

Add following win32 structure
	- Find_Data
2017-05-05 20:32:48 +02:00
Mikkel Hjortshoej a317237404 Fix casing on FILE_ATTRIBUTE_DIRECTORY 2017-05-05 20:22:18 +02:00
Ginger Bill 51ea59d76a Fix calculation of vector type sizes 2017-05-04 23:18:54 +01:00
Ginger Bill 789b297f32 Add hidden __tag for union variables. 2017-05-04 20:34:50 +01:00
Ginger Bill 3b25f924cb Remove debug bug 2017-05-03 11:01:17 +01:00
Ginger Bill cc6282a6e3 Fix alignment and size bug of enums; Remove #ordered and make the default #ordered. 2017-05-02 21:16:09 +01:00
Ginger Bill 206a3e093c Remove check on array/slice/dynamic element size 2017-05-02 20:17:53 +01:00
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
Constantine Tarasenkov d05ec5e484 Fix link time error about missing -fPIC flag 2017-04-28 18:08:11 +03: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
97 changed files with 44521 additions and 28046 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 -26
View File
@@ -1,14 +1,15 @@
<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
* joy of programming
* metaprogramming
* designed for good programmers
Website: [https://odin.handmade.network/](https://odin.handmade.network/)
## Demonstrations:
* First Talk & Demo
@@ -18,39 +19,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)
* [Context Types, Unexported Entities, Labelled Branches](https://www.youtube.com/watch?v=CkHVwT1Qk-g)
* [Bit Fields, i128 & u128, Syntax Changes](https://www.youtube.com/watch?v=NlTutcLyF64)
## 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 (C++11 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 -12
View File
@@ -4,9 +4,8 @@
set exe_name=odin.exe
:: Debug = 0, Release = 1
set release_mode=1
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
set release_mode=0
set compiler_flags= -nologo -Oi -TP -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
if %release_mode% EQU 0 ( rem Debug
set compiler_flags=%compiler_flags% -Od -MDd -Z7
@@ -43,17 +42,12 @@ set linker_settings=%libs% %linker_flags%
del *.pdb > NUL 2> NUL
del *.ilk > NUL 2> NUL
cl %compiler_settings% "src\main.c" ^
cl %compiler_settings% "src\main.cpp" ^
/link %linker_settings% -OUT:%exe_name% ^
&& odin run code/demo.odin
rem && odin build_dll code/example.odin ^
rem && odin run code/demo.odin
&& odin run code/demo.odin -opt=0
rem && odin docs core/fmt.odin
rem pushd src\asm
rem nasm hellope.asm -fwin64 -o hellope.obj ^
rem && cl /nologo hellope.obj /link kernel32.lib /entry:main ^
rem && hellope.exe
rem popd
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=c++11 -g -Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined -Wno-writable-strings"
libraries="-pthread -ldl -lm -lstdc++"
other_args=""
compiler="clang"
if [ "$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.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin
./odin run code/demo.odin
+412 -49
View File
@@ -1,70 +1,433 @@
#foreign_system_library "winmm" when ODIN_OS == "windows";
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
#import "fmt.odin";
import "fmt.odin";
timeGetTime :: proc() -> u32 #foreign #dll_import
GetSystemTimeAsFileTime :: proc(SystemTimeAsFileTime : ^win32.FILETIME) #foreign #dll_import
proc general_stuff() {
// Complex numbers
var a = 3 + 4i;
var b: complex64 = 3 + 4i;
var c: complex128 = 3 + 4i;
var d = complex(2, 3);
var e = a / conj(a);
fmt.println("(3+4i)/(3-4i) =", e);
fmt.println(real(e), "+", imag(e), "i");
// C-style variadic procedures
foreign __llvm_core {
// The variadic part allows for extra type checking too which C does not provide
proc c_printf(fmt: ^u8, #c_vararg args: ..any) -> i32 #link_name "printf";
}
type Foo struct {
x: int,
y: f32,
z: string,
}
var foo = Foo{123, 0.513, "A string"};
var x, y, z = expand_to_tuple(foo);
fmt.println(x, y, z);
// By default, all variables are zeroed
// This can be overridden with the "uninitialized value"
// This is similar to `nil` but applied to everything
var undef_int: int = ---;
// Context system is now implemented using Implicit Parameter Passing (IPP)
// The previous implementation was Thread Local Storage (TLS)
// IPP has the advantage that it works on systems without TLS and that you can
// link the context to the stack frame and thus look at previous contexts
//
// It does mean that a pointer is implicitly passed procedures with the default
// Odin calling convention (#cc_odin)
// This can be overridden with something like #cc_contextless or #cc_c if performance
// is worried about
GetCommandLineArguments :: proc() -> []string {
argString := win32.GetCommandLineA();
fullArgString := to_odin_string(argString);
// Count Spaces
for r : fullArgString {
fmt.println(r);
}
}
to_odin_string :: proc(c: ^byte) -> string {
s: string;
s.data = c;
while (c + s.count)^ != 0 {
s.count += 1;
}
return s;
}
//("Hellope!\x00" as string).data
MAGIC_VALUE :: 0xCA5E713F;
timing_file_header :: struct #ordered {
MagicValue : u32;
proc foreign_blocks() {
// See sys/windows.odin
}
timing_file_date :: struct #ordered {
E : [2]u32;
proc default_arguments() {
proc hello(a: int = 9, b: int = 9) {
fmt.printf("a is %d; b is %d\n", a, b);
}
fmt.println("\nTesting default arguments:");
hello(1, 2);
hello(1);
hello();
}
timing_file_entry_flag :: enum {
Complete = 0x1,
NoErrors = 0x2,
proc named_arguments() {
type Colour enum {
Red,
Orange,
Yellow,
Green,
Blue,
Octarine,
};
using Colour;
proc make_character(name, catch_phrase: string, favorite_color, least_favorite_color: Colour) {
fmt.println();
fmt.printf("My name is %v and I like %v. %v\n", name, favorite_color, catch_phrase);
}
make_character("Frank", "¡Ay, caramba!", Blue, Green);
// As the procedures have more and more parameters, it is very easy
// to get many of the arguments in the wrong order especialy if the
// types are the same
make_character("¡Ay, caramba!", "Frank", Green, Blue);
// Named arguments help to disambiguate this problem
make_character(catch_phrase = "¡Ay, caramba!", name = "Frank",
least_favorite_color = Green, favorite_color = Blue);
// The named arguments can be specifed in any order.
make_character(favorite_color = Octarine, catch_phrase = "U wot m8!",
least_favorite_color = Green, name = "Dennis");
// NOTE: You cannot mix named arguments with normal values
/*
make_character("Dennis",
favorite_color = Octarine, catch_phrase = "U wot m8!",
least_favorite_color = Green);
*/
// Named arguments can also aid with default arguments
proc numerous_things(s : string, a = 1, b = 2, c = 3.14,
d = "The Best String!", e = false, f = 10.3/3.1, g = false) {
var g_str = g ? "true" : "false";
fmt.printf("How many?! %s: %v\n", s, g_str);
}
numerous_things("First");
numerous_things(s = "Second", g = true);
// Default values can be placed anywhere, not just at the end like in other languages
proc weird(pre: string, mid: int = 0, post: string) {
fmt.println(pre, mid, post);
}
weird("How many things", 42, "huh?");
weird(pre = "Prefix", post = "Pat");
}
timing_file_entry :: struct #ordered {
StarDate : timing_file_date;
Flags : u32;
MillisecondsElapsed : u32;
proc default_return_values() {
proc foo(x: int) -> (first: string = "Hellope", second = "world!") {
match x {
case 0: return;
case 1: return "Goodbye";
case 2: return "Goodbye", "cruel world...";
case 3: return second = "cruel world...", first = "Goodbye";
}
return second = "my old friend.";
}
fmt.printf("%s %s\n", foo(0));
fmt.printf("%s %s\n", foo(1));
fmt.printf("%s %s\n", foo(2));
fmt.printf("%s %s\n", foo(3));
fmt.printf("%s %s\n", foo(4));
fmt.println();
// A more "real" example
type Error enum {
None,
WhyTheNumberThree,
TenIsTooBig,
};
type Entity struct {
name: string,
id: u32,
}
proc some_thing(input: int) -> (result: ^Entity = nil, err = Error.None) {
match {
case input == 3: return err = Error.WhyTheNumberThree;
case input >= 10: return err = Error.TenIsTooBig;
}
var e = new(Entity);
e.id = u32(input);
return result = e;
}
}
timing_entry_array :: struct #ordered {
Entries : []timing_file_entry;
proc call_location() {
proc amazing(n: int, using loc = #caller_location) {
fmt.printf("%s(%d:%d) just asked to do something amazing.\n",
fully_pathed_filename, line, column);
fmt.printf("Normal -> %d\n", n);
fmt.printf("Amazing -> %d\n", n+1);
fmt.println();
}
var loc = #location(main);
fmt.println("`main` is located at", loc);
fmt.println("This line is located at", #location());
fmt.println();
amazing(3);
amazing(4, #location(call_location));
// See _preload.odin for the implementations of `assert` and `panic`
}
GetClock :: proc () -> u32 {
return timeGetTime();
proc explicit_parametric_polymorphic_procedures() {
// This is how `new` is actually implemented, see _preload.odin
proc alloc_type(T: type) -> ^T {
return ^T(alloc(size_of(T), align_of(T)));
}
var int_ptr = alloc_type(int);
defer free(int_ptr);
int_ptr^ = 137;
fmt.println(int_ptr, int_ptr^);
// Named arguments work too!
var another_ptr = alloc_type(T = f32);
defer free(another_ptr);
proc add(T: type, args: ..T) -> T {
var res: T;
for arg in args {
res += arg;
}
return res;
}
fmt.println("add =", add(int, 1, 2, 3, 4, 5, 6));
proc swap(T: type, a, b: ^T) {
var tmp = a^;
a^ = b^;
b^ = tmp;
}
var a, b: int = 3, 4;
fmt.println("Pre-swap:", a, b);
swap(int, &a, &b);
fmt.println("Post-swap:", a, b);
a, b = b, a; // Or use this syntax for this silly example case
// A more complicated example using subtyping
// Something like this could be used in a game
type Vector2 struct {x, y: f32};
type Entity struct {
using position: Vector2,
flags: u64,
id: u64,
batch_index: u32,
slot_index: u32,
portable_id: u32,
derived: any,
}
type Rock struct {
using entity: ^Entity,
heavy: bool,
}
type Door struct {
using entity: ^Entity,
open: bool,
}
type Monster struct {
using entity: ^Entity,
is_robot: bool,
is_zombie: bool,
}
type EntityManager struct {
batches: [dynamic]^EntityBatch,
next_portable_id: u32,
}
const ENTITIES_PER_BATCH = 16;
type EntityBatch struct {
data: [ENTITIES_PER_BATCH]Entity,
occupied: [ENTITIES_PER_BATCH]bool,
batch_index: u32,
}
proc use_empty_slot(manager: ^EntityManager, batch: ^EntityBatch) -> ^Entity {
for ok, i in batch.occupied {
if ok -> continue;
batch.occupied[i] = true;
var e = &batch.data[i];
e.batch_index = u32(batch.batch_index);
e.slot_index = u32(i);
e.portable_id = manager.next_portable_id;
manager.next_portable_id++;
return e;
}
return nil;
}
proc gen_new_entity(manager: ^EntityManager) -> ^Entity {
for b in manager.batches {
var e = use_empty_slot(manager, b);
if e != nil -> return e;
}
var new_batch = new(EntityBatch);
append(manager.batches, new_batch);
new_batch.batch_index = u32(len(manager.batches)-1);
return use_empty_slot(manager, new_batch);
}
proc new_entity(manager: ^EntityManager, Type: type, x, y: int) -> ^Type {
var result = new(Type);
result.entity = gen_new_entity(manager);
result.derived.data = result;
result.derived.type_info = type_info(Type);
result.position.x = f32(x);
result.position.y = f32(y);
return result;
}
var manager: EntityManager;
var entities: [dynamic]^Entity;
var rock = new_entity(&manager, Rock, 3, 5);
// Named arguments work too!
var door = new_entity(manager = &manager, Type = Door, x = 3, y = 6);
// And named arguments can be any order
var monster = new_entity(
y = 1,
x = 2,
manager = &manager,
Type = Monster,
);
append(entities, rock, door, monster);
// An alternative to `union`s
for entity in entities {
match e in entity.derived {
case Rock: fmt.println("Rock", e.portable_id);
case Door: fmt.println("Door", e.portable_id);
case Monster: fmt.println("Monster", e.portable_id);
}
}
}
GetDate :: proc() -> timing_file_date {
Result : timing_file_date;
FileTime : win32.FILETIME;
GetSystemTimeAsFileTime(^FileTime);
proc main() {
general_stuff();
foreign_blocks();
default_arguments();
named_arguments();
default_return_values();
call_location();
explicit_parametric_polymorphic_procedures();
Result.E[0] = FileTime.lo;
Result.E[1] = FileTime.hi;
// Command line argument(s)!
// -opt=0,1,2,3
/*************/
/* Questions */
/*************/
/*
I'm questioning if I should change the declaration syntax back to Jai-like
as I've found solutions to the problems I had with it before.
Should I change back to Jai-like declarations or keep with the Pascal-like?
Jai-like
x: int;
x: int = 123;
x := 123;
foo : int : 123;
foo :: 123;
MyInt :: int;
BarType :: proc();
bar :: proc() {
}
foreign lib {
foreign_bar :: proc() ---;
}
Pascal-like
var x: int;
var x: int = 123;
var x = 123;
const foo: int = 123;
const foo = 123;
type MyInt int;
type BarType proc();
proc bar() {
}
foreign lib {
proc foreign_bar();
}
*/
return Result;
}
main :: proc () {
EntryClock := GetClock();
GetCommandLineArguments();
/*
proc main() {
var program = "+ + * - /";
var accumulator = 0;
for token in program {
match token {
case '+': accumulator += 1;
case '-': accumulator -= 1;
case '*': accumulator *= 2;
case '/': accumulator /= 2;
case: // Ignore everything else
}
}
fmt.printf("The program \"%s\" calculates the value %d\n",
program, accumulator);
}
*/
+97 -90
View File
@@ -1,91 +1,91 @@
#import "win32.odin" when ODIN_OS == "windows";
#import "fmt.odin";
#import "math.odin";
#import "os.odin";
#import gl "opengl.odin";
import win32 "sys/windows.odin" when ODIN_OS == "windows";
import wgl "sys/wgl.odin" when ODIN_OS == "windows";
import "fmt.odin";
import "math.odin";
import "os.odin";
import gl "opengl.odin";
TWO_HEARTS :: '💕';
const TWO_HEARTS = '💕';
win32_perf_count_freq := win32.GetQueryPerformanceFrequency();
time_now :: proc() -> f64 {
var win32_perf_count_freq = win32.get_query_performance_frequency();
proc time_now() -> f64 {
assert(win32_perf_count_freq != 0);
counter: i64;
win32.QueryPerformanceCounter(^counter);
result := counter as f64 / win32_perf_count_freq as f64;
return result;
var counter: i64;
win32.query_performance_counter(&counter);
return f64(counter) / f64(win32_perf_count_freq);
}
win32_print_last_error :: proc() {
err_code := win32.GetLastError() as int;
proc win32_print_last_error() {
var err_code = win32.get_last_error();
if err_code != 0 {
fmt.println("GetLastError: %", err_code);
fmt.println("get_last_error: ", err_code);
}
}
// 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;
proc to_c_string(s: string) -> []u8 {
var c_str = make([]u8, len(s)+1);
copy(c_str, []u8(s));
c_str[len(s)] = 0;
return c_str;
}
Window :: struct {
width, height: int;
wc: win32.WNDCLASSEXA;
dc: win32.HDC;
hwnd: win32.HWND;
opengl_context, rc: win32.HGLRC;
c_title: []u8;
type Window struct {
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) {
proc make_window(title: string, msg, height: int, window_proc: win32.WndProc) -> (Window, bool) {
using win32;
w: Window;
var 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 {
var class_name = "Win32-Odin-Window\x00";
var c_class_name = &class_name[0];
if title[len(title)-1] != 0 {
w.c_title = to_c_string(title);
} else {
w.c_title = title as []u8;
w.c_title = []u8(title);
}
instance := GetModuleHandleA(nil);
var instance = get_module_handle_a(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 = Hinstance(instance),
class_name = c_class_name,
wnd_proc = window_proc,
};
if RegisterClassExA(^w.wc) == 0 {
if register_class_ex_a(&w.wc) == 0 {
win32_print_last_error();
return w, false;
}
w.hwnd = CreateWindowExA(0,
c_class_name, w.c_title.data,
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT,
w.width as i32, w.height as i32,
nil, nil, instance, nil);
w.hwnd = create_window_ex_a(0,
c_class_name, &w.c_title[0],
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT,
i32(w.width), i32(w.height),
nil, nil, instance, nil);
if w.hwnd == nil {
win32_print_last_error();
return w, false;
}
w.dc = GetDC(w.hwnd);
w.dc = get_dc(w.hwnd);
{
pfd := PIXELFORMATDESCRIPTOR{
size = size_of(PIXELFORMATDESCRIPTOR) as u32,
var pfd = PixelFormatDescriptor{
size = size_of(PixelFormatDescriptor),
version = 1,
flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
pixel_type = PFD_TYPE_RGBA,
@@ -96,89 +96,91 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
layer_type = PFD_MAIN_PLANE,
};
SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), nil);
w.opengl_context = wglCreateContext(w.dc);
wglMakeCurrent(w.dc, w.opengl_context);
set_pixel_format(w.dc, choose_pixel_format(w.dc, &pfd), nil);
w.opengl_context = wgl.create_context(w.dc);
wgl.make_current(w.dc, w.opengl_context);
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,
var attribs = [8]i32{
wgl.CONTEXT_MAJOR_VERSION_ARB, 2,
wgl.CONTEXT_MINOR_VERSION_ARB, 1,
wgl.CONTEXT_PROFILE_MASK_ARB, wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
0, // NOTE(bill): tells the proc that this is the end of attribs
};
wglCreateContextAttribsARB := wglGetProcAddress(("wglCreateContextAttribsARB\x00" as string).data) as wglCreateContextAttribsARBType;
w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0]);
wglMakeCurrent(w.dc, w.rc);
SwapBuffers(w.dc);
var wgl_str = "wglCreateContextAttribsARB\x00";
var wglCreateContextAttribsARB = wgl.CreateContextAttribsARBType(wgl.get_proc_address(&wgl_str[0]));
w.rc = wglCreateContextAttribsARB(w.dc, nil, &attribs[0]);
wgl.make_current(w.dc, w.rc);
swap_buffers(w.dc);
}
return w, true;
}
destroy_window :: proc(w: ^Window) {
free(w.c_title.data);
proc destroy_window(w: ^Window) {
free(w.c_title);
}
display_window :: proc(w: ^Window) {
win32.SwapBuffers(w.dc);
proc display_window(w: ^Window) {
win32.swap_buffers(w.dc);
}
run :: proc() {
using win32;
proc run() {
using math;
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
proc win32_proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline {
using win32;
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
os.exit(0);
return 0;
}
return DefWindowProcA(hwnd, msg, wparam, lparam);
return def_window_proc_a(hwnd, msg, wparam, lparam);
}
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc);
var window, window_success = make_window("Odin Language Demo", 854, 480, win32.WndProc(win32_proc));
if !window_success {
return;
}
defer destroy_window(^window);
defer destroy_window(&window);
gl.init();
using win32;
prev_time := time_now();
running := true;
var prev_time = time_now();
var running = true;
pos := Vec2{100, 100};
var pos = Vec2{100, 100};
for running {
curr_time := time_now();
dt := (curr_time - prev_time) as f32;
var curr_time = time_now();
var dt = f32(curr_time - prev_time);
prev_time = curr_time;
msg: MSG;
for PeekMessageA(^msg, nil, 0, 0, PM_REMOVE) > 0 {
var msg: Msg;
for peek_message_a(&msg, nil, 0, 0, PM_REMOVE) > 0 {
if msg.message == WM_QUIT {
running = false;
}
TranslateMessage(^msg);
DispatchMessageA(^msg);
translate_message(&msg);
dispatch_message_a(&msg);
}
if is_key_down(Key_Code.ESCAPE) {
if is_key_down(KeyCode.Escape) {
running = false;
}
{
SPEED :: 500;
v: Vec2;
const SPEED = 500;
var v: Vec2;
if is_key_down(Key_Code.RIGHT) { v[0] += 1; }
if is_key_down(Key_Code.LEFT) { v[0] -= 1; }
if is_key_down(Key_Code.UP) { v[1] += 1; }
if is_key_down(Key_Code.DOWN) { v[1] -= 1; }
if is_key_down(KeyCode.Right) { v[0] += 1; }
if is_key_down(KeyCode.Left) { v[0] -= 1; }
if is_key_down(KeyCode.Up) { v[1] += 1; }
if is_key_down(KeyCode.Down) { v[1] -= 1; }
v = vec2_norm0(v);
v = norm(v);
pos += v * Vec2{SPEED * dt};
}
@@ -188,10 +190,10 @@ 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, f64(window.width),
0, f64(window.height), 0, 1);
draw_rect :: proc(x, y, w, h: f32) {
proc draw_rect(x, y, w, h: f32) {
gl.Begin(gl.TRIANGLES);
defer gl.End();
@@ -206,10 +208,15 @@ run :: proc() {
draw_rect(pos.x, pos.y, 50, 50);
display_window(^window);
ms_to_sleep := (16 - 1000*dt) as i32;
display_window(&window);
var ms_to_sleep = i32(16 - 1000*dt);
if ms_to_sleep > 0 {
win32.Sleep(ms_to_sleep);
win32.sleep(ms_to_sleep);
}
}
}
proc main() {
run();
}
+103 -99
View File
@@ -1,12 +1,12 @@
#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)
type SOCKET uint;
const INVALID_SOCKET = ~SOCKET(0);
AF :: enum i32 {
type AF enum i32 {
UNSPEC = 0, // unspecified
UNIX = 1, // local to host (pipes, portals)
INET = 2, // internetwork: UDP, TCP, etc.
@@ -35,113 +35,117 @@ 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
const (
SOCK_STREAM = 1;
SOCKET_ERROR = -1;
IPPROTO_TCP = 6;
AI_PASSIVE = 0x0020;
SOMAXCONN = 128;
)
const (
SD_RECEIVE = 0;
SD_SEND = 1;
SD_BOTH = 2;
)
SD_RECEIVE :: 0
SD_SEND :: 1
SD_BOTH :: 2
WSADESCRIPTION_LEN :: 256
WSASYS_STATUS_LEN :: 128
WSADATA :: struct #ordered {
version: i16
high_version: i16
const WSADESCRIPTION_LEN = 256;
const WSASYS_STATUS_LEN = 128;
type WSADATA struct #ordered {
version: i16,
high_version: i16,
// NOTE(bill): This is x64 ordering
max_sockets: u16
max_udp_dg: u16
vendor_info: ^byte
description: [WSADESCRIPTION_LEN+1]byte
system_status: [WSASYS_STATUS_LEN+1]byte
max_sockets: u16,
max_udp_dg: u16,
vendor_info: ^u8,
description: [WSADESCRIPTION_LEN+1]u8,
system_status: [WSASYS_STATUS_LEN+1]u8,
}
addrinfo :: struct #ordered {
flags: i32
family: i32
socktype: i32
protocol: i32
addrlen: uint
canonname: ^u8
addr: ^sockaddr
next: ^addrinfo
type addrinfo struct #ordered {
flags: i32,
family: i32,
socktype: i32,
protocol: i32,
addrlen: uint,
canonname: ^u8,
addr: ^sockaddr,
next: ^addrinfo,
}
sockaddr :: struct #ordered {
family: u16
data: [14]byte
type sockaddr struct #ordered {
family: u16,
data: [14]u8,
}
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
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
foreign ws2 {
proc WSAStartup (version_requested: i16, data: ^WSADATA) -> i32;
proc WSACleanup () -> i32;
proc getaddrinfo (node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32;
proc freeaddrinfo (ai: ^addrinfo);
proc socket (af, type_, protocol: i32) -> SOCKET;
proc closesocket (s: SOCKET) -> i32;
proc bind (s: SOCKET, name: ^sockaddr, name_len: i32) -> i32;
proc listen (s: SOCKET, back_log: i32) -> i32;
proc accept (s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET;
proc recv (s: SOCKET, buf: ^u8, len: i32, flags: i32) -> i32;
proc send (s: SOCKET, buf: ^u8, len: i32, flags: i32) -> i32;
proc shutdown (s: SOCKET, how: i32) -> i32;
proc WSAGetLastError() -> i32;
}
proc to_c_string(s: string) -> ^u8 {
var c_str = make([]u8, len(s)+1);
copy(c_str, []u8(s));
c_str[len(s)] = 0;
return &c_str[0];
}
run :: proc() {
wsa: WSADATA
res: ^addrinfo = nil
hints: addrinfo
s, client: SOCKET
proc run() {
var (
wsa: WSADATA;
res: ^addrinfo = nil;
hints: addrinfo;
s, client: SOCKET;
)
if WSAStartup(2 | (2 << 8), ^wsa) != 0 {
fmt.println("WSAStartup failed: ", WSAGetLastError())
return
if WSAStartup(2 | (2 << 8), &wsa) != 0 {
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 = 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
if getaddrinfo(nil, to_c_string("8080"), &hints, &res) != 0 {
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, 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 :=
var html =
`HTTP/1.1 200 OK
Connection: close
Content-type: text/html
@@ -154,27 +158,27 @@ Content-type: text/html
<h1 style="color: orange;">Odin Server Demo</h1>
</body>
</html>
`
`;
buf: [1024]byte
var buf: [1024]u8;
for {
bytes := recv(client, ^buf[0], buf.count as i32, 0)
var bytes = recv(client, &buf[0], i32(len(buf)), 0);
if bytes > 0 {
// fmt.println(buf[:bytes] as string)
bytes_sent := send(client, html.data, (html.count-1) as i32, 0)
// fmt.println(string(buf[0..<bytes]))
var bytes_sent = send(client, &html[0], i32(len(html)-1), 0);
if bytes_sent == SOCKET_ERROR {
fmt.println("send failed: ", WSAGetLastError())
return
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
}
+314 -298
View File
@@ -1,34 +1,42 @@
#import "win32.odin"
#import "fmt.odin"
#import "os.odin"
import (
win32 "sys/windows.odin";
"fmt.odin";
"os.odin";
"mem.odin";
)
CANVAS_WIDTH :: 128
CANVAS_HEIGHT :: 128
CANVAS_SCALE :: 3
FRAME_TIME :: 1.0/30.0
WINDOW_TITLE :: "Punity\x00"
const (
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)
const _ = compile_assert(CANVAS_WIDTH % 16 == 0);
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE
const (
WINDOW_WIDTH = CANVAS_WIDTH * CANVAS_SCALE;
WINDOW_HEIGHT = CANVAS_HEIGHT * CANVAS_SCALE;
)
const (
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
type Core struct {
stack: ^Bank,
storage: ^Bank,
Core :: struct {
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]u8,
key_deltas: [MAX_KEYS]u8,
perf_frame,
perf_frame_inner,
@@ -36,158 +44,154 @@ 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
type Perf_Span struct {
stamp: f64,
delta: f32,
}
Bank :: struct {
memory: []byte
cursor: int
type Bank struct {
memory: []u8,
cursor: int,
}
Bank_State :: struct {
state: Bank
bank: ^Bank
type Bank_State struct {
state: Bank,
bank: ^Bank,
}
Color :: raw_union {
using channels: struct{ a, b, g, r: byte; }
rgba: u32
type Color raw_union {
using channels: struct{a, b, g, r: u8},
rgba: u32,
}
Palette :: struct {
colors: [256]Color
colors_count: byte
type Palette struct {
colors: [256]Color,
colors_count: u8,
}
Rect :: raw_union {
using minmax: struct {
min_x, min_y, max_x, max_y: int
}
using pos: struct {
left, top, right, bottom: int
}
e: [4]int
type 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,
}
Bitmap :: struct {
pixels: []byte
width: int
height: int
type Bitmap struct {
pixels: []u8,
width: int,
height: int,
}
Font :: struct {
using bitmap: Bitmap
char_width: int
char_height: int
type Font struct {
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
type Canvas struct {
using bitmap: ^Bitmap,
palette: Palette,
translate_x: int,
translate_y: int,
clip: Rect,
font: ^Font,
}
DrawFlag :: enum {
type DrawFlag enum {
NONE = 0,
FLIP_H = 1<<0,
FLIP_V = 1<<1,
MASK = 1<<2,
}
Draw_List :: struct {
Item :: struct {
}
items: []Item
type Draw_Item struct {}
type Draw_List struct {
items: []Draw_Item,
}
Key :: enum {
MOD_SHIFT = 0x0001,
MOD_CONTROL = 0x0002,
MOD_ALT = 0x0004,
MOD_SUPER = 0x0008,
type Key enum {
ModShift = 0x0001,
ModControl = 0x0002,
ModAlt = 0x0004,
ModSuper = 0x0008,
UNKNOWN =-1,
INVALID =-2,
LBUTTON = 1,
RBUTTON = 2,
CANCEL = 3,
MBUTTON = 4,
Unknown =-1,
Invalid =-2,
BACK = 8,
TAB = 9,
CLEAR = 12,
RETURN = 13,
SHIFT = 16,
CONTROL = 17,
MENU = 18,
PAUSE = 19,
CAPITAL = 20,
KANA = 0x15,
HANGEUL = 0x15,
HANGUL = 0x15,
JUNJA = 0x17,
FINAL = 0x18,
HANJA = 0x19,
KANJI = 0x19,
ESCAPE = 0x1B,
CONVERT = 0x1C,
NONCONVERT = 0x1D,
ACCEPT = 0x1E,
MODECHANGE = 0x1F,
SPACE = 32,
PRIOR = 33,
NEXT = 34,
END = 35,
HOME = 36,
LEFT = 37,
UP = 38,
RIGHT = 39,
DOWN = 40,
SELECT = 41,
PRINT = 42,
EXEC = 43,
SNAPSHOT = 44,
INSERT = 45,
DELETE = 46,
HELP = 47,
LWIN = 0x5B,
RWIN = 0x5C,
APPS = 0x5D,
SLEEP = 0x5F,
NUMPAD0 = 0x60,
NUMPAD1 = 0x61,
NUMPAD2 = 0x62,
NUMPAD3 = 0x63,
NUMPAD4 = 0x64,
NUMPAD5 = 0x65,
NUMPAD6 = 0x66,
NUMPAD7 = 0x67,
NUMPAD8 = 0x68,
NUMPAD9 = 0x69,
MULTIPLY = 0x6A,
ADD = 0x6B,
SEPARATOR = 0x6C,
SUBTRACT = 0x6D,
DECIMAL = 0x6E,
DIVIDE = 0x6F,
Lbutton = 1,
Rbutton = 2,
Cancel = 3,
Mbutton = 4,
Back = 8,
Tab = 9,
Clear = 12,
Return = 13,
Shift = 16,
Control = 17,
Menu = 18,
Pause = 19,
Capital = 20,
Kana = 0x15,
Hangeul = 0x15,
Hangul = 0x15,
Junja = 0x17,
Final = 0x18,
Hanja = 0x19,
Kanji = 0x19,
Escape = 0x1B,
Convert = 0x1C,
NonConvert = 0x1D,
Accept = 0x1E,
ModeChange = 0x1F,
Space = 32,
Prior = 33,
Next = 34,
End = 35,
Home = 36,
Left = 37,
Up = 38,
Right = 39,
Down = 40,
Select = 41,
Print = 42,
Exec = 43,
Snapshot = 44,
Insert = 45,
Delete = 46,
Help = 47,
Lwin = 0x5B,
Rwin = 0x5C,
Apps = 0x5D,
Sleep = 0x5F,
Numpad0 = 0x60,
Numpad1 = 0x61,
Numpad2 = 0x62,
Numpad3 = 0x63,
Numpad4 = 0x64,
Numpad5 = 0x65,
Numpad6 = 0x66,
Numpad7 = 0x67,
Numpad8 = 0x68,
Numpad9 = 0x69,
Multiply = 0x6A,
Add = 0x6B,
Separator = 0x6C,
Subtract = 0x6D,
Decimal = 0x6E,
Divide = 0x6F,
F1 = 0x70,
F2 = 0x71,
F3 = 0x72,
@@ -212,32 +216,33 @@ Key :: enum {
F22 = 0x85,
F23 = 0x86,
F24 = 0x87,
NUMLOCK = 0x90,
SCROLL = 0x91,
LSHIFT = 0xA0,
RSHIFT = 0xA1,
LCONTROL = 0xA2,
RCONTROL = 0xA3,
LMENU = 0xA4,
RMENU = 0xA5,
Numlock = 0x90,
Scroll = 0x91,
Lshift = 0xA0,
Rshift = 0xA1,
Lcontrol = 0xA2,
Rcontrol = 0xA3,
Lmenu = 0xA4,
Rmenu = 0xA5,
APOSTROPHE = 39, /* ' */
COMMA = 44, /* , */
MINUS = 45, /* - */
PERIOD = 46, /* . */
SLASH = 47, /* / */
NUM0 = 48,
NUM1 = 49,
NUM2 = 50,
NUM3 = 51,
NUM4 = 52,
NUM5 = 53,
NUM6 = 54,
NUM7 = 55,
NUM8 = 56,
NUM9 = 57,
SEMICOLON = 59, /* ; */
EQUAL = 61, /* = */
Apostrophe = 39, /* ' */
Comma = 44, /* , */
Minus = 45, /* - */
Period = 46, /* . */
Slash = 47, /* / */
Num0 = 48,
Num1 = 49,
Num2 = 50,
Num3 = 51,
Num4 = 52,
Num5 = 53,
Num6 = 54,
Num7 = 55,
Num8 = 56,
Num9 = 57,
Semicolon = 59, /* ; */
Equal = 61, /* = */
A = 65,
B = 66,
C = 67,
@@ -264,219 +269,230 @@ Key :: enum {
X = 88,
Y = 89,
Z = 90,
LEFT_BRACKET = 91, /* [ */
BACKSLASH = 92, /* \ */
RIGHT_BRACKET = 93, /* ] */
GRAVE_ACCENT = 96, /* ` */
LeftBracket = 91, /* [ */
Backslash = 92, /* \ */
RightBracket = 93, /* ] */
GraveAccent = 96, /* ` */
};
proc key_down(k: Key) -> bool {
return _core.key_states[k] != 0;
}
key_down :: proc(k: Key) -> bool {
return _core.key_states[k] != 0
}
key_pressed :: proc(k: Key) -> bool {
return (_core.key_deltas[k] != 0) && key_down(k)
proc key_pressed(k: Key) -> bool {
return (_core.key_deltas[k] != 0) && key_down(k);
}
win32_perf_count_freq := win32.GetQueryPerformanceFrequency()
time_now :: proc() -> f64 {
assert(win32_perf_count_freq != 0)
let win32_perf_count_freq = win32.get_query_performance_frequency();
proc time_now() -> f64 {
assert(win32_perf_count_freq != 0);
counter: i64
win32.QueryPerformanceCounter(^counter)
result := counter as f64 / win32_perf_count_freq as f64
return result
var counter: i64;
win32.query_performance_counter(&counter);
return f64(counter) / f64(win32_perf_count_freq);
}
_core: Core
var _core: Core;
run :: proc(user_init, user_step: proc(c: ^Core)) {
using win32
proc run(user_init, user_step: proc(c: ^Core)) {
using win32;
_core.running = true
_core.running = true;
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline #stdcall {
win32_app_key_mods :: proc() -> u32 {
mods: u32 = 0
proc win32_proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline #cc_c {
proc win32_app_key_mods() -> u32 {
var mods: u32 = 0;
if is_key_down(Key_Code.SHIFT) {
mods |= Key.MOD_SHIFT as u32
if is_key_down(KeyCode.Shift) {
mods |= u32(Key.ModShift);
}
if is_key_down(Key_Code.CONTROL) {
mods |= Key.MOD_CONTROL as u32
if is_key_down(KeyCode.Control) {
mods |= u32(Key.ModControl);
}
if is_key_down(Key_Code.MENU) {
mods |= Key.MOD_ALT as u32
if is_key_down(KeyCode.Menu) {
mods |= u32(Key.ModAlt);
}
if is_key_down(Key_Code.LWIN) || is_key_down(Key_Code.RWIN) {
mods |= Key.MOD_SUPER as u32
if is_key_down(KeyCode.Lwin) || is_key_down(KeyCode.Rwin) {
mods |= u32(Key.ModSuper);
}
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
post_quit_message(0);
_core.running = false;
return 0;
}
return DefWindowProcA(hwnd, msg, wparam, lparam)
return def_window_proc_a(hwnd, msg, wparam, lparam);
}
window_class := WNDCLASSEXA{
class_name = ("Punity\x00" as string).data, // C-style string
size = size_of(WNDCLASSEXA) as u32,
var class_name = "Punity\x00";
var window_class = WndClassExA{
class_name = &class_name[0],
size = size_of(WndClassExA),
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
instance = GetModuleHandleA(nil) as HINSTANCE,
instance = Hinstance(get_module_handle_a(nil)),
wnd_proc = win32_proc,
// wnd_proc = DefWindowProcA,
background = GetStockObject(BLACK_BRUSH) as HBRUSH,
background = Hbrush(get_stock_object(BLACK_BRUSH)),
};
if register_class_ex_a(&window_class) == 0 {
fmt.fprintln(os.stderr, "register_class_ex_a failed");
return;
}
if RegisterClassExA(^window_class) == 0 {
fmt.fprintln(os.stderr, "RegisterClassExA failed")
return
}
var screen_width = get_system_metrics(SM_CXSCREEN);
var screen_height = get_system_metrics(SM_CYSCREEN);
screen_width := GetSystemMetrics(SM_CXSCREEN)
screen_height := GetSystemMetrics(SM_CYSCREEN)
var rc: Rect;
rc.left = (screen_width - WINDOW_WIDTH) / 2;
rc.top = (screen_height - WINDOW_HEIGHT) / 2;
rc.right = rc.left + WINDOW_WIDTH;
rc.bottom = rc.top + WINDOW_HEIGHT;
rc: RECT
rc.left = (screen_width - WINDOW_WIDTH) / 2
rc.top = (screen_height - WINDOW_HEIGHT) / 2
rc.right = rc.left + WINDOW_WIDTH
rc.bottom = rc.top + WINDOW_HEIGHT
var style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
assert(adjust_window_rect(&rc, style, 0) != 0);
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
assert(AdjustWindowRect(^rc, style, 0) != 0)
var wt = WINDOW_TITLE;
wt := WINDOW_TITLE
win32_window := CreateWindowExA(0,
window_class.class_name,
wt.data,
style,
rc.left, rc.top,
rc.right-rc.left, rc.bottom-rc.top,
nil, nil, window_class.instance,
nil)
var win32_window = create_window_ex_a(0,
window_class.class_name,
&wt[0],
style,
rc.left, rc.top,
rc.right-rc.left, rc.bottom-rc.top,
nil, nil, window_class.instance,
nil);
if win32_window == nil {
fmt.fprintln(os.stderr, "CreateWindowExA failed")
return
fmt.fprintln(os.stderr, "create_window_ex_a 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
var window_bmi: BitmapInfo;
window_bmi.size = size_of(BitmapInfoHeader);
window_bmi.width = CANVAS_WIDTH;
window_bmi.height = CANVAS_HEIGHT;
window_bmi.planes = 1;
window_bmi.bit_count = 32;
window_bmi.compression = BI_RGB;
user_init(^_core)
user_init(&_core);
show_window(win32_window, SW_SHOW);
ShowWindow(win32_window, SW_SHOW)
var window_buffer = make([]u32, CANVAS_WIDTH * CANVAS_HEIGHT);
defer free(window_buffer);
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 in window_buffer {
window_buffer[i] = 0xff00ff;
}
var (
dt: f64;
prev_time = time_now();
curr_time = time_now();
total_time : f64 = 0;
offset_x = 0;
offset_y = 0;
)
prev_time, curr_time,dt: f64
prev_time = time_now()
curr_time = time_now()
total_time : f64 = 0
offset_x := 0
offset_y := 0
message: MSG
var 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)
var buf: [128]u8;
var s = fmt.bprintf(buf[..], "Punity: %.4f ms\x00", dt*1000);
win32.set_window_text_a(win32_window, &s[0]);
}
for 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 var y = 0; y < CANVAS_HEIGHT; y++ {
for var x = 0; x < CANVAS_WIDTH; x++ {
var g = (x % 32) * 8;
var b = (y % 32) * 8;
window_buffer[x + y*CANVAS_WIDTH] = u32(g << 8 | b);
}
}
_core.key_deltas = nil
mem.zero(&_core.key_deltas[0], size_of(_core.key_deltas));
for PeekMessageA(^message, nil, 0, 0, PM_REMOVE) != 0 {
for peek_message_a(&message, nil, 0, 0, PM_REMOVE) != 0 {
if message.message == WM_QUIT {
_core.running = false
_core.running = false;
}
TranslateMessage(^message)
DispatchMessageA(^message)
translate_message(&message);
dispatch_message_a(&message);
}
user_step(^_core)
user_step(&_core);
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)
var dc = get_dc(win32_window);
stretch_dibits(dc,
0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
&window_buffer[0],
&window_bmi,
DIB_RGB_COLORS,
SRCCOPY);
release_dc(win32_window, dc);
{
delta := time_now() - prev_time
ms := ((FRAME_TIME - delta) * 1000) as i32
var delta = time_now() - prev_time;
var ms = i32((FRAME_TIME - delta) * 1000);
if ms > 0 {
win32.Sleep(ms)
win32.sleep(ms);
}
}
_core.frame++
_core.frame++;
}
}
proc main() {
proc user_init(c: ^Core) {
}
proc user_step(c: ^Core) {
}
run(user_init, user_step);
}
-5
View File
@@ -1,5 +0,0 @@
#import "fmt.odin" as fmt
thing :: proc() {
fmt.println("Sub Hello!")
}
-35
View File
@@ -1,35 +0,0 @@
/*#import "fmt.odin"
thing :: proc() {
fmt.println("Hello1!")
}*/
#import "fmt.odin" as format
thing :: proc() {
format.println("Hello2!")
}
/*#import "fmt.odin" as .
thing :: proc() {
println("Hello3!")
}
*/
/*#import "fmt.odin" as _
thing :: proc() {
// println("Hello4!")
}
*/
/*
#include "fmt.odin"
thing :: proc() {
println("Hello5!")
}*/
+709 -231
View File
File diff suppressed because it is too large Load Diff
+211 -142
View File
@@ -1,158 +1,227 @@
#shared_global_scope;
// import "fmt.odin";
// proc __u128_mod(a, b: u128) -> u128 #link_name "__umodti3" {
// var _, r := __u128_quo_mod(a, b)
// return r
// }
// proc __u128_quo(a, b: u128) -> u128 #link_name "__udivti3" {
// var n, _ := __u128_quo_mod(a, b)
// return n
// }
// proc __i128_mod(a, b: i128) -> i128 #link_name "__modti3" {
// var _, r := __i128_quo_mod(a, b)
// return r
// }
// proc __i128_quo(a, b: i128) -> i128 #link_name "__divti3" {
// var n, _ := __i128_quo_mod(a, b)
// return n
// }
// proc __i128_quo_mod(a, b: i128) -> (i128, i128) #link_name "__divmodti4" {
// var s := b >> 127
// b = (b ~ s) - s
// s = a >> 127
// a = (a ~ s) - s
// var n, r := __u128_quo_mod(a as u128, b as u128)
// return (n as i128 ~ s) - s, (r as i128 ~ s) - s
// }
proc __multi3(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
const bits_in_dword_2 = size_of(i64) * 4;
const lower_mask = u128(~u64(0) >> bits_in_dword_2);
// proc __u128_quo_mod(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" {
// proc clz(x: u64) -> u64 {
// proc clz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64"
// return clz_u64(x, false)
// }
// proc ctz(x: u64) -> u64 {
// proc ctz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.cttz.i64"
// return ctz_u64(x, false)
// }
when ODIN_ENDIAN == "bit" {
type TWords raw_union {
all: u128,
using _: struct {lo, hi: u64},
};
} else {
type TWords raw_union {
all: u128,
using _: struct {hi, lo: u64},
};
}
var r: TWords;
var t: u64;
r.lo = u64(a & lower_mask) * u64(b & lower_mask);
t = r.lo >> bits_in_dword_2;
r.lo &= u64(lower_mask);
t += u64(a >> bits_in_dword_2) * u64(b & lower_mask);
r.lo += u64(t & u64(lower_mask)) << bits_in_dword_2;
r.hi = t >> bits_in_dword_2;
t = r.lo >> bits_in_dword_2;
r.lo &= u64(lower_mask);
t += u64(b >> bits_in_dword_2) * u64(a & lower_mask);
r.lo += u64(t & u64(lower_mask)) << bits_in_dword_2;
r.hi += t >> bits_in_dword_2;
r.hi += u64(a >> bits_in_dword_2) * u64(b >> bits_in_dword_2);
return r.all;
}
proc __u128_mod(a, b: u128) -> u128 #cc_c #link_name "__umodti3" {
var r: u128;
__u128_quo_mod(a, b, &r);
return r;
}
proc __u128_quo(a, b: u128) -> u128 #cc_c #link_name "__udivti3" {
return __u128_quo_mod(a, b, nil);
}
proc __i128_mod(a, b: i128) -> i128 #cc_c #link_name "__modti3" {
var r: i128;
__i128_quo_mod(a, b, &r);
return r;
}
proc __i128_quo(a, b: i128) -> i128 #cc_c #link_name "__divti3" {
return __i128_quo_mod(a, b, nil);
}
proc __i128_quo_mod(a, b: i128, rem: ^i128) -> (quo: i128) #cc_c #link_name "__divmodti4" {
var s: i128;
s = b >> 127;
b = (b~s) - s;
s = a >> 127;
b = (a~s) - s;
var uquo: u128;
var urem = __u128_quo_mod(transmute(u128, a), transmute(u128, b), &uquo);
var iquo = transmute(i128, uquo);
var irem = transmute(i128, urem);
iquo = (iquo~s) - s;
irem = (irem~s) - s;
if rem != nil { rem^ = irem; }
return iquo;
}
// u128_lo_hi :: raw_union {
// all: u128
// using _lohi: struct {lo, hi: u64;}
// }
proc __u128_quo_mod(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "__udivmodti4" {
var alo, ahi = u64(a), u64(a>>64);
var blo, bhi = u64(b), u64(b>>64);
if b == 0 {
if rem != nil { rem^ = 0; }
return u128(alo/blo);
}
// n, d, q, r: u128_lo_hi
// sr: u64
var r, d, x, q: u128 = a, b, 1, 0;
// n.all = a
// d.all = b
for r >= d && (d>>127)&1 == 0 {
x <<= 1;
d <<= 1;
}
// if n.hi == 0 {
// if d.hi == 0 {
// return (n.lo / d.lo) as u128, (n.lo % d.lo) as u128
// }
// return 0, n.lo as u128
// }
// if d.lo == 0 {
// if d.hi == 0 {
// return (n.hi / d.lo) as u128, (n.hi % d.lo) as u128
// }
// if n.lo == 0 {
// r.hi = n.hi % d.hi
// r.lo = 0
// return (n.hi / d.hi) as u128, r.all
// }
// if (d.hi & (d.hi-1)) == 0 {
// r.lo = n.lo
// r.hi = n.hi & (d.hi-1)
// return (n.hi >> ctz(d.hi)) as u128, r.all
// }
for x != 0 {
if r >= d {
r -= d;
q |= x;
}
x >>= 1;
d >>= 1;
}
// sr = clz(d.hi) - clz(n.hi)
// if sr > 64 - 2 {
// return 0, n.all
// }
// sr++
// q.lo = 0
// q.hi = n.lo << (64-sr)
// r.hi = n.hi >> sr
// r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
// } else {
// if d.hi == 0 {
// if (d.lo & (d.lo - 1)) == 0 {
// var rem := (n.lo % (d.lo - 1)) as u128
// if d.lo == 1 {
// return n.all, rem
// }
// sr = ctz(d.lo)
// q.hi = n.hi >> sr
// q.lo = (n.hi << (64-sr)) | (n.lo >> sr)
// return q.all, rem
// }
if rem != nil { rem^ = r; }
return q;
}
// sr = 1 + 64 + clz(d.lo) - clz(n.hi)
/*
proc __f16_to_f32(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee" {
when true {
// Source: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
const FP32 = raw_union {u: u32, f: f32};
// q.all = n.all << (128-sr)
// r.all = n.all >> sr
// if sr == 64 {
// q.lo = 0
// q.hi = n.lo
// r.hi = 0
// r.lo = n.hi
// } else if sr < 64 {
// q.lo = 0
// q.hi = n.lo << (64-sr)
// r.hi = n.hi >> sr
// r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
// } else {
// q.lo = n.lo << (128-sr)
// q.hi = (n.hi << (128-sr)) | (n.lo >> (sr-64))
// r.hi = 0
// r.lo = n.hi >> (sr-64)
// }
// } else {
// sr = clz(d.hi) - clz(n.hi)
// if sr > 64-1 {
// return 0, n.all
// }
// sr++
// q.lo = 0
// q.hi = n.lo << (64-sr)
// r.all = n.all >> sr
// if sr < 64 {
// r.hi = n.hi >> sr
// r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
// } else {
// r.hi = 0
// r.lo = n.hi
// }
// }
// }
magic, was_infnan: FP32;
magic.u = (254-15) << 23;
was_infnan.u = (127+16) << 23;
// carry: u64
// for ; sr > 0; sr-- {
// r.hi = (r.hi << 1) | (r.lo >> (64-1))
// r.lo = (r.lo << 1) | (r.hi >> (64-1))
// q.hi = (q.hi << 1) | (q.lo >> (64-1))
// q.lo = (q.lo << 1) | carry
hu := transmute(u16, f);
// carry = 0
// if r.all >= d.all {
// r.all -= d.all
// carry = 1
// }
// }
o := FP32{};
// q.all = (q.all << 1) | (carry as u128)
// return q.all, r.all
// }
o.u = u32(hu & 0x7fff) << 13);
o.f *= magic.f;
if o.f >= was_infnan.f {
o.u |= 255 << 23;
}
o.u |= u32(hu & 0x8000) << 16;
return o.f;
} else {
return 0;
}
}
proc __f32_to_f16(f_: f32) -> f16 #cc_c #no_inline #link_name "__gnu_f2h_ieee" {
when false {
// Source: https://gist.github.com/rygorous/2156668
const FP16 = raw_union {u: u16, f: f16};
const FP32 = raw_union {u: u32, f: f32};
f32infty, f16infty, magic: FP32;
f32infty.u = 255<<23;
f16infty.u = 31<<23;
magic.u = 15<<23;
const sign_mask = u32(0x80000000);
const round_mask = ~u32(0x0fff);
f := transmute(FP32, f_);
o: FP16;
sign := f.u & sign_mask;
f.u ~= sign;
// NOTE all the integer compares in this function can be safely
// compiled into signed compares since all operands are below
// 0x80000000. Important if you want fast straight SSE2 code
// (since there's no unsigned PCMPGTD).
if f.u >= f32infty.u { // Inf or NaN (all exponent bits set)
o.u = f.u > f32infty.u ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf
} else { // (De)normalized number or zero
f.u &= round_mask;
f.f *= magic.f;
f.u -= round_mask;
if f.u > f16infty.u {
f.u = f16infty.u; // Clamp to signed infinity if overflowed
}
o.u = u16(f.u >> 13); // Take the bits!
}
o.u |= u16(sign >> 16);
return o.f;
} else {
f := transmute(u32, f_);
h: u16;
hs, he, hf: u16;
fs := (f >> 31) & 1;
fe := (f >> 23) & 0b1111_1111;
ff := (f >> 0) & 0b0111_1111_1111_1111_1111_1111;
add_one := false;
if (fe == 0) {
he = 0;
} else if (fe == 255) {
he = 31;
hf = ff != 0 ? 0x200 : 0;
} else {
ne := fe - 127 + 15;
if ne >= 31 {
he = 31;
} else if ne <= 0 {
if (14-ne) <= 24 {
mant := ff | 0x800000;
hf = u16(mant >> (14-ne));
if (mant >> (13-ne)) & 1 != 0 {
add_one = true;
}
}
} else {
he = u16(ne);
hf = u16(ff >> 13);
if ff&0x1000 != 0 {
add_one = true;
}
}
}
hs = u16(hs);
h |= (he&0b0001_1111)<<10;
h |= (hf&0b0011_1111_1111);
if add_one {
h++;
}
h |= (hs&1) << 15;
return transmute(f16, h);
}
}
proc __f64_to_f16(f: f64) -> f16 #cc_c #no_inline #link_name "__truncdfhf2" {
return __f32_to_f16(f32(f));
}
proc __f16_to_f64(f: f16) -> f64 #cc_c #no_inline {
return f64(__f16_to_f32(f));
}
*/
-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";
var _ = compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
proc yield_thread() { win32.mm_pause(); }
proc mfence () { win32.read_write_barrier(); }
proc sfence () { win32.write_barrier(); }
proc lfence () { win32.read_barrier(); }
proc load(a: ^i32) -> i32 {
return a^;
}
proc store(a: ^i32, value: i32) {
a^ = value;
}
proc compare_exchange(a: ^i32, expected, desired: i32) -> i32 {
return win32.interlocked_compare_exchange(a, desired, expected);
}
proc exchanged(a: ^i32, desired: i32) -> i32 {
return win32.interlocked_exchange(a, desired);
}
proc fetch_add(a: ^i32, operand: i32) -> i32 {
return win32.interlocked_exchange_add(a, operand);
}
proc fetch_and(a: ^i32, operand: i32) -> i32 {
return win32.interlocked_and(a, operand);
}
proc fetch_or(a: ^i32, operand: i32) -> i32 {
return win32.interlocked_or(a, operand);
}
proc spin_lock(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
var old_value = compare_exchange(a, 1, 0);
var counter = 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter++;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
}
return old_value == 0;
}
proc spin_unlock(a: ^i32) {
store(a, 0);
mfence();
}
proc try_acquire_lock(a: ^i32) -> bool {
yield_thread();
var old_value = compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}
proc load(a: ^i64) -> i64 {
return a^;
}
proc store(a: ^i64, value: i64) {
a^ = value;
}
proc compare_exchange(a: ^i64, expected, desired: i64) -> i64 {
return win32.interlocked_compare_exchange64(a, desired, expected);
}
proc exchanged(a: ^i64, desired: i64) -> i64 {
return win32.interlocked_exchange64(a, desired);
}
proc fetch_add(a: ^i64, operand: i64) -> i64 {
return win32.interlocked_exchange_add64(a, operand);
}
proc fetch_and(a: ^i64, operand: i64) -> i64 {
return win32.interlocked_and64(a, operand);
}
proc fetch_or(a: ^i64, operand: i64) -> i64 {
return win32.interlocked_or64(a, operand);
}
proc spin_lock(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
var old_value = compare_exchange(a, 1, 0);
var counter = 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter++;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
}
return old_value == 0;
}
proc spin_unlock(a: ^i64) {
store(a, 0);
mfence();
}
proc try_acquire_lock(a: ^i64) -> bool {
yield_thread();
var old_value = compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}
+287
View File
@@ -0,0 +1,287 @@
const (
U8_MIN = u8(0);
U16_MIN = u16(0);
U32_MIN = u32(0);
U64_MIN = u64(0);
U128_MIN = u128(0);
I8_MIN = i8(-0x80);
I16_MIN = i16(-0x8000);
I32_MIN = i32(-0x8000_0000);
I64_MIN = i64(-0x8000_0000_0000_0000);
I128_MIN = i128(-0x8000_0000_0000_0000_0000_0000_0000_0000);
U8_MAX = ~u8(0);
U16_MAX = ~u16(0);
U32_MAX = ~u32(0);
U64_MAX = ~u64(0);
U128_MAX = ~u128(0);
I8_MAX = i8(0x7f);
I16_MAX = i16(0x7fff);
I32_MAX = i32(0x7fff_ffff);
I64_MAX = i64(0x7fff_ffff_ffff_ffff);
I128_MAX = i128(0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ffff);
)
proc count_ones(i: u8) -> u8 { foreign __llvm_core proc __llvm_ctpop(u8) -> u8 #link_name "llvm.ctpop.i8"; return __llvm_ctpop(i); }
proc count_ones(i: i8) -> i8 { foreign __llvm_core proc __llvm_ctpop(i8) -> i8 #link_name "llvm.ctpop.i8"; return __llvm_ctpop(i); }
proc count_ones(i: u16) -> u16 { foreign __llvm_core proc __llvm_ctpop(u16) -> u16 #link_name "llvm.ctpop.i16"; return __llvm_ctpop(i); }
proc count_ones(i: i16) -> i16 { foreign __llvm_core proc __llvm_ctpop(i16) -> i16 #link_name "llvm.ctpop.i16"; return __llvm_ctpop(i); }
proc count_ones(i: u32) -> u32 { foreign __llvm_core proc __llvm_ctpop(u32) -> u32 #link_name "llvm.ctpop.i32"; return __llvm_ctpop(i); }
proc count_ones(i: i32) -> i32 { foreign __llvm_core proc __llvm_ctpop(i32) -> i32 #link_name "llvm.ctpop.i32"; return __llvm_ctpop(i); }
proc count_ones(i: u64) -> u64 { foreign __llvm_core proc __llvm_ctpop(u64) -> u64 #link_name "llvm.ctpop.i64"; return __llvm_ctpop(i); }
proc count_ones(i: i64) -> i64 { foreign __llvm_core proc __llvm_ctpop(i64) -> i64 #link_name "llvm.ctpop.i64"; return __llvm_ctpop(i); }
proc count_ones(i: u128) -> u128 { foreign __llvm_core proc __llvm_ctpop(u128) -> u128 #link_name "llvm.ctpop.i128";return __llvm_ctpop(i); }
proc count_ones(i: i128) -> i128 { foreign __llvm_core proc __llvm_ctpop(i128) -> i128 #link_name "llvm.ctpop.i128";return __llvm_ctpop(i); }
proc count_ones(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(count_ones(u32(i))); } else { return uint(count_ones(u64(i))); } }
proc count_ones(i: int) -> int { when size_of(int) == size_of(i32) { return int(count_ones(i32(i))); } else { return int(count_ones(i64(i))); } }
proc count_zeros(i: u8) -> u8 { return 8 - count_ones(i); }
proc count_zeros(i: i8) -> i8 { return 8 - count_ones(i); }
proc count_zeros(i: u16) -> u16 { return 16 - count_ones(i); }
proc count_zeros(i: i16) -> i16 { return 16 - count_ones(i); }
proc count_zeros(i: u32) -> u32 { return 32 - count_ones(i); }
proc count_zeros(i: i32) -> i32 { return 32 - count_ones(i); }
proc count_zeros(i: u64) -> u64 { return 64 - count_ones(i); }
proc count_zeros(i: i64) -> i64 { return 64 - count_ones(i); }
proc count_zeros(i: u128) -> u128 { return 128 - count_ones(i); }
proc count_zeros(i: i128) -> i128 { return 128 - count_ones(i); }
proc count_zeros(i: uint) -> uint { return 8*size_of(uint) - count_ones(i); }
proc count_zeros(i: int) -> int { return 8*size_of(int) - count_ones(i); }
proc rotate_left(i: u8, s: uint) -> u8 { return (i << s)|(i >> (8*size_of(u8) - s)); }
proc rotate_left(i: i8, s: uint) -> i8 { return (i << s)|(i >> (8*size_of(i8) - s)); }
proc rotate_left(i: u16, s: uint) -> u16 { return (i << s)|(i >> (8*size_of(u16) - s)); }
proc rotate_left(i: i16, s: uint) -> i16 { return (i << s)|(i >> (8*size_of(i16) - s)); }
proc rotate_left(i: u32, s: uint) -> u32 { return (i << s)|(i >> (8*size_of(u32) - s)); }
proc rotate_left(i: i32, s: uint) -> i32 { return (i << s)|(i >> (8*size_of(i32) - s)); }
proc rotate_left(i: u64, s: uint) -> u64 { return (i << s)|(i >> (8*size_of(u64) - s)); }
proc rotate_left(i: i64, s: uint) -> i64 { return (i << s)|(i >> (8*size_of(i64) - s)); }
proc rotate_left(i: u128, s: uint) -> u128 { return (i << s)|(i >> (8*size_of(u128) - s)); }
proc rotate_left(i: i128, s: uint) -> i128 { return (i << s)|(i >> (8*size_of(i128) - s)); }
proc rotate_left(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_left(u32(i), s)); } else { return uint(rotate_left(u64(i), s)); } }
proc rotate_left(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_left(i32(i), s)); } else { return int(rotate_left(i64(i), s)); } }
proc rotate_right(i: u8, s: uint) -> u8 { return (i >> s)|(i << (8*size_of(u8) - s)); }
proc rotate_right(i: i8, s: uint) -> i8 { return (i >> s)|(i << (8*size_of(i8) - s)); }
proc rotate_right(i: u16, s: uint) -> u16 { return (i >> s)|(i << (8*size_of(u16) - s)); }
proc rotate_right(i: i16, s: uint) -> i16 { return (i >> s)|(i << (8*size_of(i16) - s)); }
proc rotate_right(i: u32, s: uint) -> u32 { return (i >> s)|(i << (8*size_of(u32) - s)); }
proc rotate_right(i: i32, s: uint) -> i32 { return (i >> s)|(i << (8*size_of(i32) - s)); }
proc rotate_right(i: u64, s: uint) -> u64 { return (i >> s)|(i << (8*size_of(u64) - s)); }
proc rotate_right(i: i64, s: uint) -> i64 { return (i >> s)|(i << (8*size_of(i64) - s)); }
proc rotate_right(i: u128, s: uint) -> u128 { return (i >> s)|(i << (8*size_of(u128) - s)); }
proc rotate_right(i: i128, s: uint) -> i128 { return (i >> s)|(i << (8*size_of(i128) - s)); }
proc rotate_right(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_right(u32(i), s)); } else { return uint(rotate_right(u64(i), s)); } }
proc rotate_right(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_right(i32(i), s)); } else { return int(rotate_right(i64(i), s)); } }
proc leading_zeros(i: u8) -> u8 { foreign __llvm_core proc __llvm_ctlz(u8, bool) -> u8 #link_name "llvm.ctlz.i8"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: i8) -> i8 { foreign __llvm_core proc __llvm_ctlz(i8, bool) -> i8 #link_name "llvm.ctlz.i8"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: u16) -> u16 { foreign __llvm_core proc __llvm_ctlz(u16, bool) -> u16 #link_name "llvm.ctlz.i16"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: i16) -> i16 { foreign __llvm_core proc __llvm_ctlz(i16, bool) -> i16 #link_name "llvm.ctlz.i16"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: u32) -> u32 { foreign __llvm_core proc __llvm_ctlz(u32, bool) -> u32 #link_name "llvm.ctlz.i32"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: i32) -> i32 { foreign __llvm_core proc __llvm_ctlz(i32, bool) -> i32 #link_name "llvm.ctlz.i32"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: u64) -> u64 { foreign __llvm_core proc __llvm_ctlz(u64, bool) -> u64 #link_name "llvm.ctlz.i64"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: i64) -> i64 { foreign __llvm_core proc __llvm_ctlz(i64, bool) -> i64 #link_name "llvm.ctlz.i64"; return __llvm_ctlz(i, false); }
proc leading_zeros(i: u128) -> u128 { foreign __llvm_core proc __llvm_ctlz(u128, bool) -> u128 #link_name "llvm.ctlz.i128";return __llvm_ctlz(i, false); }
proc leading_zeros(i: i128) -> i128 { foreign __llvm_core proc __llvm_ctlz(i128, bool) -> i128 #link_name "llvm.ctlz.i128";return __llvm_ctlz(i, false); }
proc leading_zeros(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(leading_zeros(u32(i))); } else { return uint(leading_zeros(u64(i))); } }
proc leading_zeros(i: int) -> int { when size_of(int) == size_of(i32) { return int(leading_zeros(i32(i))); } else { return int(leading_zeros(i64(i))); } }
proc trailing_zeros(i: u8) -> u8 { foreign __llvm_core proc __llvm_cttz(u8, bool) -> u8 #link_name "llvm.cttz.i8"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: i8) -> i8 { foreign __llvm_core proc __llvm_cttz(i8, bool) -> i8 #link_name "llvm.cttz.i8"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: u16) -> u16 { foreign __llvm_core proc __llvm_cttz(u16, bool) -> u16 #link_name "llvm.cttz.i16"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: i16) -> i16 { foreign __llvm_core proc __llvm_cttz(i16, bool) -> i16 #link_name "llvm.cttz.i16"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: u32) -> u32 { foreign __llvm_core proc __llvm_cttz(u32, bool) -> u32 #link_name "llvm.cttz.i32"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: i32) -> i32 { foreign __llvm_core proc __llvm_cttz(i32, bool) -> i32 #link_name "llvm.cttz.i32"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: u64) -> u64 { foreign __llvm_core proc __llvm_cttz(u64, bool) -> u64 #link_name "llvm.cttz.i64"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: i64) -> i64 { foreign __llvm_core proc __llvm_cttz(i64, bool) -> i64 #link_name "llvm.cttz.i64"; return __llvm_cttz(i, false); }
proc trailing_zeros(i: u128) -> u128 { foreign __llvm_core proc __llvm_cttz(u128, bool) -> u128 #link_name "llvm.cttz.i128";return __llvm_cttz(i, false); }
proc trailing_zeros(i: i128) -> i128 { foreign __llvm_core proc __llvm_cttz(i128, bool) -> i128 #link_name "llvm.cttz.i128";return __llvm_cttz(i, false); }
proc trailing_zeros(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(trailing_zeros(u32(i))); } else { return uint(trailing_zeros(u64(i))); } }
proc trailing_zeros(i: int) -> int { when size_of(int) == size_of(i32) { return int(trailing_zeros(i32(i))); } else { return int(trailing_zeros(i64(i))); } }
proc reverse_bits(i: u8) -> u8 { foreign __llvm_core proc __llvm_bitreverse(u8) -> u8 #link_name "llvm.bitreverse.i8"; return __llvm_bitreverse(i); }
proc reverse_bits(i: i8) -> i8 { foreign __llvm_core proc __llvm_bitreverse(i8) -> i8 #link_name "llvm.bitreverse.i8"; return __llvm_bitreverse(i); }
proc reverse_bits(i: u16) -> u16 { foreign __llvm_core proc __llvm_bitreverse(u16) -> u16 #link_name "llvm.bitreverse.i16"; return __llvm_bitreverse(i); }
proc reverse_bits(i: i16) -> i16 { foreign __llvm_core proc __llvm_bitreverse(i16) -> i16 #link_name "llvm.bitreverse.i16"; return __llvm_bitreverse(i); }
proc reverse_bits(i: u32) -> u32 { foreign __llvm_core proc __llvm_bitreverse(u32) -> u32 #link_name "llvm.bitreverse.i32"; return __llvm_bitreverse(i); }
proc reverse_bits(i: i32) -> i32 { foreign __llvm_core proc __llvm_bitreverse(i32) -> i32 #link_name "llvm.bitreverse.i32"; return __llvm_bitreverse(i); }
proc reverse_bits(i: u64) -> u64 { foreign __llvm_core proc __llvm_bitreverse(u64) -> u64 #link_name "llvm.bitreverse.i64"; return __llvm_bitreverse(i); }
proc reverse_bits(i: i64) -> i64 { foreign __llvm_core proc __llvm_bitreverse(i64) -> i64 #link_name "llvm.bitreverse.i64"; return __llvm_bitreverse(i); }
proc reverse_bits(i: u128) -> u128 { foreign __llvm_core proc __llvm_bitreverse(u128) -> u128 #link_name "llvm.bitreverse.i128";return __llvm_bitreverse(i); }
proc reverse_bits(i: i128) -> i128 { foreign __llvm_core proc __llvm_bitreverse(i128) -> i128 #link_name "llvm.bitreverse.i128";return __llvm_bitreverse(i); }
proc reverse_bits(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(reverse_bits(u32(i))); } else { return uint(reverse_bits(u64(i))); } }
proc reverse_bits(i: int) -> int { when size_of(int) == size_of(i32) { return int(reverse_bits(i32(i))); } else { return int(reverse_bits(i64(i))); } }
foreign __llvm_core {
proc byte_swap(u16) -> u16 #link_name "llvm.bswap.i16";
proc byte_swap(i16) -> i16 #link_name "llvm.bswap.i16";
proc byte_swap(u32) -> u32 #link_name "llvm.bswap.i32";
proc byte_swap(i32) -> i32 #link_name "llvm.bswap.i32";
proc byte_swap(u64) -> u64 #link_name "llvm.bswap.i64";
proc byte_swap(i64) -> i64 #link_name "llvm.bswap.i64";
proc byte_swap(u128) -> u128 #link_name "llvm.bswap.i128";
proc byte_swap(i128) -> i128 #link_name "llvm.bswap.i128";
}
proc byte_swap(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(byte_swap(u32(i))); } else { return uint(byte_swap(u64(i))); } }
proc byte_swap(i: int) -> int { when size_of(int) == size_of(i32) { return int(byte_swap(i32(i))); } else { return int(byte_swap(i64(i))); } }
proc from_be(i: u8) -> u8 { return i; }
proc from_be(i: i8) -> i8 { return i; }
proc from_be(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_be(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_le(i: u8) -> u8 { return i; }
proc from_le(i: i8) -> i8 { return i; }
proc from_le(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc from_le(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_be(i: u8) -> u8 { return i; }
proc to_be(i: i8) -> i8 { return i; }
proc to_be(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_be(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_le(i: u8) -> u8 { return i; }
proc to_le(i: i8) -> i8 { return i; }
proc to_le(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_le(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc overflowing_add(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core proc op(u8, u8) -> (u8, bool) #link_name "llvm.uadd.with.overflow.i8"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core proc op(i8, i8) -> (i8, bool) #link_name "llvm.sadd.with.overflow.i8"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core proc op(u16, u16) -> (u16, bool) #link_name "llvm.uadd.with.overflow.i16"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core proc op(i16, i16) -> (i16, bool) #link_name "llvm.sadd.with.overflow.i16"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core proc op(u32, u32) -> (u32, bool) #link_name "llvm.uadd.with.overflow.i32"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core proc op(i32, i32) -> (i32, bool) #link_name "llvm.sadd.with.overflow.i32"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core proc op(u64, u64) -> (u64, bool) #link_name "llvm.uadd.with.overflow.i64"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core proc op(i64, i64) -> (i64, bool) #link_name "llvm.sadd.with.overflow.i64"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core proc op(u128, u128) -> (u128, bool) #link_name "llvm.uadd.with.overflow.i128"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core proc op(i128, i128) -> (i128, bool) #link_name "llvm.sadd.with.overflow.i128"; return op(lhs, rhs); }
proc overflowing_add(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
var x, ok = overflowing_add(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
var x, ok = overflowing_add(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
proc overflowing_add(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
var x, ok = overflowing_add(i32(lhs), i32(rhs));
return int(x), ok;
} else {
var x, ok = overflowing_add(i64(lhs), i64(rhs));
return int(x), ok;
}
}
proc overflowing_sub(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core proc op(u8, u8) -> (u8, bool) #link_name "llvm.usub.with.overflow.i8"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core proc op(i8, i8) -> (i8, bool) #link_name "llvm.ssub.with.overflow.i8"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core proc op(u16, u16) -> (u16, bool) #link_name "llvm.usub.with.overflow.i16"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core proc op(i16, i16) -> (i16, bool) #link_name "llvm.ssub.with.overflow.i16"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core proc op(u32, u32) -> (u32, bool) #link_name "llvm.usub.with.overflow.i32"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core proc op(i32, i32) -> (i32, bool) #link_name "llvm.ssub.with.overflow.i32"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core proc op(u64, u64) -> (u64, bool) #link_name "llvm.usub.with.overflow.i64"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core proc op(i64, i64) -> (i64, bool) #link_name "llvm.ssub.with.overflow.i64"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core proc op(u128, u128) -> (u128, bool) #link_name "llvm.usub.with.overflow.i128"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core proc op(i128, i128) -> (i128, bool) #link_name "llvm.ssub.with.overflow.i128"; return op(lhs, rhs); }
proc overflowing_sub(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
var x, ok = overflowing_sub(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
var x, ok = overflowing_sub(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
proc overflowing_sub(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
var x, ok = overflowing_sub(i32(lhs), i32(rhs));
return int(x), ok;
} else {
var x, ok = overflowing_sub(i64(lhs), i64(rhs));
return int(x), ok;
}
}
proc overflowing_mul(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core proc op(u8, u8) -> (u8, bool) #link_name "llvm.umul.with.overflow.i8"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core proc op(i8, i8) -> (i8, bool) #link_name "llvm.smul.with.overflow.i8"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core proc op(u16, u16) -> (u16, bool) #link_name "llvm.umul.with.overflow.i16"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core proc op(i16, i16) -> (i16, bool) #link_name "llvm.smul.with.overflow.i16"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core proc op(u32, u32) -> (u32, bool) #link_name "llvm.umul.with.overflow.i32"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core proc op(i32, i32) -> (i32, bool) #link_name "llvm.smul.with.overflow.i32"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core proc op(u64, u64) -> (u64, bool) #link_name "llvm.umul.with.overflow.i64"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core proc op(i64, i64) -> (i64, bool) #link_name "llvm.smul.with.overflow.i64"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core proc op(u128, u128) -> (u128, bool) #link_name "llvm.umul.with.overflow.i128"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core proc op(i128, i128) -> (i128, bool) #link_name "llvm.smul.with.overflow.i128"; return op(lhs, rhs); }
proc overflowing_mul(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
var x, ok = overflowing_mul(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
var x, ok = overflowing_mul(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
proc overflowing_mul(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
var x, ok = overflowing_mul(i32(lhs), i32(rhs));
return int(x), ok;
} else {
var x, ok = overflowing_mul(i64(lhs), i64(rhs));
return int(x), ok;
}
}
proc is_power_of_two(i: u8) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: i8) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: u16) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: i16) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: u32) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: i32) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: u64) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: i64) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: u128) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: i128) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0; }
proc is_power_of_two(i: int) -> bool { return i > 0 && (i & (i-1)) == 0; }
+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
type Decimal struct {
digits: [384]u8, // big-endian digits
count: int,
decimal_point: int,
neg, trunc: bool,
}
proc decimal_to_string(buf: []u8, a: ^Decimal) -> string {
proc digit_zero(buf: []u8) -> int {
for _, i in buf -> buf[i] = '0';
return len(buf);
}
var n = 10 + a.count + abs(a.decimal_point);
// TODO(bill): make this work with a buffer that's not big enough
assert(len(buf) >= n);
buf = buf[0..<n];
if a.count == 0 {
buf[0] = '0';
return string(buf[0..<1]);
}
var w = 0;
if a.decimal_point <= 0 {
buf[w] = '0'; w++;
buf[w] = '.'; w++;
w += digit_zero(buf[w ..< w-a.decimal_point]);
w += copy(buf[w..], a.digits[0..<a.count]);
} else if a.decimal_point < a.count {
w += copy(buf[w..], a.digits[0..<a.decimal_point]);
buf[w] = '.'; w++;
w += copy(buf[w..], a.digits[a.decimal_point ..< a.count]);
} else {
w += copy(buf[w..], a.digits[0..<a.count]);
w += digit_zero(buf[w ..< w+a.decimal_point-a.count]);
}
return string(buf[0..<w]);
}
// trim trailing zeros
proc trim(a: ^Decimal) {
for a.count > 0 && a.digits[a.count-1] == '0' {
a.count--;
}
if a.count == 0 {
a.decimal_point = 0;
}
}
proc assign(a: ^Decimal, i: u64) {
var buf: [32]u8;
var n = 0;
for i > 0 {
var j = i/10;
i -= 10*j;
buf[n] = u8('0'+i);
n++;
i = j;
}
a.count = 0;
for n--; n >= 0; n-- {
a.digits[a.count] = buf[n];
a.count++;
}
a.decimal_point = a.count;
trim(a);
}
proc shift_right(a: ^Decimal, k: uint) {
var r = 0; // read index
var w = 0; // write index
var n: uint;
for ; n>>k == 0; r++ {
if r >= a.count {
if n == 0 {
// Just in case
a.count = 0;
return;
}
for n>>k == 0 {
n = n * 10;
r++;
}
break;
}
var c = uint(a.digits[r]);
n = n*10 + c - '0';
}
a.decimal_point -= r-1;
var mask: uint = (1<<k) - 1;
for ; r < a.count; r++ {
var c = uint(a.digits[r]);
var dig = n>>k;
n &= mask;
a.digits[w] = u8('0' + dig);
w++;
n = n*10 + c - '0';
}
for n > 0 {
var dig = n>>k;
n &= mask;
if w < len(a.digits) {
a.digits[w] = u8('0' + dig);
w++;
} else if dig > 0 {
a.trunc = true;
}
n *= 10;
}
a.count = w;
trim(a);
}
proc shift_left(a: ^Decimal, k: uint) {
var delta = int(k/4);
var r = a.count; // read index
var w = a.count+delta; // write index
var n: uint;
for r--; r >= 0; r-- {
n += (uint(a.digits[r]) - '0') << k;
var quo = n/10;
var rem = n - 10*quo;
w--;
if w < len(a.digits) {
a.digits[w] = u8('0' + rem);
} else if rem != 0 {
a.trunc = true;
}
n = quo;
}
for n > 0 {
var quo = n/10;
var rem = n - 10*quo;
w--;
if 0 <= w && w < len(a.digits) {
a.digits[w] = u8('0' + rem);
} else if rem != 0 {
a.trunc = true;
}
n = quo;
}
a.count += delta;
a.count = min(a.count, len(a.digits));
a.decimal_point += delta;
trim(a);
}
proc shift(a: ^Decimal, k: int) {
const (
uint_size = 8*size_of(uint);
max_shift = uint_size-4;
)
match {
case a.count == 0:
// no need to update
case k > 0:
for k > max_shift {
shift_left(a, max_shift);
k -= max_shift;
}
shift_left(a, uint(k));
case k < 0:
for k < -max_shift {
shift_right(a, max_shift);
k += max_shift;
}
shift_right(a, uint(-k));
}
}
proc can_round_up(a: ^Decimal, nd: int) -> bool {
if nd < 0 || nd >= a.count { return false ; }
if a.digits[nd] == '5' && nd+1 == a.count {
if a.trunc -> return true;
return nd > 0 && (a.digits[nd-1]-'0')%2 != 0;
}
return a.digits[nd] >= '5';
}
proc round(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
if can_round_up(a, nd) {
round_up(a, nd);
} else {
round_down(a, nd);
}
}
proc round_up(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
for var i = nd-1; i >= 0; i-- {
if var c = a.digits[i]; c < '9' {
a.digits[i]++;
a.count = i+1;
return;
}
}
// Number is just 9s
a.digits[0] = '1';
a.count = 1;
a.decimal_point++;
}
proc round_down(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
a.count = nd;
trim(a);
}
// Extract integer part, rounded appropriately. There are no guarantees about overflow.
proc rounded_integer(a: ^Decimal) -> u64 {
if a.decimal_point > 20 {
return 0xffff_ffff_ffff_ffff;
}
var i: int;
var n: u64 = 0;
var m = min(a.decimal_point, a.count);
for i = 0; i < m; i++ {
n = n*10 + u64(a.digits[i]-'0');
}
for ; i < a.decimal_point; i++ {
n *= 10;
}
if can_round_up(a, a.decimal_point) {
n++;
}
return n;
}
+1079 -488
View File
File diff suppressed because it is too large Load Diff
+123 -77
View File
@@ -1,77 +1,117 @@
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];
proc crc32(data: []u8) -> u32 {
var 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];
proc crc64(data: []u8) -> u64 {
var 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);
h: u32 = 0x811c9dc5;
for i : 0..<len {
h = (h * 0x01000193) ~ s[i] as u32;
proc fnv32(data: []u8) -> u32 {
var h: u32 = 0x811c9dc5;
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);
h: u64 = 0xcbf29ce484222325;
for i : 0..<len {
h = (h * 0x100000001b3) ~ s[i] as u64;
proc fnv64(data: []u8) -> u64 {
var h: u64 = 0xcbf29ce484222325;
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);
h: u32 = 0x811c9dc5;
for i : 0..<len {
h = (h ~ s[i] as u32) * 0x01000193;
proc fnv32a(data: []u8) -> u32 {
var h: u32 = 0x811c9dc5;
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;
proc fnv64a(data: []u8) -> u64 {
var h: u64 = 0xcbf29ce484222325;
for b in data {
h = (h ~ u64(b)) * 0x100000001b3;
}
return h;
}
proc murmur32(data: []u8) -> u32 {
const (
c1_32: u32 = 0xcc9e2d51;
c2_32: u32 = 0x1b873593;
)
murmur64 :: proc(data_: rawptr, len: int) -> u64 {
SEED :: 0x9747b28c;
var (
h1: u32 = 0;
nblocks = len(data)/4;
p = &data[0];
p1 = p + 4*nblocks;
)
for ; p < p1; p += 4 {
var 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;
}
var tail = data[nblocks*4 ..];
var 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;
}
proc murmur64(data: []u8) -> u64 {
const SEED = 0x9747b28c;
when size_of(int) == 8 {
m :: 0xc6a4a7935bd1e995;
r :: 47;
const (
m = 0xc6a4a7935bd1e995;
r = 47;
)
h: u64 = SEED ~ (len as u64 * m);
var h: u64 = SEED ~ (u64(len(data)) * m);
var 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 {
var k = data64[i];
k *= m;
k ~= k>>r;
@@ -81,15 +121,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;
}
@@ -99,18 +139,22 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
return h;
} else {
m :: 0x5bd1e995;
r :: 24;
const (
m = 0x5bd1e995;
r = 24;
)
h1: u32 = SEED as u32 ~ len as u32;
h2: u32 = SEED >> 32;
var (
h1 = u32(SEED) ~ u32(len(data));
h2 = u32(SEED) >> 32;
data32 = slice_ptr(^u32(&data[0]), len(data)/size_of(u32));
len = len(data);
i = 0;
)
data := slice_ptr(data_ as ^u32, len/size_of(u32));
i := 0;
while len >= 8 {
k1, k2: u32;
k1 = data[i]; i += 1;
for len >= 8 {
var k1, k2: u32;
k1 = data32[i]; i++;
k1 *= m;
k1 ~= k1>>r;
k1 *= m;
@@ -118,7 +162,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;
@@ -128,8 +172,8 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
}
if len >= 4 {
k1: u32;
k1 = data[i]; i += 1;
var k1: u32;
k1 = data32[i]; i++;
k1 *= m;
k1 ~= k1>>r;
k1 *= m;
@@ -138,13 +182,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 var 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 +205,12 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
h2 ~= h1>>19;
h2 *= m;
h := (h1 as u64)<<32 | h2 as u64;
return h;
return u64(h1)<<32 | u64(h2);
}
}
__CRC32_TABLE := [256]u32{
var _crc32_table = [256]u32{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -230,7 +276,7 @@ __CRC32_TABLE := [256]u32{
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
__CRC64_TABLE := [256]u64{
var _crc64_table = [256]u64{
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
+208 -178
View File
@@ -1,141 +1,166 @@
TAU :: 6.28318530717958647692528676655900576;
PI :: 3.14159265358979323846264338327950288;
ONE_OVER_TAU :: 0.636619772367581343075535053490057448;
ONE_OVER_PI :: 0.159154943091895335768883763372514362;
const (
TAU = 6.28318530717958647692528676655900576;
PI = 3.14159265358979323846264338327950288;
ONE_OVER_TAU = 0.636619772367581343075535053490057448;
ONE_OVER_PI = 0.159154943091895335768883763372514362;
E :: 2.71828182845904523536;
SQRT_TWO :: 1.41421356237309504880168872420969808;
SQRT_THREE :: 1.73205080756887729352744634150587236;
SQRT_FIVE :: 2.23606797749978969640917366873127623;
E = 2.71828182845904523536;
SQRT_TWO = 1.41421356237309504880168872420969808;
SQRT_THREE = 1.73205080756887729352744634150587236;
SQRT_FIVE = 2.23606797749978969640917366873127623;
LOG_TWO :: 0.693147180559945309417232121458176568;
LOG_TEN :: 2.30258509299404568401799145468436421;
LOG_TWO = 0.693147180559945309417232121458176568;
LOG_TEN = 2.30258509299404568401799145468436421;
EPSILON :: 1.19209290e-7;
EPSILON = 1.19209290e-7;
τ :: TAU;
π :: PI;
τ = TAU;
π = PI;
)
type (
Vec2 [vector 2]f32;
Vec3 [vector 3]f32;
Vec4 [vector 4]f32;
Vec2 :: [vector 2]f32;
Vec3 :: [vector 3]f32;
Vec4 :: [vector 4]f32;
// Column major
Mat2 [2][2]f32;
Mat3 [3][3]f32;
Mat4 [4][4]f32;
Mat2 :: [2]Vec2;
Mat3 :: [3]Vec3;
Mat4 :: [4]Vec4;
Complex complex64;
)
sqrt32 :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
sqrt64 :: proc(x: f64) -> f64 #foreign "llvm.sqrt.f64"
foreign __llvm_core {
proc sqrt(x: f32) -> f32 #link_name "llvm.sqrt.f32";
proc sqrt(x: f64) -> f64 #link_name "llvm.sqrt.f64";
sin32 :: proc(x: f32) -> f32 #foreign "llvm.sin.f32"
sin64 :: proc(x: f64) -> f64 #foreign "llvm.sin.f64"
proc sin (θ: f32) -> f32 #link_name "llvm.sin.f32";
proc sin (θ: f64) -> f64 #link_name "llvm.sin.f64";
cos32 :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
cos64 :: proc(x: f64) -> f64 #foreign "llvm.cos.f64"
proc cos (θ: f32) -> f32 #link_name "llvm.cos.f32";
proc cos (θ: f64) -> f64 #link_name "llvm.cos.f64";
tan32 :: proc(x: f32) -> f32 #inline { return sin32(x)/cos32(x); }
tan64 :: proc(x: f64) -> f64 #inline { return sin64(x)/cos64(x); }
proc pow (x, power: f32) -> f32 #link_name "llvm.pow.f32";
proc pow (x, power: f64) -> f64 #link_name "llvm.pow.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; }
sign32 :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
sign64 :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
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;
proc fmuladd(a, b, c: f32) -> f32 #link_name "llvm.fmuladd.f32";
proc fmuladd(a, b, c: f64) -> f64 #link_name "llvm.fmuladd.f64";
}
remainder32 :: proc(x, y: f32) -> f32 {
return x - round32(x/y) * y;
proc tan (θ: f32) -> f32 #inline { return sin(θ)/cos(θ); }
proc tan (θ: f64) -> f64 #inline { return sin(θ)/cos(θ); }
proc lerp (a, b, t: f32) -> (x: f32) { return a*(1-t) + b*t; }
proc lerp (a, b, t: f64) -> (x: f64) { return a*(1-t) + b*t; }
proc unlerp(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); }
proc unlerp(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); }
proc sign(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
proc sign(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
proc copy_sign(x, y: f32) -> f32 {
var ix = transmute(u32, x);
var iy = transmute(u32, y);
ix &= 0x7fff_ffff;
ix |= iy & 0x8000_0000;
return transmute(f32, ix);
}
fmod32 :: proc(x, y: f32) -> f32 {
proc copy_sign(x, y: f64) -> f64 {
var ix = transmute(u64, x);
var iy = transmute(u64, y);
ix &= 0x7fff_ffff_ffff_ff;
ix |= iy & 0x8000_0000_0000_0000;
return transmute(f64, ix);
}
proc round (x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
proc round (x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
proc floor (x: f32) -> f32 { return x >= 0 ? f32(i64(x)) : f32(i64(x-0.5)); } // TODO: Get accurate versions
proc floor (x: f64) -> f64 { return x >= 0 ? f64(i64(x)) : f64(i64(x-0.5)); } // TODO: Get accurate versions
proc ceil (x: f32) -> f32 { return x < 0 ? f32(i64(x)) : f32(i64(x+1)); } // TODO: Get accurate versions
proc ceil (x: f64) -> f64 { return x < 0 ? f64(i64(x)) : f64(i64(x+1)); } // TODO: Get accurate versions
proc remainder(x, y: f32) -> f32 { return x - round(x/y) * y; }
proc remainder(x, y: f64) -> f64 { return x - round(x/y) * y; }
proc mod(x, y: f32) -> f32 {
var result: f32;
y = abs(y);
result := 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);
}
proc mod(x, y: f64) -> f64 {
var result: f64;
y = abs(y);
result = remainder(abs(x), y);
if sign(result) < 0 {
result += y;
}
return copy_sign(result, x);
}
to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360; }
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
proc to_radians(degrees: f32) -> f32 { return degrees * TAU / 360; }
proc to_degrees(radians: f32) -> f32 { return radians * 360 / TAU; }
proc dot(a, b: Vec2) -> f32 { var c = a*b; return c.x + c.y; }
proc dot(a, b: Vec3) -> f32 { var c = a*b; return c.x + c.y + c.z; }
proc dot(a, b: Vec4) -> f32 { var c = a*b; return c.x + c.y + c.z + c.w; }
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 {
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
proc cross(x, y: Vec3) -> Vec3 {
var a = swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
var b = swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
return a - b;
}
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)); }
proc mag(v: Vec2) -> f32 { return sqrt(dot(v, v)); }
proc mag(v: Vec3) -> f32 { return sqrt(dot(v, v)); }
proc mag(v: Vec4) -> f32 { return sqrt(dot(v, v)); }
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)}; }
proc norm(v: Vec2) -> Vec2 { return v / mag(v); }
proc norm(v: Vec3) -> Vec3 { return v / mag(v); }
proc norm(v: Vec4) -> Vec4 { return v / mag(v); }
vec2_norm0 :: proc(v: Vec2) -> Vec2 {
m := vec2_mag(v);
proc norm0(v: Vec2) -> Vec2 {
var 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);
proc norm0(v: Vec3) -> Vec3 {
var 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);
proc norm0(v: Vec4) -> Vec4 {
var m = mag(v);
if m == 0 {
return Vec4{0};
return 0;
}
return v / Vec4{m};
return v / m;
}
mat4_identity :: proc() -> Mat4 {
proc mat4_identity() -> Mat4 {
return Mat4{
{1, 0, 0, 0},
{0, 1, 0, 0},
@@ -144,19 +169,19 @@ mat4_identity :: proc() -> Mat4 {
};
}
mat4_transpose :: proc(m: Mat4) -> Mat4 {
for j : 0..<4 {
for i : 0..<4 {
proc mat4_transpose(m: Mat4) -> Mat4 {
for j in 0..<4 {
for i in 0..<4 {
m[i][j], m[j][i] = m[j][i], m[i][j];
}
}
return m;
}
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
c: Mat4;
for j : 0..<4 {
for i : 0..<4 {
proc mul(a, b: Mat4) -> Mat4 {
var c: Mat4;
for j in 0..<4 {
for i in 0..<4 {
c[j][i] = a[0][i]*b[j][0] +
a[1][i]*b[j][1] +
a[2][i]*b[j][2] +
@@ -166,7 +191,7 @@ mat4_mul :: proc(a, b: Mat4) -> Mat4 {
return c;
}
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
proc mul(m: Mat4, v: Vec4) -> Vec4 {
return Vec4{
m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
@@ -175,28 +200,30 @@ mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
};
}
mat4_inverse :: proc(m: Mat4) -> Mat4 {
o: Mat4;
proc inverse(m: Mat4) -> Mat4 {
var o: Mat4;
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3];
sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2];
sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3];
sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2];
sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1];
sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3];
sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2];
sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3];
sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2];
sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1];
sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3];
sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3];
sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2];
sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3];
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2];
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1];
var (
sf00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
sf01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
sf02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
sf03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
sf04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
sf05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
sf06 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
sf07 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
sf08 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
sf09 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
sf10 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
sf11 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
sf12 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
sf13 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
sf14 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
sf15 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
sf16 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
sf17 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
sf18 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
)
o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02);
o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04);
@@ -218,7 +245,7 @@ mat4_inverse :: proc(m: Mat4) -> Mat4 {
o[3][2] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18);
o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18);
ood := 1.0 / (m[0][0] * o[0][0] +
var ood = 1.0 / (m[0][0] * o[0][0] +
m[0][1] * o[0][1] +
m[0][2] * o[0][2] +
m[0][3] * o[0][3]);
@@ -244,8 +271,8 @@ mat4_inverse :: proc(m: Mat4) -> Mat4 {
}
mat4_translate :: proc(v: Vec3) -> Mat4 {
m := mat4_identity();
proc mat4_translate(v: Vec3) -> Mat4 {
var m = mat4_identity();
m[3][0] = v.x;
m[3][1] = v.y;
m[3][2] = v.z;
@@ -253,14 +280,16 @@ mat4_translate :: proc(v: Vec3) -> Mat4 {
return m;
}
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
c := cos32(angle_radians);
s := sin32(angle_radians);
proc mat4_rotate(v: Vec3, angle_radians: f32) -> Mat4 {
var (
c = cos(angle_radians);
s = sin(angle_radians);
a := vec3_norm(v);
t := a * Vec3{1-c};
a = norm(v);
t = a * (1-c);
rot := mat4_identity();
rot = mat4_identity();
)
rot[0][0] = c + t.x*a.x;
rot[0][1] = 0 + t.x*a.y + s*a.z;
@@ -280,14 +309,14 @@ mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
return rot;
}
mat4_scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
proc scale(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 {
proc scale(m: Mat4, s: f32) -> Mat4 {
m[0][0] *= s;
m[1][1] *= s;
m[2][2] *= s;
@@ -295,23 +324,26 @@ 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);
proc look_at(eye, centre, up: Vec3) -> Mat4 {
var (
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};
return m;
return Mat4{
{+s.x, +u.x, -f.x, 0},
{+s.y, +u.y, -f.y, 0},
{+s.z, +u.z, -f.z, 0},
{-dot(s, eye), -dot(u, eye), dot(f, eye), 1},
};
}
mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
m: Mat4;
tan_half_fovy := tan32(0.5 * fovy);
proc perspective(fovy, aspect, near, far: f32) -> Mat4 {
var (
m: Mat4;
tan_half_fovy = tan(0.5 * fovy);
)
m[0][0] = 1.0 / (aspect*tan_half_fovy);
m[1][1] = 1.0 / (tan_half_fovy);
m[2][2] = -(far + near) / (far - near);
@@ -321,8 +353,8 @@ mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
}
mat4_ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
m := mat4_identity();
proc ortho3d(left, right, bottom, top, near, far: f32) -> Mat4 {
var m = mat4_identity();
m[0][0] = +2.0 / (right - left);
m[1][1] = +2.0 / (top - bottom);
m[2][2] = -2.0 / (far - near);
@@ -335,32 +367,30 @@ mat4_ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
const (
F32_DIG = 6;
F32_EPSILON = 1.192092896e-07;
F32_GUARD = 0;
F32_MANT_DIG = 24;
F32_MAX = 3.402823466e+38;
F32_MAX_10_EXP = 38;
F32_MAX_EXP = 128;
F32_MIN = 1.175494351e-38;
F32_MIN_10_EXP = -37;
F32_MIN_EXP = -125;
F32_NORMALIZE = 0;
F32_RADIX = 2;
F32_ROUNDS = 1;
F32_DIG :: 6;
F32_EPSILON :: 1.192092896e-07;
F32_GUARD :: 0;
F32_MANT_DIG :: 24;
F32_MAX :: 3.402823466e+38;
F32_MAX_10_EXP :: 38;
F32_MAX_EXP :: 128;
F32_MIN :: 1.175494351e-38;
F32_MIN_10_EXP :: -37;
F32_MIN_EXP :: -125;
F32_NORMALIZE :: 0;
F32_RADIX :: 2;
F32_ROUNDS :: 1;
F64_DIG :: 15; // # of decimal digits of precision
F64_EPSILON :: 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0
F64_MANT_DIG :: 53; // # of bits in mantissa
F64_MAX :: 1.7976931348623158e+308; // max value
F64_MAX_10_EXP :: 308; // max decimal exponent
F64_MAX_EXP :: 1024; // max binary exponent
F64_MIN :: 2.2250738585072014e-308; // min positive value
F64_MIN_10_EXP :: -307; // min decimal exponent
F64_MIN_EXP :: -1021; // min binary exponent
F64_RADIX :: 2; // exponent radix
F64_ROUNDS :: 1; // addition rounding: near
F64_DIG = 15; // # of decimal digits of precision
F64_EPSILON = 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0
F64_MANT_DIG = 53; // # of bits in mantissa
F64_MAX = 1.7976931348623158e+308; // max value
F64_MAX_10_EXP = 308; // max decimal exponent
F64_MAX_EXP = 1024; // max binary exponent
F64_MIN = 2.2250738585072014e-308; // min positive value
F64_MIN_10_EXP = -307; // min decimal exponent
F64_MIN_EXP = -1021; // min binary exponent
F64_RADIX = 2; // exponent radix
F64_ROUNDS = 1; // addition rounding: near
)
+126 -164
View File
@@ -1,112 +1,78 @@
#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;
import (
"fmt.odin";
"os.odin";
)
foreign __llvm_core {
proc swap(b: u16) -> u16 #link_name "llvm.bswap.i16";
proc swap(b: u32) -> u32 #link_name "llvm.bswap.i32";
proc swap(b: u64) -> u64 #link_name "llvm.bswap.i64";
}
zero :: proc(data: rawptr, len: int) -> rawptr #link_name "__mem_zero" {
return set(data, 0, len);
proc set(data: rawptr, value: i32, len: int) -> rawptr {
return __mem_set(data, value, 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;
proc zero(data: rawptr, len: int) -> rawptr {
return __mem_zero(data, 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;
proc copy(dst, src: rawptr, len: int) -> rawptr {
return __mem_copy(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;
proc copy_non_overlapping(dst, src: rawptr, len: int) -> rawptr {
return __mem_copy_non_overlapping(dst, src, len);
}
proc compare(a, b: []u8) -> int {
return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
}
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; }
proc kilobytes(x: int) -> int #inline { return (x) * 1024; }
proc megabytes(x: int) -> int #inline { return kilobytes(x) * 1024; }
proc gigabytes(x: int) -> int #inline { return megabytes(x) * 1024; }
proc terabytes(x: int) -> int #inline { return gigabytes(x) * 1024; }
is_power_of_two :: proc(x: int) -> bool {
proc is_power_of_two(x: int) -> bool {
if x <= 0 {
return false;
}
return (x & (x-1)) == 0;
}
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
proc align_forward(ptr: rawptr, align: int) -> rawptr {
assert(is_power_of_two(align));
a := align as uint;
p := ptr as uint;
modulo := p & (a-1);
var a = uint(align);
var p = uint(ptr);
var modulo = p & (a-1);
if modulo != 0 {
p += a - modulo;
}
return p as rawptr;
return rawptr(p);
}
Allocation_Header :: struct {
size: int;
type AllocationHeader struct {
size: int,
}
allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) {
proc allocation_header_fill(header: ^AllocationHeader, data: rawptr, size: int) {
header.size = size;
ptr := (header+1) as ^int;
var ptr = ^int(header+1);
while i := 0; ptr as rawptr < data {
for var 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 {
proc allocation_header(data: rawptr) -> ^AllocationHeader {
if data == nil {
return nil;
}
var p = ^int(data);
for (p-1)^ == -1 {
p = (p-1);
}
return (p as ^Allocation_Header)-1;
return ^AllocationHeader(p-1);
}
@@ -114,99 +80,100 @@ allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
// Custom allocators
Arena :: struct {
backing: Allocator;
offset: int;
memory: []byte;
temp_count: int;
}
type (
Arena struct {
backing: Allocator,
offset: int,
memory: []u8,
temp_count: int,
}
Arena_Temp_Memory :: struct {
arena: ^Arena;
original_count: int;
}
ArenaTempMemory struct {
arena: ^Arena,
original_count: int,
}
)
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
proc init_arena_from_memory(using a: ^Arena, data: []u8) {
backing = Allocator{};
memory = data[:0];
memory = data[0..<0];
temp_count = 0;
}
init_arena_from_context :: proc(using a: ^Arena, size: int) {
proc init_arena_from_context(using a: ^Arena, size: int) {
backing = context.allocator;
memory = new_slice(byte, size);
memory = make([]u8, size);
temp_count = 0;
}
free_arena :: proc(using a: ^Arena) {
proc free_arena(using a: ^Arena) {
if backing.procedure != nil {
push_allocator backing {
free(memory.data);
memory = memory[0:0];
free(memory);
memory = nil;
offset = 0;
}
}
}
arena_allocator :: proc(arena: ^Arena) -> Allocator {
proc arena_allocator(arena: ^Arena) -> Allocator {
return Allocator{
procedure = arena_allocator_proc,
data = arena,
};
}
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
proc arena_allocator_proc(allocator_data: rawptr, mode: AllocatorMode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
using Allocator_Mode;
arena := allocator_data as ^Arena;
using AllocatorMode;
var arena = ^Arena(allocator_data);
match mode {
case ALLOC:
total_size := size + alignment;
case Alloc:
var 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 var end = &arena.memory[arena.offset];
ptr := align_forward(end, alignment);
var ptr = align_forward(end, alignment);
arena.offset += total_size;
return zero(ptr, size);
case FREE:
case Free:
// NOTE(bill): Free all at once
// Use Arena_Temp_Memory if you want to free a block
// Use ArenaTempMemory if you want to free a block
case FREE_ALL:
case FreeAll:
arena.offset = 0;
case RESIZE:
case Resize:
return default_resize_align(old_memory, old_size, size, alignment);
}
return nil;
}
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
tmp: Arena_Temp_Memory;
proc begin_arena_temp_memory(a: ^Arena) -> ArenaTempMemory {
var tmp: ArenaTempMemory;
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);
proc end_arena_temp_memory(using tmp: ArenaTempMemory) {
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--;
}
@@ -215,8 +182,8 @@ end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
align_of_type_info :: proc(type_info: ^Type_Info) -> int {
prev_pow2 :: proc(n: i64) -> i64 {
proc align_of_type_info(type_info: ^TypeInfo) -> int {
proc prev_pow2(n: i64) -> i64 {
if n <= 0 {
return 0;
}
@@ -229,11 +196,10 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
return n - (n >> 1);
}
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 {
const WORD_SIZE = size_of(int);
const MAX_ALIGN = size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
using TypeInfo;
match info in type_info {
case Named:
return align_of_type_info(info.base);
case Integer:
@@ -244,101 +210,97 @@ 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 DynamicArray:
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;
total := size * count;
var size = size_of_type_info(info.elem);
var count = int(max(prev_pow2(i64(info.count)), 1));
var total = size * count;
return clamp(total, 1, MAX_ALIGN);
case Tuple:
return info.align;
case Struct:
return info.align;
case Union:
return info.align;
case Raw_Union:
case RawUnion:
return info.align;
case Enum:
return align_of_type_info(info.base);
case Map:
return align_of_type_info(info.generated_struct);
}
return 0;
}
align_formula :: proc(size, align: int) -> int {
result := size + align-1;
proc align_formula(size, align: int) -> int {
var result = size + align-1;
return result - result%align;
}
size_of_type_info :: proc(type_info: ^Type_Info) -> int {
WORD_SIZE :: size_of(int);
using Type_Info;
match type info : type_info {
proc size_of_type_info(type_info: ^TypeInfo) -> int {
const WORD_SIZE = size_of(int);
using TypeInfo;
match info in type_info {
case Named:
return size_of_type_info(info.base);
case Integer:
return info.size;
case Float:
return info.size;
case 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:
count := info.count;
var count = info.count;
if count == 0 {
return 0;
}
size := size_of_type_info(info.elem);
align := align_of_type_info(info.elem);
alignment := align_formula(size, align);
var size = size_of_type_info(info.elem);
var align = align_of_type_info(info.elem);
var alignment = align_formula(size, align);
return alignment*(count-1) + size;
case DynamicArray:
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
case Slice:
return 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;
var 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;
var size = size_of_type_info(info.elem);
var align = align_of_type_info(info.elem);
var alignment = align_formula(size, align);
return alignment*(count-1) + size;
case Struct:
return info.size;
case Union:
return info.size;
case Raw_Union:
case RawUnion:
return info.size;
case Enum:
return size_of_type_info(info.base);
case Map:
return size_of_type_info(info.generated_struct);
}
return 0;
+144 -122
View File
@@ -1,154 +1,176 @@
#foreign_system_library "opengl32" when ODIN_OS == "windows";
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
#include "opengl_constants.odin";
foreign_system_library (
lib "opengl32.lib" when ODIN_OS == "windows";
lib "gl" when ODIN_OS == "linux";
)
import (
win32 "sys/windows.odin" when ODIN_OS == "windows";
"sys/wgl.odin" when ODIN_OS == "windows";
)
import_load "opengl_constants.odin";
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"
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"
foreign lib {
proc Clear (mask: u32) #link_name "glClear";
proc ClearColor (r, g, b, a: f32) #link_name "glClearColor";
proc Begin (mode: i32) #link_name "glBegin";
proc End () #link_name "glEnd";
proc Finish () #link_name "glFinish";
proc BlendFunc (sfactor, dfactor: i32) #link_name "glBlendFunc";
proc Enable (cap: i32) #link_name "glEnable";
proc Disable (cap: i32) #link_name "glDisable";
proc GenTextures (count: i32, result: ^u32) #link_name "glGenTextures";
proc DeleteTextures(count: i32, result: ^u32) #link_name "glDeleteTextures";
proc TexParameteri (target, pname, param: i32) #link_name "glTexParameteri";
proc TexParameterf (target: i32, pname: i32, param: f32) #link_name "glTexParameterf";
proc BindTexture (target: i32, texture: u32) #link_name "glBindTexture";
proc LoadIdentity () #link_name "glLoadIdentity";
proc Viewport (x, y, width, height: i32) #link_name "glViewport";
proc Ortho (left, right, bottom, top, near, far: f64) #link_name "glOrtho";
proc Color3f (r, g, b: f32) #link_name "glColor3f";
proc Vertex3f (x, y, z: f32) #link_name "glVertex3f";
proc GetError () -> i32 #link_name "glGetError";
proc GetString (name: i32) -> ^u8 #link_name "glGetString";
proc GetIntegerv (name: i32, v: ^i32) #link_name "glGetIntegerv";
proc TexCoord2f (x, y: f32) #link_name "glTexCoord2f";
proc TexImage2D (target, level, internal_format,
width, height, border,
format, type_: i32, pixels: rawptr) #link_name "glTexImage2D";
}
proc _string_data(s: string) -> ^u8 #inline { return &s[0]; }
_libgl := win32.LoadLibraryA(("opengl32.dll\x00" as string).data);
var _libgl = win32.load_library_a(_string_data("opengl32.dll\x00"));
GetProcAddress :: proc(name: string) -> proc() #cc_c {
assert(name[name.count-1] == 0);
res := win32.wglGetProcAddress(name.data);
if res == nil {
res = win32.GetProcAddress(_libgl, name.data);
proc get_proc_address(name: string) -> rawptr {
if name[len(name)-1] == 0 {
name = name[0..<len(name)-1];
}
return res;
// NOTE(bill): null terminated
assert((&name[0] + len(name))^ == 0);
var res = wgl.get_proc_address(&name[0]);
if res == nil {
res = win32.get_proc_address(_libgl, &name[0]);
}
return rawptr(res);
}
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;
var (
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
DeleteBuffers: proc(count: i32, buffers: ^u32) #cc_c;
BindBuffer: proc(target: i32, buffer: u32) #cc_c;
BindVertexArray: proc(buffer: u32) #cc_c;
DeleteVertexArrays: proc(count: i32, arrays: ^u32) #cc_c;
BindSampler: proc(position: i32, sampler: u32) #cc_c;
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c;
BufferSubData: proc(target: i32, offset, size: int, data: rawptr) #cc_c;
DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
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;
EnableVertexAttribArray: proc(index: u32) #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: ^^u8, length: ^i32) #cc_c;
CompileShader: proc(shader: u32) #cc_c;
CreateProgram: proc() -> u32 #cc_c;
AttachShader: proc(program, shader: u32) #cc_c;
DetachShader: proc(program, shader: u32) #cc_c;
DeleteShader: proc(shader: u32) #cc_c;
LinkProgram: proc(program: u32) #cc_c;
UseProgram: proc(program: u32) #cc_c;
DeleteProgram: proc(program: u32) #cc_c;
GetShaderiv: proc(shader: u32, pname: i32, params: ^i32) #cc_c;
GetProgramiv: proc(program: u32, pname: i32, params: ^i32) #cc_c;
GetShaderInfoLog: proc(shader: u32, max_length: u32, length: ^u32, info_long: ^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: ^u8) #cc_c;
GetProgramInfoLog: proc(program: u32, max_length: u32, length: ^u32, info_long: ^u8) #cc_c;
ActiveTexture: proc(texture: i32) #cc_c;
GenerateMipmap: proc(target: i32) #cc_c;
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: ^u8) -> i32 #cc_c;
)
init :: proc() {
set_proc_address :: proc(p: rawptr, name: string) #inline { (p as ^(proc() #cc_c))^ = GetProcAddress(name); }
proc init() {
proc set_proc_address(p: rawptr, name: string) #inline {
var x = ^rawptr(p);
x^ = get_proc_address(name);
}
set_proc_address(^GenBuffers, "glGenBuffers\x00");
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
set_proc_address(^GenSamplers, "glGenSamplers\x00");
set_proc_address(^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(&DeleteVertexArrays, "glDeleteVertexArrays\x00");
set_proc_address(&BufferData, "glBufferData\x00");
set_proc_address(&BufferSubData, "glBufferSubData\x00");
set_proc_address(^DrawArrays, "glDrawArrays\x00");
set_proc_address(^DrawElements, "glDrawElements\x00");
set_proc_address(&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");
}
+1367 -1367
View File
File diff suppressed because it is too large Load Diff
+48 -1
View File
@@ -1,2 +1,49 @@
#include "os_windows.odin" when ODIN_OS == "windows"
import_load (
"os_windows.odin" when ODIN_OS == "windows";
"os_x.odin" when ODIN_OS == "osx";
"os_linux.odin" when ODIN_OS == "linux";
)
proc write_string(fd: Handle, str: string) -> (int, Errno) {
return write(fd, []u8(str));
}
proc read_entire_file(name: string) -> ([]u8, bool) {
var fd, err = open(name, O_RDONLY, 0);
if err != 0 {
return nil, false;
}
defer close(fd);
var length: i64;
if length, err = file_size(fd); err != 0 {
return nil, false;
}
if length == 0 {
return nil, true;
}
var data = make([]u8, length);
if data == nil {
return nil, false;
}
var bytes_read, read_err = read(fd, data);
if read_err != 0 {
free(data);
return nil, false;
}
return data[0..<bytes_read], true;
}
proc write_entire_file(name: string, data: []u8) -> bool {
var fd, err = open(name, O_WRONLY, 0);
if err != 0 {
return false;
}
defer close(fd);
var bytes_written, write_err = write(fd, data);
return write_err != 0;
}
+281
View File
@@ -0,0 +1,281 @@
foreign_system_library (
dl "dl";
libc "c";
)
import "strings.odin";
type (
Handle i32;
FileTime u64;
Errno i32;
)
const (
O_RDONLY = 0x00000;
O_WRONLY = 0x00001;
O_RDWR = 0x00002;
O_CREAT = 0x00040;
O_EXCL = 0x00080;
O_NOCTTY = 0x00100;
O_TRUNC = 0x00200;
O_NONBLOCK = 0x00800;
O_APPEND = 0x00400;
O_SYNC = 0x01000;
O_ASYNC = 0x02000;
O_CLOEXEC = 0x80000;
)
const (
SEEK_SET = 0;
SEEK_CUR = 1;
SEEK_END = 2;
SEEK_DATA = 3;
SEEK_HOLE = 4;
SEEK_MAX = SEEK_HOLE;
)
const (
// NOTE(zangent): These are OS specific!
// Do not mix these up!
RTLD_LAZY = 0x001;
RTLD_NOW = 0x002;
RTLD_BINDING_MASK = 0x3;
RTLD_GLOBAL = 0x100;
)
// "Argv" arguments converted to Odin strings
var args = _alloc_command_line_arguments();
type _FileTime struct #ordered {
seconds: i64,
nanoseconds: i32,
reserved: i32,
}
// Translated from
// https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/+/jb-dev/sysroot/usr/include/bits/stat.h
// Validity is not guaranteed.
type Stat struct #ordered {
device_id: u64, // ID of device containing file
serial: u64, // File serial number
nlink: u32, // Number of hard links
mode: u32, // Mode of the file
uid: u32, // User ID of the file's owner
gid: u32, // Group ID of the file's group
_padding: i32, // 32 bits of padding
rdev: u64, // Device ID, if device
size: i64, // Size of the file, in bytes
block_size: i64, // Optimal bllocksize for I/O
blocks: i64, // Number of 512-byte blocks allocated
last_access: _FileTime, // Time of last access
modified: _FileTime, // Time of last modification
status_change: _FileTime, // Time of last status change
_reserve1,
_reserve2,
_reserve3: i64,
serial_numbe: u64, // File serial number...? Maybe.
_reserve4: i64,
};
// File type
const (
S_IFMT = 0170000; // Type of file mask
S_IFIFO = 0010000; // Named pipe (fifo)
S_IFCHR = 0020000; // Character special
S_IFDIR = 0040000; // Directory
S_IFBLK = 0060000; // Block special
S_IFREG = 0100000; // Regular
S_IFLNK = 0120000; // Symbolic link
S_IFSOCK = 0140000; // Socket
// File mode
// Read, write, execute/search by owner
S_IRWXU = 0000700; // RWX mask for owner
S_IRUSR = 0000400; // R for owner
S_IWUSR = 0000200; // W for owner
S_IXUSR = 0000100; // X for owner
// Read, write, execute/search by group
S_IRWXG = 0000070; // RWX mask for group
S_IRGRP = 0000040; // R for group
S_IWGRP = 0000020; // W for group
S_IXGRP = 0000010; // X for group
// Read, write, execute/search by others
S_IRWXO = 0000007; // RWX mask for other
S_IROTH = 0000004; // R for other
S_IWOTH = 0000002; // W for other
S_IXOTH = 0000001; // X for other
S_ISUID = 0004000; // Set user id on execution
S_ISGID = 0002000; // Set group id on execution
S_ISVTX = 0001000; // Directory restrcted delete
)
proc S_ISLNK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFLNK; }
proc S_ISREG (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFREG; }
proc S_ISDIR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFDIR; }
proc S_ISCHR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFCHR; }
proc S_ISBLK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFBLK; }
proc S_ISFIFO(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFIFO; }
proc S_ISSOCK(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFSOCK;}
const (
R_OK = 4; // Test for read permission
W_OK = 2; // Test for write permission
X_OK = 1; // Test for execute permission
F_OK = 0; // Test for file existance
)
foreign libc {
proc _unix_open (path: ^u8, mode: int) -> Handle #link_name "open";
proc _unix_close (fd: Handle) -> i32 #link_name "close";
proc _unix_read (fd: Handle, buf: rawptr, size: int) -> int #link_name "read";
proc _unix_write (fd: Handle, buf: rawptr, size: int) -> int #link_name "write";
proc _unix_seek (fd: Handle, offset: i64, whence: i32) -> i64 #link_name "lseek64";
proc _unix_gettid() -> u64 #link_name "gettid";
proc _unix_stat (path: ^u8, stat: ^Stat) -> i32 #link_name "stat";
proc _unix_access(path: ^u8, mask: int) -> i32 #link_name "access";
proc _unix_malloc (size: int) -> rawptr #link_name "malloc";
proc _unix_free (ptr: rawptr) #link_name "free";
proc _unix_realloc(ptr: rawptr, size: int) -> rawptr #link_name "realloc";
proc _unix_getenv (^u8) -> ^u8 #link_name "getenv";
proc _unix_exit(status: int) #link_name "exit";
}
foreign dl {
proc _unix_dlopen (filename: ^u8, flags: int) -> rawptr #link_name "dlopen";
proc _unix_dlsym (handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym";
proc _unix_dlclose(handle: rawptr) -> int #link_name "dlclose";
proc _unix_dlerror() -> ^u8 #link_name "dlerror";
}
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
proc open_simple(path: string, mode: int) -> (Handle, Errno) {
var cstr = strings.new_c_string(path);
var handle = _unix_open(cstr, mode);
free(cstr);
if(handle == -1) {
return 0, 1;
}
return handle, 0;
}
// NOTE(zangent): This is here for compatability reasons. Should this be here?
proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
return open_simple(path, mode);
}
proc close(fd: Handle) {
_unix_close(fd);
}
proc read(fd: Handle, data: []u8) -> (int, Errno) {
var sz = _unix_read(fd, &data[0], len(data));
return sz, 0;
}
proc write(fd: Handle, data: []u8) -> (int, Errno) {
var sz = _unix_write(fd, &data[0], len(data));
return sz, 0;
}
proc seek(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
var res = _unix_seek(fd, offset, i32(whence));
return res, 0;
}
proc file_size(fd: Handle) -> (i64, Errno) {
var prev, _ = seek(fd, 0, SEEK_CUR);
var size, err = seek(fd, 0, SEEK_END);
seek(fd, prev, SEEK_SET);
return size, err;
}
// NOTE(bill): Uses startup to initialize it
var (
stdin: Handle = 0;
stdout: Handle = 1;
stderr: Handle = 2;
)
/* TODO(zangent): Implement these!
proc last_write_time(fd: Handle) -> FileTime {}
proc last_write_time_by_name(name: string) -> FileTime {}
*/
proc stat(path: string) -> (Stat, int) #inline {
var s: Stat;
var cstr = strings.new_c_string(path);
defer free(cstr);
var ret_int = _unix_stat(cstr, &s);
return s, int(ret_int);
}
proc access(path: string, mask: int) -> bool #inline {
var cstr = strings.new_c_string(path);
defer free(cstr);
return _unix_access(cstr, mask) == 0;
}
proc heap_alloc(size: int) -> rawptr {
assert(size > 0);
return _unix_malloc(size);
}
proc heap_resize(ptr: rawptr, new_size: int) -> rawptr {
return _unix_realloc(ptr, new_size);
}
proc heap_free(ptr: rawptr) {
_unix_free(ptr);
}
proc getenv(name: string) -> (string, bool) {
var path_str = strings.new_c_string(name);
var cstr: ^u8 = _unix_getenv(path_str);
free(path_str);
if(cstr == nil) {
return "", false;
}
return strings.to_odin_string(cstr), true;
}
proc exit(code: int) {
_unix_exit(code);
}
proc current_thread_id() -> int {
// return int(_unix_gettid());
return 0;
}
proc dlopen(filename: string, flags: int) -> rawptr #inline {
var cstr = strings.new_c_string(filename);
var handle = _unix_dlopen(cstr, flags);
free(cstr);
return handle;
}
proc dlsym(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
assert(handle != nil);
var cstr = strings.new_c_string(symbol);
var proc_handle = _unix_dlsym(handle, cstr);
free(cstr);
return proc_handle;
}
proc dlclose(handle: rawptr) -> bool #inline {
assert(handle != nil);
return _unix_dlclose(handle) == 0;
}
proc dlerror() -> string {
return strings.to_odin_string(_unix_dlerror());
}
proc _alloc_command_line_arguments() -> []string {
// TODO(bill):
return nil;
}
+263 -190
View File
@@ -1,166 +1,217 @@
#import win32 "sys/windows.odin";
#import "fmt.odin";
import win32 "sys/windows.odin";
type (
Handle int;
FileTime u64;
)
const INVALID_HANDLE: Handle = -1;
Handle :: uint;
File_Time :: u64;
Error :: int;
const (
O_RDONLY = 0x00000;
O_WRONLY = 0x00001;
O_RDWR = 0x00002;
O_CREAT = 0x00040;
O_EXCL = 0x00080;
O_NOCTTY = 0x00100;
O_TRUNC = 0x00200;
O_NONBLOCK = 0x00800;
O_APPEND = 0x00400;
O_SYNC = 0x01000;
O_ASYNC = 0x02000;
O_CLOEXEC = 0x80000;
)
INVALID_HANDLE: Handle : ~(0 as Handle);
type Errno int;
const (
ERROR_NONE: Errno = 0;
ERROR_FILE_NOT_FOUND = 2;
ERROR_PATH_NOT_FOUND = 3;
ERROR_ACCESS_DENIED = 5;
ERROR_NO_MORE_FILES = 18;
ERROR_HANDLE_EOF = 38;
ERROR_NETNAME_DELETED = 64;
ERROR_FILE_EXISTS = 80;
ERROR_BROKEN_PIPE = 109;
ERROR_BUFFER_OVERFLOW = 111;
ERROR_INSUFFICIENT_BUFFER = 122;
ERROR_MOD_NOT_FOUND = 126;
ERROR_PROC_NOT_FOUND = 127;
ERROR_DIR_NOT_EMPTY = 145;
ERROR_ALREADY_EXISTS = 183;
ERROR_ENVVAR_NOT_FOUND = 203;
ERROR_MORE_DATA = 234;
ERROR_OPERATION_ABORTED = 995;
ERROR_IO_PENDING = 997;
ERROR_NOT_FOUND = 1168;
ERROR_PRIVILEGE_NOT_HELD = 1314;
WSAEACCES = 10013;
WSAECONNRESET = 10054;
// Windows reserves errors >= 1<<29 for application use
ERROR_FILE_IS_PIPE = 1<<29 + 0;
)
// "Argv" arguments converted to Odin strings
var args = _alloc_command_line_arguments();
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;
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;
// Windows reserves errors >= 1<<29 for application use
ERROR_FILE_IS_PIPE: Error : 1<<29 + 0;
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Error) {
using win32;
if path.count == 0 {
proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
if len(path) == 0 {
return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
}
access: u32;
var 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};
var share_mode = u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE);
var sa: ^win32.Security_Attributes = nil;
var sa_inherit = win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = 1};
if mode&O_CLOEXEC == 0 {
sa = ^sa_inherit;
sa = &sa_inherit;
}
create_mode: u32;
var 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;
default:
create_mode = OPEN_EXISTING;
create_mode = win32.TRUNCATE_EXISTING;
case:
create_mode = win32.OPEN_EXISTING;
}
buf: [300]byte;
copy(buf[:], path as []byte);
var buf: [300]u8;
copy(buf[..], []u8(path));
handle := CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil) as Handle;
if handle == INVALID_HANDLE {
var handle = Handle(win32.create_file_a(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
if handle != INVALID_HANDLE {
return handle, ERROR_NONE;
}
err := GetLastError();
return INVALID_HANDLE, err as Error;
var err = win32.get_last_error();
return INVALID_HANDLE, Errno(err);
}
close :: proc(fd: Handle) {
win32.CloseHandle(fd as win32.HANDLE);
proc close(fd: Handle) {
win32.close_handle(win32.Handle(fd));
}
write :: proc(fd: Handle, data: []byte) -> (int, Error) {
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;
proc write(fd: Handle, data: []u8) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
}
return bytes_written as int, ERROR_NONE;
}
var single_write_length: i32;
var total_write: i64;
var length = i64(len(data));
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 {
err := win32.GetLastError();
return 0, err as Error;
for total_write < length {
var remaining = length - total_write;
var to_read: i32;
const MAX = 1<<31-1;
if remaining <= MAX {
to_read = i32(remaining);
} else {
to_read = MAX;
}
var e = win32.write_file(win32.Handle(fd), &data[total_write], to_read, &single_write_length, nil);
if single_write_length <= 0 || e == win32.FALSE {
var err = win32.get_last_error();
return int(total_write), Errno(e);
}
total_write += i64(single_write_length);
}
return bytes_read as int, ERROR_NONE;
return int(total_write), ERROR_NONE;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
using win32;
w: u32;
proc read(fd: Handle, data: []u8) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
}
var single_read_length: i32;
var total_read: i64;
var length = i64(len(data));
for total_read < length {
var remaining = length - total_read;
var to_read: u32;
const MAX = 1<<32-1;
if remaining <= MAX {
to_read = u32(remaining);
} else {
to_read = MAX;
}
var e = win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
if single_read_length <= 0 || e == win32.FALSE {
var err = win32.get_last_error();
return int(total_read), Errno(e);
}
total_read += i64(single_read_length);
}
return int(total_read), ERROR_NONE;
}
proc seek(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
var w: u32;
match whence {
case 0: w = 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 {
var hi = i32(offset>>32);
var lo = i32(offset);
var ft = win32.get_file_type(win32.Handle(fd));
if ft == win32.FILE_TYPE_PIPE {
return 0, ERROR_FILE_IS_PIPE;
}
dw_ptr := SetFilePointer(fd as HANDLE, lo, ^hi, w);
if dw_ptr == INVALID_SET_FILE_POINTER {
err := GetLastError();
return 0, err as Error;
var dw_ptr = win32.set_file_pointer(win32.Handle(fd), lo, &hi, w);
if dw_ptr == win32.INVALID_SET_FILE_POINTER {
var err = win32.get_last_error();
return 0, Errno(err);
}
return (hi as i64)<<32 + (dw_ptr as i64), ERROR_NONE;
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
}
proc file_size(fd: Handle) -> (i64, Errno) {
var length: i64;
var err: Errno;
if win32.get_file_size_ex(win32.Handle(fd), &length) == 0 {
err = Errno(win32.get_last_error());
}
return length, err;
}
// NOTE(bill): Uses startup to initialize it
stdin := get_std_handle(win32.STD_INPUT_HANDLE);
stdout := get_std_handle(win32.STD_OUTPUT_HANDLE);
stderr := get_std_handle(win32.STD_ERROR_HANDLE);
var stdin = get_std_handle(win32.STD_INPUT_HANDLE);
var stdout = get_std_handle(win32.STD_OUTPUT_HANDLE);
var stderr = get_std_handle(win32.STD_ERROR_HANDLE);
get_std_handle :: proc(h: int) -> Handle {
fd := win32.GetStdHandle(h as i32);
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
return fd as Handle;
proc get_std_handle(h: int) -> Handle {
var fd = win32.get_std_handle(i32(h));
win32.set_handle_information(fd, win32.HANDLE_FLAG_INHERIT, 0);
return Handle(fd);
}
@@ -168,105 +219,127 @@ 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;
proc last_write_time(fd: Handle) -> FileTime {
var file_info: win32.ByHandleFileInformation;
win32.get_file_information_by_handle(win32.Handle(fd), &file_info);
var lo = FileTime(file_info.last_write_time.lo);
var hi = FileTime(file_info.last_write_time.hi);
return lo | hi << 32;
}
last_write_time_by_name :: proc(name: string) -> File_Time {
last_write_time: win32.FILETIME;
data: win32.FILE_ATTRIBUTE_DATA;
buf: [1024]byte;
proc last_write_time_by_name(name: string) -> FileTime {
var last_write_time: win32.Filetime;
var data: win32.FileAttributeData;
var buf: [1024]u8;
assert(buf.count > name.count);
assert(len(buf) > len(name));
copy(buf[:], name as []byte);
copy(buf[..], []u8(name));
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
if win32.get_file_attributes_ex_a(&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;
var l = FileTime(last_write_time.lo);
var h = FileTime(last_write_time.hi);
return l | h << 32;
}
read_entire_file :: proc(name: string) -> ([]byte, bool) {
buf: [300]byte;
copy(buf[:], name as []byte);
fd, err := open(name, O_RDONLY, 0);
if err != ERROR_NONE {
return nil, false;
proc heap_alloc(size: int) -> rawptr {
return win32.heap_alloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, size);
}
proc heap_resize(ptr: rawptr, new_size: int) -> rawptr {
if new_size == 0 {
heap_free(ptr);
return nil;
}
defer close(fd);
length: i64;
file_size_ok := win32.GetFileSizeEx(fd as win32.HANDLE, ^length) != 0;
if !file_size_ok {
return nil, false;
if ptr == nil {
return heap_alloc(new_size);
}
data := new_slice(u8, length);
if data.data == nil {
return nil, false;
return win32.heap_realloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
}
proc heap_free(ptr: rawptr) {
if ptr == nil {
return;
}
win32.heap_free(win32.get_process_heap(), 0, ptr);
}
single_read_length: i32;
total_read: i64;
while total_read < length {
remaining := length - total_read;
to_read: u32;
MAX :: 1<<32-1;
if remaining <= MAX {
to_read = remaining as u32;
} else {
to_read = MAX;
proc exit(code: int) {
win32.exit_process(u32(code));
}
proc current_thread_id() -> int {
return int(win32.get_current_thread_id());
}
proc _alloc_command_line_arguments() -> []string {
proc alloc_ucs2_to_utf8(wstr: ^u16) -> string {
var wstr_len = 0;
for (wstr+wstr_len)^ != 0 {
wstr_len++;
}
var len = 2*wstr_len-1;
var buf = make([]u8, len+1);
var str = slice_ptr(wstr, wstr_len+1);
var i, j = 0, 0;
for str[j] != 0 {
match {
case str[j] < 0x80:
if i+1 > len {
return "";
}
buf[i] = u8(str[j]); i++;
j++;
case str[j] < 0x800:
if i+2 > len {
return "";
}
buf[i] = u8(0xc0 + (str[j]>>6)); i++;
buf[i] = u8(0x80 + (str[j]&0x3f)); i++;
j++;
case 0xd800 <= str[j] && str[j] < 0xdc00:
if i+4 > len {
return "";
}
var c = rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000;
buf[i] = u8(0xf0 + (c >> 18)); i++;
buf[i] = u8(0x80 + ((c >> 12) & 0x3f)); i++;
buf[i] = u8(0x80 + ((c >> 6) & 0x3f)); i++;
buf[i] = u8(0x80 + ((c ) & 0x3f)); i++;
j += 2;
case 0xdc00 <= str[j] && str[j] < 0xe000:
return "";
case:
if i+3 > len {
return "";
}
buf[i] = 0xe0 + u8 (str[j] >> 12); i++;
buf[i] = 0x80 + u8((str[j] >> 6) & 0x3f); i++;
buf[i] = 0x80 + u8((str[j] ) & 0x3f); i++;
j++;
}
}
win32.ReadFile(fd as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil);
if single_read_length <= 0 {
free(data.data);
return nil, false;
}
total_read += single_read_length as i64;
return string(buf[0..<i]);
}
return data, true;
var arg_count: i32;
var arg_list_ptr = win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count);
var arg_list = make([]string, arg_count);
for _, i in arg_list {
arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^);
}
return arg_list;
}
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 {
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
}
heap_free :: proc(ptr: rawptr) {
win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
}
exit :: proc(code: int) {
win32.ExitProcess(code as u32);
}
current_thread_id :: proc() -> int {
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
return GetCurrentThreadId() as int;
}
+292
View File
@@ -0,0 +1,292 @@
foreign_system_library (
dl "dl";
libc "c";
)
import "strings.odin";
type (
Handle i32;
FileTime u64;
Errno int;
AddressSize int;
)
const (
O_RDONLY = 0x00000;
O_WRONLY = 0x00001;
O_RDWR = 0x00002;
O_CREAT = 0x00040;
O_EXCL = 0x00080;
O_NOCTTY = 0x00100;
O_TRUNC = 0x00200;
O_NONBLOCK = 0x00800;
O_APPEND = 0x00400;
O_SYNC = 0x01000;
O_ASYNC = 0x02000;
O_CLOEXEC = 0x80000;
)
const (
SEEK_SET = 0;
SEEK_CUR = 1;
SEEK_END = 2;
SEEK_DATA = 3;
SEEK_HOLE = 4;
SEEK_MAX = SEEK_HOLE;
)
const (
// NOTE(zangent): These are OS specific!
// Do not mix these up!
RTLD_LAZY = 0x1;
RTLD_NOW = 0x2;
RTLD_LOCAL = 0x4;
RTLD_GLOBAL = 0x8;
RTLD_NODELETE = 0x80;
RTLD_NOLOAD = 0x10;
RTLD_FIRST = 0x100;
)
var args: [dynamic]string;
type _FileTime struct #ordered {
seconds: i64,
nanoseconds: i64
}
type Stat struct #ordered {
device_id : i32, // ID of device containing file
mode : u16, // Mode of the file
nlink : u16, // Number of hard links
serial : u64, // File serial number
uid : u32, // User ID of the file's owner
gid : u32, // Group ID of the file's group
rdev : i32, // Device ID, if device
last_access : FileTime, // Time of last access
modified : FileTime, // Time of last modification
status_change : FileTime, // Time of last status change
created : FileTime, // Time of creation
size : i64, // Size of the file, in bytes
blocks : i64, // Number of blocks allocated for the file
block_size: i32, // Optimal blocksize for I/O
flags : u32, // User-defined flags for the file
gen_num : u32, // File generation number ...?
_spare : i32, // RESERVED
_reserve1,
_reserve2 : i64, // RESERVED
};
// File type
const (
S_IFMT = 0170000; // Type of file mask
S_IFIFO = 0010000; // Named pipe (fifo)
S_IFCHR = 0020000; // Character special
S_IFDIR = 0040000; // Directory
S_IFBLK = 0060000; // Block special
S_IFREG = 0100000; // Regular
S_IFLNK = 0120000; // Symbolic link
S_IFSOCK = 0140000; // Socket
// File mode
// Read, write, execute/search by owner
S_IRWXU = 0000700; // RWX mask for owner
S_IRUSR = 0000400; // R for owner
S_IWUSR = 0000200; // W for owner
S_IXUSR = 0000100; // X for owner
// Read, write, execute/search by group
S_IRWXG = 0000070; // RWX mask for group
S_IRGRP = 0000040; // R for group
S_IWGRP = 0000020; // W for group
S_IXGRP = 0000010; // X for group
// Read, write, execute/search by others
S_IRWXO = 0000007; // RWX mask for other
S_IROTH = 0000004; // R for other
S_IWOTH = 0000002; // W for other
S_IXOTH = 0000001; // X for other
S_ISUID = 0004000; // Set user id on execution
S_ISGID = 0002000; // Set group id on execution
S_ISVTX = 0001000; // Directory restrcted delete
)
proc S_ISLNK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFLNK; }
proc S_ISREG (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFREG; }
proc S_ISDIR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFDIR; }
proc S_ISCHR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFCHR; }
proc S_ISBLK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFBLK; }
proc S_ISFIFO(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFIFO; }
proc S_ISSOCK(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFSOCK;}
const (
R_OK = 4; // Test for read permission
W_OK = 2; // Test for write permission
X_OK = 1; // Test for execute permission
F_OK = 0; // Test for file existance
)
foreign libc {
proc unix_open (path: ^u8, mode: int) -> Handle #link_name "open";
proc unix_close (handle: Handle) #link_name "close";
proc unix_read (handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "read";
proc unix_write (handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "write";
proc unix_lseek (fs: Handle, offset: AddressSize, whence: int) -> AddressSize #link_name "lseek";
proc unix_gettid() -> u64 #link_name "gettid";
proc unix_stat (path: ^u8, stat: ^Stat) -> int #link_name "stat";
proc unix_access(path: ^u8, mask: int) -> int #link_name "access";
proc unix_malloc (size: int) -> rawptr #link_name "malloc";
proc unix_free (ptr: rawptr) #link_name "free";
proc unix_realloc(ptr: rawptr, size: int) -> rawptr #link_name "realloc";
proc unix_getenv (^u8) -> ^u8 #link_name "getenv";
proc unix_exit(status: int) #link_name "exit";
}
foreign dl {
proc unix_dlopen (filename: ^u8, flags: int) -> rawptr #link_name "dlopen";
proc unix_dlsym (handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym";
proc unix_dlclose(handle: rawptr) -> int #link_name "dlclose";
proc unix_dlerror() -> ^u8 #link_name "dlerror";
}
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
proc open_simple(path: string, mode: int) -> (Handle, Errno) {
var cstr = strings.new_c_string(path);
var handle = unix_open(cstr, mode);
free(cstr);
if(handle == -1) {
return 0, 1;
}
return handle, 0;
}
// NOTE(zangent): This is here for compatability reasons. Should this be here?
proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
return open_simple(path, mode);
}
proc close(fd: Handle) {
unix_close(fd);
}
proc write(fd: Handle, data: []u8) -> (AddressSize, Errno) {
assert(fd != -1);
var bytes_written = unix_write(fd, &data[0], len(data));
if(bytes_written == -1) {
return 0, 1;
}
return bytes_written, 0;
}
proc read(fd: Handle, data: []u8) -> (AddressSize, Errno) {
assert(fd != -1);
var bytes_read = unix_read(fd, &data[0], len(data));
if(bytes_read == -1) {
return 0, 1;
}
return bytes_read, 0;
}
proc seek(fd: Handle, offset: AddressSize, whence: int) -> (AddressSize, Errno) {
assert(fd != -1);
var final_offset = unix_lseek(fd, offset, whence);
if(final_offset == -1) {
return 0, 1;
}
return final_offset, 0;
}
proc file_size(fd: Handle) -> (i64, Errno) {
var prev, _ = seek(fd, 0, SEEK_CUR);
var size, err = seek(fd, 0, SEEK_END);
seek(fd, prev, SEEK_SET);
return size, err;
}
// NOTE(bill): Uses startup to initialize it
var (
stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE);
stdout: Handle = 1; // get_std_handle(win32.STD_OUTPUT_HANDLE);
stderr: Handle = 2; // get_std_handle(win32.STD_ERROR_HANDLE);
)
/* TODO(zangent): Implement these!
proc last_write_time(fd: Handle) -> FileTime {}
proc last_write_time_by_name(name: string) -> FileTime {}
*/
proc stat(path: string) -> (Stat, bool) #inline {
var s: Stat;
var cstr = strings.new_c_string(path);
defer free(cstr);
var ret_int = unix_stat(cstr, &s);
return s, ret_int==0;
}
proc access(path: string, mask: int) -> bool #inline {
var cstr = strings.new_c_string(path);
defer free(cstr);
return unix_access(cstr, mask) == 0;
}
proc heap_alloc(size: int) -> rawptr #inline {
assert(size > 0);
return unix_malloc(size);
}
proc heap_resize(ptr: rawptr, new_size: int) -> rawptr #inline {
return unix_realloc(ptr, new_size);
}
proc heap_free(ptr: rawptr) #inline {
unix_free(ptr);
}
proc getenv(name: string) -> (string, bool) {
var path_str = strings.new_c_string(name);
var cstr: ^u8 = unix_getenv(path_str);
free(path_str);
if(cstr == nil) {
return "", false;
}
return strings.to_odin_string(cstr), true;
}
proc exit(code: int) #inline {
unix_exit(code);
}
proc current_thread_id() -> int {
// return cast(int) unix_gettid();
return 0;
}
proc dlopen(filename: string, flags: int) -> rawptr #inline {
var cstr = strings.new_c_string(filename);
var handle = unix_dlopen(cstr, flags);
free(cstr);
return handle;
}
proc dlsym(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
assert(handle != nil);
var cstr = strings.new_c_string(symbol);
var proc_handle = unix_dlsym(handle, cstr);
free(cstr);
return proc_handle;
}
proc dlclose(handle: rawptr) -> bool #inline {
assert(handle != nil);
return unix_dlclose(handle) == 0;
}
proc dlerror() -> string {
return strings.to_odin_string(unix_dlerror());
}
+29
View File
@@ -0,0 +1,29 @@
type (
Any struct #ordered {
data: rawptr,
type_info: ^TypeInfo,
};
String struct #ordered {
data: ^u8,
len: int,
};
Slice struct #ordered {
data: rawptr,
len: int,
cap: int,
};
DynamicArray struct #ordered {
data: rawptr,
len: int,
cap: int,
allocator: Allocator,
};
DynamicMap struct #ordered {
hashes: [dynamic]int,
entries: DynamicArray,
};
)
+500
View File
@@ -0,0 +1,500 @@
import . "decimal.odin";
type IntFlag enum {
Prefix = 1<<0,
Plus = 1<<1,
Space = 1<<2,
}
proc parse_bool(s: string) -> (result: bool, ok: bool) {
match s {
case "1", "t", "T", "true", "TRUE", "True":
return true, true;
case "0", "f", "F", "false", "FALSE", "False":
return false, true;
}
return false, false;
}
proc _digit_value(r: rune) -> int {
var ri = int(r);
var v: int = 16;
match r {
case '0'..'9': v = ri-'0';
case 'a'..'z': v = ri-'a'+10;
case 'A'..'Z': v = ri-'A'+10;
}
return v;
}
proc parse_i128(s: string) -> i128 {
var neg = false;
if len(s) > 1 {
match s[0] {
case '-':
neg = true;
s = s[1..];
case '+':
s = s[1..];
}
}
var base: i128 = 10;
if len(s) > 2 && s[0] == '0' {
match s[1] {
case 'b': base = 2; s = s[2..];
case 'o': base = 8; s = s[2..];
case 'd': base = 10; s = s[2..];
case 'z': base = 12; s = s[2..];
case 'x': base = 16; s = s[2..];
}
}
var value: i128;
for r in s {
if r == '_' {
continue;
}
var v = i128(_digit_value(r));
if v >= base {
break;
}
value *= base;
value += v;
}
return neg ? -value : value;
}
proc parse_u128(s: string) -> u128 {
var neg = false;
if len(s) > 1 && s[0] == '+' {
s = s[1..];
}
var base = u128(10);
if len(s) > 2 && s[0] == '0' {
match s[1] {
case 'b': base = 2; s = s[2..];
case 'o': base = 8; s = s[2..];
case 'd': base = 10; s = s[2..];
case 'z': base = 12; s = s[2..];
case 'x': base = 16; s = s[2..];
}
}
var value: u128;
for r in s {
if r == '_' {
continue;
}
var v = u128(_digit_value(r));
if v >= base {
break;
}
value *= base;
value += u128(v);
}
return neg ? -value : value;
}
proc parse_int(s: string) -> int {
return int(parse_i128(s));
}
proc parse_uint(s: string, base: int) -> uint {
return uint(parse_u128(s));
}
proc parse_f64(s: string) -> f64 {
var i = 0;
var sign: f64 = 1;
match s[i] {
case '-': i++; sign = -1;
case '+': i++;
}
var value: f64 = 0;
for ; i < len(s); i++ {
var r = rune(s[i]);
if r == '_' {
continue;
}
var v = _digit_value(r);
if v >= 10 {
break;
}
value *= 10;
value += f64(v);
}
if s[i] == '.' {
var pow10: f64 = 10;
i++;
for ; i < len(s); i++ {
var r = rune(s[i]);
if r == '_' {
continue;
}
var v = _digit_value(r);
if v >= 10 {
break;
}
value += f64(v)/pow10;
pow10 *= 10;
}
}
var frac = false;
var scale: f64 = 1;
if s[i] == 'e' || s[i] == 'E' {
i++;
match s[i] {
case '-': i++; frac = true;
case '+': i++;
}
var exp: u32 = 0;
for ; i < len(s); i++ {
var r = rune(s[i]);
if r == '_' {
continue;
}
var d = u32(_digit_value(r));
if d >= 10 {
break;
}
exp = exp * 10 + d;
}
if exp > 308 { exp = 308; }
for exp >= 50 { scale *= 1e50; exp -= 50; }
for exp >= 8 { scale *= 1e8; exp -= 8; }
for exp > 0 { scale *= 10; exp -= 1; }
}
return sign * (frac ? (value/scale) : (value*scale));
}
proc append_bool(buf: []u8, b: bool) -> string {
var s = b ? "true" : "false";
append(buf, ..[]u8(s));
return string(buf);
}
proc append_uint(buf: []u8, u: u64, base: int) -> string {
return append_bits(buf, u128(u), base, false, 8*size_of(uint), digits, 0);
}
proc append_int(buf: []u8, i: i64, base: int) -> string {
return append_bits(buf, u128(i), base, true, 8*size_of(int), digits, 0);
}
proc itoa(buf: []u8, i: int) -> string { return append_int(buf, i64(i), 10); }
proc append_float(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string {
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
}
type DecimalSlice struct {
digits: []u8,
count: int,
decimal_point: int,
neg: bool,
}
type Float_Info struct {
mantbits: uint,
expbits: uint,
bias: int,
}
var (
_f16_info = Float_Info{10, 5, -15};
_f32_info = Float_Info{23, 8, -127};
_f64_info = Float_Info{52, 11, -1023};
)
proc generic_ftoa(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
var bits: u64;
var flt: ^Float_Info;
match bit_size {
case 32:
bits = u64(transmute(u32, f32(val)));
flt = &_f32_info;
case 64:
bits = transmute(u64, val);
flt = &_f64_info;
case:
panic("strconv: invalid bit_size");
}
var neg = bits>>(flt.expbits+flt.mantbits) != 0;
var exp = int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
var mant = bits & (u64(1) << flt.mantbits - 1);
match exp {
case 1<<flt.expbits - 1:
var s: string;
if mant != 0 {
s = "NaN";
} else if neg {
s = "-Inf";
} else {
s = "+Inf";
}
append(buf, ..[]u8(s));
return buf;
case 0: // denormalized
exp++;
case:
mant |= u64(1) << flt.mantbits;
}
exp += flt.bias;
var d_: Decimal;
var d = &d_;
assign(d, mant);
shift(d, exp - int(flt.mantbits));
var digs: DecimalSlice;
var shortest = prec < 0;
if shortest {
round_shortest(d, mant, exp, flt);
digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
match fmt {
case 'e', 'E': prec = digs.count-1;
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
case 'g', 'G': prec = digs.count;
}
} else {
match fmt {
case 'e', 'E': round(d, prec+1);
case 'f', 'F': round(d, d.decimal_point+prec);
case 'g', 'G':
if prec == 0 {
prec = 1;
}
round(d, prec);
}
digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
}
return format_digits(buf, shortest, neg, digs, prec, fmt);
}
proc format_digits(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: u8) -> []u8 {
match fmt {
case 'f', 'F':
append(buf, neg ? '-' : '+');
// integer, padded with zeros when needed
if digs.decimal_point > 0 {
var m = min(digs.count, digs.decimal_point);
append(buf, ..digs.digits[0..<m]);
for ; m < digs.decimal_point; m++ {
append(buf, '0');
}
} else {
append(buf, '0');
}
// fractional part
if prec > 0 {
append(buf, '.');
for i in 0..<prec {
var c: u8 = '0';
if var j = digs.decimal_point + i; 0 <= j && j < digs.count {
c = digs.digits[j];
}
append(buf, c);
}
}
return buf;
case 'e', 'E':
panic("strconv: e/E float printing is not yet supported");
return buf; // TODO
case 'g', 'G':
panic("strconv: g/G float printing is not yet supported");
return buf; // TODO
}
var c: [2]u8;
c[0] = '%';
c[1] = fmt;
append(buf, ..c[..]);
return buf;
}
proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
if mant == 0 { // If mantissa is zero, the number is zero
d.count = 0;
return;
}
/*
10^(dp-nd) > 2^(exp-mantbits)
log2(10) * (dp-nd) > exp-mantbits
log(2) >~ 0.332
332*(dp-nd) >= 100*(exp-mantbits)
*/
var minexp = flt.bias+1;
if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - int(flt.mantbits)) {
// Number is already its shortest
return;
}
var upper_: Decimal; var upper = &upper_;
assign(upper, 2*mant - 1);
shift(upper, exp - int(flt.mantbits) - 1);
var mantlo: u64;
var explo: int;
if mant > 1<<flt.mantbits || exp == minexp {
mantlo = mant-1;
explo = exp;
} else {
mantlo = 2*mant - 1;
explo = exp-1;
}
var lower_: Decimal; var lower = &lower_;
assign(lower, 2*mantlo + 1);
shift(lower, explo - int(flt.mantbits) - 1);
var inclusive = mant%2 == 0;
for i in 0..<d.count {
var l: u8 = '0'; // lower digit
if i < lower.count {
l = lower.digits[i];
}
var m = d.digits[i]; // middle digit
var u: u8 = '0'; // upper digit
if i < upper.count {
u = upper.digits[i];
}
var ok_round_down = l != m || inclusive && i+1 == lower.count;
var ok_round_up = m != u && (inclusive || m+1 < u || i+1 < upper.count);
if (ok_round_down && ok_round_up) {
round(d, i+1);
return;
}
if (ok_round_down) {
round_down(d, i+1);
return;
}
if (ok_round_up) {
round_up(d, i+1);
return;
}
}
}
const MAX_BASE = 32;
var digits = "0123456789abcdefghijklmnopqrstuvwxyz";
proc is_integer_negative(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
var neg = false;
if is_signed {
match bit_size {
case 8:
var i = i8(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
case 16:
var i = i16(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
case 32:
var i = i32(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
case 64:
var i = i64(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
case 128:
var i = i128(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
case:
panic("is_integer_negative: Unknown integer size");
}
}
return u, neg;
}
proc append_bits(buf: []u8, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: IntFlag) -> string {
if base < 2 || base > MAX_BASE {
panic("strconv: illegal base passed to append_bits");
}
var neg: bool;
var a: [129]u8;
var i = len(a);
u, neg = is_integer_negative(u, is_signed, bit_size);
var b = u128(base);
for u >= b {
i--; a[i] = digits[uint(u % b)];
u /= b;
}
i--; a[i] = digits[uint(u % b)];
if flags&IntFlag.Prefix != 0 {
var ok = true;
match base {
case 2: i--; a[i] = 'b';
case 8: i--; a[i] = 'o';
case 10: i--; a[i] = 'd';
case 12: i--; a[i] = 'z';
case 16: i--; a[i] = 'x';
case: ok = false;
}
if ok {
i--; a[i] = '0';
}
}
if neg {
i--; a[i] = '-';
} else if flags&IntFlag.Plus != 0 {
i--; a[i] = '+';
} else if flags&IntFlag.Space != 0 {
i--; a[i] = ' ';
}
append(buf, ..a[i..]);
return string(buf);
}
+21
View File
@@ -0,0 +1,21 @@
proc new_string(s: string) -> string {
var c = make([]u8, len(s)+1);
copy(c, []u8(s));
c[len(s)] = 0;
return string(c[0..<len(s)]);
}
proc new_c_string(s: string) -> ^u8 {
var c = make([]u8, len(s)+1);
copy(c, []u8(s));
c[len(s)] = 0;
return &c[0];
}
proc to_odin_string(c: ^u8) -> string {
var len = 0;
for (c+len)^ != 0 {
len++;
}
return string(slice_ptr(c, len));
}
+4 -91
View File
@@ -1,91 +1,4 @@
#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);
}
}
}
import_load (
"sync_windows.odin" when ODIN_OS == "windows";
"sync_linux.odin" when ODIN_OS == "linux";
)
+95
View File
@@ -0,0 +1,95 @@
import (
"atomics.odin";
"os.odin";
)
type Semaphore struct {
// _handle: win32.Handle,
}
type Mutex struct {
_semaphore: Semaphore,
_counter: i32,
_owner: i32,
_recursion: i32,
}
proc current_thread_id() -> i32 {
return i32(os.current_thread_id());
}
proc semaphore_init(s: ^Semaphore) {
// s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
}
proc semaphore_destroy(s: ^Semaphore) {
// win32.CloseHandle(s._handle);
}
proc semaphore_post(s: ^Semaphore, count: int) {
// win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
}
proc semaphore_release(s: ^Semaphore) #inline {
semaphore_post(s, 1);
}
proc semaphore_wait(s: ^Semaphore) {
// win32.WaitForSingleObject(s._handle, win32.INFINITE);
}
proc mutex_init(m: ^Mutex) {
atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore);
m._recursion = 0;
}
proc mutex_destroy(m: ^Mutex) {
semaphore_destroy(&m._semaphore);
}
proc mutex_lock(m: ^Mutex) {
var thread_id = current_thread_id();
if atomics.fetch_add(&m._counter, 1) > 0 {
if thread_id != atomics.load(&m._owner) {
semaphore_wait(&m._semaphore);
}
}
atomics.store(&m._owner, thread_id);
m._recursion++;
}
proc mutex_try_lock(m: ^Mutex) -> bool {
var thread_id = current_thread_id();
if atomics.load(&m._owner) == thread_id {
atomics.fetch_add(&m._counter, 1);
} else {
var expected: i32 = 0;
if atomics.load(&m._counter) != 0 {
return false;
}
if atomics.compare_exchange(&m._counter, expected, 1) == 0 {
return false;
}
atomics.store(&m._owner, thread_id);
}
m._recursion++;
return true;
}
proc mutex_unlock(m: ^Mutex) {
var recursion: i32;
var thread_id = current_thread_id();
assert(thread_id == atomics.load(&m._owner));
m._recursion--;
recursion = m._recursion;
if recursion == 0 {
atomics.store(&m._owner, thread_id);
}
if atomics.fetch_add(&m._counter, -1) > 1 {
if recursion == 0 {
semaphore_release(&m._semaphore);
}
}
}
+93
View File
@@ -0,0 +1,93 @@
import (
win32 "sys/windows.odin" when ODIN_OS == "windows";
"atomics.odin";
)
type Semaphore struct {
_handle: win32.Handle,
}
type Mutex struct {
_semaphore: Semaphore,
_counter: i32,
_owner: i32,
_recursion: i32,
}
proc current_thread_id() -> i32 {
return i32(win32.get_current_thread_id());
}
proc semaphore_init(s: ^Semaphore) {
s._handle = win32.create_semaphore_a(nil, 0, 1<<31-1, nil);
}
proc semaphore_destroy(s: ^Semaphore) {
win32.close_handle(s._handle);
}
proc semaphore_post(s: ^Semaphore, count: int) {
win32.release_semaphore(s._handle, i32(count), nil);
}
proc semaphore_release(s: ^Semaphore) #inline { semaphore_post(s, 1); }
proc semaphore_wait(s: ^Semaphore) {
win32.wait_for_single_object(s._handle, win32.INFINITE);
}
proc mutex_init(m: ^Mutex) {
atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore);
m._recursion = 0;
}
proc mutex_destroy(m: ^Mutex) {
semaphore_destroy(&m._semaphore);
}
proc mutex_lock(m: ^Mutex) {
var thread_id = current_thread_id();
if atomics.fetch_add(&m._counter, 1) > 0 {
if thread_id != atomics.load(&m._owner) {
semaphore_wait(&m._semaphore);
}
}
atomics.store(&m._owner, thread_id);
m._recursion++;
}
proc mutex_try_lock(m: ^Mutex) -> bool {
var thread_id = current_thread_id();
if atomics.load(&m._owner) == thread_id {
atomics.fetch_add(&m._counter, 1);
} else {
var expected: i32 = 0;
if atomics.load(&m._counter) != 0 {
return false;
}
if atomics.compare_exchange(&m._counter, expected, 1) == 0 {
return false;
}
atomics.store(&m._owner, thread_id);
}
m._recursion++;
return true;
}
proc mutex_unlock(m: ^Mutex) {
var recursion: i32;
var thread_id = current_thread_id();
assert(thread_id == atomics.load(&m._owner));
m._recursion--;
recursion = m._recursion;
if recursion == 0 {
atomics.store(&m._owner, thread_id);
}
if atomics.fetch_add(&m._counter, -1) > 1 {
if recursion == 0 {
semaphore_release(&m._semaphore);
}
}
}
+90
View File
@@ -0,0 +1,90 @@
foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
import . "windows.odin";
const (
CONTEXT_MAJOR_VERSION_ARB = 0x2091;
CONTEXT_MINOR_VERSION_ARB = 0x2092;
CONTEXT_FLAGS_ARB = 0x2094;
CONTEXT_PROFILE_MASK_ARB = 0x9126;
CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x0002;
CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001;
CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002;
)
type (
Hglrc Handle;
ColorRef u32;
LayerPlaneDescriptor struct {
size: u16,
version: u16,
flags: u32,
pixel_type: u8,
color_bits: u8,
red_bits: u8,
red_shift: u8,
green_bits: u8,
green_shift: u8,
blue_bits: u8,
blue_shift: u8,
alpha_bits: u8,
alpha_shift: u8,
accum_bits: u8,
accum_red_bits: u8,
accum_green_bits: u8,
accum_blue_bits: u8,
accum_alpha_bits: u8,
depth_bits: u8,
stencil_bits: u8,
aux_buffers: u8,
layer_type: u8,
reserved: u8,
transparent: ColorRef,
}
PointFloat struct {
x, y: f32,
}
Glyph_MetricsFloat struct {
black_box_x: f32,
black_box_y: f32,
glyph_origin: PointFloat,
cell_inc_x: f32,
cell_inc_y: f32,
}
)
type (
CreateContextAttribsARBType proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
ChoosePixelFormatARBType proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c;
SwapIntervalEXTType proc(interval: i32) -> bool #cc_c;
GetExtensionsStringARBType proc(Hdc) -> ^u8 #cc_c;
)
var (
create_context_attribs_arb: CreateContextAttribsARBType;
choose_pixel_format_arb: ChoosePixelFormatARBType;
swap_interval_ext: SwapIntervalEXTType;
get_extensions_string_arb: GetExtensionsStringARBType;
)
foreign opengl32 {
proc create_context (hdc: Hdc) -> Hglrc #link_name "wglCreateContext";
proc make_current (hdc: Hdc, hglrc: Hglrc) -> Bool #link_name "wglMakeCurrent";
proc get_proc_address (c_str: ^u8) -> Proc #link_name "wglGetProcAddress";
proc delete_context (hglrc: Hglrc) -> Bool #link_name "wglDeleteContext";
proc copy_context (src, dst: Hglrc, mask: u32) -> Bool #link_name "wglCopyContext";
proc create_layer_context (hdc: Hdc, layer_plane: i32) -> Hglrc #link_name "wglCreateLayerContext";
proc describe_layer_plane (hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^LayerPlaneDescriptor) -> Bool #link_name "wglDescribeLayerPlane";
proc get_current_context () -> Hglrc #link_name "wglGetCurrentContext";
proc get_current_dc () -> Hdc #link_name "wglGetCurrentDC";
proc get_layer_palette_entries(hdc: Hdc, layer_plane, start, entries: i32, cr: ^ColorRef) -> i32 #link_name "wglGetLayerPaletteEntries";
proc realize_layer_palette (hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool #link_name "wglRealizeLayerPalette";
proc set_layer_palette_entries(hdc: Hdc, layer_plane, start, entries: i32, cr: ^ColorRef) -> i32 #link_name "wglSetLayerPaletteEntries";
proc share_lists (hglrc1, hglrc2: Hglrc) -> Bool #link_name "wglShareLists";
proc swap_layer_buffers (hdc: Hdc, planes: u32) -> Bool #link_name "wglSwapLayerBuffers";
proc use_font_bitmaps (hdc: Hdc, first, count, list_base: u32) -> Bool #link_name "wglUseFontBitmaps";
proc use_font_outlines (hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_MetricsFloat) -> Bool #link_name "wglUseFontOutlines";
}
+578 -433
View File
File diff suppressed because it is too large Load Diff
+98
View File
@@ -0,0 +1,98 @@
proc is_signed(info: ^TypeInfo) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case TypeInfo.Integer: return i.signed;
case TypeInfo.Float: return true;
}
return false;
}
proc is_integer(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Integer);
return ok;
}
proc is_float(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Float);
return ok;
}
proc is_complex(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Complex);
return ok;
}
proc is_any(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Any);
return ok;
}
proc is_string(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.String);
return ok;
}
proc is_boolean(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Boolean);
return ok;
}
proc is_pointer(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Pointer);
return ok;
}
proc is_procedure(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Procedure);
return ok;
}
proc is_array(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Array);
return ok;
}
proc is_dynamic_array(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.DynamicArray);
return ok;
}
proc is_dynamic_map(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Map);
return ok;
}
proc is_slice(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Slice);
return ok;
}
proc is_vector(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Vector);
return ok;
}
proc is_tuple(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Tuple);
return ok;
}
proc is_struct(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Struct);
return ok;
}
proc is_union(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Union);
return ok;
}
proc is_raw_union(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.RawUnion);
return ok;
}
proc is_enum(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Enum);
return ok;
}
+59
View File
@@ -0,0 +1,59 @@
const (
REPLACEMENT_CHAR = '\uFFFD';
MAX_RUNE = '\U0010FFFF';
_surr1 = 0xd800;
_surr2 = 0xdc00;
_surr3 = 0xe000;
_surr_self = 0x10000;
)
proc is_surrogate(r: rune) -> bool {
return _surr1 <= r && r < _surr3;
}
proc decode_surrogate_pair(r1, r2: rune) -> rune {
if _surr1 <= r1 && r1 < _surr2 && _surr2 <= r2 && r2 < _surr3 {
return (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self;
}
return REPLACEMENT_CHAR;
}
proc encode_surrogate_pair(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;
}
proc encode(d: []u16, s: []rune) {
var n = len(s);
for r in s {
if r >= _surr_self {
n++;
}
}
var 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:
var r1, r2 = encode_surrogate_pair(r);
d[n] = u16(r1);
d[n+1] = u16(r2);
n += 2;
case:
d[n] = u16(REPLACEMENT_CHAR);
n++;
}
}
}
+166 -108
View File
@@ -1,56 +1,78 @@
RUNE_ERROR :: '\ufffd';
RUNE_SELF :: 0x80;
RUNE_BOM :: 0xfeff;
RUNE_EOF :: ~(0 as rune);
MAX_RUNE :: '\U0010ffff';
UTF_MAX :: 4;
const (
RUNE_ERROR = '\ufffd';
RUNE_SELF = 0x80;
RUNE_BOM = 0xfeff;
RUNE_EOF = ~rune(0);
MAX_RUNE = '\U0010ffff';
UTF_MAX = 4;
SURROGATE_MIN :: 0xd800;
SURROGATE_MAX :: 0xdfff;
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{
{0x80, 0xbf},
{0xa0, 0xbf},
{0x80, 0x9f},
{0x90, 0xbf},
{0x80, 0x8f},
};
MASKX = 0b0011_1111;
MASK2 = 0b0001_1111;
MASK3 = 0b0000_1111;
MASK4 = 0b0000_0111;
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
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
RUNE1_MAX = 1<<7 - 1;
RUNE2_MAX = 1<<11 - 1;
RUNE3_MAX = 1<<16 - 1;
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
};
// The default lowest and highest continuation byte.
LOCB = 0b1000_0000;
HICB = 0b1011_1111;
)
encode_rune :: proc(r: rune) -> ([4]byte, int) {
buf: [4]byte;
i := r as u32;
mask: byte : 0x3f;
type AcceptRange struct { lo, hi: u8 }
var (
accept_ranges = [5]AcceptRange{
{0x80, 0xbf},
{0xa0, 0xbf},
{0x80, 0x9f},
{0x90, 0xbf},
{0x80, 0x8f},
};
accept_sizes = [256]u8{
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
};
)
proc encode_rune(r: rune) -> ([4]u8, int) {
var buf: [4]u8;
var i = u32(r);
const mask: u8 = 0x3f;
if i <= 1<<7-1 {
buf[0] = r as byte;
buf[0] = u8(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 | u8(r>>6);
buf[1] = 0x80 | u8(r) & mask;
return buf, 2;
}
@@ -61,65 +83,99 @@ 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 | u8(r>>12);
buf[1] = 0x80 | u8(r>>6) & mask;
buf[2] = 0x80 | u8(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 | u8(r>>18);
buf[1] = 0x80 | u8(r>>12) & mask;
buf[2] = 0x80 | u8(r>>6) & mask;
buf[3] = 0x80 | u8(r) & mask;
return buf, 4;
}
decode_rune :: proc(s: string) -> (rune, int) {
n := s.count;
proc decode_rune(s: string) -> (rune, int) #inline { return decode_rune([]u8(s)); }
proc decode_rune(s: []u8) -> (rune, int) {
var 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;
var s0 = s[0];
var x = accept_sizes[s0];
if x >= 0xF0 {
var 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 {
var sz = x & 7;
var accept = accept_ranges[x>>4];
if n < int(sz) {
return RUNE_ERROR, 1;
}
b1 := s[1];
if b1 < ar.lo || ar.hi < b1 {
var b1 = s[1];
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 {
var b2 = s[2];
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 {
var b3 = s[3];
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;
}
valid_rune :: proc(r: rune) -> bool {
proc decode_last_rune(s: string) -> (rune, int) #inline { return decode_last_rune([]u8(s)); }
proc decode_last_rune(s: []u8) -> (rune, int) {
var r: rune;
var size: int;
var 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;
}
proc valid_rune(r: rune) -> bool {
if r < 0 {
return false;
} else if SURROGATE_MIN <= r && r <= SURROGATE_MAX {
@@ -130,33 +186,32 @@ valid_rune :: proc(r: rune) -> bool {
return true;
}
valid_string :: proc(s: string) -> bool {
n := s.count;
i := 0;
while i < n {
si := s[i];
proc valid_string(s: string) -> bool {
var n = len(s);
for var i = 0; i < n; {
var si = s[i];
if si < RUNE_SELF { // ascii
i += 1;
i++;
continue;
}
x := accept_sizes[si];
var x = accept_sizes[si];
if x == 0xf1 {
return false;
}
size := (x & 7) as int;
var size = int(x & 7);
if i+size > n {
return false;
}
ar := accept_ranges[x>>4];
if b := s[i+1]; b < ar.lo || ar.hi < b {
var ar = accept_ranges[x>>4];
if var b = s[i+1]; b < ar.lo || ar.hi < b {
return false;
} else if size == 2 {
// Okay
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
} else if var b = s[i+2]; b < 0x80 || 0xbf < b {
return false;
} else if size == 3 {
// Okay
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
} else if var b = s[i+3]; b < 0x80 || 0xbf < b {
return false;
}
i += size;
@@ -164,37 +219,40 @@ valid_string :: proc(s: string) -> bool {
return true;
}
rune_count :: proc(s: string) -> int {
count := 0;
n := s.count;
i := 0;
while i < n {
defer count += 1;
si := s[i];
proc rune_start(b: u8) -> bool #inline { return b&0xc0 != 0x80; }
proc rune_count(s: string) -> int #inline { return rune_count([]u8(s)); }
proc rune_count(s: []u8) -> int {
var count = 0;
var n = len(s);
for var i = 0; i < n; {
defer count++;
var si = s[i];
if si < RUNE_SELF { // ascii
i += 1;
i++;
continue;
}
x := accept_sizes[si];
var x = accept_sizes[si];
if x == 0xf1 {
i += 1;
i++;
continue;
}
size := (x & 7) as int;
var size = int(x & 7);
if i+size > n {
i += 1;
i++;
continue;
}
ar := accept_ranges[x>>4];
if b := s[i+1]; b < ar.lo || ar.hi < b {
var ar = accept_ranges[x>>4];
if var b = s[i+1]; b < ar.lo || ar.hi < b {
size = 1;
} else if size == 2 {
// Okay
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
} else if var b = s[i+2]; b < 0x80 || 0xbf < b {
size = 1;
} else if size == 3 {
// Okay
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
} else if var b = s[i+3]; b < 0x80 || 0xbf < b {
size = 1;
}
i += size;
@@ -203,7 +261,7 @@ rune_count :: proc(s: string) -> int {
}
rune_size :: proc(r: rune) -> int {
proc rune_size(r: rune) -> int {
match {
case r < 0: return -1;
case r <= 1<<7 - 1: return 1;
+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
+4 -2
View File
@@ -1,8 +1,10 @@
@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
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
set _NO_DEBUG_HEAP=1
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
+94 -100
View File
@@ -1,104 +1,7 @@
#define ARRAY_GROW_FORMULA(x) (2*(x) + 8)
GB_STATIC_ASSERT(ARRAY_GROW_FORMULA(0) > 0);
#define Array(Type_) struct { \
gbAllocator allocator; \
Type_ * e; \
isize count; \
isize capacity; \
}
typedef Array(void) ArrayVoid;
#define array_init_reserve(x_, allocator_, init_capacity_) do { \
void **e = cast(void **)&((x_)->e); \
GB_ASSERT((x_) != NULL); \
(x_)->allocator = (allocator_); \
(x_)->count = 0; \
(x_)->capacity = (init_capacity_); \
*e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_capacity_)); \
} while (0)
#define array_init_count(x_, allocator_, init_count_) do { \
void **e = cast(void **)&((x_)->e); \
GB_ASSERT((x_) != NULL); \
(x_)->allocator = (allocator_); \
(x_)->count = (init_count_); \
(x_)->capacity = (init_count_); \
*e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_count_)); \
} while (0)
#define array_init(x_, allocator_) do { array_init_reserve(x_, allocator_, ARRAY_GROW_FORMULA(0)); } while (0)
#define array_free(x_) do { gb_free((x_)->allocator, (x_)->e); } while (0)
#define array_set_capacity(x_, capacity_) do { array__set_capacity((x_), (capacity_), gb_size_of(*(x_)->e)); } while (0)
#define array_grow(x_, min_capacity_) do { \
isize new_capacity = ARRAY_GROW_FORMULA((x_)->capacity); \
if (new_capacity < (min_capacity_)) { \
new_capacity = (min_capacity_); \
} \
array_set_capacity(x_, new_capacity); \
} while (0)
#define array_add(x_, item_) do { \
if ((x_)->capacity < (x_)->count+1) { \
array_grow(x_, 0); \
} \
(x_)->e[(x_)->count++] = item_; \
} while (0)
#define array_pop(x_) do { GB_ASSERT((x_)->count > 0); (x_)->count--; } while (0)
#define array_clear(x_) do { (x_)->count = 0; } while (0)
#define array_resize(x_, new_count_) do { \
if ((x_)->capacity < (new_count_)) { \
array_grow((x_), (new_count_)); \
} \
(x_)->count = (new_count_); \
} while (0)
#define array_reserve(x_, new_capacity_) do { \
if ((x_)->capacity < (new_capacity_)) { \
array_set_capacity((x_), (new_capacity_)); \
} \
} while (0)
void array__set_capacity(void *ptr, isize capacity, isize element_size) {
ArrayVoid *x = cast(ArrayVoid *)ptr;
GB_ASSERT(ptr != NULL);
GB_ASSERT(element_size > 0);
if (capacity == x->capacity) {
return;
}
if (capacity < x->count) {
if (x->capacity < capacity) {
isize new_capacity = ARRAY_GROW_FORMULA(x->capacity);
if (new_capacity < capacity) {
new_capacity = capacity;
}
array__set_capacity(ptr, new_capacity, 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;
}
}
#if 0
#if 1
template <typename T>
struct Array {
gbAllocator allocator;
@@ -230,6 +133,97 @@ void array_set_capacity(Array<T> *array, isize capacity) {
array->capacity = capacity;
}
#endif
#if 0
#define Array(Type_) struct { \
gbAllocator allocator; \
Type_ * e; \
isize count; \
isize capacity; \
}
typedef Array(void) ArrayVoid;
#define array_init_reserve(x_, allocator_, init_capacity_) do { \
void **e = cast(void **)&((x_)->e); \
GB_ASSERT((x_) != NULL); \
(x_)->allocator = (allocator_); \
(x_)->count = 0; \
(x_)->capacity = (init_capacity_); \
*e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_capacity_)); \
} while (0)
#define array_init_count(x_, allocator_, init_count_) do { \
void **e = cast(void **)&((x_)->e); \
GB_ASSERT((x_) != NULL); \
(x_)->allocator = (allocator_); \
(x_)->count = (init_count_); \
(x_)->capacity = (init_count_); \
*e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_count_)); \
} while (0)
#define array_init(x_, allocator_) do { array_init_reserve(x_, allocator_, ARRAY_GROW_FORMULA(0)); } while (0)
#define array_free(x_) do { gb_free((x_)->allocator, (x_)->e); } while (0)
#define array_set_capacity(x_, capacity_) do { array__set_capacity((x_), (capacity_), gb_size_of(*(x_)->e)); } while (0)
#define array_grow(x_, min_capacity_) do { \
isize new_capacity = ARRAY_GROW_FORMULA((x_)->capacity); \
if (new_capacity < (min_capacity_)) { \
new_capacity = (min_capacity_); \
} \
array_set_capacity(x_, new_capacity); \
} while (0)
#define array_add(x_, item_) do { \
if ((x_)->capacity < (x_)->count+1) { \
array_grow(x_, 0); \
} \
(x_)->e[(x_)->count++] = item_; \
} while (0)
#define array_pop(x_) do { GB_ASSERT((x_)->count > 0); (x_)->count--; } while (0)
#define array_clear(x_) do { (x_)->count = 0; } while (0)
#define array_resize(x_, new_count_) do { \
if ((x_)->capacity < (new_count_)) { \
array_grow((x_), (new_count_)); \
} \
(x_)->count = (new_count_); \
} while (0)
#define array_reserve(x_, new_capacity_) do { \
if ((x_)->capacity < (new_capacity_)) { \
array_set_capacity((x_), (new_capacity_)); \
} \
} while (0)
void array__set_capacity(void *ptr, isize capacity, isize element_size) {
ArrayVoid *x = cast(ArrayVoid *)ptr;
GB_ASSERT(ptr != NULL);
GB_ASSERT(element_size > 0);
if (capacity == x->capacity) {
return;
}
if (capacity < x->count) {
if (x->capacity < capacity) {
isize new_capacity = ARRAY_GROW_FORMULA(x->capacity);
if (new_capacity < capacity) {
new_capacity = capacity;
}
array__set_capacity(ptr, new_capacity, element_size);
}
x->count = capacity;
}
x->e = gb_resize(x->allocator, x->e, element_size*x->capacity, element_size*capacity);
x->capacity = capacity;
}
#endif
-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.5a");
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 ");
}
}
+360
View File
@@ -0,0 +1,360 @@
// This stores the information for the specify architecture of this build
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 opt_flags;
String llc_flags;
String link_flags;
bool is_dll;
bool generate_docs;
i32 optimization_level;
};
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[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);
}
len += 1; // NOTE(bill): It needs an extra 1 for some reason
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[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;
u8 *text;
if (global_module_path_set) {
return global_module_path;
}
array_init_count(&path_buf, heap_allocator(), 300);
len = 0;
for (;;) {
u32 sz = path_buf.count;
int res = _NSGetExecutablePath(&path_buf[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[0], len);
path = make_string(text, len);
for (i = path.len-1; i >= 0; i--) {
u8 c = path[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[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[0], len);
path = make_string(text, len);
for (i = path.len-1; i >= 0; i--) {
u8 c = path[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[0], 0, NULL, NULL);
if (len != 0) {
wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
GetFullPathNameW(&string16[0], 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[0], 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[0], base_dir.len); i += base_dir.len;
gb_memmove(str+i, &path[0], 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[0], module_dir.len);
gb_memmove(str+module_dir.len, core, core_len);
gb_memmove(str+module_dir.len+core_len, &path[0], 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.5.0");
bc->ODIN_ROOT = odin_root_dir();
#if defined(GB_SYSTEM_WINDOWS)
bc->ODIN_OS = str_lit("windows");
#elif defined(GB_SYSTEM_OSX)
bc->ODIN_OS = str_lit("osx");
#else
bc->ODIN_OS = str_lit("linux");
#endif
#if defined(GB_ARCH_64_BIT)
bc->ODIN_ARCH = str_lit("amd64");
#else
bc->ODIN_ARCH = str_lit("x86");
#endif
{
u16 x = 1;
bool big = !(*cast(u8 *)&x);
bc->ODIN_ENDIAN = big ? str_lit("big") : str_lit("little");
}
// 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(bc->ODIN_ARCH == "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 (bc->ODIN_ARCH == "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 (bc->ODIN_ARCH == "x86") {
bc->word_size = 4;
bc->max_align = 8;
bc->llc_flags = str_lit("-march=x86 ");
bc->link_flags = str_lit(LINK_FLAG_X86 " ");
} else {
gb_printf_err("This current architecture is not supported");
gb_exit(1);
}
isize opt_max = 1023;
char *opt_flags_string = gb_alloc_array(heap_allocator(), char, opt_max+1);
isize opt_len = 0;
bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
if (bc->optimization_level != 0) {
opt_len = gb_snprintf(opt_flags_string, opt_max, "-O%d", bc->optimization_level);
} else {
opt_len = gb_snprintf(opt_flags_string, opt_max, "");
}
if (opt_len > 0) {
opt_len--;
}
bc->opt_flags = make_string(cast(u8 *)opt_flags_string, opt_len);
#undef LINK_FLAG_X64
#undef LINK_FLAG_X86
}
+269 -201
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?
error_node(operand->expr,
"Cannot assign builtin procedure `%s` in %.*s",
expr_str,
LIT(context_name));
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
error(operand->expr,
"Cannot assign built-in procedure `%s` in %.*s",
expr_str,
LIT(context_name));
operand->mode = Addressing_Invalid;
@@ -34,15 +34,36 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
Type *t = operand->type;
if (is_type_untyped(t)) {
if (t == t_invalid || is_type_untyped_nil(t)) {
error(e->token, "Use of untyped nil in %.*s", LIT(context_name));
error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name));
e->type = t_invalid;
return NULL;
}
if (t == t_invalid || is_type_untyped_undef(t)) {
error(e->token, "Invalid use of --- in %.*s", LIT(context_name));
e->type = t_invalid;
return NULL;
}
t = default_type(t);
}
if (is_type_gen_proc(t)) {
error(e->token, "Invalid use of a generic procedure in %.*s", LIT(context_name));
e->type = t_invalid;
return NULL;
}
if (is_type_bit_field_value(t)) {
t = default_bit_field_value_type(t);
}
if (is_type_variant(t)) {
Type *st = base_type(t);
GB_ASSERT(st->Record.variant_parent != NULL);
t = st->Record.variant_parent;
}
GB_ASSERT(is_type_typed(t));
e->type = t;
}
e->parent_proc_decl = c->context.curr_proc_decl;
check_assignment(c, operand, e->type, context_name);
if (operand->mode == Addressing_Invalid) {
return NULL;
@@ -51,138 +72,43 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
return e->type;
}
void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArray inits, String context_name) {
void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNode *> inits, String context_name) {
if ((lhs == NULL || lhs_count == 0) && inits.count == 0) {
return;
}
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
// 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;
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);
}
}
}
Array<Operand> operands = {};
array_init(&operands, c->tmp_allocator, 2*lhs_count);
check_unpack_arguments(c, lhs_count, &operands, inits, true);
isize rhs_count = operands.count;
for_array(i, operands) {
if (operands.e[i].mode == Addressing_Invalid) {
if (operands[i].mode == Addressing_Invalid) {
rhs_count--;
}
}
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);
check_init_variable(c, lhs[i], &operands[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;
}
@@ -192,7 +118,7 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
if (operand->mode != Addressing_Constant) {
// TODO(bill): better error
gbString str = expr_to_string(operand->expr);
error_node(operand->expr, "`%s` is not a constant", str);
error(operand->expr, "`%s` is not a constant", str);
gb_string_free(str);
if (e->type == NULL) {
e->type = t_invalid;
@@ -201,7 +127,7 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
}
if (!is_type_constant_type(operand->type)) {
gbString type_str = type_to_string(operand->type);
error_node(operand->expr, "Invalid constant type: `%s`", type_str);
error(operand->expr, "Invalid constant type: `%s`", type_str);
gb_string_free(type_str);
if (e->type == NULL) {
e->type = t_invalid;
@@ -218,12 +144,15 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
return;
}
e->parent_proc_decl = c->context.curr_proc_decl;
e->Constant.value = operand->value;
}
void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
GB_ASSERT(e->type == NULL);
Type *named = make_type_named(c->allocator, e->token.string, NULL, e);
String name = e->token.string;
Type *named = make_type_named(c->allocator, name, NULL, e);
named->Named.type_name = e;
if (def != NULL && def->kind == Type_Named) {
def->Named.base = named;
@@ -232,7 +161,7 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
// gb_printf_err("%.*s %p\n", LIT(e->token.string), e);
Type *bt = check_type_extra(c, type_expr, named);
Type *bt = check_type(c, type_expr, named);
named->Named.base = base_type(bt);
if (named->Named.base == t_invalid) {
// gb_printf("check_type_decl: %s\n", type_to_string(named));
@@ -249,30 +178,24 @@ 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)) {
gbString str = type_to_string(t);
error_node(type_expr, "Invalid constant type `%s`", str);
error(type_expr, "Invalid constant type `%s`", str);
gb_string_free(str);
e->type = t_invalid;
c->context.iota = (ExactValue){0};
return;
}
e->type = t;
}
Operand operand = {0};
Operand operand = {};
if (init != NULL) {
check_expr_or_type(c, &operand, init);
}
#if 0
if (operand.mode == Addressing_Type) {
c->context.iota = (ExactValue){0};
e->Constant.value = (ExactValue){0};
e->kind = Entity_TypeName;
DeclInfo *d = c->context.decl;
@@ -280,12 +203,13 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
check_type_decl(c, e, d->type_expr, named_type);
return;
}
#endif
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");
}
}
@@ -304,12 +228,20 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
return false;
}
for (isize i = 0; i < a->param_count; i++) {
Type *x = base_type(a->params->Tuple.variables[i]->type);
Type *y = base_type(b->params->Tuple.variables[i]->type);
Type *x = core_type(a->params->Tuple.variables[i]->type);
Type *y = core_type(b->params->Tuple.variables[i]->type);
if (is_type_pointer(x) && is_type_pointer(y)) {
continue;
}
if (is_type_integer(x) && is_type_integer(y)) {
GB_ASSERT(x->kind == Type_Basic);
GB_ASSERT(y->kind == Type_Basic);
if (x->Basic.size == y->Basic.size) {
continue;
}
}
if (!are_types_identical(x, y)) {
return false;
}
@@ -321,6 +253,14 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
continue;
}
if (is_type_integer(x) && is_type_integer(y)) {
GB_ASSERT(x->kind == Type_Basic);
GB_ASSERT(y->kind == Type_Basic);
if (x->Basic.size == y->Basic.size) {
continue;
}
}
if (!are_types_identical(x, y)) {
return false;
}
@@ -329,92 +269,170 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
return true;
}
void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
GB_ASSERT(e->type == NULL);
if (d->proc_lit->kind != AstNode_ProcLit) {
// TOOD(bill): Better error message
error_node(d->proc_lit, "Expected a procedure to check");
void init_entity_foreign_library(Checker *c, Entity *e) {
AstNode *ident = NULL;
Entity **foreign_library = NULL;
switch (e->kind) {
case Entity_Procedure:
ident = e->Procedure.foreign_library_ident;
foreign_library = &e->Procedure.foreign_library;
break;
case Entity_Variable:
ident = e->Variable.foreign_library_ident;
foreign_library = &e->Variable.foreign_library;
break;
default:
return;
}
Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
if (ident == NULL) {
error(e->token, "foreign entiies must declare which library they are from");
} else if (ident->kind != AstNode_Ident) {
error(ident, "foreign library names must be an identifier");
} else {
String name = ident->Ident.string;
Entity *found = scope_lookup_entity(c->context.scope, name);
if (found == NULL) {
if (name == "_") {
error(ident, "`_` cannot be used as a value type");
} else {
error(ident, "Undeclared name: %.*s", LIT(name));
}
} else if (found->kind != Entity_LibraryName) {
error(ident, "`%.*s` cannot be used as a library name", LIT(name));
} else {
// TODO(bill): Extra stuff to do with library names?
*foreign_library = found;
add_entity_use(c, ident, found);
}
}
}
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
GB_ASSERT(e->type == NULL);
if (d->proc_decl->kind != AstNode_ProcDecl) {
// TOOD(bill): Better error message
error(d->proc_decl, "Expected a procedure to check");
return;
}
Type *proc_type = e->type;
if (d->gen_proc_type != NULL) {
proc_type = d->gen_proc_type;
} else {
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_lit);
ast_node(pd, ProcDecl, d->proc_decl);
check_open_scope(c, pd->type);
defer (check_close_scope(c));
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 (proc_type != NULL) {
TypeProc *pt = &proc_type->Proc;
if (pt->param_count != 0 ||
pt->result_count != 0) {
gbString str = type_to_string(proc_type);
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
gb_string_free(str);
}
TypeProc *pt = &proc_type->Proc;
if (d->scope->is_file && e->token.string == "main") {
if (pt->param_count != 0 ||
pt->result_count != 0) {
gbString str = type_to_string(proc_type);
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
gb_string_free(str);
}
if (proc_type->Proc.calling_convention != ProcCC_Odin &&
proc_type->Proc.calling_convention != ProcCC_Contextless) {
error(e->token, "Procedure `main` cannot have a custom calling convention");
}
proc_type->Proc.calling_convention = ProcCC_Contextless;
}
if (is_inline && is_no_inline) {
error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
error(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
}
if (is_foreign && is_link_name) {
error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
} else if (is_foreign && is_export) {
error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
if (is_foreign && is_export) {
error(pd->type, "A foreign procedure cannot have an `export` tag");
}
if (pt->is_generic) {
if (pd->body == NULL) {
error(e->token, "Polymorphic procedures must have a body");
}
if (is_foreign) {
error(e->token, "A foreign procedures cannot be a polymorphic");
return;
}
}
if (pd->body != NULL) {
if (is_foreign) {
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
error(pd->body, "A foreign procedure cannot have a body");
}
if (proc_type->Proc.calling_convention != ProcCC_Odin) {
error_node(d->proc_lit, "An internal procedure may only have the Odin calling convention");
proc_type->Proc.calling_convention = ProcCC_Odin;
if (proc_type->Proc.c_vararg) {
error(pd->body, "A procedure with a `#c_vararg` field cannot have a body");
}
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);
} else if (!is_foreign) {
error(e->token, "Only a foreign procedure cannot have a body");
}
if (pt->result_count == 0 && is_require_results) {
error(pd->type, "`#require_results` is not needed on a procedure with no results");
} else {
pt->require_results = is_require_results;
}
if (is_foreign) {
MapEntity *fp = &c->info.foreign_procs;
String name = e->token.string;
if (pd->foreign_name.len > 0) {
name = pd->foreign_name;
if (pd->link_name.len > 0) {
name = pd->link_name;
}
e->Procedure.is_foreign = true;
e->Procedure.foreign_name = name;
e->Procedure.link_name = name;
init_entity_foreign_library(c, e);
auto *fp = &c->info.foreigns;
HashKey key = hash_string(name);
Entity **found = map_entity_get(fp, key);
Entity **found = map_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
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_lit,
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
if (is_type_proc(this_type) && is_type_proc(other_type)) {
if (!are_signatures_similar_enough(this_type, other_type)) {
error(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);
}
} else if (!are_types_identical(this_type, other_type)) {
error(d->proc_decl,
"Foreign entity `%.*s` previously declared elsewhere with a different type\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else {
map_entity_set(fp, key, e);
map_set(fp, key, e);
}
} else {
String name = e->token.string;
@@ -423,27 +441,25 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
}
if (is_link_name || is_export) {
MapEntity *fp = &c->info.foreign_procs;
auto *fp = &c->info.foreigns;
e->Procedure.link_name = name;
HashKey key = hash_string(name);
Entity **found = map_entity_get(fp, key);
Entity **found = map_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
// TODO(bill): Better error message?
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);
error(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);
} else {
map_entity_set(fp, key, e);
map_set(fp, key, e);
}
}
}
check_close_scope(c);
}
void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) {
@@ -457,7 +473,34 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
e->flags |= EntityFlag_Visited;
if (type_expr != NULL) {
e->type = check_type_extra(c, type_expr, NULL);
e->type = check_type(c, type_expr);
}
if (e->Variable.is_foreign) {
if (init_expr != NULL) {
error(e->token, "A foreign variable declaration cannot have a default value");
}
init_entity_foreign_library(c, e);
String name = e->token.string;
auto *fp = &c->info.foreigns;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
Type *this_type = base_type(e->type);
Type *other_type = base_type(f->type);
if (!are_types_identical(this_type, other_type)) {
error(e->token,
"Foreign entity `%.*s` previously declared elsewhere with a different type\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else {
map_set(fp, key, e);
}
}
if (init_expr == NULL) {
@@ -469,7 +512,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
if (entities == NULL || entity_count == 1) {
GB_ASSERT(entities == NULL || entities[0] == e);
Operand operand = {0};
Operand operand = {};
check_expr(c, &operand, init_expr);
check_init_variable(c, e, &operand, str_lit("variable declaration"));
}
@@ -480,23 +523,21 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
}
}
AstNodeArray inits;
array_init_reserve(&inits, c->allocator, 1);
Array<AstNode *> inits;
array_init(&inits, c->allocator, 1);
array_add(&inits, init_expr);
check_init_variables(c, entities, entity_count, inits, str_lit("variable declaration"));
}
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
if (e->type != NULL) {
return;
}
if (d == NULL) {
DeclInfo **found = map_decl_info_get(&c->info.entities, hash_pointer(e));
if (found) {
d = *found;
} else {
d = decl_info_of_entity(&c->info, e);
if (d == NULL) {
// TODO(bill): Err here?
e->type = t_invalid;
set_base_type(named_type, t_invalid);
@@ -509,6 +550,8 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
c->context.scope = d->scope;
c->context.decl = d;
e->parent_proc_decl = c->context.curr_proc_decl;
switch (e->kind) {
case Entity_Variable:
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
@@ -520,7 +563,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
check_type_decl(c, e, d->type_expr, named_type);
break;
case Entity_Procedure:
check_proc_lit(c, e, d);
check_proc_decl(c, e, d);
break;
}
@@ -530,30 +573,47 @@ 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) {
if (body == NULL) {
return;
}
GB_ASSERT(body->kind == AstNode_BlockStmt);
String proc_name = {};
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;
c->context.curr_proc_decl = decl;
GB_ASSERT(type->kind == Type_Proc);
if (type->Proc.param_count > 0) {
TypeTuple *params = &type->Proc.params->Tuple;
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->kind != Entity_Variable) {
continue;
}
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)) {
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
GB_ASSERT(found != NULL);
for_array(i, (*found)->elements.entries) {
Entity *f = (*found)->elements.entries.e[i].value;
Scope *scope = scope_of_node(&c->info, t->Record.node);
GB_ASSERT(scope != NULL);
for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[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,7 +631,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
push_procedure(c, type);
{
ast_node(bs, BlockStmt, body);
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)) {
if (token.kind == Token_Ident) {
@@ -586,8 +646,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[i].key;
Entity *e = cast(Entity *)key.ptr;
map_set(&decl->parent->deps, key, true);
}
}
}
+7138
View File
File diff suppressed because it is too large Load Diff
+1825
View File
File diff suppressed because it is too large Load Diff
+2365
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-4759
View File
File diff suppressed because it is too large Load Diff
-1299
View File
File diff suppressed because it is too large Load Diff
-1682
View File
File diff suppressed because it is too large Load Diff
-136
View File
@@ -1,136 +0,0 @@
#define GB_NO_DEFER
#define GB_IMPLEMENTATION
#include "gb/gb.h"
gbAllocator heap_allocator(void) {
return gb_heap_allocator();
}
#include "string.c"
#include "array.c"
gb_global String global_module_path = {0};
gb_global bool global_module_path_set = false;
i64 next_pow2(i64 n) {
if (n <= 0) {
return 0;
}
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
n++;
return n;
}
i64 prev_pow2(i64 n) {
if (n <= 0) {
return 0;
}
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
return n - (n >> 1);
}
i16 f32_to_f16(f32 value) {
union { u32 i; f32 f; } v;
i32 i, s, e, m;
v.f = value;
i = (i32)v.i;
s = (i >> 16) & 0x00008000;
e = ((i >> 23) & 0x000000ff) - (127 - 15);
m = i & 0x007fffff;
if (e <= 0) {
if (e < -10) return cast(i16)s;
m = (m | 0x00800000) >> (1 - e);
if (m & 0x00001000)
m += 0x00002000;
return cast(i16)(s | (m >> 13));
} else if (e == 0xff - (127 - 15)) {
if (m == 0) {
return cast(i16)(s | 0x7c00); /* NOTE(bill): infinity */
} else {
/* NOTE(bill): NAN */
m >>= 13;
return cast(i16)(s | 0x7c00 | m | (m == 0));
}
} else {
if (m & 0x00001000) {
m += 0x00002000;
if (m & 0x00800000) {
m = 0;
e += 1;
}
}
if (e > 30) {
float volatile f = 1e12f;
int j;
for (j = 0; j < 10; j++) {
f *= f; /* NOTE(bill): Cause overflow */
}
return cast(i16)(s | 0x7c00);
}
return cast(i16)(s | (e << 10) | (m >> 13));
}
}
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
// Doubly Linked Lists
#define DLIST_SET(curr_element, next_element) do { \
(curr_element)->next = (next_element); \
(curr_element)->next->prev = (curr_element); \
(curr_element) = (curr_element)->next; \
} while (0)
#define DLIST_APPEND(root_element, curr_element, next_element) do { \
if ((root_element) == NULL) { \
(root_element) = (curr_element) = (next_element); \
} else { \
DLIST_SET(curr_element, next_element); \
} \
} while (0)
////////////////////////////////////////////////////////////////
//
// Generic Data Structures
//
////////////////////////////////////////////////////////////////
#define MAP_TYPE String
#define MAP_PROC map_string_
#define MAP_NAME MapString
#include "map.c"
#define MAP_TYPE bool
#define MAP_PROC map_bool_
#define MAP_NAME MapBool
#include "map.c"
#define MAP_TYPE isize
#define MAP_PROC map_isize_
#define MAP_NAME MapIsize
#include "map.c"
+311
View File
@@ -0,0 +1,311 @@
#if defined(GB_SYSTEM_UNIX)
// Required for intrinsics on GCC
#include <xmmintrin.h>
#endif
#define GB_IMPLEMENTATION
#include "gb/gb.h"
#include <wchar.h>
#include <stdio.h>
#include <math.h>
gbAllocator heap_allocator(void) {
return gb_heap_allocator();
}
#include "unicode.cpp"
#include "string.cpp"
#include "array.cpp"
#include "integer128.cpp"
#include "murmurhash3.cpp"
u128 fnv128a(void const *data, isize len) {
u128 o = u128_lo_hi(0x13bull, 0x1000000ull);
u128 h = u128_lo_hi(0x62b821756295c58dull, 0x6c62272e07bb0142ull);
u8 const *bytes = cast(u8 const *)data;
for (isize i = 0; i < len; i++) {
h.lo ^= bytes[i];
h = h * o;
}
return h;
}
#include "map.cpp"
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);
}
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) {
return 0;
}
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
n++;
return n;
}
i64 prev_pow2(i64 n) {
if (n <= 0) {
return 0;
}
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
return n - (n >> 1);
}
i16 f32_to_f16(f32 value) {
union { u32 i; f32 f; } v;
i32 i, s, e, m;
v.f = value;
i = (i32)v.i;
s = (i >> 16) & 0x00008000;
e = ((i >> 23) & 0x000000ff) - (127 - 15);
m = i & 0x007fffff;
if (e <= 0) {
if (e < -10) return cast(i16)s;
m = (m | 0x00800000) >> (1 - e);
if (m & 0x00001000)
m += 0x00002000;
return cast(i16)(s | (m >> 13));
} else if (e == 0xff - (127 - 15)) {
if (m == 0) {
return cast(i16)(s | 0x7c00); /* NOTE(bill): infinity */
} else {
/* NOTE(bill): NAN */
m >>= 13;
return cast(i16)(s | 0x7c00 | m | (m == 0));
}
} else {
if (m & 0x00001000) {
m += 0x00002000;
if (m & 0x00800000) {
m = 0;
e += 1;
}
}
if (e > 30) {
float volatile f = 1e12f;
int j;
for (j = 0; j < 10; j++) {
f *= f; /* NOTE(bill): Cause overflow */
}
return cast(i16)(s | 0x7c00);
}
return cast(i16)(s | (e << 10) | (m >> 13));
}
}
f64 gb_sqrt(f64 x) {
return sqrt(x);
}
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
// Doubly Linked Lists
#define DLIST_SET(curr_element, next_element) do { \
(curr_element)->next = (next_element); \
(curr_element)->next->prev = (curr_element); \
(curr_element) = (curr_element)->next; \
} while (0)
#define DLIST_APPEND(root_element, curr_element, next_element) do { \
if ((root_element) == NULL) { \
(root_element) = (curr_element) = (next_element); \
} else { \
DLIST_SET(curr_element, next_element); \
} \
} while (0)
#if defined(GB_SYSTEM_WINDOWS)
wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
u32 i, j;
u32 len = string16_len(cmd_line);
i = ((len+2)/2)*gb_size_of(void *) + gb_size_of(void *);
wchar_t **argv = cast(wchar_t **)GlobalAlloc(GMEM_FIXED, i + (len+2)*gb_size_of(wchar_t));
wchar_t *_argv = cast(wchar_t *)((cast(u8 *)argv)+i);
u32 argc = 0;
argv[argc] = _argv;
bool in_quote = false;
bool in_text = false;
bool in_space = true;
i = 0;
j = 0;
for (;;) {
wchar_t a = cmd_line[i];
if (a == 0) {
break;
}
if (in_quote) {
if (a == '\"') {
in_quote = false;
} else {
_argv[j++] = a;
}
} else {
switch (a) {
case '\"':
in_quote = true;
in_text = true;
if (in_space) argv[argc++] = _argv+j;
in_space = false;
break;
case ' ':
case '\t':
case '\n':
case '\r':
if (in_text) _argv[j++] = '\0';
in_text = false;
in_space = true;
break;
default:
in_text = true;
if (in_space) argv[argc++] = _argv+j;
_argv[j++] = a;
in_space = false;
break;
}
}
i++;
}
_argv[j] = '\0';
argv[argc] = NULL;
if (_argc) *_argc = argc;
return argv;
}
#endif
+136
View File
@@ -0,0 +1,136 @@
// Generates Documentation
gbString expr_to_string(AstNode *expression);
String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
isize len = 0;
for_array(i, g.list) {
String comment = g.list[i].string;
len += comment.len;
len += 1; // for \n
}
if (len == 0) {
return make_string(NULL, 0);
}
u8 *text = gb_alloc_array(a, u8, len+1);
len = 0;
for_array(i, g.list) {
String comment = g.list[i].string;
if (comment[1] == '/') {
comment.text += 2;
comment.len -= 2;
} else if (comment[1] == '*') {
comment.text += 2;
comment.len -= 4;
}
comment = string_trim_whitespace(comment);
gb_memmove(text+len, comment.text, comment.len);
len += comment.len;
text[len++] = '\n';
}
return make_string(text, len);
}
void print_type_spec(AstNode *spec) {
ast_node(ts, TypeSpec, spec);
GB_ASSERT(ts->name->kind == AstNode_Ident);
String name = ts->name->Ident.string;
if (name.len == 0) {
return;
}
if (name[0] == '_') {
return;
}
gb_printf("type %.*s\n", LIT(name));
}
void print_proc_decl(AstNodeProcDecl *pd) {
GB_ASSERT(pd->name->kind == AstNode_Ident);
String name = pd->name->Ident.string;
if (name.len == 0) {
return;
}
if (name[0] == '_') {
return;
}
String docs = alloc_comment_group_string(heap_allocator(), pd->docs);
defer (gb_free(heap_allocator(), docs.text));
if (docs.len > 0) {
gb_file_write(&gb__std_files[gbFileStandard_Output], docs.text, docs.len);
} else {
return;
}
ast_node(proc_type, ProcType, pd->type);
gbString params = expr_to_string(proc_type->params);
defer (gb_string_free(params));
gb_printf("proc %.*s(%s)", LIT(name), params);
if (proc_type->results != NULL) {
ast_node(fl, FieldList, proc_type->results);
isize count = fl->list.count;
if (count > 0) {
gbString results = expr_to_string(proc_type->results);
defer (gb_string_free(results));
gb_printf(" -> ");
if (count != 1) {
gb_printf("(");
}
gb_printf("%s", results);
if (count != 1) {
gb_printf(")");
}
}
}
gb_printf("\n\n");
}
void print_declaration(AstNode *decl) {
switch (decl->kind) {
case_ast_node(gd, GenDecl, decl);
for_array(spec_index, gd->specs) {
AstNode *spec = gd->specs[spec_index];
switch(gd->token.kind) {
case Token_var:
break;
case Token_const:
break;
case Token_type:
// print_type_spec(spec);
break;
case Token_import:
case Token_import_load:
break;
case Token_foreign_library:
case Token_foreign_system_library:
break;
}
}
case_end;
case_ast_node(pd, ProcDecl, decl);
print_proc_decl(pd);
case_end;
case_ast_node(fb, ForeignBlockDecl, decl);
// TODO(bill)
case_end;
}
}
void generate_documentation(Parser *parser) {
for_array(file_index, parser->files) {
AstFile *file = &parser->files[file_index];
Tokenizer *tokenizer = &file->tokenizer;
String fullpath = tokenizer->fullpath;
gb_printf("%.*s\n", LIT(fullpath));
for_array(decl_index, file->decls) {
AstNode *decl = file->decls[decl_index];
print_declaration(decl);
}
}
}
+131 -47
View File
@@ -1,8 +1,9 @@
typedef struct Scope Scope;
typedef struct Checker Checker;
typedef struct Type Type;
typedef enum BuiltinProcId BuiltinProcId;
typedef enum ImplicitValueId ImplicitValueId;
struct Scope;
struct Checker;
struct Type;
struct DeclInfo;
// typedef enum BuiltinProcId BuiltinProcId;
#define ENTITY_KINDS \
ENTITY_KIND(Invalid) \
@@ -12,15 +13,16 @@ typedef enum ImplicitValueId ImplicitValueId;
ENTITY_KIND(Procedure) \
ENTITY_KIND(Builtin) \
ENTITY_KIND(ImportName) \
ENTITY_KIND(LibraryName) \
ENTITY_KIND(Nil) \
ENTITY_KIND(ImplicitValue) \
ENTITY_KIND(Count)
ENTITY_KIND(Label)
typedef enum EntityKind {
enum EntityKind {
#define ENTITY_KIND(k) GB_JOIN2(Entity_, k),
ENTITY_KINDS
#undef ENTITY_KIND
} EntityKind;
Entity_Count,
};
String const entity_strings[] = {
#define ENTITY_KIND(k) {cast(u8 *)#k, gb_size_of(#k)-1},
@@ -28,23 +30,48 @@ String const entity_strings[] = {
#undef ENTITY_KIND
};
typedef enum EntityFlag {
EntityFlag_Visited = 1<<0,
EntityFlag_Used = 1<<1,
EntityFlag_Anonymous = 1<<2,
EntityFlag_Field = 1<<3,
EntityFlag_Param = 1<<4,
EntityFlag_VectorElem = 1<<5,
} EntityFlag;
enum EntityFlag {
EntityFlag_Visited = 1<<0,
EntityFlag_Used = 1<<1,
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_Sret = 1<<10,
EntityFlag_BitFieldValue = 1<<11,
typedef struct Entity Entity;
EntityFlag_CVarArg = 1<<20,
};
// Zero value means the overloading process is not yet done
enum OverloadKind {
Overload_Unknown,
Overload_No,
Overload_Yes,
};
enum EntityAliasKind {
EntityAlias_Invalid,
EntityAlias_Type,
EntityAlias_Entity,
};
// An Entity is a named "thing" in the language
struct Entity {
EntityKind kind;
u64 id;
u32 flags;
Token token;
Scope * scope;
Type * type;
AstNode * identifier; // Can be NULL
DeclInfo * parent_proc_decl; // NULL if in file/global scope
// TODO(bill): Cleanup how `using` works for entities
Entity * using_parent;
@@ -55,19 +82,30 @@ struct Entity {
ExactValue value;
} Constant;
struct {
i32 field_index;
i32 field_src_index;
bool is_immutable;
i32 field_index;
i32 field_src_index;
ExactValue default_value;
bool default_is_nil;
bool default_is_location;
bool is_immutable;
bool is_thread_local;
bool is_foreign;
Entity * foreign_library;
AstNode * foreign_library_ident;
} Variable;
i32 TypeName;
struct {
bool is_foreign;
String foreign_name;
String link_name;
u64 tags;
bool is_type_alias;
} TypeName;
struct {
OverloadKind overload_kind;
String link_name;
u64 tags;
bool is_foreign;
Entity * foreign_library;
AstNode * foreign_library_ident;
} Procedure;
struct {
BuiltinProcId id;
i32 id;
} Builtin;
struct {
String path;
@@ -75,18 +113,47 @@ struct Entity {
Scope *scope;
bool used;
} ImportName;
struct {
String path;
String name;
bool used;
} LibraryName;
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[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 +161,23 @@ 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->parent_proc_decl = parent->parent_proc_decl;
entity->flags |= EntityFlag_Using;
return entity;
}
@@ -122,25 +193,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 +225,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 +240,35 @@ 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_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);
}
-401
View File
@@ -1,401 +0,0 @@
#include <math.h>
// TODO(bill): Big numbers
// IMPORTANT TODO(bill): This needs to be completely fixed!!!!!!!!
typedef struct AstNode AstNode;
typedef enum ExactValueKind {
ExactValue_Invalid,
ExactValue_Bool,
ExactValue_String,
ExactValue_Integer,
ExactValue_Float,
ExactValue_Pointer,
ExactValue_Compound, // TODO(bill): Is this good enough?
ExactValue_Count,
} 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;
};
} ExactValue;
HashKey hash_exact_value(ExactValue v) {
return hashing_proc(&v, gb_size_of(ExactValue));
}
ExactValue make_exact_value_compound(AstNode *node) {
ExactValue result = {ExactValue_Compound};
result.value_compound = node;
return result;
}
ExactValue make_exact_value_bool(bool b) {
ExactValue result = {ExactValue_Bool};
result.value_bool = (b != 0);
return result;
}
ExactValue make_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 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 result = {ExactValue_Float};
result.value_float = f;
return result;
}
ExactValue make_exact_value_pointer(i64 ptr) {
ExactValue result = {ExactValue_Pointer};
result.value_pointer = ptr;
return result;
}
ExactValue make_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_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);
}
default:
GB_PANIC("Invalid token for basic literal");
break;
}
ExactValue result = {ExactValue_Invalid};
return result;
}
ExactValue exact_value_to_integer(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return v;
case ExactValue_Float: {
i64 i = cast(i64)v.value_float;
f64 f = cast(f64)i;
if (f == v.value_float) {
return make_exact_value_integer(i);
}
} break;
case ExactValue_Pointer:
return make_exact_value_integer(cast(i64)cast(intptr)v.value_pointer);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_to_float(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return make_exact_value_float(cast(i64)v.value_integer);
case ExactValue_Float:
return v;
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) {
switch (op) {
case Token_Add: {
switch (v.kind) {
case ExactValue_Invalid:
case ExactValue_Integer:
case ExactValue_Float:
return v;
}
} break;
case Token_Sub: {
switch (v.kind) {
case ExactValue_Invalid:
return v;
case ExactValue_Integer: {
ExactValue i = v;
i.value_integer = -i.value_integer;
return i;
}
case ExactValue_Float: {
ExactValue i = v;
i.value_float = -i.value_float;
return i;
}
}
} break;
case Token_Xor: {
i64 i = 0;
switch (v.kind) {
case ExactValue_Invalid:
return v;
case ExactValue_Integer:
i = v.value_integer;
i = ~i;
break;
default:
goto failure;
}
// NOTE(bill): unsigned integers will be negative and will need to be
// limited to the types precision
if (precision > 0)
i &= ~((~0ll)<<precision);
return make_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);
}
} break;
}
failure:
GB_PANIC("Invalid unary operation, %.*s", LIT(token_strings[op]));
ExactValue error_value = {0};
return error_value;
}
// NOTE(bill): Make sure things are evaluated in correct order
i32 exact_value_order(ExactValue v) {
switch (v.kind) {
case ExactValue_Invalid:
return 0;
case ExactValue_Bool:
case ExactValue_String:
return 1;
case ExactValue_Integer:
return 2;
case ExactValue_Float:
return 3;
case ExactValue_Pointer:
return 4;
default:
GB_PANIC("How'd you get here? Invalid Value.kind");
return -1;
}
}
void match_exact_values(ExactValue *x, ExactValue *y) {
if (exact_value_order(*y) < exact_value_order(*x)) {
match_exact_values(y, x);
return;
}
switch (x->kind) {
case ExactValue_Invalid:
*y = *x;
return;
case ExactValue_Bool:
case ExactValue_String:
return;
case ExactValue_Integer:
switch (y->kind) {
case ExactValue_Integer:
return;
case ExactValue_Float:
// TODO(bill): Is this good enough?
*x = make_exact_value_float(cast(f64)x->value_integer);
return;
}
break;
case ExactValue_Float:
if (y->kind == ExactValue_Float)
return;
break;
}
compiler_error("How'd you get here? Invalid ExactValueKind");
}
// TODO(bill): Allow for pointer arithmetic? Or are pointer slices good enough?
ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) {
match_exact_values(&x, &y);
switch (x.kind) {
case ExactValue_Invalid:
return x;
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);
default: goto error;
}
break;
case ExactValue_Integer: {
i64 a = x.value_integer;
i64 b = y.value_integer;
i64 c = 0;
switch (op) {
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_QuoEq: c = a / b; break; // NOTE(bill): Integer division
case Token_Mod: c = a % b; break;
case Token_And: c = a & b; break;
case Token_Or: c = a | b; break;
case Token_Xor: c = a ^ b; break;
case Token_AndNot: c = a&(~b); break;
case Token_Shl: c = a << b; break;
case Token_Shr: c = a >> b; break;
default: goto error;
}
return make_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);
default: goto error;
}
} break;
}
error:
ExactValue error_value = {0};
// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
return error_value;
}
gb_inline ExactValue exact_value_add(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Add, x, y); }
gb_inline ExactValue exact_value_sub(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Sub, x, y); }
gb_inline ExactValue exact_value_mul(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Mul, x, y); }
gb_inline ExactValue exact_value_quo(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Quo, x, y); }
gb_inline ExactValue exact_value_shift(TokenKind op, ExactValue x, ExactValue y) { return exact_binary_operator_value(op, x, y); }
i32 cmp_f64(f64 a, f64 b) {
return (a > b) - (a < b);
}
bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
match_exact_values(&x, &y);
switch (x.kind) {
case ExactValue_Invalid:
return false;
case ExactValue_Bool:
switch (op) {
case Token_CmpEq: return x.value_bool == y.value_bool;
case Token_NotEq: return x.value_bool != y.value_bool;
}
break;
case ExactValue_Integer: {
i64 a = x.value_integer;
i64 b = y.value_integer;
switch (op) {
case Token_CmpEq: return a == b;
case Token_NotEq: return a != b;
case Token_Lt: return a < b;
case Token_LtEq: return a <= b;
case Token_Gt: return a > b;
case Token_GtEq: return a >= b;
}
} break;
case ExactValue_Float: {
f64 a = x.value_float;
f64 b = y.value_float;
switch (op) {
case Token_CmpEq: return cmp_f64(a, b) == 0;
case Token_NotEq: return cmp_f64(a, b) != 0;
case Token_Lt: return cmp_f64(a, b) < 0;
case Token_LtEq: return cmp_f64(a, b) <= 0;
case Token_Gt: return cmp_f64(a, b) > 0;
case Token_GtEq: return cmp_f64(a, b) >= 0;
}
} break;
case ExactValue_String: {
String a = x.value_string;
String b = y.value_string;
isize len = gb_min(a.len, b.len);
// TODO(bill): gb_memcompare is used because the strings are UTF-8
switch (op) {
case Token_CmpEq: return gb_memcompare(a.text, b.text, len) == 0;
case Token_NotEq: return gb_memcompare(a.text, b.text, len) != 0;
case Token_Lt: return gb_memcompare(a.text, b.text, len) < 0;
case Token_LtEq: return gb_memcompare(a.text, b.text, len) <= 0;
case Token_Gt: return gb_memcompare(a.text, b.text, len) > 0;
case Token_GtEq: return gb_memcompare(a.text, b.text, len) >= 0;
}
} break;
}
GB_PANIC("Invalid comparison");
return false;
}
+646
View File
@@ -0,0 +1,646 @@
#include <math.h>
// TODO(bill): Big numbers
// IMPORTANT TODO(bill): This needs to be completely fixed!!!!!!!!
struct AstNode;
struct HashKey;
struct Complex128 {
f64 real, imag;
};
enum ExactValueKind {
ExactValue_Invalid,
ExactValue_Bool,
ExactValue_String,
ExactValue_Integer,
ExactValue_Float,
ExactValue_Complex,
ExactValue_Pointer,
ExactValue_Compound, // TODO(bill): Is this good enough?
ExactValue_Count,
};
struct ExactValue {
ExactValueKind kind;
union {
bool value_bool;
String value_string;
i128 value_integer; // NOTE(bill): This must be an integer and not a pointer
f64 value_float;
i64 value_pointer;
Complex128 value_complex;
AstNode * value_compound;
};
};
gb_global ExactValue const empty_exact_value = {};
HashKey hash_exact_value(ExactValue v) {
return hashing_proc(&v, gb_size_of(ExactValue));
}
ExactValue exact_value_compound(AstNode *node) {
ExactValue result = {ExactValue_Compound};
result.value_compound = node;
return result;
}
ExactValue exact_value_bool(bool b) {
ExactValue result = {ExactValue_Bool};
result.value_bool = (b != 0);
return result;
}
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 exact_value_i64(i64 i) {
ExactValue result = {ExactValue_Integer};
result.value_integer = i128_from_i64(i);
return result;
}
ExactValue exact_value_i128(i128 i) {
ExactValue result = {ExactValue_Integer};
result.value_integer = i;
return result;
}
ExactValue exact_value_u128(u128 i) {
ExactValue result = {ExactValue_Integer};
result.value_integer = u128_to_i128(i);
return result;
}
ExactValue exact_value_float(f64 f) {
ExactValue result = {ExactValue_Float};
result.value_float = f;
return result;
}
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_pointer(i64 ptr) {
ExactValue result = {ExactValue_Pointer};
result.value_pointer = ptr;
return result;
}
ExactValue exact_value_integer_from_string(String string) {
return exact_value_u128(u128_from_string(string));
}
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++;
}
#if 0
if (len-i > 2 &&
str[i] == '0' &&
str[i+1] == 'h') {
i += 2;
u8 *text = string.text;
isize len = string.len;
if (has_prefix) {
text += 2;
len -= 2;
}
u64 base = 16;
u64 result = {0};
for (isize i = 0; i < len; i++) {
Rune r = cast(Rune)text[i];
if (r == '_') {
continue;
}
u64 v = bit128__digit_value(r);
if (v >= base) {
break;
}
result *= base;
result += v;
}
return *cast(f64 *)&result;
}
#endif
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 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[str.len-1];
str.len--; // Ignore the `i|j|k`
f64 imag = float_from_string(str);
if (last_rune == 'i') {
return exact_value_complex(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 exact_value_i64(r);
}
default:
GB_PANIC("Invalid token for basic literal");
break;
}
ExactValue result = {ExactValue_Invalid};
return result;
}
ExactValue exact_value_to_integer(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return v;
case ExactValue_Float: {
i128 i = i128_from_f64(v.value_float);
f64 f = i128_to_f64(i);
if (f == v.value_float) {
return exact_value_i128(i);
}
} break;
case ExactValue_Pointer:
return exact_value_i64(cast(i64)cast(intptr)v.value_pointer);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_to_float(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_float(i128_to_f64(v.value_integer));
case ExactValue_Float:
return v;
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_to_complex(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_complex(i128_to_f64(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_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);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_imag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
return exact_value_i64(0);
case ExactValue_Complex:
return exact_value_float(v.value_complex.imag);
}
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_unary_operator_value(TokenKind op, ExactValue v, i32 precision) {
switch (op) {
case Token_Add: {
switch (v.kind) {
case ExactValue_Invalid:
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
return v;
}
} break;
case Token_Sub: {
switch (v.kind) {
case ExactValue_Invalid:
return v;
case ExactValue_Integer: {
ExactValue i = v;
i.value_integer = -i.value_integer;
return i;
}
case ExactValue_Float: {
ExactValue i = v;
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);
}
}
} break;
case Token_Xor: {
i128 i = I128_ZERO;
switch (v.kind) {
case ExactValue_Invalid:
return v;
case ExactValue_Integer:
i = ~v.value_integer;
break;
default:
goto failure;
}
// NOTE(bill): unsigned integers will be negative and will need to be
// limited to the types precision
// IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored
if (0 < precision && precision < 128) {
i = i & ~(I128_NEG_ONE << precision);
}
return exact_value_i128(i);
} break;
case Token_Not: {
switch (v.kind) {
case ExactValue_Invalid: return v;
case ExactValue_Bool:
return exact_value_bool(!v.value_bool);
}
} break;
}
failure:
GB_PANIC("Invalid unary operation, %.*s", LIT(token_strings[op]));
ExactValue error_value = {};
return error_value;
}
// NOTE(bill): Make sure things are evaluated in correct order
i32 exact_value_order(ExactValue v) {
switch (v.kind) {
case ExactValue_Invalid:
return 0;
case ExactValue_Bool:
case ExactValue_String:
return 1;
case ExactValue_Integer:
return 2;
case ExactValue_Float:
return 3;
case ExactValue_Complex:
return 4;
case ExactValue_Pointer:
return 5;
default:
GB_PANIC("How'd you get here? Invalid Value.kind");
return -1;
}
}
void match_exact_values(ExactValue *x, ExactValue *y) {
if (exact_value_order(*y) < exact_value_order(*x)) {
match_exact_values(y, x);
return;
}
switch (x->kind) {
case ExactValue_Invalid:
*y = *x;
return;
case ExactValue_Bool:
case ExactValue_String:
case ExactValue_Complex:
return;
case ExactValue_Integer:
switch (y->kind) {
case ExactValue_Integer:
return;
case ExactValue_Float:
// TODO(bill): Is this good enough?
*x = exact_value_float(i128_to_f64(x->value_integer));
return;
case ExactValue_Complex:
*x = exact_value_complex(i128_to_f64(x->value_integer), 0);
return;
}
break;
case ExactValue_Float:
switch (y->kind) {
case ExactValue_Float:
return;
case ExactValue_Complex:
*x = exact_value_to_complex(*x);
return;
}
break;
}
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?
ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) {
match_exact_values(&x, &y);
switch (x.kind) {
case ExactValue_Invalid:
return x;
case ExactValue_Bool:
switch (op) {
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;
case ExactValue_Integer: {
i128 a = x.value_integer;
i128 b = y.value_integer;
i128 c = I128_ZERO;
switch (op) {
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 exact_value_float(fmod(i128_to_f64(a), i128_to_f64(b)));
case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division
case Token_Mod: c = a % b; break;
case Token_ModMod: c = ((a % b) + b) % b; break;
case Token_And: c = a & b; break;
case Token_Or: c = a | b; break;
case Token_Xor: c = a ^ b; break;
case Token_AndNot: c = i128_and_not(a, b); break;
case Token_Shl: c = a << i128_to_u64(b); break;
case Token_Shr: c = a >> i128_to_u64(b); break;
default: goto error;
}
return exact_value_i128(c);
} break;
case ExactValue_Float: {
f64 a = x.value_float;
f64 b = y.value_float;
switch (op) {
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;
}
error:
; // MSVC accepts this??? apparently you cannot declare variables immediately after labels...
ExactValue error_value = {};
// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
return error_value;
}
gb_inline ExactValue exact_value_add(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Add, x, y); }
gb_inline ExactValue exact_value_sub(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Sub, x, y); }
gb_inline ExactValue exact_value_mul(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Mul, x, y); }
gb_inline ExactValue exact_value_quo(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Quo, x, y); }
gb_inline ExactValue exact_value_shift(TokenKind op, ExactValue x, ExactValue y) { return exact_binary_operator_value(op, x, y); }
i32 cmp_f64(f64 a, f64 b) {
return (a > b) - (a < b);
}
bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
match_exact_values(&x, &y);
switch (x.kind) {
case ExactValue_Invalid:
return false;
case ExactValue_Bool:
switch (op) {
case Token_CmpEq: return x.value_bool == y.value_bool;
case Token_NotEq: return x.value_bool != y.value_bool;
}
break;
case ExactValue_Integer: {
i128 a = x.value_integer;
i128 b = y.value_integer;
switch (op) {
case Token_CmpEq: return a == b;
case Token_NotEq: return a != b;
case Token_Lt: return a < b;
case Token_LtEq: return a <= b;
case Token_Gt: return a > b;
case Token_GtEq: return a >= b;
}
} break;
case ExactValue_Float: {
f64 a = x.value_float;
f64 b = y.value_float;
switch (op) {
case Token_CmpEq: return cmp_f64(a, b) == 0;
case Token_NotEq: return cmp_f64(a, b) != 0;
case Token_Lt: return cmp_f64(a, b) < 0;
case Token_LtEq: return cmp_f64(a, b) <= 0;
case Token_Gt: return cmp_f64(a, b) > 0;
case Token_GtEq: return cmp_f64(a, b) >= 0;
}
} 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_String: {
String a = x.value_string;
String b = y.value_string;
// TODO(bill): gb_memcompare is used because the strings are UTF-8
switch (op) {
case Token_CmpEq: return a == b;
case Token_NotEq: return a != b;
case Token_Lt: return a < b;
case Token_LtEq: return a <= b;
case Token_Gt: return a > b;
case Token_GtEq: return a >= b;
}
} break;
}
GB_PANIC("Invalid comparison");
return false;
}
+551 -179
View File
File diff suppressed because it is too large Load Diff
+726
View File
@@ -0,0 +1,726 @@
#if defined(GB_COMPILER_MSVC) && defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86)
#define MSVC_AMD64_INTRINSICS
#include <intrin.h>
#pragma intrinsic(_mul128)
#endif
#define BIT128_U64_HIGHBIT 0x8000000000000000ull
#define BIT128_U64_BITS62 0x7fffffffffffffffull
#define BIT128_U64_ALLBITS 0xffffffffffffffffull
typedef struct u128 { u64 lo; u64 hi; } u128;
typedef struct i128 { u64 lo; i64 hi; } i128;
static u128 const U128_ZERO = {0, 0};
static u128 const U128_ONE = {1, 0};
static i128 const I128_ZERO = {0, 0};
static i128 const I128_ONE = {1, 0};
static u128 const U128_NEG_ONE = {BIT128_U64_ALLBITS, BIT128_U64_ALLBITS};
static i128 const I128_NEG_ONE = {BIT128_U64_ALLBITS, cast(i64)BIT128_U64_ALLBITS};
u128 u128_lo_hi (u64 lo, u64 hi);
u128 u128_from_u32 (u32 u);
u128 u128_from_u64 (u64 u);
u128 u128_from_i64 (i64 u);
u128 u128_from_f32 (f32 f);
u128 u128_from_f64 (f64 f);
u128 u128_from_string(String string);
i128 i128_lo_hi (u64 lo, i64 hi);
i128 i128_from_u32 (u32 u);
i128 i128_from_u64 (u64 u);
i128 i128_from_i64 (i64 u);
i128 i128_from_f32 (f32 f);
i128 i128_from_f64 (f64 f);
i128 i128_from_string(String string);
u64 u128_to_u64(u128 a);
i64 u128_to_i64(u128 a);
f64 u128_to_f64(u128 a);
i128 u128_to_i128(u128 a);
u64 i128_to_u64(i128 a);
i64 i128_to_i64(i128 a);
f64 i128_to_f64(i128 a);
u128 i128_to_u128(i128 a);
String u128_to_string(u128 a, char *buf, isize len);
String i128_to_string(i128 a, char *buf, isize len);
i32 u128_cmp (u128 a, u128 b);
bool u128_eq (u128 a, u128 b);
bool u128_ne (u128 a, u128 b);
bool u128_lt (u128 a, u128 b);
bool u128_gt (u128 a, u128 b);
bool u128_le (u128 a, u128 b);
bool u128_ge (u128 a, u128 b);
u128 u128_add (u128 a, u128 b);
u128 u128_not (u128 a);
u128 u128_neg (u128 a);
u128 u128_sub (u128 a, u128 b);
u128 u128_and (u128 a, u128 b);
u128 u128_or (u128 a, u128 b);
u128 u128_xor (u128 a, u128 b);
u128 u128_and_not(u128 a, u128 b);
u128 u128_shl (u128 a, u32 n);
u128 u128_shr (u128 a, u32 n);
u128 u128_mul (u128 a, u128 b);
void u128_divide (u128 num, u128 den, u128 *quo, u128 *rem);
u128 u128_quo (u128 a, u128 b);
u128 u128_mod (u128 a, u128 b);
i128 i128_abs (i128 a);
i32 i128_cmp (i128 a, i128 b);
bool i128_eq (i128 a, i128 b);
bool i128_ne (i128 a, i128 b);
bool i128_lt (i128 a, i128 b);
bool i128_gt (i128 a, i128 b);
bool i128_le (i128 a, i128 b);
bool i128_ge (i128 a, i128 b);
i128 i128_add (i128 a, i128 b);
i128 i128_not (i128 a);
i128 i128_neg (i128 a);
i128 i128_sub (i128 a, i128 b);
i128 i128_and (i128 a, i128 b);
i128 i128_or (i128 a, i128 b);
i128 i128_xor (i128 a, i128 b);
i128 i128_and_not(i128 a, i128 b);
i128 i128_shl (i128 a, u32 n);
i128 i128_shr (i128 a, u32 n);
i128 i128_mul (i128 a, i128 b);
void i128_divide (i128 num, i128 den, i128 *quo, i128 *rem);
i128 i128_quo (i128 a, i128 b);
i128 i128_mod (i128 a, i128 b);
bool operator==(u128 a, u128 b) { return u128_eq(a, b); }
bool operator!=(u128 a, u128 b) { return u128_ne(a, b); }
bool operator< (u128 a, u128 b) { return u128_lt(a, b); }
bool operator> (u128 a, u128 b) { return u128_gt(a, b); }
bool operator<=(u128 a, u128 b) { return u128_le(a, b); }
bool operator>=(u128 a, u128 b) { return u128_ge(a, b); }
u128 operator+(u128 a, u128 b) { return u128_add(a, b); }
u128 operator-(u128 a, u128 b) { return u128_sub(a, b); }
u128 operator*(u128 a, u128 b) { return u128_mul(a, b); }
u128 operator/(u128 a, u128 b) { return u128_quo(a, b); }
u128 operator%(u128 a, u128 b) { return u128_mod(a, b); }
u128 operator&(u128 a, u128 b) { return u128_and(a, b); }
u128 operator|(u128 a, u128 b) { return u128_or (a, b); }
u128 operator^(u128 a, u128 b) { return u128_xor(a, b); }
u128 operator~(u128 a) { return u128_not(a); }
u128 operator+(u128 a) { return a; }
u128 operator-(u128 a) { return u128_neg(a); }
u128 operator<<(u128 a, u32 b) { return u128_shl(a, b); }
u128 operator>>(u128 a, u32 b) { return u128_shr(a, b); }
bool operator==(i128 a, i128 b) { return i128_eq(a, b); }
bool operator!=(i128 a, i128 b) { return i128_ne(a, b); }
bool operator< (i128 a, i128 b) { return i128_lt(a, b); }
bool operator> (i128 a, i128 b) { return i128_gt(a, b); }
bool operator<=(i128 a, i128 b) { return i128_le(a, b); }
bool operator>=(i128 a, i128 b) { return i128_ge(a, b); }
i128 operator+(i128 a, i128 b) { return i128_add(a, b); }
i128 operator-(i128 a, i128 b) { return i128_sub(a, b); }
i128 operator*(i128 a, i128 b) { return i128_mul(a, b); }
i128 operator/(i128 a, i128 b) { return i128_quo(a, b); }
i128 operator%(i128 a, i128 b) { return i128_mod(a, b); }
i128 operator&(i128 a, i128 b) { return i128_and(a, b); }
i128 operator|(i128 a, i128 b) { return i128_or (a, b); }
i128 operator^(i128 a, i128 b) { return i128_xor(a, b); }
i128 operator~(i128 a) { return i128_not(a); }
i128 operator+(i128 a) { return a; }
i128 operator-(i128 a) { return i128_neg(a); }
i128 operator<<(i128 a, u32 b) { return i128_shl(a, b); }
i128 operator>>(i128 a, u32 b) { return i128_shr(a, b); }
////////////////////////////////////////////////////////////////
u64 bit128__digit_value(Rune r) {
if ('0' <= r && r <= '9') {
return r - '0';
} else if ('a' <= r && r <= 'f') {
return r - 'a' + 10;
} else if ('A' <= r && r <= 'F') {
return r - 'A' + 10;
}
return 16; // NOTE(bill): Larger than highest possible
}
u128 u128_lo_hi(u64 lo, u64 hi) {
u128 r = {};
r.lo = lo;
r.hi = hi;
return r;
}
u128 u128_from_u32(u32 u) { return u128_lo_hi(cast(u64)u, 0); }
u128 u128_from_u64(u64 u) { return u128_lo_hi(cast(u64)u, 0); }
u128 u128_from_i64(i64 u) { return u128_lo_hi(cast(u64)u, u < 0 ? -1 : 0); }
u128 u128_from_f32(f32 f) { return u128_lo_hi(cast(u64)f, 0); }
u128 u128_from_f64(f64 f) { return u128_lo_hi(cast(u64)f, 0); }
u128 u128_from_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
u64 base = 10;
bool has_prefix = false;
if (string.len > 2 && string[0] == '0') {
switch (string[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;
}
u128 base_ = u128_from_u64(base);
u128 result = {0};
for (isize i = 0; i < len; i++) {
Rune r = cast(Rune)text[i];
if (r == '_') {
continue;
}
u64 v = bit128__digit_value(r);
if (v >= base) {
break;
}
result = u128_mul(result, base_);
result = u128_add(result, u128_from_u64(v));
}
return result;
}
i128 i128_lo_hi(u64 lo, i64 hi) {
i128 i;
i.lo = lo;
i.hi = hi;
return i;
}
i128 i128_from_u32(u32 u) { return i128_lo_hi(cast(u64)u, 0); }
i128 i128_from_u64(u64 u) { return i128_lo_hi(cast(u64)u, 0); }
i128 i128_from_i64(i64 u) { return i128_lo_hi(cast(u64)u, u < 0 ? -1 : 0); }
i128 i128_from_f32(f32 f) { return i128_lo_hi(cast(u64)f, 0); }
i128 i128_from_f64(f64 f) { return i128_lo_hi(cast(u64)f, 0); }
i128 i128_from_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
u64 base = 10;
bool has_prefix = false;
if (string.len > 2 && string[0] == '0') {
switch (string[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;
}
i128 base_ = i128_from_u64(base);
i128 result = {0};
for (isize i = 0; i < len; i++) {
Rune r = cast(Rune)text[i];
if (r == '_') {
continue;
}
u64 v = bit128__digit_value(r);
if (v >= base) {
break;
}
result = i128_mul(result, base_);
result = i128_add(result, i128_from_u64(v));
}
return result;
}
u64 u128_to_u64(u128 a) {
return (a.lo&BIT128_U64_BITS62) | (a.hi&BIT128_U64_HIGHBIT);
}
i64 u128_to_i64(u128 a) {
return a.lo;
}
f64 u128_to_f64(u128 a) {
if (a.hi >= 0) {
return (cast(f64)a.hi * 18446744073709551616.0) + cast(f64)a.lo;
}
i64 h = cast(i64)a.hi;
u64 l = a.lo;
h = ~h;
l = ~l;
l += 1;
if (l == 0) {
h += 1;
}
return -((cast(f64)h * 18446744073709551616.0) + cast(f64)l);
}
i128 u128_to_i128(u128 a) {
return *cast(i128 *)&a;
}
u64 i128_to_u64(i128 a) {
return (a.lo&BIT128_U64_BITS62) | (a.hi&BIT128_U64_HIGHBIT);
}
i64 i128_to_i64(i128 a) {
return cast(i64)a.lo;
}
f64 i128_to_f64(i128 a) {
if (a.hi >= 0) {
return (cast(f64)a.hi * 18446744073709551616.0) + cast(f64)a.lo;
}
i64 h = a.hi;
u64 l = a.lo;
h = ~h;
l = ~l;
l += 1;
if (l == 0) {
h += 1;
}
return -((cast(f64)h * 18446744073709551616.0) + cast(f64)l);
}
u128 i128_to_u128(i128 a) {
return *cast(u128 *)&a;
}
String u128_to_string(u128 v, char *out_buf, isize out_buf_len) {
char buf[200] = {0};
isize i = gb_size_of(buf);
u128 b = u128_from_u64(10);;
while (u128_ge(v, b)) {
buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
v = u128_quo(v, b);
}
buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
gb_memcopy(out_buf, &buf[i], len);
return make_string(cast(u8 *)out_buf, len);
}
String i128_to_string(i128 a, char *out_buf, isize out_buf_len) {
char buf[200] = {0};
isize i = gb_size_of(buf);
bool negative = false;
if (i128_lt(a, I128_ZERO)) {
negative = true;
a = i128_neg(a);
}
u128 v = *cast(u128 *)&a;
u128 b = u128_from_u64(10);;
while (u128_ge(v, b)) {
buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
v = u128_quo(v, b);
}
buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
if (negative) {
buf[--i] = '-';
}
isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
gb_memcopy(out_buf, &buf[i], len);
return make_string(cast(u8 *)out_buf, len);
}
////////////////////////////////////////////////////////////////
i32 u128_cmp(u128 a, u128 b) {
if (a.hi == b.hi && b.lo == b.lo) {
return 0;
}
if (a.hi == b.hi) {
return a.lo < b.lo ? -1 : +1;
}
return a.hi < b.hi ? -1 : +1;
}
bool u128_eq(u128 a, u128 b) { return a.hi == b.hi && a.lo == b.lo; }
bool u128_ne(u128 a, u128 b) { return !u128_eq(a, b); }
bool u128_lt(u128 a, u128 b) { return a.hi == b.hi ? a.lo < b.lo : a.hi < b.hi; }
bool u128_gt(u128 a, u128 b) { return a.hi == b.hi ? a.lo > b.lo : a.hi > b.hi; }
bool u128_le(u128 a, u128 b) { return !u128_gt(a, b); }
bool u128_ge(u128 a, u128 b) { return !u128_lt(a, b); }
u128 u128_add(u128 a, u128 b) {
u128 old_a = a;
a.lo += b.lo;
a.hi += b.hi;
if (a.lo < old_a.lo) {
a.hi += 1;
}
return a;
}
u128 u128_not(u128 a) { return u128_lo_hi(~a.lo, ~a.hi); }
u128 u128_neg(u128 a) {
return u128_add(u128_not(a), u128_from_u64(1));
}
u128 u128_sub(u128 a, u128 b) {
return u128_add(a, u128_neg(b));
}
u128 u128_and(u128 a, u128 b) { return u128_lo_hi(a.lo&b.lo, a.hi&b.hi); }
u128 u128_or (u128 a, u128 b) { return u128_lo_hi(a.lo|b.lo, a.hi|b.hi); }
u128 u128_xor(u128 a, u128 b) { return u128_lo_hi(a.lo^b.lo, a.hi^b.hi); }
u128 u128_and_not(u128 a, u128 b) { return u128_lo_hi(a.lo&(~b.lo), a.hi&(~b.hi)); }
u128 u128_shl(u128 a, u32 n) {
if (n >= 128) {
return u128_lo_hi(0, 0);
}
#if 0 && defined(MSVC_AMD64_INTRINSICS)
a.hi = __shiftleft128(a.lo, a.hi, n);
a.lo = a.lo << n;
return a;
#else
if (n >= 64) {
n -= 64;
a.hi = a.lo;
a.lo = 0;
}
if (n != 0) {
u64 mask = ~(BIT128_U64_ALLBITS >> n);
a.hi <<= n;
a.hi |= (a.lo&mask) >> (64 - n);
a.lo <<= n;
}
return a;
#endif
}
u128 u128_shr(u128 a, u32 n) {
if (n >= 128) {
return u128_lo_hi(0, 0);
}
#if 0 && defined(MSVC_AMD64_INTRINSICS)
a.lo = __shiftright128(a.lo, a.hi, n);
a.hi = a.hi >> n;
return a;
#else
if (n >= 64) {
n -= 64;
a.lo = a.hi;
a.hi = 0;
}
if (n != 0) {
u64 mask = ~(BIT128_U64_ALLBITS << n);
a.lo >>= n;
a.lo |= (a.hi&mask) << (64 - n);
a.hi >>= n;
}
return a;
#endif
}
u128 u128_mul(u128 a, u128 b) {
if (a.lo == 0 && a.hi == 0) {
return u128_from_u64(0);
} else if (b.lo == 0 && b.hi == 0) {
return u128_from_u64(0);
}
if (u128_eq(a, U128_ONE)) {
return b;
}
if (u128_eq(b, U128_ONE)) {
return a;
}
#if defined(MSVC_AMD64_INTRINSICS)
if (a.hi == 0 && b.hi == 0) {
a.lo = _umul128(a.lo, b.lo, &a.hi);
return a;
}
#endif
u128 res = {0};
u128 t = b;
for (u32 i = 0; i < 128; i++) {
if ((t.lo&1) != 0) {
res = u128_add(res, u128_shl(a, i));
}
t = u128_shr(t, 1);
}
return res;
}
bool u128_hibit(u128 *d) { return (d->hi & BIT128_U64_HIGHBIT) != 0; }
void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) {
if (u128_eq(den, U128_ZERO)) {
if (quo) *quo = u128_from_u64(num.lo/den.lo);
if (rem) *rem = U128_ZERO;
} else {
u128 n = num;
u128 d = den;
u128 x = U128_ONE;
u128 r = U128_ZERO;
while (u128_ge(n, d) && !u128_hibit(&d)) {
x = u128_shl(x, 1);
d = u128_shl(d, 1);
}
while (u128_ne(x, U128_ZERO)) {
if (u128_ge(n, d)) {
n = u128_sub(n, d);
r = u128_or(r, x);
}
x = u128_shr(x, 1);
d = u128_shr(d, 1);
}
if (quo) *quo = r;
if (rem) *rem = n;
}
}
u128 u128_quo(u128 a, u128 b) {
if (a.hi == 0 && b.hi == 0) {
return u128_from_u64(a.lo/b.lo);
}
u128 res = {0};
u128_divide(a, b, &res, NULL);
return res;
}
u128 u128_mod(u128 a, u128 b) {
if (a.hi == 0 && b.hi == 0) {
return u128_from_u64(a.lo%b.lo);
}
u128 res = {0};
u128_divide(a, b, NULL, &res);
return res;
}
////////////////////////////////////////////////////////////////
i128 i128_abs(i128 a) {
if ((a.hi&BIT128_U64_HIGHBIT) != 0) {
return i128_neg(a);
}
return a;
}
i32 i128_cmp(i128 a, i128 b) {
if (a.hi == b.hi && b.lo == b.lo) {
return 0;
}
if (a.hi == b.hi) {
return a.lo < b.lo ? -1 : +1;
}
return a.hi < b.hi ? -1 : +1;
}
bool i128_eq(i128 a, i128 b) { return a.hi == b.hi && a.lo == b.lo; }
bool i128_ne(i128 a, i128 b) { return !i128_eq(a, b); }
bool i128_lt(i128 a, i128 b) { return a.hi == b.hi ? a.lo < b.lo : a.hi < b.hi; }
bool i128_gt(i128 a, i128 b) { return a.hi == b.hi ? a.lo > b.lo : a.hi > b.hi; }
bool i128_le(i128 a, i128 b) { return a.hi == b.hi ? a.lo <= b.lo : a.hi <= b.hi; }
bool i128_ge(i128 a, i128 b) { return a.hi == b.hi ? a.lo >= b.lo : a.hi >= b.hi; }
i128 i128_add(i128 a, i128 b) {
i128 old_a = a;
a.lo += b.lo;
a.hi += b.hi;
if (a.lo < old_a.lo) {
a.hi += 1;
}
return a;
}
i128 i128_not(i128 a) { return i128_lo_hi(~a.lo, ~a.hi); }
i128 i128_neg(i128 a) {
return i128_add(i128_not(a), i128_from_u64(1));
}
i128 i128_sub(i128 a, i128 b) {
return i128_add(a, i128_neg(b));
}
i128 i128_and(i128 a, i128 b) { return i128_lo_hi(a.lo&b.lo, a.hi&b.hi); }
i128 i128_or (i128 a, i128 b) { return i128_lo_hi(a.lo|b.lo, a.hi|b.hi); }
i128 i128_xor(i128 a, i128 b) { return i128_lo_hi(a.lo^b.lo, a.hi^b.hi); }
i128 i128_and_not(i128 a, i128 b) { return i128_lo_hi(a.lo&(~b.lo), a.hi&(~b.hi)); }
i128 i128_shl(i128 a, u32 n) {
if (n >= 128) {
return i128_lo_hi(0, 0);
}
#if 0 && defined(MSVC_AMD64_INTRINSICS)
a.hi = __shiftleft128(a.lo, a.hi, n);
a.lo = a.lo << n;
return a;
#else
if (n >= 64) {
n -= 64;
a.hi = a.lo;
a.lo = 0;
}
if (n != 0) {
u64 mask = ~(BIT128_U64_ALLBITS >> n);
a.hi <<= n;
a.hi |= (a.lo&mask) >> (64 - n);
a.lo <<= n;
}
return a;
#endif
}
i128 i128_shr(i128 a, u32 n) {
if (n >= 128) {
return i128_lo_hi(0, 0);
}
#if 0 && defined(MSVC_AMD64_INTRINSICS)
a.lo = __shiftright128(a.lo, a.hi, n);
a.hi = a.hi >> n;
return a;
#else
if (n >= 64) {
n -= 64;
a.lo = a.hi;
a.hi = 0;
}
if (n != 0) {
u64 mask = ~(BIT128_U64_ALLBITS << n);
a.lo >>= n;
a.lo |= (a.hi&mask) << (64 - n);
a.hi >>= n;
}
return a;
#endif
}
i128 i128_mul(i128 a, i128 b) {
if (a.lo == 0 && a.hi == 0) {
return i128_from_u64(0);
} else if (b.lo == 0 && b.hi == 0) {
return i128_from_u64(0);
}
if (i128_eq(a, I128_ONE)) {
return b;
}
if (i128_eq(b, I128_ONE)) {
return a;
}
#if defined(MSVC_AMD64_INTRINSICS)
if (a.hi == 0 && b.hi == 0) {
a.lo = _mul128(a.lo, b.lo, &a.hi);
return a;
}
#endif
i128 res = {0};
i128 t = b;
for (u32 i = 0; i < 128; i++) {
if ((t.lo&1) != 0) {
res = i128_add(res, i128_shl(a, i));
}
t = i128_shr(t, 1);
}
return res;
}
void i128_divide(i128 a, i128 b, i128 *quo, i128 *rem) {
// TODO(bill): Which one is correct?!
#if 1
i128 s = i128_shr(b, 127);
b = i128_sub(i128_xor(b, s), s);
s = i128_shr(a, 127);
b = i128_sub(i128_xor(a, s), s);
u128 n, r = {0};
u128_divide(*cast(u128 *)&a, *cast(u128 *)&b, &n, &r);
i128 ni = *cast(i128 *)&n;
i128 ri = *cast(i128 *)&r;
if (quo) *quo = i128_sub(i128_xor(ni, s), s);
if (rem) *rem = i128_sub(i128_xor(ri, s), s);
#else
if (i128_eq(b, I128_ZERO)) {
if (quo) *quo = i128_from_u64(a.lo/b.lo);
if (rem) *rem = I128_ZERO;
} else {
i128 n = a;
i128 d = b;
i128 x = I128_ONE;
i128 r = I128_ZERO;
while (i128_ge(n, d) && ((i128_shr(d, 128-1).lo&1) == 0)) {
x = i128_shl(x, 1);
d = i128_shl(d, 1);
}
while (i128_ne(x, I128_ZERO)) {
if (i128_ge(n, d)) {
n = i128_sub(n, d);
r = i128_or(r, x);
}
x = i128_shr(x, 1);
d = i128_shr(d, 1);
}
if (quo) *quo = r;
if (rem) *rem = n;
}
#endif
}
i128 i128_quo(i128 a, i128 b) {
i128 res = {0};
i128_divide(a, b, &res, NULL);
return res;
}
i128 i128_mod(i128 a, i128 b) {
i128 res = {0};
i128_divide(a, b, NULL, &res);
return res;
}
-5794
View File
File diff suppressed because it is too large Load Diff
+8200
View File
File diff suppressed because it is too large Load Diff
+60 -60
View File
@@ -1,6 +1,6 @@
// Optimizations for the IR code
void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
void ir_opt_add_operands(Array<irValue *> *ops, irInstr *i) {
switch (i->kind) {
case irInstr_Comment:
break;
@@ -27,9 +27,6 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
array_add(ops, i->PtrOffset.address);
array_add(ops, i->PtrOffset.offset);
break;
case irInstr_ArrayExtractValue:
array_add(ops, i->ArrayExtractValue.address);
break;
case irInstr_StructExtractValue:
array_add(ops, i->StructExtractValue.address);
break;
@@ -51,7 +48,7 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
break;
case irInstr_Phi:
for_array(j, i->Phi.edges) {
array_add(ops, i->Phi.edges.e[j]);
array_add(ops, i->Phi.edges[j]);
}
break;
case irInstr_Unreachable:
@@ -69,20 +66,22 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
array_add(ops, i->Call.args[j]);
}
break;
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_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;
#if 0
case irInstr_BoundsCheck:
array_add(ops, i->BoundsCheck.index);
array_add(ops, i->BoundsCheck.len);
@@ -91,6 +90,7 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
array_add(ops, i->SliceBoundsCheck.low);
array_add(ops, i->SliceBoundsCheck.high);
break;
#endif
}
}
@@ -100,24 +100,24 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
void ir_opt_block_replace_pred(irBlock *b, irBlock *from, irBlock *to) {
for_array(i, b->preds) {
irBlock *pred = b->preds.e[i];
irBlock *pred = b->preds[i];
if (pred == from) {
b->preds.e[i] = to;
b->preds[i] = to;
}
}
}
void ir_opt_block_replace_succ(irBlock *b, irBlock *from, irBlock *to) {
for_array(i, b->succs) {
irBlock *succ = b->succs.e[i];
irBlock *succ = b->succs[i];
if (succ == from) {
b->succs.e[i] = to;
b->succs[i] = to;
}
}
}
bool ir_opt_block_has_phi(irBlock *b) {
return b->instrs.e[0]->Instr.kind == irInstr_Phi;
return b->instrs[0]->Instr.kind == irInstr_Phi;
}
@@ -129,10 +129,10 @@ bool ir_opt_block_has_phi(irBlock *b) {
irValueArray ir_get_block_phi_nodes(irBlock *b) {
irValueArray phis = {0};
Array<irValue *> ir_get_block_phi_nodes(irBlock *b) {
Array<irValue *> phis = {0};
for_array(i, b->instrs) {
irInstr *instr = &b->instrs.e[i]->Instr;
irInstr *instr = &b->instrs[i]->Instr;
if (instr->kind != irInstr_Phi) {
phis = b->instrs;
phis.count = i;
@@ -143,22 +143,22 @@ irValueArray ir_get_block_phi_nodes(irBlock *b) {
}
void ir_remove_pred(irBlock *b, irBlock *p) {
irValueArray phis = ir_get_block_phi_nodes(b);
Array<irValue *> phis = ir_get_block_phi_nodes(b);
isize i = 0;
for_array(j, b->preds) {
irBlock *pred = b->preds.e[j];
irBlock *pred = b->preds[j];
if (pred != p) {
b->preds.e[i] = b->preds.e[j];
b->preds[i] = b->preds[j];
for_array(k, phis) {
irInstrPhi *phi = &phis.e[k]->Instr.Phi;
phi->edges.e[i] = phi->edges.e[j];
irInstrPhi *phi = &phis[k]->Instr.Phi;
phi->edges[i] = phi->edges[j];
}
i++;
}
}
b->preds.count = i;
for_array(k, phis) {
irInstrPhi *phi = &phis.e[k]->Instr.Phi;
irInstrPhi *phi = &phis[k]->Instr.Phi;
phi->edges.count = i;
}
@@ -167,13 +167,13 @@ void ir_remove_pred(irBlock *b, irBlock *p) {
void ir_remove_dead_blocks(irProcedure *proc) {
isize j = 0;
for_array(i, proc->blocks) {
irBlock *b = proc->blocks.e[i];
irBlock *b = proc->blocks[i];
if (b == NULL) {
continue;
}
// NOTE(bill): Swap order
b->index = j;
proc->blocks.e[j++] = b;
proc->blocks[j++] = b;
}
proc->blocks.count = j;
}
@@ -183,7 +183,7 @@ void ir_mark_reachable(irBlock *b) {
isize const BLACK = -1;
b->index = BLACK;
for_array(i, b->succs) {
irBlock *succ = b->succs.e[i];
irBlock *succ = b->succs[i];
if (succ->index == WHITE) {
ir_mark_reachable(succ);
}
@@ -194,23 +194,23 @@ 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;
proc->blocks[i]->index = WHITE;
}
ir_mark_reachable(proc->blocks.e[0]);
ir_mark_reachable(proc->blocks[0]);
for_array(i, proc->blocks) {
irBlock *b = proc->blocks.e[i];
irBlock *b = proc->blocks[i];
if (b->index == WHITE) {
for_array(j, b->succs) {
irBlock *c = b->succs.e[j];
irBlock *c = b->succs[j];
if (c->index == BLACK) {
ir_remove_pred(c, b);
}
}
// NOTE(bill): Mark as empty but don't actually free it
// As it's been allocated with an arena
proc->blocks.e[i] = NULL;
proc->blocks[i] = NULL;
}
}
ir_remove_dead_blocks(proc);
@@ -220,7 +220,7 @@ bool ir_opt_block_fusion(irProcedure *proc, irBlock *a) {
if (a->succs.count != 1) {
return false;
}
irBlock *b = a->succs.e[0];
irBlock *b = a->succs[0];
if (b->preds.count != 1) {
return false;
}
@@ -231,21 +231,21 @@ bool ir_opt_block_fusion(irProcedure *proc, irBlock *a) {
array_pop(&a->instrs); // Remove branch at end
for_array(i, b->instrs) {
array_add(&a->instrs, b->instrs.e[i]);
ir_set_instr_parent(b->instrs.e[i], a);
array_add(&a->instrs, b->instrs[i]);
ir_set_instr_parent(b->instrs[i], a);
}
array_clear(&a->succs);
for_array(i, b->succs) {
array_add(&a->succs, b->succs.e[i]);
array_add(&a->succs, b->succs[i]);
}
// Fix preds links
for_array(i, b->succs) {
ir_opt_block_replace_pred(b->succs.e[i], b, a);
ir_opt_block_replace_pred(b->succs[i], b, a);
}
proc->blocks.e[b->index] = NULL;
proc->blocks[b->index] = NULL;
return true;
}
@@ -257,11 +257,11 @@ void ir_opt_blocks(irProcedure *proc) {
while (changed) {
changed = false;
for_array(i, proc->blocks) {
irBlock *b = proc->blocks.e[i];
irBlock *b = proc->blocks[i];
if (b == NULL) {
continue;
}
GB_ASSERT(b->index == i);
GB_ASSERT_MSG(b->index == i, "%d, %td", b->index, i);
if (ir_opt_block_fusion(proc, b)) {
changed = true;
@@ -276,20 +276,20 @@ void ir_opt_blocks(irProcedure *proc) {
void ir_opt_build_referrers(irProcedure *proc) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
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
Array<irValue *> ops = {0}; // NOTE(bill): Act as a buffer
array_init(&ops, proc->module->tmp_allocator, 64); // HACK(bill): This _could_ overflow the temp arena
for_array(i, proc->blocks) {
irBlock *b = proc->blocks.e[i];
irBlock *b = proc->blocks[i];
for_array(j, b->instrs) {
irValue *instr = b->instrs.e[j];
irValue *instr = b->instrs[j];
array_clear(&ops);
ir_opt_add_operands(&ops, &instr->Instr);
for_array(k, ops) {
irValue *op = ops.e[k];
irValue *op = ops[k];
if (op == NULL) {
continue;
}
irValueArray *refs = ir_value_referrers(op);
Array<irValue *> *refs = ir_value_referrers(op);
if (refs != NULL) {
array_add(refs, instr);
}
@@ -327,7 +327,7 @@ i32 ir_lt_depth_first_search(irLTState *lt, irBlock *p, i32 i, irBlock **preorde
lt->sdom[p->index] = p;
ir_lt_link(lt, NULL, p);
for_array(index, p->succs) {
irBlock *q = p->succs.e[index];
irBlock *q = p->succs[index];
if (lt->sdom[q->index] == NULL) {
lt->parent[q->index] = p;
i = ir_lt_depth_first_search(lt, q, i, preorder);
@@ -357,7 +357,7 @@ irDomPrePost ir_opt_number_dom_tree(irBlock *v, i32 pre, i32 post) {
v->dom.pre = pre++;
for_array(i, v->dom.children) {
result = ir_opt_number_dom_tree(v->dom.children.e[i], result.pre, result.post);
result = ir_opt_number_dom_tree(v->dom.children[i], result.pre, result.post);
}
v->dom.post = post++;
@@ -384,7 +384,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
irBlock **preorder = &buf[3*n];
irBlock **buckets = &buf[4*n];
irBlock *root = proc->blocks.e[0];
irBlock *root = proc->blocks[0];
// Step 1 - number vertices
i32 pre_num = ir_lt_depth_first_search(&lt, root, 0, preorder);
@@ -406,7 +406,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
// Step 2 - Compute all sdoms
lt.sdom[w->index] = lt.parent[w->index];
for_array(pred_index, w->preds) {
irBlock *v = w->preds.e[pred_index];
irBlock *v = w->preds[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];
@@ -441,7 +441,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
}
// Calculate children relation as inverse of idom
if (w->dom.idom->dom.children.e == NULL) {
if (w->dom.idom->dom.children.data == NULL) {
// TODO(bill): Is this good enough for memory allocations?
array_init(&w->dom.idom->dom.children, heap_allocator());
}
@@ -464,13 +464,13 @@ void ir_opt_tree(irGen *s) {
s->opt_called = true;
for_array(member_index, s->module.procs) {
irProcedure *proc = s->module.procs.e[member_index];
irProcedure *proc = s->module.procs[member_index];
if (proc->blocks.count == 0) { // Prototype/external procedure
continue;
}
ir_opt_blocks(proc);
#if 1
#if 0
ir_opt_build_referrers(proc);
ir_opt_build_dom_tree(proc);
File diff suppressed because it is too large Load Diff
-285
View File
@@ -1,285 +0,0 @@
#if defined(__cplusplus)
extern "C" {
#endif
#include "common.c"
#include "timings.c"
#include "unicode.c"
#include "build.c"
#include "tokenizer.c"
#include "parser.c"
// #include "printer.c"
#include "checker/checker.c"
// #include "ssa.c"
#include "ir.c"
#include "ir_opt.c"
#include "ir_print.c"
// #include "vm.c"
// NOTE(bill): `name` is used in debugging and profiling modes
i32 win32_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};
isize cmd_len;
va_list va;
gbTempArenaMemory tmp;
String16 cmd;
i32 exit_code = 0;
start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
start_info.wShowWindow = SW_SHOW;
start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
start_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
va_start(va, fmt);
cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
va_end(va);
// gb_printf("%.*s\n", cast(int)cmd_len, cmd_line);
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1));
if (CreateProcessW(NULL, cmd.text,
NULL, NULL, true, 0, NULL, NULL,
&start_info, &pi)) {
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
} else {
// NOTE(bill): failed to create process
gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
exit_code = -1;
}
gb_temp_arena_memory_end(tmp);
return exit_code;
}
void print_usage_line(i32 indent, char *fmt, ...) {
while (indent --> 0) {
gb_printf_err("\t");
}
va_list va;
va_start(va, fmt);
gb_printf_err_va(fmt, va);
va_end(va);
gb_printf_err("\n");
}
void usage(char *argv0) {
print_usage_line(0, "%s is a tool for managing Odin source code", argv0);
print_usage_line(0, "Usage:");
print_usage_line(1, "%s command [arguments]", argv0);
print_usage_line(0, "Commands:");
print_usage_line(1, "build compile .odin file as executable");
print_usage_line(1, "build_dll compile .odin file as dll");
print_usage_line(1, "run compile and run .odin file");
print_usage_line(1, "version print version");
}
int main(int argc, char **argv) {
if (argc < 2) {
usage(argv[0]);
return 1;
}
Timings timings = {0};
timings_init(&timings, str_lit("Total Time"), 128);
// defer (timings_destroy(&timings));
init_string_buffer_memory();
init_global_error_collector();
#if 1
BuildContext build_context = {0};
init_build_context(&build_context);
init_universal_scope(&build_context);
char *init_filename = NULL;
bool run_output = false;
String arg1 = make_string_c(argv[1]);
if (str_eq(arg1, str_lit("run"))) {
if (argc != 3) {
usage(argv[0]);
return 1;
}
init_filename = argv[2];
run_output = true;
} else if (str_eq(arg1, str_lit("build_dll"))) {
if (argc != 3) {
usage(argv[0]);
return 1;
}
init_filename = argv[2];
build_context.is_dll = true;
} else if (str_eq(arg1, str_lit("build"))) {
if (argc != 3) {
usage(argv[0]);
return 1;
}
init_filename = argv[2];
} else if (str_eq(arg1, str_lit("version"))) {
gb_printf("%s version %.*s", argv[0], LIT(build_context.ODIN_VERSION));
return 0;
} else {
usage(argv[0]);
return 1;
}
// TODO(bill): prevent compiling without a linker
timings_start_section(&timings, str_lit("parse files"));
Parser parser = {0};
if (!init_parser(&parser)) {
return 1;
}
// defer (destroy_parser(&parser));
if (parse_files(&parser, init_filename) != ParseFile_None) {
return 1;
}
#if 1
timings_start_section(&timings, str_lit("type check"));
Checker checker = {0};
init_checker(&checker, &parser, &build_context);
// defer (destroy_checker(&checker));
check_parsed_files(&checker);
#endif
#if 0
if (global_error_collector.count != 0) {
return 1;
}
if (checker.parser->total_token_count < 2) {
return 1;
}
ssa_generate(&checker.info, &build_context);
#endif
#if 1
irGen ir_gen = {0};
if (!ir_gen_init(&ir_gen, &checker, &build_context)) {
return 1;
}
// defer (ssa_gen_destroy(&ir_gen));
timings_start_section(&timings, str_lit("llvm ir gen"));
ir_gen_tree(&ir_gen);
timings_start_section(&timings, str_lit("llvm ir opt tree"));
ir_opt_tree(&ir_gen);
timings_start_section(&timings, str_lit("llvm ir print"));
print_llvm_ir(&ir_gen);
// prof_print_all();
#if 1
timings_start_section(&timings, str_lit("llvm-opt"));
char const *output_name = ir_gen.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);
i32 optimization_level = 0;
optimization_level = gb_clamp(optimization_level, 0, 3);
i32 exit_code = 0;
// 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 "
"-mem2reg "
"-memcpyopt "
"-die "
// "-dse "
// "-dce "
// "-S "
"",
LIT(build_context.ODIN_ROOT),
output_name, LIT(output));
if (exit_code != 0) {
return exit_code;
}
#if 1
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 "
"%.*s "
// "-debug-pass=Arguments "
"",
LIT(build_context.ODIN_ROOT),
LIT(output),
optimization_level,
LIT(build_context.llc_flags));
if (exit_code != 0) {
return exit_code;
}
timings_start_section(&timings, str_lit("msvc-link"));
gbString lib_str = gb_string_make(heap_allocator(), "Kernel32.lib");
// 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];
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" %.*s.lib", LIT(lib));
lib_str = gb_string_appendc(lib_str, lib_str_buf);
}
char *output_ext = "exe";
char *link_settings = "";
if (build_context.is_dll) {
output_ext = "dll";
link_settings = "/DLL";
}
exit_code = win32_exec_command_line_app("msvc-link", true,
"link %.*s.obj -OUT:%.*s.%s %s "
"/defaultlib:libcmt "
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
" %.*s "
" %s "
"",
LIT(output), LIT(output), 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) {
win32_exec_command_line_app("odin run", false, "%.*s.exe", cast(int)base_name_len, output_name);
}
#endif
#endif
#endif
#endif
return 0;
}
#if defined(__cplusplus)
}
#endif
+679
View File
@@ -0,0 +1,679 @@
#define USE_CUSTOM_BACKEND 0
// #define PRINT_TIMINGS
#include "common.cpp"
#include "timings.cpp"
#include "build_settings.cpp"
#include "tokenizer.cpp"
#include "parser.cpp"
#include "docs.cpp"
#include "checker.cpp"
#include "ssa.cpp"
#include "ir.cpp"
#include "ir_opt.cpp"
#include "ir_print.cpp"
#if defined(GB_SYSTEM_WINDOWS)
// NOTE(bill): `name` is used in debugging and profiling modes
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};
isize cmd_len;
va_list va;
gbTempArenaMemory tmp;
String16 cmd;
i32 exit_code = 0;
start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
start_info.wShowWindow = SW_SHOW;
start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
start_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
va_start(va, fmt);
cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
va_end(va);
// gb_printf_err("%.*s\n", cast(int)cmd_len, cmd_line);
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1));
if (CreateProcessW(NULL, cmd.text,
NULL, NULL, true, 0, NULL, NULL,
&start_info, &pi)) {
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
} else {
// NOTE(bill): failed to create process
gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
exit_code = -1;
}
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
Array<String> setup_args(int argc, char **argv) {
Array<String> args = {};
gbAllocator a = heap_allocator();
int i;
#if defined(GB_SYSTEM_WINDOWS)
int wargc = 0;
wchar_t **wargv = command_line_to_wargv(GetCommandLineW(), &wargc);
array_init(&args, a, wargc);
for (i = 0; i < wargc; i++) {
wchar_t *warg = wargv[i];
isize wlen = string16_len(warg);
String16 wstr = make_string16(warg, wlen);
String arg = string16_to_string(a, wstr);
if (arg.len > 0) {
array_add(&args, arg);
}
}
#else
array_init(&args, a, argc);
for (i = 0; i < argc; i++) {
String arg = make_string_c(argv[i]);
if (arg.len > 0) {
array_add(&args, arg);
}
}
#endif
return args;
}
void print_usage_line(i32 indent, char *fmt, ...) {
while (indent --> 0) {
gb_printf_err("\t");
}
va_list va;
va_start(va, fmt);
gb_printf_err_va(fmt, va);
va_end(va);
gb_printf_err("\n");
}
void usage(String argv0) {
print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(argv0));
print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
print_usage_line(0, "Commands:");
print_usage_line(1, "build compile .odin file as executable");
print_usage_line(1, "build_dll compile .odin file as dll");
print_usage_line(1, "run compile and run .odin file");
print_usage_line(1, "docs generate documentation for a .odin file");
print_usage_line(1, "version print version");
}
enum BuildFlagKind {
BuildFlag_Invalid,
BuildFlag_OptimizationLevel,
BuildFlag_COUNT,
};
enum BuildFlagParamKind {
BuildFlagParam_None,
BuildFlagParam_Boolean,
BuildFlagParam_Integer,
BuildFlagParam_Float,
BuildFlagParam_String,
BuildFlagParam_COUNT,
};
struct BuildFlag {
BuildFlagKind kind;
String name;
BuildFlagParamKind param_kind;
};
void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind) {
BuildFlag flag = {kind, name, param_kind};
array_add(build_flags, flag);
}
bool parse_build_flags(Array<String> args) {
Array<BuildFlag> build_flags = {};
array_init(&build_flags, heap_allocator(), BuildFlag_COUNT);
add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer);
Array<String> flag_args = args;
flag_args.data += 3;
flag_args.count -= 3;
bool set_flags[BuildFlag_COUNT] = {};
bool bad_flags = false;
for_array(i, flag_args) {
String flag = flag_args[i];
if (flag[0] != '-') {
gb_printf_err("Invalid flag: %.*s\n", LIT(flag));
} else {
String name = substring(flag, 1, flag.len);
isize end = 0;
for (; end < name.len; end++) {
if (name[end] == '=') {
break;
}
}
name.len = end;
String param = substring(flag, 2+end, flag.len);
bool found = false;
for_array(build_flag_index, build_flags) {
BuildFlag bf = build_flags[build_flag_index];
if (bf.name == name) {
found = true;
if (set_flags[bf.kind]) {
gb_printf_err("Previous flag set: `%.*s`\n", LIT(name));
bad_flags = true;
} else {
ExactValue value = {};
bool ok = false;
if (bf.param_kind == BuildFlagParam_None) {
if (param.len == 0) {
ok = true;
} else {
gb_printf_err("Flag `%.*s` was not expecting a parameter `%.*s`\n", LIT(name), LIT(param));
bad_flags = true;
}
} else {
if (param.len == 0) {
gb_printf_err("Flag missing for `%.*s`\n", LIT(name));
bad_flags = true;
} else {
ok = true;
switch (bf.param_kind) {
default: ok = false; break;
case BuildFlagParam_Boolean: {
if (param == "t") {
value = exact_value_bool(true);
} else if (param == "T") {
value = exact_value_bool(true);
} else if (param == "true") {
value = exact_value_bool(true);
} else if (param == "TRUE") {
value = exact_value_bool(true);
} else if (param == "1") {
value = exact_value_bool(true);
} else if (param == "f") {
value = exact_value_bool(false);
} else if (param == "F") {
value = exact_value_bool(false);
} else if (param == "false") {
value = exact_value_bool(false);
} else if (param == "FALSE") {
value = exact_value_bool(false);
} else if (param == "0") {
value = exact_value_bool(false);
} else {
gb_printf_err("Invalid flag parameter for `%.*s` = `%.*s`\n", LIT(name), LIT(param));
}
} break;
case BuildFlagParam_Integer:
value = exact_value_integer_from_string(param);
break;
case BuildFlagParam_Float:
value = exact_value_float_from_string(param);
break;
case BuildFlagParam_String:
value = exact_value_string(param);
break;
}
}
}
if (ok) {
switch (bf.kind) {
case BuildFlag_OptimizationLevel:
if (value.kind == ExactValue_Integer) {
build_context.optimization_level = cast(i32)i128_to_i64(value.value_integer);
} else {
gb_printf_err("%.*s expected an integer, got %.*s", LIT(name), LIT(param));
bad_flags = true;
ok = false;
}
break;
}
}
set_flags[bf.kind] = ok;
}
break;
}
}
if (!found) {
gb_printf_err("Unknown flag: `%.*s`\n", LIT(name));
bad_flags = true;
}
}
}
return !bad_flags;
}
int main(int arg_count, char **arg_ptr) {
if (arg_count < 2) {
usage(make_string_c(arg_ptr[0]));
return 1;
}
Timings timings = {0};
timings_init(&timings, str_lit("Total Time"), 128);
defer (timings_destroy(&timings));
init_string_buffer_memory();
init_scratch_memory(gb_megabytes(10));
init_global_error_collector();
Array<String> args = setup_args(arg_count, arg_ptr);
#if 1
String init_filename = {};
bool run_output = false;
if (args[1] == "run") {
if (args.count < 3) {
usage(args[0]);
return 1;
}
init_filename = args[2];
run_output = true;
} else if (args[1] == "build_dll") {
if (args.count < 3) {
usage(args[0]);
return 1;
}
init_filename = args[2];
build_context.is_dll = true;
} else if (args[1] == "build") {
if (args.count < 3) {
usage(args[0]);
return 1;
}
init_filename = args[2];
} else if (args[1] == "docs") {
if (args.count < 3) {
usage(args[0]);
return 1;
}
init_filename = args[2];
build_context.generate_docs = true;
#if 1
print_usage_line(0, "Documentation generation is not yet supported");
return 1;
#endif
} else if (args[1] == "version") {
gb_printf("%s version %.*s\n", args[0], LIT(build_context.ODIN_VERSION));
return 0;
} else {
usage(args[0]);
return 1;
}
if (!parse_build_flags(args)) {
return 1;
}
init_build_context();
if (build_context.word_size == 4) {
print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
return 1;
}
init_universal_scope();
// TODO(bill): prevent compiling without a linker
timings_start_section(&timings, str_lit("parse files"));
Parser parser = {0};
if (!init_parser(&parser)) {
return 1;
}
defer (destroy_parser(&parser));
if (parse_files(&parser, init_filename) != ParseFile_None) {
return 1;
}
if (build_context.generate_docs) {
generate_documentation(&parser);
return 0;
}
#if 1
timings_start_section(&timings, str_lit("type check"));
Checker checker = {0};
init_checker(&checker, &parser);
defer (destroy_checker(&checker));
check_parsed_files(&checker);
#endif
#if defined(USE_CUSTOM_BACKEND) && USE_CUSTOM_BACKEND
if (global_error_collector.count != 0) {
return 1;
}
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 (ir_gen_destroy(&ir_gen));
timings_start_section(&timings, str_lit("llvm ir gen"));
ir_gen_tree(&ir_gen);
timings_start_section(&timings, str_lit("llvm ir opt tree"));
ir_opt_tree(&ir_gen);
timings_start_section(&timings, str_lit("llvm ir print"));
print_llvm_ir(&ir_gen);
// prof_print_all();
#if 1
timings_start_section(&timings, str_lit("llvm-opt"));
String output_name = ir_gen.output_name;
String output_base = ir_gen.output_base;
int base_name_len = output_base.len;
build_context.optimization_level = gb_clamp(build_context.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 = system_exec_command_line_app("llvm-opt", false,
"\"%.*sbin/opt\" \"%.*s\".ll -o \"%.*s\".bc %.*s "
"-mem2reg "
"-memcpyopt "
"-die "
"",
LIT(build_context.ODIN_ROOT),
LIT(output_base), LIT(output_base),
LIT(build_context.opt_flags));
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 %.*s "
"-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
"",
LIT(output_base), LIT(output_base),
LIT(build_context.opt_flags));
if (exit_code != 0) {
return exit_code;
}
#endif
#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 = 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_base),
build_context.optimization_level,
LIT(build_context.llc_flags));
if (exit_code != 0) {
return exit_code;
}
timings_start_section(&timings, str_lit("msvc-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[i];
// gb_printf_err("Linking lib: %.*s\n", LIT(lib));
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" \"%.*s\"", LIT(lib));
lib_str = gb_string_appendc(lib_str, lib_str_buf);
}
char *output_ext = "exe";
char *link_settings = "";
if (build_context.is_dll) {
output_ext = "dll";
link_settings = "/DLL";
} else {
link_settings = "/ENTRY:mainCRTStartup";
}
exit_code = system_exec_command_line_app("msvc-link", true,
"link \"%.*s\".obj -OUT:\"%.*s.%s\" %s "
"/defaultlib:libcmt "
// "/nodefaultlib "
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
" %.*s "
" %s "
"",
LIT(output_base), LIT(output_base), output_ext,
lib_str, LIT(build_context.link_flags),
link_settings
);
if (exit_code != 0) {
return exit_code;
}
#if defined(PRINT_TIMINGS)
timings_print_all(&timings);
#endif
if (run_output) {
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 -relocation-model=pic -O%d "
"%.*s "
// "-debug-pass=Arguments "
"",
LIT(output_base),
build_context.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[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[0] == '-' && lib[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;
}
#if defined(PRINT_TIMINGS)
timings_print_all(&timings);
#endif
if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base));
}
#endif
#endif
#endif
#endif
return 0;
}
-356
View File
@@ -1,356 +0,0 @@
/*
Example of usage:
#define MAP_TYPE String
#define MAP_PROC map_string_
#define MAP_NAME MapString
#include "map.c"
*/
#ifndef MAP_UTIL_STUFF
#define MAP_UTIL_STUFF
// NOTE(bill): This util stuff is the same for every `Map`
typedef struct MapFindResult {
isize hash_index;
isize entry_prev;
isize entry_index;
} MapFindResult;
typedef enum HashKeyKind {
HashKey_Default,
HashKey_String,
HashKey_Pointer,
} HashKeyKind;
typedef struct HashKey {
HashKeyKind kind;
u64 key;
union {
String string; // if String, s.len > 0
void * ptr;
};
} HashKey;
gb_inline HashKey hashing_proc(void const *data, isize len) {
HashKey h = {HashKey_Default};
h.kind = HashKey_Default;
// h.key = gb_murmur64(data, len);
h.key = gb_fnv64a(data, len);
return h;
}
gb_inline HashKey hash_string(String s) {
HashKey h = hashing_proc(s.text, s.len);
h.kind = HashKey_String;
h.string = s;
return h;
}
gb_inline HashKey hash_pointer(void *ptr) {
HashKey h = {HashKey_Default};
h.key = cast(u64)cast(uintptr)ptr;
h.ptr = ptr;
h.kind = HashKey_Default;
return h;
}
bool hash_key_equal(HashKey a, HashKey b) {
if (a.key == b.key) {
// NOTE(bill): If two string's hashes collide, compare the strings themselves
if (a.kind == HashKey_String) {
if (b.kind == HashKey_String) {
return str_eq(a.string, b.string);
}
return false;
}
return true;
}
return false;
}
#endif
#define _J2_IND(a, b) a##b
#define _J2(a, b) _J2_IND(a, b)
/*
MAP_TYPE - Entry type
MAP_PROC - Function prefix (e.g. entity_map_)
MAP_NAME - Name of Map (e.g. EntityMap)
*/
#define MAP_ENTRY _J2(MAP_NAME,Entry)
typedef struct MAP_ENTRY {
HashKey key;
isize next;
MAP_TYPE value;
} MAP_ENTRY;
typedef struct MAP_NAME {
Array(isize) hashes;
Array(MAP_ENTRY) entries;
} MAP_NAME;
void _J2(MAP_PROC,init) (MAP_NAME *h, gbAllocator a);
void _J2(MAP_PROC,init_with_reserve)(MAP_NAME *h, gbAllocator a, isize capacity);
void _J2(MAP_PROC,destroy) (MAP_NAME *h);
MAP_TYPE *_J2(MAP_PROC,get) (MAP_NAME *h, HashKey key);
void _J2(MAP_PROC,set) (MAP_NAME *h, HashKey key, MAP_TYPE value);
void _J2(MAP_PROC,remove) (MAP_NAME *h, HashKey key);
void _J2(MAP_PROC,clear) (MAP_NAME *h);
void _J2(MAP_PROC,grow) (MAP_NAME *h);
void _J2(MAP_PROC,rehash) (MAP_NAME *h, isize new_count);
// Mutlivalued map procedure
MAP_ENTRY *_J2(MAP_PROC,multi_find_first)(MAP_NAME *h, HashKey key);
MAP_ENTRY *_J2(MAP_PROC,multi_find_next) (MAP_NAME *h, MAP_ENTRY *e);
isize _J2(MAP_PROC,multi_count) (MAP_NAME *h, HashKey key);
void _J2(MAP_PROC,multi_get_all) (MAP_NAME *h, HashKey key, MAP_TYPE *items);
void _J2(MAP_PROC,multi_insert) (MAP_NAME *h, HashKey key, MAP_TYPE value);
void _J2(MAP_PROC,multi_remove) (MAP_NAME *h, HashKey key, MAP_ENTRY *e);
void _J2(MAP_PROC,multi_remove_all)(MAP_NAME *h, HashKey key);
gb_inline void _J2(MAP_PROC,init)(MAP_NAME *h, gbAllocator a) {
array_init(&h->hashes, a);
array_init(&h->entries, a);
}
gb_inline void _J2(MAP_PROC,init_with_reserve)(MAP_NAME *h, gbAllocator a, isize capacity) {
array_init_reserve(&h->hashes, a, capacity);
array_init_reserve(&h->entries, a, capacity);
}
gb_inline void _J2(MAP_PROC,destroy)(MAP_NAME *h) {
array_free(&h->entries);
array_free(&h->hashes);
}
gb_internal isize _J2(MAP_PROC,_add_entry)(MAP_NAME *h, HashKey key) {
MAP_ENTRY e = {0};
e.key = key;
e.next = -1;
array_add(&h->entries, e);
return h->entries.count-1;
}
gb_internal MapFindResult _J2(MAP_PROC,_find)(MAP_NAME *h, HashKey key) {
MapFindResult fr = {-1, -1, -1};
if (h->hashes.count > 0) {
fr.hash_index = key.key % h->hashes.count;
fr.entry_index = h->hashes.e[fr.hash_index];
while (fr.entry_index >= 0) {
if (hash_key_equal(h->entries.e[fr.entry_index].key, key)) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries.e[fr.entry_index].next;
}
}
return fr;
}
gb_internal MapFindResult _J2(MAP_PROC,_find_from_entry)(MAP_NAME *h, MAP_ENTRY *e) {
MapFindResult fr = {-1, -1, -1};
if (h->hashes.count > 0) {
fr.hash_index = e->key.key % h->hashes.count;
fr.entry_index = h->hashes.e[fr.hash_index];
while (fr.entry_index >= 0) {
if (&h->entries.e[fr.entry_index] == e) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries.e[fr.entry_index].next;
}
}
return fr;
}
gb_internal b32 _J2(MAP_PROC,_full)(MAP_NAME *h) {
return 0.75f * h->hashes.count <= h->entries.count;
}
gb_inline void _J2(MAP_PROC,grow)(MAP_NAME *h) {
isize new_count = ARRAY_GROW_FORMULA(h->entries.count);
_J2(MAP_PROC,rehash)(h, new_count);
}
void _J2(MAP_PROC,rehash)(MAP_NAME *h, isize new_count) {
isize i, j;
MAP_NAME nh = {0};
_J2(MAP_PROC,init)(&nh, h->hashes.allocator);
array_resize(&nh.hashes, new_count);
array_reserve(&nh.entries, h->entries.count);
for (i = 0; i < new_count; i++) {
nh.hashes.e[i] = -1;
}
for (i = 0; i < h->entries.count; i++) {
MAP_ENTRY *e = &h->entries.e[i];
MapFindResult fr;
if (nh.hashes.count == 0) {
_J2(MAP_PROC,grow)(&nh);
}
fr = _J2(MAP_PROC,_find)(&nh, e->key);
j = _J2(MAP_PROC,_add_entry)(&nh, e->key);
if (fr.entry_prev < 0) {
nh.hashes.e[fr.hash_index] = j;
} else {
nh.entries.e[fr.entry_prev].next = j;
}
nh.entries.e[j].next = fr.entry_index;
nh.entries.e[j].value = e->value;
if (_J2(MAP_PROC,_full)(&nh)) {
_J2(MAP_PROC,grow)(&nh);
}
}
_J2(MAP_PROC,destroy)(h);
*h = nh;
}
gb_inline MAP_TYPE *_J2(MAP_PROC,get)(MAP_NAME *h, HashKey key) {
isize index = _J2(MAP_PROC,_find)(h, key).entry_index;
if (index >= 0) {
return &h->entries.e[index].value;
}
return NULL;
}
void _J2(MAP_PROC,set)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
isize index;
MapFindResult fr;
if (h->hashes.count == 0)
_J2(MAP_PROC,grow)(h);
fr = _J2(MAP_PROC,_find)(h, key);
if (fr.entry_index >= 0) {
index = fr.entry_index;
} else {
index = _J2(MAP_PROC,_add_entry)(h, key);
if (fr.entry_prev >= 0) {
h->entries.e[fr.entry_prev].next = index;
} else {
h->hashes.e[fr.hash_index] = index;
}
}
h->entries.e[index].value = value;
if (_J2(MAP_PROC,_full)(h)) {
_J2(MAP_PROC,grow)(h);
}
}
void _J2(MAP_PROC,_erase)(MAP_NAME *h, MapFindResult fr) {
MapFindResult last;
if (fr.entry_prev < 0) {
h->hashes.e[fr.hash_index] = h->entries.e[fr.entry_index].next;
} else {
h->entries.e[fr.entry_prev].next = h->entries.e[fr.entry_index].next;
}
if (fr.entry_index == h->entries.count-1) {
array_pop(&h->entries);
return;
}
h->entries.e[fr.entry_index] = h->entries.e[h->entries.count-1];
last = _J2(MAP_PROC,_find)(h, h->entries.e[fr.entry_index].key);
if (last.entry_prev >= 0) {
h->entries.e[last.entry_prev].next = fr.entry_index;
} else {
h->hashes.e[last.hash_index] = fr.entry_index;
}
}
void _J2(MAP_PROC,remove)(MAP_NAME *h, HashKey key) {
MapFindResult fr = _J2(MAP_PROC,_find)(h, key);
if (fr.entry_index >= 0) {
_J2(MAP_PROC,_erase)(h, fr);
}
}
gb_inline void _J2(MAP_PROC,clear)(MAP_NAME *h) {
array_clear(&h->hashes);
array_clear(&h->entries);
}
#if 1
MAP_ENTRY *_J2(MAP_PROC,multi_find_first)(MAP_NAME *h, HashKey key) {
isize i = _J2(MAP_PROC,_find)(h, key).entry_index;
if (i < 0) {
return NULL;
}
return &h->entries.e[i];
}
MAP_ENTRY *_J2(MAP_PROC,multi_find_next)(MAP_NAME *h, MAP_ENTRY *e) {
isize i = e->next;
while (i >= 0) {
if (hash_key_equal(h->entries.e[i].key, e->key)) {
return &h->entries.e[i];
}
i = h->entries.e[i].next;
}
return NULL;
}
isize _J2(MAP_PROC,multi_count)(MAP_NAME *h, HashKey key) {
isize count = 0;
MAP_ENTRY *e = _J2(MAP_PROC,multi_find_first)(h, key);
while (e != NULL) {
count++;
e = _J2(MAP_PROC,multi_find_next)(h, e);
}
return count;
}
void _J2(MAP_PROC,multi_get_all)(MAP_NAME *h, HashKey key, MAP_TYPE *items) {
isize i = 0;
MAP_ENTRY *e = _J2(MAP_PROC,multi_find_first)(h, key);
while (e != NULL) {
items[i++] = e->value;
e = _J2(MAP_PROC,multi_find_next)(h, e);
}
}
void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
MapFindResult fr;
isize i;
if (h->hashes.count == 0) {
_J2(MAP_PROC,grow)(h);
}
fr = _J2(MAP_PROC,_find)(h, key);
i = _J2(MAP_PROC,_add_entry)(h, key);
if (fr.entry_prev < 0) {
h->hashes.e[fr.hash_index] = i;
} else {
h->entries.e[fr.entry_prev].next = i;
}
h->entries.e[i].next = fr.entry_index;
h->entries.e[i].value = value;
if (_J2(MAP_PROC,_full)(h)) {
_J2(MAP_PROC,grow)(h);
}
}
void _J2(MAP_PROC,multi_remove)(MAP_NAME *h, HashKey key, MAP_ENTRY *e) {
MapFindResult fr = _J2(MAP_PROC,_find_from_entry)(h, e);
if (fr.entry_index >= 0) {
_J2(MAP_PROC,_erase)(h, fr);
}
}
void _J2(MAP_PROC,multi_remove_all)(MAP_NAME *h, HashKey key) {
while (_J2(MAP_PROC,get)(h, key) != NULL) {
_J2(MAP_PROC,remove)(h, key);
}
}
#endif
#undef _J2
#undef MAP_TYPE
#undef MAP_PROC
#undef MAP_NAME
#undef MAP_ENTRY
+381
View File
@@ -0,0 +1,381 @@
// 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_map_*` stuff to be #ifdefed out
#ifndef MAP_UTIL_STUFF
#define MAP_UTIL_STUFF
// NOTE(bill): This util stuff is the same for every `Map`
struct MapFindResult {
isize hash_index;
isize entry_prev;
isize entry_index;
};
enum HashKeyKind {
HashKey_Default,
HashKey_String,
HashKey_Ptr,
HashKey_PtrAndId,
};
struct PtrAndId {
void *ptr;
u32 id;
};
struct HashKey {
HashKeyKind kind;
// u128 key;
u64 key;
union {
String string; // if String, s.len > 0
void * ptr;
PtrAndId ptr_and_id;
};
};
gb_inline HashKey hashing_proc(void const *data, isize len) {
HashKey h = {HashKey_Default};
h.kind = HashKey_Default;
// h.key = u128_from_u64(gb_fnv64a(data, len));
h.key = gb_fnv64a(data, len);
return h;
}
gb_inline HashKey hash_string(String s) {
HashKey h = hashing_proc(s.text, s.len);
h.kind = HashKey_String;
h.string = s;
return h;
}
gb_inline HashKey hash_pointer(void *ptr) {
HashKey h = {HashKey_Ptr};
h.key = cast(u64)cast(uintptr)ptr;
h.ptr = ptr;
return h;
}
gb_inline HashKey hash_ptr_and_id(void *ptr, u32 id) {
HashKey h = {HashKey_PtrAndId};
h.key = cast(u64)cast(uintptr)ptr;
h.ptr_and_id.ptr = ptr;
h.ptr_and_id.id = id;
return h;
}
bool hash_key_equal(HashKey a, HashKey b) {
if (a.key == b.key) {
// NOTE(bill): If two string's hashes collide, compare the strings themselves
if (a.kind == HashKey_String) {
if (b.kind == HashKey_String) {
return a.string == b.string;
}
return false;
} else if (a.kind == HashKey_PtrAndId) {
if (b.kind == HashKey_PtrAndId) {
return a.ptr_and_id.id == b.ptr_and_id.id;
}
return false;
}
return true;
}
return false;
}
bool operator==(HashKey a, HashKey b) { return hash_key_equal(a, b); }
bool operator!=(HashKey a, HashKey b) { return !hash_key_equal(a, b); }
#endif
template <typename T>
struct MapEntry {
HashKey key;
isize next;
T value;
};
template <typename T>
struct Map {
Array<isize> hashes;
Array<MapEntry<T> > entries;
};
template <typename T> void map_init (Map<T> *h, gbAllocator a);
template <typename T> void map_init_with_reserve(Map<T> *h, gbAllocator a, isize capacity);
template <typename T> void map_destroy (Map<T> *h);
template <typename T> T * map_get (Map<T> *h, HashKey key);
template <typename T> void map_set (Map<T> *h, HashKey key, T const &value);
template <typename T> void map_remove (Map<T> *h, HashKey key);
template <typename T> void map_clear (Map<T> *h);
template <typename T> void map_grow (Map<T> *h);
template <typename T> void map_rehash (Map<T> *h, isize new_count);
// Mutlivalued map procedure
template <typename T> MapEntry<T> * multi_map_find_first(Map<T> *h, HashKey key);
template <typename T> MapEntry<T> * multi_map_find_next (Map<T> *h, MapEntry<T> *e);
template <typename T> isize multi_map_count (Map<T> *h, HashKey key);
template <typename T> void multi_map_get_all (Map<T> *h, HashKey key, T *items);
template <typename T> void multi_map_insert (Map<T> *h, HashKey key, T const &value);
template <typename T> void multi_map_remove (Map<T> *h, HashKey key, MapEntry<T> *e);
template <typename T> void multi_map_remove_all(Map<T> *h, HashKey key);
template <typename T>
gb_inline void map_init(Map<T> *h, gbAllocator a) {
array_init(&h->hashes, a);
array_init(&h->entries, a);
}
template <typename T>
gb_inline void map_init_with_reserve(Map<T> *h, gbAllocator a, isize capacity) {
array_init(&h->hashes, a, capacity);
array_init(&h->entries, a, capacity);
}
template <typename T>
gb_inline void map_destroy(Map<T> *h) {
array_free(&h->entries);
array_free(&h->hashes);
}
template <typename T>
gb_internal isize map__add_entry(Map<T> *h, HashKey key) {
MapEntry<T> e = {};
e.key = key;
e.next = -1;
array_add(&h->entries, e);
return h->entries.count-1;
}
template <typename T>
gb_internal MapFindResult map__find(Map<T> *h, HashKey key) {
MapFindResult fr = {-1, -1, -1};
if (h->hashes.count > 0) {
// fr.hash_index = u128_to_i64(key.key % u128_from_i64(h->hashes.count));
fr.hash_index = key.key % h->hashes.count;
fr.entry_index = h->hashes[fr.hash_index];
while (fr.entry_index >= 0) {
if (hash_key_equal(h->entries[fr.entry_index].key, key)) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries[fr.entry_index].next;
}
}
return fr;
}
template <typename T>
gb_internal MapFindResult map__find_from_entry(Map<T> *h, MapEntry<T> *e) {
MapFindResult fr = {-1, -1, -1};
if (h->hashes.count > 0) {
fr.hash_index = e->key.key % h->hashes.count;
fr.entry_index = h->hashes[fr.hash_index];
while (fr.entry_index >= 0) {
if (&h->entries[fr.entry_index] == e) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries[fr.entry_index].next;
}
}
return fr;
}
template <typename T>
gb_internal b32 map__full(Map<T> *h) {
return 0.75f * h->hashes.count <= h->entries.count;
}
template <typename T>
gb_inline void map_grow(Map<T> *h) {
isize new_count = ARRAY_GROW_FORMULA(h->entries.count);
map_rehash(h, new_count);
}
template <typename T>
void map_rehash(Map<T> *h, isize new_count) {
isize i, j;
Map<T> nh = {};
map_init(&nh, h->hashes.allocator);
array_resize(&nh.hashes, new_count);
array_reserve(&nh.entries, h->entries.count);
for (i = 0; i < new_count; i++) {
nh.hashes[i] = -1;
}
for (i = 0; i < h->entries.count; i++) {
MapEntry<T> *e = &h->entries[i];
MapFindResult fr;
if (nh.hashes.count == 0) {
map_grow(&nh);
}
fr = map__find(&nh, e->key);
j = map__add_entry(&nh, e->key);
if (fr.entry_prev < 0) {
nh.hashes[fr.hash_index] = j;
} else {
nh.entries[fr.entry_prev].next = j;
}
nh.entries[j].next = fr.entry_index;
nh.entries[j].value = e->value;
if (map__full(&nh)) {
map_grow(&nh);
}
}
map_destroy(h);
*h = nh;
}
template <typename T>
gb_inline T *map_get(Map<T> *h, HashKey key) {
isize index = map__find(h, key).entry_index;
if (index >= 0) {
return &h->entries[index].value;
}
return NULL;
}
template <typename T>
void map_set(Map<T> *h, HashKey key, T const &value) {
isize index;
MapFindResult fr;
if (h->hashes.count == 0)
map_grow(h);
fr = map__find(h, key);
if (fr.entry_index >= 0) {
index = fr.entry_index;
} else {
index = map__add_entry(h, key);
if (fr.entry_prev >= 0) {
h->entries[fr.entry_prev].next = index;
} else {
h->hashes[fr.hash_index] = index;
}
}
h->entries[index].value = value;
if (map__full(h)) {
map_grow(h);
}
}
template <typename T>
void map__erase(Map<T> *h, MapFindResult fr) {
MapFindResult last;
if (fr.entry_prev < 0) {
h->hashes[fr.hash_index] = h->entries[fr.entry_index].next;
} else {
h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next;
}
if (fr.entry_index == h->entries.count-1) {
array_pop(&h->entries);
return;
}
h->entries[fr.entry_index] = h->entries[h->entries.count-1];
last = map__find(h, h->entries[fr.entry_index].key);
if (last.entry_prev >= 0) {
h->entries[last.entry_prev].next = fr.entry_index;
} else {
h->hashes[last.hash_index] = fr.entry_index;
}
}
template <typename T>
void map_remove(Map<T> *h, HashKey key) {
MapFindResult fr = map__find(h, key);
if (fr.entry_index >= 0) {
map__erase(h, fr);
}
}
template <typename T>
gb_inline void map_clear(Map<T> *h) {
array_clear(&h->hashes);
array_clear(&h->entries);
}
#if 1
template <typename T>
MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey key) {
isize i = map__find(h, key).entry_index;
if (i < 0) {
return NULL;
}
return &h->entries[i];
}
template <typename T>
MapEntry<T> *multi_map_find_next(Map<T> *h, MapEntry<T> *e) {
isize i = e->next;
while (i >= 0) {
if (hash_key_equal(h->entries[i].key, e->key)) {
return &h->entries[i];
}
i = h->entries[i].next;
}
return NULL;
}
template <typename T>
isize multi_map_count(Map<T> *h, HashKey key) {
isize count = 0;
MapEntry<T> *e = multi_map_find_first(h, key);
while (e != NULL) {
count++;
e = multi_map_find_next(h, e);
}
return count;
}
template <typename T>
void multi_map_get_all(Map<T> *h, HashKey key, T *items) {
isize i = 0;
MapEntry<T> *e = multi_map_find_first(h, key);
while (e != NULL) {
items[i++] = e->value;
e = multi_map_find_next(h, e);
}
}
template <typename T>
void multi_map_insert(Map<T> *h, HashKey key, T const &value) {
MapFindResult fr;
isize i;
if (h->hashes.count == 0) {
map_grow(h);
}
// Make
fr = map__find(h, key);
i = map__add_entry(h, key);
if (fr.entry_prev < 0) {
h->hashes[fr.hash_index] = i;
} else {
h->entries[fr.entry_prev].next = i;
}
h->entries[i].next = fr.entry_index;
h->entries[i].value = value;
// Grow if needed
if (map__full(h)) {
map_grow(h);
}
}
template <typename T>
void multi_map_remove(Map<T> *h, HashKey key, MapEntry<T> *e) {
MapFindResult fr = map__find_from_entry(h, e);
if (fr.entry_index >= 0) {
map__erase(h, fr);
}
}
template <typename T>
void multi_map_remove_all(Map<T> *h, HashKey key) {
while (map_get(h, key) != NULL) {
map_remove(h, key);
}
}
#endif
+225
View File
@@ -0,0 +1,225 @@
//-----------------------------------------------------------------------------
// MurmurHash3 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.
// Note - The x86 and x64 versions do _not_ produce the same results, as the
// algorithms are optimized for their respective platforms. You can still
// compile and run any of them on any platform, but your performance with the
// non-native version will be less than optimal.
#if defined(_MSC_VER)
#define ROTL32(x,y) _rotl(x,y)
#define ROTL64(x,y) _rotl64(x,y)
#else
gb_inline u32 rotl32(u32 x, i8 r) {
return (x << r) | (x >> (32-r));
}
gb_inline u64 rotl64(u64 x, i8 r) {
return (x << r) | (x >> (64-r));
}
#define ROTL32(x,y) rotl32(x,y)
#define ROTL64(x,y) rotl64(x,y)
#endif
gb_inline u32 fmix32(u32 h) {
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
gb_inline u64 fmix64(u64 k) {
k ^= k >> 33;
k *= 0xff51afd7ed558ccdULL;
k ^= k >> 33;
k *= 0xc4ceb9fe1a85ec53ULL;
k ^= k >> 33;
return k;
}
gb_inline u32 mm3_getblock32(u32 const *p, isize i) {
return p[i];
}
gb_inline u64 mm3_getblock64(u64 const *p, isize i) {
return p[i];
}
void MurmurHash3_x64_128(void const *key, isize len, u32 seed, void *out) {
u8 const * data = cast(u8 const *)key;
isize nblocks = len / 16;
u64 h1 = seed;
u64 h2 = seed;
u64 const c1 = 0x87c37b91114253d5ULL;
u64 const c2 = 0x4cf5ad432745937fULL;
u64 const * blocks = cast(u64 const *)data;
for (isize i = 0; i < nblocks; i++) {
u64 k1 = mm3_getblock64(blocks, i*2 + 0);
u64 k2 = mm3_getblock64(blocks, i*2 + 1);
k1 *= c1; k1 = ROTL64(k1, 31); k1 *= c2; h1 ^= k1;
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
}
u8 const * tail = cast(u8 const *)(data + nblocks*16);
u64 k1 = 0;
u64 k2 = 0;
switch(len & 15) {
case 15: k2 ^= ((u64)tail[14]) << 48;
case 14: k2 ^= ((u64)tail[13]) << 40;
case 13: k2 ^= ((u64)tail[12]) << 32;
case 12: k2 ^= ((u64)tail[11]) << 24;
case 11: k2 ^= ((u64)tail[10]) << 16;
case 10: k2 ^= ((u64)tail[ 9]) << 8;
case 9: k2 ^= ((u64)tail[ 8]) << 0;
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
case 8: k1 ^= ((u64)tail[ 7]) << 56;
case 7: k1 ^= ((u64)tail[ 6]) << 48;
case 6: k1 ^= ((u64)tail[ 5]) << 40;
case 5: k1 ^= ((u64)tail[ 4]) << 32;
case 4: k1 ^= ((u64)tail[ 3]) << 24;
case 3: k1 ^= ((u64)tail[ 2]) << 16;
case 2: k1 ^= ((u64)tail[ 1]) << 8;
case 1: k1 ^= ((u64)tail[ 0]) << 0;
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
}
h1 ^= len;
h2 ^= len;
h1 += h2;
h2 += h1;
h1 = fmix64(h1);
h2 = fmix64(h2);
h1 += h2;
h2 += h1;
((u64 *)out)[0] = h1;
((u64 *)out)[1] = h2;
}
void MurmurHash3_x86_128(void const *key, isize len, u32 seed, void *out) {
u8 const * data = cast(u8 * const)key;
isize nblocks = len / 16;
u32 h1 = seed;
u32 h2 = seed;
u32 h3 = seed;
u32 h4 = seed;
u32 const c1 = 0x239b961b;
u32 const c2 = 0xab0e9789;
u32 const c3 = 0x38b34ae5;
u32 const c4 = 0xa1e38b93;
//----------
// body
u32 const * blocks = cast(u32 const *)(data + nblocks*16);
for (isize i = -nblocks; i != 0; i++) {
u32 k1 = mm3_getblock32(blocks, i*4 + 0);
u32 k2 = mm3_getblock32(blocks, i*4 + 1);
u32 k3 = mm3_getblock32(blocks, i*4 + 2);
u32 k4 = mm3_getblock32(blocks, i*4 + 3);
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
}
//----------
// tail
u8 const * tail = cast(u8 const *)(data + nblocks*16);
u32 k1 = 0;
u32 k2 = 0;
u32 k3 = 0;
u32 k4 = 0;
switch(len & 15) {
case 15: k4 ^= tail[14] << 16;
case 14: k4 ^= tail[13] << 8;
case 13: k4 ^= tail[12] << 0;
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
case 12: k3 ^= tail[11] << 24;
case 11: k3 ^= tail[10] << 16;
case 10: k3 ^= tail[ 9] << 8;
case 9: k3 ^= tail[ 8] << 0;
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
case 8: k2 ^= tail[ 7] << 24;
case 7: k2 ^= tail[ 6] << 16;
case 6: k2 ^= tail[ 5] << 8;
case 5: k2 ^= tail[ 4] << 0;
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
case 4: k1 ^= tail[ 3] << 24;
case 3: k1 ^= tail[ 2] << 16;
case 2: k1 ^= tail[ 1] << 8;
case 1: k1 ^= tail[ 0] << 0;
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
};
//----------
// finalization
h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
h1 += h2; h1 += h3; h1 += h4;
h2 += h1; h3 += h1; h4 += h1;
h1 = fmix32(h1);
h2 = fmix32(h2);
h3 = fmix32(h3);
h4 = fmix32(h4);
h1 += h2; h1 += h3; h1 += h4;
h2 += h1; h3 += h1; h4 += h1;
((u32 *)out)[0] = h1;
((u32 *)out)[1] = h2;
((u32 *)out)[2] = h3;
((u32 *)out)[3] = h4;
}
gb_inline u128 MurmurHash3_128(void const *key, isize len, u32 seed) {
u128 res;
#if defined(GB_ARCH_64_BIT)
MurmurHash3_x64_128(key, len, seed, &res);
#else
MurmurHash3_x86_128(key, len, seed, &res);
#endif
return res;
}
-1305
View File
File diff suppressed because it is too large Load Diff
-3484
View File
File diff suppressed because it is too large Load Diff
+4784
View File
File diff suppressed because it is too large Load Diff
View File
+2575
View File
File diff suppressed because it is too large Load Diff
+275
View File
@@ -0,0 +1,275 @@
#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
};
String const ssa_op_strings[] = {
#define SSA_OP(k) {cast(u8 *)#k, gb_size_of(#k)-1},
SSA_OPS
#undef SSA_OP
};
+176 -45
View File
@@ -1,5 +1,5 @@
gb_global gbArena string_buffer_arena = {0};
gb_global gbAllocator string_buffer_allocator = {0};
gb_global gbArena string_buffer_arena = {};
gb_global gbAllocator string_buffer_allocator = {};
void init_string_buffer_memory(void) {
// NOTE(bill): This should be enough memory for file systems
@@ -9,18 +9,41 @@ void init_string_buffer_memory(void) {
// NOTE(bill): Used for UTF-8 strings
typedef struct String {
struct String {
u8 * text;
isize len;
} String;
u8 &operator[](isize i) {
GB_ASSERT(0 <= i && i < len);
return text[i];
}
u8 const &operator[](isize i) const {
GB_ASSERT(0 <= i && i < len);
return text[i];
}
};
// 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}
#if defined(GB_COMPILER_MSVC) && _MSC_VER < 1700
#define str_lit(c_str) make_string(cast(u8 *)c_str, gb_size_of(c_str)-1)
#else
#define str_lit(c_str) String{cast(u8 *)c_str, gb_size_of(c_str)-1}
#endif
typedef struct String16 {
// NOTE(bill): String16 is only used for Windows due to its file directories
struct String16 {
wchar_t *text;
isize len;
} String16;
wchar_t &operator[](isize i) {
GB_ASSERT(0 <= i && i < len);
return text[i];
}
wchar_t const &operator[](isize i) const {
GB_ASSERT(0 <= i && i < len);
return text[i];
}
};
gb_inline String make_string(u8 *text, isize len) {
@@ -41,12 +64,29 @@ gb_inline String16 make_string16(wchar_t *text, isize len) {
return s;
}
isize string16_len(wchar_t *s) {
if (s == NULL) {
return 0;
}
wchar_t *p = s;
while (*p) {
p++;
}
return p - s;
}
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)
String substring(String s, isize lo, isize hi) {
isize max = s.len;
GB_ASSERT(lo <= hi && hi <= max);
return make_string(s.text+lo, hi-lo);
}
@@ -54,8 +94,8 @@ gb_inline bool str_eq_ignore_case(String a, String b) {
if (a.len == b.len) {
isize i;
for (i = 0; i < a.len; i++) {
char x = cast(char)a.text[i];
char y = cast(char)b.text[i];
char x = cast(char)a[i];
char y = cast(char)b[i];
if (gb_char_to_lower(x) != gb_char_to_lower(y))
return false;
}
@@ -86,16 +126,16 @@ int string_compare(String x, String y) {
for (; curr_block < fast; curr_block++) {
if (la[curr_block] ^ lb[curr_block]) {
for (pos = curr_block*gb_size_of(isize); pos < n; pos++) {
if (x.text[pos] ^ y.text[pos]) {
return cast(int)x.text[pos] - cast(int)y.text[pos];
if (x[pos] ^ y[pos]) {
return cast(int)x[pos] - cast(int)y[pos];
}
}
}
}
for (; offset < n; offset++) {
if (x.text[offset] ^ y.text[offset]) {
return cast(int)x.text[offset] - cast(int)y.text[offset];
if (x[offset] ^ y[offset]) {
return cast(int)x[offset] - cast(int)y[offset];
}
}
}
@@ -115,13 +155,29 @@ gb_inline bool str_gt(String a, String b) { return string_compare(a, b) > 0;
gb_inline bool str_le(String a, String b) { return string_compare(a, b) <= 0; }
gb_inline bool str_ge(String a, String b) { return string_compare(a, b) >= 0; }
bool operator == (String a, String b) { return str_eq(a, b); }
bool operator != (String a, String b) { return str_ne(a, b); }
bool operator < (String a, String b) { return str_lt(a, b); }
bool operator > (String a, String b) { return str_gt(a, b); }
bool operator <= (String a, String b) { return str_le(a, b); }
bool operator >= (String a, String b) { return str_ge(a, b); }
template <isize N> bool operator == (String a, char const (&b)[N]) { return str_eq(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator != (String a, char const (&b)[N]) { return str_ne(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator < (String a, char const (&b)[N]) { return str_lt(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator > (String a, char const (&b)[N]) { return str_gt(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator <= (String a, char const (&b)[N]) { return str_le(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator >= (String a, char const (&b)[N]) { return str_ge(a, make_string(cast(u8 *)b, N-1)); }
gb_inline bool str_has_prefix(String s, String prefix) {
isize i;
if (prefix.len < s.len) {
return false;
}
for (i = 0; i < prefix.len; i++) {
if (s.text[i] != prefix.text[i]) {
if (s[i] != prefix[i]) {
return false;
}
}
@@ -133,9 +189,9 @@ gb_inline isize string_extension_position(String str) {
isize i = str.len;
bool seen_dot = false;
while (i --> 0) {
if (str.text[i] == GB_PATH_SEPARATOR)
if (str[i] == GB_PATH_SEPARATOR)
break;
if (str.text[i] == '.') {
if (str[i] == '.') {
dot_pos = i;
break;
}
@@ -144,27 +200,105 @@ 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[str.len-1])) {
str.len--;
}
while (str.len > 0 && rune_is_whitespace(str[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[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) {
isize i;
for (i = 0; i < s.len; i++) {
if (s.text[i] == c)
if (s[i] == c)
return true;
}
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[j] == '/' ||
s[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 +308,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);
@@ -193,6 +325,7 @@ String16 string_to_string16(gbAllocator a, String s) {
return make_string16(text, len-1);
}
String string16_to_string(gbAllocator a, String16 s) {
int len, len1;
u8 *text;
@@ -201,16 +334,15 @@ 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);
}
len += 1; // NOTE(bill): It needs an extra 1 for some reason
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,22 +368,21 @@ 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;
if (s.text[0] == quote &&
if (s[0] == quote &&
(quote == '\'' || quote == '"')) {
return false;
} else if (s.text[0] >= 0x80) {
} else if (s[0] >= 0x80) {
Rune r = -1;
isize size = gb_utf8_decode(s.text, s.len, &r);
*rune = r;
*multiple_bytes = true;
*tail_string = make_string(s.text+size, s.len-size);
return true;
} else if (s.text[0] != '\\') {
*rune = s.text[0];
} else if (s[0] != '\\') {
*rune = s[0];
*tail_string = make_string(s.text+1, s.len-1);
return true;
}
@@ -259,7 +390,7 @@ bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *
if (s.len <= 1) {
return false;
}
c = s.text[1];
c = s[1];
s = make_string(s.text+2, s.len-2);
switch (c) {
@@ -297,7 +428,7 @@ bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *
return false;
}
for (i = 0; i < 2; i++) {
i32 d = gb_digit_to_int(s.text[i]);
i32 d = gb_digit_to_int(s[i]);
if (d < 0 || d > 7) {
return false;
}
@@ -325,7 +456,7 @@ bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *
return false;
}
for (i = 0; i < count; i++) {
i32 d = gb_hex_digit_to_int(s.text[i]);
i32 d = gb_hex_digit_to_int(s[i]);
if (d < 0) {
return false;
}
@@ -358,8 +489,8 @@ i32 unquote_string(gbAllocator a, String *s_) {
if (n < 2) {
return 0;
}
quote = s.text[0];
if (quote != s.text[n-1]) {
quote = s[0];
if (quote != s[n-1]) {
return 0;
}
s.text += 1;
@@ -396,12 +527,12 @@ i32 unquote_string(gbAllocator a, String *s_) {
{
u8 rune_temp[4] = {0};
u8 rune_temp[4] = {};
isize buf_len = 3*s.len / 2;
u8 *buf = gb_alloc_array(a, u8, buf_len);
isize offset = 0;
while (s.len > 0) {
String tail_string = {0};
String tail_string = {};
Rune r = 0;
bool multiple_bytes = false;
bool success = unquote_char(s, quote, &r, &multiple_bytes, &tail_string);
+42 -10
View File
@@ -1,16 +1,17 @@
typedef struct TimeStamp {
struct TimeStamp {
u64 start;
u64 finish;
String label;
} TimeStamp;
};
typedef struct Timings {
struct Timings {
TimeStamp total;
Array(TimeStamp) sections;
Array<TimeStamp> sections;
u64 freq;
} Timings;
};
#if defined(GB_SYSTEM_WINDOWS)
u64 win32_time_stamp_time_now(void) {
LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
@@ -27,9 +28,38 @@ 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);
freq = cast(u64) ((1.0 / ts.tv_nsec) * 1000000000.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 +68,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
@@ -51,7 +83,7 @@ TimeStamp make_time_stamp(String label) {
}
void timings_init(Timings *t, String label, isize buffer_size) {
array_init_reserve(&t->sections, heap_allocator(), buffer_size);
array_init(&t->sections, heap_allocator(), buffer_size);
t->total = make_time_stamp(label);
t->freq = time_stamp__freq();
}
@@ -62,7 +94,7 @@ void timings_destroy(Timings *t) {
void timings__stop_current_section(Timings *t) {
if (t->sections.count > 0) {
t->sections.e[t->sections.count-1].finish = time_stamp_time_now();
t->sections[t->sections.count-1].finish = time_stamp_time_now();
}
}
@@ -78,14 +110,14 @@ f64 time_stamp_as_ms(TimeStamp ts, u64 freq) {
void timings_print_all(Timings *t) {
char const SPACES[] = " ";
isize max_len, i;
isize max_len;
timings__stop_current_section(t);
t->total.finish = time_stamp_time_now();
max_len = t->total.label.len;
for_array(i, t->sections) {
TimeStamp ts = t->sections.e[i];
TimeStamp ts = t->sections[i];
max_len = gb_max(max_len, ts.label.len);
}
@@ -97,7 +129,7 @@ void timings_print_all(Timings *t) {
time_stamp_as_ms(t->total, t->freq));
for_array(i, t->sections) {
TimeStamp ts = t->sections.e[i];
TimeStamp ts = t->sections[i];
gb_printf("%.*s%.*s - %.3f ms\n",
LIT(ts.label),
cast(int)(max_len-ts.label.len), SPACES,
+249 -212
View File
@@ -1,121 +1,135 @@
#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_ModMod, "%%"), \
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_ModModEq, "%%="), \
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_Undef, "---"), \
\
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_var, "var"), \
TOKEN_KIND(Token_const, "const"), \
TOKEN_KIND(Token_type, "type"), \
TOKEN_KIND(Token_import, "import"), \
TOKEN_KIND(Token_import_load, "import_load"), \
TOKEN_KIND(Token_foreign, "foreign"), \
TOKEN_KIND(Token_foreign_library, "foreign_library"), \
TOKEN_KIND(Token_foreign_system_library, "foreign_system_library"), \
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_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_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_bit_field, "bit_field"), \
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_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, "")
typedef enum TokenKind {
enum TokenKind {
#define TOKEN_KIND(e, s) e
TOKEN_KINDS
#undef TOKEN_KIND
} TokenKind;
};
String const token_strings[] = {
#define TOKEN_KIND(e, s) {cast(u8 *)s, gb_size_of(s)-1}
@@ -124,11 +138,11 @@ String const token_strings[] = {
};
typedef struct TokenPos {
struct TokenPos {
String file;
isize line;
isize column;
} TokenPos;
};
i32 token_pos_cmp(TokenPos a, TokenPos b) {
if (a.line == b.line) {
@@ -146,12 +160,11 @@ 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 {
struct Token {
TokenKind kind;
String string;
TokenPos pos;
} Token;
};
Token empty_token = {Token_Invalid};
Token blank_token = {Token_Ident, {cast(u8 *)"_", 1}};
@@ -162,12 +175,12 @@ Token make_token_ident(String s) {
}
typedef struct ErrorCollector {
struct ErrorCollector {
TokenPos prev;
i64 count;
i64 warning_count;
i64 count;
i64 warning_count;
gbMutex mutex;
} ErrorCollector;
};
gb_global ErrorCollector global_error_collector;
@@ -198,6 +211,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 +227,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 +273,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,26 +295,26 @@ 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)); }
typedef enum TokenizerInitError {
enum TokenizerInitError {
TokenizerInit_None,
TokenizerInit_Invalid,
@@ -282,18 +323,18 @@ typedef enum TokenizerInitError {
TokenizerInit_Empty,
TokenizerInit_Count,
} TokenizerInitError;
};
typedef struct TokenizerState {
struct TokenizerState {
Rune curr_rune; // current character
u8 * curr; // character pos
u8 * read_curr; // pos from start
u8 * line; // current line pos
isize line_count;
} TokenizerState;
};
typedef struct Tokenizer {
struct Tokenizer {
String fullpath;
u8 *start;
u8 *end;
@@ -305,12 +346,12 @@ typedef struct Tokenizer {
isize line_count;
isize error_count;
Array(String) allocated_strings;
} Tokenizer;
Array<String> allocated_strings;
};
TokenizerState save_tokenizer_state(Tokenizer *t) {
TokenizerState state = {0};
TokenizerState state = {};
state.curr_rune = t->curr_rune;
state.curr = t->curr;
state.read_curr = t->read_curr;
@@ -382,7 +423,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
@@ -402,7 +443,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
array_init(&t->allocated_strings, heap_allocator());
} else {
gbFile f = {0};
gbFile f = {};
gbFileError file_err = gb_file_open(&f, c_str);
switch (file_err) {
@@ -427,7 +468,7 @@ gb_inline void destroy_tokenizer(Tokenizer *t) {
gb_free(heap_allocator(), t->start);
}
for_array(i, t->allocated_strings) {
gb_free(heap_allocator(), t->allocated_strings.e[i].text);
gb_free(heap_allocator(), t->allocated_strings[i].text);
}
array_free(&t->allocated_strings);
}
@@ -453,17 +494,13 @@ 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 token = {};
token.kind = Token_Integer;
token.string = make_string(t->curr, 1);
token.pos.file = t->fullpath;
@@ -497,13 +534,26 @@ 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);
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} else {
} /* else if (t->curr_rune == 'h') { // Hexadecimal Float
token.kind = Token_Float;
advance_to_next_rune(t);
scan_mantissa(t, 16);
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} */ else {
seen_decimal_point = false;
scan_mantissa(t, 10);
@@ -513,12 +563,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 +593,11 @@ exponent:
scan_mantissa(t, 10);
}
if (t->curr_rune == 'i') {
token.kind = Token_Imag;
advance_to_next_rune(t);
}
end:
token.string.len = t->curr - token.string.text;
return token;
@@ -577,20 +632,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;
}
@@ -700,7 +757,7 @@ bool tokenizer_find_line_end(Tokenizer *t) {
Token tokenizer_get_token(Tokenizer *t) {
tokenizer_skip_whitespace(t);
Token token = {0};
Token token = {};
token.string = make_string(t->curr, 1);
token.pos.file = t->fullpath;
token.pos.line = t->line_count;
@@ -717,20 +774,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 (token.string == token_strings[k]) {
token.kind = cast(TokenKind)k;
break;
}
}
}
@@ -832,71 +879,61 @@ 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;
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 0x2260: token.kind = Token_NotEq; break; // '≠'
case 0x2264: token.kind = Token_LtEq; break; // '≤'
case 0x2265: token.kind = Token_GtEq; break; // '≥'
case '%': token.kind = token_kind_dub_eq(t, '%', Token_Mod, Token_ModEq, Token_ModMod, Token_ModModEq); break;
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); 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_Sub;
if (t->curr_rune == '=') {
advance_to_next_rune(t);
token.kind = Token_SubEq;
} else if (t->curr_rune == '-') {
advance_to_next_rune(t);
token.kind = Token_Dec;
if (t->curr_rune == '-') {
advance_to_next_rune(t);
token.kind = Token_Undef;
}
} else if (t->curr_rune == '>') {
advance_to_next_rune(t);
token.kind = 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_variant2(t, Token_Add, Token_AddEq);
break;
case '-':
token.kind = token_kind_variant3(t, Token_Sub, Token_SubEq, '>', Token_ArrowRight);
break;
case '/': {
if (t->curr_rune == '/') {
while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) {
@@ -907,7 +944,9 @@ Token tokenizer_get_token(Tokenizer *t) {
isize comment_scope = 1;
advance_to_next_rune(t);
while (comment_scope > 0) {
if (t->curr_rune == '/') {
if (t->curr_rune == GB_RUNE_EOF) {
break;
} else if (t->curr_rune == '/') {
advance_to_next_rune(t);
if (t->curr_rune == '*') {
advance_to_next_rune(t);
@@ -936,9 +975,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;
@@ -957,8 +994,8 @@ Token tokenizer_get_token(Tokenizer *t) {
case '|': token.kind = token_kind_dub_eq(t, '|', Token_Or, Token_OrEq, Token_CmpOr, Token_CmpOrEq); break;
default:
if (curr_rune != GB_RUNE_BOM) {
u8 str[4] = {0};
if (curr_rune != GB_RUNE_BOM) {
u8 str[4] = {};
int len = cast(int)gb_utf8_encode_rune(str, curr_rune);
tokenizer_err(t, "Illegal character: %.*s (%d) ", len, str, curr_rune);
}
+2502
View File
File diff suppressed because it is too large Load Diff
+3 -26
View File
@@ -1,11 +1,13 @@
#pragma warning(push)
#pragma warning(disable: 4245)
extern "C" {
// #include "utf8proc/utf8proc.h"
#include "utf8proc/utf8proc.c"
}
#pragma warning(pop)
bool rune_is_letter(Rune r) {
if ((r < 0x80 && gb_char_is_alpha(cast(char)r)) ||
r == '_') {
@@ -39,28 +41,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;
}
+64 -46
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 cast(utf8proc_category_t)utf8proc_get_property(c)->category;
}
UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
@@ -391,19 +391,17 @@ 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, \
(utf8proc_option_t)(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;
utf8proc_propval_t category;
utf8proc_category_t category;
utf8proc_int32_t hangul_sindex;
if (uc < 0 || uc >= 0x110000) return UTF8PROC_ERROR_NOTASSIGNED;
property = unsafe_get_property(uc);
category = property->category;
category = cast(utf8proc_category_t)property->category;
hangul_sindex = uc - UTF8PROC_HANGUL_SBASE;
if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) {
if (hangul_sindex >= 0 && hangul_sindex < UTF8PROC_HANGUL_SCOUNT) {
@@ -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,24 @@ 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, cast(utf8proc_option_t)(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, cast(utf8proc_option_t)(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, cast(utf8proc_option_t)(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, cast(utf8proc_option_t)(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)