Compare commits

...

230 Commits

Author SHA1 Message Date
gingerBill 0c06a8d154 Fix issue #146 regarding polymorphic type parameters 2017-11-18 20:56:53 +00:00
gingerBill b0e3a4e276 build_dll replace with -build-mode=dll 2017-11-17 20:21:58 +00:00
gingerBill b651466630 Add ptr_to_bytes 2017-11-16 19:01:57 +00:00
gingerBill 24c09c9201 Allow for printf style assert and panic 2017-11-16 18:57:03 +00:00
gingerBill e48346a9ee Disable negation of unsigned constants (Issue: #145) 2017-11-15 21:25:16 +00:00
gingerBill 9bd8bdaa5a Disable all cyclic importations 2017-11-13 23:53:01 +00:00
gingerBill a137699d95 Add optional truncate parameter to write_entire_file (#144) 2017-11-13 20:35:21 +00:00
gingerBill f6a56c2f82 Remove #const; Minor fixes 2017-11-12 20:15:17 +00:00
gingerBill dffa791607 In error messages, remove with '; Fix error messages for switch` 2017-11-12 19:00:48 +00:00
gingerBill 5ce6555721 Allow for default arguments after a variadic parameter 2017-11-12 17:55:16 +00:00
gingerBill 53b3ad186f Fix untyped type IR bug 2017-11-10 22:37:38 +00:00
gingerBill 82c1c5b3fe Merge pull request #142 from zangent/master
Added static linking for macOS, too. There's literally %number% of us!
2017-11-10 22:14:40 +00:00
Zachary Pierson 6d880bc3bb Added static linking for macOS. Also fixed the build.sh. Thanks, vass :/ 2017-11-10 16:11:55 -06:00
gingerBill 40281d595d Fix parsing errors for variadic signatures 2017-11-10 22:03:05 +00:00
gingerBill 85fab55e57 Fix make 2017-11-10 21:43:37 +00:00
gingerBill 1d2eb8055e Merge pull request #140 from vassvik/master
Fixed foreign import for linux. Modified .gitignore to ignore temp files and files in shared/. Added a Makefile for linux
2017-11-10 21:17:16 +00:00
vassvik 9e0b69312b Fixed foreign import for linux. Modified .gitignore to ignore temp files and files in shared/. Added a Makefile for linux 2017-11-10 21:31:13 +01:00
gingerBill bbddbba340 Fix cast to uintptr 2017-11-10 18:56:47 +00:00
gingerBill 0d01a6f552 Fix issue #139 2017-11-10 18:24:49 +00:00
gingerBill ae3672608d Fix link_name overriding 2017-11-09 23:36:10 +00:00
gingerBill e5c39fb2a9 Fix opening file without close; Minor fixes 2017-11-09 22:58:44 +00:00
gingerBill eb4b3f5976 Change push allocator system; update core libraries 2017-11-09 22:48:00 +00:00
gingerBill dbb070524f Allow nil in a ternary statement 2017-11-09 21:10:08 +00:00
gingerBill 36b0b50ba4 Amend allocation procedures with caller location; Compound literals missing type can determine type in certain cases. 2017-11-09 20:51:13 +00:00
gingerBill ac46b2053d Remove unnecessary IR bound checks 2017-11-08 22:14:07 +00:00
gingerBill 0ffcccdae5 Add Source_Code_Location parameter Allocator_Proc (#138) 2017-11-08 22:05:51 +00:00
gingerBill 4777bd607e Fix issue #137 2017-11-08 22:02:15 +00:00
gingerBill 39e9b50482 Remove debug code 2017-11-07 23:09:05 +00:00
gingerBill 30adb9c770 Fix issue #134 2017-11-07 23:05:39 +00:00
gingerBill b1d1497f4b Fix array of array arithmetic 2017-11-07 23:02:53 +00:00
gingerBill 9df3a94d33 Fix cyclic type checking bug 2017-11-05 23:38:09 +00:00
gingerBill d4f335d068 Fix fmt.odin %#v fancy printing 2017-11-05 19:47:18 +00:00
gingerBill 74341b9b74 Fix IR generation issue 2017-11-05 19:37:46 +00:00
gingerBill 66ee2cb6ed #const value procedure parameters; $N for polymorphic array lengths 2017-11-05 18:26:24 +00:00
gingerBill 1d4881cbbe Add array programming 2017-11-05 14:22:18 +00:00
gingerBill 04b917a60a More code clean up 2017-11-04 10:53:47 +00:00
gingerBill e6c99cd289 Cleanup attribute handling 2017-11-04 10:26:56 +00:00
gingerBill 6bc5584add Fix fmt printing uintptr type 2017-11-04 00:16:54 +00:00
gingerBill 121f0185d6 Custom thread local models 2017-11-03 23:46:42 +00:00
gingerBill e7999f8450 Foreign context cleanup 2017-11-03 23:20:30 +00:00
gingerBill 0b29e42adb link_prefix; thread_local; fix link_name for file-scope variables 2017-11-03 23:11:06 +00:00
gingerBill fcc8b89e6b Fix issue #130; allow conversion from any pointer to uintptr and vice versa 2017-11-02 22:34:09 +00:00
gingerBill 529d1c78c7 Fix issue #131 2017-11-02 22:30:12 +00:00
gingerBill 414486829a Add string_set.cpp; Code clean up 2017-10-30 20:26:05 +00:00
gingerBill 3e05be8eb8 @(default_calling_convention = ...) for foreign blocks 2017-10-29 18:09:05 +00:00
gingerBill ae24a8e5ae Fix pointer arithmetic; remove suffix #tags for proc types 2017-10-29 17:00:54 +00:00
gingerBill d2588f9d1d Infix proc calling convention proc "std" (...) 2017-10-29 16:44:44 +00:00
gingerBill 1eb9994d88 Attributes; @(link_name="foo") 2017-10-29 15:46:23 +00:00
gingerBill a43b89f36e #alias type declarations; core library additions; _global import name for the global scope 2017-10-29 11:35:21 +00:00
gingerBill 0ed34af19d Fix importation of empty file (issue #128) 2017-10-18 22:52:42 +01:00
gingerBill 71729c2855 Add anonymous using import names with an underscore (#127)
`using import _ "foo.odin"`
2017-10-18 22:29:14 +01:00
gingerBill 6c8c430c2a Fix enum iteration (issue #126) 2017-10-18 22:26:04 +01:00
gingerBill 57b97ad0bd Fix issue #124 2017-10-15 23:30:55 +01:00
gingerBill 56f7a859df Refactor code to remove entity flag for export 2017-10-15 16:16:16 +01:00
gingerBill e5e14b9947 Remove name mangling for foreign export variables 2017-10-15 16:11:34 +01:00
gingerBill 3d8bf36a30 foreign export block
```
foreign export {
    my_i32: i32;
    my_foo :: proc() -> i32 {
        return 123;
    }
}
```
2017-10-15 16:05:42 +01:00
gingerBill 85f7c2d040 Change foreign_library to foreign import 2017-10-15 15:21:56 +01:00
gingerBill 26ea8f6dcb Syntax: Replace foreign_system_library "kernel.lib" to foreign_library "system:kernel.lib"; Remove keyword: foreign_system_library 2017-10-15 12:11:33 +01:00
gingerBill e05fe1837d Fix minimal dependency generation for polymorphic structs (related to issue #121) 2017-10-15 11:21:48 +01:00
gingerBill 94762b56f6 Fix issue #122 2017-10-15 10:14:17 +01:00
gingerBill b3b688fa50 Fix issue #123 2017-10-15 10:09:50 +01:00
Ginger Bill 5eaa8de8f9 Fix issue with #118 2017-10-12 21:01:16 +01:00
Ginger Bill 26d3c54aff Fix issue #119
This may need better error messages
2017-10-12 20:52:19 +01:00
Ginger Bill 349a62121c Fix issue #120 2017-10-12 20:32:44 +01:00
Ginger Bill bbb0e14633 Fix using import to work correctly 2017-10-12 20:28:32 +01:00
Ginger Bill 42312d9def Fix typos in c.odin 2017-10-10 23:43:31 +01:00
Ginger Bill 065d0e4ee3 Fix string_to_enum_value 2017-10-09 22:56:48 +01:00
Ginger Bill b772ad7094 Fix issue #116 2017-10-09 17:58:12 +01:00
Ginger Bill 444d366c39 Fix issue #115 2017-10-09 17:56:26 +01:00
Ginger Bill 8e4233b86a Correct union size 2017-10-08 15:19:01 +01:00
Ginger Bill 6424966b7a Union tag stored as an integer 2017-10-08 15:16:13 +01:00
Ginger Bill 4e42d7df43 Minor code reorganization 2017-10-08 12:27:03 +01:00
Ginger Bill 580ee5cc4a Fix using on import names 2017-10-08 11:08:15 +01:00
Ginger Bill 56a98a483f Better error messages for import cycles 2017-10-08 10:58:16 +01:00
Ginger Bill df7a4eda8a Allow for cyclic import but disallow cyclic using import and export 2017-10-07 11:37:43 +01:00
Ginger Bill 91cc0b282a Fix issue #114 2017-10-04 18:57:27 +01:00
Ginger Bill 01d8aea4df Disallow procedures literals as default values in anonymous struct types 2017-10-01 21:44:55 +01:00
Ginger Bill ee904060c5 Disallow anonymous structs with procedures as default values 2017-10-01 21:22:39 +01:00
Ginger Bill afb5538e83 Default procedure values for proc 2017-10-01 20:27:02 +01:00
Ginger Bill 1f24f105cc "Constant" procedure values for default values in structs 2017-10-01 20:10:13 +01:00
Ginger Bill 8f39ebbe5a Procedure literals for default values in structs 2017-10-01 20:01:00 +01:00
Ginger Bill c1e720a49b match to switch; Optional semicolons after "import" statements 2017-10-01 17:09:57 +01:00
Ginger Bill f38c8875b2 Fix issue #104 2017-10-01 14:29:54 +01:00
Ginger Bill e7e51f53ce Fix cyclic polymorphic struct bug #111 2017-10-01 14:10:31 +01:00
Ginger Bill 5259de5872 Reserve the link_name main 2017-09-30 11:28:17 +01:00
Ginger Bill e2b9c87aa8 Wrap entry point main around the C style main in the IR 2017-09-30 11:20:35 +01:00
Ginger Bill 8c7cf0dbb0 Fix union array bug (Issue #112) 2017-09-29 21:35:59 +01:00
Ginger Bill e6e9375b09 Remove http_test.odin 2017-09-29 21:20:39 +01:00
Ginger Bill c6096f9205 Revert to demo.odin 2017-09-29 21:11:51 +01:00
Ginger Bill 11614c2649 Fix old_demos; Fix when bug; Fix enum .names 2017-09-29 21:11:16 +01:00
Ginger Bill 793bc8c585 Fix issue #89 2017-09-25 23:08:22 +01:00
Ginger Bill 335e88b738 Fix issue #106 2017-09-25 23:06:04 +01:00
Ginger Bill b77ea94976 Fix issue #108 2017-09-25 22:59:59 +01:00
Ginger Bill ae17a51c0d Fix issue #109 2017-09-25 22:53:59 +01:00
gingerBill ee7a83f124 Merge pull request #110 from ThisDrunkDane/invalid-token-print-pos
Print position of the invalid token found during parsing.
2017-09-25 22:51:41 +01:00
Mikkel Hjortshoej 67ac551a2f The position that the invalid token was found at is printed 2017-09-25 21:42:23 +02:00
Ginger Bill 572ac616c1 Prevent statements after branch statements. 2017-09-24 14:58:15 +01:00
Ginger Bill 96bf6a5bcb Fix cyclic importation error printing 2017-09-23 20:47:02 +01:00
Ginger Bill c43d66c286 Use comma for struct field separators (disallow nesting) 2017-09-21 23:18:28 +01:00
Ginger Bill 95fb5fa46c Fix #export proc tag 2017-09-21 22:32:24 +01:00
Ginger Bill d614913c11 Fix decimal.odin, again 2017-09-20 23:17:33 +01:00
Ginger Bill 3bfaac0844 Fix decimal.odin assignment bug 2017-09-20 22:59:46 +01:00
Ginger Bill 14d0cbf6d7 Fix load order of files (again) 2017-09-20 21:42:42 +01:00
Ginger Bill 61a163d773 Fix crash with build_dll (Issue #100) 2017-09-20 21:00:40 +01:00
Ginger Bill 3a644dad78 Fix issue #101 2017-09-20 20:45:40 +01:00
Ginger Bill d2c1c719bd Fix file load order and allow when statements at file scope 2017-09-20 20:38:32 +01:00
Ginger Bill 333db4dc94 Fix issues #95 and #96 2017-09-13 22:20:27 +01:00
Ginger Bill cbcf4b6071 Fix issue #94 2017-09-11 22:49:26 +01:00
Ginger Bill e6e0aba8c3 Remove when suffixes; Implement file scope when statement, evaluated in source order 2017-09-10 15:17:37 +01:00
Ginger Bill 85097a9958 Fix global variable initialization IR bug 2017-09-10 13:50:11 +01:00
Ginger Bill 7791c343c4 Allow for multiple library collections; Store AstFile as pointer 2017-09-10 13:26:14 +01:00
Ginger Bill 3bd762591a Fix path_is_directory for *nix 2017-09-07 21:33:37 +01:00
Ginger Bill 8e3b77aba8 Library collections 2017-09-07 20:55:59 +01:00
Ginger Bill 36e3a02f67 Fix bit_field type information 2017-09-02 22:54:11 +01:00
Ginger Bill 566a242ba3 Fix issue #92 2017-09-02 10:06:44 +01:00
Ginger Bill 1e3b3c107c IR Fix for UnionTagValue 2017-08-28 23:04:48 +01:00
Ginger Bill 2ac33285c1 Remove metagen.odin 2017-08-27 23:28:20 +01:00
Ginger Bill 7cb8016df3 Add examples 2017-08-27 23:27:12 +01:00
Ginger Bill cf3c5a878a export declarations 2017-08-27 19:36:43 +01:00
Ginger Bill 2d20bde495 Remove () grouping for foreign_library 2017-08-27 19:24:30 +01:00
Ginger Bill b9e347ef50 Replace import_load with using import . 2017-08-27 17:03:27 +01:00
Ginger Bill 6707c8750e Import cycle checking 2017-08-27 14:42:19 +01:00
Ginger Bill e5502c13ee Restrict global variables to not allow tuples 2017-08-20 19:35:52 +01:00
Ginger Bill f30d2e43ea Add priority_queue.cpp and ptr_set.cpp 2017-08-20 18:39:09 +01:00
Ginger Bill 6c73f9d3fd Global variable dependency initialization ordering
Fuck graph theory
2017-08-20 18:28:21 +01:00
Ginger Bill 1161aa829d Fix mem.Arena 2017-08-13 22:20:44 +01:00
Ginger Bill 01519f2fd5 Fix push_allocator 2017-08-13 22:09:26 +01:00
Ginger Bill 33aad3a8ce Merge branch 'master' of https://github.com/gingerBill/Odin 2017-08-12 20:04:58 +01:00
Ginger Bill 4262c125c5 Fix struct #packed alignment calculation 2017-08-12 20:04:35 +01:00
Ginger Bill a09d5959ef Fix issues with OSX 2017-08-11 12:47:07 +01:00
Ginger Bill d7bd3f8402 Fix compilation issues on OSX 2017-08-11 00:16:57 +01:00
Ginger Bill 0fff6a2b74 Fix i128 division 2017-08-10 23:46:12 +01:00
Ginger Bill f4c0405221 Fix inline #raw_union bug in issue #87 2017-08-08 21:27:42 +01:00
Ginger Bill 49d337c830 v0.6.2; Use Ada_Case for types 2017-08-03 21:21:56 +01:00
Ginger Bill 294092979e Update build.bat 2017-08-01 21:38:06 +01:00
Ginger Bill c454ede184 v0.6.1a 2017-08-01 17:30:26 +01:00
Ginger Bill d854c5003c Fix minor errors for *nix 2017-08-01 17:28:49 +01:00
Ginger Bill 66d8776b83 v0.6.1 2017-08-01 15:18:37 +01:00
Ginger Bill ba6ecf35cf Disable threading on *nix for the time being 2017-08-01 15:09:43 +01:00
Ginger Bill 10cc9cf661 Add mutexes to string buffer allocator uses 2017-08-01 14:24:40 +01:00
Ginger Bill 2db971eedd Use pthread mutex 2017-08-01 13:49:12 +01:00
Ginger Bill 1775e80b41 HACK: Ignore Mutex check 2017-07-31 23:18:21 +01:00
Ginger Bill e4a93619db Update gb.h 2017-07-31 12:17:53 +01:00
Ginger Bill 4d14b3bcb4 Update remove_temp_files 2017-07-31 12:15:20 +01:00
Ginger Bill 9f4f5f9346 Add -keep-temp-files option 2017-07-31 12:06:04 +01:00
Ginger Bill 0fae31fb54 Extra type safety; Fix typos 2017-07-31 11:36:00 +01:00
Ginger Bill 8987a6630c v0.6.0 2017-07-30 22:26:22 +01:00
Ginger Bill 10ff8e0426 Fix ir for TypeInfo.Map 2017-07-30 20:17:25 +01:00
Ginger Bill a0ae02168a Update add_type_info_type to ignore polymorphic types 2017-07-30 20:13:23 +01:00
Ginger Bill a3c1ac2030 Speed up llvm ir printing; Use CRITICAL_SECTION for Mutex on windows 2017-07-30 19:47:37 +01:00
Ginger Bill 629b248f53 Parallelization of the Parser
~66% reduction (unoptimized build)
~30% reduction (optimized build)
2017-07-30 19:01:02 +01:00
Ginger Bill 62a72f0163 transmute(type)x; Minor code clean up 2017-07-30 14:52:42 +01:00
Ginger Bill 655931f0ea Minor Simplification of threading demo 2017-07-29 15:18:36 +01:00
Ginger Bill ca36fabfc0 Remove dead code for the "fixed" map idea 2017-07-29 14:43:42 +01:00
Ginger Bill 7bd62481ad Fix nil assignment to unions 2017-07-29 14:23:34 +01:00
Ginger Bill fbd27d7c45 Fix map internal type generation 2017-07-29 13:56:45 +01:00
Ginger Bill 3546391311 Merge branch 'master' of https://github.com/gingerBill/Odin 2017-07-29 13:01:28 +01:00
Ginger Bill 24c812115e Remove empty union check on array types; Fix overflowing error printing 2017-07-29 13:01:17 +01:00
gingerBill 28be0ad69b Fix IR print bug for empty structs; 2017-07-28 11:35:01 +01:00
gingerBill f0980c0a98 Fix import name exportation bug; Fix procedure type printing 2017-07-24 07:57:09 +01:00
Ginger Bill 1df4aa90ce Fix struct parameter bugs 2017-07-21 15:25:58 +01:00
Ginger Bill 6b3cf051f8 Fix math.odin, again 2017-07-21 12:39:05 +01:00
Ginger Bill 4ecd6e592b Fix missing semicolons in math.odin 2017-07-21 10:37:49 +01:00
Ginger Bill dbddec33c8 Internal changes; thread.odin for windows only 2017-07-20 23:57:56 +01:00
Ginger Bill 401a5955a4 Fix minor check on vector types 2017-07-20 19:55:54 +01:00
Ginger Bill 9a3b4167bb Fix polymorphic element types usage; Empty union as opaque type 2017-07-20 19:40:51 +01:00
Ginger Bill 13bc6eeea4 Make fields et al an Array rather than a raw pointer 2017-07-20 15:32:34 +01:00
Ginger Bill 2da18b6d33 Change internals from Record to Struct 2017-07-20 15:23:13 +01:00
Ginger Bill 6d37ed12d2 Update internals of a Union and Tuple 2017-07-20 15:17:04 +01:00
Ginger Bill eab23cd5b7 Fix parsing bug with procedure types in return values 2017-07-19 22:34:50 +01:00
Ginger Bill d233706a2d Fix minor parsing bug with procedure return types 2017-07-19 22:17:57 +01:00
Ginger Bill f1ab17ed4e type_info_of; enum_value_to_string and string_to_enum_value 2017-07-19 14:01:56 +01:00
Ginger Bill 6113164211 Change union layout to store type info rather than an integer; ternary expression for types with constant condition 2017-07-19 12:15:21 +01:00
Ginger Bill 4db462a703 Fix copy 2017-07-18 20:39:53 +01:00
Ginger Bill a22c6d6c0c Fix parsing error for compound literals 2017-07-18 19:57:30 +01:00
Ginger Bill 59fb7b020a Merge raw_union into struct as a memory layout tag #raw_union 2017-07-18 19:24:45 +01:00
Ginger Bill 65f079ebc4 Remove atomic, ++, and -- 2017-07-18 18:58:41 +01:00
Ginger Bill d16aa79492 General specialization for polymorphic parameters 2017-07-18 18:05:41 +01:00
Ginger Bill 5af0acc4af Disallow default struct values for any; new_clone 2017-07-18 16:02:01 +01:00
Ginger Bill a459364de3 Ignore missing default values for struct literals at the end 2017-07-18 15:32:34 +01:00
Ginger Bill 277ef1a68f Allow undefined --- as a struct field default value. 2017-07-18 15:09:24 +01:00
Ginger Bill 193c7c82c8 Default struct field values 2017-07-18 14:56:07 +01:00
Ginger Bill f7d8ba408c Fix some preload bugs. 2017-07-18 11:42:16 +01:00
Ginger Bill 9a8759efef Polymorphic type specialization for procedures 2017-07-17 15:08:36 +01:00
Ginger Bill 054948e701 Basic procedure type parameter specialization 2017-07-16 15:00:16 +01:00
Ginger Bill 1c5ddd65b4 Rudimentary support for parametric polymorphic types 2017-07-13 22:35:00 +01:00
Ginger Bill b8697fb4ed Change precedence order for types e.g. ^T(x) == ^(T(x)) 2017-07-13 16:20:07 +01:00
Ginger Bill 03570275c1 Fix issue #78 and have a better error message. 2017-07-13 11:35:01 +01:00
Ginger Bill b5587f1937 Fix aliasing of overloaded procedures from other scopes 2017-07-11 20:54:38 +01:00
Ginger Bill c4c6975f1b cast(Type)expr; Fix overloaded procedure determination on assignment 2017-07-11 14:40:27 +01:00
Ginger Bill 0be0fb2a57 Nested when statements within records 2017-07-10 23:47:22 +01:00
Ginger Bill 115e6e7f9e Update demo for both subtyping and union based Entity 2017-07-10 23:28:53 +01:00
Ginger Bill 3868a9a0f0 Clean up _preload.odin types 2017-07-10 23:15:41 +01:00
Ginger Bill ba5050ac7c Compiler Internal Changes: TypeRecord_Union -> Type_Union 2017-07-10 22:59:23 +01:00
Ginger Bill d936ca1ea0 Compiler internal change: TypeRecord_Enum -> Type_Enum 2017-07-10 22:42:58 +01:00
Ginger Bill fd8c4d58bb union type allow for any types and removes common fields 2017-07-10 22:32:21 +01:00
Ginger Bill ce4b7b8b7d Nested record declarations 2017-07-10 20:39:42 +01:00
Ginger Bill 069a47220e Make record semicolon syntax more consistent 2017-07-10 14:52:58 +01:00
Ginger Bill 66e4aaffc5 Use semicolons as field delimiters in records 2017-07-10 13:49:50 +01:00
Ginger Bill 81336b58cb "Fix" printing of embedded any to prevent recursion 2017-07-10 10:37:51 +01:00
Ginger Bill b201670f7a Fix _preload.odin; Add for in without parameters; Change sync.Mutex for windows 2017-07-08 23:13:57 +01:00
Ginger Bill 4b051a0d3b .. half closed range; ... open range; ... variadic syntax 2017-07-07 23:42:43 +01:00
Ginger Bill 45353465a6 Add sort.odin 2017-07-07 22:26:55 +01:00
Ginger Bill c63cb98019 Fix else do 2017-07-07 17:50:45 +01:00
Ginger Bill 773cf5ca08 Add -show-timings; Clean up polymorphic procedure code a bit 2017-07-07 15:26:49 +01:00
Ginger Bill 2db03cb4a5 Fix aprint* bug; NULL -> nullptr; Better error messages for overloaded functions 2017-07-06 22:43:55 +01:00
Ginger Bill eed873c6ec Add free for maps (a previous oversight) 2017-07-05 13:51:25 +01:00
Ginger Bill 3d2d461867 Replace many built-in procedures with user-level procedures 2017-07-04 23:52:00 +01:00
Ginger Bill 36392d658e Fix demo.odin 2017-07-04 22:43:38 +01:00
Ginger Bill 82696179e8 Merge branch 'master' of https://github.com/gingerBill/Odin 2017-07-04 22:42:41 +01:00
Ginger Bill 188bc28f6a Allow for overloading of polymorphic procedures 2017-07-04 22:42:25 +01:00
Ginger Bill 240da5c8e0 Allow aliasing of aliases 2017-07-04 16:06:08 +01:00
Ginger Bill 689a0c0b49 *_of as keyords; Allow constant aliasing for user/built-in procedures, import names, and library names 2017-07-04 11:23:48 +01:00
Ginger Bill bc16b290ba Disable polymorphic overloading in the global scope
TODO: Figure out why it does not work in the global scope
2017-07-02 22:08:39 +01:00
Ginger Bill 96d32680fe Allow overloading of polymorphic procedures 2017-07-02 10:45:22 +01:00
Ginger Bill d782b3d21d Fix do on for loops 2017-07-01 11:53:01 +01:00
Ginger Bill ed089b44b9 do keyword for inline statements instead of blocks 2017-07-01 11:38:44 +01:00
Ginger Bill 33f4af2e19 Fix demo 2017-06-29 21:01:07 +01:00
Ginger Bill 69f7382eec Implicit parametric polymorphic procedures 2017-06-29 20:56:18 +01:00
Ginger Bill 7e3293fc20 Fix odin version printing 2017-06-29 16:08:30 +01:00
Ginger Bill e4a8283327 Remove Type
What was I thinking?!
2017-06-29 15:48:07 +01:00
Ginger Bill 001baf4419 Add Type -- Runtime type for comparing types (similar to TypeInfo but simpler) 2017-06-29 15:13:41 +01:00
Ginger Bill d167290b28 Make AstNodeIdent a struct wrapping its Token 2017-06-29 12:11:50 +01:00
Ginger Bill f4879d4723 Update procedure names and extend demo.odin 2017-06-29 11:25:05 +01:00
Ginger Bill fd81c06c35 Remove var and const keywords; Fix default parameter syntax 2017-06-28 23:55:40 +01:00
Ginger Bill 94afcec757 :: style procedure declarations; remove old parsing code 2017-06-28 23:47:06 +01:00
Ginger Bill 4f28e9e1fb Remove type prefix declarations 2017-06-28 23:23:10 +01:00
Ginger Bill 0622509807 Disable var and const declarations 2017-06-28 23:17:20 +01:00
Ginger Bill 9ca2246bac Basic allowance for := and :: 2017-06-28 22:38:04 +01:00
Ginger Bill 647e2cafd7 Fix expand_to_tuple 2017-06-27 22:47:19 +01:00
78 changed files with 22359 additions and 15168 deletions
+10
View File
@@ -257,7 +257,17 @@ paket-files/
builds/
bin/
*.exe
*.obj
*.pdb
# - Linux/MacOS
odin
odin.dSYM
# shared collection
shared/
# temp files
* .ll
*.bc
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2016 Ginger Bill. All rights reserved.
Copyright (c) 2016-2017 Ginger Bill. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
+24
View File
@@ -0,0 +1,24 @@
DISABLED_WARNINGS=-Wno-switch -Wno-writable-strings -Wno-tautological-compare -Wno-macro-redefined #-Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare
LDFLAGS=-pthread -ldl -lm -lstdc++
CFLAGS=-std=c++11
CC=clang
OS=$(shell uname)
ifeq ($(OS), DARWIN)
LDFLAGS=$(LDFLAGS) -liconv
endif
all: debug demo
demo:
./odin run examples/demo.odin
debug:
$(CC) src/main.cpp $(DISABLED_WARNINGS) $(CFLAGS) -g $(LDFLAGS) -o odin
release:
$(CC) src/main.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 -march=native $(LDFLAGS) -o odin
+1 -2
View File
@@ -38,13 +38,12 @@ if %release_mode% EQU 0 ( rem Debug
set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings%
set linker_settings=%libs% %linker_flags%
del *.pdb > NUL 2> NUL
del *.ilk > NUL 2> NUL
cl %compiler_settings% "src\main.cpp" ^
/link %linker_settings% -OUT:%exe_name% ^
&& odin run code/demo.odin -opt=0
&& odin run examples/demo.odin -opt=0
rem && odin docs core/fmt.odin
del *.obj > NUL 2> NUL
+10 -6
View File
@@ -1,15 +1,21 @@
#!/bin/bash
release_mode=0
release_mode=$1
warnings_to_disable="-std=c++11 -g -Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined -Wno-writable-strings"
warnings_to_disable="-std=c++11 -Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined -Wno-writable-strings"
libraries="-pthread -ldl -lm -lstdc++"
other_args=""
compiler="clang"
if [ -z "$release_mode" ]; then release_mode="0"; fi
if [ "$release_mode" -eq "0" ]; then
other_args="${other_args} -g -fno-inline-functions"
other_args="${other_args} -g"
fi
if [ "$release_mode" -eq "1" ]; then
other_args="${other_args} -O3 -march=native"
fi
if [[ "$(uname)" == "Darwin" ]]; then
# Set compiler to clang on MacOS
@@ -19,6 +25,4 @@ if [[ "$(uname)" == "Darwin" ]]; then
other_args="${other_args} -liconv"
fi
${compiler} src/main.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin
./odin run code/demo.odin
${compiler} src/main.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin && ./odin run examples/demo.odin
-433
View File
@@ -1,433 +0,0 @@
import "fmt.odin";
proc general_stuff() {
// Complex numbers
var a = 3 + 4i;
var b: complex64 = 3 + 4i;
var c: complex128 = 3 + 4i;
var d = complex(2, 3);
var e = a / conj(a);
fmt.println("(3+4i)/(3-4i) =", e);
fmt.println(real(e), "+", imag(e), "i");
// C-style variadic procedures
foreign __llvm_core {
// The variadic part allows for extra type checking too which C does not provide
proc c_printf(fmt: ^u8, #c_vararg args: ..any) -> i32 #link_name "printf";
}
type Foo struct {
x: int,
y: f32,
z: string,
}
var foo = Foo{123, 0.513, "A string"};
var x, y, z = expand_to_tuple(foo);
fmt.println(x, y, z);
// By default, all variables are zeroed
// This can be overridden with the "uninitialized value"
// This is similar to `nil` but applied to everything
var undef_int: int = ---;
// Context system is now implemented using Implicit Parameter Passing (IPP)
// The previous implementation was Thread Local Storage (TLS)
// IPP has the advantage that it works on systems without TLS and that you can
// link the context to the stack frame and thus look at previous contexts
//
// It does mean that a pointer is implicitly passed procedures with the default
// Odin calling convention (#cc_odin)
// This can be overridden with something like #cc_contextless or #cc_c if performance
// is worried about
}
proc foreign_blocks() {
// See sys/windows.odin
}
proc default_arguments() {
proc hello(a: int = 9, b: int = 9) {
fmt.printf("a is %d; b is %d\n", a, b);
}
fmt.println("\nTesting default arguments:");
hello(1, 2);
hello(1);
hello();
}
proc named_arguments() {
type Colour enum {
Red,
Orange,
Yellow,
Green,
Blue,
Octarine,
};
using Colour;
proc make_character(name, catch_phrase: string, favorite_color, least_favorite_color: Colour) {
fmt.println();
fmt.printf("My name is %v and I like %v. %v\n", name, favorite_color, catch_phrase);
}
make_character("Frank", "¡Ay, caramba!", Blue, Green);
// As the procedures have more and more parameters, it is very easy
// to get many of the arguments in the wrong order especialy if the
// types are the same
make_character("¡Ay, caramba!", "Frank", Green, Blue);
// Named arguments help to disambiguate this problem
make_character(catch_phrase = "¡Ay, caramba!", name = "Frank",
least_favorite_color = Green, favorite_color = Blue);
// The named arguments can be specifed in any order.
make_character(favorite_color = Octarine, catch_phrase = "U wot m8!",
least_favorite_color = Green, name = "Dennis");
// NOTE: You cannot mix named arguments with normal values
/*
make_character("Dennis",
favorite_color = Octarine, catch_phrase = "U wot m8!",
least_favorite_color = Green);
*/
// Named arguments can also aid with default arguments
proc numerous_things(s : string, a = 1, b = 2, c = 3.14,
d = "The Best String!", e = false, f = 10.3/3.1, g = false) {
var g_str = g ? "true" : "false";
fmt.printf("How many?! %s: %v\n", s, g_str);
}
numerous_things("First");
numerous_things(s = "Second", g = true);
// Default values can be placed anywhere, not just at the end like in other languages
proc weird(pre: string, mid: int = 0, post: string) {
fmt.println(pre, mid, post);
}
weird("How many things", 42, "huh?");
weird(pre = "Prefix", post = "Pat");
}
proc default_return_values() {
proc foo(x: int) -> (first: string = "Hellope", second = "world!") {
match x {
case 0: return;
case 1: return "Goodbye";
case 2: return "Goodbye", "cruel world...";
case 3: return second = "cruel world...", first = "Goodbye";
}
return second = "my old friend.";
}
fmt.printf("%s %s\n", foo(0));
fmt.printf("%s %s\n", foo(1));
fmt.printf("%s %s\n", foo(2));
fmt.printf("%s %s\n", foo(3));
fmt.printf("%s %s\n", foo(4));
fmt.println();
// A more "real" example
type Error enum {
None,
WhyTheNumberThree,
TenIsTooBig,
};
type Entity struct {
name: string,
id: u32,
}
proc some_thing(input: int) -> (result: ^Entity = nil, err = Error.None) {
match {
case input == 3: return err = Error.WhyTheNumberThree;
case input >= 10: return err = Error.TenIsTooBig;
}
var e = new(Entity);
e.id = u32(input);
return result = e;
}
}
proc call_location() {
proc amazing(n: int, using loc = #caller_location) {
fmt.printf("%s(%d:%d) just asked to do something amazing.\n",
fully_pathed_filename, line, column);
fmt.printf("Normal -> %d\n", n);
fmt.printf("Amazing -> %d\n", n+1);
fmt.println();
}
var loc = #location(main);
fmt.println("`main` is located at", loc);
fmt.println("This line is located at", #location());
fmt.println();
amazing(3);
amazing(4, #location(call_location));
// See _preload.odin for the implementations of `assert` and `panic`
}
proc explicit_parametric_polymorphic_procedures() {
// This is how `new` is actually implemented, see _preload.odin
proc alloc_type(T: type) -> ^T {
return ^T(alloc(size_of(T), align_of(T)));
}
var int_ptr = alloc_type(int);
defer free(int_ptr);
int_ptr^ = 137;
fmt.println(int_ptr, int_ptr^);
// Named arguments work too!
var another_ptr = alloc_type(T = f32);
defer free(another_ptr);
proc add(T: type, args: ..T) -> T {
var res: T;
for arg in args {
res += arg;
}
return res;
}
fmt.println("add =", add(int, 1, 2, 3, 4, 5, 6));
proc swap(T: type, a, b: ^T) {
var tmp = a^;
a^ = b^;
b^ = tmp;
}
var a, b: int = 3, 4;
fmt.println("Pre-swap:", a, b);
swap(int, &a, &b);
fmt.println("Post-swap:", a, b);
a, b = b, a; // Or use this syntax for this silly example case
// A more complicated example using subtyping
// Something like this could be used in a game
type Vector2 struct {x, y: f32};
type Entity struct {
using position: Vector2,
flags: u64,
id: u64,
batch_index: u32,
slot_index: u32,
portable_id: u32,
derived: any,
}
type Rock struct {
using entity: ^Entity,
heavy: bool,
}
type Door struct {
using entity: ^Entity,
open: bool,
}
type Monster struct {
using entity: ^Entity,
is_robot: bool,
is_zombie: bool,
}
type EntityManager struct {
batches: [dynamic]^EntityBatch,
next_portable_id: u32,
}
const ENTITIES_PER_BATCH = 16;
type EntityBatch struct {
data: [ENTITIES_PER_BATCH]Entity,
occupied: [ENTITIES_PER_BATCH]bool,
batch_index: u32,
}
proc use_empty_slot(manager: ^EntityManager, batch: ^EntityBatch) -> ^Entity {
for ok, i in batch.occupied {
if ok -> continue;
batch.occupied[i] = true;
var e = &batch.data[i];
e.batch_index = u32(batch.batch_index);
e.slot_index = u32(i);
e.portable_id = manager.next_portable_id;
manager.next_portable_id++;
return e;
}
return nil;
}
proc gen_new_entity(manager: ^EntityManager) -> ^Entity {
for b in manager.batches {
var e = use_empty_slot(manager, b);
if e != nil -> return e;
}
var new_batch = new(EntityBatch);
append(manager.batches, new_batch);
new_batch.batch_index = u32(len(manager.batches)-1);
return use_empty_slot(manager, new_batch);
}
proc new_entity(manager: ^EntityManager, Type: type, x, y: int) -> ^Type {
var result = new(Type);
result.entity = gen_new_entity(manager);
result.derived.data = result;
result.derived.type_info = type_info(Type);
result.position.x = f32(x);
result.position.y = f32(y);
return result;
}
var manager: EntityManager;
var entities: [dynamic]^Entity;
var rock = new_entity(&manager, Rock, 3, 5);
// Named arguments work too!
var door = new_entity(manager = &manager, Type = Door, x = 3, y = 6);
// And named arguments can be any order
var monster = new_entity(
y = 1,
x = 2,
manager = &manager,
Type = Monster,
);
append(entities, rock, door, monster);
// An alternative to `union`s
for entity in entities {
match e in entity.derived {
case Rock: fmt.println("Rock", e.portable_id);
case Door: fmt.println("Door", e.portable_id);
case Monster: fmt.println("Monster", e.portable_id);
}
}
}
proc main() {
general_stuff();
foreign_blocks();
default_arguments();
named_arguments();
default_return_values();
call_location();
explicit_parametric_polymorphic_procedures();
// Command line argument(s)!
// -opt=0,1,2,3
/*************/
/* Questions */
/*************/
/*
I'm questioning if I should change the declaration syntax back to Jai-like
as I've found solutions to the problems I had with it before.
Should I change back to Jai-like declarations or keep with the Pascal-like?
Jai-like
x: int;
x: int = 123;
x := 123;
foo : int : 123;
foo :: 123;
MyInt :: int;
BarType :: proc();
bar :: proc() {
}
foreign lib {
foreign_bar :: proc() ---;
}
Pascal-like
var x: int;
var x: int = 123;
var x = 123;
const foo: int = 123;
const foo = 123;
type MyInt int;
type BarType proc();
proc bar() {
}
foreign lib {
proc foreign_bar();
}
*/
}
/*
proc main() {
var program = "+ + * - /";
var accumulator = 0;
for token in program {
match token {
case '+': accumulator += 1;
case '-': accumulator -= 1;
case '*': accumulator *= 2;
case '/': accumulator /= 2;
case: // Ignore everything else
}
}
fmt.printf("The program \"%s\" calculates the value %d\n",
program, accumulator);
}
*/
-184
View File
@@ -1,184 +0,0 @@
import "fmt.odin";
foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows";
type SOCKET uint;
const INVALID_SOCKET = ~SOCKET(0);
type AF enum i32 {
UNSPEC = 0, // unspecified
UNIX = 1, // local to host (pipes, portals)
INET = 2, // internetwork: UDP, TCP, etc.
IMPLINK = 3, // arpanet imp addresses
PUP = 4, // pup protocols: e.g. BSP
CHAOS = 5, // mit CHAOS protocols
NS = 6, // XEROX NS protocols
ISO = 7, // ISO protocols
OSI = ISO, // OSI is ISO
ECMA = 8, // european computer manufacturers
DATAKIT = 9, // datakit protocols
CCITT = 10, // CCITT protocols, X.25 etc
SNA = 11, // IBM SNA
DECnet = 12, // DECnet
DLI = 13, // Direct data link interface
LAT = 14, // LAT
HYLINK = 15, // NSC Hyperchannel
APPLETALK = 16, // AppleTalk
ROUTE = 17, // Internal Routing Protocol
LINK = 18, // Link layer interface
XTP = 19, // eXpress Transfer Protocol (no AF)
COIP = 20, // connection-oriented IP, aka ST II
CNT = 21, // Computer Network Technology
RTIP = 22, // Help Identify RTIP packets
IPX = 23, // Novell Internet Protocol
SIP = 24, // Simple Internet Protocol
PIP = 25, // Help Identify PIP packets
MAX = 26,
};
const (
SOCK_STREAM = 1;
SOCKET_ERROR = -1;
IPPROTO_TCP = 6;
AI_PASSIVE = 0x0020;
SOMAXCONN = 128;
)
const (
SD_RECEIVE = 0;
SD_SEND = 1;
SD_BOTH = 2;
)
const WSADESCRIPTION_LEN = 256;
const WSASYS_STATUS_LEN = 128;
type WSADATA struct #ordered {
version: i16,
high_version: i16,
// NOTE(bill): This is x64 ordering
max_sockets: u16,
max_udp_dg: u16,
vendor_info: ^u8,
description: [WSADESCRIPTION_LEN+1]u8,
system_status: [WSASYS_STATUS_LEN+1]u8,
}
type addrinfo struct #ordered {
flags: i32,
family: i32,
socktype: i32,
protocol: i32,
addrlen: uint,
canonname: ^u8,
addr: ^sockaddr,
next: ^addrinfo,
}
type sockaddr struct #ordered {
family: u16,
data: [14]u8,
}
foreign ws2 {
proc WSAStartup (version_requested: i16, data: ^WSADATA) -> i32;
proc WSACleanup () -> i32;
proc getaddrinfo (node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32;
proc freeaddrinfo (ai: ^addrinfo);
proc socket (af, type_, protocol: i32) -> SOCKET;
proc closesocket (s: SOCKET) -> i32;
proc bind (s: SOCKET, name: ^sockaddr, name_len: i32) -> i32;
proc listen (s: SOCKET, back_log: i32) -> i32;
proc accept (s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET;
proc recv (s: SOCKET, buf: ^u8, len: i32, flags: i32) -> i32;
proc send (s: SOCKET, buf: ^u8, len: i32, flags: i32) -> i32;
proc shutdown (s: SOCKET, how: i32) -> i32;
proc WSAGetLastError() -> i32;
}
proc to_c_string(s: string) -> ^u8 {
var c_str = make([]u8, len(s)+1);
copy(c_str, []u8(s));
c_str[len(s)] = 0;
return &c_str[0];
}
proc run() {
var (
wsa: WSADATA;
res: ^addrinfo = nil;
hints: addrinfo;
s, client: SOCKET;
)
if WSAStartup(2 | (2 << 8), &wsa) != 0 {
fmt.println("WSAStartup failed: ", WSAGetLastError());
return;
}
defer WSACleanup();
hints.family = i32(AF.INET);
hints.socktype = SOCK_STREAM;
hints.protocol = IPPROTO_TCP;
hints.flags = AI_PASSIVE;
if getaddrinfo(nil, to_c_string("8080"), &hints, &res) != 0 {
fmt.println("getaddrinfo failed: ", WSAGetLastError());
return;
}
defer freeaddrinfo(res);
s = socket(res.family, res.socktype, res.protocol);
if s == INVALID_SOCKET {
fmt.println("socket failed: ", WSAGetLastError());
return;
}
defer closesocket(s);
bind(s, res.addr, i32(res.addrlen));
listen(s, SOMAXCONN);
client = accept(s, nil, 0);
if client == INVALID_SOCKET {
fmt.println("socket failed: ", WSAGetLastError());
return;
}
defer closesocket(client);
var html =
`HTTP/1.1 200 OK
Connection: close
Content-type: text/html
<html>
<head>
<title>Demo Title</title>
</head>
<body>
<h1 style="color: orange;">Odin Server Demo</h1>
</body>
</html>
`;
var buf: [1024]u8;
for {
var bytes = recv(client, &buf[0], i32(len(buf)), 0);
if bytes > 0 {
// fmt.println(string(buf[0..<bytes]))
var bytes_sent = send(client, &html[0], i32(len(html)-1), 0);
if bytes_sent == SOCKET_ERROR {
fmt.println("send failed: ", WSAGetLastError());
return;
}
break;
} else if bytes == 0 {
fmt.println("Connection closing...");
break;
} else {
fmt.println("recv failed: ", WSAGetLastError());
return;
}
}
shutdown(client, SD_SEND);
}
+721 -479
View File
File diff suppressed because it is too large Load Diff
+41 -158
View File
@@ -1,88 +1,95 @@
#shared_global_scope;
#shared_global_scope
proc __multi3(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
const bits_in_dword_2 = size_of(i64) * 4;
const lower_mask = u128(~u64(0) >> bits_in_dword_2);
@(link_name="__multi3")
__multi3 :: proc "c" (a, b: u128) -> u128 {
bits_in_dword_2 :: size_of(i64) * 4;
lower_mask :: u128(~u64(0) >> bits_in_dword_2);
when ODIN_ENDIAN == "bit" {
type TWords raw_union {
when ODIN_ENDIAN == "big" {
TWords :: struct #raw_union {
all: u128,
using _: struct {lo, hi: u64},
};
} else {
type TWords raw_union {
TWords :: struct #raw_union {
all: u128,
using _: struct {hi, lo: u64},
};
}
var r: TWords;
var t: u64;
r: TWords;
t: u64;
r.lo = u64(a & lower_mask) * u64(b & lower_mask);
t = r.lo >> bits_in_dword_2;
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);
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.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);
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;
@(link_name="__umodti3")
__u128_mod :: proc "c" (a, b: u128) -> u128 {
r: u128;
__u128_quo_mod(a, b, &r);
return r;
}
proc __u128_quo(a, b: u128) -> u128 #cc_c #link_name "__udivti3" {
@(link_name="__udivti3")
__u128_quo :: proc "c" (a, b: u128) -> u128 {
return __u128_quo_mod(a, b, nil);
}
proc __i128_mod(a, b: i128) -> i128 #cc_c #link_name "__modti3" {
var r: i128;
@(link_name="__modti3")
__i128_mod :: proc "c" (a, b: i128) -> i128 {
r: i128;
__i128_quo_mod(a, b, &r);
return r;
}
proc __i128_quo(a, b: i128) -> i128 #cc_c #link_name "__divti3" {
@(link_name="__divti3")
__i128_quo :: proc "c" (a, b: i128) -> i128 {
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;
@(link_name="__divmodti4")
__i128_quo_mod :: proc "c" (a, b: i128, rem: ^i128) -> (quo: i128) {
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);
uquo: u128;
urem := __u128_quo_mod(transmute(u128)a, transmute(u128)b, &uquo);
iquo := transmute(i128)uquo;
irem := transmute(i128)urem;
iquo = (iquo~s) - s;
irem = (irem~s) - s;
if rem != nil { rem^ = irem; }
if rem != nil do rem^ = irem;
return iquo;
}
proc __u128_quo_mod(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "__udivmodti4" {
var alo, ahi = u64(a), u64(a>>64);
var blo, bhi = u64(b), u64(b>>64);
@(link_name="__udivmodti4")
__u128_quo_mod :: proc "c" (a, b: u128, rem: ^u128) -> (quo: u128) {
alo := u64(a);
blo := u64(b);
if b == 0 {
if rem != nil { rem^ = 0; }
if rem != nil do rem^ = 0;
return u128(alo/blo);
}
var r, d, x, q: u128 = a, b, 1, 0;
r, d, x, q: u128 = a, b, 1, 0;
for r >= d && (d>>127)&1 == 0 {
x <<= 1;
@@ -98,130 +105,6 @@ proc __u128_quo_mod(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "__u
d >>= 1;
}
if rem != nil { rem^ = r; }
if rem != nil do rem^ = r;
return q;
}
/*
proc __f16_to_f32(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee" {
when true {
// Source: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
const FP32 = raw_union {u: u32, f: f32};
magic, was_infnan: FP32;
magic.u = (254-15) << 23;
was_infnan.u = (127+16) << 23;
hu := transmute(u16, f);
o := FP32{};
o.u = u32(hu & 0x7fff) << 13);
o.f *= magic.f;
if o.f >= was_infnan.f {
o.u |= 255 << 23;
}
o.u |= u32(hu & 0x8000) << 16;
return o.f;
} else {
return 0;
}
}
proc __f32_to_f16(f_: f32) -> f16 #cc_c #no_inline #link_name "__gnu_f2h_ieee" {
when false {
// Source: https://gist.github.com/rygorous/2156668
const FP16 = raw_union {u: u16, f: f16};
const FP32 = raw_union {u: u32, f: f32};
f32infty, f16infty, magic: FP32;
f32infty.u = 255<<23;
f16infty.u = 31<<23;
magic.u = 15<<23;
const sign_mask = u32(0x80000000);
const round_mask = ~u32(0x0fff);
f := transmute(FP32, f_);
o: FP16;
sign := f.u & sign_mask;
f.u ~= sign;
// NOTE all the integer compares in this function can be safely
// compiled into signed compares since all operands are below
// 0x80000000. Important if you want fast straight SSE2 code
// (since there's no unsigned PCMPGTD).
if f.u >= f32infty.u { // Inf or NaN (all exponent bits set)
o.u = f.u > f32infty.u ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf
} else { // (De)normalized number or zero
f.u &= round_mask;
f.f *= magic.f;
f.u -= round_mask;
if f.u > f16infty.u {
f.u = f16infty.u; // Clamp to signed infinity if overflowed
}
o.u = u16(f.u >> 13); // Take the bits!
}
o.u |= u16(sign >> 16);
return o.f;
} else {
f := transmute(u32, f_);
h: u16;
hs, he, hf: u16;
fs := (f >> 31) & 1;
fe := (f >> 23) & 0b1111_1111;
ff := (f >> 0) & 0b0111_1111_1111_1111_1111_1111;
add_one := false;
if (fe == 0) {
he = 0;
} else if (fe == 255) {
he = 31;
hf = ff != 0 ? 0x200 : 0;
} else {
ne := fe - 127 + 15;
if ne >= 31 {
he = 31;
} else if ne <= 0 {
if (14-ne) <= 24 {
mant := ff | 0x800000;
hf = u16(mant >> (14-ne));
if (mant >> (13-ne)) & 1 != 0 {
add_one = true;
}
}
} else {
he = u16(ne);
hf = u16(ff >> 13);
if ff&0x1000 != 0 {
add_one = true;
}
}
}
hs = u16(hs);
h |= (he&0b0001_1111)<<10;
h |= (hf&0b0011_1111_1111);
if add_one {
h++;
}
h |= (hs&1) << 15;
return transmute(f16, h);
}
}
proc __f64_to_f16(f: f64) -> f16 #cc_c #no_inline #link_name "__truncdfhf2" {
return __f32_to_f16(f32(f));
}
proc __f16_to_f64(f: f16) -> f64 #cc_c #no_inline {
return f64(__f16_to_f32(f));
}
*/
+36 -34
View File
@@ -1,100 +1,102 @@
// 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
when ODIN_OS == "windows" {
import win32 "core:sys/windows.odin"
}
_ :: 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(); }
yield_thread :: proc() { win32.mm_pause(); }
mfence :: proc() { win32.read_write_barrier(); }
sfence :: proc() { win32.write_barrier(); }
lfence :: proc() { win32.read_barrier(); }
proc load(a: ^i32) -> i32 {
load :: proc(a: ^i32) -> i32 {
return a^;
}
proc store(a: ^i32, value: i32) {
store :: proc(a: ^i32, value: i32) {
a^ = value;
}
proc compare_exchange(a: ^i32, expected, desired: i32) -> i32 {
compare_exchange :: proc(a: ^i32, expected, desired: i32) -> i32 {
return win32.interlocked_compare_exchange(a, desired, expected);
}
proc exchanged(a: ^i32, desired: i32) -> i32 {
exchanged :: proc(a: ^i32, desired: i32) -> i32 {
return win32.interlocked_exchange(a, desired);
}
proc fetch_add(a: ^i32, operand: i32) -> i32 {
fetch_add :: proc(a: ^i32, operand: i32) -> i32 {
return win32.interlocked_exchange_add(a, operand);
}
proc fetch_and(a: ^i32, operand: i32) -> i32 {
fetch_and :: proc(a: ^i32, operand: i32) -> i32 {
return win32.interlocked_and(a, operand);
}
proc fetch_or(a: ^i32, operand: i32) -> i32 {
fetch_or :: proc(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;
spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange(a, 1, 0);
counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter++;
counter += 1;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
}
return old_value == 0;
}
proc spin_unlock(a: ^i32) {
spin_unlock :: proc(a: ^i32) {
store(a, 0);
mfence();
}
proc try_acquire_lock(a: ^i32) -> bool {
try_acquire_lock :: proc(a: ^i32) -> bool {
yield_thread();
var old_value = compare_exchange(a, 1, 0);
old_value := compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}
proc load(a: ^i64) -> i64 {
load :: proc(a: ^i64) -> i64 {
return a^;
}
proc store(a: ^i64, value: i64) {
store :: proc(a: ^i64, value: i64) {
a^ = value;
}
proc compare_exchange(a: ^i64, expected, desired: i64) -> i64 {
compare_exchange :: proc(a: ^i64, expected, desired: i64) -> i64 {
return win32.interlocked_compare_exchange64(a, desired, expected);
}
proc exchanged(a: ^i64, desired: i64) -> i64 {
exchanged :: proc(a: ^i64, desired: i64) -> i64 {
return win32.interlocked_exchange64(a, desired);
}
proc fetch_add(a: ^i64, operand: i64) -> i64 {
fetch_add :: proc(a: ^i64, operand: i64) -> i64 {
return win32.interlocked_exchange_add64(a, operand);
}
proc fetch_and(a: ^i64, operand: i64) -> i64 {
fetch_and :: proc(a: ^i64, operand: i64) -> i64 {
return win32.interlocked_and64(a, operand);
}
proc fetch_or(a: ^i64, operand: i64) -> i64 {
fetch_or :: proc(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;
spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange(a, 1, 0);
counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter++;
counter += 1;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
}
return old_value == 0;
}
proc spin_unlock(a: ^i64) {
spin_unlock :: proc(a: ^i64) {
store(a, 0);
mfence();
}
proc try_acquire_lock(a: ^i64) -> bool {
try_acquire_lock :: proc(a: ^i64) -> bool {
yield_thread();
var old_value = compare_exchange(a, 1, 0);
old_value := compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}
+277 -236
View File
@@ -1,287 +1,328 @@
const (
U8_MIN = u8(0);
U16_MIN = u16(0);
U32_MIN = u32(0);
U64_MIN = u64(0);
U128_MIN = u128(0);
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);
U8_MAX = ~u8(0);
U16_MAX = ~u16(0);
U32_MAX = ~u32(0);
U64_MAX = ~u64(0);
U128_MAX = ~u128(0);
I8_MIN :: i8( ~u8(0) >> 1);
I16_MIN :: i16( ~u16(0) >> 1);
I32_MIN :: i32( ~u32(0) >> 1);
I64_MIN :: i64( ~u64(0) >> 1);
I128_MIN :: i128(~u128(0) >> 1);
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))); } }
I8_MAX :: -I8_MIN - 1;
I16_MAX :: -I16_MIN - 1;
I32_MAX :: -I32_MIN - 1;
I64_MAX :: -I64_MIN - 1;
I128_MAX :: -I128_MIN - 1;
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";
@(link_name="llvm.ctpop.i8") __llvm_ctpop :: proc(u8) -> u8 ---;
@(link_name="llvm.ctpop.i8") __llvm_ctpop :: proc(i8) -> i8 ---;
@(link_name="llvm.ctpop.i16") __llvm_ctpop :: proc(u16) -> u16 ---;
@(link_name="llvm.ctpop.i16") __llvm_ctpop :: proc(i16) -> i16 ---;
@(link_name="llvm.ctpop.i32") __llvm_ctpop :: proc(u32) -> u32 ---;
@(link_name="llvm.ctpop.i32") __llvm_ctpop :: proc(i32) -> i32 ---;
@(link_name="llvm.ctpop.i64") __llvm_ctpop :: proc(u64) -> u64 ---;
@(link_name="llvm.ctpop.i64") __llvm_ctpop :: proc(i64) -> i64 ---;
@(link_name="llvm.ctpop.i128") __llvm_ctpop :: proc(u128) -> u128 ---;
@(link_name="llvm.ctpop.i128") __llvm_ctpop :: proc(i128) -> i128 ---;
@(link_name="llvm.ctlz.i8") __llvm_ctlz :: proc(u8, bool) -> u8 ---;
@(link_name="llvm.ctlz.i8") __llvm_ctlz :: proc(i8, bool) -> i8 ---;
@(link_name="llvm.ctlz.i16") __llvm_ctlz :: proc(u16, bool) -> u16 ---;
@(link_name="llvm.ctlz.i16") __llvm_ctlz :: proc(i16, bool) -> i16 ---;
@(link_name="llvm.ctlz.i32") __llvm_ctlz :: proc(u32, bool) -> u32 ---;
@(link_name="llvm.ctlz.i32") __llvm_ctlz :: proc(i32, bool) -> i32 ---;
@(link_name="llvm.ctlz.i64") __llvm_ctlz :: proc(u64, bool) -> u64 ---;
@(link_name="llvm.ctlz.i64") __llvm_ctlz :: proc(i64, bool) -> i64 ---;
@(link_name="llvm.ctlz.i128") __llvm_ctlz :: proc(u128, bool) -> u128 ---;
@(link_name="llvm.ctlz.i128") __llvm_ctlz :: proc(i128, bool) -> i128 ---;
@(link_name="llvm.cttz.i8") __llvm_cttz :: proc(u8, bool) -> u8 ---;
@(link_name="llvm.cttz.i8") __llvm_cttz :: proc(i8, bool) -> i8 ---;
@(link_name="llvm.cttz.i16") __llvm_cttz :: proc(u16, bool) -> u16 ---;
@(link_name="llvm.cttz.i16") __llvm_cttz :: proc(i16, bool) -> i16 ---;
@(link_name="llvm.cttz.i32") __llvm_cttz :: proc(u32, bool) -> u32 ---;
@(link_name="llvm.cttz.i32") __llvm_cttz :: proc(i32, bool) -> i32 ---;
@(link_name="llvm.cttz.i64") __llvm_cttz :: proc(u64, bool) -> u64 ---;
@(link_name="llvm.cttz.i64") __llvm_cttz :: proc(i64, bool) -> i64 ---;
@(link_name="llvm.cttz.i128") __llvm_cttz :: proc(u128, bool) -> u128 ---;
@(link_name="llvm.cttz.i128") __llvm_cttz :: proc(i128, bool) -> i128 ---;
@(link_name="llvm.bitreverse.i8") __llvm_bitreverse :: proc(u8) -> u8 ---;
@(link_name="llvm.bitreverse.i8") __llvm_bitreverse :: proc(i8) -> i8 ---;
@(link_name="llvm.bitreverse.i16") __llvm_bitreverse :: proc(u16) -> u16 ---;
@(link_name="llvm.bitreverse.i16") __llvm_bitreverse :: proc(i16) -> i16 ---;
@(link_name="llvm.bitreverse.i32") __llvm_bitreverse :: proc(u32) -> u32 ---;
@(link_name="llvm.bitreverse.i32") __llvm_bitreverse :: proc(i32) -> i32 ---;
@(link_name="llvm.bitreverse.i64") __llvm_bitreverse :: proc(u64) -> u64 ---;
@(link_name="llvm.bitreverse.i64") __llvm_bitreverse :: proc(i64) -> i64 ---;
@(link_name="llvm.bitreverse.i128") __llvm_bitreverse :: proc(u128) -> u128 ---;
@(link_name="llvm.bitreverse.i128") __llvm_bitreverse :: proc(i128) -> i128 ---;
@(link_name="llvm.bswap.i16") byte_swap :: proc(u16) -> u16 ---;
@(link_name="llvm.bswap.i16") byte_swap :: proc(i16) -> i16 ---;
@(link_name="llvm.bswap.i32") byte_swap :: proc(u32) -> u32 ---;
@(link_name="llvm.bswap.i32") byte_swap :: proc(i32) -> i32 ---;
@(link_name="llvm.bswap.i64") byte_swap :: proc(u64) -> u64 ---;
@(link_name="llvm.bswap.i64") byte_swap :: proc(i64) -> i64 ---;
@(link_name="llvm.bswap.i128") byte_swap :: proc(u128) -> u128 ---;
@(link_name="llvm.bswap.i128") byte_swap :: proc(i128) -> 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))); } }
byte_swap :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(byte_swap(u32(i))); } else { return uint(byte_swap(u64(i))); } }
byte_swap :: proc(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); } }
count_ones :: proc(i: u8) -> u8 { return __llvm_ctpop(i); }
count_ones :: proc(i: i8) -> i8 { return __llvm_ctpop(i); }
count_ones :: proc(i: u16) -> u16 { return __llvm_ctpop(i); }
count_ones :: proc(i: i16) -> i16 { return __llvm_ctpop(i); }
count_ones :: proc(i: u32) -> u32 { return __llvm_ctpop(i); }
count_ones :: proc(i: i32) -> i32 { return __llvm_ctpop(i); }
count_ones :: proc(i: u64) -> u64 { return __llvm_ctpop(i); }
count_ones :: proc(i: i64) -> i64 { return __llvm_ctpop(i); }
count_ones :: proc(i: u128) -> u128 { return __llvm_ctpop(i); }
count_ones :: proc(i: i128) -> i128 { return __llvm_ctpop(i); }
count_ones :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(count_ones(u32(i))); } else { return uint(count_ones(u64(i))); } }
count_ones :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(count_ones(i32(i))); } else { return int(count_ones(i64(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); } }
count_zeros :: proc(i: u8) -> u8 { return 8 - count_ones(i); }
count_zeros :: proc(i: i8) -> i8 { return 8 - count_ones(i); }
count_zeros :: proc(i: u16) -> u16 { return 16 - count_ones(i); }
count_zeros :: proc(i: i16) -> i16 { return 16 - count_ones(i); }
count_zeros :: proc(i: u32) -> u32 { return 32 - count_ones(i); }
count_zeros :: proc(i: i32) -> i32 { return 32 - count_ones(i); }
count_zeros :: proc(i: u64) -> u64 { return 64 - count_ones(i); }
count_zeros :: proc(i: i64) -> i64 { return 64 - count_ones(i); }
count_zeros :: proc(i: u128) -> u128 { return 128 - count_ones(i); }
count_zeros :: proc(i: i128) -> i128 { return 128 - count_ones(i); }
count_zeros :: proc(i: uint) -> uint { return 8*size_of(uint) - count_ones(i); }
count_zeros :: proc(i: int) -> int { return 8*size_of(int) - count_ones(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); } }
rotate_left :: proc(i: u8, s: uint) -> u8 { return (i << s)|(i >> (8*size_of(u8) - s)); }
rotate_left :: proc(i: i8, s: uint) -> i8 { return (i << s)|(i >> (8*size_of(i8) - s)); }
rotate_left :: proc(i: u16, s: uint) -> u16 { return (i << s)|(i >> (8*size_of(u16) - s)); }
rotate_left :: proc(i: i16, s: uint) -> i16 { return (i << s)|(i >> (8*size_of(i16) - s)); }
rotate_left :: proc(i: u32, s: uint) -> u32 { return (i << s)|(i >> (8*size_of(u32) - s)); }
rotate_left :: proc(i: i32, s: uint) -> i32 { return (i << s)|(i >> (8*size_of(i32) - s)); }
rotate_left :: proc(i: u64, s: uint) -> u64 { return (i << s)|(i >> (8*size_of(u64) - s)); }
rotate_left :: proc(i: i64, s: uint) -> i64 { return (i << s)|(i >> (8*size_of(i64) - s)); }
rotate_left :: proc(i: u128, s: uint) -> u128 { return (i << s)|(i >> (8*size_of(u128) - s)); }
rotate_left :: proc(i: i128, s: uint) -> i128 { return (i << s)|(i >> (8*size_of(i128) - s)); }
rotate_left :: proc(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)); } }
rotate_left :: proc(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 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) {
rotate_right :: proc(i: u8, s: uint) -> u8 { return (i >> s)|(i << (8*size_of(u8) - s)); }
rotate_right :: proc(i: i8, s: uint) -> i8 { return (i >> s)|(i << (8*size_of(i8) - s)); }
rotate_right :: proc(i: u16, s: uint) -> u16 { return (i >> s)|(i << (8*size_of(u16) - s)); }
rotate_right :: proc(i: i16, s: uint) -> i16 { return (i >> s)|(i << (8*size_of(i16) - s)); }
rotate_right :: proc(i: u32, s: uint) -> u32 { return (i >> s)|(i << (8*size_of(u32) - s)); }
rotate_right :: proc(i: i32, s: uint) -> i32 { return (i >> s)|(i << (8*size_of(i32) - s)); }
rotate_right :: proc(i: u64, s: uint) -> u64 { return (i >> s)|(i << (8*size_of(u64) - s)); }
rotate_right :: proc(i: i64, s: uint) -> i64 { return (i >> s)|(i << (8*size_of(i64) - s)); }
rotate_right :: proc(i: u128, s: uint) -> u128 { return (i >> s)|(i << (8*size_of(u128) - s)); }
rotate_right :: proc(i: i128, s: uint) -> i128 { return (i >> s)|(i << (8*size_of(i128) - s)); }
rotate_right :: proc(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)); } }
rotate_right :: proc(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)); } }
leading_zeros :: proc(i: u8) -> u8 { return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: i8) -> i8 { return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: u16) -> u16 { return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: i16) -> i16 { return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: u32) -> u32 { return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: i32) -> i32 { return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: u64) -> u64 { return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: i64) -> i64 { return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: u128) -> u128 { return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: i128) -> i128 { return __llvm_ctlz(i, false); }
leading_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(leading_zeros(u32(i))); } else { return uint(leading_zeros(u64(i))); } }
leading_zeros :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(leading_zeros(i32(i))); } else { return int(leading_zeros(i64(i))); } }
trailing_zeros :: proc(i: u8) -> u8 { return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: i8) -> i8 { return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: u16) -> u16 { return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: i16) -> i16 { return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: u32) -> u32 { return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: i32) -> i32 { return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: u64) -> u64 { return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: i64) -> i64 { return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: u128) -> u128 { return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: i128) -> i128 { return __llvm_cttz(i, false); }
trailing_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(trailing_zeros(u32(i))); } else { return uint(trailing_zeros(u64(i))); } }
trailing_zeros :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(trailing_zeros(i32(i))); } else { return int(trailing_zeros(i64(i))); } }
reverse_bits :: proc(i: u8) -> u8 { return __llvm_bitreverse(i); }
reverse_bits :: proc(i: i8) -> i8 { return __llvm_bitreverse(i); }
reverse_bits :: proc(i: u16) -> u16 { return __llvm_bitreverse(i); }
reverse_bits :: proc(i: i16) -> i16 { return __llvm_bitreverse(i); }
reverse_bits :: proc(i: u32) -> u32 { return __llvm_bitreverse(i); }
reverse_bits :: proc(i: i32) -> i32 { return __llvm_bitreverse(i); }
reverse_bits :: proc(i: u64) -> u64 { return __llvm_bitreverse(i); }
reverse_bits :: proc(i: i64) -> i64 { return __llvm_bitreverse(i); }
reverse_bits :: proc(i: u128) -> u128 { return __llvm_bitreverse(i); }
reverse_bits :: proc(i: i128) -> i128 { return __llvm_bitreverse(i); }
reverse_bits :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(reverse_bits(u32(i))); } else { return uint(reverse_bits(u64(i))); } }
reverse_bits :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(reverse_bits(i32(i))); } else { return int(reverse_bits(i64(i))); } }
from_be :: proc(i: u8) -> u8 { return i; }
from_be :: proc(i: i8) -> i8 { return i; }
from_be :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_be :: proc(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: u8) -> u8 { return i; }
from_le :: proc(i: i8) -> i8 { return i; }
from_le :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
from_le :: proc(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: u8) -> u8 { return i; }
to_be :: proc(i: i8) -> i8 { return i; }
to_be :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_be :: proc(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: u8) -> u8 { return i; }
to_le :: proc(i: i8) -> i8 { return i; }
to_le :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
to_le :: proc(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
overflowing_add :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i128") op :: proc(u128, u128) -> (u128, bool) ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i128") op :: proc(i128, i128) -> (i128, bool) ---; return op(lhs, rhs); }
overflowing_add :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
var x, ok = overflowing_add(u32(lhs), u32(rhs));
x, ok := overflowing_add(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
var x, ok = overflowing_add(u64(lhs), u64(rhs));
x, ok := overflowing_add(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
proc overflowing_add(lhs, rhs: int) -> (int, bool) {
overflowing_add :: proc(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
var x, ok = overflowing_add(i32(lhs), i32(rhs));
x, ok := overflowing_add(i32(lhs), i32(rhs));
return int(x), ok;
} else {
var x, ok = overflowing_add(i64(lhs), i64(rhs));
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) {
overflowing_sub :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i128") op :: proc(u128, u128) -> (u128, bool) ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i128") op :: proc(i128, i128) -> (i128, bool) ---; return op(lhs, rhs); }
overflowing_sub :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
var x, ok = overflowing_sub(u32(lhs), u32(rhs));
x, ok := overflowing_sub(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
var x, ok = overflowing_sub(u64(lhs), u64(rhs));
x, ok := overflowing_sub(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
proc overflowing_sub(lhs, rhs: int) -> (int, bool) {
overflowing_sub :: proc(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
var x, ok = overflowing_sub(i32(lhs), i32(rhs));
x, ok := overflowing_sub(i32(lhs), i32(rhs));
return int(x), ok;
} else {
var x, ok = overflowing_sub(i64(lhs), i64(rhs));
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) {
overflowing_mul :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i128") op :: proc(u128, u128) -> (u128, bool) ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i128") op :: proc(i128, i128) -> (i128, bool) ---; return op(lhs, rhs); }
overflowing_mul :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) {
var x, ok = overflowing_mul(u32(lhs), u32(rhs));
x, ok := overflowing_mul(u32(lhs), u32(rhs));
return uint(x), ok;
} else {
var x, ok = overflowing_mul(u64(lhs), u64(rhs));
x, ok := overflowing_mul(u64(lhs), u64(rhs));
return uint(x), ok;
}
}
proc overflowing_mul(lhs, rhs: int) -> (int, bool) {
overflowing_mul :: proc(lhs, rhs: int) -> (int, bool) {
when size_of(int) == size_of(i32) {
var x, ok = overflowing_mul(i32(lhs), i32(rhs));
x, ok := overflowing_mul(i32(lhs), i32(rhs));
return int(x), ok;
} else {
var x, ok = overflowing_mul(i64(lhs), i64(rhs));
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; }
is_power_of_two :: proc(i: u8) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: i8) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: u16) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: i16) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: u32) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: i32) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: u64) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: i64) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: u128) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: i128) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0; }
is_power_of_two :: proc(i: int) -> bool { return i > 0 && (i & (i-1)) == 0; }
+38
View File
@@ -0,0 +1,38 @@
CHAR_BIT :: 8;
c_bool :: #alias bool;
c_char :: #alias u8;
c_byte :: #alias u8;
c_schar :: #alias i8;
c_uchar :: #alias u8;
c_short :: #alias i16;
c_ushort :: #alias u16;
c_int :: #alias i32;
c_uint :: #alias u32;
when ODIN_OS == "windows" || size_of(rawptr) == 4 {
c_long :: #alias i32;
} else {
c_long :: #alias i64;
}
when ODIN_OS == "windows" || size_of(rawptr) == 4 {
c_ulong :: #alias u32;
} else {
c_ulong :: #alias u64;
}
c_longlong :: #alias i64;
c_ulonglong :: #alias u64;
c_float :: #alias f32;
c_double :: #alias f64;
c_complex_float :: #alias complex64;
c_complex_double :: #alias complex128;
_ :: compile_assert(size_of(uintptr) == size_of(int));
c_size_t :: #alias uint;
c_ssize_t :: #alias int;
c_ptrdiff_t :: #alias int;
c_uintptr_t :: #alias uintptr;
c_intptr_t :: #alias int;
+73 -76
View File
@@ -1,54 +1,53 @@
// #import "fmt.odin";
// Multiple precision decimal numbers
// NOTE: This is only for floating point printing and nothing else
type Decimal struct {
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';
decimal_to_string :: proc(buf: []u8, a: ^Decimal) -> string {
digit_zero :: proc(buf: []u8) -> int {
for _, i in buf do buf[i] = '0';
return len(buf);
}
var n = 10 + a.count + abs(a.decimal_point);
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];
buf = buf[0..n];
if a.count == 0 {
buf[0] = '0';
return string(buf[0..<1]);
return string(buf[0..1]);
}
var w = 0;
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]);
buf[w] = '0'; w += 1;
buf[w] = '.'; w += 1;
w += digit_zero(buf[w .. w-a.decimal_point]);
w += copy(buf[w..], a.digits[0..a.count]);
} 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]);
w += copy(buf[w..], a.digits[0..a.decimal_point]);
buf[w] = '.'; w += 1;
w += copy(buf[w..], a.digits[a.decimal_point .. a.count]);
} else {
w += copy(buf[w..], a.digits[0..<a.count]);
w += digit_zero(buf[w ..< w+a.decimal_point-a.count]);
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]);
return string(buf[0..w]);
}
// trim trailing zeros
proc trim(a: ^Decimal) {
trim :: proc(a: ^Decimal) {
for a.count > 0 && a.digits[a.count-1] == '0' {
a.count--;
a.count -= 1;
}
if a.count == 0 {
a.decimal_point = 0;
@@ -56,21 +55,21 @@ proc trim(a: ^Decimal) {
}
proc assign(a: ^Decimal, i: u64) {
var buf: [32]u8;
var n = 0;
assign :: proc(a: ^Decimal, i: u64) {
buf: [64]u8;
n := 0;
for i > 0 {
var j = i/10;
j := i/10;
i -= 10*j;
buf[n] = u8('0'+i);
n++;
n += 1;
i = j;
}
a.count = 0;
for n--; n >= 0; n-- {
for n -= 1; n >= 0; n -= 1 {
a.digits[a.count] = buf[n];
a.count++;
a.count += 1;
}
a.decimal_point = a.count;
trim(a);
@@ -78,12 +77,12 @@ proc assign(a: ^Decimal, i: u64) {
proc shift_right(a: ^Decimal, k: uint) {
var r = 0; // read index
var w = 0; // write index
shift_right :: proc(a: ^Decimal, k: uint) {
r := 0; // read index
w := 0; // write index
var n: uint;
for ; n>>k == 0; r++ {
n: uint;
for ; n>>k == 0; r += 1 {
if r >= a.count {
if n == 0 {
// Just in case
@@ -92,32 +91,32 @@ proc shift_right(a: ^Decimal, k: uint) {
}
for n>>k == 0 {
n = n * 10;
r++;
r += 1;
}
break;
}
var c = uint(a.digits[r]);
c := uint(a.digits[r]);
n = n*10 + c - '0';
}
a.decimal_point -= r-1;
var mask: uint = (1<<k) - 1;
mask: uint = (1<<k) - 1;
for ; r < a.count; r++ {
var c = uint(a.digits[r]);
var dig = n>>k;
for ; r < a.count; r += 1 {
c := uint(a.digits[r]);
dig := n>>k;
n &= mask;
a.digits[w] = u8('0' + dig);
w++;
w += 1;
n = n*10 + c - '0';
}
for n > 0 {
var dig = n>>k;
dig := n>>k;
n &= mask;
if w < len(a.digits) {
a.digits[w] = u8('0' + dig);
w++;
w += 1;
} else if dig > 0 {
a.trunc = true;
}
@@ -129,18 +128,18 @@ proc shift_right(a: ^Decimal, k: uint) {
trim(a);
}
proc shift_left(a: ^Decimal, k: uint) {
var delta = int(k/4);
shift_left :: proc(a: ^Decimal, k: uint) {
delta := int(k/4);
var r = a.count; // read index
var w = a.count+delta; // write index
r := a.count; // read index
w := a.count+delta; // write index
var n: uint;
for r--; r >= 0; r-- {
n: uint;
for r -= 1; r >= 0; r -= 1 {
n += (uint(a.digits[r]) - '0') << k;
var quo = n/10;
var rem = n - 10*quo;
w--;
quo := n/10;
rem := n - 10*quo;
w -= 1;
if w < len(a.digits) {
a.digits[w] = u8('0' + rem);
} else if rem != 0 {
@@ -150,9 +149,9 @@ proc shift_left(a: ^Decimal, k: uint) {
}
for n > 0 {
var quo = n/10;
var rem = n - 10*quo;
w--;
quo := n/10;
rem := n - 10*quo;
w -= 1;
if 0 <= w && w < len(a.digits) {
a.digits[w] = u8('0' + rem);
} else if rem != 0 {
@@ -167,13 +166,11 @@ proc shift_left(a: ^Decimal, k: uint) {
trim(a);
}
proc shift(a: ^Decimal, k: int) {
const (
uint_size = 8*size_of(uint);
max_shift = uint_size-4;
)
shift :: proc(a: ^Decimal, k: int) {
uint_size :: 8*size_of(uint);
max_shift :: uint_size-4;
match {
switch {
case a.count == 0:
// no need to update
case k > 0:
@@ -193,17 +190,17 @@ proc shift(a: ^Decimal, k: int) {
}
}
proc can_round_up(a: ^Decimal, nd: int) -> bool {
can_round_up :: proc(a: ^Decimal, nd: int) -> bool {
if nd < 0 || nd >= a.count { return false ; }
if a.digits[nd] == '5' && nd+1 == a.count {
if a.trunc -> return true;
if a.trunc do return true;
return nd > 0 && (a.digits[nd-1]-'0')%2 != 0;
}
return a.digits[nd] >= '5';
}
proc round(a: ^Decimal, nd: int) {
round :: proc(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
if can_round_up(a, nd) {
round_up(a, nd);
@@ -212,12 +209,12 @@ proc round(a: ^Decimal, nd: int) {
}
}
proc round_up(a: ^Decimal, nd: int) {
round_up :: proc(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]++;
for i := nd-1; i >= 0; i -= 1 {
if c := a.digits[i]; c < '9' {
a.digits[i] += 1;
a.count = i+1;
return;
}
@@ -226,10 +223,10 @@ proc round_up(a: ^Decimal, nd: int) {
// Number is just 9s
a.digits[0] = '1';
a.count = 1;
a.decimal_point++;
a.decimal_point += 1;
}
proc round_down(a: ^Decimal, nd: int) {
round_down :: proc(a: ^Decimal, nd: int) {
if nd < 0 || nd >= a.count { return; }
a.count = nd;
trim(a);
@@ -237,21 +234,21 @@ proc round_down(a: ^Decimal, nd: int) {
// Extract integer part, rounded appropriately. There are no guarantees about overflow.
proc rounded_integer(a: ^Decimal) -> u64 {
rounded_integer :: proc(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++ {
i: int = 0;
n: u64 = 0;
m := min(a.decimal_point, a.count);
for ; i < m; i += 1 {
n = n*10 + u64(a.digits[i]-'0');
}
for ; i < a.decimal_point; i++ {
for ; i < a.decimal_point; i += 1 {
n *= 10;
}
if can_round_up(a, a.decimal_point) {
n++;
n += 1;
}
return n;
}
+467 -443
View File
File diff suppressed because it is too large Load Diff
+59 -57
View File
@@ -1,65 +1,73 @@
proc crc32(data: []u8) -> u32 {
var result = ~u32(0);
import "core:mem.odin"
adler32 :: proc(data: []u8) -> u32 {
ADLER_CONST :: 65521;
a, b: u32 = 1, 0;
for x in data {
a = (a + u32(x)) % ADLER_CONST;
b = (b + a) % ADLER_CONST;
}
return (b << 16) | a;
}
crc32 :: proc(data: []u8) -> u32 {
result := ~u32(0);
for b in data {
result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff];
}
return ~result;
}
proc crc64(data: []u8) -> u64 {
var result = ~u64(0);
crc64 :: proc(data: []u8) -> u64 {
result := ~u64(0);
for b in data {
result = result>>8 ~ _crc64_table[(result ~ u64(b)) & 0xff];
}
return ~result;
}
proc fnv32(data: []u8) -> u32 {
var h: u32 = 0x811c9dc5;
fnv32 :: proc(data: []u8) -> u32 {
h: u32 = 0x811c9dc5;
for b in data {
h = (h * 0x01000193) ~ u32(b);
}
return h;
}
proc fnv64(data: []u8) -> u64 {
var h: u64 = 0xcbf29ce484222325;
fnv64 :: proc(data: []u8) -> u64 {
h: u64 = 0xcbf29ce484222325;
for b in data {
h = (h * 0x100000001b3) ~ u64(b);
}
return h;
}
proc fnv32a(data: []u8) -> u32 {
var h: u32 = 0x811c9dc5;
fnv32a :: proc(data: []u8) -> u32 {
h: u32 = 0x811c9dc5;
for b in data {
h = (h ~ u32(b)) * 0x01000193;
}
return h;
}
proc fnv64a(data: []u8) -> u64 {
var h: u64 = 0xcbf29ce484222325;
fnv64a :: proc(data: []u8) -> u64 {
h: u64 = 0xcbf29ce484222325;
for b in data {
h = (h ~ u64(b)) * 0x100000001b3;
}
return h;
}
proc murmur32(data: []u8) -> u32 {
const (
c1_32: u32 = 0xcc9e2d51;
c2_32: u32 = 0x1b873593;
)
murmur32 :: proc(data: []u8) -> u32 {
c1_32: u32 : 0xcc9e2d51;
c2_32: u32 : 0x1b873593;
var (
h1: u32 = 0;
nblocks = len(data)/4;
p = &data[0];
p1 = p + 4*nblocks;
)
h1: u32 = 0;
nblocks := len(data)/4;
p := &data[0];
p1 := p + 4*nblocks;
for ; p < p1; p += 4 {
var k1 = ^u32(p)^;
k1 := (cast(^u32)p)^;
k1 *= c1_32;
k1 = (k1 << 15) | (k1 >> 17);
@@ -70,9 +78,9 @@ proc murmur32(data: []u8) -> u32 {
h1 = h1*5 + 0xe6546b64;
}
var tail = data[nblocks*4 ..];
var k1: u32;
match len(tail)&3 {
tail := data[nblocks*4 ..];
k1: u32;
switch len(tail)&3 {
case 3:
k1 ~= u32(tail[2]) << 16;
fallthrough;
@@ -98,20 +106,18 @@ proc murmur32(data: []u8) -> u32 {
return h1;
}
proc murmur64(data: []u8) -> u64 {
const SEED = 0x9747b28c;
murmur64 :: proc(data: []u8) -> u64 {
SEED :: 0x9747b28c;
when size_of(int) == 8 {
const (
m = 0xc6a4a7935bd1e995;
r = 47;
)
m :: 0xc6a4a7935bd1e995;
r :: 47;
var h: u64 = SEED ~ (u64(len(data)) * m);
var data64 = slice_ptr(^u64(&data[0]), len(data)/size_of(u64));
h: u64 = SEED ~ (u64(len(data)) * m);
data64 := mem.slice_ptr(cast(^u64)&data[0], len(data)/size_of(u64));
for _, i in data64 {
var k = data64[i];
k := data64[i];
k *= m;
k ~= k>>r;
@@ -121,7 +127,7 @@ proc murmur64(data: []u8) -> u64 {
h *= m;
}
match len(data)&7 {
switch len(data)&7 {
case 7: h ~= u64(data[6]) << 48; fallthrough;
case 6: h ~= u64(data[5]) << 40; fallthrough;
case 5: h ~= u64(data[4]) << 32; fallthrough;
@@ -139,22 +145,18 @@ proc murmur64(data: []u8) -> u64 {
return h;
} else {
const (
m = 0x5bd1e995;
r = 24;
)
m :: 0x5bd1e995;
r :: 24;
var (
h1 = u32(SEED) ~ u32(len(data));
h2 = u32(SEED) >> 32;
data32 = slice_ptr(^u32(&data[0]), len(data)/size_of(u32));
len = len(data);
i = 0;
)
h1 := u32(SEED) ~ u32(len(data));
h2 := u32(SEED) >> 32;
data32 := mem.slice_ptr(cast(^u32)&data[0], len(data)/size_of(u32));
len := len(data);
i := 0;
for len >= 8 {
var k1, k2: u32;
k1 = data32[i]; i++;
k1, k2: u32;
k1 = data32[i]; i += 1;
k1 *= m;
k1 ~= k1>>r;
k1 *= m;
@@ -162,7 +164,7 @@ proc murmur64(data: []u8) -> u64 {
h1 ~= k1;
len -= 4;
k2 = data32[i]; i++;
k2 = data32[i]; i += 1;
k2 *= m;
k2 ~= k2>>r;
k2 *= m;
@@ -172,8 +174,8 @@ proc murmur64(data: []u8) -> u64 {
}
if len >= 4 {
var k1: u32;
k1 = data32[i]; i++;
k1: u32;
k1 = data32[i]; i += 1;
k1 *= m;
k1 ~= k1>>r;
k1 *= m;
@@ -183,8 +185,8 @@ proc murmur64(data: []u8) -> u64 {
}
// TODO(bill): Fix this
#no_bounds_check var data8 = slice_to_bytes(data32[i..])[0..<3];
match len {
#no_bounds_check data8 := slice_to_bytes(data32[i..])[..3];
switch len {
case 3:
h2 ~= u32(data8[2]) << 16;
fallthrough;
@@ -210,7 +212,7 @@ proc murmur64(data: []u8) -> u64 {
}
var _crc32_table = [256]u32{
_crc32_table := [256]u32{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -276,7 +278,7 @@ var _crc32_table = [256]u32{
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
var _crc64_table = [256]u64{
_crc64_table := [256]u64{
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
+186 -208
View File
@@ -1,97 +1,104 @@
const (
TAU = 6.28318530717958647692528676655900576;
PI = 3.14159265358979323846264338327950288;
ONE_OVER_TAU = 0.636619772367581343075535053490057448;
ONE_OVER_PI = 0.159154943091895335768883763372514362;
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;
)
type (
Vec2 [vector 2]f32;
Vec3 [vector 3]f32;
Vec4 [vector 4]f32;
τ :: TAU;
π :: PI;
// Column major
Mat2 [2][2]f32;
Mat3 [3][3]f32;
Mat4 [4][4]f32;
Vec2 :: [2]f32;
Vec3 :: [3]f32;
Vec4 :: [4]f32;
Complex complex64;
)
// Column major
Mat2 :: [2][2]f32;
Mat3 :: [3][3]f32;
Mat4 :: [4][4]f32;
Complex :: complex64;
@(default_calling_convention="c")
foreign __llvm_core {
proc sqrt(x: f32) -> f32 #link_name "llvm.sqrt.f32";
proc sqrt(x: f64) -> f64 #link_name "llvm.sqrt.f64";
@(link_name="llvm.sqrt.f32")
sqrt :: proc(x: f32) -> f32 ---;
@(link_name="llvm.sqrt.f64")
sqrt :: proc(x: f64) -> f64 ---;
proc sin (θ: f32) -> f32 #link_name "llvm.sin.f32";
proc sin (θ: f64) -> f64 #link_name "llvm.sin.f64";
@(link_name="llvm.sin.f32")
sin :: proc(θ: f32) -> f32 ---;
@(link_name="llvm.sin.f64")
sin :: proc(θ: f64) -> f64 ---;
proc cos (θ: f32) -> f32 #link_name "llvm.cos.f32";
proc cos (θ: f64) -> f64 #link_name "llvm.cos.f64";
@(link_name="llvm.cos.f32")
cos :: proc(θ: f32) -> f32 ---;
@(link_name="llvm.cos.f64")
cos :: proc(θ: f64) -> f64 ---;
proc pow (x, power: f32) -> f32 #link_name "llvm.pow.f32";
proc pow (x, power: f64) -> f64 #link_name "llvm.pow.f64";
@(link_name="llvm.pow.f32")
pow :: proc(x, power: f32) -> f32 ---;
@(link_name="llvm.pow.f64")
pow :: proc(x, power: f64) -> f64 ---;
proc fmuladd(a, b, c: f32) -> f32 #link_name "llvm.fmuladd.f32";
proc fmuladd(a, b, c: f64) -> f64 #link_name "llvm.fmuladd.f64";
@(link_name="llvm.fmuladd.f32")
fmuladd :: proc(a, b, c: f32) -> f32 ---;
@(link_name="llvm.fmuladd.f64")
fmuladd :: proc(a, b, c: f64) -> f64 ---;
}
proc tan (θ: f32) -> f32 #inline { return sin(θ)/cos(θ); }
proc tan (θ: f64) -> f64 #inline { return sin(θ)/cos(θ); }
tan :: proc "c" (θ: f32) -> f32 do return sin(θ)/cos(θ);
tan :: proc "c" (θ: f64) -> f64 do return sin(θ)/cos(θ);
lerp :: proc(a, b: $T, t: $E) -> (x: T) do return a*(1-t) + b*t;
unlerp :: proc(a, b, x: f32) -> (t: f32) do return (x-a)/(b-a);
unlerp :: proc(a, b, x: f64) -> (t: f64) do return (x-a)/(b-a);
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; }
sign :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
sign :: proc(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);
copy_sign :: proc(x, y: f32) -> f32 {
ix := transmute(u32)x;
iy := transmute(u32)y;
ix &= 0x7fff_ffff;
ix |= iy & 0x8000_0000;
return transmute(f32, ix);
return transmute(f32)ix;
}
proc copy_sign(x, y: f64) -> f64 {
var ix = transmute(u64, x);
var iy = transmute(u64, y);
copy_sign :: proc(x, y: f64) -> f64 {
ix := transmute(u64)x;
iy := transmute(u64)y;
ix &= 0x7fff_ffff_ffff_ff;
ix |= iy & 0x8000_0000_0000_0000;
return transmute(f64, ix);
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); }
round :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
round :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
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
floor :: proc(x: f32) -> f32 { return x >= 0 ? f32(i64(x)) : f32(i64(x-0.5)); } // TODO: Get accurate versions
floor :: proc(x: f64) -> f64 { return x >= 0 ? f64(i64(x)) : f64(i64(x-0.5)); } // TODO: Get accurate versions
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
ceil :: proc(x: f32) -> f32 { return x < 0 ? f32(i64(x)) : f32(i64(x+1)); }// TODO: Get accurate versions
ceil :: proc(x: f64) -> f64 { return x < 0 ? f64(i64(x)) : f64(i64(x+1)); }// TODO: Get accurate versions
proc remainder(x, y: f32) -> f32 { return x - round(x/y) * y; }
proc remainder(x, y: f64) -> f64 { return x - round(x/y) * y; }
remainder :: proc(x, y: f32) -> f32 do return x - round(x/y) * y;
remainder :: proc(x, y: f64) -> f64 do return x - round(x/y) * y;
proc mod(x, y: f32) -> f32 {
var result: f32;
mod :: proc(x, y: f32) -> f32 {
result: f32;
y = abs(y);
result = remainder(abs(x), y);
if sign(result) < 0 {
@@ -99,8 +106,8 @@ proc mod(x, y: f32) -> f32 {
}
return copy_sign(result, x);
}
proc mod(x, y: f64) -> f64 {
var result: f64;
mod :: proc(x, y: f64) -> f64 {
result: f64;
y = abs(y);
result = remainder(abs(x), y);
if sign(result) < 0 {
@@ -110,57 +117,36 @@ proc mod(x, y: f64) -> f64 {
}
proc to_radians(degrees: f32) -> f32 { return degrees * TAU / 360; }
proc to_degrees(radians: f32) -> f32 { return radians * 360 / TAU; }
to_radians :: proc(degrees: f32) -> f32 do return degrees * TAU / 360;
to_degrees :: proc(radians: f32) -> f32 do 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; }
dot :: proc(a, b: $T/[$N]$E) -> E {
res: E;
for i in 0..N do res += a[i] * b[i];
return res;
}
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;
cross :: proc(x, y: $T/[3]$E) -> T {
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
return T(a - b);
}
proc mag(v: Vec2) -> f32 { return sqrt(dot(v, v)); }
proc mag(v: Vec3) -> f32 { return sqrt(dot(v, v)); }
proc mag(v: Vec4) -> f32 { return sqrt(dot(v, v)); }
mag :: proc(v: $T/[$N]$E) -> E do return sqrt(dot(v, v));
proc norm(v: Vec2) -> Vec2 { return v / mag(v); }
proc norm(v: Vec3) -> Vec3 { return v / mag(v); }
proc norm(v: Vec4) -> Vec4 { return v / mag(v); }
norm :: proc(v: $T/[$N]$E) -> T do return v / mag(v);
proc norm0(v: Vec2) -> Vec2 {
var m = mag(v);
if m == 0 {
return 0;
}
return v / m;
}
proc norm0(v: Vec3) -> Vec3 {
var m = mag(v);
if m == 0 {
return 0;
}
return v / m;
}
proc norm0(v: Vec4) -> Vec4 {
var m = mag(v);
if m == 0 {
return 0;
}
return v / m;
norm0 :: proc(v: $T/[$N]$E) -> T {
m := mag(v);
return m == 0 ? 0 : v/m;
}
proc mat4_identity() -> Mat4 {
mat4_identity :: proc() -> Mat4 {
return Mat4{
{1, 0, 0, 0},
{0, 1, 0, 0},
@@ -169,19 +155,19 @@ proc mat4_identity() -> Mat4 {
};
}
proc mat4_transpose(m: Mat4) -> Mat4 {
for j in 0..<4 {
for i in 0..<4 {
mat4_transpose :: proc(m: Mat4) -> Mat4 {
for j in 0..4 {
for i in 0..4 {
m[i][j], m[j][i] = m[j][i], m[i][j];
}
}
return m;
}
proc mul(a, b: Mat4) -> Mat4 {
var c: Mat4;
for j in 0..<4 {
for i in 0..<4 {
mul :: proc(a, b: Mat4) -> Mat4 {
c: Mat4;
for j in 0..4 {
for i in 0..4 {
c[j][i] = a[0][i]*b[j][0] +
a[1][i]*b[j][1] +
a[2][i]*b[j][2] +
@@ -191,39 +177,38 @@ proc mul(a, b: Mat4) -> Mat4 {
return c;
}
proc mul(m: Mat4, v: Vec4) -> Vec4 {
mul :: proc(m: Mat4, v: Vec4) -> Vec4 {
return Vec4{
m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z + m[3][2]*v.w,
m[0][3]*v.x + m[1][3]*v.y + m[2][3]*v.z + m[3][3]*v.w,
m[0][0]*v[0] + m[1][0]*v[1] + m[2][0]*v[2] + m[3][0]*v[3],
m[0][1]*v[0] + m[1][1]*v[1] + m[2][1]*v[2] + m[3][1]*v[3],
m[0][2]*v[0] + m[1][2]*v[1] + m[2][2]*v[2] + m[3][2]*v[3],
m[0][3]*v[0] + m[1][3]*v[1] + m[2][3]*v[2] + m[3][3]*v[3],
};
}
proc inverse(m: Mat4) -> Mat4 {
var o: Mat4;
inverse :: proc(m: Mat4) -> Mat4 {
o: Mat4;
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3];
sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2];
sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3];
sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2];
sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1];
sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3];
sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2];
sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3];
sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2];
sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1];
sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3];
sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3];
sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2];
sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3];
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2];
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1];
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);
@@ -245,7 +230,7 @@ proc inverse(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);
var ood = 1.0 / (m[0][0] * o[0][0] +
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]);
@@ -271,52 +256,50 @@ proc inverse(m: Mat4) -> Mat4 {
}
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;
mat4_translate :: proc(v: Vec3) -> Mat4 {
m := mat4_identity();
m[3][0] = v[0];
m[3][1] = v[1];
m[3][2] = v[2];
m[3][3] = 1;
return m;
}
proc mat4_rotate(v: Vec3, angle_radians: f32) -> Mat4 {
var (
c = cos(angle_radians);
s = sin(angle_radians);
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
c := cos(angle_radians);
s := sin(angle_radians);
a = norm(v);
t = a * (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;
rot[0][2] = 0 + t.x*a.z - s*a.y;
rot[0][0] = c + t[0]*a[0];
rot[0][1] = 0 + t[0]*a[1] + s*a[2];
rot[0][2] = 0 + t[0]*a[2] - s*a[1];
rot[0][3] = 0;
rot[1][0] = 0 + t.y*a.x - s*a.z;
rot[1][1] = c + t.y*a.y;
rot[1][2] = 0 + t.y*a.z + s*a.x;
rot[1][0] = 0 + t[1]*a[0] - s*a[2];
rot[1][1] = c + t[1]*a[1];
rot[1][2] = 0 + t[1]*a[2] + s*a[0];
rot[1][3] = 0;
rot[2][0] = 0 + t.z*a.x + s*a.y;
rot[2][1] = 0 + t.z*a.y - s*a.x;
rot[2][2] = c + t.z*a.z;
rot[2][0] = 0 + t[2]*a[0] + s*a[1];
rot[2][1] = 0 + t[2]*a[1] - s*a[0];
rot[2][2] = c + t[2]*a[2];
rot[2][3] = 0;
return rot;
}
proc scale(m: Mat4, v: Vec3) -> Mat4 {
m[0][0] *= v.x;
m[1][1] *= v.y;
m[2][2] *= v.z;
scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
m[0][0] *= v[0];
m[1][1] *= v[1];
m[2][2] *= v[2];
return m;
}
proc scale(m: Mat4, s: f32) -> Mat4 {
scale :: proc(m: Mat4, s: f32) -> Mat4 {
m[0][0] *= s;
m[1][1] *= s;
m[2][2] *= s;
@@ -324,26 +307,23 @@ proc scale(m: Mat4, s: f32) -> Mat4 {
}
proc look_at(eye, centre, up: Vec3) -> Mat4 {
var (
f = norm(centre - eye);
s = norm(cross(f, up));
u = cross(s, f);
)
look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
f := norm(centre - eye);
s := norm(cross(f, up));
u := cross(s, f);
return Mat4{
{+s.x, +u.x, -f.x, 0},
{+s.y, +u.y, -f.y, 0},
{+s.z, +u.z, -f.z, 0},
{+s[0], +u[0], -f[0], 0},
{+s[1], +u[1], -f[1], 0},
{+s[2], +u[2], -f[2], 0},
{-dot(s, eye), -dot(u, eye), dot(f, eye), 1},
};
}
proc perspective(fovy, aspect, near, far: f32) -> Mat4 {
var (
m: Mat4;
tan_half_fovy = tan(0.5 * fovy);
)
perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
m: Mat4;
tan_half_fovy := tan(0.5 * fovy);
m[0][0] = 1.0 / (aspect*tan_half_fovy);
m[1][1] = 1.0 / (tan_half_fovy);
m[2][2] = -(far + near) / (far - near);
@@ -353,8 +333,8 @@ proc perspective(fovy, aspect, near, far: f32) -> Mat4 {
}
proc ortho3d(left, right, bottom, top, near, far: f32) -> Mat4 {
var m = mat4_identity();
ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
m := mat4_identity();
m[0][0] = +2.0 / (right - left);
m[1][1] = +2.0 / (top - bottom);
m[2][2] = -2.0 / (far - near);
@@ -367,30 +347,28 @@ proc ortho3d(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
+174 -160
View File
@@ -1,78 +1,95 @@
import (
"fmt.odin";
"os.odin";
)
import "core:raw.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";
@(link_name = "llvm.bswap.i16") swap :: proc(b: u16) -> u16 ---;
@(link_name = "llvm.bswap.i32") swap :: proc(b: u32) -> u32 ---;
@(link_name = "llvm.bswap.i64") swap :: proc(b: u64) -> u64 ---;
}
proc set(data: rawptr, value: i32, len: int) -> rawptr {
set :: proc "contextless" (data: rawptr, value: i32, len: int) -> rawptr {
return __mem_set(data, value, len);
}
proc zero(data: rawptr, len: int) -> rawptr {
zero :: proc "contextless" (data: rawptr, len: int) -> rawptr {
return __mem_zero(data, len);
}
proc copy(dst, src: rawptr, len: int) -> rawptr {
copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
return __mem_copy(dst, src, len);
}
proc copy_non_overlapping(dst, src: rawptr, len: int) -> rawptr {
copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
return __mem_copy_non_overlapping(dst, src, len);
}
proc compare(a, b: []u8) -> int {
compare :: proc "contextless" (a, b: []u8) -> int {
return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
}
slice_ptr :: proc "contextless" (ptr: ^$T, len: int) -> []T {
assert(len >= 0);
slice := raw.Slice{data = ptr, len = len, cap = len};
return transmute([]T)slice;
}
slice_ptr :: proc "contextless" (ptr: ^$T, len, cap: int) -> []T {
assert(0 <= len && len <= cap);
slice := raw.Slice{data = ptr, len = len, cap = cap};
return transmute([]T)slice;
}
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; }
slice_to_bytes :: proc "contextless" (slice: $E/[]$T) -> []u8 {
s := transmute(raw.Slice)slice;
s.len *= size_of(T);
s.cap *= size_of(T);
return transmute([]u8)s;
}
proc is_power_of_two(x: int) -> bool {
if x <= 0 {
return false;
}
ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []u8 {
assert(len >= 0);
return transmute([]u8)raw.Slice{ptr, len*size_of(T), len*size_of(T)};
}
ptr_to_bytes :: proc "contextless" (ptr: ^$T, len, cap: int) -> []u8 {
assert(0 <= len && len <= cap);
return transmute([]u8)raw.Slice{ptr, len*size_of(T), cap*size_of(T)};
}
kilobytes :: inline proc "contextless" (x: int) -> int do return (x) * 1024;
megabytes :: inline proc "contextless" (x: int) -> int do return kilobytes(x) * 1024;
gigabytes :: inline proc "contextless" (x: int) -> int do return megabytes(x) * 1024;
terabytes :: inline proc "contextless" (x: int) -> int do return gigabytes(x) * 1024;
is_power_of_two :: proc(x: uintptr) -> bool {
if x <= 0 do return false;
return (x & (x-1)) == 0;
}
proc align_forward(ptr: rawptr, align: int) -> rawptr {
align_forward :: proc(ptr: rawptr, align: uintptr) -> rawptr {
assert(is_power_of_two(align));
var a = uint(align);
var p = uint(ptr);
var modulo = p & (a-1);
if modulo != 0 {
p += a - modulo;
}
a := uintptr(align);
p := uintptr(ptr);
modulo := p & (a-1);
if modulo != 0 do p += a - modulo;
return rawptr(p);
}
type AllocationHeader struct {
size: int,
}
AllocationHeader :: struct {size: int};
proc allocation_header_fill(header: ^AllocationHeader, data: rawptr, size: int) {
allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) {
header.size = size;
var ptr = ^int(header+1);
ptr := cast(^uint)(header+1);
n := cast(^uint)data - ptr;
for var i = 0; rawptr(ptr) < data; i++ {
(ptr+i)^ = -1;
for i in 0..n {
(ptr+i)^ = ~uint(0);
}
}
proc allocation_header(data: rawptr) -> ^AllocationHeader {
if data == nil {
return nil;
}
var p = ^int(data);
for (p-1)^ == -1 {
p = (p-1);
}
return ^AllocationHeader(p-1);
allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
if data == nil do return nil;
p := cast(^uint)data;
for (p-1)^ == ~uint(0) do p = (p-1);
return cast(^AllocationHeader)(p-1);
}
@@ -80,71 +97,76 @@ proc allocation_header(data: rawptr) -> ^AllocationHeader {
// Custom allocators
type (
Arena struct {
backing: Allocator,
offset: int,
memory: []u8,
temp_count: int,
}
ArenaTempMemory struct {
arena: ^Arena,
original_count: int,
}
)
Arena :: struct {
backing: Allocator,
memory: []u8,
temp_count: int,
}
ArenaTempMemory :: struct {
arena: ^Arena,
original_count: int,
}
proc init_arena_from_memory(using a: ^Arena, data: []u8) {
init_arena_from_memory :: proc(using a: ^Arena, data: []u8) {
backing = Allocator{};
memory = data[0..<0];
memory = data[..0];
temp_count = 0;
}
proc init_arena_from_context(using a: ^Arena, size: int) {
init_arena_from_context :: proc(using a: ^Arena, size: int) {
backing = context.allocator;
memory = make([]u8, size);
memory = make([]u8, 0, size);
temp_count = 0;
}
proc free_arena(using a: ^Arena) {
context_from_allocator :: proc(a: Allocator) -> Context {
c := context;
c.allocator = a;
return c;
}
destroy_arena :: proc(using a: ^Arena) {
if backing.procedure != nil {
push_allocator backing {
context <- context_from_allocator(backing) {
free(memory);
memory = nil;
offset = 0;
}
}
}
proc arena_allocator(arena: ^Arena) -> Allocator {
arena_allocator :: proc(arena: ^Arena) -> Allocator {
return Allocator{
procedure = arena_allocator_proc,
data = arena,
};
}
proc arena_allocator_proc(allocator_data: rawptr, mode: AllocatorMode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
using AllocatorMode;
var arena = ^Arena(allocator_data);
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
using Allocator_Mode;
arena := cast(^Arena)allocator_data;
match mode {
switch mode {
case Alloc:
var total_size = size + alignment;
total_size := size + alignment;
if arena.offset + total_size > len(arena.memory) {
fmt.fprintln(os.stderr, "Arena out of memory");
if len(arena.memory) + total_size > cap(arena.memory) {
return nil;
}
#no_bounds_check var end = &arena.memory[arena.offset];
#no_bounds_check end := &arena.memory[len(arena.memory)];
var ptr = align_forward(end, alignment);
arena.offset += total_size;
ptr := align_forward(end, uintptr(alignment));
(^raw.Slice)(&arena.memory).len += total_size;
return zero(ptr, size);
case Free:
@@ -152,7 +174,7 @@ proc arena_allocator_proc(allocator_data: rawptr, mode: AllocatorMode,
// Use ArenaTempMemory if you want to free a block
case FreeAll:
arena.offset = 0;
(^raw.Slice)(&arena.memory).len = 0;
case Resize:
return default_resize_align(old_memory, old_size, size, alignment);
@@ -161,19 +183,19 @@ proc arena_allocator_proc(allocator_data: rawptr, mode: AllocatorMode,
return nil;
}
proc begin_arena_temp_memory(a: ^Arena) -> ArenaTempMemory {
var tmp: ArenaTempMemory;
begin_arena_temp_memory :: proc(a: ^Arena) -> ArenaTempMemory {
tmp: ArenaTempMemory;
tmp.arena = a;
tmp.original_count = len(a.memory);
a.temp_count++;
a.temp_count += 1;
return tmp;
}
proc end_arena_temp_memory(using tmp: ArenaTempMemory) {
end_arena_temp_memory :: proc(using tmp: ArenaTempMemory) {
assert(len(arena.memory) >= original_count);
assert(arena.temp_count > 0);
arena.memory = arena.memory[0..<original_count];
arena.temp_count--;
arena.memory = arena.memory[..original_count];
arena.temp_count -= 1;
}
@@ -182,11 +204,9 @@ proc end_arena_temp_memory(using tmp: ArenaTempMemory) {
proc align_of_type_info(type_info: ^TypeInfo) -> int {
proc prev_pow2(n: i64) -> i64 {
if n <= 0 {
return 0;
}
align_of_type_info :: proc(type_info: ^Type_Info) -> int {
prev_pow2 :: proc(n: i64) -> i64 {
if n <= 0 do return 0;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
@@ -196,110 +216,104 @@ proc align_of_type_info(type_info: ^TypeInfo) -> int {
return n - (n >> 1);
}
const WORD_SIZE = size_of(int);
const MAX_ALIGN = size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
using TypeInfo;
match info in type_info {
case Named:
WORD_SIZE :: size_of(int);
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
switch info in type_info.variant {
case Type_Info_Named:
return align_of_type_info(info.base);
case Integer:
return info.size;
case Float:
return info.size;
case String:
case Type_Info_Integer:
return type_info.align;
case Type_Info_Rune:
return type_info.align;
case Type_Info_Float:
return type_info.align;
case Type_Info_String:
return WORD_SIZE;
case Boolean:
case Type_Info_Boolean:
return 1;
case Any:
case Type_Info_Any:
return WORD_SIZE;
case Pointer:
case Type_Info_Pointer:
return WORD_SIZE;
case Procedure:
case Type_Info_Procedure:
return WORD_SIZE;
case Array:
case Type_Info_Array:
return align_of_type_info(info.elem);
case DynamicArray:
case Type_Info_Dynamic_Array:
return WORD_SIZE;
case Slice:
case Type_Info_Slice:
return WORD_SIZE;
case Vector:
var size = size_of_type_info(info.elem);
var count = int(max(prev_pow2(i64(info.count)), 1));
var total = size * count;
case Type_Info_Vector:
size := size_of_type_info(info.elem);
count := int(max(prev_pow2(i64(info.count)), 1));
total := size * count;
return clamp(total, 1, MAX_ALIGN);
case Tuple:
return info.align;
case Struct:
return info.align;
case Union:
return info.align;
case RawUnion:
return info.align;
case Enum:
case Type_Info_Tuple:
return type_info.align;
case Type_Info_Struct:
return type_info.align;
case Type_Info_Union:
return type_info.align;
case Type_Info_Enum:
return align_of_type_info(info.base);
case Map:
case Type_Info_Map:
return align_of_type_info(info.generated_struct);
}
return 0;
}
proc align_formula(size, align: int) -> int {
var result = size + align-1;
align_formula :: proc(size, align: int) -> int {
result := size + align-1;
return result - result%align;
}
proc size_of_type_info(type_info: ^TypeInfo) -> int {
const WORD_SIZE = size_of(int);
using TypeInfo;
match info in type_info {
case Named:
size_of_type_info :: proc(type_info: ^Type_Info) -> int {
WORD_SIZE :: size_of(int);
switch info in type_info.variant {
case Type_Info_Named:
return size_of_type_info(info.base);
case Integer:
return info.size;
case Float:
return info.size;
case String:
case Type_Info_Integer:
return type_info.size;
case Type_Info_Rune:
return type_info.size;
case Type_Info_Float:
return type_info.size;
case Type_Info_String:
return 2*WORD_SIZE;
case Boolean:
case Type_Info_Boolean:
return 1;
case Any:
case Type_Info_Any:
return 2*WORD_SIZE;
case Pointer:
case Type_Info_Pointer:
return WORD_SIZE;
case Procedure:
case Type_Info_Procedure:
return WORD_SIZE;
case Array:
var count = info.count;
if count == 0 {
return 0;
}
var size = size_of_type_info(info.elem);
var align = align_of_type_info(info.elem);
var alignment = align_formula(size, align);
case Type_Info_Array:
count := info.count;
if count == 0 do return 0;
size := size_of_type_info(info.elem);
align := align_of_type_info(info.elem);
alignment := align_formula(size, align);
return alignment*(count-1) + size;
case DynamicArray:
case Type_Info_Dynamic_Array:
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
case Slice:
case Type_Info_Slice:
return 2*WORD_SIZE;
case Vector:
var count = info.count;
if count == 0 {
return 0;
}
var size = size_of_type_info(info.elem);
var align = align_of_type_info(info.elem);
var alignment = align_formula(size, align);
case Type_Info_Vector:
count := info.count;
if count == 0 do return 0;
size := size_of_type_info(info.elem);
align := align_of_type_info(info.elem);
alignment := align_formula(size, align);
return alignment*(count-1) + size;
case Struct:
return info.size;
case Union:
return info.size;
case RawUnion:
return info.size;
case Enum:
case Type_Info_Struct:
return type_info.size;
case Type_Info_Union:
return type_info.size;
case Type_Info_Enum:
return size_of_type_info(info.base);
case Map:
case Type_Info_Map:
return size_of_type_info(info.generated_struct);
}
+95 -92
View File
@@ -1,124 +1,127 @@
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";
when ODIN_OS == "windows" {
foreign import lib "system:opengl32.lib"
import win32 "core:sys/windows.odin"
import "core:sys/wgl.odin"
} else when ODIN_OS == "linux" {
foreign import lib "system:gl"
}
export "core:opengl_constants.odin"
_ := compile_assert(ODIN_OS != "osx");
@(default_calling_convention="c", link_prefix="gl")
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";
Clear :: proc(mask: u32) ---;
ClearColor :: proc(r, g, b, a: f32) ---;
Begin :: proc(mode: i32) ---;
End :: proc() ---;
Finish :: proc() ---;
BlendFunc :: proc(sfactor, dfactor: i32) ---;
Enable :: proc(cap: i32) ---;
Disable :: proc(cap: i32) ---;
GenTextures :: proc(count: i32, result: ^u32) ---;
DeleteTextures :: proc(count: i32, result: ^u32) ---;
TexParameteri :: proc(target, pname, param: i32) ---;
TexParameterf :: proc(target: i32, pname: i32, param: f32) ---;
BindTexture :: proc(target: i32, texture: u32) ---;
LoadIdentity :: proc() ---;
Viewport :: proc(x, y, width, height: i32) ---;
Ortho :: proc(left, right, bottom, top, near, far: f64) ---;
Color3f :: proc(r, g, b: f32) ---;
Vertex3f :: proc(x, y, z: f32) ---;
GetError :: proc() -> i32 ---;
GetString :: proc(name: i32) -> ^u8 ---;
GetIntegerv :: proc(name: i32, v: ^i32) ---;
TexCoord2f :: proc(x, y: f32) ---;
TexImage2D :: proc(target, level, internal_format: i32,
width, height, border: i32,
format, type_: i32, pixels: rawptr) ---;
}
proc _string_data(s: string) -> ^u8 #inline { return &s[0]; }
_string_data :: inline proc(s: string) -> ^u8 do return &s[0];
var _libgl = win32.load_library_a(_string_data("opengl32.dll\x00"));
_libgl := win32.load_library_a(_string_data("opengl32.dll\x00"));
proc get_proc_address(name: string) -> rawptr {
get_proc_address :: proc(name: string) -> rawptr {
if name[len(name)-1] == 0 {
name = name[0..<len(name)-1];
name = name[..len(name)-1];
}
// NOTE(bill): null terminated
assert((&name[0] + len(name))^ == 0);
var res = wgl.get_proc_address(&name[0]);
res := wgl.get_proc_address(&name[0]);
if res == nil {
res = win32.get_proc_address(_libgl, &name[0]);
}
return rawptr(res);
}
var (
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
DeleteBuffers: proc(count: i32, buffers: ^u32) #cc_c;
BindBuffer: proc(target: i32, buffer: u32) #cc_c;
BindVertexArray: proc(buffer: u32) #cc_c;
DeleteVertexArrays: proc(count: i32, arrays: ^u32) #cc_c;
BindSampler: proc(position: i32, sampler: u32) #cc_c;
BufferData: proc(target: i32, size: int, data: rawptr, usage: i32) #cc_c;
BufferSubData: proc(target: i32, offset, size: int, data: rawptr) #cc_c;
// Procedures
GenBuffers: proc "c" (count: i32, buffers: ^u32);
GenVertexArrays: proc "c" (count: i32, buffers: ^u32);
GenSamplers: proc "c" (count: i32, buffers: ^u32);
DeleteBuffers: proc "c" (count: i32, buffers: ^u32);
BindBuffer: proc "c" (target: i32, buffer: u32);
BindVertexArray: proc "c" (buffer: u32);
DeleteVertexArrays: proc "c" (count: i32, arrays: ^u32);
BindSampler: proc "c" (position: i32, sampler: u32);
BufferData: proc "c" (target: i32, size: int, data: rawptr, usage: i32);
BufferSubData: proc "c" (target: i32, offset, size: int, data: rawptr);
DrawArrays: proc(mode, first: i32, count: u32) #cc_c;
DrawElements: proc(mode: i32, count: u32, type_: i32, indices: rawptr) #cc_c;
DrawArrays: proc "c" (mode, first: i32, count: u32);
DrawElements: proc "c" (mode: i32, count: u32, type_: i32, indices: rawptr);
MapBuffer: proc(target, access: i32) -> rawptr #cc_c;
UnmapBuffer: proc(target: i32) #cc_c;
MapBuffer: proc "c" (target, access: i32) -> rawptr;
UnmapBuffer: proc "c" (target: i32);
VertexAttribPointer: proc(index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr) #cc_c;
EnableVertexAttribArray: proc(index: u32) #cc_c;
VertexAttribPointer: proc "c" (index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr);
EnableVertexAttribArray: proc "c" (index: u32);
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;
CreateShader: proc "c" (shader_type: i32) -> u32;
ShaderSource: proc "c" (shader: u32, count: u32, str: ^^u8, length: ^i32);
CompileShader: proc "c" (shader: u32);
CreateProgram: proc "c" () -> u32;
AttachShader: proc "c" (program, shader: u32);
DetachShader: proc "c" (program, shader: u32);
DeleteShader: proc "c" (shader: u32);
LinkProgram: proc "c" (program: u32);
UseProgram: proc "c" (program: u32);
DeleteProgram: proc "c" (program: u32);
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;
GetShaderiv: proc "c" (shader: u32, pname: i32, params: ^i32);
GetProgramiv: proc "c" (program: u32, pname: i32, params: ^i32);
GetShaderInfoLog: proc "c" (shader: u32, max_length: u32, length: ^u32, info_long: ^u8);
GetProgramInfoLog: proc "c" (program: u32, max_length: u32, length: ^u32, info_long: ^u8);
ActiveTexture: proc(texture: i32) #cc_c;
GenerateMipmap: proc(target: i32) #cc_c;
ActiveTexture: proc "c" (texture: i32);
GenerateMipmap: proc "c" (target: i32);
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 "c" (sampler: u32, pname: i32, param: i32);
SamplerParameterf: proc "c" (sampler: u32, pname: i32, param: f32);
SamplerParameteriv: proc "c" (sampler: u32, pname: i32, params: ^i32);
SamplerParameterfv: proc "c" (sampler: u32, pname: i32, params: ^f32);
SamplerParameterIiv: proc "c" (sampler: u32, pname: i32, params: ^i32);
SamplerParameterIuiv: proc "c" (sampler: u32, pname: i32, params: ^u32);
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 "c" (loc: i32, v0: i32);
Uniform2i: proc "c" (loc: i32, v0, v1: i32);
Uniform3i: proc "c" (loc: i32, v0, v1, v2: i32);
Uniform4i: proc "c" (loc: i32, v0, v1, v2, v3: i32);
Uniform1f: proc "c" (loc: i32, v0: f32);
Uniform2f: proc "c" (loc: i32, v0, v1: f32);
Uniform3f: proc "c" (loc: i32, v0, v1, v2: f32);
Uniform4f: proc "c" (loc: i32, v0, v1, v2, v3: f32);
UniformMatrix4fv: proc "c" (loc: i32, count: u32, transpose: i32, value: ^f32);
GetUniformLocation: proc(program: u32, name: ^u8) -> i32 #cc_c;
)
GetUniformLocation: proc "c" (program: u32, name: ^u8) -> i32;
proc init() {
proc set_proc_address(p: rawptr, name: string) #inline {
var x = ^rawptr(p);
init :: proc() {
set_proc_address :: proc(p: rawptr, name: string) {
x := cast(^rawptr)p;
x^ = get_proc_address(name);
}
+1389 -1367
View File
File diff suppressed because it is too large Load Diff
+29 -17
View File
@@ -1,49 +1,61 @@
import_load (
"os_windows.odin" when ODIN_OS == "windows";
"os_x.odin" when ODIN_OS == "osx";
"os_linux.odin" when ODIN_OS == "linux";
)
when ODIN_OS == "windows" do export "core:os_windows.odin";
when ODIN_OS == "osx" do export "core:os_x.odin";
when ODIN_OS == "linux" do export "core:os_linux.odin";
proc write_string(fd: Handle, str: string) -> (int, Errno) {
return write(fd, []u8(str));
import "mem.odin";
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
return write(fd, cast([]u8)str);
}
proc read_entire_file(name: string) -> ([]u8, bool) {
var fd, err = open(name, O_RDONLY, 0);
read_entire_file :: proc(name: string) -> (data: []u8, success: bool) {
fd, err := open(name, O_RDONLY, 0);
if err != 0 {
return nil, false;
}
defer close(fd);
var length: i64;
length: i64;
if length, err = file_size(fd); err != 0 {
return nil, false;
}
if length == 0 {
if length <= 0 {
return nil, true;
}
var data = make([]u8, length);
data := make([]u8, int(length));
if data == nil {
return nil, false;
}
var bytes_read, read_err = read(fd, data);
bytes_read, read_err := read(fd, data);
if read_err != 0 {
free(data);
return nil, false;
}
return data[0..<bytes_read], true;
return data[0..bytes_read], true;
}
proc write_entire_file(name: string, data: []u8) -> bool {
var fd, err = open(name, O_WRONLY, 0);
write_entire_file :: proc(name: string, data: []u8, truncate := true) -> (success: bool) {
flags: int = O_WRONLY|O_CREATE;
if truncate {
flags |= O_TRUNC;
}
fd, err := open(name, flags, 0);
if err != 0 {
return false;
}
defer close(fd);
var bytes_written, write_err = write(fd, data);
bytes_written, write_err := write(fd, data);
return write_err != 0;
}
write :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
return write(fd, mem.slice_ptr(cast(^u8)data, len));
}
read :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
return read(fd, mem.slice_ptr(cast(^u8)data, len));
}
+146 -150
View File
@@ -1,51 +1,46 @@
foreign_system_library (
dl "dl";
libc "c";
)
import "strings.odin";
foreign import dl "system:dl"
foreign import libc "system:c"
type (
Handle i32;
FileTime u64;
Errno i32;
)
import "core:strings.odin"
import "core:mem.odin"
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;
)
Handle :: i32;
File_Time :: u64;
Errno :: i32;
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;
)
O_RDONLY :: 0x00000;
O_WRONLY :: 0x00001;
O_RDWR :: 0x00002;
O_CREATE :: 0x00040;
O_EXCL :: 0x00080;
O_NOCTTY :: 0x00100;
O_TRUNC :: 0x00200;
O_NONBLOCK :: 0x00800;
O_APPEND :: 0x00400;
O_SYNC :: 0x01000;
O_ASYNC :: 0x02000;
O_CLOEXEC :: 0x80000;
SEEK_SET :: 0;
SEEK_CUR :: 1;
SEEK_END :: 2;
SEEK_DATA :: 3;
SEEK_HOLE :: 4;
SEEK_MAX :: SEEK_HOLE;
// NOTE(zangent): These are OS specific!
// Do not mix these up!
RTLD_LAZY :: 0x001;
RTLD_NOW :: 0x002;
RTLD_BINDING_MASK :: 0x3;
RTLD_GLOBAL :: 0x100;
// "Argv" arguments converted to Odin strings
var args = _alloc_command_line_arguments();
args := _alloc_command_line_arguments();
type _FileTime struct #ordered {
_File_Time :: struct #ordered {
seconds: i64,
nanoseconds: i32,
reserved: i32,
@@ -55,7 +50,7 @@ type _FileTime struct #ordered {
// 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 {
Stat :: struct #ordered {
device_id: u64, // ID of device containing file
serial: u64, // File serial number
nlink: u32, // Number of hard links
@@ -68,9 +63,9 @@ type Stat struct #ordered {
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
last_access: _File_Time, // Time of last access
modified: _File_Time, // Time of last modification
status_change: _File_Time, // Time of last status change
_reserve1,
_reserve2,
@@ -80,84 +75,82 @@ type Stat struct #ordered {
};
// 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
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
// 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
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_IRWXO :: 0000007; // RWX mask for other
S_IROTH :: 0000004; // R for other
S_IWOTH :: 0000002; // W for other
S_IXOTH :: 0000001; // X for other
S_ISUID = 0004000; // Set user id on execution
S_ISGID = 0002000; // Set group id on execution
S_ISVTX = 0001000; // Directory restrcted delete
)
S_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
)
S_ISLNK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK;
S_ISREG :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG;
S_ISDIR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR;
S_ISCHR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR;
S_ISBLK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK;
S_ISFIFO :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO;
S_ISSOCK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK;
F_OK :: 0; // Test for file existance
X_OK :: 1; // Test for execute permission
W_OK :: 2; // Test for write permission
R_OK :: 4; // Test for read permission
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";
@(link_name="open") _unix_open :: proc(path: ^u8, mode: int) -> Handle ---;
@(link_name="close") _unix_close :: proc(fd: Handle) -> i32 ---;
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
@(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 ---;
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---;
@(link_name="stat") _unix_stat :: proc(path: ^u8, stat: ^Stat) -> i32 ---;
@(link_name="access") _unix_access :: proc(path: ^u8, mask: int) -> i32 ---;
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";
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---;
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---;
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
@(link_name="getenv") _unix_getenv :: proc(^u8) -> ^u8 ---;
proc _unix_exit(status: int) #link_name "exit";
@(link_name="exit") _unix_exit :: proc(status: int) ---;
}
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";
@(link_name="dlopen") _unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr ---;
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> rawptr ---;
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---;
@(link_name="dlerror") _unix_dlerror :: proc() -> ^u8 ---;
}
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
proc open_simple(path: string, mode: int) -> (Handle, Errno) {
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
var cstr = strings.new_c_string(path);
var handle = _unix_open(cstr, mode);
cstr := strings.new_c_string(path);
handle := _unix_open(cstr, mode);
free(cstr);
if(handle == -1) {
return 0, 1;
@@ -165,78 +158,78 @@ proc open_simple(path: string, mode: int) -> (Handle, Errno) {
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) {
open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
return open_simple(path, mode);
}
proc close(fd: Handle) {
close :: proc(fd: Handle) {
_unix_close(fd);
}
proc read(fd: Handle, data: []u8) -> (int, Errno) {
var sz = _unix_read(fd, &data[0], len(data));
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
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));
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
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));
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
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);
file_size :: proc(fd: Handle) -> (i64, Errno) {
prev, _ := seek(fd, 0, SEEK_CUR);
size, err := seek(fd, 0, SEEK_END);
seek(fd, prev, SEEK_SET);
return size, err;
}
// NOTE(bill): Uses startup to initialize it
var (
stdin: Handle = 0;
stdout: Handle = 1;
stderr: Handle = 2;
)
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 {}
last_write_time :: proc(fd: Handle) -> File_Time {}
last_write_time_by_name :: proc(name: string) -> File_Time {}
*/
proc stat(path: string) -> (Stat, int) #inline {
var s: Stat;
var cstr = strings.new_c_string(path);
stat :: inline proc(path: string) -> (Stat, int) {
s: Stat;
cstr := strings.new_c_string(path);
defer free(cstr);
var ret_int = _unix_stat(cstr, &s);
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);
access :: inline proc(path: string, mask: int) -> bool {
cstr := strings.new_c_string(path);
defer free(cstr);
return _unix_access(cstr, mask) == 0;
}
proc heap_alloc(size: int) -> rawptr {
heap_alloc :: proc(size: int) -> rawptr {
assert(size > 0);
return _unix_malloc(size);
return _unix_calloc(1, size);
}
proc heap_resize(ptr: rawptr, new_size: int) -> rawptr {
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
return _unix_realloc(ptr, new_size);
}
proc heap_free(ptr: rawptr) {
heap_free :: proc(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);
getenv :: proc(name: string) -> (string, bool) {
path_str := strings.new_c_string(name);
cstr: ^u8 = _unix_getenv(path_str);
free(path_str);
if(cstr == nil) {
return "", false;
@@ -244,38 +237,41 @@ proc getenv(name: string) -> (string, bool) {
return strings.to_odin_string(cstr), true;
}
proc exit(code: int) {
exit :: proc(code: int) {
_unix_exit(code);
}
proc current_thread_id() -> int {
current_thread_id :: proc() -> 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);
dlopen :: inline proc(filename: string, flags: int) -> rawptr {
cstr := strings.new_c_string(filename);
handle := _unix_dlopen(cstr, flags);
free(cstr);
return handle;
}
proc dlsym(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
assert(handle != nil);
var cstr = strings.new_c_string(symbol);
var proc_handle = _unix_dlsym(handle, cstr);
cstr := strings.new_c_string(symbol);
proc_handle := _unix_dlsym(handle, cstr);
free(cstr);
return proc_handle;
}
proc dlclose(handle: rawptr) -> bool #inline {
dlclose :: inline proc(handle: rawptr) -> bool {
assert(handle != nil);
return _unix_dlclose(handle) == 0;
}
proc dlerror() -> string {
dlerror :: proc() -> string {
return strings.to_odin_string(_unix_dlerror());
}
proc _alloc_command_line_arguments() -> []string {
// TODO(bill):
return nil;
_alloc_command_line_arguments :: proc() -> []string {
args := make([]string, __argc__);
for i in 0..__argc__ {
args[i] = strings.to_odin_string((__argv__+i)^);
}
return args;
}
+165 -196
View File
@@ -1,75 +1,72 @@
import win32 "sys/windows.odin";
import win32 "core:sys/windows.odin"
import "core:mem.odin"
type (
Handle int;
FileTime u64;
)
const INVALID_HANDLE: Handle = -1;
Handle :: uintptr;
File_Time :: u64;
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);
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;
)
O_RDONLY :: 0x00000;
O_WRONLY :: 0x00001;
O_RDWR :: 0x00002;
O_CREATE :: 0x00040;
O_EXCL :: 0x00080;
O_NOCTTY :: 0x00100;
O_TRUNC :: 0x00200;
O_NONBLOCK :: 0x00800;
O_APPEND :: 0x00400;
O_SYNC :: 0x01000;
O_ASYNC :: 0x02000;
O_CLOEXEC :: 0x80000;
Errno :: int;
ERROR_NONE: Errno : 0;
ERROR_FILE_NOT_FOUND: Errno : 2;
ERROR_PATH_NOT_FOUND: Errno : 3;
ERROR_ACCESS_DENIED: Errno : 5;
ERROR_NO_MORE_FILES: Errno : 18;
ERROR_HANDLE_EOF: Errno : 38;
ERROR_NETNAME_DELETED: Errno : 64;
ERROR_FILE_EXISTS: Errno : 80;
ERROR_BROKEN_PIPE: Errno : 109;
ERROR_BUFFER_OVERFLOW: Errno : 111;
ERROR_INSUFFICIENT_BUFFER: Errno : 122;
ERROR_MOD_NOT_FOUND: Errno : 126;
ERROR_PROC_NOT_FOUND: Errno : 127;
ERROR_DIR_NOT_EMPTY: Errno : 145;
ERROR_ALREADY_EXISTS: Errno : 183;
ERROR_ENVVAR_NOT_FOUND: Errno : 203;
ERROR_MORE_DATA: Errno : 234;
ERROR_OPERATION_ABORTED: Errno : 995;
ERROR_IO_PENDING: Errno : 997;
ERROR_NOT_FOUND: Errno : 1168;
ERROR_PRIVILEGE_NOT_HELD: Errno : 1314;
WSAEACCES: Errno : 10013;
WSAECONNRESET: Errno : 10054;
// Windows reserves errors >= 1<<29 for application use
ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
// "Argv" arguments converted to Odin strings
var args = _alloc_command_line_arguments();
args := _alloc_command_line_arguments();
proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
if len(path) == 0 {
return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
}
open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
if len(path) == 0 do return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
var access: u32;
match mode & (O_RDONLY|O_WRONLY|O_RDWR) {
access: u32;
switch mode & (O_RDONLY|O_WRONLY|O_RDWR) {
case O_RDONLY: access = win32.FILE_GENERIC_READ;
case O_WRONLY: access = win32.FILE_GENERIC_WRITE;
case O_RDWR: access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE;
}
if mode&O_CREAT != 0 {
if mode&O_CREATE != 0 {
access |= win32.FILE_GENERIC_WRITE;
}
if mode&O_APPEND != 0 {
@@ -77,20 +74,20 @@ proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno)
access |= win32.FILE_APPEND_DATA;
}
var share_mode = u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE);
var sa: ^win32.Security_Attributes = nil;
var sa_inherit = win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = 1};
share_mode := u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE);
sa: ^win32.Security_Attributes = nil;
sa_inherit := win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = 1};
if mode&O_CLOEXEC == 0 {
sa = &sa_inherit;
}
var create_mode: u32;
match {
case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
create_mode: u32;
switch {
case mode&(O_CREATE|O_EXCL) == (O_CREATE | O_EXCL):
create_mode = win32.CREATE_NEW;
case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
case mode&(O_CREATE|O_TRUNC) == (O_CREATE | O_TRUNC):
create_mode = win32.CREATE_ALWAYS;
case mode&O_CREAT == O_CREAT:
case mode&O_CREATE == O_CREATE:
create_mode = win32.OPEN_ALWAYS;
case mode&O_TRUNC == O_TRUNC:
create_mode = win32.TRUNCATE_EXISTING;
@@ -98,102 +95,88 @@ proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno)
create_mode = win32.OPEN_EXISTING;
}
var buf: [300]u8;
copy(buf[..], []u8(path));
buf: [300]u8;
copy(buf[..], cast([]u8)path);
var handle = Handle(win32.create_file_a(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
if handle != INVALID_HANDLE {
return handle, ERROR_NONE;
}
var err = win32.get_last_error();
return INVALID_HANDLE, Errno(err);
handle := Handle(win32.create_file_a(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
if handle != INVALID_HANDLE do return handle, ERROR_NONE;
err := Errno(win32.get_last_error());
return INVALID_HANDLE, err;
}
proc close(fd: Handle) {
close :: proc(fd: Handle) {
win32.close_handle(win32.Handle(fd));
}
proc write(fd: Handle, data: []u8) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
}
var single_write_length: i32;
var total_write: i64;
var length = i64(len(data));
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
if len(data) == 0 do return 0, ERROR_NONE;
single_write_length: i32;
total_write: i64;
length := i64(len(data));
for total_write < length {
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);
remaining := length - total_write;
MAX :: 1<<31-1;
to_write: i32 = min(i32(remaining), MAX);
e := win32.write_file(win32.Handle(fd), &data[total_write], to_write, &single_write_length, nil);
if single_write_length <= 0 || e == win32.FALSE {
var err = win32.get_last_error();
return int(total_write), Errno(e);
err := Errno(win32.get_last_error());
return int(total_write), err;
}
total_write += i64(single_write_length);
}
return int(total_write), ERROR_NONE;
}
proc read(fd: Handle, data: []u8) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
}
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
if len(data) == 0 do return 0, ERROR_NONE;
var single_read_length: i32;
var total_read: i64;
var length = i64(len(data));
single_read_length: i32;
total_read: i64;
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;
}
remaining := length - total_read;
MAX :: 1<<32-1;
to_read: u32 = min(u32(remaining), MAX);
var e = win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
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);
err := Errno(win32.get_last_error());
return int(total_read), err;
}
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 {
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
w: u32;
switch whence {
case 0: w = win32.FILE_BEGIN;
case 1: w = win32.FILE_CURRENT;
case 2: w = win32.FILE_END;
}
var hi = i32(offset>>32);
var lo = i32(offset);
var ft = win32.get_file_type(win32.Handle(fd));
if ft == win32.FILE_TYPE_PIPE {
return 0, ERROR_FILE_IS_PIPE;
}
var dw_ptr = win32.set_file_pointer(win32.Handle(fd), lo, &hi, w);
hi := i32(offset>>32);
lo := i32(offset);
ft := win32.get_file_type(win32.Handle(fd));
if ft == win32.FILE_TYPE_PIPE do return 0, ERROR_FILE_IS_PIPE;
dw_ptr := win32.set_file_pointer(win32.Handle(fd), lo, &hi, w);
if dw_ptr == win32.INVALID_SET_FILE_POINTER {
var err = win32.get_last_error();
return 0, Errno(err);
err := Errno(win32.get_last_error());
return 0, err;
}
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
}
proc file_size(fd: Handle) -> (i64, Errno) {
var length: i64;
var err: Errno;
file_size :: proc(fd: Handle) -> (i64, Errno) {
length: i64;
err: Errno;
if win32.get_file_size_ex(win32.Handle(fd), &length) == 0 {
err = Errno(win32.get_last_error());
}
@@ -203,13 +186,13 @@ proc file_size(fd: Handle) -> (i64, Errno) {
// NOTE(bill): Uses startup to initialize it
var stdin = get_std_handle(win32.STD_INPUT_HANDLE);
var stdout = get_std_handle(win32.STD_OUTPUT_HANDLE);
var stderr = get_std_handle(win32.STD_ERROR_HANDLE);
stdin := get_std_handle(win32.STD_INPUT_HANDLE);
stdout := get_std_handle(win32.STD_OUTPUT_HANDLE);
stderr := get_std_handle(win32.STD_ERROR_HANDLE);
proc get_std_handle(h: int) -> Handle {
var fd = win32.get_std_handle(i32(h));
get_std_handle :: proc(h: int) -> Handle {
fd := win32.get_std_handle(i32(h));
win32.set_handle_information(fd, win32.HANDLE_FLAG_INHERIT, 0);
return Handle(fd);
}
@@ -219,126 +202,112 @@ proc get_std_handle(h: int) -> Handle {
proc last_write_time(fd: Handle) -> FileTime {
var file_info: win32.ByHandleFileInformation;
last_write_time :: proc(fd: Handle) -> File_Time {
file_info: win32.By_Handle_File_Information;
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);
lo := File_Time(file_info.last_write_time.lo);
hi := File_Time(file_info.last_write_time.hi);
return lo | hi << 32;
}
proc last_write_time_by_name(name: string) -> FileTime {
var last_write_time: win32.Filetime;
var data: win32.FileAttributeData;
var buf: [1024]u8;
last_write_time_by_name :: proc(name: string) -> File_Time {
last_write_time: win32.Filetime;
data: win32.File_Attribute_Data;
buf: [1024]u8;
assert(len(buf) > len(name));
copy(buf[..], []u8(name));
copy(buf[..], cast([]u8)name);
if win32.get_file_attributes_ex_a(&buf[0], win32.GetFileExInfoStandard, &data) != 0 {
last_write_time = data.last_write_time;
}
var l = FileTime(last_write_time.lo);
var h = FileTime(last_write_time.hi);
l := File_Time(last_write_time.lo);
h := File_Time(last_write_time.hi);
return l | h << 32;
}
proc heap_alloc(size: int) -> rawptr {
heap_alloc :: proc(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 {
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
if new_size == 0 {
heap_free(ptr);
return nil;
}
if ptr == nil {
return heap_alloc(new_size);
}
if ptr == nil do return heap_alloc(new_size);
return win32.heap_realloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
}
proc heap_free(ptr: rawptr) {
if ptr == nil {
return;
}
heap_free :: proc(ptr: rawptr) {
if ptr == nil do return;
win32.heap_free(win32.get_process_heap(), 0, ptr);
}
proc exit(code: int) {
exit :: proc(code: int) {
win32.exit_process(u32(code));
}
proc current_thread_id() -> int {
current_thread_id :: proc() -> 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);
_alloc_command_line_arguments :: proc() -> []string {
alloc_ucs2_to_utf8 :: proc(wstr: ^u16) -> string {
wstr_len := 0;
for (wstr+wstr_len)^ != 0 do wstr_len += 1;
var i, j = 0, 0;
len := 2*wstr_len-1;
buf := make([]u8, len+1);
str := mem.slice_ptr(wstr, wstr_len+1);
i, j := 0, 0;
for str[j] != 0 {
match {
switch {
case str[j] < 0x80:
if i+1 > len {
return "";
}
buf[i] = u8(str[j]); i++;
j++;
if i+1 > len do return "";
buf[i] = u8(str[j]); i += 1;
j += 1;
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++;
if i+2 > len do return "";
buf[i] = u8(0xc0 + (str[j]>>6)); i += 1;
buf[i] = u8(0x80 + (str[j]&0x3f)); i += 1;
j += 1;
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++;
if i+4 > len do return "";
c := rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000;
buf[i] = u8(0xf0 + (c >> 18)); i += 1;
buf[i] = u8(0x80 + ((c >> 12) & 0x3f)); i += 1;
buf[i] = u8(0x80 + ((c >> 6) & 0x3f)); i += 1;
buf[i] = u8(0x80 + ((c ) & 0x3f)); i += 1;
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++;
if i+3 > len do return "";
buf[i] = 0xe0 + u8 (str[j] >> 12); i += 1;
buf[i] = 0x80 + u8((str[j] >> 6) & 0x3f); i += 1;
buf[i] = 0x80 + u8((str[j] ) & 0x3f); i += 1;
j += 1;
}
}
return string(buf[0..<i]);
return string(buf[..i]);
}
var arg_count: i32;
var arg_list_ptr = win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count);
var arg_list = make([]string, arg_count);
for _, i in arg_list {
arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^);
}
arg_count: i32;
arg_list_ptr := win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count);
arg_list := make([]string, int(arg_count));
for _, i in arg_list do arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^);
return arg_list;
}
+179 -178
View File
@@ -1,164 +1,157 @@
foreign_system_library (
dl "dl";
libc "c";
)
foreign import dl "system:dl"
foreign import libc "system:c"
import "strings.odin";
import "core:strings.odin"
import "core:mem.odin"
type (
Handle i32;
FileTime u64;
Errno int;
Handle :: i32;
File_Time :: 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;
)
O_RDONLY :: 0x00000;
O_WRONLY :: 0x00001;
O_RDWR :: 0x00002;
O_CREATE :: 0x00040;
O_EXCL :: 0x00080;
O_NOCTTY :: 0x00100;
O_TRUNC :: 0x00200;
O_NONBLOCK :: 0x00800;
O_APPEND :: 0x00400;
O_SYNC :: 0x01000;
O_ASYNC :: 0x02000;
O_CLOEXEC :: 0x80000;
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;
SEEK_SET :: 0;
SEEK_CUR :: 1;
SEEK_END :: 2;
SEEK_DATA :: 3;
SEEK_HOLE :: 4;
SEEK_MAX :: SEEK_HOLE;
type _FileTime struct #ordered {
// NOTE(zangent): These are OS specific!
// Do not mix these up!
RTLD_LAZY :: 0x1;
RTLD_NOW :: 0x2;
RTLD_LOCAL :: 0x4;
RTLD_GLOBAL :: 0x8;
RTLD_NODELETE :: 0x80;
RTLD_NOLOAD :: 0x10;
RTLD_FIRST :: 0x100;
// "Argv" arguments converted to Odin strings
args := _alloc_command_line_arguments();
_File_Time :: struct #ordered {
seconds: i64,
nanoseconds: 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
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
last_access: File_Time, // Time of last access
modified: File_Time, // Time of last modification
status_change: File_Time, // Time of last status change
created: File_Time, // Time of creation
size : i64, // Size of the file, in bytes
blocks : i64, // Number of blocks allocated for the file
block_size: i32, // Optimal blocksize for I/O
flags : u32, // User-defined flags for the file
gen_num : u32, // File generation number ...?
_spare : i32, // RESERVED
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
_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
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
// 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 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
// Read, write, execute/search by others
S_IRWXO :: 0000007; // RWX mask for other
S_IROTH :: 0000004; // R for other
S_IWOTH :: 0000002; // W for other
S_IXOTH :: 0000001; // X for other
S_ISUID = 0004000; // Set user id on execution
S_ISGID = 0002000; // Set group id on execution
S_ISVTX = 0001000; // Directory restrcted delete
)
S_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;}
S_ISLNK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK;
S_ISREG :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG;
S_ISDIR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR;
S_ISCHR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR;
S_ISBLK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK;
S_ISFIFO :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO;
S_ISSOCK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK;
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
)
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";
@(link_name="open") _unix_open :: proc(path: ^u8, mode: int) -> Handle ---;
@(link_name="close") _unix_close :: proc(handle: Handle) ---;
@(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---;
@(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---;
@(link_name="lseek") _unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int ---;
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---;
@(link_name="stat") _unix_stat :: proc(path: ^u8, stat: ^Stat) -> int ---;
@(link_name="access") _unix_access :: proc(path: ^u8, mask: int) -> int ---;
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";
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---;
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---;
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
@(link_name="getenv") _unix_getenv :: proc(^u8) -> ^u8 ---;
proc unix_exit(status: int) #link_name "exit";
@(link_name="exit") _unix_exit :: proc(status: int) ---;
}
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";
@(link_name="dlopen") _unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr ---;
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> rawptr ---;
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---;
@(link_name="dlerror") _unix_dlerror :: proc() -> ^u8 ---;
}
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
proc open_simple(path: string, mode: int) -> (Handle, Errno) {
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
var cstr = strings.new_c_string(path);
var handle = unix_open(cstr, mode);
cstr := strings.new_c_string(path);
handle := _unix_open(cstr, mode);
free(cstr);
if(handle == -1) {
return 0, 1;
@@ -167,92 +160,91 @@ proc open_simple(path: string, mode: int) -> (Handle, Errno) {
}
// 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) {
open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
return open_simple(path, mode);
}
proc close(fd: Handle) {
unix_close(fd);
close :: proc(fd: Handle) {
_unix_close(fd);
}
proc write(fd: Handle, data: []u8) -> (AddressSize, Errno) {
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
assert(fd != -1);
var bytes_written = unix_write(fd, &data[0], len(data));
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) {
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
assert(fd != -1);
var bytes_read = unix_read(fd, &data[0], len(data));
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) {
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
assert(fd != -1);
var final_offset = unix_lseek(fd, offset, whence);
final_offset := i64(_unix_lseek(fd, int(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);
file_size :: proc(fd: Handle) -> (i64, Errno) {
prev, _ := seek(fd, 0, SEEK_CUR);
size, err := seek(fd, 0, SEEK_END);
seek(fd, prev, SEEK_SET);
return size, err;
return i64(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);
)
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 {}
last_write_time :: proc(fd: Handle) -> File_Time {}
last_write_time_by_name :: proc(name: string) -> File_Time {}
*/
proc stat(path: string) -> (Stat, bool) #inline {
var s: Stat;
var cstr = strings.new_c_string(path);
stat :: inline proc(path: string) -> (Stat, bool) {
s: Stat;
cstr := strings.new_c_string(path);
defer free(cstr);
var ret_int = unix_stat(cstr, &s);
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);
access :: inline proc(path: string, mask: int) -> bool {
cstr := strings.new_c_string(path);
defer free(cstr);
return unix_access(cstr, mask) == 0;
return _unix_access(cstr, mask) == 0;
}
proc heap_alloc(size: int) -> rawptr #inline {
heap_alloc :: inline proc(size: int) -> rawptr {
assert(size > 0);
return unix_malloc(size);
return _unix_calloc(1, size);
}
proc heap_resize(ptr: rawptr, new_size: int) -> rawptr #inline {
return unix_realloc(ptr, new_size);
heap_resize :: inline proc(ptr: rawptr, new_size: int) -> rawptr {
return _unix_realloc(ptr, new_size);
}
proc heap_free(ptr: rawptr) #inline {
unix_free(ptr);
heap_free :: inline proc(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);
getenv :: proc(name: string) -> (string, bool) {
path_str := strings.new_c_string(name);
cstr: ^u8 = _unix_getenv(path_str);
free(path_str);
if(cstr == nil) {
return "", false;
@@ -260,33 +252,42 @@ proc getenv(name: string) -> (string, bool) {
return strings.to_odin_string(cstr), true;
}
proc exit(code: int) #inline {
unix_exit(code);
exit :: inline proc(code: int) {
_unix_exit(code);
}
proc current_thread_id() -> int {
// return cast(int) unix_gettid();
current_thread_id :: proc() -> 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);
dlopen :: inline proc(filename: string, flags: int) -> rawptr {
cstr := strings.new_c_string(filename);
handle := _unix_dlopen(cstr, flags);
free(cstr);
return handle;
}
proc dlsym(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
assert(handle != nil);
var cstr = strings.new_c_string(symbol);
var proc_handle = unix_dlsym(handle, cstr);
cstr := strings.new_c_string(symbol);
proc_handle := _unix_dlsym(handle, cstr);
free(cstr);
return proc_handle;
}
proc dlclose(handle: rawptr) -> bool #inline {
dlclose :: inline proc(handle: rawptr) -> bool {
assert(handle != nil);
return unix_dlclose(handle) == 0;
return _unix_dlclose(handle) == 0;
}
proc dlerror() -> string {
return strings.to_odin_string(unix_dlerror());
dlerror :: proc() -> string {
return strings.to_odin_string(_unix_dlerror());
}
_alloc_command_line_arguments :: proc() -> []string {
args := make([]string, __argc__);
for i in 0..__argc__ {
args[i] = strings.to_odin_string((__argv__+i)^);
}
return args;
}
+24 -25
View File
@@ -1,29 +1,28 @@
type (
Any struct #ordered {
data: rawptr,
type_info: ^TypeInfo,
};
Any :: struct #ordered {
data: rawptr,
type_info: ^Type_Info,
}
String struct #ordered {
data: ^u8,
len: int,
};
String :: struct #ordered {
data: ^u8,
len: int,
}
Slice struct #ordered {
data: rawptr,
len: int,
cap: int,
};
Slice :: struct #ordered {
data: rawptr,
len: int,
cap: int,
}
DynamicArray struct #ordered {
data: rawptr,
len: int,
cap: int,
allocator: Allocator,
};
Dynamic_Array :: struct #ordered {
data: rawptr,
len: int,
cap: int,
allocator: Allocator,
}
Map :: struct #ordered {
hashes: [dynamic]int,
entries: Dynamic_Array,
}
DynamicMap struct #ordered {
hashes: [dynamic]int,
entries: DynamicArray,
};
)
+213
View File
@@ -0,0 +1,213 @@
bubble_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
assert(f != nil);
count := len(array);
init_j, last_j := 0, count-1;
for {
init_swap, prev_swap := -1, -1;
for j in init_j..last_j {
if f(array[j], array[j+1]) > 0 {
array[j], array[j+1] = array[j+1], array[j];
prev_swap = j;
if init_swap == -1 do init_swap = j;
}
}
if prev_swap == -1 do return;
init_j = max(init_swap-1, 0);
last_j = prev_swap;
}
}
bubble_sort :: proc(array: $A/[]$T) {
count := len(array);
init_j, last_j := 0, count-1;
for {
init_swap, prev_swap := -1, -1;
for j in init_j..last_j {
if array[j] > array[j+1] {
array[j], array[j+1] = array[j+1], array[j];
prev_swap = j;
if init_swap == -1 do init_swap = j;
}
}
if prev_swap == -1 do return;
init_j = max(init_swap-1, 0);
last_j = prev_swap;
}
}
quick_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
assert(f != nil);
a := array;
n := len(a);
if n < 2 do return;
p := a[n/2];
i, j := 0, n-1;
loop: for {
for f(a[i], p) < 0 do i += 1;
for f(p, a[j]) < 0 do j -= 1;
if i >= j do break loop;
a[i], a[j] = a[j], a[i];
i += 1;
j -= 1;
}
quick_sort(a[0..i], f);
quick_sort(a[i..n], f);
}
quick_sort :: proc(array: $A/[]$T) {
a := array;
n := len(a);
if n < 2 do return;
p := a[n/2];
i, j := 0, n-1;
loop: for {
for a[i] < p do i += 1;
for p < a[j] do j -= 1;
if i >= j do break loop;
a[i], a[j] = a[j], a[i];
i += 1;
j -= 1;
}
quick_sort(a[0..i]);
quick_sort(a[i..n]);
}
_log2 :: proc(n: int) -> int {
res := 0;
for ; n != 0; n >>= 1 do res += 1;
return res;
}
merge_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
merge_slices :: proc(arr1, arr2, out: A, f: proc(T, T) -> int) {
N1, N2 := len(arr1), len(arr2);
i, j := 0, 0;
for k in 0..N1+N2 {
if j == N2 || i < N1 && j < N2 && f(arr1[i], arr2[j]) < 0 {
out[k] = arr1[i];
i += 1;
} else {
out[k] = arr2[j];
j += 1;
}
}
}
assert(f != nil);
arr1 := array;
N := len(arr1);
arr2 := make([]T, N);
defer free(arr2);
a, b, m, M := N/2, N, 1, _log2(N);
for i in 0..M+1 {
for j in 0..a {
k := 2*j*m;
merge_slices(arr1[k..k+m], arr1[k+m..k+m+m], arr2[k..], f);
}
if N-b > m {
k := 2*a*m;
merge_slices(arr1[k..k+m], arr1[k+m..k+m+(N-b)&(m-1)], arr2[k..], f);
} else {
copy(arr2[b..N], arr1[b..N]);
}
arr1, arr2 = arr2, arr1;
m <<= 1;
a >>= 1;
b = a << uint(i) << 2;
}
if M & 1 == 0 do copy(arr2, arr1);
}
merge_sort :: proc(array: $A/[]$T) {
merge_slices :: proc(arr1, arr2, out: A) {
N1, N2 := len(arr1), len(arr2);
i, j := 0, 0;
for k in 0..N1+N2 {
if j == N2 || i < N1 && j < N2 && arr1[i] < arr2[j] {
out[k] = arr1[i];
i += 1;
} else {
out[k] = arr2[j];
j += 1;
}
}
}
arr1 := array;
N := len(arr1);
arr2 := make([]T, N);
defer free(arr2);
a, b, m, M := N/2, N, 1, _log2(N);
for i in 0..M+1 {
for j in 0..a {
k := 2*j*m;
merge_slices(arr1[k..k+m], arr1[k+m..k+m+m], arr2[k..]);
}
if N-b > m {
k := 2*a*m;
merge_slices(arr1[k..k+m], arr1[k+m..k+m+(N-b)&(m-1)], arr2[k..]);
} else {
copy(arr2[b..N], arr1[b..N]);
}
arr1, arr2 = arr2, arr1;
m <<= 1;
a >>= 1;
b = a << uint(i) << 2;
}
if M & 1 == 0 do copy(arr2, arr1);
}
compare_ints :: proc(a, b: int) -> int {
switch delta := a - b; {
case delta < 0: return -1;
case delta > 0: return +1;
}
return 0;
}
compare_f32s :: proc(a, b: f32) -> int {
switch delta := a - b; {
case delta < 0: return -1;
case delta > 0: return +1;
}
return 0;
}
compare_f64s :: proc(a, b: f64) -> int {
switch delta := a - b; {
case delta < 0: return -1;
case delta > 0: return +1;
}
return 0;
}
compare_strings :: proc(a, b: string) -> int {
return __string_cmp(a, b);
}
+181 -198
View File
@@ -1,37 +1,37 @@
import . "decimal.odin";
using import "core:decimal.odin"
type IntFlag enum {
Int_Flag :: enum {
Prefix = 1<<0,
Plus = 1<<1,
Space = 1<<2,
}
proc parse_bool(s: string) -> (result: bool, ok: bool) {
match s {
parse_bool :: proc(s: string) -> (result: bool = false, ok: bool) {
switch s {
case "1", "t", "T", "true", "TRUE", "True":
return true, true;
case "0", "f", "F", "false", "FALSE", "False":
return false, true;
}
return false, false;
return ok = 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;
_digit_value :: proc(r: rune) -> int {
ri := int(r);
v: int = 16;
switch r {
case '0'...'9': v = ri-'0';
case 'a'...'z': v = ri-'a'+10;
case 'A'...'Z': v = ri-'A'+10;
}
return v;
}
proc parse_i128(s: string) -> i128 {
var neg = false;
parse_i128 :: proc(s: string) -> i128 {
neg := false;
if len(s) > 1 {
match s[0] {
switch s[0] {
case '-':
neg = true;
s = s[1..];
@@ -41,9 +41,9 @@ proc parse_i128(s: string) -> i128 {
}
var base: i128 = 10;
base: i128 = 10;
if len(s) > 2 && s[0] == '0' {
match s[1] {
switch s[1] {
case 'b': base = 2; s = s[2..];
case 'o': base = 8; s = s[2..];
case 'd': base = 10; s = s[2..];
@@ -53,13 +53,13 @@ proc parse_i128(s: string) -> i128 {
}
var value: i128;
value: i128;
for r in s {
if r == '_' {
continue;
}
var v = i128(_digit_value(r));
v := i128(_digit_value(r));
if v >= base {
break;
}
@@ -67,19 +67,20 @@ proc parse_i128(s: string) -> i128 {
value += v;
}
return neg ? -value : value;
if neg do return -value;
return value;
}
proc parse_u128(s: string) -> u128 {
var neg = false;
parse_u128 :: proc(s: string) -> u128 {
neg := false;
if len(s) > 1 && s[0] == '+' {
s = s[1..];
}
var base = u128(10);
base := u128(10);
if len(s) > 2 && s[0] == '0' {
match s[1] {
switch s[1] {
case 'b': base = 2; s = s[2..];
case 'o': base = 8; s = s[2..];
case 'd': base = 10; s = s[2..];
@@ -89,167 +90,157 @@ proc parse_u128(s: string) -> u128 {
}
var value: u128;
value: u128;
for r in s {
if r == '_' {
continue;
}
var v = u128(_digit_value(r));
if v >= base {
break;
}
if r == '_' do continue;
v := u128(_digit_value(r));
if v >= base do break;
value *= base;
value += u128(v);
}
return neg ? -value : value;
if neg do return -value;
return value;
}
proc parse_int(s: string) -> int {
parse_int :: proc(s: string) -> int {
return int(parse_i128(s));
}
proc parse_uint(s: string, base: int) -> uint {
parse_uint :: proc(s: string, base: int) -> uint {
return uint(parse_u128(s));
}
proc parse_f64(s: string) -> f64 {
var i = 0;
parse_f64 :: proc(s: string) -> f64 {
i := 0;
var sign: f64 = 1;
match s[i] {
case '-': i++; sign = -1;
case '+': i++;
sign: f64 = 1;
switch s[i] {
case '-': i += 1; sign = -1;
case '+': i += 1;
}
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: f64 = 0;
for ; i < len(s); i += 1 {
r := rune(s[i]);
if r == '_' do continue;
v := _digit_value(r);
if v >= 10 do break;
value *= 10;
value += f64(v);
}
if s[i] == '.' {
var pow10: f64 = 10;
i++;
if i < len(s) && s[i] == '.' {
pow10: f64 = 10;
i += 1;
for ; i < len(s); i++ {
var r = rune(s[i]);
if r == '_' {
continue;
}
var v = _digit_value(r);
if v >= 10 {
break;
}
for ; i < len(s); i += 1 {
r := rune(s[i]);
if r == '_' do continue;
v := _digit_value(r);
if v >= 10 do break;
value += f64(v)/pow10;
pow10 *= 10;
}
}
var frac = false;
var scale: f64 = 1;
frac := false;
scale: f64 = 1;
if s[i] == 'e' || s[i] == 'E' {
i++;
if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
i += 1;
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;
if i < len(s) {
switch s[i] {
case '-': i += 1; frac = true;
case '+': i += 1;
}
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; }
exp: u32 = 0;
for ; i < len(s); i += 1 {
r := rune(s[i]);
if r == '_' do continue;
d := u32(_digit_value(r));
if d >= 10 do break;
exp = exp * 10 + d;
}
if exp > 308 { exp = 308; }
for exp >= 50 { scale *= 1e50; exp -= 50; }
for exp >= 8 { scale *= 1e8; exp -= 8; }
for exp > 0 { scale *= 10; exp -= 1; }
}
}
return sign * (frac ? (value/scale) : (value*scale));
if frac do return sign * (value/scale);
return sign * (value*scale);
}
proc append_bool(buf: []u8, b: bool) -> string {
var s = b ? "true" : "false";
append(buf, ..[]u8(s));
append_bool :: proc(buf: []u8, b: bool) -> string {
if b do append(&buf, "true");
else do append(&buf, "false");
return string(buf);
}
proc append_uint(buf: []u8, u: u64, base: int) -> string {
append_uint :: proc(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 {
append_int :: proc(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); }
itoa :: proc(buf: []u8, i: int) -> string do return append_int(buf, i64(i), 10);
proc append_float(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string {
append_float :: proc(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string {
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
}
type DecimalSlice struct {
DecimalSlice :: struct {
digits: []u8,
count: int,
decimal_point: int,
neg: bool,
}
type Float_Info struct {
FloatInfo :: 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 {
_f16_info := FloatInfo{10, 5, -15};
_f32_info := FloatInfo{23, 8, -127};
_f64_info := FloatInfo{52, 11, -1023};
generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
bits: u64;
flt: ^FloatInfo;
switch bit_size {
case 32:
bits = u64(transmute(u32, f32(val)));
bits = u64(transmute(u32)f32(val));
flt = &_f32_info;
case 64:
bits = transmute(u64, val);
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);
neg := bits>>(flt.expbits+flt.mantbits) != 0;
exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
mant := bits & (u64(1) << flt.mantbits - 1);
match exp {
switch exp {
case 1<<flt.expbits - 1:
var s: string;
s: string;
if mant != 0 {
s = "NaN";
} else if neg {
@@ -257,11 +248,11 @@ proc generic_ftoa(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
} else {
s = "+Inf";
}
append(buf, ..[]u8(s));
append(&buf, ...cast([]u8)s);
return buf;
case 0: // denormalized
exp++;
exp += 1;
case:
mant |= u64(1) << flt.mantbits;
@@ -269,22 +260,22 @@ proc generic_ftoa(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
exp += flt.bias;
var d_: Decimal;
var d = &d_;
d_: Decimal;
d := &d_;
assign(d, mant);
shift(d, exp - int(flt.mantbits));
var digs: DecimalSlice;
var shortest = prec < 0;
digs: DecimalSlice;
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 {
switch fmt {
case 'e', 'E': prec = digs.count-1;
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
case 'g', 'G': prec = digs.count;
}
} else {
match fmt {
switch fmt {
case 'e', 'E': round(d, prec+1);
case 'f', 'F': round(d, d.decimal_point+prec);
case 'g', 'G':
@@ -301,35 +292,34 @@ proc generic_ftoa(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
proc format_digits(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: u8) -> []u8 {
match fmt {
format_digits :: proc(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: u8) -> []u8 {
switch fmt {
case 'f', 'F':
append(buf, neg ? '-' : '+');
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');
m := min(digs.count, digs.decimal_point);
append(&buf, ...digs.digits[0..m]);
for ; m < digs.decimal_point; m += 1 {
append(&buf, '0');
}
} else {
append(buf, '0');
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 {
append(&buf, '.');
for i in 0..prec {
c: u8 = '0';
if j := digs.decimal_point + i; 0 <= j && j < digs.count {
c = digs.digits[j];
}
append(buf, c);
append(&buf, c);
}
}
return buf;
case 'e', 'E':
@@ -341,14 +331,12 @@ proc format_digits(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice, pre
return buf; // TODO
}
var c: [2]u8;
c[0] = '%';
c[1] = fmt;
append(buf, ..c[..]);
c := [2]u8{'%', fmt};
append(&buf, ...c[..]);
return buf;
}
proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^FloatInfo) {
if mant == 0 { // If mantissa is zero, the number is zero
d.count = 0;
return;
@@ -360,18 +348,18 @@ proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
log(2) >~ 0.332
332*(dp-nd) >= 100*(exp-mantbits)
*/
var minexp = flt.bias+1;
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_;
upper_: Decimal; upper := &upper_;
assign(upper, 2*mant - 1);
shift(upper, exp - int(flt.mantbits) - 1);
var mantlo: u64;
var explo: int;
mantlo: u64;
explo: int;
if mant > 1<<flt.mantbits || exp == minexp {
mantlo = mant-1;
explo = exp;
@@ -379,35 +367,35 @@ proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
mantlo = 2*mant - 1;
explo = exp-1;
}
var lower_: Decimal; var lower = &lower_;
lower_: Decimal; lower := &lower_;
assign(lower, 2*mantlo + 1);
shift(lower, explo - int(flt.mantbits) - 1);
var inclusive = mant%2 == 0;
inclusive := mant%2 == 0;
for i in 0..<d.count {
var l: u8 = '0'; // lower digit
for i in 0..d.count {
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
m := d.digits[i]; // middle digit
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);
ok_round_down := l != m || inclusive && i+1 == lower.count;
ok_round_up := m != u && (inclusive || m+1 < u || i+1 < upper.count);
if (ok_round_down && ok_round_up) {
if ok_round_down && ok_round_up {
round(d, i+1);
return;
}
if (ok_round_down) {
if ok_round_down {
round_down(d, i+1);
return;
}
if (ok_round_up) {
if ok_round_up {
round_up(d, i+1);
return;
}
@@ -415,39 +403,34 @@ proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
}
const MAX_BASE = 32;
var digits = "0123456789abcdefghijklmnopqrstuvwxyz";
MAX_BASE :: 32;
digits := "0123456789abcdefghijklmnopqrstuvwxyz";
proc is_integer_negative(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
var neg = false;
is_integer_negative :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
neg := false;
if is_signed {
match bit_size {
switch bit_size {
case 8:
var i = i8(u);
i := i8(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
u = u128(abs(i));
case 16:
var i = i16(u);
i := i16(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
u = u128(abs(i));
case 32:
var i = i32(u);
i := i32(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
u = u128(abs(i));
case 64:
var i = i64(u);
i := i64(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
u = u128(abs(i));
case 128:
var i = i128(u);
i := i128(u);
neg = i < 0;
if neg { i = -i; }
u = u128(i);
u = u128(abs(i));
case:
panic("is_integer_negative: Unknown integer size");
}
@@ -455,46 +438,46 @@ proc is_integer_negative(u: u128, is_signed: bool, bit_size: int) -> (unsigned:
return u, neg;
}
proc append_bits(buf: []u8, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: IntFlag) -> string {
append_bits :: proc(buf: []u8, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> 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);
neg: bool;
a: [129]u8;
i := len(a);
u, neg = is_integer_negative(u, is_signed, bit_size);
var b = u128(base);
b := u128(base);
for u >= b {
i--; a[i] = digits[uint(u % b)];
i-=1; a[i] = digits[uint(u % b)];
u /= b;
}
i--; a[i] = digits[uint(u % b)];
i-=1; 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';
if flags&Int_Flag.Prefix != 0 {
ok := true;
switch base {
case 2: i-=1; a[i] = 'b';
case 8: i-=1; a[i] = 'o';
case 10: i-=1; a[i] = 'd';
case 12: i-=1; a[i] = 'z';
case 16: i-=1; a[i] = 'x';
case: ok = false;
}
if ok {
i--; a[i] = '0';
i-=1; 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] = ' ';
i-=1; a[i] = '-';
} else if flags&Int_Flag.Plus != 0 {
i-=1; a[i] = '+';
} else if flags&Int_Flag.Space != 0 {
i-=1; a[i] = ' ';
}
append(buf, ..a[i..]);
append(&buf, ...a[i..]);
return string(buf);
}
+14 -13
View File
@@ -1,21 +1,22 @@
proc new_string(s: string) -> string {
var c = make([]u8, len(s)+1);
copy(c, []u8(s));
import "core:mem.odin"
new_string :: proc(s: string) -> string {
c := make([]u8, len(s)+1);
copy(c, cast([]u8)s);
c[len(s)] = 0;
return string(c[0..<len(s)]);
return string(c[..len(s)]);
}
proc new_c_string(s: string) -> ^u8 {
var c = make([]u8, len(s)+1);
copy(c, []u8(s));
new_c_string :: proc(s: string) -> ^u8 {
c := make([]u8, len(s)+1);
copy(c, cast([]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));
to_odin_string :: proc(str: ^u8) -> string {
if str == nil do return "";
end := str;
for end^ != 0 do end+=1;
return string(mem.slice_ptr(str, end-str));
}
+2 -4
View File
@@ -1,4 +1,2 @@
import_load (
"sync_windows.odin" when ODIN_OS == "windows";
"sync_linux.odin" when ODIN_OS == "linux";
)
when ODIN_OS == "windows" do export "core:sync_windows.odin";
when ODIN_OS == "linux" do export "core:sync_linux.odin";
+23 -25
View File
@@ -1,69 +1,67 @@
import (
"atomics.odin";
"os.odin";
)
import "core:atomics.odin"
import "core:os.odin"
type Semaphore struct {
Semaphore :: struct {
// _handle: win32.Handle,
}
type Mutex struct {
Mutex :: struct {
_semaphore: Semaphore,
_counter: i32,
_owner: i32,
_recursion: i32,
}
proc current_thread_id() -> i32 {
current_thread_id :: proc() -> i32 {
return i32(os.current_thread_id());
}
proc semaphore_init(s: ^Semaphore) {
semaphore_init :: proc(s: ^Semaphore) {
// s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
}
proc semaphore_destroy(s: ^Semaphore) {
semaphore_destroy :: proc(s: ^Semaphore) {
// win32.CloseHandle(s._handle);
}
proc semaphore_post(s: ^Semaphore, count: int) {
semaphore_post :: proc(s: ^Semaphore, count: int) {
// win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
}
proc semaphore_release(s: ^Semaphore) #inline {
semaphore_release :: inline proc(s: ^Semaphore) {
semaphore_post(s, 1);
}
proc semaphore_wait(s: ^Semaphore) {
semaphore_wait :: proc(s: ^Semaphore) {
// win32.WaitForSingleObject(s._handle, win32.INFINITE);
}
proc mutex_init(m: ^Mutex) {
mutex_init :: proc(m: ^Mutex) {
atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore);
m._recursion = 0;
}
proc mutex_destroy(m: ^Mutex) {
mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(&m._semaphore);
}
proc mutex_lock(m: ^Mutex) {
var thread_id = current_thread_id();
mutex_lock :: proc(m: ^Mutex) {
thread_id := current_thread_id();
if atomics.fetch_add(&m._counter, 1) > 0 {
if thread_id != atomics.load(&m._owner) {
semaphore_wait(&m._semaphore);
}
}
atomics.store(&m._owner, thread_id);
m._recursion++;
m._recursion += 1;
}
proc mutex_try_lock(m: ^Mutex) -> bool {
var thread_id = current_thread_id();
mutex_try_lock :: proc(m: ^Mutex) -> bool {
thread_id := current_thread_id();
if atomics.load(&m._owner) == thread_id {
atomics.fetch_add(&m._counter, 1);
} else {
var expected: i32 = 0;
expected: i32 = 0;
if atomics.load(&m._counter) != 0 {
return false;
}
@@ -72,15 +70,15 @@ proc mutex_try_lock(m: ^Mutex) -> bool {
}
atomics.store(&m._owner, thread_id);
}
m._recursion++;
m._recursion += 1;
return true;
}
proc mutex_unlock(m: ^Mutex) {
var recursion: i32;
var thread_id = current_thread_id();
mutex_unlock :: proc(m: ^Mutex) {
recursion: i32;
thread_id := current_thread_id();
assert(thread_id == atomics.load(&m._owner));
m._recursion--;
m._recursion -= 1;
recursion = m._recursion;
if recursion == 0 {
atomics.store(&m._owner, thread_id);
+54 -23
View File
@@ -1,53 +1,84 @@
import (
win32 "sys/windows.odin" when ODIN_OS == "windows";
"atomics.odin";
)
when ODIN_OS == "windows" {
import win32 "core:sys/windows.odin";
}
import "core:atomics.odin"
type Semaphore struct {
Semaphore :: struct {
_handle: win32.Handle,
}
type Mutex struct {
/*
Mutex :: struct {
_semaphore: Semaphore,
_counter: i32,
_owner: i32,
_recursion: i32,
}
*/
proc current_thread_id() -> i32 {
Mutex :: struct {
_critical_section: win32.Critical_Section,
}
current_thread_id :: proc() -> i32 {
return i32(win32.get_current_thread_id());
}
proc semaphore_init(s: ^Semaphore) {
semaphore_init :: proc(s: ^Semaphore) {
s._handle = win32.create_semaphore_a(nil, 0, 1<<31-1, nil);
}
proc semaphore_destroy(s: ^Semaphore) {
semaphore_destroy :: proc(s: ^Semaphore) {
win32.close_handle(s._handle);
}
proc semaphore_post(s: ^Semaphore, count: int) {
semaphore_post :: proc(s: ^Semaphore, count: int) {
win32.release_semaphore(s._handle, i32(count), nil);
}
proc semaphore_release(s: ^Semaphore) #inline { semaphore_post(s, 1); }
semaphore_release :: inline proc(s: ^Semaphore) {
semaphore_post(s, 1);
}
proc semaphore_wait(s: ^Semaphore) {
semaphore_wait :: proc(s: ^Semaphore) {
win32.wait_for_single_object(s._handle, win32.INFINITE);
}
proc mutex_init(m: ^Mutex) {
mutex_init :: proc(m: ^Mutex, spin_count := 0) {
win32.initialize_critical_section_and_spin_count(&m._critical_section, u32(spin_count));
}
mutex_destroy :: proc(m: ^Mutex) {
win32.delete_critical_section(&m._critical_section);
}
mutex_lock :: proc(m: ^Mutex) {
win32.enter_critical_section(&m._critical_section);
}
mutex_try_lock :: proc(m: ^Mutex) -> bool {
return win32.try_enter_critical_section(&m._critical_section) != 0;
}
mutex_unlock :: proc(m: ^Mutex) {
win32.leave_critical_section(&m._critical_section);
}
/*
mutex_init :: proc(m: ^Mutex) {
atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore);
m._recursion = 0;
}
proc mutex_destroy(m: ^Mutex) {
mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(&m._semaphore);
}
proc mutex_lock(m: ^Mutex) {
var thread_id = current_thread_id();
mutex_lock :: proc(m: ^Mutex) {
thread_id := current_thread_id();
if atomics.fetch_add(&m._counter, 1) > 0 {
if thread_id != atomics.load(&m._owner) {
semaphore_wait(&m._semaphore);
@@ -56,12 +87,12 @@ proc mutex_lock(m: ^Mutex) {
atomics.store(&m._owner, thread_id);
m._recursion++;
}
proc mutex_try_lock(m: ^Mutex) -> bool {
var thread_id = current_thread_id();
mutex_try_lock :: proc(m: ^Mutex) -> bool {
thread_id := current_thread_id();
if atomics.load(&m._owner) == thread_id {
atomics.fetch_add(&m._counter, 1);
} else {
var expected: i32 = 0;
expected: i32 = 0;
if atomics.load(&m._counter) != 0 {
return false;
}
@@ -73,9 +104,9 @@ proc mutex_try_lock(m: ^Mutex) -> bool {
m._recursion++;
return true;
}
proc mutex_unlock(m: ^Mutex) {
var recursion: i32;
var thread_id = current_thread_id();
mutex_unlock :: proc(m: ^Mutex) {
recursion: i32;
thread_id := current_thread_id();
assert(thread_id == atomics.load(&m._owner));
m._recursion--;
@@ -90,4 +121,4 @@ proc mutex_unlock(m: ^Mutex) {
}
}
}
*/
+104 -79
View File
@@ -1,90 +1,115 @@
foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
import . "windows.odin";
when ODIN_OS == "windows" {
foreign import "system:opengl32.lib"
using import "core:sys/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;
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;
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,
}
Hglrc :: Handle;
Color_Ref :: u32;
PointFloat struct {
x, y: f32,
}
Layer_Plane_Descriptor :: 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: Color_Ref,
}
Glyph_MetricsFloat struct {
black_box_x: f32,
black_box_y: f32,
glyph_origin: PointFloat,
cell_inc_x: f32,
cell_inc_y: f32,
}
)
Point_Float :: struct {x, 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;
)
Glyph_Metrics_Float :: struct {
black_box_x: f32,
black_box_y: f32,
glyph_origin: Point_Float,
cell_inc_x: f32,
cell_inc_y: f32,
}
var (
create_context_attribs_arb: CreateContextAttribsARBType;
choose_pixel_format_arb: ChoosePixelFormatARBType;
swap_interval_ext: SwapIntervalEXTType;
get_extensions_string_arb: GetExtensionsStringARBType;
)
Create_Context_Attribs_ARB_Type :: #type proc "c" (hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
Choose_Pixel_Format_ARB_Type :: #type proc "c" (hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool;
Swap_Interval_EXT_Type :: #type proc "c" (interval: i32) -> bool;
Get_Extensions_String_ARB_Type :: #type proc "c" (Hdc) -> ^u8;
// Procedures
create_context_attribs_arb: Create_Context_Attribs_ARB_Type;
choose_pixel_format_arb: Choose_Pixel_Format_ARB_Type;
swap_interval_ext: Swap_Interval_EXT_Type;
get_extensions_string_arb: Get_Extensions_String_ARB_Type;
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";
@(link_name="wglCreateContext")
create_context :: proc(hdc: Hdc) -> Hglrc ---;
@(link_name="wglMakeCurrent")
make_current :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool ---;
@(link_name="wglGetProcAddress")
get_proc_address :: proc(c_str: ^u8) -> rawptr ---;
@(link_name="wglDeleteContext")
delete_context :: proc(hglrc: Hglrc) -> Bool ---;
@(link_name="wglCopyContext")
copy_context :: proc(src, dst: Hglrc, mask: u32) -> Bool ---;
@(link_name="wglCreateLayerContext")
create_layer_context :: proc(hdc: Hdc, layer_plane: i32) -> Hglrc ---;
@(link_name="wglDescribeLayerPlane")
describe_layer_plane :: proc(hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^Layer_Plane_Descriptor) -> Bool ---;
@(link_name="wglGetCurrentContext")
get_current_context :: proc() -> Hglrc ---;
@(link_name="wglGetCurrentDC")
get_current_dc :: proc() -> Hdc ---;
@(link_name="wglGetLayerPaletteEntries")
get_layer_palette_entries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 ---;
@(link_name="wglRealizeLayerPalette")
realize_layer_palette :: proc(hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool ---;
@(link_name="wglSetLayerPaletteEntries")
set_layer_palette_entries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 ---;
@(link_name="wglShareLists")
share_lists :: proc(hglrc1, hglrc2: Hglrc) -> Bool ---;
@(link_name="wglSwapLayerBuffers")
swap_layer_buffers :: proc(hdc: Hdc, planes: u32) -> Bool ---;
@(link_name="wglUseFontBitmaps")
use_font_bitmaps :: proc(hdc: Hdc, first, count, list_base: u32) -> Bool ---;
@(link_name="wglUseFontOutlines")
use_font_outlines :: proc(hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_Metrics_Float) -> Bool ---;
}
+543 -331
View File
File diff suppressed because it is too large Load Diff
+75
View File
@@ -0,0 +1,75 @@
_ :: compile_assert(ODIN_OS == "windows");
when ODIN_OS == "windows" {
import win32 "core:sys/windows.odin"
}
Thread_Proc :: #type proc(^Thread) -> int;
Thread_Os_Specific :: struct {
win32_thread: win32.Handle,
win32_thread_id: u32,
}
Thread :: struct {
using specific: Thread_Os_Specific,
procedure: Thread_Proc,
data: any,
user_index: int,
init_context: Context,
use_init_context: bool,
}
create :: proc(procedure: Thread_Proc) -> ^Thread {
win32_thread_id: u32;
__windows_thread_entry_proc :: proc "c" (t: ^Thread) -> i32 {
c := context;
if t.use_init_context {
c = t.init_context;
}
exit := 0;
context <- c {
exit = t.procedure(t);
}
return i32(exit);
}
win32_thread_proc := rawptr(__windows_thread_entry_proc);
thread := new(Thread);
win32_thread := win32.create_thread(nil, 0, win32_thread_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id);
if win32_thread == nil {
free(thread);
return nil;
}
thread.procedure = procedure;
thread.win32_thread = win32_thread;
thread.win32_thread_id = win32_thread_id;
return thread;
}
start :: proc(using thread: ^Thread) {
win32.resume_thread(win32_thread);
}
is_done :: proc(using thread: ^Thread) -> bool {
res := win32.wait_for_single_object(win32_thread, 0);
return res != win32.WAIT_TIMEOUT;
}
join :: proc(using thread: ^Thread) {
win32.wait_for_single_object(win32_thread, win32.INFINITE);
win32.close_handle(win32_thread);
win32_thread = win32.INVALID_HANDLE;
}
destroy :: proc(thread: ^Thread) {
join(thread);
free(thread);
}
+226 -61
View File
@@ -1,98 +1,263 @@
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;
are_types_identical :: proc(a, b: ^Type_Info) -> bool {
if a == b do return true;
if (a == nil && b != nil) ||
(a != nil && b == nil) {
return false;
}
switch {
case a.size != b.size, a.align != b.align:
return false;
}
switch x in a.variant {
case Type_Info_Named:
y, ok := b.variant.(Type_Info_Named);
if !ok do return false;
return x.base == y.base;
case Type_Info_Integer:
y, ok := b.variant.(Type_Info_Integer);
if !ok do return false;
return x.signed == y.signed;
case Type_Info_Rune:
_, ok := b.variant.(Type_Info_Rune);
return ok;
case Type_Info_Float:
_, ok := b.variant.(Type_Info_Float);
return ok;
case Type_Info_Complex:
_, ok := b.variant.(Type_Info_Complex);
return ok;
case Type_Info_String:
_, ok := b.variant.(Type_Info_String);
return ok;
case Type_Info_Boolean:
_, ok := b.variant.(Type_Info_Boolean);
return ok;
case Type_Info_Any:
_, ok := b.variant.(Type_Info_Any);
return ok;
case Type_Info_Pointer:
y, ok := b.variant.(Type_Info_Pointer);
return are_types_identical(x.elem, y.elem);
case Type_Info_Procedure:
y, ok := b.variant.(Type_Info_Procedure);
if !ok do return false;
switch {
case x.variadic != y.variadic,
x.convention != y.convention:
return false;
}
return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results);
case Type_Info_Array:
y, ok := b.variant.(Type_Info_Array);
if !ok do return false;
if x.count != y.count do return false;
return are_types_identical(x.elem, y.elem);
case Type_Info_Dynamic_Array:
y, ok := b.variant.(Type_Info_Dynamic_Array);
if !ok do return false;
return are_types_identical(x.elem, y.elem);
case Type_Info_Slice:
y, ok := b.variant.(Type_Info_Slice);
if !ok do return false;
return are_types_identical(x.elem, y.elem);
case Type_Info_Vector:
y, ok := b.variant.(Type_Info_Vector);
if !ok do return false;
if x.count != y.count do return false;
return are_types_identical(x.elem, y.elem);
case Type_Info_Tuple:
y, ok := b.variant.(Type_Info_Tuple);
if !ok do return false;
if len(x.types) != len(y.types) do return false;
for _, i in x.types {
xt, yt := x.types[i], y.types[i];
if !are_types_identical(xt, yt) {
return false;
}
}
return true;
case Type_Info_Struct:
y, ok := b.variant.(Type_Info_Struct);
if !ok do return false;
switch {
case len(x.types) != len(y.types),
x.is_packed != y.is_packed,
x.is_ordered != y.is_ordered,
x.is_raw_union != y.is_raw_union,
x.custom_align != y.custom_align:
return false;
}
for _, i in x.types {
xn, yn := x.names[i], y.names[i];
xt, yt := x.types[i], y.types[i];
if xn != yn do return false;
if !are_types_identical(xt, yt) do return false;
}
return true;
case Type_Info_Union:
y, ok := b.variant.(Type_Info_Union);
if !ok do return false;
if len(x.variants) != len(y.variants) do return false;
for _, i in x.variants {
xv, yv := x.variants[i], y.variants[i];
if !are_types_identical(xv, yv) do return false;
}
return true;
case Type_Info_Enum:
// NOTE(bill): Should be handled above
return false;
case Type_Info_Map:
y, ok := b.variant.(Type_Info_Map);
if !ok do return false;
return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value);
case Type_Info_Bit_Field:
y, ok := b.variant.(Type_Info_Bit_Field);
if !ok do return false;
if len(x.names) != len(y.names) do return false;
for _, i in x.names {
xb, yb := x.bits[i], y.bits[i];
xo, yo := x.offsets[i], y.offsets[i];
xn, yn := x.names[i], y.names[i];
if xb != yb do return false;
if xo != yo do return false;
if xn != yn do return false;
}
return true;
}
return false;
}
is_signed :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
switch i in type_info_base(info).variant {
case Type_Info_Integer: return i.signed;
case Type_Info_Float: return true;
}
return false;
}
proc is_integer(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Integer);
is_integer :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Integer);
return ok;
}
proc is_float(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Float);
is_rune :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Rune);
return ok;
}
proc is_complex(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Complex);
is_float :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Float);
return ok;
}
proc is_any(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Any);
is_complex :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Complex);
return ok;
}
proc is_string(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.String);
is_any :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Any);
return ok;
}
proc is_boolean(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Boolean);
is_string :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_String);
return ok;
}
proc is_pointer(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Pointer);
is_boolean :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Boolean);
return ok;
}
proc is_procedure(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Procedure);
is_pointer :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Pointer);
return ok;
}
proc is_array(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Array);
is_procedure :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Procedure);
return ok;
}
proc is_dynamic_array(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.DynamicArray);
is_array :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Array);
return ok;
}
proc is_dynamic_map(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Map);
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Dynamic_Array);
return ok;
}
proc is_slice(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Slice);
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Map);
return ok;
}
proc is_vector(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Vector);
is_slice :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Slice);
return ok;
}
proc is_tuple(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Tuple);
is_vector :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Vector);
return ok;
}
proc is_struct(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Struct);
is_tuple :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Tuple);
return ok;
}
proc is_union(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Union);
is_struct :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
s, ok := type_info_base(info).variant.(Type_Info_Struct);
return ok && !s.is_raw_union;
}
is_raw_union :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
s, ok := type_info_base(info).variant.(Type_Info_Struct);
return ok && s.is_raw_union;
}
is_union :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_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);
is_enum :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info_Enum);
return ok;
}
+50 -24
View File
@@ -1,18 +1,19 @@
const (
REPLACEMENT_CHAR = '\uFFFD';
MAX_RUNE = '\U0010FFFF';
import "utf8.odin"
_surr1 = 0xd800;
_surr2 = 0xdc00;
_surr3 = 0xe000;
_surr_self = 0x10000;
)
REPLACEMENT_CHAR :: '\uFFFD';
MAX_RUNE :: '\U0010FFFF';
proc is_surrogate(r: rune) -> bool {
_surr1 :: 0xd800;
_surr2 :: 0xdc00;
_surr3 :: 0xe000;
_surr_self :: 0x10000;
is_surrogate :: proc(r: rune) -> bool {
return _surr1 <= r && r < _surr3;
}
proc decode_surrogate_pair(r1, r2: rune) -> rune {
decode_surrogate_pair :: proc(r1, r2: rune) -> rune {
if _surr1 <= r1 && r1 < _surr2 && _surr2 <= r2 && r2 < _surr3 {
return (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self;
}
@@ -20,7 +21,7 @@ proc decode_surrogate_pair(r1, r2: rune) -> rune {
}
proc encode_surrogate_pair(r: rune) -> (r1, r2: rune) {
encode_surrogate_pair :: proc(r: rune) -> (r1, r2: rune) {
if r < _surr_self || r > MAX_RUNE {
return REPLACEMENT_CHAR, REPLACEMENT_CHAR;
}
@@ -28,32 +29,57 @@ proc encode_surrogate_pair(r: rune) -> (r1, r2: rune) {
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++;
}
}
encode :: proc(d: []u16, s: []rune) -> int {
n := len(s);
for r in s do if r >= _surr_self do n += 1;
var max_n = min(len(d), n);
max_n := min(len(d), n);
n = 0;
for r in s {
match r {
case 0..<_surr1, _surr3..<_surr_self:
switch r {
case 0.._surr1, _surr3.._surr_self:
d[n] = u16(r);
n++;
n += 1;
case _surr_self..MAX_RUNE:
var r1, r2 = encode_surrogate_pair(r);
r1, r2 := encode_surrogate_pair(r);
d[n] = u16(r1);
d[n+1] = u16(r2);
n += 2;
case:
d[n] = u16(REPLACEMENT_CHAR);
n++;
n += 1;
}
}
return n;
}
encode :: proc(d: []u16, s: string) -> int {
n := utf8.rune_count(s);
for r in s do if r >= _surr_self do n += 1;
max_n := min(len(d), n);
n = 0;
for r in s {
switch r {
case 0.._surr1, _surr3.._surr_self:
d[n] = u16(r);
n += 1;
case _surr_self..MAX_RUNE:
r1, r2 := encode_surrogate_pair(r);
d[n] = u16(r1);
d[n+1] = u16(r2);
n += 2;
case:
d[n] = u16(REPLACEMENT_CHAR);
n += 1;
}
}
return n;
}
+103 -111
View File
@@ -1,71 +1,67 @@
const (
RUNE_ERROR = '\ufffd';
RUNE_SELF = 0x80;
RUNE_BOM = 0xfeff;
RUNE_EOF = ~rune(0);
MAX_RUNE = '\U0010ffff';
UTF_MAX = 4;
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;
T1 = 0b0000_0000;
TX = 0b1000_0000;
T2 = 0b1100_0000;
T3 = 0b1110_0000;
T4 = 0b1111_0000;
T5 = 0b1111_1000;
T1 :: 0b0000_0000;
TX :: 0b1000_0000;
T2 :: 0b1100_0000;
T3 :: 0b1110_0000;
T4 :: 0b1111_0000;
T5 :: 0b1111_1000;
MASKX = 0b0011_1111;
MASK2 = 0b0001_1111;
MASK3 = 0b0000_1111;
MASK4 = 0b0000_0111;
MASKX :: 0b0011_1111;
MASK2 :: 0b0001_1111;
MASK3 :: 0b0000_1111;
MASK4 :: 0b0000_0111;
RUNE1_MAX = 1<<7 - 1;
RUNE2_MAX = 1<<11 - 1;
RUNE3_MAX = 1<<16 - 1;
RUNE1_MAX :: 1<<7 - 1;
RUNE2_MAX :: 1<<11 - 1;
RUNE3_MAX :: 1<<16 - 1;
// The default lowest and highest continuation byte.
LOCB = 0b1000_0000;
HICB = 0b1011_1111;
)
LOCB :: 0b1000_0000;
HICB :: 0b1011_1111;
type AcceptRange struct { lo, hi: u8 }
Accept_Range :: struct {lo, hi: u8};
var (
accept_ranges = [5]AcceptRange{
{0x80, 0xbf},
{0xa0, 0xbf},
{0x80, 0x9f},
{0x90, 0xbf},
{0x80, 0x8f},
};
accept_ranges := [5]Accept_Range{
{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
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
};
)
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;
encode_rune :: proc(r: rune) -> ([4]u8, int) {
buf: [4]u8;
i := u32(r);
mask :: u8(0x3f);
if i <= 1<<7-1 {
buf[0] = u8(r);
return buf, 1;
@@ -96,38 +92,38 @@ proc encode_rune(r: rune) -> ([4]u8, int) {
return buf, 4;
}
proc decode_rune(s: string) -> (rune, int) #inline { return decode_rune([]u8(s)); }
proc decode_rune(s: []u8) -> (rune, int) {
var n = len(s);
decode_rune :: inline proc(s: string) -> (rune, int) do return decode_rune(cast([]u8)s);
decode_rune :: proc(s: []u8) -> (rune, int) {
n := len(s);
if n < 1 {
return RUNE_ERROR, 0;
}
var s0 = s[0];
var x = accept_sizes[s0];
s0 := s[0];
x := accept_sizes[s0];
if x >= 0xF0 {
var mask = rune(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
mask := rune(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
return rune(s[0])&~mask | RUNE_ERROR&mask, 1;
}
var sz = x & 7;
var accept = accept_ranges[x>>4];
sz := x & 7;
accept := accept_ranges[x>>4];
if n < int(sz) {
return RUNE_ERROR, 1;
}
var b1 = s[1];
b1 := s[1];
if b1 < accept.lo || accept.hi < b1 {
return RUNE_ERROR, 1;
}
if sz == 2 {
return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2;
}
var b2 = s[2];
b2 := s[2];
if b2 < LOCB || HICB < b2 {
return RUNE_ERROR, 1;
}
if sz == 3 {
return rune(s0&MASK3)<<12 | rune(b1&MASKX)<<6 | rune(b2&MASKX), 3;
}
var b3 = s[3];
b3 := s[3];
if b3 < LOCB || HICB < b3 {
return RUNE_ERROR, 1;
}
@@ -136,11 +132,11 @@ proc decode_rune(s: []u8) -> (rune, int) {
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;
decode_last_rune :: inline proc(s: string) -> (rune, int) do return decode_last_rune(cast([]u8)s);
decode_last_rune :: proc(s: []u8) -> (rune, int) {
r: rune;
size: int;
start, end, limit: int;
end = len(s);
if end == 0 {
@@ -155,16 +151,12 @@ proc decode_last_rune(s: []u8) -> (rune, int) {
limit = max(end - UTF_MAX, 0);
start--;
for start >= limit {
if rune_start(s[start]) {
break;
}
start--;
for start-=1; start >= limit; start-=1 {
if rune_start(s[start]) do break;
}
start = max(start, 0);
r, size = decode_rune(s[start..<end]);
r, size = decode_rune(s[start..end]);
if start+size != end {
return RUNE_ERROR, 1;
}
@@ -175,7 +167,7 @@ proc decode_last_rune(s: []u8) -> (rune, int) {
proc valid_rune(r: rune) -> bool {
valid_rune :: proc(r: rune) -> bool {
if r < 0 {
return false;
} else if SURROGATE_MIN <= r && r <= SURROGATE_MAX {
@@ -186,32 +178,32 @@ proc valid_rune(r: rune) -> bool {
return true;
}
proc valid_string(s: string) -> bool {
var n = len(s);
for var i = 0; i < n; {
var si = s[i];
valid_string :: proc(s: string) -> bool {
n := len(s);
for i := 0; i < n; {
si := s[i];
if si < RUNE_SELF { // ascii
i++;
i += 1;
continue;
}
var x = accept_sizes[si];
x := accept_sizes[si];
if x == 0xf1 {
return false;
}
var size = int(x & 7);
size := int(x & 7);
if i+size > n {
return false;
}
var ar = accept_ranges[x>>4];
if var b = s[i+1]; b < ar.lo || ar.hi < b {
ar := accept_ranges[x>>4];
if b := s[i+1]; b < ar.lo || ar.hi < b {
return false;
} else if size == 2 {
// Okay
} else if var b = s[i+2]; b < 0x80 || 0xbf < b {
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
return false;
} else if size == 3 {
// Okay
} else if var b = s[i+3]; b < 0x80 || 0xbf < b {
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
return false;
}
i += size;
@@ -219,40 +211,40 @@ proc valid_string(s: string) -> bool {
return true;
}
proc rune_start(b: u8) -> bool #inline { return b&0xc0 != 0x80; }
rune_start :: inline proc(b: u8) -> bool do 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);
rune_count :: inline proc(s: string) -> int do return rune_count(cast([]u8)s);
rune_count :: proc(s: []u8) -> int {
count := 0;
n := len(s);
for var i = 0; i < n; {
defer count++;
var si = s[i];
for i := 0; i < n; {
defer count += 1;
si := s[i];
if si < RUNE_SELF { // ascii
i++;
i += 1;
continue;
}
var x = accept_sizes[si];
x := accept_sizes[si];
if x == 0xf1 {
i++;
i += 1;
continue;
}
var size = int(x & 7);
size := int(x & 7);
if i+size > n {
i++;
i += 1;
continue;
}
var ar = accept_ranges[x>>4];
if var b = s[i+1]; b < ar.lo || ar.hi < b {
ar := accept_ranges[x>>4];
if b := s[i+1]; b < ar.lo || ar.hi < b {
size = 1;
} else if size == 2 {
// Okay
} else if var b = s[i+2]; b < 0x80 || 0xbf < b {
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
size = 1;
} else if size == 3 {
// Okay
} else if var b = s[i+3]; b < 0x80 || 0xbf < b {
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
size = 1;
}
i += size;
@@ -261,8 +253,8 @@ proc rune_count(s: []u8) -> int {
}
proc rune_size(r: rune) -> int {
match {
rune_size :: proc(r: rune) -> int {
switch {
case r < 0: return -1;
case r <= 1<<7 - 1: return 1;
case r <= 1<<11 - 1: return 2;
+570
View File
@@ -0,0 +1,570 @@
import "core:fmt.odin"
import "core:strconv.odin"
import "core:mem.odin"
import "core:bits.odin"
import "core:hash.odin"
import "core:math.odin"
import "core:os.odin"
import "core:raw.odin"
import "core:sort.odin"
import "core:strings.odin"
import "core:types.odin"
import "core:utf16.odin"
import "core:utf8.odin"
when ODIN_OS == "windows" {
import "core:atomics.odin"
import "core:opengl.odin"
import "core:thread.odin"
import win32 "core:sys/windows.odin"
}
general_stuff :: proc() {
{ // `do` for inline statmes rather than block
foo :: proc() do fmt.println("Foo!");
if false do foo();
for false do foo();
when false do foo();
if false do foo();
else do foo();
}
{ // Removal of `++` and `--` (again)
x: int;
x += 1;
x -= 1;
}
{ // Casting syntaxes
i := i32(137);
ptr := &i;
fp1 := (^f32)(ptr);
// ^f32(ptr) == ^(f32(ptr))
fp2 := cast(^f32)ptr;
f1 := (^f32)(ptr)^;
f2 := (cast(^f32)ptr)^;
// Questions: Should there be two ways to do it?
}
/*
* Remove *_val_of built-in procedures
* size_of, align_of, offset_of
* type_of, type_info_of
*/
{ // `expand_to_tuple` built-in procedure
Foo :: struct {
x: int,
b: bool,
}
f := Foo{137, true};
x, b := expand_to_tuple(f);
fmt.println(f);
fmt.println(x, b);
fmt.println(expand_to_tuple(f));
}
{
// .. half-closed range
// ... open range
for in 0..2 {} // 0, 1
for in 0...2 {} // 0, 1, 2
}
}
default_struct_values :: proc() {
{
Vector3 :: struct {
x: f32,
y: f32,
z: f32,
}
v: Vector3;
fmt.println(v);
}
{
// Default values must be constants
Vector3 :: struct {
x: f32 = 1,
y: f32 = 4,
z: f32 = 9,
}
v: Vector3;
fmt.println(v);
v = Vector3{};
fmt.println(v);
// Uses the same semantics as a default values in a procedure
v = Vector3{137};
fmt.println(v);
v = Vector3{z = 137};
fmt.println(v);
}
{
Vector3 :: struct {
x := 1.0,
y := 4.0,
z := 9.0,
}
stack_default: Vector3;
stack_literal := Vector3{};
heap_one := new(Vector3); defer free(heap_one);
heap_two := new_clone(Vector3{}); defer free(heap_two);
fmt.println("stack_default - ", stack_default);
fmt.println("stack_literal - ", stack_literal);
fmt.println("heap_one - ", heap_one^);
fmt.println("heap_two - ", heap_two^);
N :: 4;
stack_array: [N]Vector3;
heap_array := new([N]Vector3); defer free(heap_array);
heap_slice := make([]Vector3, N); defer free(heap_slice);
fmt.println("stack_array[1] - ", stack_array[1]);
fmt.println("heap_array[1] - ", heap_array[1]);
fmt.println("heap_slice[1] - ", heap_slice[1]);
}
}
union_type :: proc() {
{
val: union{int, bool};
val = 137;
if i, ok := val.(int); ok {
fmt.println(i);
}
val = true;
fmt.println(val);
val = nil;
switch v in val {
case int: fmt.println("int", v);
case bool: fmt.println("bool", v);
case: fmt.println("nil");
}
}
{
// There is a duality between `any` and `union`
// An `any` has a pointer to the data and allows for any type (open)
// A `union` has as binary blob to store the data and allows only certain types (closed)
// The following code is with `any` but has the same syntax
val: any;
val = 137;
if i, ok := val.(int); ok {
fmt.println(i);
}
val = true;
fmt.println(val);
val = nil;
switch v in val {
case int: fmt.println("int", v);
case bool: fmt.println("bool", v);
case: fmt.println("nil");
}
}
Vector3 :: struct {x, y, z: f32};
Quaternion :: struct {x, y, z: f32, w: f32 = 1};
// More realistic examples
{
// NOTE(bill): For the above basic examples, you may not have any
// particular use for it. However, my main use for them is not for these
// simple cases. My main use is for hierarchical types. Many prefer
// subtyping, embedding the base data into the derived types. Below is
// an example of this for a basic game Entity.
Entity :: struct {
id: u64,
name: string,
position: Vector3,
orientation: Quaternion,
derived: any,
}
Frog :: struct {
using entity: Entity,
jump_height: f32,
}
Monster :: struct {
using entity: Entity,
is_robot: bool,
is_zombie: bool,
}
// See `parametric_polymorphism` procedure for details
new_entity :: proc(T: type) -> ^Entity {
t := new(T);
t.derived = t^;
return t;
}
entity := new_entity(Monster);
switch e in entity.derived {
case Frog:
fmt.println("Ribbit");
case Monster:
if e.is_robot do fmt.println("Robotic");
if e.is_zombie do fmt.println("Grrrr!");
}
}
{
// NOTE(bill): A union can be used to achieve something similar. Instead
// of embedding the base data into the derived types, the derived data
// in embedded into the base type. Below is the same example of the
// basic game Entity but using an union.
Entity :: struct {
id: u64,
name: string,
position: Vector3,
orientation: Quaternion,
derived: union {Frog, Monster},
}
Frog :: struct {
using entity: ^Entity,
jump_height: f32,
}
Monster :: struct {
using entity: ^Entity,
is_robot: bool,
is_zombie: bool,
}
// See `parametric_polymorphism` procedure for details
new_entity :: proc(T: type) -> ^Entity {
t := new(Entity);
t.derived = T{entity = t};
return t;
}
entity := new_entity(Monster);
switch e in entity.derived {
case Frog:
fmt.println("Ribbit");
case Monster:
if e.is_robot do fmt.println("Robotic");
if e.is_zombie do fmt.println("Grrrr!");
}
// NOTE(bill): As you can see, the usage code has not changed, only its
// memory layout. Both approaches have their own advantages but they can
// be used together to achieve different results. The subtyping approach
// can allow for a greater control of the memory layout and memory
// allocation, e.g. storing the derivatives together. However, this is
// also its disadvantage. You must either preallocate arrays for each
// derivative separation (which can be easily missed) or preallocate a
// bunch of "raw" memory; determining the maximum size of the derived
// types would require the aid of metaprogramming. Unions solve this
// particular problem as the data is stored with the base data.
// Therefore, it is possible to preallocate, e.g. [100]Entity.
// It should be noted that the union approach can have the same memory
// layout as the any and with the same type restrictions by using a
// pointer type for the derivatives.
/*
Entity :: struct {
...
derived: union{^Frog, ^Monster};
}
Frog :: struct {
using entity: Entity;
...
}
Monster :: struct {
using entity: Entity;
...
}
new_entity :: proc(T: type) -> ^Entity {
t := new(T);
t.derived = t;
return t;
}
*/
}
}
parametric_polymorphism :: proc() {
print_value :: proc(value: $T) {
fmt.printf("print_value: %T %v\n", value, value);
}
v1: int = 1;
v2: f32 = 2.1;
v3: f64 = 3.14;
v4: string = "message";
print_value(v1);
print_value(v2);
print_value(v3);
print_value(v4);
fmt.println();
add :: proc(p, q: $T) -> T {
x: T = p + q;
return x;
}
a := add(3, 4);
fmt.printf("a: %T = %v\n", a, a);
b := add(3.2, 4.3);
fmt.printf("b: %T = %v\n", b, b);
// This is how `new` is implemented
alloc_type :: proc(T: type) -> ^T {
t := cast(^T)alloc(size_of(T), align_of(T));
t^ = T{}; // Use default initialization value
return t;
}
copy_slice :: proc(dst, src: []$T) -> int {
n := min(len(dst), len(src));
if n > 0 {
mem.copy(&dst[0], &src[0], n*size_of(T));
}
return n;
}
double_params :: proc(a: $A, b: $B) -> A {
return a + A(b);
}
fmt.println(double_params(12, 1.345));
{ // Polymorphic Types and Type Specialization
Table_Slot :: struct(Key, Value: type) {
occupied: bool,
hash: u32,
key: Key,
value: Value,
}
TABLE_SIZE_MIN :: 32;
Table :: struct(Key, Value: type) {
count: int,
allocator: Allocator,
slots: []Table_Slot(Key, Value),
}
// Only allow types that are specializations of a (polymorphic) slice
make_slice :: proc(T: type/[]$E, len: int) -> T {
return make(T, len);
}
// Only allow types that are specializations of `Table`
allocate :: proc(table: ^$T/Table, capacity: int) {
c := context;
if table.allocator.procedure != nil do c.allocator = table.allocator;
context <- c {
table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN));
}
}
expand :: proc(table: ^$T/Table) {
c := context;
if table.allocator.procedure != nil do c.allocator = table.allocator;
context <- c {
old_slots := table.slots;
cap := max(2*cap(table.slots), TABLE_SIZE_MIN);
allocate(table, cap);
for s in old_slots do if s.occupied {
put(table, s.key, s.value);
}
free(old_slots);
}
}
// Polymorphic determination of a polymorphic struct
// put :: proc(table: ^$T/Table, key: T.Key, value: T.Value) {
put :: proc(table: ^Table($Key, $Value), key: Key, value: Value) {
hash := get_hash(key); // Ad-hoc method which would fail in a different scope
index := find_index(table, key, hash);
if index < 0 {
if f64(table.count) >= 0.75*f64(cap(table.slots)) {
expand(table);
}
assert(table.count <= cap(table.slots));
hash := get_hash(key);
index = int(hash % u32(cap(table.slots)));
for table.slots[index].occupied {
if index += 1; index >= cap(table.slots) {
index = 0;
}
}
table.count += 1;
}
slot := &table.slots[index];
slot.occupied = true;
slot.hash = hash;
slot.key = key;
slot.value = value;
}
// find :: proc(table: ^$T/Table, key: T.Key) -> (T.Value, bool) {
find :: proc(table: ^Table($Key, $Value), key: Key) -> (Value, bool) {
hash := get_hash(key);
index := find_index(table, key, hash);
if index < 0 {
return Value{}, false;
}
return table.slots[index].value, true;
}
find_index :: proc(table: ^Table($Key, $Value), key: Key, hash: u32) -> int {
if cap(table.slots) <= 0 do return -1;
index := int(hash % u32(cap(table.slots)));
for table.slots[index].occupied {
if table.slots[index].hash == hash {
if table.slots[index].key == key {
return index;
}
}
if index += 1; index >= cap(table.slots) {
index = 0;
}
}
return -1;
}
get_hash :: proc(s: string) -> u32 { // fnv32a
h: u32 = 0x811c9dc5;
for i in 0..len(s) {
h = (h ~ u32(s[i])) * 0x01000193;
}
return h;
}
table: Table(string, int);
for i in 0..36 do put(&table, "Hellope", i);
for i in 0..42 do put(&table, "World!", i);
found, _ := find(&table, "Hellope");
fmt.printf("`found` is %v\n", found);
found, _ = find(&table, "World!");
fmt.printf("`found` is %v\n", found);
// I would not personally design a hash table like this in production
// but this is a nice basic example
// A better approach would either use a `u64` or equivalent for the key
// and let the user specify the hashing function or make the user store
// the hashing procedure with the table
}
}
prefix_table := [...]string{
"White",
"Red",
"Green",
"Blue",
"Octarine",
"Black",
};
threading_example :: proc() {
when ODIN_OS == "windows" {
unordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) {
__bounds_check_error_loc(loc, index, len(array));
array[index] = array[len(array)-1];
pop(array);
}
ordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) {
__bounds_check_error_loc(loc, index, len(array));
copy(array[index..], array[index+1..]);
pop(array);
}
worker_proc :: proc(t: ^thread.Thread) -> int {
for iteration in 1...5 {
fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration);
fmt.printf("`%s`: iteration %d\n", prefix_table[t.user_index], iteration);
// win32.sleep(1);
}
return 0;
}
threads := make([]^thread.Thread, 0, len(prefix_table));
defer free(threads);
for i in 0..len(prefix_table) {
if t := thread.create(worker_proc); t != nil {
t.init_context = context;
t.use_init_context = true;
t.user_index = len(threads);
append(&threads, t);
thread.start(t);
}
}
for len(threads) > 0 {
for i := 0; i < len(threads); /**/ {
if t := threads[i]; thread.is_done(t) {
fmt.printf("Thread %d is done\n", t.user_index);
thread.destroy(t);
ordered_remove(&threads, i);
} else {
i += 1;
}
}
}
}
}
main :: proc() {
when false {
fmt.println("\n# general_stuff"); general_stuff();
fmt.println("\n# default_struct_values"); default_struct_values();
fmt.println("\n# union_type"); union_type();
fmt.println("\n# parametric_polymorphism"); parametric_polymorphism();
fmt.println("\n# threading_example"); threading_example();
}
}
+20
View File
@@ -0,0 +1,20 @@
import "core:fmt.odin";
main :: proc() {
recursive_factorial :: proc(i: u64) -> u64 {
if i < 2 do return 1;
return i * recursive_factorial(i-1);
}
loop_factorial :: proc(i: u64) -> u64 {
result: u64 = 1;
for n in 2..i {
result *= n;
}
return result;
}
fmt.println(recursive_factorial(12));
fmt.println(loop_factorial(12));
}
+52 -53
View File
@@ -1,63 +1,63 @@
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";
import win32 "core:sys/windows.odin" when ODIN_OS == "windows";
import wgl "core:sys/wgl.odin" when ODIN_OS == "windows";
import "core:fmt.odin";
import "core:math.odin";
import "core:os.odin";
import gl "core:opengl.odin";
const TWO_HEARTS = '💕';
TWO_HEARTS :: '💕';
var win32_perf_count_freq = win32.get_query_performance_frequency();
proc time_now() -> f64 {
win32_perf_count_freq := win32.get_query_performance_frequency();
time_now :: proc() -> f64 {
assert(win32_perf_count_freq != 0);
var counter: i64;
counter: i64;
win32.query_performance_counter(&counter);
return f64(counter) / f64(win32_perf_count_freq);
}
proc win32_print_last_error() {
var err_code = win32.get_last_error();
win32_print_last_error :: proc() {
err_code := win32.get_last_error();
if err_code != 0 {
fmt.println("get_last_error: ", err_code);
}
}
// Yuk!
proc to_c_string(s: string) -> []u8 {
var c_str = make([]u8, len(s)+1);
copy(c_str, []u8(s));
to_c_string :: proc(s: string) -> []u8 {
c_str := make([]u8, len(s)+1);
copy(c_str, cast([]u8)s);
c_str[len(s)] = 0;
return c_str;
}
type Window struct {
Window :: struct {
width, height: int,
wc: win32.WndClassExA,
wc: win32.Wnd_Class_Ex_A,
dc: win32.Hdc,
hwnd: win32.Hwnd,
opengl_context, rc: wgl.Hglrc,
c_title: []u8,
}
proc make_window(title: string, msg, height: int, window_proc: win32.WndProc) -> (Window, bool) {
make_window :: proc(title: string, msg, height: int, window_proc: win32.Wnd_Proc) -> (Window, bool) {
using win32;
var w: Window;
w: Window;
w.width, w.height = msg, height;
var class_name = "Win32-Odin-Window\x00";
var c_class_name = &class_name[0];
class_name := "Win32-Odin-Window\x00";
c_class_name := &class_name[0];
if title[len(title)-1] != 0 {
w.c_title = to_c_string(title);
} else {
w.c_title = []u8(title);
w.c_title = cast([]u8)title;
}
var instance = get_module_handle_a(nil);
instance := get_module_handle_a(nil);
w.wc = WndClassExA{
size = size_of(WndClassExA),
w.wc = Wnd_Class_Ex_A{
size = size_of(Wnd_Class_Ex_A),
style = CS_VREDRAW | CS_HREDRAW,
instance = Hinstance(instance),
class_name = c_class_name,
@@ -84,8 +84,8 @@ proc make_window(title: string, msg, height: int, window_proc: win32.WndProc) ->
w.dc = get_dc(w.hwnd);
{
var pfd = PixelFormatDescriptor{
size = size_of(PixelFormatDescriptor),
pfd := Pixel_Format_Descriptor{
size = size_of(Pixel_Format_Descriptor),
version = 1,
flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
pixel_type = PFD_TYPE_RGBA,
@@ -100,15 +100,15 @@ proc make_window(title: string, msg, height: int, window_proc: win32.WndProc) ->
w.opengl_context = wgl.create_context(w.dc);
wgl.make_current(w.dc, w.opengl_context);
var attribs = [8]i32{
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
0, // NOTE(bill): tells the that :: proc this is the end of attribs
};
var wgl_str = "wglCreateContextAttribsARB\x00";
var wglCreateContextAttribsARB = wgl.CreateContextAttribsARBType(wgl.get_proc_address(&wgl_str[0]));
wgl_str := "wglCreateContextAttribsARB\x00";
wglCreateContextAttribsARB := cast(wgl.Create_Context_Attribs_ARB_Type)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);
@@ -117,19 +117,19 @@ proc make_window(title: string, msg, height: int, window_proc: win32.WndProc) ->
return w, true;
}
proc destroy_window(w: ^Window) {
destroy_window :: proc(w: ^Window) {
free(w.c_title);
}
proc display_window(w: ^Window) {
display_window :: proc(w: ^Window) {
win32.swap_buffers(w.dc);
}
proc run() {
run :: proc() {
using math;
proc win32_proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline {
win32_proc :: 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);
@@ -138,7 +138,7 @@ proc run() {
return def_window_proc_a(hwnd, msg, wparam, lparam);
}
var window, window_success = make_window("Odin Language Demo", 854, 480, win32.WndProc(win32_proc));
window, window_success := make_window("Odin Language Demo", 854, 480, cast(win32.Wnd_Proc)win32_proc);
if !window_success {
return;
}
@@ -148,17 +148,17 @@ proc run() {
using win32;
var prev_time = time_now();
var running = true;
prev_time := time_now();
running := true;
var pos = Vec2{100, 100};
pos := Vec2{100, 100};
for running {
var curr_time = time_now();
var dt = f32(curr_time - prev_time);
curr_time := time_now();
dt := f32(curr_time - prev_time);
prev_time = curr_time;
var msg: Msg;
msg: Msg;
for peek_message_a(&msg, nil, 0, 0, PM_REMOVE) > 0 {
if msg.message == WM_QUIT {
running = false;
@@ -167,18 +167,18 @@ proc run() {
dispatch_message_a(&msg);
}
if is_key_down(KeyCode.Escape) {
if is_key_down(Key_Code.Escape) {
running = false;
}
{
const SPEED = 500;
var v: Vec2;
SPEED :: 500;
v: Vec2;
if is_key_down(KeyCode.Right) { v[0] += 1; }
if is_key_down(KeyCode.Left) { v[0] -= 1; }
if is_key_down(KeyCode.Up) { v[1] += 1; }
if is_key_down(KeyCode.Down) { v[1] -= 1; }
if is_key_down(Key_Code.Right) do v[0] += 1;
if is_key_down(Key_Code.Left) do v[0] -= 1;
if is_key_down(Key_Code.Up) do v[1] += 1;
if is_key_down(Key_Code.Down) do v[1] -= 1;
v = norm(v);
@@ -193,7 +193,7 @@ proc run() {
gl.Ortho(0, f64(window.width),
0, f64(window.height), 0, 1);
proc draw_rect(x, y, w, h: f32) {
draw_rect :: proc(x, y, w, h: f32) {
gl.Begin(gl.TRIANGLES);
defer gl.End();
@@ -209,14 +209,13 @@ proc run() {
draw_rect(pos.x, pos.y, 50, 50);
display_window(&window);
var ms_to_sleep = i32(16 - 1000*dt);
if ms_to_sleep > 0 {
if ms_to_sleep := i32(16 - 1000*dt); ms_to_sleep > 0 {
win32.sleep(ms_to_sleep);
}
}
}
proc main() {
main :: proc() {
run();
}
+5
View File
@@ -0,0 +1,5 @@
import "core:fmt.odin";
main :: proc() {
fmt.println("Hellope, world!");
}
@@ -1,9 +1,9 @@
#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 "core:fmt.odin";
import "core:os.odin";
import "core:mem.odin";
// import "http_test.odin" as ht;
// import "game.odin" as game;
// import "punity.odin" as pn;
main :: proc() {
struct_padding();
@@ -160,21 +160,21 @@ type_introspection :: proc() {
info: ^Type_Info;
x: int;
info = type_info(int); // by type
info = type_info_of_val(x); // by value
info = type_info_of(int); // by type
info = type_info_of(x); // by value
// See: runtime.odin
match i in info {
case Type_Info.Integer:
match i in info.variant {
case Type_Info_Integer:
fmt.println("integer!");
case Type_Info.Float:
case Type_Info_Float:
fmt.println("float!");
default:
case:
fmt.println("potato!");
}
// Unsafe cast
integer_info := cast(^Type_Info.Integer)cast(rawptr)info;
integer_info := cast(^Type_Info_Integer)cast(rawptr)info;
}
{
@@ -185,9 +185,9 @@ type_introspection :: proc() {
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(v1);
t2 := type_info_of(v2);
t3 := type_info_of(v3);
fmt.println();
fmt.print("Type of v1 is:\n\t", t1);
@@ -262,12 +262,12 @@ crazy_introspection :: proc() {
TOMATO,
}
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
fruit_ti := type_info_of(Fruit);
name := fruit_ti.variant.(Type_Info_Named).name;
info, _ := type_info_base(fruit_ti).variant.(Type_Info_Enum);
fmt.printf("%s :: enum %T {\n", name, info.base);
for i := 0; i < len(info.values); i++ {
for _, i in info.values {
fmt.printf("\t%s\t= %v,\n", info.names[i], info.values[i]);
}
fmt.printf("}\n");
@@ -1,7 +1,8 @@
// Demo 002
#load "fmt.odin";
#load "math.odin";
// #load "game.odin"
export "core:fmt.odin";
export "core:math.odin";
export "core:mem.odin";
// export "game.odin"
#thread_local tls_int: int;
@@ -94,11 +95,9 @@ enumerations :: proc() {
}
variadic_procedures :: proc() {
print_ints :: proc(args: ..int) {
print_ints :: proc(args: ...int) {
for arg, i in args {
if i > 0 {
print(", ");
}
if i > 0 do print(", ");
print(arg);
}
}
@@ -107,13 +106,11 @@ variadic_procedures :: proc() {
print_ints(1); nl();
print_ints(1, 2, 3); nl();
print_prefix_f32s :: proc(prefix: string, args: ..f32) {
print_prefix_f32s :: proc(prefix: string, args: ...f32) {
print(prefix);
print(": ");
for arg, i in args {
if i > 0 {
print(", ");
}
if i > 0 do print(", ");
print(arg);
}
}
@@ -147,13 +144,7 @@ new_builtins :: proc() {
// Q: Should this be `free` rather than `free` and should I overload it for slices too?
{
prev_context := context;
defer __context = prev_context;
// Q: Should I add a `push_context` feature to the language?
__context.allocator = default_allocator();
push_allocator default_allocator() {
a := new(int);
defer free(a);
@@ -164,7 +155,7 @@ new_builtins :: proc() {
{
a: int = 123;
b: type_of_val(a) = 321;
b: type_of(a) = 321;
// NOTE(bill): This matches the current naming scheme
// size_of
@@ -205,7 +196,7 @@ new_builtins :: proc() {
a: [16]int;
a[1] = 1;
b := ^a;
b := &a;
// Auto pointer deref
// consistent with record members
assert(b[1] == 1);
@@ -255,7 +246,7 @@ match_statement :: proc() {
print("5!\n");
fallthrough; // explicit fallthrough
default:
case:
print("default!\n");
}
@@ -267,7 +258,7 @@ match_statement :: proc() {
// break by default
case TAU:
print("τ!\n");
default:
case:
print("default!\n");
}
@@ -279,7 +270,7 @@ match_statement :: proc() {
// break by default
case "Goodbye":
print("farewell\n");
default:
case:
print("???\n");
}
@@ -302,7 +293,7 @@ match_statement :: proc() {
print("dozens\n");
case a >= 100 && a < 1000:
print("hundreds\n");
default:
case:
print("a fuck ton\n");
}
@@ -332,11 +323,9 @@ match_statement :: proc() {
Vector3 :: struct {x, y, z: f32}
print_floats :: proc(args: ..f32) {
print_floats :: proc(args: ...f32) {
for arg, i in args {
if i > 0 {
print(", ");
}
if i > 0 do print(", ");
print(arg);
}
println();
@@ -355,7 +344,7 @@ namespacing :: proc() {
Thing :: #type struct {
y: int,
test: bool,
}
};
b: Thing; // Uses this scope's Thing
b.test = true;
@@ -473,10 +462,10 @@ namespacing :: proc() {
}
e := Entity{position = Vector3{1, 2, 3}};
print_pos_1(^e);
print_pos_2(^e);
print_pos_3(^e);
print_pos_4(^e);
print_pos_1(&e);
print_pos_2(&e);
print_pos_3(&e);
print_pos_4(&e);
// This is similar to C++'s `this` pointer that is implicit and only available in methods
}
@@ -574,20 +563,20 @@ subtyping :: proc() {
entity_count := 0;
next_entity :: proc(entities: []Entity, entity_count: ^int) -> ^Entity {
e := ^entities[entity_count^];
entity_count^++;
e := &entities[entity_count^];
entity_count^ += 1;
return e;
}
f: Frog;
f.entity = next_entity(entities[..], ^entity_count);
f.entity = next_entity(entities[..], &entity_count);
f.position = Vector3{3, 4, 6};
using f.position;
print_floats(x, y, z);
}
{
/*{
// Down casting
Entity :: struct {
@@ -609,7 +598,7 @@ subtyping :: proc() {
// NOTE(bill): `down_cast` is unsafe and there are not check are compile time or run time
// Q: Should I completely remove `down_cast` as I added it in about 30 minutes
}
}*/
{
// Multiple "inheritance"/subclassing
@@ -630,7 +619,7 @@ subtyping :: proc() {
tagged_unions :: proc() {
{
EntityKind :: enum {
Entity_Kind :: enum {
INVALID,
FROG,
GIRAFFE,
@@ -638,8 +627,8 @@ tagged_unions :: proc() {
}
Entity :: struct {
kind: EntityKind
using data: raw_union {
kind: Entity_Kind
using data: struct #raw_union {
frog: struct {
jump_height: f32,
colour: u32,
@@ -657,33 +646,31 @@ tagged_unions :: proc() {
}
e: Entity;
e.kind = EntityKind.FROG;
e.kind = Entity_Kind.FROG;
e.frog.jump_height = 12;
f: type_of_val(e.frog);
f: type_of(e.frog);
// But this is very unsafe and extremely cumbersome to write
// In C++, I use macros to alleviate this but it's not a solution
}
{
Entity :: union {
Frog{
jump_height: f32,
colour: u32,
},
Giraffe{
neck_length: f32,
spot_count: int,
},
Helicopter{
blade_count: int,
weight: f32,
pilot_name: string,
},
Frog :: struct {
jump_height: f32,
colour: u32,
}
Giraffe :: struct {
neck_length: f32,
spot_count: int,
}
Helicopter :: struct {
blade_count: int,
weight: f32,
pilot_name: string,
}
Entity :: union {Frog, Giraffe, Helicopter};
using Entity;
f1: Frog = Frog{12, 0xff9900};
f2: Entity = Frog{12, 0xff9900}; // Implicit cast
f3 := cast(Entity)Frog{12, 0xff9900}; // Explicit cast
@@ -703,7 +690,7 @@ tagged_unions :: proc() {
// Requires a pointer to the union
// `x` will be a pointer to type of the case
match x in ^f {
match x in &f {
case Frog:
print("Frog!\n");
print(x.jump_height); nl();
@@ -713,7 +700,7 @@ tagged_unions :: proc() {
print("Giraffe!\n");
case Helicopter:
print("ROFLCOPTER!\n");
default:
case:
print("invalid entity\n");
}
@@ -755,11 +742,11 @@ tagged_unions :: proc() {
AstNode :: struct {};
ExactValue :: struct {};
EntityKind :: enum {
Entity_Kind :: enum {
Invalid,
Constant,
Variable,
UsingVariable,
Using_Variable,
TypeName,
Procedure,
Builtin,
@@ -769,14 +756,14 @@ tagged_unions :: proc() {
Guid :: i64;
Entity :: struct {
kind: EntityKind,
kind: Entity_Kind,
guid: Guid,
scope: ^Scope,
token: Token,
type_: ^Type,
using data: raw_union {
using data: struct #raw_union {
Constant: struct {
value: ExactValue,
},
@@ -786,7 +773,7 @@ tagged_unions :: proc() {
is_field: bool, // Is struct field
anonymous: bool, // Variable is an anonymous
},
UsingVariable: struct {
Using_Variable: struct {
},
TypeName: struct {
},
@@ -813,44 +800,44 @@ tagged_unions :: proc() {
Guid :: i64;
Entity_Base :: struct {
}
Entity :: union {
Constant :: struct {
value: ExactValue,
}
Variable :: struct {
visited: bool, // Cycle detection
used: bool, // Variable is used
is_field: bool, // Is struct field
anonymous: bool, // Variable is an anonymous
}
Using_Variable :: struct {
}
TypeName :: struct {
}
Procedure :: struct {
used: bool,
}
Builtin :: struct {
id: int,
}
Entity :: struct {
guid: Guid,
scope: ^Scope,
token: Token,
type_: ^Type,
Constant{
value: ExactValue,
},
Variable{
visited: bool, // Cycle detection
used: bool, // Variable is used
is_field: bool, // Is struct field
anonymous: bool, // Variable is an anonymous
},
UsingVariable{
},
TypeName{
},
Procedure{
used: bool,
},
Builtin{
id: int,
},
variant: union {Constant, Variable, Using_Variable, TypeName, Procedure, Builtin},
}
using Entity;
e: Entity;
e = Variable{
used = true,
anonymous = false,
e := Entity{
variant = Variable{
used = true,
anonymous = false,
},
};
@@ -863,13 +850,13 @@ tagged_unions :: proc() {
{
// `Raw` unions still have uses, especially for mathematic types
Vector2 :: raw_union {
Vector2 :: struct #raw_union {
using xy_: struct { x, y: f32 },
e: [2]f32,
v: [vector 2]f32,
}
Vector3 :: raw_union {
Vector3 :: struct #raw_union {
using xyz_: struct { x, y, z: f32 },
xy: Vector2,
e: [3]f32,
@@ -1,14 +1,14 @@
#import "fmt.odin";
#import "utf8.odin";
#import "hash.odin";
#import "mem.odin";
import "core:fmt.odin";
import "core:utf8.odin";
import "core:hash.odin";
import "core:mem.odin";
main :: proc() {
{ // New Standard Library stuff
s := "Hello";
fmt.println(s,
utf8.valid_string(s),
hash.murmur64(cast([]byte)s));
hash.murmur64(cast([]u8)s));
// utf8.odin
// hash.odin
@@ -20,10 +20,10 @@ main :: proc() {
{
arena: mem.Arena;
mem.init_arena_from_context(^arena, mem.megabytes(16)); // Uses default allocator
defer mem.free_arena(^arena);
mem.init_arena_from_context(&arena, mem.megabytes(16)); // Uses default allocator
defer mem.destroy_arena(&arena);
push_allocator mem.arena_allocator(^arena) {
push_allocator mem.arena_allocator(&arena) {
x := new(int);
x^ = 1337;
@@ -49,7 +49,7 @@ main :: proc() {
// You can also "push" a context
c := context; // Create copy of the allocator
c.allocator = mem.arena_allocator(^arena);
c.allocator = mem.arena_allocator(&arena);
push_context c {
x := new(int);
@@ -1,13 +1,13 @@
#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";
import "core:fmt.odin";
import "core:utf8.odin";
// import "core:atomic.odin";
// import "core:hash.odin";
// import "core:math.odin";
// import "core:mem.odin";
// import "core:opengl.odin";
// import "core:os.odin";
// import "core:sync.odin";
// import win32 "core:sys/windows.odin";
main :: proc() {
// syntax();
@@ -43,7 +43,7 @@ syntax :: proc() {
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));
slice: []int; compile_assert(size_of(slice) == 3*size_of(int));
// Helper type - Help the reader understand what it is quicker
My_Int :: #type int;
@@ -90,22 +90,17 @@ Prefix_Type :: struct {x: int, y: f32, z: rawptr};
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
foo :: proc(using pt: Prefix_Type) {
}
// Same as C99's `restrict`
bar :: proc(no_alias a, b: ^int) {
bar :: proc(#no_alias a, b: ^int) {
// Assumes a never equals b so it can perform optimizations with that fact
}
@@ -138,14 +133,18 @@ when_statements :: proc() {
foreign_procedures();
}
#foreign_system_library win32_user "user32.lib" when ODIN_OS == "windows";
when ODIN_OS == "windows" {
foreign_system_library win32_user "user32.lib";
}
// 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";
foreign win32_user {
ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 ---;
show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #link_name "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
@@ -203,14 +202,14 @@ loops :: proc() {
fmt.println(val, idx);
}
primes := [..]int{2, 3, 5, 7, 11, 13, 17, 19};
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 {
for _ in &primes {
// ignore the value and just iterate across it
}
@@ -219,7 +218,7 @@ loops :: proc() {
name := "你好,世界";
fmt.println(name);
for r in name {
compile_assert(type_of_val(r) == rune);
compile_assert(type_of(r) == rune);
fmt.printf("%r\n", r);
}
@@ -270,8 +269,8 @@ procedure_overloading :: proc() {
a: i32 = 123;
b: f32;
c: rawptr;
fmt.println(foo(^a));
foo(^b);
fmt.println(foo(&a));
foo(&b);
foo(c);
// foo(nil); // nil could go to numerous types thus the ambiguity
+310
View File
@@ -0,0 +1,310 @@
// import "core:atomic.odin";
import "core:hash.odin";
import "core:mem.odin";
import "core:opengl.odin";
import "core:strconv.odin";
import "core:sync.odin";
import win32 "core:sys/windows.odin";
import "core:fmt.odin";
import "core:os.odin";
import "core:math.odin";
main :: proc() {
when true {
/*
Added:
* Unexported entities and fields using an underscore prefix
- See `sync.odin` and explain
Removed:
* Maybe/option types
* Remove `type` keyword and other "reserved" keywords
* ..< and ... removed and replace with .. (half-closed range)
Changed:
* `compile_assert` and `assert` return the value of the condition for semantic reasons
* 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
* Core library additions to Windows specific stuff
*/
{
Fruit :: enum {
APPLE,
BANANA,
COCONUT,
}
fmt.println(Fruit.names);
}
{
A :: struct {x, y: f32};
B :: struct #align 16 {x, y: f32};
fmt.println("align_of(A) =", align_of(A));
fmt.println("align_of(B) =", align_of(B));
}
{
// Removal of ..< and ...
for i in 0..16 {
}
// Is similar to
for i := 0; i < 16; i += 1 {
}
}
{
thing: for i in 0..10 {
for j in i+1..10 {
if j == 2 {
fmt.println(i, j);
continue thing;
}
if j == 3 {
break thing;
}
}
}
// Works with, `for`, `for in`, `match`, `match in`
// NOTE(bill): This solves most of the problems I need `goto` for
}
{
t := type_info_of(int);
match i in t.variant {
case Type_Info_Integer, Type_Info_Float:
fmt.println("It's a number");
}
x: any = 123;
foo: match i in x {
case int, f32:
fmt.println("It's an int or f32");
break foo;
}
}
{
cond := true;
x: int;
if cond {
x = 3;
} else {
x = 4;
}
// Ternary operator
y := cond ? 3 : 4;
FOO :: true ? 123 : 432; // Constant ternary expression
fmt.println("Ternary values:", y, FOO);
}
{
// Slices now store a capacity
buf: [256]u8;
s: []u8;
s = buf[..0]; // == buf[0..0];
fmt.println("count =", len(s));
fmt.println("capacity =", cap(s));
append(&s, 1, 2, 3);
fmt.println(s);
s = buf[1..2..3];
fmt.println("count =", len(s));
fmt.println("capacity =", cap(s));
fmt.println(s);
clear(&s); // Sets count to zero
}
{
Foo :: struct {
x, y, z: f32,
ok: bool,
flags: u32,
}
foo_array: [256]Foo;
foo_as_bytes: []u8 = mem.slice_to_bytes(foo_array[..]);
// Useful for things like
// os.write(handle, foo_as_bytes);
foo_slice := mem.slice_ptr(cast(^Foo)&foo_as_bytes[0], len(foo_as_bytes)/size_of(Foo), cap(foo_as_bytes)/size_of(Foo));
// Question: Should there be a bytes_to_slice procedure or is it clearer to do this even if it is error prone?
// And if so what would the syntax be?
// slice_transmute([]Foo, foo_as_bytes);
}
{
Vec3 :: [vector 3]f32;
x := Vec3{1, 2, 3};
y := Vec3{4, 5, 6};
fmt.println(x < y);
fmt.println(x + y);
fmt.println(x - y);
fmt.println(x * y);
fmt.println(x / y);
for i in x {
fmt.println(i);
}
compile_assert(size_of([vector 7]bool) >= size_of([7]bool));
compile_assert(size_of([vector 7]i32) >= size_of([7]i32));
// align_of([vector 7]i32) != align_of([7]i32) // this may be the case
}
{
// fmt.* changes
// bprint* returns `string`
data: [256]u8;
str := fmt.bprintf(data[..], "Hellope %d %s %c", 123, "others", '!');
fmt.println(str);
}
{
x: [dynamic]f64;
reserve(&x, 16);
defer free(x); // `free` is overloaded for numerous types
// Number literals can have underscores in them for readability
append(&x, 2_000_000.500_000, 123, 5, 7); // variadic append
for p, i in x {
if i > 0 { fmt.print(", "); }
fmt.print(p);
}
fmt.println();
}
{
// Dynamic array "literals"
x := [dynamic]f64{2_000_000.500_000, 3, 5, 7};
defer free(x);
fmt.println(x); // fmt.print* supports printing of dynamic types
clear(&x);
fmt.println(x);
}
{
m: map[f32]int;
reserve(&m, 16);
defer free(m);
m[1.0] = 1278;
m[2.0] = 7643;
m[3.0] = 564;
_, ok := m[3.0];
c := m[3.0];
assert(ok && c == 564);
fmt.print("map[");
i := 0;
for val, key in m {
if i > 0 {
fmt.print(", ");
}
fmt.printf("%v=%v", key, val);
i += 1;
}
fmt.println("]");
}
{
m := map[string]u32{
"a" = 56,
"b" = 13453,
"c" = 7654,
};
defer free(m);
c := m["c"];
_, ok := m["c"];
assert(ok && c == 7654);
fmt.println(m);
delete(&m, "c"); // deletes entry with key "c"
_, found := m["c"];
assert(!found);
fmt.println(m);
clear(&m);
fmt.println(m);
// NOTE: Fixed size maps are planned but we have not yet implemented
// them as we have had no need for them as of yet
}
{
Vector3 :: struct{x, y, z: f32};
Quaternion :: struct{x, y, z, w: f32};
// Variants
Frog :: struct {
ribbit_volume: f32,
jump_height: f32,
}
Door :: struct {
openness: f32,
}
Map :: struct {
width, height: f32,
place_positions: []Vector3,
place_names: []string,
}
Entity :: struct {
// Common Fields
id: u64,
name: string,
using position: Vector3,
orientation: Quaternion,
flags: u32,
variant: union { Frog, Door, Map },
}
entity: Entity;
entity.id = 1337;
// implicit conversion from variant to base type
entity.variant = Frog{
ribbit_volume = 0.5,
jump_height = 2.1,
/*other data */
};
entity.name = "Frank";
entity.position = Vector3{1, 4, 9};
match e in entity.variant {
case Frog:
fmt.println("Ribbit");
case Door:
fmt.println("Creak");
case Map:
fmt.println("Rustle");
case:
fmt.println("Just a normal entity");
}
if frog, ok := entity.variant.(Frog); ok {
fmt.printf("The frog jumps %f feet high at %v\n", frog.jump_height, entity.position);
}
// Panics if not the correct type
frog: Frog;
frog = entity.variant.(Frog);
frog, _ = entity.variant.(Frog); // ignore error and force cast
}
}
}
+430
View File
@@ -0,0 +1,430 @@
import (
"fmt.odin";
"atomics.odin";
"bits.odin";
"decimal.odin";
"hash.odin";
"math.odin";
"mem.odin";
"opengl.odin";
"os.odin";
"raw.odin";
"strconv.odin";
"strings.odin";
"sync.odin";
"sort.odin";
"types.odin";
"utf8.odin";
"utf16.odin";
/*
*/
)
general_stuff :: proc() {
// Complex numbers
a := 3 + 4i;
b: complex64 = 3 + 4i;
c: complex128 = 3 + 4i;
d := complex(2, 3);
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
c_printf :: proc(fmt: ^u8, #c_vararg args: ...any) -> i32 #link_name "printf" ---;
}
str := "%d\n\x00";
// c_printf(&str[0], i32(789456123));
Foo :: struct {
x: int;
y: f32;
z: string;
}
foo := Foo{123, 0.513, "A string"};
x, y, z := expand_to_tuple(foo);
fmt.println(x, y, z);
compile_assert(type_of(x) == int);
compile_assert(type_of(y) == f32);
compile_assert(type_of(z) == string);
// By default, all variables are zeroed
// This can be overridden with the "uninitialized value"
// This is similar to `nil` but applied to everything
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
}
foreign_blocks :: proc() {
// See sys/windows.odin
}
default_arguments :: proc() {
hello :: proc(a: int = 9, b: int = 9) do fmt.printf("a is %d; b is %d\n", a, b);
fmt.println("\nTesting default arguments:");
hello(1, 2);
hello(1);
hello();
}
named_arguments :: proc() {
Colour :: enum {
Red,
Orange,
Yellow,
Green,
Blue,
Octarine,
};
using Colour;
make_character :: proc(name, catch_phrase: string, favourite_colour, least_favourite_colour: Colour) {
fmt.println();
fmt.printf("My name is %v and I like %v. %v\n", name, favourite_colour, 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_favourite_colour = Green, favourite_colour = Blue);
// The named arguments can be specifed in any order.
make_character(favourite_colour = Octarine, catch_phrase = "U wot m8!",
least_favourite_colour = Green, name = "Dennis");
// NOTE: You cannot mix named arguments with normal values
/*
make_character("Dennis",
favourite_colour = Octarine, catch_phrase = "U wot m8!",
least_favourite_colour = Green);
*/
// Named arguments can also aid with default arguments
numerous_things :: proc(s: string, a := 1, b := 2, c := 3.14,
d := "The Best String!", e := false, f := 10.3/3.1, g := false) {
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
weird :: proc(pre: string, mid: int = 0, post: string) {
fmt.println(pre, mid, post);
}
weird("How many things", 42, "huh?");
weird(pre = "Prefix", post = "Pat");
}
default_return_values :: proc() {
foo :: proc(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
Error :: enum {
None,
WhyTheNumberThree,
TenIsTooBig,
};
Entity :: struct {
name: string;
id: u32;
}
some_thing :: proc(input: int) -> (result: ^Entity = nil, err := Error.None) {
match {
case input == 3: return err = Error.WhyTheNumberThree;
case input >= 10: return err = Error.TenIsTooBig;
}
e := new(Entity);
e.id = u32(input);
return result = e;
}
}
call_location :: proc() {
amazing :: proc(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();
}
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`
}
explicit_parametric_polymorphic_procedures :: proc() {
// This is how `new` is actually implemented, see _preload.odin
alloc_type :: proc(T: type) -> ^T do return cast(^T)alloc(size_of(T), align_of(T));
int_ptr := alloc_type(int);
defer free(int_ptr);
int_ptr^ = 137;
fmt.println(int_ptr, int_ptr^);
// Named arguments work too!
another_ptr := alloc_type(T = f32);
defer free(another_ptr);
add :: proc(T: type, args: ...T) -> T {
res: T;
for arg in args do res += arg;
return res;
}
fmt.println("add =", add(int, 1, 2, 3, 4, 5, 6));
swap :: proc(T: type, a, b: ^T) {
tmp := a^;
a^ = b^;
b^ = tmp;
}
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
Vector2 :: struct {x, y: f32;};
{
// A more complicated example using subtyping
// Something like this could be used in a game
Entity :: struct {
using position: Vector2;
flags: u64;
id: u64;
derived: any;
}
Rock :: struct {
using entity: Entity;
heavy: bool;
}
Door :: struct {
using entity: Entity;
open: bool;
}
Monster :: struct {
using entity: Entity;
is_robot: bool;
is_zombie: bool;
}
new_entity :: proc(T: type, x, y: f32) -> ^T {
result := new(T);
result.derived = result^;
result.x = x;
result.y = y;
return result;
}
entities: [dynamic]^Entity;
rock := new_entity(Rock, 3, 5);
// Named arguments work too!
door := new_entity(T = Door, x = 3, y = 6);
// And named arguments can be any order
monster := new_entity(
y = 1,
x = 2,
T = Monster,
);
append(&entities, rock, door, monster);
fmt.println("Subtyping");
for entity in entities {
match e in entity.derived {
case Rock: fmt.println("Rock", e.x, e.y);
case Door: fmt.println("Door", e.x, e.y);
case Monster: fmt.println("Monster", e.x, e.y);
}
}
}
{
Entity :: struct {
using position: Vector2;
flags: u64;
id: u64;
variant: union { Rock, Door, Monster };
}
Rock :: struct {
using entity: ^Entity;
heavy: bool;
}
Door :: struct {
using entity: ^Entity;
open: bool;
}
Monster :: struct {
using entity: ^Entity;
is_robot: bool;
is_zombie: bool;
}
new_entity :: proc(T: type, x, y: f32) -> ^T {
result := new(Entity);
result.variant = T{entity = result};
result.x = x;
result.y = y;
return cast(^T)&result.variant;
}
entities: [dynamic]^Entity;
rock := new_entity(Rock, 3, 5);
// Named arguments work too!
door := new_entity(T = Door, x = 3, y = 6);
// And named arguments can be any order
monster := new_entity(
y = 1,
x = 2,
T = Monster,
);
append(&entities, rock, door, monster);
fmt.println("Union");
for entity in entities {
match e in entity.variant {
case Rock: fmt.println("Rock", e.x, e.y);
case Door: fmt.println("Door", e.x, e.y);
case Monster: fmt.println("Monster", e.x, e.y);
}
}
}
}
implicit_polymorphic_assignment :: proc() {
yep :: proc(p: proc(x: int)) {
p(123);
}
frank :: proc(x: $T) do fmt.println("frank ->", x);
tim :: proc(x, y: $T) do fmt.println("tim ->", x, y);
yep(frank);
// yep(tim);
}
main :: proc() {
/*
foo :: proc(x: i64, y: f32) do fmt.println("#1", x, y);
foo :: proc(x: type, y: f32) do fmt.println("#2", type_info(x), y);
foo :: proc(x: type) do fmt.println("#3", type_info(x));
f :: foo;
f(y = 3785.1546, x = 123);
f(x = int, y = 897.513);
f(x = f32);
general_stuff();
foreign_blocks();
default_arguments();
named_arguments();
default_return_values();
call_location();
explicit_parametric_polymorphic_procedures();
implicit_polymorphic_assignment();
// Command line argument(s)!
// -opt=0,1,2,3
*/
/*
program := "+ + * - /";
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);
*/
}
+99 -118
View File
@@ -1,35 +1,30 @@
import (
win32 "sys/windows.odin";
"fmt.odin";
"os.odin";
"mem.odin";
)
import win32 "core:sys/windows.odin";
import "core:fmt.odin";
import "core:os.odin";
import "core:mem.odin";
const (
CANVAS_WIDTH = 128;
CANVAS_HEIGHT = 128;
CANVAS_SCALE = 3;
FRAME_TIME = 1.0/30.0;
WINDOW_TITLE = "Punity\x00";
)
const _ = compile_assert(CANVAS_WIDTH % 16 == 0);
CANVAS_WIDTH :: 128;
CANVAS_HEIGHT :: 128;
CANVAS_SCALE :: 3;
FRAME_TIME :: 1.0/30.0;
WINDOW_TITLE :: "Punity\x00";
const (
WINDOW_WIDTH = CANVAS_WIDTH * CANVAS_SCALE;
WINDOW_HEIGHT = CANVAS_HEIGHT * CANVAS_SCALE;
)
_ :: compile_assert(CANVAS_WIDTH % 16 == 0);
const (
STACK_CAPACITY = 1<<20;
STORAGE_CAPACITY = 1<<20;
DRAW_LIST_RESERVE = 128;
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE;
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE;
MAX_KEYS = 256;
)
type Core struct {
STACK_CAPACITY :: 1<<20;
STORAGE_CAPACITY :: 1<<20;
DRAW_LIST_RESERVE :: 128;
MAX_KEYS :: 256;
Core :: struct {
stack: ^Bank,
storage: ^Bank,
@@ -52,52 +47,52 @@ type Core struct {
draw_list: ^Draw_List,
}
type Perf_Span struct {
Perf_Span :: struct {
stamp: f64,
delta: f32,
}
type Bank struct {
Bank :: struct {
memory: []u8,
cursor: int,
}
type Bank_State struct {
Bank_State :: struct {
state: Bank,
bank: ^Bank,
}
type Color raw_union {
Color :: struct #raw_union {
using channels: struct{a, b, g, r: u8},
rgba: u32,
}
type Palette struct {
Palette :: struct {
colors: [256]Color,
colors_count: u8,
}
type Rect raw_union {
Rect :: struct #raw_union {
using minmax: struct {min_x, min_y, max_x, max_y: int},
using pos: struct {left, top, right, bottom: int},
e: [4]int,
}
type Bitmap struct {
Bitmap :: struct {
pixels: []u8,
width: int,
height: int,
}
type Font struct {
Font :: struct {
using bitmap: Bitmap,
char_width: int,
char_height: int,
}
type Canvas struct {
Canvas :: struct {
using bitmap: ^Bitmap,
palette: Palette,
translate_x: int,
@@ -106,23 +101,23 @@ type Canvas struct {
font: ^Font,
}
type DrawFlag enum {
DrawFlag :: enum {
NONE = 0,
FLIP_H = 1<<0,
FLIP_V = 1<<1,
MASK = 1<<2,
}
type Draw_Item struct {}
type Draw_List struct {
Draw_Item :: struct {}
Draw_List :: struct {
items: []Draw_Item,
}
type Key enum {
ModShift = 0x0001,
ModControl = 0x0002,
ModAlt = 0x0004,
ModSuper = 0x0008,
Key :: enum {
Mod_Shift = 0x0001,
Mod_Control = 0x0002,
Mod_Alt = 0x0004,
Mod_Super = 0x0008,
Unknown =-1,
@@ -153,9 +148,9 @@ type Key enum {
Kanji = 0x19,
Escape = 0x1B,
Convert = 0x1C,
NonConvert = 0x1D,
Non_Convert = 0x1D,
Accept = 0x1E,
ModeChange = 0x1F,
Mode_Change = 0x1F,
Space = 32,
Prior = 33,
Next = 34,
@@ -269,56 +264,49 @@ type Key enum {
X = 88,
Y = 89,
Z = 90,
LeftBracket = 91, /* [ */
Left_Bracket = 91, /* [ */
Backslash = 92, /* \ */
RightBracket = 93, /* ] */
GraveAccent = 96, /* ` */
Right_Bracket = 93, /* ] */
Grave_Accent = 96, /* ` */
};
proc key_down(k: Key) -> bool {
key_down :: proc(k: Key) -> bool {
return _core.key_states[k] != 0;
}
proc key_pressed(k: Key) -> bool {
key_pressed :: proc(k: Key) -> bool {
return (_core.key_deltas[k] != 0) && key_down(k);
}
let win32_perf_count_freq = win32.get_query_performance_frequency();
proc time_now() -> f64 {
win32_perf_count_freq := win32.get_query_performance_frequency();
time_now :: proc() -> f64 {
assert(win32_perf_count_freq != 0);
var counter: i64;
counter: i64;
win32.query_performance_counter(&counter);
return f64(counter) / f64(win32_perf_count_freq);
}
var _core: Core;
_core: Core;
proc run(user_init, user_step: proc(c: ^Core)) {
run :: proc(user_init, user_step: proc(c: ^Core)) {
using win32;
_core.running = true;
proc win32_proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline #cc_c {
proc win32_app_key_mods() -> u32 {
var mods: u32 = 0;
win32_proc :: proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline #cc_c {
win32_app_key_mods :: proc() -> u32 {
mods: u32 = 0;
if is_key_down(KeyCode.Shift) {
mods |= u32(Key.ModShift);
}
if is_key_down(KeyCode.Control) {
mods |= u32(Key.ModControl);
}
if is_key_down(KeyCode.Menu) {
mods |= u32(Key.ModAlt);
}
if is_key_down(KeyCode.Lwin) || is_key_down(KeyCode.Rwin) {
mods |= u32(Key.ModSuper);
}
if is_key_down(Key_Code.Shift) do mods |= u32(Key.Mod_Shift);
if is_key_down(Key_Code.Control) do mods |= u32(Key.Mod_Control);
if is_key_down(Key_Code.Menu) do mods |= u32(Key.Mod_Alt);
if is_key_down(Key_Code.Lwin) do mods |= u32(Key.Mod_Super);
if is_key_down(Key_Code.Rwin) do mods |= u32(Key.Mod_Super);
return mods;
}
@@ -350,14 +338,13 @@ proc run(user_init, user_step: proc(c: ^Core)) {
}
var class_name = "Punity\x00";
var window_class = WndClassExA{
class_name := "Punity\x00";
window_class := Wnd_Class_Ex_A{
class_name = &class_name[0],
size = size_of(WndClassExA),
size = size_of(Wnd_Class_Ex_A),
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
instance = Hinstance(get_module_handle_a(nil)),
wnd_proc = win32_proc,
// wnd_proc = DefWindowProcA,
background = Hbrush(get_stock_object(BLACK_BRUSH)),
};
@@ -366,28 +353,28 @@ proc run(user_init, user_step: proc(c: ^Core)) {
return;
}
var screen_width = get_system_metrics(SM_CXSCREEN);
var screen_height = get_system_metrics(SM_CYSCREEN);
screen_width := get_system_metrics(SM_CXSCREEN);
screen_height := get_system_metrics(SM_CYSCREEN);
var rc: Rect;
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;
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
assert(adjust_window_rect(&rc, style, 0) != 0);
var wt = WINDOW_TITLE;
wt := WINDOW_TITLE;
var win32_window = create_window_ex_a(0,
window_class.class_name,
&wt[0],
style,
rc.left, rc.top,
rc.right-rc.left, rc.bottom-rc.top,
nil, nil, window_class.instance,
nil);
win32_window := create_window_ex_a(0,
window_class.class_name,
&wt[0],
style,
rc.left, rc.top,
rc.right-rc.left, rc.bottom-rc.top,
nil, nil, window_class.instance,
nil);
if win32_window == nil {
fmt.fprintln(os.stderr, "create_window_ex_a failed");
@@ -395,8 +382,8 @@ proc run(user_init, user_step: proc(c: ^Core)) {
}
var window_bmi: BitmapInfo;
window_bmi.size = size_of(BitmapInfoHeader);
window_bmi: Bitmap_Info;
window_bmi.size = size_of(Bitmap_Info_Header);
window_bmi.width = CANVAS_WIDTH;
window_bmi.height = CANVAS_HEIGHT;
window_bmi.planes = 1;
@@ -408,23 +395,19 @@ proc run(user_init, user_step: proc(c: ^Core)) {
show_window(win32_window, SW_SHOW);
var window_buffer = make([]u32, CANVAS_WIDTH * CANVAS_HEIGHT);
window_buffer := make([]u32, CANVAS_WIDTH * CANVAS_HEIGHT);
defer free(window_buffer);
for _, i in window_buffer {
window_buffer[i] = 0xff00ff;
}
for _, i in window_buffer do 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;
)
dt: f64;
prev_time := time_now();
curr_time := time_now();
total_time: f64 = 0;
offset_x := 0;
offset_y := 0;
var message: Msg;
message: Msg;
for _core.running {
curr_time = time_now();
dt = curr_time - prev_time;
@@ -435,16 +418,16 @@ proc run(user_init, user_step: proc(c: ^Core)) {
offset_y += 2;
{
var buf: [128]u8;
var s = fmt.bprintf(buf[..], "Punity: %.4f ms\x00", dt*1000);
buf: [128]u8;
s := fmt.bprintf(buf[..], "Punity: %.4f ms\x00", dt*1000);
win32.set_window_text_a(win32_window, &s[0]);
}
for var y = 0; y < CANVAS_HEIGHT; y++ {
for var x = 0; x < CANVAS_WIDTH; x++ {
var g = (x % 32) * 8;
var b = (y % 32) * 8;
for y in 0..CANVAS_HEIGHT {
for x in 0..CANVAS_WIDTH {
g := (x % 32) * 8;
b := (y % 32) * 8;
window_buffer[x + y*CANVAS_WIDTH] = u32(g << 8 | b);
}
}
@@ -461,7 +444,7 @@ proc run(user_init, user_step: proc(c: ^Core)) {
user_step(&_core);
var dc = get_dc(win32_window);
dc := get_dc(win32_window);
stretch_dibits(dc,
0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
@@ -472,25 +455,23 @@ proc run(user_init, user_step: proc(c: ^Core)) {
release_dc(win32_window, dc);
{
var delta = time_now() - prev_time;
var ms = i32((FRAME_TIME - delta) * 1000);
if ms > 0 {
win32.sleep(ms);
}
delta := time_now() - prev_time;
if ms := i32((FRAME_TIME - delta) * 1000); ms > 0 {
win32.sleep(ms);
}
_core.frame++;
_core.frame += 1;
}
}
proc main() {
proc user_init(c: ^Core) {
main :: proc() {
user_init :: proc(c: ^Core) {
}
proc user_step(c: ^Core) {
user_step :: proc(c: ^Core) {
}
+2 -2
View File
@@ -1,8 +1,8 @@
@echo off
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
set _NO_DEBUG_HEAP=1
View File
+11 -8
View File
@@ -10,12 +10,16 @@ struct Array {
isize capacity;
T &operator[](isize index) {
GB_ASSERT_MSG(0 <= index && index < count, "Index out of bounds");
#if !defined(NO_ARRAY_BOUNDS_CHECK)
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
#endif
return data[index];
}
T const &operator[](isize index) const {
GB_ASSERT_MSG(0 <= index && index < count, "Index out of bounds");
#if !defined(NO_ARRAY_BOUNDS_CHECK)
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
#endif
return data[index];
}
};
@@ -31,7 +35,6 @@ template <typename T> void array_reserve (Array<T> *array, isize capacit
template <typename T> void array_resize (Array<T> *array, isize count);
template <typename T> void array_set_capacity(Array<T> *array, isize capacity);
template <typename T>
void array_init(Array<T> *array, gbAllocator a, isize init_capacity) {
array->allocator = a;
@@ -61,7 +64,7 @@ Array<T> array_make(T *data, isize count, isize capacity) {
template <typename T>
void array_free(Array<T> *array) {
if (array->allocator.proc != NULL) {
if (array->allocator.proc != nullptr) {
gb_free(array->allocator, array->data);
}
array->count = 0;
@@ -123,7 +126,7 @@ void array_set_capacity(Array<T> *array, isize capacity) {
array_resize(array, capacity);
}
T *new_data = NULL;
T *new_data = nullptr;
if (capacity > 0) {
new_data = gb_alloc_array(array->allocator, T, capacity);
gb_memmove(new_data, array->data, gb_size_of(T) * array->capacity);
@@ -147,7 +150,7 @@ typedef Array(void) ArrayVoid;
#define array_init_reserve(x_, allocator_, init_capacity_) do { \
void **e = cast(void **)&((x_)->e); \
GB_ASSERT((x_) != NULL); \
GB_ASSERT((x_) != nullptr); \
(x_)->allocator = (allocator_); \
(x_)->count = 0; \
(x_)->capacity = (init_capacity_); \
@@ -156,7 +159,7 @@ typedef Array(void) ArrayVoid;
#define array_init_count(x_, allocator_, init_count_) do { \
void **e = cast(void **)&((x_)->e); \
GB_ASSERT((x_) != NULL); \
GB_ASSERT((x_) != nullptr); \
(x_)->allocator = (allocator_); \
(x_)->count = (init_count_); \
(x_)->capacity = (init_count_); \
@@ -203,7 +206,7 @@ typedef Array(void) ArrayVoid;
void array__set_capacity(void *ptr, isize capacity, isize element_size) {
ArrayVoid *x = cast(ArrayVoid *)ptr;
GB_ASSERT(ptr != NULL);
GB_ASSERT(ptr != nullptr);
GB_ASSERT(element_size > 0);
+86 -39
View File
@@ -12,19 +12,47 @@ struct BuildContext {
i64 word_size; // Size of a pointer, must be >= 4
i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
String command;
String opt_flags;
String llc_flags;
String link_flags;
bool is_dll;
bool generate_docs;
i32 optimization_level;
bool show_timings;
bool keep_temp_files;
gbAffinity affinity;
isize thread_count;
};
gb_global BuildContext build_context = {0};
struct LibraryCollections {
String name;
String path;
};
gb_global Array<LibraryCollections> library_collections = {0};
void add_library_collection(String name, String path) {
// TODO(bill): Check the path is valid and a directory
LibraryCollections lc = {name, string_trim_whitespace(path)};
array_add(&library_collections, lc);
}
bool find_library_collection_path(String name, String *path) {
for_array(i, library_collections) {
if (library_collections[i].name == name) {
if (path) *path = library_collections[i].path;
return true;
}
}
return false;
}
// TODO(bill): OS dependent versions for the BuildContext
@@ -53,9 +81,9 @@ String odin_root_dir(void) {
len = 0;
for (;;) {
len = GetModuleFileNameW(NULL, &path_buf[0], path_buf.count);
len = GetModuleFileNameW(nullptr, &path_buf[0], cast(int)path_buf.count);
if (len == 0) {
return make_string(NULL, 0);
return make_string(nullptr, 0);
}
if (len < path_buf.count) {
break;
@@ -64,12 +92,15 @@ String odin_root_dir(void) {
}
len += 1; // NOTE(bill): It needs an extra 1 for some reason
gb_mutex_lock(&string_buffer_mutex);
defer (gb_mutex_unlock(&string_buffer_mutex));
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
defer (gb_temp_arena_memory_end(tmp));
text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
GetModuleFileNameW(NULL, text, len);
GetModuleFileNameW(nullptr, text, cast(int)len);
path = string16_to_string(heap_allocator(), make_string16(text, len));
for (i = path.len-1; i >= 0; i--) {
@@ -83,7 +114,6 @@ String odin_root_dir(void) {
global_module_path = path;
global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
array_free(&path_buf);
@@ -119,8 +149,12 @@ String odin_root_dir(void) {
}
}
gb_mutex_lock(&string_buffer_mutex);
defer (gb_mutex_unlock(&string_buffer_mutex));
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
defer (gb_temp_arena_memory_end(tmp));
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
gb_memmove(text, &path_buf[0], len);
@@ -136,7 +170,6 @@ String odin_root_dir(void) {
global_module_path = path;
global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
// array_free(&path_buf);
@@ -159,6 +192,7 @@ String odin_root_dir(void) {
}
array_init_count(&path_buf, heap_allocator(), 300);
defer (array_free(&path_buf));
len = 0;
for (;;) {
@@ -168,7 +202,7 @@ String odin_root_dir(void) {
// 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);
return make_string(nullptr, 0);
}
if (len < path_buf.count) {
break;
@@ -176,9 +210,14 @@ String odin_root_dir(void) {
array_resize(&path_buf, 2*path_buf.count + 300);
}
gb_mutex_lock(&string_buffer_mutex);
defer (gb_mutex_unlock(&string_buffer_mutex));
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
defer (gb_temp_arena_memory_end(tmp));
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
gb_memmove(text, &path_buf[0], len);
path = make_string(text, len);
@@ -193,10 +232,6 @@ String odin_root_dir(void) {
global_module_path = path;
global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
array_free(&path_buf);
return path;
}
#endif
@@ -204,14 +239,17 @@ String odin_root_dir(void) {
#if defined(GB_SYSTEM_WINDOWS)
String path_to_fullpath(gbAllocator a, String s) {
String result = {};
gb_mutex_lock(&string_buffer_mutex);
defer (gb_mutex_unlock(&string_buffer_mutex));
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);
DWORD len = GetFullPathNameW(&string16[0], 0, nullptr, nullptr);
if (len != 0) {
wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
GetFullPathNameW(&string16[0], len, text, NULL);
GetFullPathNameW(&string16[0], len, text, nullptr);
text[len] = 0;
result = string16_to_string(a, make_string16(text, len));
}
@@ -220,9 +258,11 @@ String path_to_fullpath(gbAllocator a, String s) {
}
#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("");
char *p;
gb_mutex_lock(&string_buffer_mutex);
p = realpath(cast(char *)s.text, 0);
gb_mutex_unlock(&string_buffer_mutex);
if(p == nullptr) return make_string_c("");
return make_string_c(p);
}
#else
@@ -231,47 +271,54 @@ String path_to_fullpath(gbAllocator a, String s) {
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);
u8 *str = gb_alloc_array(heap_allocator(), u8, base_dir.len+1+path.len+1);
defer (gb_free(heap_allocator(), str));
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;
gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len;
gb_memmove(str+i, "/", 1); i += 1;
gb_memmove(str+i, path.text, path.len); i += path.len;
str[i] = 0;
String res = make_string(str, i);
res = string_trim_whitespace(res);
return path_to_fullpath(a, 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;
String core = str_lit("core/");
isize str_len = module_dir.len + core_len + path.len;
isize str_len = module_dir.len + core.len + path.len;
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
defer (gb_free(heap_allocator(), str));
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';
isize i = 0;
gb_memmove(str+i, module_dir.text, module_dir.len); i += module_dir.len;
gb_memmove(str+i, core.text, core.len); i += core.len;
gb_memmove(str+i, path.text, path.len); i += path.len;
str[i] = 0;
res = path_to_fullpath(a, make_string(str, str_len));
gb_free(heap_allocator(), str);
return res;
String res = make_string(str, i);
res = string_trim_whitespace(res);
return path_to_fullpath(a, res);
}
String const ODIN_VERSION = str_lit("0.6.2");
void init_build_context(void) {
BuildContext *bc = &build_context;
gb_affinity_init(&bc->affinity);
if (bc->thread_count == 0) {
bc->thread_count = gb_max(bc->affinity.thread_count, 1);
}
bc->ODIN_VENDOR = str_lit("odin");
bc->ODIN_VERSION = str_lit("0.5.0");
bc->ODIN_VERSION = ODIN_VERSION;
bc->ODIN_ROOT = odin_root_dir();
#if defined(GB_SYSTEM_WINDOWS)
+353 -171
View File
@@ -1,7 +1,7 @@
bool check_is_terminating(AstNode *node);
void check_stmt (Checker *c, AstNode *node, u32 flags);
// NOTE(bill): `content_name` is for debugging and error messages
// 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 ||
@@ -13,7 +13,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
// TODO(bill): is this a good enough error message?
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
error(operand->expr,
"Cannot assign built-in procedure `%s` in %.*s",
"Cannot assign built-in procedure '%s' in %.*s",
expr_str,
LIT(context_name));
@@ -23,41 +23,58 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
}
if (e->type == NULL) {
if (operand->mode == Addressing_Overload) {
if (e->type == nullptr) {
error(operand->expr, "Cannot determine type from overloaded procedure '%.*s'", LIT(operand->overload_entities[0]->token.string));
} else {
check_assignment(c, operand, e->type, str_lit("variable assignment"));
if (operand->mode != Addressing_Type) {
return operand->type;
}
}
}
if (e->type == nullptr) {
e->type = t_invalid;
}
return NULL;
return nullptr;
}
if (e->type == NULL) {
if (e->type == nullptr) {
// NOTE(bill): Use the type of the operand
Type *t = operand->type;
if (is_type_untyped(t)) {
if (t == t_invalid || is_type_untyped_nil(t)) {
error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name));
e->type = t_invalid;
return NULL;
return nullptr;
}
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;
return nullptr;
}
t = default_type(t);
}
if (is_type_gen_proc(t)) {
error(e->token, "Invalid use of a generic procedure in %.*s", LIT(context_name));
if (is_type_polymorphic(t)) {
gbString str = type_to_string(t);
defer (gb_string_free(str));
error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
e->type = t_invalid;
return NULL;
return nullptr;
} else if (is_type_empty_union(t)) {
gbString str = type_to_string(t);
defer (gb_string_free(str));
error(e->token, "An empty union '%s' cannot be instantiated in %.*s", str, LIT(context_name));
e->type = t_invalid;
return nullptr;
}
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;
}
@@ -66,25 +83,26 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
check_assignment(c, operand, e->type, context_name);
if (operand->mode == Addressing_Invalid) {
return NULL;
return nullptr;
}
return e->type;
}
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) {
if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) {
return;
}
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
defer (gb_temp_arena_memory_end(tmp));
// 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(&operands, c->tmp_allocator, 2*lhs_count);
check_unpack_arguments(c, lhs_count, &operands, inits, true);
check_unpack_arguments(c, lhs, lhs_count, &operands, inits, true);
isize rhs_count = operands.count;
for_array(i, operands) {
@@ -95,21 +113,24 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNo
isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) {
check_init_variable(c, lhs[i], &operands[i], context_name);
Entity *e = lhs[i];
DeclInfo *d = decl_info_of_entity(&c->info, e);
Operand *o = &operands[i];
check_init_variable(c, e, o, context_name);
if (d != nullptr) {
d->init_expr = o->expr;
}
}
if (rhs_count > 0 && lhs_count != rhs_count) {
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
error(lhs[0]->token, "Assignment count mismatch '%td' = '%td'", lhs_count, rhs_count);
}
gb_temp_arena_memory_end(tmp);
}
void check_init_constant(Checker *c, Entity *e, Operand *operand) {
if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid ||
e->type == t_invalid) {
if (e->type == NULL) {
if (e->type == nullptr) {
e->type = t_invalid;
}
return;
@@ -118,24 +139,24 @@ 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(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) {
if (e->type == nullptr) {
e->type = t_invalid;
}
return;
}
if (!is_type_constant_type(operand->type)) {
gbString type_str = type_to_string(operand->type);
error(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) {
if (e->type == nullptr) {
e->type = t_invalid;
}
return;
}
if (e->type == NULL) { // NOTE(bill): type inference
if (e->type == nullptr) { // NOTE(bill): type inference
e->type = operand->type;
}
@@ -149,27 +170,55 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
e->Constant.value = operand->value;
}
void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
GB_ASSERT(e->type == NULL);
AstNode *remove_type_alias(AstNode *node) {
for (;;) {
if (node == nullptr) {
return nullptr;
}
if (node->kind == AstNode_ParenExpr) {
node = node->ParenExpr.expr;
} else if (node->kind == AstNode_AliasType) {
node = node->AliasType.type;
} else {
return node;
}
}
}
void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, bool is_alias) {
GB_ASSERT(e->type == nullptr);
DeclInfo *decl = decl_info_of_entity(&c->info, e);
if (decl != nullptr && decl->attributes.count > 0) {
error(decl->attributes[0], "Attributes are not allowed on type declarations");
}
AstNode *te = remove_type_alias(type_expr);
e->type = t_invalid;
String name = e->token.string;
Type *named = make_type_named(c->allocator, name, NULL, e);
Type *named = make_type_named(c->allocator, name, nullptr, e);
named->Named.type_name = e;
if (def != NULL && def->kind == Type_Named) {
if (def != nullptr && def->kind == Type_Named) {
def->Named.base = named;
}
e->type = named;
// gb_printf_err("%.*s %p\n", LIT(e->token.string), e);
Type *bt = check_type(c, type_expr, named);
Type *bt = check_type(c, te, named);
named->Named.base = base_type(bt);
if (named->Named.base == t_invalid) {
// gb_printf("check_type_decl: %s\n", type_to_string(named));
if (is_alias) {
if (is_type_named(bt)) {
e->type = bt;
e->TypeName.is_type_alias = true;
} else {
gbString str = type_to_string(bt);
error(type_expr, "Type alias declaration with a non-named type '%s'", str);
gb_string_free(str);
}
}
}
void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, Type *named_type) {
GB_ASSERT(e->type == NULL);
GB_ASSERT(e->type == nullptr);
GB_ASSERT(e->kind == Entity_Constant);
if (e->flags & EntityFlag_Visited) {
@@ -182,7 +231,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
Type *t = check_type(c, type_expr);
if (!is_type_constant_type(t)) {
gbString str = type_to_string(t);
error(type_expr, "Invalid constant type `%s`", str);
error(type_expr, "Invalid constant type '%s'", str);
gb_string_free(str);
e->type = t_invalid;
return;
@@ -191,25 +240,98 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
}
Operand operand = {};
if (init != NULL) {
check_expr_or_type(c, &operand, init);
}
#if 0
if (operand.mode == Addressing_Type) {
e->kind = Entity_TypeName;
DeclInfo *d = c->context.decl;
d->type_expr = d->init_expr;
check_type_decl(c, e, d->type_expr, named_type);
return;
if (init != nullptr) {
Entity *entity = nullptr;
if (init->kind == AstNode_Ident) {
entity = check_ident(c, &operand, init, nullptr, e->type, true);
} else if (init->kind == AstNode_SelectorExpr) {
entity = check_selector(c, &operand, init, e->type);
} else {
check_expr_or_type(c, &operand, init, e->type);
}
switch (operand.mode) {
case Addressing_Type: {
e->kind = Entity_TypeName;
DeclInfo *d = c->context.decl;
if (d->type_expr != nullptr) {
error(e->token, "A type declaration cannot have an type parameter");
}
d->type_expr = d->init_expr;
check_type_decl(c, e, d->type_expr, named_type, false);
return;
}
// NOTE(bill): Check to see if the expression it to be aliases
#if 1
case Addressing_Builtin:
if (e->type != nullptr) {
error(type_expr, "A constant alias of a built-in procedure may not have a type initializer");
}
e->kind = Entity_Builtin;
e->Builtin.id = operand.builtin_id;
e->type = t_invalid;
return;
case Addressing_Overload:
e->kind = Entity_Alias;
e->Alias.base = operand.overload_entities[0];
e->type = t_invalid;
return;
#endif
}
#if 1
if (entity != nullptr) {
switch (entity->kind) {
case Entity_Alias:
e->kind = Entity_Alias;
e->type = entity->type;
e->Alias.base = entity->Alias.base;
return;
case Entity_Procedure:
e->kind = Entity_Alias;
e->type = entity->type;
e->Alias.base = entity;
return;
case Entity_ImportName:
e->kind = Entity_ImportName;
e->type = entity->type;
e->ImportName.path = entity->ImportName.path;
e->ImportName.name = entity->ImportName.path;
e->ImportName.scope = entity->ImportName.scope;
e->ImportName.used = false;
return;
case Entity_LibraryName:
e->kind = Entity_LibraryName;
e->type = entity->type;
e->LibraryName.path = entity->LibraryName.path;
e->LibraryName.name = entity->LibraryName.path;
e->LibraryName.used = false;
return;
}
}
#endif
}
if (init != nullptr) {
check_expr_or_type(c, &operand, init, e->type);
}
#endif
check_init_constant(c, e, &operand);
if (operand.mode == Addressing_Invalid ||
base_type(operand.type) == t_invalid) {
error(e->token, "Invalid declaration type");
gbString str = expr_to_string(init);
error(e->token, "Invalid declaration type '%s'", str);
gb_string_free(str);
}
DeclInfo *decl = decl_info_of_entity(&c->info, e);
if (decl != nullptr && decl->attributes.count > 0) {
error(decl->attributes[0], "Attributes are not allowed on constant value declarations");
}
}
@@ -237,14 +359,12 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
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;
}
i64 sx = type_size_of(heap_allocator(), x);
i64 sy = type_size_of(heap_allocator(), y);
if (sx == sy) continue;
}
if (!are_types_identical(x, y)) {
return false;
}
if (!are_types_identical(x, y)) return false;
}
for (isize i = 0; i < a->result_count; i++) {
Type *x = base_type(a->results->Tuple.variables[i]->type);
@@ -256,9 +376,9 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
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;
}
i64 sx = type_size_of(heap_allocator(), x);
i64 sy = type_size_of(heap_allocator(), y);
if (sx == sy) continue;
}
if (!are_types_identical(x, y)) {
@@ -270,8 +390,8 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
}
void init_entity_foreign_library(Checker *c, Entity *e) {
AstNode *ident = NULL;
Entity **foreign_library = NULL;
AstNode *ident = nullptr;
Entity **foreign_library = nullptr;
switch (e->kind) {
case Entity_Procedure:
@@ -286,21 +406,21 @@ void init_entity_foreign_library(Checker *c, Entity *e) {
return;
}
if (ident == NULL) {
if (ident == nullptr) {
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;
String name = ident->Ident.token.string;
Entity *found = scope_lookup_entity(c->context.scope, name);
if (found == NULL) {
if (name == "_") {
error(ident, "`_` cannot be used as a value type");
if (found == nullptr) {
if (is_blank_ident(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));
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;
@@ -309,107 +429,142 @@ void init_entity_foreign_library(Checker *c, Entity *e) {
}
}
String handle_link_name(Checker *c, Token token, String link_name, String link_prefix) {
if (link_prefix.len > 0) {
if (link_name.len > 0) {
error(token, "'link_name' and 'link_prefix' cannot be used together");
} else {
isize len = link_prefix.len + token.string.len;
u8 *name = gb_alloc_array(c->allocator, u8, len+1);
gb_memmove(name, &link_prefix[0], link_prefix.len);
gb_memmove(name+link_prefix.len, &token.string[0], token.string.len);
name[len] = 0;
link_name = make_string(name, len);
}
}
return link_name;
}
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
GB_ASSERT(e->type == NULL);
if (d->proc_decl->kind != AstNode_ProcDecl) {
GB_ASSERT(e->type == nullptr);
if (d->proc_lit->kind != AstNode_ProcLit) {
// TOOD(bill): Better error message
error(d->proc_decl, "Expected a procedure to check");
error(d->proc_lit, "Expected a procedure to check");
return;
}
Type *proc_type = e->type;
if (d->gen_proc_type != NULL) {
if (d->gen_proc_type != nullptr) {
proc_type = d->gen_proc_type;
} else {
proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
proc_type = make_type_proc(c->allocator, e->scope, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
}
e->type = proc_type;
ast_node(pd, ProcDecl, d->proc_decl);
ast_node(pl, ProcLit, d->proc_lit);
check_open_scope(c, pd->type);
check_open_scope(c, pl->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_require_results = (pd->tags & ProcTag_require_results) != 0;
auto prev_context = c->context;
c->context.allow_polymorphic_types = true;
check_procedure_type(c, proc_type, pl->type);
c->context = prev_context;
TypeProc *pt = &proc_type->Proc;
if (d->scope->is_file && e->token.string == "main") {
bool is_foreign = e->Procedure.is_foreign;
bool is_export = e->Procedure.is_export;
bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
AttributeContext ac = make_attribute_context(e->Procedure.link_prefix);
if (d != nullptr) {
check_decl_attributes(c, d->attributes, proc_decl_attribute, &ac);
}
ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
if (d->scope->file != nullptr && 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);
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");
if (pt->calling_convention != ProcCC_Odin &&
pt->calling_convention != ProcCC_Contextless) {
error(e->token, "Procedure 'main' cannot have a custom calling convention");
}
pt->calling_convention = ProcCC_Contextless;
if (d->scope->is_init) {
if (c->info.entry_point != nullptr) {
error(e->token, "Redeclaration of the entry pointer procedure 'main'");
} else {
c->info.entry_point = e;
}
}
proc_type->Proc.calling_convention = ProcCC_Contextless;
}
if (is_inline && is_no_inline) {
error(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
}
if (is_foreign && is_export) {
error(pd->type, "A foreign procedure cannot have an `export` tag");
error(pl->type, "A foreign procedure cannot have an 'export' tag");
}
if (pt->is_generic) {
if (pd->body == NULL) {
if (pt->is_polymorphic) {
if (pl->body == nullptr) {
error(e->token, "Polymorphic procedures must have a body");
}
if (is_foreign) {
error(e->token, "A foreign procedures cannot be a polymorphic");
error(e->token, "A foreign procedure cannot be a polymorphic");
return;
}
}
if (pd->body != NULL) {
if (pl->body != nullptr) {
if (is_foreign) {
error(pd->body, "A foreign procedure cannot have a body");
error(pl->body, "A foreign procedure cannot have a body");
}
if (proc_type->Proc.c_vararg) {
error(pd->body, "A procedure with a `#c_vararg` field cannot have a body");
error(pl->body, "A procedure with a '#c_vararg' field cannot have a body and must be foreign");
}
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);
GB_ASSERT(pl->body->kind == AstNode_BlockStmt);
if (!pt->is_polymorphic) {
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pl->body, pl->tags);
}
} else if (!is_foreign) {
error(e->token, "Only a foreign procedure cannot have a body");
if (e->Procedure.is_export) {
error(e->token, "Foreign export procedures must have a body");
} else {
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");
error(pl->type, "'#require_results' is not needed on a procedure with no results");
} else {
pt->require_results = is_require_results;
}
if (ac.link_name.len > 0) {
e->Procedure.link_name = ac.link_name;
}
if (is_foreign) {
String name = e->token.string;
if (pd->link_name.len > 0) {
name = pd->link_name;
if (e->Procedure.link_name.len > 0) {
name = e->Procedure.link_name;
}
e->Procedure.is_foreign = true;
e->Procedure.link_name = name;
init_entity_foreign_library(c, e);
auto *fp = &c->info.foreigns;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
@@ -420,41 +575,41 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
Type *other_type = base_type(f->type);
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);
error(d->proc_lit,
"Redeclaration of foreign procedure '%.*s' with different type signatures\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else 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);
error(d->proc_lit,
"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 if (name == "main") {
error(d->proc_lit, "The link name 'main' is reserved for internal use");
} else {
map_set(fp, key, e);
}
} else {
String name = e->token.string;
if (is_link_name) {
name = pd->link_name;
if (e->Procedure.link_name.len > 0) {
name = e->Procedure.link_name;
}
if (is_link_name || is_export) {
if (e->Procedure.link_name.len > 0 || is_export) {
auto *fp = &c->info.foreigns;
e->Procedure.link_name = name;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
// TODO(bill): Better error message?
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);
error(d->proc_lit,
"Non unique linking name for procedure '%.*s'\n"
"\tother at %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
} else if (name == "main") {
error(d->proc_lit, "The link name 'main' is reserved for internal use");
} else {
map_set(fp, key, e);
}
@@ -462,8 +617,8 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
}
}
void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) {
GB_ASSERT(e->type == NULL);
void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, Array<AstNode *> init_expr_list) {
GB_ASSERT(e->type == nullptr);
GB_ASSERT(e->kind == Entity_Variable);
if (e->flags & EntityFlag_Visited) {
@@ -472,18 +627,52 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
}
e->flags |= EntityFlag_Visited;
if (type_expr != NULL) {
AttributeContext ac = make_attribute_context(e->Variable.link_prefix);
ac.init_expr_list_count = init_expr_list.count;
DeclInfo *decl = decl_info_of_entity(&c->info, e);
if (decl != nullptr) {
check_decl_attributes(c, decl->attributes, var_decl_attribute, &ac);
}
ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
e->Variable.thread_local_model = ac.thread_local_model;
String context_name = str_lit("variable declaration");
if (type_expr != nullptr) {
e->type = check_type(c, type_expr);
}
if (e->type != nullptr) {
if (is_type_polymorphic(base_type(e->type))) {
gbString str = type_to_string(e->type);
defer (gb_string_free(str));
error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
e->type = t_invalid;
} else if (is_type_empty_union(e->type)) {
gbString str = type_to_string(e->type);
defer (gb_string_free(str));
error(e->token, "An empty union '%s' cannot be instantiated in %.*s", str, LIT(context_name));
e->type = t_invalid;
}
}
if (e->Variable.is_foreign) {
if (init_expr != NULL) {
if (init_expr_list.count > 0) {
error(e->token, "A foreign variable declaration cannot have a default value");
}
init_entity_foreign_library(c, e);
}
if (ac.link_name.len > 0) {
e->Variable.link_name = ac.link_name;
}
if (e->Variable.is_foreign || e->Variable.is_export) {
String name = e->token.string;
if (e->Variable.link_name.len > 0) {
name = e->Variable.link_name;
}
auto *fp = &c->info.foreigns;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
@@ -494,7 +683,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
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"
"Foreign entity '%.*s' previously declared elsewhere with a different type\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
@@ -503,46 +692,35 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
}
}
if (init_expr == NULL) {
if (type_expr == NULL) {
if (init_expr_list.count == 0) {
if (type_expr == nullptr) {
e->type = t_invalid;
}
return;
}
if (entities == NULL || entity_count == 1) {
GB_ASSERT(entities == NULL || entities[0] == e);
Operand operand = {};
check_expr(c, &operand, init_expr);
check_init_variable(c, e, &operand, str_lit("variable declaration"));
}
if (type_expr != NULL) {
if (type_expr != nullptr) {
for (isize i = 0; i < entity_count; i++) {
entities[i]->type = e->type;
}
}
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"));
check_init_variables(c, entities, entity_count, init_expr_list, context_name);
}
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
if (e->type != NULL) {
if (e->type != nullptr) {
return;
}
if (d == NULL) {
if (d == nullptr) {
d = decl_info_of_entity(&c->info, e);
if (d == NULL) {
if (d == nullptr) {
// TODO(bill): Err here?
e->type = t_invalid;
set_base_type(named_type, t_invalid);
return;
// GB_PANIC("`%.*s` should been declared!", LIT(e->token.string));
// GB_PANIC("'%.*s' should been declared!", LIT(e->token.string));
}
}
@@ -554,14 +732,16 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
switch (e->kind) {
case Entity_Variable:
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr_list);
break;
case Entity_Constant:
check_const_decl(c, e, d->type_expr, d->init_expr, named_type);
break;
case Entity_TypeName:
check_type_decl(c, e, d->type_expr, named_type);
case Entity_TypeName: {
bool is_alias = unparen_expr(d->type_expr)->kind == AstNode_AliasType;
check_type_decl(c, e, d->type_expr, named_type, is_alias);
break;
}
case Entity_Procedure:
check_proc_decl(c, e, d);
break;
@@ -573,7 +753,7 @@ 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) {
if (body == nullptr) {
return;
}
GB_ASSERT(body->kind == AstNode_BlockStmt);
@@ -587,6 +767,8 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
}
CheckerContext old_context = c->context;
defer (c->context = old_context);
c->context.scope = decl->scope;
c->context.decl = decl;
c->context.proc_name = proc_name;
@@ -595,7 +777,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
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++) {
for_array(i, params->variables) {
Entity *e = params->variables[i];
if (e->kind != Entity_Variable) {
continue;
@@ -606,23 +788,26 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
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 *scope = scope_of_node(&c->info, t->Record.node);
GB_ASSERT(scope != NULL);
if (t->kind == Type_Struct) {
Scope *scope = t->Struct.scope;
if (scope == nullptr) {
scope = scope_of_node(&c->info, t->Struct.node);
}
GB_ASSERT(scope != nullptr);
for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = 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));
if (prev != nullptr) {
error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
break;
}
}
}
} else {
error(e->token, "`using` can only be applied to variables of type struct or raw_union");
error(e->token, "'using' can only be applied to variables of type struct");
break;
}
}
@@ -635,7 +820,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
if (type->Proc.result_count > 0) {
if (!check_is_terminating(body)) {
if (token.kind == Token_Ident) {
error(bs->close, "Missing return statement at the end of the procedure `%.*s`", LIT(token.string));
error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string));
} else {
error(bs->close, "Missing return statement at the end of the procedure");
}
@@ -644,16 +829,13 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
}
pop_procedure(c);
check_scope_usage(c, c->context.scope);
c->context = old_context;
if (decl->parent != NULL) {
if (decl->parent != nullptr) {
// 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);
Entity *e = decl->deps.entries[i].ptr;
ptr_set_add(&decl->parent->deps, e);
}
}
}
+2109 -2550
View File
File diff suppressed because it is too large Load Diff
+462 -429
View File
File diff suppressed because it is too large Load Diff
+2436
View File
File diff suppressed because it is too large Load Diff
+1909 -807
View File
File diff suppressed because it is too large Load Diff
+315 -64
View File
@@ -12,9 +12,84 @@
#include <math.h>
GB_ALLOCATOR_PROC(heap_allocator_proc);
gbAllocator heap_allocator(void) {
return gb_heap_allocator();
gbAllocator a;
a.proc = heap_allocator_proc;
a.data = NULL;
return a;
}
GB_ALLOCATOR_PROC(heap_allocator_proc) {
void *ptr = NULL;
gb_unused(allocator_data);
gb_unused(old_size);
// TODO(bill): Throughly test!
switch (type) {
#if defined(GB_COMPILER_MSVC)
case gbAllocation_Alloc:
ptr = _aligned_malloc(size, alignment);
if (flags & gbAllocatorFlag_ClearToZero)
gb_zero_size(ptr, size);
break;
case gbAllocation_Free:
_aligned_free(old_memory);
break;
case gbAllocation_Resize:
ptr = _aligned_realloc(old_memory, size, alignment);
break;
#elif defined(GB_SYSTEM_LINUX)
// TODO(bill): *nix version that's decent
case gbAllocation_Alloc: {
ptr = aligned_alloc(alignment, size);
// ptr = malloc(size+alignment);
if (flags & gbAllocatorFlag_ClearToZero) {
gb_zero_size(ptr, size);
}
break;
}
case gbAllocation_Free: {
free(old_memory);
break;
}
case gbAllocation_Resize: {
// ptr = realloc(old_memory, size);
ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
break;
}
#else
// TODO(bill): *nix version that's decent
case gbAllocation_Alloc: {
posix_memalign(&ptr, alignment, size);
if (flags & gbAllocatorFlag_ClearToZero) {
gb_zero_size(ptr, size);
}
break;
}
case gbAllocation_Free: {
free(old_memory);
break;
}
case gbAllocation_Resize: {
ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
break;
}
#endif
case gbAllocation_FreeAll:
break;
}
return ptr;
}
#include "unicode.cpp"
@@ -23,6 +98,9 @@ gbAllocator heap_allocator(void) {
#include "integer128.cpp"
#include "murmurhash3.cpp"
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
u128 fnv128a(void const *data, isize len) {
u128 o = u128_lo_hi(0x13bull, 0x1000000ull);
u128 h = u128_lo_hi(0x62b821756295c58dull, 0x6c62272e07bb0142ull);
@@ -35,6 +113,9 @@ u128 fnv128a(void const *data, isize len) {
}
#include "map.cpp"
#include "ptr_set.cpp"
#include "string_set.cpp"
#include "priority_queue.cpp"
@@ -52,93 +133,163 @@ gbAllocator scratch_allocator(void) {
return gb_scratch_allocator(&scratch_memory);
}
struct Pool {
isize memblock_size;
isize out_of_band_size;
isize alignment;
struct DynamicArenaBlock {
DynamicArenaBlock *prev;
DynamicArenaBlock *next;
u8 * start;
isize count;
isize capacity;
Array<u8 *> unused_memblock;
Array<u8 *> used_memblock;
Array<u8 *> out_of_band_allocations;
gbVirtualMemory vm;
u8 * current_memblock;
u8 * current_pos;
isize bytes_left;
gbAllocator block_allocator;
};
struct DynamicArena {
DynamicArenaBlock *start_block;
DynamicArenaBlock *current_block;
isize block_size;
enum {
POOL_BUCKET_SIZE_DEFAULT = 65536,
POOL_OUT_OF_BAND_SIZE_DEFAULT = 6554,
};
DynamicArenaBlock *add_dynamic_arena_block(DynamicArena *a) {
GB_ASSERT(a != NULL);
GB_ASSERT(a->block_size > 0);
void pool_init(Pool *pool,
isize memblock_size = POOL_BUCKET_SIZE_DEFAULT,
isize out_of_band_size = POOL_OUT_OF_BAND_SIZE_DEFAULT,
isize alignment = 8,
gbAllocator block_allocator = heap_allocator(),
gbAllocator array_allocator = heap_allocator()) {
pool->memblock_size = memblock_size;
pool->out_of_band_size = out_of_band_size;
pool->alignment = alignment;
pool->block_allocator = block_allocator;
gbVirtualMemory vm = gb_vm_alloc(NULL, a->block_size);
DynamicArenaBlock *block = cast(DynamicArenaBlock *)vm.data;
array_init(&pool->unused_memblock, array_allocator);
array_init(&pool->used_memblock, array_allocator);
array_init(&pool->out_of_band_allocations, array_allocator);
}
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;
void pool_free_all(Pool *p) {
if (p->current_memblock != nullptr) {
array_add(&p->unused_memblock, p->current_memblock);
p->current_memblock = nullptr;
}
a->current_block = block;
return block;
for_array(i, p->used_memblock) {
array_add(&p->unused_memblock, p->used_memblock[i]);
}
array_clear(&p->unused_memblock);
for_array(i, p->out_of_band_allocations) {
gb_free(p->block_allocator, p->out_of_band_allocations[i]);
}
array_clear(&p->out_of_band_allocations);
}
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 pool_destroy(Pool *p) {
pool_free_all(p);
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);
for_array(i, p->unused_memblock) {
gb_free(p->block_allocator, p->unused_memblock[i]);
}
}
GB_ALLOCATOR_PROC(dynamic_arena_allocator_proc) {
DynamicArena *a = cast(DynamicArena *)allocator_data;
void *ptr = NULL;
void pool_cycle_new_block(Pool *p) {
GB_ASSERT_MSG(p->block_allocator.proc != nullptr,
"You must call pool_init on a Pool before using it!");
if (p->current_memblock != nullptr) {
array_add(&p->used_memblock, p->current_memblock);
}
u8 *new_block = nullptr;
if (p->unused_memblock.count > 0) {
new_block = array_pop(&p->unused_memblock);
} else {
GB_ASSERT(p->block_allocator.proc != nullptr);
new_block = cast(u8 *)gb_alloc_align(p->block_allocator, p->memblock_size, p->alignment);
}
p->bytes_left = p->memblock_size;
p->current_memblock = new_block;
p->current_memblock = new_block;
}
void *pool_get(Pool *p,
isize size, isize alignment = 0) {
if (alignment <= 0) alignment = p->alignment;
isize extra = alignment - (size & alignment);
size += extra;
if (size >= p->out_of_band_size) {
GB_ASSERT(p->block_allocator.proc != nullptr);
u8 *memory = cast(u8 *)gb_alloc_align(p->block_allocator, p->memblock_size, alignment);
if (memory != nullptr) {
array_add(&p->out_of_band_allocations, memory);
}
return memory;
}
if (p->bytes_left < size) {
pool_cycle_new_block(p);
if (p->current_memblock != nullptr) {
return nullptr;
}
}
u8 *res = p->current_pos;
p->current_pos += size;
p->bytes_left -= size;
return res;
}
gbAllocator pool_allocator(Pool *pool);
GB_ALLOCATOR_PROC(pool_allocator_procedure) {
Pool *p = cast(Pool *)allocator_data;
void *ptr = nullptr;
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");
case gbAllocation_Alloc:
return pool_get(p, size, alignment);
case gbAllocation_Free:
// Does nothing
break;
case gbAllocation_FreeAll:
pool_free_all(p);
break;
case gbAllocation_Resize:
return gb_default_resize_align(pool_allocator(p), old_memory, old_size, size, alignment);
}
return ptr;
}
gbAllocator dynamic_arena_allocator(DynamicArena *a) {
gbAllocator allocator = {dynamic_arena_allocator_proc, a};
gbAllocator pool_allocator(Pool *pool) {
gbAllocator allocator;
allocator.proc = pool_allocator_procedure;
allocator.data = pool;
return allocator;
}
i32 next_pow2(i32 n) {
if (n <= 0) {
return 0;
}
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n++;
return n;
}
i64 next_pow2(i64 n) {
if (n <= 0) {
return 0;
@@ -154,6 +305,79 @@ i64 next_pow2(i64 n) {
return n;
}
i32 bit_set_count(u32 x) {
x -= ((x >> 1) & 0x55555555);
x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
x = (((x >> 4) + x) & 0x0f0f0f0f);
x += (x >> 8);
x += (x >> 16);
return cast(i32)(x & 0x0000003f);
}
i64 bit_set_count(u64 x) {
u32 a = *(cast(u32 *)&x);
u32 b = *(cast(u32 *)&x + 1);
return bit_set_count(a) + bit_set_count(b);
}
u32 floor_log2(u32 x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return cast(u32)(bit_set_count(x) - 1);
}
u64 floor_log2(u64 x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x |= x >> 32;
return cast(u64)(bit_set_count(x) - 1);
}
u32 ceil_log2(u32 x) {
i32 y = cast(i32)(x & (x-1));
y |= -y;
y >>= 32-1;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return cast(u32)(bit_set_count(x) - 1 - y);
}
u64 ceil_log2(u64 x) {
i64 y = cast(i64)(x & (x-1));
y |= -y;
y >>= 64-1;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x |= x >> 32;
return cast(u64)(bit_set_count(x) - 1 - y);
}
i32 prev_pow2(i32 n) {
if (n <= 0) {
return 0;
}
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n - (n >> 1);
}
i64 prev_pow2(i64 n) {
if (n <= 0) {
return 0;
@@ -224,7 +448,6 @@ f64 gb_sqrt(f64 x) {
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
// Doubly Linked Lists
@@ -236,7 +459,7 @@ f64 gb_sqrt(f64 x) {
} while (0)
#define DLIST_APPEND(root_element, curr_element, next_element) do { \
if ((root_element) == NULL) { \
if ((root_element) == nullptr) { \
(root_element) = (curr_element) = (next_element); \
} else { \
DLIST_SET(curr_element, next_element); \
@@ -250,7 +473,7 @@ f64 gb_sqrt(f64 x) {
wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
u32 i, j;
u32 len = string16_len(cmd_line);
u32 len = cast(u32)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));
@@ -302,10 +525,38 @@ wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
i++;
}
_argv[j] = '\0';
argv[argc] = NULL;
argv[argc] = nullptr;
if (_argc) *_argc = argc;
return argv;
}
#endif
#if defined(GB_SYSTEM_WINDOWS)
bool path_is_directory(String path) {
gbAllocator a = heap_allocator();
String16 wstr = string_to_string16(a, path);
defer (gb_free(a, wstr.text));
i32 attribs = GetFileAttributesW(wstr.text);
if (attribs < 0) return false;
return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
#else
bool path_is_directory(String path) {
gbAllocator a = heap_allocator();
char *copy = cast(char *)copy_string(a, path).text;
defer (gb_free(a, copy));
struct stat s;
if (stat(copy, &s) == 0) {
return (s.st_mode & S_IFDIR) != 0;
}
return false;
}
#endif
+5 -34
View File
@@ -10,7 +10,7 @@ String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
len += 1; // for \n
}
if (len == 0) {
return make_string(NULL, 0);
return make_string(nullptr, 0);
}
u8 *text = gb_alloc_array(a, u8, len+1);
@@ -32,6 +32,7 @@ String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
return make_string(text, len);
}
#if 0
void print_type_spec(AstNode *spec) {
ast_node(ts, TypeSpec, spec);
GB_ASSERT(ts->name->kind == AstNode_Ident);
@@ -69,7 +70,7 @@ void print_proc_decl(AstNodeProcDecl *pd) {
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) {
if (proc_type->results != nullptr) {
ast_node(fl, FieldList, proc_type->results);
isize count = fl->list.count;
if (count > 0) {
@@ -87,43 +88,13 @@ void print_proc_decl(AstNodeProcDecl *pd) {
}
gb_printf("\n\n");
}
#endif
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];
AstFile *file = parser->files[file_index];
Tokenizer *tokenizer = &file->tokenizer;
String fullpath = tokenizer->fullpath;
gb_printf("%.*s\n", LIT(fullpath));
+44 -22
View File
@@ -2,7 +2,6 @@ struct Scope;
struct Checker;
struct Type;
struct DeclInfo;
// typedef enum BuiltinProcId BuiltinProcId;
#define ENTITY_KINDS \
@@ -12,6 +11,7 @@ struct DeclInfo;
ENTITY_KIND(TypeName) \
ENTITY_KIND(Procedure) \
ENTITY_KIND(Builtin) \
ENTITY_KIND(Alias) \
ENTITY_KIND(ImportName) \
ENTITY_KIND(LibraryName) \
ENTITY_KIND(Nil) \
@@ -43,22 +43,16 @@ enum EntityFlag {
EntityFlag_Value = 1<<9,
EntityFlag_Sret = 1<<10,
EntityFlag_BitFieldValue = 1<<11,
EntityFlag_PolyConst = 1<<12,
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,
Overload_Unknown = 0,
Overload_No = 1,
Overload_Yes = 2,
};
@@ -70,13 +64,15 @@ struct Entity {
Token token;
Scope * scope;
Type * type;
AstNode * identifier; // Can be NULL
DeclInfo * parent_proc_decl; // NULL if in file/global scope
AstNode * identifier; // Can be nullptr
DeclInfo * parent_proc_decl; // nullptr if in file/global scope
// TODO(bill): Cleanup how `using` works for entities
Entity * using_parent;
AstNode * using_expr;
isize order_in_src;
union {
struct {
ExactValue value;
@@ -86,20 +82,27 @@ struct Entity {
i32 field_src_index;
ExactValue default_value;
bool default_is_nil;
bool default_is_undef;
bool default_is_location;
bool is_immutable;
bool is_thread_local;
String thread_local_model;
bool is_foreign;
bool is_export;
Entity * foreign_library;
AstNode * foreign_library_ident;
String link_name;
String link_prefix;
} Variable;
struct {
bool is_type_alias;
bool is_type_alias;
Type *type_parameter_specialization;
} TypeName;
struct {
OverloadKind overload_kind;
String link_name;
String link_prefix;
u64 tags;
bool is_export;
bool is_foreign;
Entity * foreign_library;
AstNode * foreign_library_ident;
@@ -107,6 +110,9 @@ struct Entity {
struct {
i32 id;
} Builtin;
struct {
Entity *base;
} Alias;
struct {
String path;
String name;
@@ -120,13 +126,13 @@ struct Entity {
} LibraryName;
i32 Nil;
struct {
String name;
String name;
AstNode *node;
} Label;
};
};
gb_global Entity *e_context = NULL;
gb_global Entity *e_context = nullptr;
bool is_entity_kind_exported(EntityKind kind) {
switch (kind) {
@@ -141,7 +147,7 @@ bool is_entity_kind_exported(EntityKind kind) {
bool is_entity_exported(Entity *e) {
// TODO(bill): Determine the actual exportation rules for imports of entities
GB_ASSERT(e != NULL);
GB_ASSERT(e != nullptr);
if (!is_entity_kind_exported(e->kind)) {
return false;
}
@@ -153,6 +159,7 @@ bool is_entity_exported(Entity *e) {
return name[0] != '_';
}
gb_global u64 global_entity_id = 0;
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
@@ -172,7 +179,7 @@ Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *typ
}
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
GB_ASSERT(parent != NULL);
GB_ASSERT(parent != nullptr);
token.pos = parent->token.pos;
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
entity->using_parent = parent;
@@ -201,6 +208,16 @@ Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type,
return entity;
}
Entity *make_entity_const_param(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value, bool poly_const) {
Entity *entity = make_entity_constant(a, scope, token, type, value);
entity->flags |= EntityFlag_Used;
if (poly_const) entity->flags |= EntityFlag_PolyConst;
entity->flags |= EntityFlag_Param;
return entity;
}
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;
@@ -231,6 +248,12 @@ Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type
return entity;
}
Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type, Entity *base) {
Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type);
entity->Alias.base = base;
return entity;
}
Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *type,
String path, String name, Scope *import_scope) {
Entity *entity = alloc_entity(a, Entity_ImportName, scope, token, type);
@@ -253,8 +276,7 @@ Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type
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);
Entity *entity = alloc_entity(a, Entity_Nil, nullptr, make_token_ident(name), type);
return entity;
}
@@ -269,6 +291,6 @@ Entity *make_entity_label(gbAllocator a, Scope *scope, Token token, Type *type,
Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
token.string = str_lit("_");
return make_entity_variable(a, scope, token, NULL, false);
return make_entity_variable(a, scope, token, nullptr, false);
}
+81 -32
View File
@@ -5,6 +5,8 @@
struct AstNode;
struct HashKey;
struct Type;
bool are_types_identical(Type *x, Type *y);
struct Complex128 {
f64 real, imag;
@@ -20,6 +22,8 @@ enum ExactValueKind {
ExactValue_Complex,
ExactValue_Pointer,
ExactValue_Compound, // TODO(bill): Is this good enough?
ExactValue_Procedure, // TODO(bill): Is this good enough?
ExactValue_Type,
ExactValue_Count,
};
@@ -34,6 +38,8 @@ struct ExactValue {
i64 value_pointer;
Complex128 value_complex;
AstNode * value_compound;
AstNode * value_procedure;
Type * value_type;
};
};
@@ -99,6 +105,18 @@ ExactValue exact_value_pointer(i64 ptr) {
return result;
}
ExactValue exact_value_type(Type *type) {
ExactValue result = {ExactValue_Type};
result.value_type = type;
return result;
}
ExactValue exact_value_procedure(AstNode *node) {
ExactValue result = {ExactValue_Procedure};
result.value_procedure = node;
return result;
}
ExactValue exact_value_integer_from_string(String string) {
return exact_value_u128(u128_from_string(string));
@@ -228,7 +246,7 @@ ExactValue exact_value_from_basic_literal(Token token) {
case Token_Imag: {
String str = token.string;
Rune last_rune = cast(Rune)str[str.len-1];
str.len--; // Ignore the `i|j|k`
str.len--; // Ignore the 'i|j|k'
f64 imag = float_from_string(str);
if (last_rune == 'i') {
@@ -260,7 +278,8 @@ ExactValue exact_value_to_integer(ExactValue v) {
if (f == v.value_float) {
return exact_value_i128(i);
}
} break;
break;
}
case ExactValue_Pointer:
return exact_value_i64(cast(i64)cast(intptr)v.value_pointer);
@@ -325,7 +344,7 @@ ExactValue exact_value_make_imag(ExactValue v) {
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`");
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
}
ExactValue r = {ExactValue_Invalid};
return r;
@@ -342,7 +361,8 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
case ExactValue_Complex:
return v;
}
} break;
break;
}
case Token_Sub: {
switch (v.kind) {
@@ -364,7 +384,8 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
return exact_value_complex(-real, -imag);
}
}
} break;
break;
}
case Token_Xor: {
i128 i = I128_ZERO;
@@ -386,7 +407,8 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
}
return exact_value_i128(i);
} break;
break;
}
case Token_Not: {
switch (v.kind) {
@@ -394,7 +416,8 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
case ExactValue_Bool:
return exact_value_bool(!v.value_bool);
}
} break;
break;
}
}
failure:
@@ -494,24 +517,25 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
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_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;
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 << cast(u32)i128_to_u64(b); break;
case Token_Shr: c = a >> cast(u32)i128_to_u64(b); break;
default: goto error;
}
return exact_value_i128(c);
} break;
break;
}
case ExactValue_Float: {
f64 a = x.value_float;
@@ -523,7 +547,8 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
case Token_Quo: return exact_value_float(a / b);
default: goto error;
}
} break;
break;
}
case ExactValue_Complex: {
y = exact_value_to_complex(y);
@@ -550,18 +575,31 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
f64 s = c*c + d*d;
real = (a*c + b*d)/s;
imag = (b*c - a*d)/s;
} break;
break;
}
default: goto error;
}
return exact_value_complex(real, imag);
} break;
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;
case ExactValue_String: {
if (op != Token_Add) goto error;
// NOTE(bill): How do you minimize this over allocation?
String sx = x.value_string;
String sy = y.value_string;
isize len = sx.len+sy.len;
u8 *data = gb_alloc_array(heap_allocator(), u8, len);
gb_memmove(data, sx.text, sx.len);
gb_memmove(data+sx.len, sy.text, sy.len);
return exact_value_string(make_string(data, len));
break;
}
}
error:; // NOTE(bill): MSVC accepts this??? apparently you cannot declare variables immediately after labels...
return empty_exact_value;
}
gb_inline ExactValue exact_value_add(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Add, x, y); }
@@ -600,7 +638,8 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
case Token_Gt: return a > b;
case Token_GtEq: return a >= b;
}
} break;
break;
}
case ExactValue_Float: {
f64 a = x.value_float;
@@ -613,7 +652,8 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
case Token_Gt: return cmp_f64(a, b) > 0;
case Token_GtEq: return cmp_f64(a, b) >= 0;
}
} break;
break;
}
case ExactValue_Complex: {
f64 a = x.value_complex.real;
@@ -624,7 +664,8 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
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;
break;
}
case ExactValue_String: {
String a = x.value_string;
@@ -638,7 +679,15 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
case Token_Gt: return a > b;
case Token_GtEq: return a >= b;
}
} break;
break;
}
case ExactValue_Type:
switch (op) {
case Token_CmpEq: return are_types_identical(x.value_type, y.value_type);
case Token_NotEq: return !are_types_identical(x.value_type, y.value_type);
}
break;
}
GB_PANIC("Invalid comparison");
+114 -69
View File
@@ -1,4 +1,4 @@
/* gb.h - v0.28 - Ginger Bill's C Helper Library - public domain
/* gb.h - v0.31 - Ginger Bill's C Helper Library - public domain
- no warranty implied; use at your own risk
This is a single header file with a bunch of useful stuff
@@ -58,6 +58,9 @@ TODOS
- More date & time functions
VERSION HISTORY
0.31 - Add gb_file_remove
0.30 - Changes to gbThread (and gbMutex on Windows)
0.29 - Add extras for gbString
0.28 - Handle UCS2 correctly in Win32 part
0.27 - OSX fixes and Linux gbAffinity
0.26d - Minor changes to how gbFile works
@@ -927,12 +930,12 @@ GB_DEF void gb_semaphore_wait (gbSemaphore *s);
// Mutex
// TODO(bill): Should this be replaced with a CRITICAL_SECTION on win32 or is the better?
typedef struct gbMutex {
gbSemaphore semaphore;
gbAtomic32 counter;
gbAtomic32 owner;
i32 recursion;
#if defined(GB_SYSTEM_WINDOWS)
CRITICAL_SECTION win32_critical_section;
#else
pthread_mutex_t pthread_mutex;
#endif
} gbMutex;
GB_DEF void gb_mutex_init (gbMutex *m);
@@ -956,7 +959,7 @@ gb_mutex_init(&m);
#define GB_THREAD_PROC(name) void name(void *data)
#define GB_THREAD_PROC(name) isize name(struct gbThread *thread)
typedef GB_THREAD_PROC(gbThreadProc);
typedef struct gbThread {
@@ -967,7 +970,9 @@ typedef struct gbThread {
#endif
gbThreadProc *proc;
void * data;
void * user_data;
isize user_index;
isize return_value;
gbSemaphore semaphore;
isize stack_size;
@@ -975,7 +980,7 @@ typedef struct gbThread {
} gbThread;
GB_DEF void gb_thread_init (gbThread *t);
GB_DEF void gb_thread_destory (gbThread *t);
GB_DEF void gb_thread_destroy (gbThread *t);
GB_DEF void gb_thread_start (gbThread *t, gbThreadProc *proc, void *data);
GB_DEF void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size);
GB_DEF void gb_thread_join (gbThread *t);
@@ -1521,6 +1526,8 @@ GB_DEF void gb_string_clear (gbString str);
GB_DEF gbString gb_string_append (gbString str, gbString const other);
GB_DEF gbString gb_string_append_length (gbString str, void const *other, isize num_bytes);
GB_DEF gbString gb_string_appendc (gbString str, char const *other);
GB_DEF gbString gb_string_append_rune (gbString str, Rune r);
GB_DEF gbString gb_string_append_fmt (gbString str, char const *fmt, ...);
GB_DEF gbString gb_string_set (gbString str, char const *cstr);
GB_DEF gbString gb_string_make_space_for (gbString str, isize add_len);
GB_DEF isize gb_string_allocation_size(gbString const str);
@@ -2044,6 +2051,7 @@ GB_DEF b32 gb_file_exists (char const *filepath);
GB_DEF gbFileTime gb_file_last_write_time(char const *filepath);
GB_DEF b32 gb_file_copy (char const *existing_filename, char const *new_filename, b32 fail_if_exists);
GB_DEF b32 gb_file_move (char const *existing_filename, char const *new_filename);
GB_DEF b32 gb_file_remove (char const *filename);
#ifndef GB_PATH_SEPARATOR
@@ -4590,59 +4598,44 @@ gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); }
#error
#endif
// NOTE(bill): THIS IS FUCKING AWESOME THAT THIS "MUTEX" IS FAST AND RECURSIVE TOO!
// NOTE(bill): WHO THE FUCK NEEDS A NORMAL MUTEX NOW?!?!?!?!
gb_inline void gb_mutex_init(gbMutex *m) {
gb_atomic32_store(&m->counter, 0);
gb_atomic32_store(&m->owner, gb_thread_current_id());
gb_semaphore_init(&m->semaphore);
m->recursion = 0;
#if defined(GB_SYSTEM_WINDOWS)
InitializeCriticalSection(&m->win32_critical_section);
#else
pthread_mutex_init(&m->pthread_mutex, NULL);
#endif
}
gb_inline void gb_mutex_destroy(gbMutex *m) { gb_semaphore_destroy(&m->semaphore); }
gb_inline void gb_mutex_destroy(gbMutex *m) {
#if defined(GB_SYSTEM_WINDOWS)
DeleteCriticalSection(&m->win32_critical_section);
#else
pthread_mutex_destroy(&m->pthread_mutex);
#endif
}
gb_inline void gb_mutex_lock(gbMutex *m) {
i32 thread_id = cast(i32)gb_thread_current_id();
if (gb_atomic32_fetch_add(&m->counter, 1) > 0) {
if (thread_id != gb_atomic32_load(&m->owner))
gb_semaphore_wait(&m->semaphore);
}
gb_atomic32_store(&m->owner, thread_id);
m->recursion++;
#if defined(GB_SYSTEM_WINDOWS)
EnterCriticalSection(&m->win32_critical_section);
#else
pthread_mutex_lock(&m->pthread_mutex);
#endif
}
gb_inline b32 gb_mutex_try_lock(gbMutex *m) {
i32 thread_id = cast(i32)gb_thread_current_id();
if (gb_atomic32_load(&m->owner) == thread_id) {
gb_atomic32_fetch_add(&m->counter, 1);
} else {
i32 expected = 0;
if (gb_atomic32_load(&m->counter) != 0)
return false;
if (!gb_atomic32_compare_exchange(&m->counter, expected, 1))
return false;
gb_atomic32_store(&m->owner, thread_id);
}
m->recursion++;
return true;
#if defined(GB_SYSTEM_WINDOWS)
return TryEnterCriticalSection(&m->win32_critical_section) != 0;
#else
return pthread_mutex_trylock(&m->pthread_mutex) == 0;
#endif
}
gb_inline void gb_mutex_unlock(gbMutex *m) {
i32 recursion;
i32 thread_id = cast(i32)gb_thread_current_id();
GB_ASSERT(thread_id == gb_atomic32_load(&m->owner));
recursion = --m->recursion;
if (recursion == 0)
gb_atomic32_store(&m->owner, thread_id);
if (gb_atomic32_fetch_add(&m->counter, -1) > 1) {
if (recursion == 0)
gb_semaphore_release(&m->semaphore);
}
#if defined(GB_SYSTEM_WINDOWS)
LeaveCriticalSection(&m->win32_critical_section);
#else
pthread_mutex_unlock(&m->pthread_mutex);
#endif
}
@@ -4661,7 +4654,7 @@ void gb_thread_init(gbThread *t) {
gb_semaphore_init(&t->semaphore);
}
void gb_thread_destory(gbThread *t) {
void gb_thread_destroy(gbThread *t) {
if (t->is_running) gb_thread_join(t);
gb_semaphore_destroy(&t->semaphore);
}
@@ -4669,22 +4662,32 @@ void gb_thread_destory(gbThread *t) {
gb_inline void gb__thread_run(gbThread *t) {
gb_semaphore_release(&t->semaphore);
t->proc(t->data);
t->return_value = t->proc(t);
}
#if defined(GB_SYSTEM_WINDOWS)
gb_inline DWORD __stdcall gb__thread_proc(void *arg) { gb__thread_run(cast(gbThread *)arg); return 0; }
gb_inline DWORD __stdcall gb__thread_proc(void *arg) {
gbThread *t = cast(gbThread *)arg;
gb__thread_run(t);
t->is_running = false;
return 0;
}
#else
gb_inline void * gb__thread_proc(void *arg) { gb__thread_run(cast(gbThread *)arg); return NULL; }
gb_inline void * gb__thread_proc(void *arg) {
gbThread *t = cast(gbThread *)arg;
gb__thread_run(t);
t->is_running = false;
return NULL;
}
#endif
gb_inline void gb_thread_start(gbThread *t, gbThreadProc *proc, void *data) { gb_thread_start_with_stack(t, proc, data, 0); }
gb_inline void gb_thread_start(gbThread *t, gbThreadProc *proc, void *user_data) { gb_thread_start_with_stack(t, proc, user_data, 0); }
gb_inline void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size) {
gb_inline void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *user_data, isize stack_size) {
GB_ASSERT(!t->is_running);
GB_ASSERT(proc != NULL);
t->proc = proc;
t->data = data;
t->user_data = user_data;
t->stack_size = stack_size;
#if defined(GB_SYSTEM_WINDOWS)
@@ -4695,8 +4698,9 @@ gb_inline void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (stack_size != 0)
if (stack_size != 0) {
pthread_attr_setstacksize(&attr, stack_size);
}
pthread_create(&t->posix_handle, &attr, gb__thread_proc, t);
pthread_attr_destroy(&attr);
}
@@ -5398,7 +5402,8 @@ gb_inline gbTempArenaMemory gb_temp_arena_memory_begin(gbArena *arena) {
}
gb_inline void gb_temp_arena_memory_end(gbTempArenaMemory tmp) {
GB_ASSERT(tmp.arena->total_allocated >= tmp.original_count);
GB_ASSERT_MSG(tmp.arena->total_allocated >= tmp.original_count,
"%td >= %td", tmp.arena->total_allocated, tmp.original_count);
GB_ASSERT(tmp.arena->temp_count > 0);
tmp.arena->total_allocated = tmp.original_count;
tmp.arena->temp_count--;
@@ -6573,6 +6578,26 @@ gb_inline gbString gb_string_appendc(gbString str, char const *other) {
return gb_string_append_length(str, other, gb_strlen(other));
}
gbString gb_string_append_rune(gbString str, Rune r) {
if (r >= 0) {
u8 buf[8] = {0};
isize len = gb_utf8_encode_rune(buf, r);
return gb_string_append_length(str, buf, len);
}
return str;
}
gbString gb_string_append_fmt(gbString str, char const *fmt, ...) {
isize res;
char buf[4096] = {0};
va_list va;
va_start(va, fmt);
res = gb_snprintf_va(str, gb_count_of(buf)-1, fmt, va);
va_end(va);
return gb_string_append_length(str, buf, res);
}
gbString gb_string_set(gbString str, char const *cstr) {
isize len = gb_strlen(cstr);
@@ -7403,13 +7428,13 @@ u64 gb_murmur64_seed(void const *data_, isize len, u64 seed) {
if (w_len_) *w_len_ = w_len;
return NULL;
}
w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, len, NULL, 0);
w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int)len, NULL, 0);
if (w_len == 0) {
if (w_len_) *w_len_ = w_len;
return NULL;
}
w_text = gb_alloc_array(a, wchar_t, w_len+1);
w_len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, len, w_text, w_len);
w_len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int)len, w_text, cast(int)w_len);
if (w_len1 == 0) {
gb_free(a, w_text);
if (w_len_) *w_len_ = 0;
@@ -7908,6 +7933,19 @@ gb_inline b32 gb_file_move(char const *existing_filename, char const *new_filena
return result;
}
b32 gb_file_remove(char const *filename) {
wchar_t *w_filename = NULL;
gbAllocator a = gb_heap_allocator();
b32 result = false;
w_filename = gb__alloc_utf8_to_ucs2(a, filename, NULL);
if (w_filename == NULL) {
return false;
}
result = DeleteFileW(w_filename);
gb_free(a, w_filename);
return result;
}
#else
@@ -7916,7 +7954,7 @@ gbFileTime gb_file_last_write_time(char const *filepath) {
time_t result = 0;
struct stat file_stat;
if (stat(filepath, &file_stat)) {
if (stat(filepath, &file_stat) == 0) {
result = file_stat.st_mtime;
}
@@ -7946,13 +7984,20 @@ gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filena
gb_inline b32 gb_file_move(char const *existing_filename, char const *new_filename) {
if (link(existing_filename, new_filename) == 0) {
if (unlink(existing_filename) != -1) {
return true;
}
return unlink(existing_filename) != -1;
}
return false;
}
b32 gb_file_remove(char const *filename) {
#if defined(GB_SYSTEM_OSX)
return unlink(filename) != -1;
#else
return remove(filename) == 0;
#endif
}
#endif
@@ -8057,17 +8102,17 @@ char *gb_path_get_full_name(gbAllocator a, char const *path) {
return NULL;
}
w_fullpath = gb_alloc_array(gb_heap_allocator(), wchar_t, w_len+1);
GetFullPathNameW(w_path, w_len, w_fullpath, NULL);
GetFullPathNameW(w_path, cast(int)w_len, w_fullpath, NULL);
w_fullpath[w_len] = 0;
gb_free(gb_heap_allocator(), w_path);
new_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, w_len, NULL, 0, NULL, NULL);
new_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int)w_len, NULL, 0, NULL, NULL);
if (new_len == 0) {
gb_free(gb_heap_allocator(), w_fullpath);
return NULL;
}
new_path = gb_alloc_array(a, char, new_len+1);
new_len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, w_len, new_path, new_len, NULL, NULL);
new_len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int)w_len, new_path, cast(int)new_len, NULL, NULL);
if (new_len1 == 0) {
gb_free(gb_heap_allocator(), w_fullpath);
gb_free(a, new_path);
+119 -106
View File
@@ -95,48 +95,48 @@ 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); }
bool operator==(u128 const &a, u128 const &b) { return u128_eq(a, b); }
bool operator!=(u128 const &a, u128 const &b) { return u128_ne(a, b); }
bool operator< (u128 const &a, u128 const &b) { return u128_lt(a, b); }
bool operator> (u128 const &a, u128 const &b) { return u128_gt(a, b); }
bool operator<=(u128 const &a, u128 const &b) { return u128_le(a, b); }
bool operator>=(u128 const &a, u128 const &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); }
u128 operator+ (u128 const &a, u128 const &b) { return u128_add(a, b); }
u128 operator- (u128 const &a, u128 const &b) { return u128_sub(a, b); }
u128 operator* (u128 const &a, u128 const &b) { return u128_mul(a, b); }
u128 operator/ (u128 const &a, u128 const &b) { return u128_quo(a, b); }
u128 operator% (u128 const &a, u128 const &b) { return u128_mod(a, b); }
u128 operator& (u128 const &a, u128 const &b) { return u128_and(a, b); }
u128 operator| (u128 const &a, u128 const &b) { return u128_or (a, b); }
u128 operator^ (u128 const &a, u128 const &b) { return u128_xor(a, b); }
u128 operator~ (u128 const &a) { return u128_not(a); }
u128 operator+ (u128 const &a) { return a; }
u128 operator- (u128 const &a) { return u128_neg(a); }
u128 operator<<(u128 const &a, u32 const &b) { return u128_shl(a, b); }
u128 operator>>(u128 const &a, u32 const &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); }
bool operator==(i128 const &a, i128 const &b) { return i128_eq(a, b); }
bool operator!=(i128 const &a, i128 const &b) { return i128_ne(a, b); }
bool operator< (i128 const &a, i128 const &b) { return i128_lt(a, b); }
bool operator> (i128 const &a, i128 const &b) { return i128_gt(a, b); }
bool operator<=(i128 const &a, i128 const &b) { return i128_le(a, b); }
bool operator>=(i128 const &a, i128 const &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); }
i128 operator+ (i128 const &a, i128 const &b) { return i128_add(a, b); }
i128 operator- (i128 const &a, i128 const &b) { return i128_sub(a, b); }
i128 operator* (i128 const &a, i128 const &b) { return i128_mul(a, b); }
i128 operator/ (i128 const &a, i128 const &b) { return i128_quo(a, b); }
i128 operator% (i128 const &a, i128 const &b) { return i128_mod(a, b); }
i128 operator& (i128 const &a, i128 const &b) { return i128_and(a, b); }
i128 operator| (i128 const &a, i128 const &b) { return i128_or (a, b); }
i128 operator^ (i128 const &a, i128 const &b) { return i128_xor(a, b); }
i128 operator~ (i128 const &a) { return i128_not(a); }
i128 operator+ (i128 const &a) { return a; }
i128 operator- (i128 const &a) { return i128_neg(a); }
i128 operator<<(i128 const &a, u32 b) { return i128_shl(a, b); }
i128 operator>>(i128 const &a, u32 b) { return i128_shr(a, b); }
////////////////////////////////////////////////////////////////
@@ -482,36 +482,37 @@ u128 u128_mul(u128 a, u128 b) {
return res;
}
bool u128_hibit(u128 *d) { return (d->hi & BIT128_U64_HIGHBIT) != 0; }
bool u128_hibit(u128 const &d) { return (d.hi & BIT128_U64_HIGHBIT) != 0; }
bool i128_hibit(i128 const &d) { return d.hi < 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);
void u128_divide(u128 a, u128 b, u128 *quo, u128 *rem) {
if (u128_eq(b, U128_ZERO)) {
if (quo) *quo = u128_from_u64(a.lo/b.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;
return;
}
u128 r = a;
u128 d = b;
u128 x = U128_ONE;
u128 q = U128_ZERO;
while (u128_ge(r, d) && !u128_hibit(d)) {
x = u128_shl(x, 1);
d = u128_shl(d, 1);
}
while (u128_ne(x, U128_ZERO)) {
if (u128_ge(r, d)) {
r = u128_sub(r, d);
q = u128_or(q, x);
}
x = u128_shr(x, 1);
d = u128_shr(d, 1);
}
if (quo) *quo = q;
if (rem) *rem = r;
}
u128 u128_quo(u128 a, u128 b) {
@@ -520,7 +521,7 @@ u128 u128_quo(u128 a, u128 b) {
}
u128 res = {0};
u128_divide(a, b, &res, NULL);
u128_divide(a, b, &res, nullptr);
return res;
}
u128 u128_mod(u128 a, u128 b) {
@@ -528,7 +529,7 @@ u128 u128_mod(u128 a, u128 b) {
return u128_from_u64(a.lo%b.lo);
}
u128 res = {0};
u128_divide(a, b, NULL, &res);
u128_divide(a, b, nullptr, &res);
return res;
}
@@ -668,59 +669,71 @@ i128 i128_mul(i128 a, i128 b) {
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;
void i128_divide(i128 a, i128 b, i128 *quo_, i128 *rem_) {
// TODO(bill): Optimize this i128 division calculation
i128 iquo = {0};
i128 irem = {0};
if (a.hi == 0 && b.hi == 0) {
u64 q = a.lo / b.lo;
u64 r = a.lo % b.lo;
iquo = i128_from_u64(q);
irem = i128_from_u64(r);
} else if ((~a.hi) == 0 && (~b.hi) == 0) {
i64 x = i128_to_i64(a);
i64 y = i128_to_i64(b);
i64 q = x / y;
i64 r = x % y;
iquo = i128_from_i64(q);
irem = i128_from_i64(r);
} else if (a.hi > 0 || b.hi > 0) {
u128 q, r = {0};
u128_divide(*cast(u128 *)&a, *cast(u128 *)&b, &q, &r);
iquo = *cast(i128 *)&q;
irem = *cast(i128 *)&r;
} else if (i128_eq(b, I128_ZERO)) {
iquo = i128_from_u64(a.lo/b.lo);
} 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);
i32 rem_sign = 1;
i32 quo_sign = 1;
if (i128_lt(a, I128_ZERO)) {
a = i128_neg(a);
rem_sign = -1;
}
if (i128_lt(b, I128_ZERO)) {
b = i128_neg(b);
quo_sign = -1;
}
quo_sign *= rem_sign;
while (i128_ne(x, I128_ZERO)) {
if (i128_ge(n, d)) {
n = i128_sub(n, d);
r = i128_or(r, x);
iquo = a;
for (isize i = 0; i < 128; i++) {
irem = i128_shl(irem, 1);
if (i128_lt(iquo, I128_ZERO)) {
irem.lo |= 1;
}
iquo = i128_shl(iquo, 1);
if (i128_ge(irem, b)) {
irem = i128_sub(irem, b);
iquo = i128_add(iquo, I128_ONE);
}
x = i128_shr(x, 1);
d = i128_shr(d, 1);
}
if (quo) *quo = r;
if (rem) *rem = n;
if (quo_sign < 0) iquo = i128_neg(iquo);
if (rem_sign < 0) irem = i128_neg(irem);
}
#endif
if (quo_) *quo_ = iquo;
if (rem_) *rem_ = irem;
}
i128 i128_quo(i128 a, i128 b) {
i128 res = {0};
i128_divide(a, b, &res, NULL);
i128_divide(a, b, &res, nullptr);
return res;
}
i128 i128_mod(i128 a, i128 b) {
i128 res = {0};
i128_divide(a, b, NULL, &res);
i128_divide(a, b, nullptr, &res);
return res;
}
+2403 -1839
View File
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -39,7 +39,7 @@ void ir_opt_add_operands(Array<irValue *> *ops, irInstr *i) {
array_add(ops, i->If.cond);
break;
case irInstr_Return:
if (i->Return.value != NULL) {
if (i->Return.value != nullptr) {
array_add(ops, i->Return.value);
}
break;
@@ -168,11 +168,11 @@ void ir_remove_dead_blocks(irProcedure *proc) {
isize j = 0;
for_array(i, proc->blocks) {
irBlock *b = proc->blocks[i];
if (b == NULL) {
if (b == nullptr) {
continue;
}
// NOTE(bill): Swap order
b->index = j;
b->index = cast(i32)j;
proc->blocks[j++] = b;
}
proc->blocks.count = j;
@@ -210,7 +210,7 @@ void ir_remove_unreachable_blocks(irProcedure *proc) {
}
// NOTE(bill): Mark as empty but don't actually free it
// As it's been allocated with an arena
proc->blocks[i] = NULL;
proc->blocks[i] = nullptr;
}
}
ir_remove_dead_blocks(proc);
@@ -245,7 +245,7 @@ bool ir_opt_block_fusion(irProcedure *proc, irBlock *a) {
ir_opt_block_replace_pred(b->succs[i], b, a);
}
proc->blocks[b->index] = NULL;
proc->blocks[b->index] = nullptr;
return true;
}
@@ -258,7 +258,7 @@ void ir_opt_blocks(irProcedure *proc) {
changed = false;
for_array(i, proc->blocks) {
irBlock *b = proc->blocks[i];
if (b == NULL) {
if (b == nullptr) {
continue;
}
GB_ASSERT_MSG(b->index == i, "%d, %td", b->index, i);
@@ -286,11 +286,11 @@ void ir_opt_build_referrers(irProcedure *proc) {
ir_opt_add_operands(&ops, &instr->Instr);
for_array(k, ops) {
irValue *op = ops[k];
if (op == NULL) {
if (op == nullptr) {
continue;
}
Array<irValue *> *refs = ir_value_referrers(op);
if (refs != NULL) {
if (refs != nullptr) {
array_add(refs, instr);
}
}
@@ -325,10 +325,10 @@ i32 ir_lt_depth_first_search(irLTState *lt, irBlock *p, i32 i, irBlock **preorde
preorder[i] = p;
p->dom.pre = i++;
lt->sdom[p->index] = p;
ir_lt_link(lt, NULL, p);
ir_lt_link(lt, nullptr, p);
for_array(index, p->succs) {
irBlock *q = p->succs[index];
if (lt->sdom[q->index] == NULL) {
if (lt->sdom[q->index] == nullptr) {
lt->parent[q->index] = p;
i = ir_lt_depth_first_search(lt, q, i, preorder);
}
@@ -339,7 +339,7 @@ i32 ir_lt_depth_first_search(irLTState *lt, irBlock *p, i32 i, irBlock **preorde
irBlock *ir_lt_eval(irLTState *lt, irBlock *v) {
irBlock *u = v;
for (;
lt->ancestor[v->index] != NULL;
lt->ancestor[v->index] != nullptr;
v = lt->ancestor[v->index]) {
if (lt->sdom[v->index]->dom.pre < lt->sdom[u->index]->dom.pre) {
u = v;
@@ -373,7 +373,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
isize n = proc->blocks.count;
i32 n = cast(i32)proc->blocks.count;
irBlock **buf = gb_alloc_array(proc->module->tmp_allocator, irBlock *, 5*n);
irLTState lt = {0};
@@ -432,7 +432,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
for (isize i = 1; i < n; i++) {
irBlock *w = preorder[i];
if (w == root) {
w->dom.idom = NULL;
w->dom.idom = nullptr;
} else {
// Weird tree relationships here!
@@ -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.data == NULL) {
if (w->dom.idom->dom.children.data == nullptr) {
// TODO(bill): Is this good enough for memory allocations?
array_init(&w->dom.idom->dom.children, heap_allocator());
}
+752 -563
View File
File diff suppressed because it is too large Load Diff
+399 -123
View File
@@ -1,5 +1,10 @@
#define ALLOW_ARRAY_PROGRAMMING
#define USE_CUSTOM_BACKEND 0
// #define PRINT_TIMINGS
// #define NO_ARRAY_BOUNDS_CHECK
#if !defined(USE_THREADED_PARSER)
#define USE_THREADED_PARSER 0
#endif
#include "common.cpp"
#include "timings.cpp"
@@ -14,7 +19,7 @@
#include "ir_print.cpp"
#if defined(GB_SYSTEM_WINDOWS)
// NOTE(bill): `name` is used in debugging and profiling modes
// 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};
@@ -41,8 +46,8 @@ i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
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,
if (CreateProcessW(nullptr, cmd.text,
nullptr, nullptr, true, 0, nullptr, nullptr,
&start_info, &pi)) {
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code);
@@ -166,11 +171,45 @@ void usage(String argv0) {
}
bool string_is_valid_identifier(String str) {
if (str.len <= 0) return false;
isize rune_count = 0;
isize w = 0;
isize offset = 0;
while (offset < str.len) {
Rune r = 0;
w = gb_utf8_decode(str.text, str.len, &r);
if (r == GB_RUNE_INVALID) {
return false;
}
if (rune_count == 0) {
if (!rune_is_letter(r)) {
return false;
}
} else {
if (!rune_is_letter(r) && !rune_is_digit(r)) {
return false;
}
}
rune_count += 1;
offset += w;
}
return true;
}
enum BuildFlagKind {
BuildFlag_Invalid,
BuildFlag_OptimizationLevel,
BuildFlag_ShowTimings,
BuildFlag_ThreadCount,
BuildFlag_KeepTempFiles,
BuildFlag_Collection,
BuildFlag_BuildMode,
BuildFlag_COUNT,
};
@@ -192,7 +231,6 @@ struct BuildFlag {
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);
@@ -201,7 +239,13 @@ void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, Bu
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);
add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer);
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String);
Array<String> flag_args = args;
flag_args.data += 3;
@@ -214,105 +258,244 @@ bool parse_build_flags(Array<String> 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);
continue;
}
String name = substring(flag, 1, flag.len);
isize end = 0;
for (; end < name.len; end++) {
if (name[end] == '=') break;
}
name = substring(name, 0, end);
String param = {};
if (end < flag.len-1) 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));
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 {
ExactValue value = {};
bool ok = false;
if (bf.param_kind == BuildFlagParam_None) {
if (param.len == 0) {
ok = true;
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 == "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 == "False") {
value = exact_value_bool(false);
} else if (param == "0") {
value = exact_value_bool(false);
} else {
gb_printf_err("Flag `%.*s` was not expecting a parameter `%.*s`\n", LIT(name), LIT(param));
bad_flags = true;
gb_printf_err("Invalid flag parameter for '%.*s' = '%.*s'\n", LIT(name), LIT(param));
}
} 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;
}
}
} 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;
}
if (ok) {
switch (bf.param_kind) {
case BuildFlagParam_None:
if (value.kind != ExactValue_Invalid) {
gb_printf_err("%.*s expected no value, got %.*s", LIT(name), LIT(param));
bad_flags = true;
ok = false;
}
break;
case BuildFlagParam_Boolean:
if (value.kind != ExactValue_Bool) {
gb_printf_err("%.*s expected a boolean, got %.*s", LIT(name), LIT(param));
bad_flags = true;
ok = false;
}
break;
case BuildFlagParam_Integer:
if (value.kind != ExactValue_Integer) {
gb_printf_err("%.*s expected an integer, got %.*s", LIT(name), LIT(param));
bad_flags = true;
ok = false;
}
break;
case BuildFlagParam_Float:
if (value.kind != ExactValue_Float) {
gb_printf_err("%.*s expected a floating pointer number, got %.*s", LIT(name), LIT(param));
bad_flags = true;
ok = false;
}
break;
case BuildFlagParam_String:
if (value.kind != ExactValue_String) {
gb_printf_err("%.*s expected a string, got %.*s", LIT(name), LIT(param));
bad_flags = true;
ok = false;
}
break;
}
if (ok) switch (bf.kind) {
case BuildFlag_OptimizationLevel:
GB_ASSERT(value.kind == ExactValue_Integer);
build_context.optimization_level = cast(i32)i128_to_i64(value.value_integer);
break;
case BuildFlag_ShowTimings:
GB_ASSERT(value.kind == ExactValue_Invalid);
build_context.show_timings = true;
break;
case BuildFlag_ThreadCount: {
GB_ASSERT(value.kind == ExactValue_Integer);
isize count = cast(isize)i128_to_i64(value.value_integer);
if (count <= 0) {
gb_printf_err("%.*s expected a positive non-zero number, got %.*s", LIT(name), LIT(param));
build_context.thread_count = 0;
} else {
build_context.thread_count = count;
}
break;
}
case BuildFlag_KeepTempFiles:
GB_ASSERT(value.kind == ExactValue_Invalid);
build_context.keep_temp_files = true;
break;
case BuildFlag_Collection: {
GB_ASSERT(value.kind == ExactValue_String);
String str = value.value_string;
isize eq_pos = -1;
for (isize i = 0; i < str.len; i++) {
if (str[i] == '=') {
eq_pos = i;
break;
}
}
if (eq_pos < 0) {
gb_printf_err("Expected 'name=path', got '%.*s'\n", LIT(param));
bad_flags = true;
break;
}
String name = substring(str, 0, eq_pos);
String path = substring(str, eq_pos+1, str.len);
if (name.len == 0 || path.len == 0) {
gb_printf_err("Expected 'name=path', got '%.*s'\n", LIT(param));
bad_flags = true;
break;
}
if (!string_is_valid_identifier(name)) {
gb_printf_err("Library collection name '%.*s' must be a valid identifier\n", LIT(name));
bad_flags = true;
break;
}
if (name == "_") {
gb_printf_err("Library collection name cannot be an underscore\n");
bad_flags = true;
break;
}
if (name == "system") {
gb_printf_err("Library collection name 'system' is reserved\n");
bad_flags = true;
break;
}
String prev_path = {};
bool found = find_library_collection_path(name, &prev_path);
if (found) {
gb_printf_err("Library collection '%.*s' already exists with path '%.*s'\n", LIT(name), LIT(prev_path));
bad_flags = true;
break;
}
gbAllocator a = heap_allocator();
String fullpath = path_to_fullpath(a, path);
if (!path_is_directory(fullpath)) {
gb_printf_err("Library collection '%.*s' path must be a directory, got '%.*s'\n", LIT(name), LIT(fullpath));
gb_free(a, fullpath.text);
bad_flags = true;
break;
}
add_library_collection(name, path);
// NOTE(bill): Allow for multiple library collections
continue;
}
case BuildFlag_BuildMode: {
GB_ASSERT(value.kind == ExactValue_String);
String str = value.value_string;
set_flags[bf.kind] = ok;
if (build_context.command != "build") {
gb_printf_err("'build-mode' can only be used with the 'build' command\n");
bad_flags = true;
break;
}
if (str == "dll") {
build_context.is_dll = true;
} else if (str == "exe") {
build_context.is_dll = false;
} else {
gb_printf_err("Unknown build mode '%.*s'\n", LIT(str));
bad_flags = true;
break;
}
break;
}
}
}
break;
set_flags[bf.kind] = ok;
}
break;
}
if (!found) {
gb_printf_err("Unknown flag: `%.*s`\n", LIT(name));
bad_flags = true;
}
}
if (!found) {
gb_printf_err("Unknown flag: '%.*s'\n", LIT(name));
bad_flags = true;
}
}
@@ -320,7 +503,64 @@ bool parse_build_flags(Array<String> args) {
}
void show_timings(Checker *c, Timings *t) {
Parser *p = c->parser;
isize lines = p->total_line_count;
isize tokens = p->total_token_count;
isize files = p->files.count;
{
timings_print_all(t);
gb_printf("\n");
gb_printf("Total Lines - %td\n", lines);
gb_printf("Total Tokens - %td\n", tokens);
gb_printf("Total Files - %td\n", files);
gb_printf("\n");
}
{
TimeStamp ts = t->sections[0];
GB_ASSERT(ts.label == "parse files");
f64 parse_time = time_stamp_as_second(ts, t->freq);
gb_printf("Parse pass\n");
gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time);
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
gb_printf("\n");
}
{
f64 total_time = t->total_time_seconds;
gb_printf("Total pass\n");
gb_printf("LOC/s - %.3f\n", cast(f64)lines/total_time);
gb_printf("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines);
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/total_time);
gb_printf("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens);
gb_printf("\n");
}
}
void remove_temp_files(String output_base) {
if (build_context.keep_temp_files) return;
Array<u8> data = {};
array_init_count(&data, heap_allocator(), output_base.len + 10);
defer (array_free(&data));
isize n = output_base.len;
gb_memcopy(data.data, output_base.text, n);
#define EXT_REMOVE(s) do { \
gb_memcopy(data.data+n, s, gb_size_of(s)); \
gb_file_remove(cast(char *)data.data); \
} while (0)
EXT_REMOVE(".ll");
EXT_REMOVE(".bc");
#if defined(GB_SYSTEM_WINDOWS)
EXT_REMOVE(".obj");
#else
EXT_REMOVE(".o");
#endif
#undef EXT_REMOVE
}
int main(int arg_count, char **arg_ptr) {
if (arg_count < 2) {
@@ -335,34 +575,32 @@ int main(int arg_count, char **arg_ptr) {
init_scratch_memory(gb_megabytes(10));
init_global_error_collector();
Array<String> args = setup_args(arg_count, arg_ptr);
array_init(&library_collections, heap_allocator());
// NOTE(bill): 'core' cannot be (re)defined by the user
add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core")));
Array<String> args = setup_args(arg_count, arg_ptr);
#if 1
String command = args[1];
String init_filename = {};
bool run_output = false;
if (args[1] == "run") {
if (command == "run") {
if (args.count < 3) {
usage(args[0]);
return 1;
}
init_filename = args[2];
run_output = true;
} else if (args[1] == "build_dll") {
} else if (command == "build") {
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") {
} else if (command == "docs") {
if (args.count < 3) {
usage(args[0]);
return 1;
@@ -374,19 +612,29 @@ int main(int arg_count, char **arg_ptr) {
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));
} else if (command == "version") {
gb_printf("%.*s version %.*s\n", LIT(args[0]), LIT(ODIN_VERSION));
return 0;
} else {
usage(args[0]);
return 1;
}
build_context.command = command;
if (!parse_build_flags(args)) {
return 1;
}
// NOTE(bill): add 'shared' directory if it is not already set
if (!find_library_collection_path(str_lit("shared"), nullptr)) {
add_library_collection(str_lit("shared"),
get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("shared")));
}
init_build_context();
if (build_context.word_size == 4) {
print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
@@ -460,7 +708,6 @@ int main(int arg_count, char **arg_ptr) {
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);
@@ -491,7 +738,7 @@ int main(int arg_count, char **arg_ptr) {
#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`
// make sure to also change the 'macosx_version_min' param passed to 'llc'
"-mtriple=x86_64-apple-macosx10.8 "
#endif
"",
@@ -541,7 +788,7 @@ int main(int arg_count, char **arg_ptr) {
}
exit_code = system_exec_command_line_app("msvc-link", true,
"link \"%.*s\".obj -OUT:\"%.*s.%s\" %s "
"link \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
"/defaultlib:libcmt "
// "/nodefaultlib "
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
@@ -556,10 +803,11 @@ int main(int arg_count, char **arg_ptr) {
return exit_code;
}
#if defined(PRINT_TIMINGS)
timings_print_all(&timings);
#endif
if (build_context.show_timings) {
show_timings(&checker, &timings);
}
remove_temp_files(output_base);
if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s.exe", LIT(output_base));
@@ -584,9 +832,15 @@ int main(int arg_count, char **arg_ptr) {
return exit_code;
}
timings_start_section(&timings, str_lit("ld-link"));
// NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe
char cwd[256];
getcwd(&cwd[0], 256);
//printf("%s\n", cwd);
// NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library
// files can be passed with -l:
gbString lib_str = gb_string_make(heap_allocator(), "-L/");
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) {
@@ -598,15 +852,36 @@ int main(int arg_count, char **arg_ptr) {
#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);
// framework thingie
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
} else if (string_has_extension(lib, str_lit("a"))) {
// static libs, absolute full path relative to the file in which the lib was imported from
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " %.*s ", LIT(lib));
} else if (string_has_extension(lib, str_lit("dylib"))) {
// dynamic lib, relative path to executable
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%s/%.*s ", cwd, LIT(lib));
} else {
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" -l%.*s ", LIT(lib));
// dynamic or static system lib, just link regularly searching system library paths
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));
// NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path,
// since those are statically linked to at link time. shared libraries (.so) has to be
// available at runtime wherever the executable is run, so we make require those to be
// local to the executable (unless the system collection is used, in which case we search
// the system library paths for the library file).
if (string_has_extension(lib, str_lit("a"))) {
// static libs, absolute full path relative to the file in which the lib was imported from
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%.*s ", LIT(lib));
} else if (string_has_extension(lib, str_lit("so"))) {
// dynamic lib, relative path to executable
// NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible
// at runtimeto the executable
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%s/%.*s ", cwd, LIT(lib));
} else {
// dynamic or static system lib, just link regularly searching system library paths
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);
}
@@ -618,7 +893,6 @@ int main(int arg_count, char **arg_ptr) {
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
@@ -642,14 +916,14 @@ int main(int arg_count, char **arg_ptr) {
#endif
exit_code = system_exec_command_line_app("ld-link", true,
"%s \"%.*s\".o -o \"%.*s%s\" %s "
"%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`
// 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 "
@@ -662,9 +936,11 @@ int main(int arg_count, char **arg_ptr) {
return exit_code;
}
#if defined(PRINT_TIMINGS)
timings_print_all(&timings);
#endif
if (build_context.show_timings) {
show_timings(&checker, &timings);
}
remove_temp_files(output_base);
if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base));
+8 -15
View File
@@ -101,8 +101,7 @@ struct Map {
};
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_init (Map<T> *h, gbAllocator a, isize capacity = 16);
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);
@@ -123,13 +122,7 @@ 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) {
gb_inline void map_init(Map<T> *h, gbAllocator a, isize capacity) {
array_init(&h->hashes, a, capacity);
array_init(&h->entries, a, capacity);
}
@@ -234,7 +227,7 @@ gb_inline T *map_get(Map<T> *h, HashKey key) {
if (index >= 0) {
return &h->entries[index].value;
}
return NULL;
return nullptr;
}
template <typename T>
@@ -303,7 +296,7 @@ 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 nullptr;
}
return &h->entries[i];
}
@@ -317,14 +310,14 @@ MapEntry<T> *multi_map_find_next(Map<T> *h, MapEntry<T> *e) {
}
i = h->entries[i].next;
}
return NULL;
return nullptr;
}
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) {
while (e != nullptr) {
count++;
e = multi_map_find_next(h, e);
}
@@ -335,7 +328,7 @@ 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) {
while (e != nullptr) {
items[i++] = e->value;
e = multi_map_find_next(h, e);
}
@@ -374,7 +367,7 @@ 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) {
while (map_get(h, key) != NULL) {
while (map_get(h, key) != nullptr) {
map_remove(h, key);
}
}
+1798 -1372
View File
File diff suppressed because it is too large Load Diff
-221
View File
@@ -1,221 +0,0 @@
gb_inline void print_indent(isize indent) {
while (indent --> 0)
gb_printf(" ");
}
void print_ast(AstNode *node, isize indent) {
if (node == NULL)
return;
switch (node->kind) {
case AstNode_BasicLit:
print_indent(indent);
print_token(node->BasicLit);
break;
case AstNode_Ident:
print_indent(indent);
print_token(node->Ident);
break;
case AstNode_ProcLit:
print_indent(indent);
gb_printf("(proc lit)\n");
print_ast(node->ProcLit.type, indent+1);
print_ast(node->ProcLit.body, indent+1);
break;
case AstNode_CompoundLit:
print_indent(indent);
gb_printf("(compound lit)\n");
print_ast(node->CompoundLit.type, indent+1);
for_array(i, node->CompoundLit.elems) {
print_ast(node->CompoundLit.elems[i], indent+1);
}
break;
case AstNode_TagExpr:
print_indent(indent);
gb_printf("(tag)\n");
print_indent(indent+1);
print_token(node->TagExpr.name);
print_ast(node->TagExpr.expr, indent+1);
break;
case AstNode_UnaryExpr:
print_indent(indent);
print_token(node->UnaryExpr.op);
print_ast(node->UnaryExpr.expr, indent+1);
break;
case AstNode_BinaryExpr:
print_indent(indent);
print_token(node->BinaryExpr.op);
print_ast(node->BinaryExpr.left, indent+1);
print_ast(node->BinaryExpr.right, indent+1);
break;
case AstNode_CallExpr:
print_indent(indent);
gb_printf("(call)\n");
print_ast(node->CallExpr.proc, indent+1);
for_array(i, node->CallExpr.args) {
print_ast(node->CallExpr.args[i], indent+1);
}
break;
case AstNode_SelectorExpr:
print_indent(indent);
gb_printf(".\n");
print_ast(node->SelectorExpr.expr, indent+1);
print_ast(node->SelectorExpr.selector, indent+1);
break;
case AstNode_IndexExpr:
print_indent(indent);
gb_printf("([])\n");
print_ast(node->IndexExpr.expr, indent+1);
print_ast(node->IndexExpr.index, indent+1);
break;
case AstNode_DerefExpr:
print_indent(indent);
gb_printf("(deref)\n");
print_ast(node->DerefExpr.expr, indent+1);
break;
case AstNode_ExprStmt:
print_ast(node->ExprStmt.expr, indent);
break;
case AstNode_IncDecStmt:
print_indent(indent);
print_token(node->IncDecStmt.op);
print_ast(node->IncDecStmt.expr, indent+1);
break;
case AstNode_AssignStmt:
print_indent(indent);
print_token(node->AssignStmt.op);
for_array(i, node->AssignStmt.lhs) {
print_ast(node->AssignStmt.lhs[i], indent+1);
}
for_array(i, node->AssignStmt.rhs) {
print_ast(node->AssignStmt.rhs[i], indent+1);
}
break;
case AstNode_BlockStmt:
print_indent(indent);
gb_printf("(block)\n");
for_array(i, node->BlockStmt.stmts) {
print_ast(node->BlockStmt.stmts[i], indent+1);
}
break;
case AstNode_IfStmt:
print_indent(indent);
gb_printf("(if)\n");
print_ast(node->IfStmt.cond, indent+1);
print_ast(node->IfStmt.body, indent+1);
if (node->IfStmt.else_stmt) {
print_indent(indent);
gb_printf("(else)\n");
print_ast(node->IfStmt.else_stmt, indent+1);
}
break;
case AstNode_ReturnStmt:
print_indent(indent);
gb_printf("(return)\n");
for_array(i, node->ReturnStmt.results) {
print_ast(node->ReturnStmt.results[i], indent+1);
}
break;
case AstNode_ForStmt:
print_indent(indent);
gb_printf("(for)\n");
print_ast(node->ForStmt.init, indent+1);
print_ast(node->ForStmt.cond, indent+1);
print_ast(node->ForStmt.post, indent+1);
print_ast(node->ForStmt.body, indent+1);
break;
case AstNode_DeferStmt:
print_indent(indent);
gb_printf("(defer)\n");
print_ast(node->DeferStmt.stmt, indent+1);
break;
case AstNode_VarDecl:
print_indent(indent);
gb_printf("(decl:var)\n");
for_array(i, node->VarDecl.names) {
print_ast(node->VarDecl.names[i], indent+1);
}
print_ast(node->VarDecl.type, indent+1);
for_array(i, node->VarDecl.values) {
print_ast(node->VarDecl.values[i], indent+1);
}
break;
case AstNode_ConstDecl:
print_indent(indent);
gb_printf("(decl:const)\n");
for_array(i, node->VarDecl.names) {
print_ast(node->VarDecl.names[i], indent+1);
}
print_ast(node->VarDecl.type, indent+1);
for_array(i, node->VarDecl.values) {
print_ast(node->VarDecl.values[i], indent+1);
}
break;
case AstNode_ProcDecl:
print_indent(indent);
gb_printf("(decl:proc)\n");
print_ast(node->ProcDecl.type, indent+1);
print_ast(node->ProcDecl.body, indent+1);
break;
case AstNode_TypeDecl:
print_indent(indent);
gb_printf("(type)\n");
print_ast(node->TypeDecl.name, indent+1);
print_ast(node->TypeDecl.type, indent+1);
break;
case AstNode_ProcType:
print_indent(indent);
gb_printf("(type:proc)(%td -> %td)\n", node->ProcType.params.count, node->ProcType.results.count);
for_array(i, node->ProcType.params) {
print_ast(node->ProcType.params[i], indent+1);
}
if (node->ProcType.results.count > 0) {
print_indent(indent+1);
gb_printf("->\n");
for_array(i, node->ProcType.results) {
print_ast(node->ProcType.results[i], indent+1);
}
}
break;
case AstNode_Parameter:
for_array(i, node->Parameter.names) {
print_ast(node->Parameter.names[i], indent+1);
}
print_ast(node->Parameter.type, indent);
break;
case AstNode_PointerType:
print_indent(indent);
print_token(node->PointerType.token);
print_ast(node->PointerType.type, indent+1);
break;
case AstNode_ArrayType:
print_indent(indent);
gb_printf("[]\n");
print_ast(node->ArrayType.count, indent+1);
print_ast(node->ArrayType.elem, indent+1);
break;
case AstNode_StructType:
print_indent(indent);
gb_printf("(struct)\n");
for_array(i, node->StructType.decls) {
print_ast(node->StructType.decls[i], indent+1);
}
break;
}
// if (node->next)
// print_ast(node->next, indent);
}
+96
View File
@@ -0,0 +1,96 @@
template <typename T>
struct PriorityQueue {
Array<T> queue;
int (* cmp) (T *q, isize i, isize j);
void (* swap)(T *q, isize i, isize j);
};
template <typename T>
bool priority_queue_shift_down(PriorityQueue<T> *pq, isize i0, isize n) {
// O(n log n)
isize i = i0;
isize j, j1, j2;
if (0 > i || i > n) return false;
for (;;) {
j1 = 2*i + 1;
if (0 > j1 || j1 >= n) break;
j = j1;
j2 = j1 + 1;
if (j2 < n && pq->cmp(&pq->queue[0], j2, j1) < 0) {
j = j2;
}
if (pq->cmp(&pq->queue[0], i, j) < 0) break;
pq->swap(&pq->queue[0], i, j);
i = j;
}
return i > i0;
}
template <typename T>
void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
while (0 <= j && j < pq->queue.count) {
isize i = (j-1)/2;
if (i == j || pq->cmp(&pq->queue[0], i, j) < 0) {
break;
}
pq->swap(&pq->queue[0], i, j);
j = i;
}
}
// NOTE(bill): When an element at index `i0` has changed its value, this will fix the
// the heap ordering. This using a basic "heapsort" with shift up and a shift down parts.
template <typename T>
void priority_queue_fix(PriorityQueue<T> *pq, isize i) {
if (!priority_queue_shift_down(pq, i, pq->queue.count)) {
priority_queue_shift_up(pq, i);
}
}
template <typename T>
void priority_queue_push(PriorityQueue<T> *pq, T const &value) {
array_add(&pq->queue, value);
priority_queue_shift_up(pq, pq->queue.count-1);
}
template <typename T>
T priority_queue_pop(PriorityQueue<T> *pq) {
GB_ASSERT(pq->queue.count > 0);
isize n = pq->queue.count - 1;
pq->swap(&pq->queue[0], 0, n);
priority_queue_shift_down(pq, 0, n);
return array_pop(&pq->queue);
}
template <typename T>
T priority_queue_remove(PriorityQueue<T> *pq, isize i) {
GB_ASSERT(0 <= i && i < pq->queue.count);
isize n = pq->queue.count - 1;
if (n != i) {
pq->swap(&pq->queue[0], i, n);
priority_queue_shift_down(pq, i, n);
priority_queue_shift_up(pq, i);
}
return array_pop(&pq->queue);
}
template <typename T>
PriorityQueue<T> priority_queue_create(Array<T> queue,
int (* cmp) (T *q, isize i, isize j),
void (* swap)(T *q, isize i, isize j)) {
PriorityQueue<T> pq = {};
pq.queue = queue;
pq.cmp = cmp;
pq.swap = swap;
isize n = pq.queue.count;
for (isize i = n/2 - 1; i >= 0; i--) {
priority_queue_shift_down(&pq, i, n);
}
return pq;
}
+195
View File
@@ -0,0 +1,195 @@
struct PtrSetFindResult {
isize hash_index;
isize entry_prev;
isize entry_index;
};
template <typename T>
struct PtrSetEntry {
T ptr;
isize next;
};
template <typename T>
struct PtrSet {
Array<isize> hashes;
Array<PtrSetEntry<T>> entries;
};
template <typename T> void ptr_set_init (PtrSet<T> *s, gbAllocator a, isize capacity = 16);
template <typename T> void ptr_set_destroy (PtrSet<T> *s);
template <typename T> void ptr_set_add (PtrSet<T> *s, T ptr);
template <typename T> bool ptr_set_exists (PtrSet<T> *s, T ptr);
template <typename T> void ptr_set_remove (PtrSet<T> *s, T ptr);
template <typename T> void ptr_set_clear (PtrSet<T> *s);
template <typename T> void ptr_set_grow (PtrSet<T> *s);
template <typename T> void ptr_set_rehash (PtrSet<T> *s, isize new_count);
template <typename T>
void ptr_set_init(PtrSet<T> *s, gbAllocator a, isize capacity) {
array_init(&s->hashes, a, capacity);
array_init(&s->entries, a, capacity);
}
template <typename T>
void ptr_set_destroy(PtrSet<T> *s) {
array_free(&s->hashes);
array_free(&s->entries);
}
template <typename T>
gb_internal isize ptr_set__add_entry(PtrSet<T> *s, T ptr) {
PtrSetEntry<T> e = {};
e.ptr = ptr;
e.next = -1;
array_add(&s->entries, e);
return s->entries.count-1;
}
template <typename T>
gb_internal PtrSetFindResult ptr_set__find(PtrSet<T> *s, T ptr) {
PtrSetFindResult fr = {-1, -1, -1};
if (s->hashes.count > 0) {
uintptr p = cast(uintptr)ptr;
uintptr n = cast(uintptr)s->hashes.count;
fr.hash_index = cast(isize)(p % n);
fr.entry_index = s->hashes[fr.hash_index];
while (fr.entry_index >= 0) {
if (s->entries[fr.entry_index].ptr == ptr) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = s->entries[fr.entry_index].next;
}
}
return fr;
}
template <typename T>
gb_internal PtrSetFindResult ptr_set__find_from_entry(PtrSet<T> *s, PtrSetEntry<T> *e) {
PtrSetFindResult fr = {-1, -1, -1};
if (s->hashes.count > 0) {
fr.hash_index = e->key.key % s->hashes.count;
fr.entry_index = s->hashes[fr.hash_index];
while (fr.entry_index >= 0) {
if (&s->entries[fr.entry_index] == e) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = s->entries[fr.entry_index].next;
}
}
return fr;
}
template <typename T>
gb_internal b32 ptr_set__full(PtrSet<T> *s) {
return 0.75f * s->hashes.count <= s->entries.count;
}
template <typename T>
gb_inline void ptr_set_grow(PtrSet<T> *s) {
isize new_count = ARRAY_GROW_FORMULA(s->entries.count);
ptr_set_rehash(s, new_count);
}
template <typename T>
void ptr_set_rehash(PtrSet<T> *s, isize new_count) {
isize i, j;
PtrSet<T> ns = {};
ptr_set_init(&ns, s->hashes.allocator);
array_resize(&ns.hashes, new_count);
array_reserve(&ns.entries, s->entries.count);
for (i = 0; i < new_count; i++) {
ns.hashes[i] = -1;
}
for (i = 0; i < s->entries.count; i++) {
PtrSetEntry<T> *e = &s->entries[i];
PtrSetFindResult fr;
if (ns.hashes.count == 0) {
ptr_set_grow(&ns);
}
fr = ptr_set__find(&ns, e->ptr);
j = ptr_set__add_entry(&ns, e->ptr);
if (fr.entry_prev < 0) {
ns.hashes[fr.hash_index] = j;
} else {
ns.entries[fr.entry_prev].next = j;
}
ns.entries[j].next = fr.entry_index;
if (ptr_set__full(&ns)) {
ptr_set_grow(&ns);
}
}
ptr_set_destroy(s);
*s = ns;
}
template <typename T>
gb_inline bool ptr_set_exists(PtrSet<T> *s, T ptr) {
isize index = ptr_set__find(s, ptr).entry_index;
return index >= 0;
}
// Returns true if it already exists
template <typename T>
void ptr_set_add(PtrSet<T> *s, T ptr) {
isize index;
PtrSetFindResult fr;
if (s->hashes.count == 0) {
ptr_set_grow(s);
}
fr = ptr_set__find(s, ptr);
if (fr.entry_index >= 0) {
index = fr.entry_index;
} else {
index = ptr_set__add_entry(s, ptr);
if (fr.entry_prev >= 0) {
s->entries[fr.entry_prev].next = index;
} else {
s->hashes[fr.hash_index] = index;
}
}
if (ptr_set__full(s)) {
ptr_set_grow(s);
}
}
template <typename T>
void ptr_set__erase(PtrSet<T> *s, PtrSetFindResult fr) {
PtrSetFindResult last;
if (fr.entry_prev < 0) {
s->hashes[fr.hash_index] = s->entries[fr.entry_index].next;
} else {
s->entries[fr.entry_prev].next = s->entries[fr.entry_index].next;
}
if (fr.entry_index == s->entries.count-1) {
array_pop(&s->entries);
return;
}
s->entries[fr.entry_index] = s->entries[s->entries.count-1];
last = ptr_set__find(s, s->entries[fr.entry_index].ptr);
if (last.entry_prev >= 0) {
s->entries[last.entry_prev].next = fr.entry_index;
} else {
s->hashes[last.hash_index] = fr.entry_index;
}
}
template <typename T>
void ptr_set_remove(PtrSet<T> *s, T ptr) {
PtrSetFindResult fr = ptr_set__find(s, ptr);
if (fr.entry_index >= 0) {
ptr_set__erase(s, fr);
}
}
template <typename T>
gb_inline void ptr_set_clear(PtrSet<T> *s) {
array_clear(&s->hashes);
array_clear(&s->entries);
}
+154 -168
View File
@@ -159,7 +159,7 @@ struct ssaModule {
gbAllocator tmp_allocator;
gbArena tmp_arena;
Map<Entity *> min_dep_map; // Key: Entity *
PtrSet<Entity *> min_dep_map;
Map<ssaValue *> values; // Key: Entity *
// List of registers for the specific architecture
Array<ssaRegister> registers;
@@ -206,7 +206,7 @@ ssaBlock *ssa_new_block(ssaProc *p, ssaBlockKind kind, char *name) {
b->kind = kind;
b->proc = p;
p->scope_level = p->scope_level;
if (name != NULL || name[0] != 0) {
if (name != nullptr || name[0] != 0) {
b->name = make_string_c(name);
}
@@ -218,34 +218,34 @@ ssaBlock *ssa_new_block(ssaProc *p, ssaBlockKind kind, char *name) {
}
void ssa_clear_block(ssaProc *p, ssaBlock *b) {
GB_ASSERT(b->proc != NULL);
GB_ASSERT(b->proc != nullptr);
array_clear(&b->values);
array_clear(&b->preds);
array_clear(&b->succs);
b->proc = NULL;
b->proc = nullptr;
b->kind = ssaBlock_Plain;
}
void ssa_start_block(ssaProc *p, ssaBlock *b) {
GB_ASSERT(p->curr_block == NULL);
GB_ASSERT(p->curr_block == nullptr);
p->curr_block = b;
}
ssaBlock *ssa_end_block(ssaProc *p) {
ssaBlock *b = p->curr_block;
if (b == NULL) {
return NULL;
if (b == nullptr) {
return nullptr;
}
p->curr_block = NULL;
p->curr_block = nullptr;
return b;
}
void ssa_add_edge_to(ssaBlock *b, ssaBlock *c) {
if (b == NULL) {
if (b == nullptr) {
return;
}
GB_ASSERT(c != NULL);
GB_ASSERT(c != nullptr);
isize i = b->succs.count;
isize j = b->preds.count;
ssaEdge s = {c, j};
@@ -255,11 +255,11 @@ void ssa_add_edge_to(ssaBlock *b, ssaBlock *c) {
}
void ssa_set_control(ssaBlock *b, ssaValue *v) {
if (b->control != NULL) {
if (b->control != nullptr) {
b->control->uses--;
}
b->control = v;
if (v != NULL) {
if (v != nullptr) {
v->uses++;
}
}
@@ -295,7 +295,7 @@ void ssa_add_arg(ssaValueArgs *va, ssaValue *arg) {
ssaValue *ssa_new_value(ssaProc *p, ssaOp op, Type *t, ssaBlock *b) {
GB_ASSERT(b != NULL);
GB_ASSERT(b != nullptr);
ssaValue *v = gb_alloc_item(p->allocator, ssaValue);
v->id = p->value_id++;
v->op = op;
@@ -388,7 +388,7 @@ ssaValue *ssa_const_int(ssaProc *p, Type *t, i64 c) {
case 64: return ssa_const_i64(p, t, cast(i64)c);
}
GB_PANIC("Unknown int size");
return NULL;
return nullptr;
}
@@ -416,8 +416,8 @@ void ssa_reset(ssaValue *v, ssaOp op) {
}
ssaValue *ssa_get_last_value(ssaBlock *b) {
if (b == NULL) {
return NULL;
if (b == nullptr) {
return nullptr;
}
isize len = b->values.count;
if (len <= 0) {
@@ -428,7 +428,7 @@ ssaValue *ssa_get_last_value(ssaBlock *b) {
}
void ssa_emit_comment(ssaProc *p, String s) {
// ssa_new_value0v(p, ssaOp_Comment, NULL, exact_value_string(s));
// ssa_new_value0v(p, ssaOp_Comment, nullptr, exact_value_string(s));
}
void ssa_build_defer_stmt(ssaProc *p, ssaDefer d) {
@@ -463,7 +463,7 @@ void ssa_emit_defer_stmts(ssaProc *p, ssaDeferExitKind kind, ssaBlock *b) {
} else if (kind == ssaDeferExit_Return) {
ssa_build_defer_stmt(p, d);
} else if (kind == ssaDeferExit_Branch) {
GB_ASSERT(b != NULL);
GB_ASSERT(b != nullptr);
i32 lower_limit = b->scope_level+1;
if (lower_limit < d.scope_level) {
ssa_build_defer_stmt(p, d);
@@ -534,7 +534,7 @@ bool ssa_is_op_const(ssaOp op) {
bool ssa_is_blank_ident(AstNode *node) {
if (node->kind == AstNode_Ident) {
ast_node(i, Ident, node);
return is_blank_ident(i->string);
return is_blank_ident(i->token.string);
}
return false;
}
@@ -542,7 +542,7 @@ bool ssa_is_blank_ident(AstNode *node) {
ssaAddr ssa_addr(ssaValue *v) {
if (v != NULL) {
if (v != nullptr) {
GB_ASSERT(is_type_pointer(v->type));
}
ssaAddr addr = {0};
@@ -551,13 +551,13 @@ ssaAddr ssa_addr(ssaValue *v) {
}
Type *ssa_addr_type(ssaAddr addr) {
if (addr.addr == NULL) {
return NULL;
if (addr.addr == nullptr) {
return nullptr;
}
if (addr.kind == ssaAddr_Map) {
GB_PANIC("TODO: ssa_addr_type");
return NULL;
return nullptr;
}
Type *t = addr.addr->type;
@@ -603,18 +603,18 @@ ssaAddr ssa_add_local_for_ident(ssaProc *p, AstNode *name) {
return ssa_add_local(p, e, name);
}
return ssa_addr(NULL);
return ssa_addr(nullptr);
}
ssaAddr ssa_add_local_generated(ssaProc *p, Type *t) {
GB_ASSERT(t != NULL);
GB_ASSERT(t != nullptr);
Scope *scope = NULL;
Scope *scope = nullptr;
if (p->curr_block) {
// scope = p->curr_block->scope;
}
Entity *e = make_entity_variable(p->allocator, scope, empty_token, t, false);
return ssa_add_local(p, e, NULL);
return ssa_add_local(p, e, nullptr);
}
@@ -639,24 +639,25 @@ bool can_ssa_type(Type *t) {
case Type_Map:
return false;
case Type_Tuple:
if (t->Tuple.variable_count > SSA_MAX_STRUCT_FIELD_COUNT) {
if (t->Tuple.variables.count > SSA_MAX_STRUCT_FIELD_COUNT) {
return false;
}
for (isize i = 0; i < t->Tuple.variable_count; i++) {
for_array(i, t->Tuple.variables) {
if (!can_ssa_type(t->Tuple.variables[i]->type)) {
return false;
}
}
return true;
case Type_Record:
if (t->Record.kind == TypeRecord_Union) {
return false;
} else if (t->Record.kind == TypeRecord_Struct) {
if (t->Record.field_count > SSA_MAX_STRUCT_FIELD_COUNT) {
case Type_Union:
return false;
case Type_Struct:
if (!t->Struct.is_raw_union) {
if (t->Struct.fields.count > SSA_MAX_STRUCT_FIELD_COUNT) {
return false;
}
for (isize i = 0; i < t->Record.field_count; i++) {
if (!can_ssa_type(t->Record.fields[i]->type)) {
for_array(i, t->Struct.fields) {
if (!can_ssa_type(t->Struct.fields[i]->type)) {
return false;
}
}
@@ -667,7 +668,7 @@ bool can_ssa_type(Type *t) {
}
void ssa_addr_store(ssaProc *p, ssaAddr addr, ssaValue *value) {
if (addr.addr == NULL) {
if (addr.addr == nullptr) {
return;
}
if (addr.kind == ssaAddr_Map) {
@@ -679,13 +680,13 @@ void ssa_addr_store(ssaProc *p, ssaAddr addr, ssaValue *value) {
}
ssaValue *ssa_addr_load(ssaProc *p, ssaAddr addr) {
if (addr.addr == NULL) {
return NULL;
if (addr.addr == nullptr) {
return nullptr;
}
if (addr.kind == ssaAddr_Map) {
GB_PANIC("here\n");
return NULL;
return nullptr;
}
Type *t = addr.addr->type;
@@ -702,23 +703,23 @@ ssaValue *ssa_get_using_variable(ssaProc *p, Entity *e) {
String name = e->token.string;
Entity *parent = e->using_parent;
Selection sel = lookup_field(p->allocator, parent->type, name, false);
GB_ASSERT(sel.entity != NULL);
GB_ASSERT(sel.entity != nullptr);
ssaValue **pv = map_get(&p->module->values, hash_pointer(parent));
ssaValue *v = NULL;
if (pv != NULL) {
ssaValue *v = nullptr;
if (pv != nullptr) {
v = *pv;
} else {
v = ssa_build_addr(p, e->using_expr).addr;
}
GB_ASSERT(v != NULL);
GB_ASSERT(v != nullptr);
GB_ASSERT(type_deref(v->type) == parent->type);
return ssa_emit_deep_field_ptr_index(p, v, sel);
}
ssaAddr ssa_build_addr_from_entity(ssaProc *p, Entity *e, AstNode *expr) {
GB_ASSERT(e != NULL);
GB_ASSERT(e != nullptr);
ssaValue *v = NULL;
ssaValue *v = nullptr;
ssaValue **found = map_get(&p->module->values, hash_pointer(e));
if (found) {
v = *found;
@@ -727,7 +728,7 @@ ssaAddr ssa_build_addr_from_entity(ssaProc *p, Entity *e, AstNode *expr) {
v = ssa_get_using_variable(p, e);
}
if (v == NULL) {
if (v == nullptr) {
GB_PANIC("Unknown value: %.*s, entity: %p %.*s\n", LIT(e->token.string), e, LIT(entity_strings[e->kind]));
}
@@ -773,11 +774,11 @@ ssaValue *ssa_emit_conv(ssaProc *p, ssaValue *v, Type *t) {
GB_PANIC("Invalid type conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t));
return NULL;
return nullptr;
}
// NOTE(bill): Returns NULL if not possible
// NOTE(bill): Returns nullptr if not possible
ssaValue *ssa_address_from_load_or_generate_local(ssaProc *p, ssaValue *v) {
if (v->op == ssaOp_Load) {
return v->args[0];
@@ -789,11 +790,11 @@ ssaValue *ssa_address_from_load_or_generate_local(ssaProc *p, ssaValue *v) {
ssaValue *ssa_emit_array_index(ssaProc *p, ssaValue *v, ssaValue *index) {
GB_ASSERT(v != NULL);
GB_ASSERT(v != nullptr);
GB_ASSERT(is_type_pointer(v->type));
Type *t = base_type(type_deref(v->type));
GB_ASSERT_MSG(is_type_array(t) || is_type_vector(t), "%s", type_to_string(t));
Type *elem_ptr = NULL;
Type *elem_ptr = nullptr;
if (is_type_array(t)) {
elem_ptr = make_type_pointer(p->allocator, t->Array.elem);
} else if (is_type_vector(t)) {
@@ -806,20 +807,14 @@ ssaValue *ssa_emit_array_index(ssaProc *p, ssaValue *v, ssaValue *index) {
ssaValue *ssa_emit_ptr_index(ssaProc *p, ssaValue *s, i64 index) {
gbAllocator a = p->allocator;
Type *t = base_type(type_deref(s->type));
Type *result_type = NULL;
Type *result_type = nullptr;
if (is_type_struct(t)) {
GB_ASSERT(t->Record.field_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
result_type = make_type_pointer(a, t->Record.fields[index]->type);
} else if (is_type_union(t)) {
type_set_offsets(a, t);
GB_ASSERT(t->Record.field_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
result_type = make_type_pointer(a, t->Record.fields[index]->type);
GB_ASSERT(t->Struct.fields.count > 0);
result_type = make_type_pointer(a, t->Struct.fields[index]->type);
} else if (is_type_tuple(t)) {
GB_ASSERT(t->Tuple.variable_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
GB_ASSERT(t->Tuple.variables.count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Tuple.variables.count-1));
result_type = make_type_pointer(a, t->Tuple.variables[index]->type);
} else if (is_type_slice(t)) {
switch (index) {
@@ -844,17 +839,17 @@ ssaValue *ssa_emit_ptr_index(ssaProc *p, ssaValue *s, i64 index) {
case 2: result_type = t_int_ptr; break;
case 3: result_type = t_allocator_ptr; break;
}
} else if (is_type_dynamic_map(t)) {
} else if (is_type_map(t)) {
Type *gst = t->Map.generated_struct_type;
switch (index) {
case 0: result_type = make_type_pointer(a, gst->Record.fields[0]->type); break;
case 1: result_type = make_type_pointer(a, gst->Record.fields[1]->type); break;
case 0: result_type = make_type_pointer(a, gst->Struct.fields[0]->type); break;
case 1: result_type = make_type_pointer(a, gst->Struct.fields[1]->type); break;
}
}else {
GB_PANIC("TODO(bill): ssa_emit_ptr_index type: %s, %d", type_to_string(s->type), index);
}
GB_ASSERT(result_type != NULL);
GB_ASSERT(result_type != nullptr);
return ssa_new_value1i(p, ssaOp_PtrIndex, result_type, index, s);
}
@@ -869,20 +864,17 @@ ssaValue *ssa_emit_value_index(ssaProc *p, ssaValue *s, i64 index) {
gbAllocator a = p->allocator;
Type *t = base_type(s->type);
Type *result_type = NULL;
Type *result_type = nullptr;
if (is_type_struct(t)) {
GB_ASSERT(t->Record.field_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
result_type = t->Record.fields[index]->type;
GB_ASSERT(t->Struct.fields.count > 0);
result_type = t->Struct.fields[index]->type;
} else if (is_type_union(t)) {
type_set_offsets(a, t);
GB_ASSERT(t->Record.field_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
result_type = t->Record.fields[index]->type;
GB_ASSERT(t->Struct.fields.count > 0);
result_type = t->Struct.fields[index]->type;
} else if (is_type_tuple(t)) {
GB_ASSERT(t->Tuple.variable_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
GB_ASSERT(t->Tuple.variables.count > 0);
result_type = t->Tuple.variables[index]->type;
} else if (is_type_slice(t)) {
switch (index) {
@@ -907,17 +899,17 @@ ssaValue *ssa_emit_value_index(ssaProc *p, ssaValue *s, i64 index) {
case 2: result_type = t_int; break;
case 3: result_type = t_allocator; break;
}
} else if (is_type_dynamic_map(t)) {
} else if (is_type_map(t)) {
Type *gst = t->Map.generated_struct_type;
switch (index) {
case 0: result_type = gst->Record.fields[0]->type; break;
case 1: result_type = gst->Record.fields[1]->type; break;
case 0: result_type = gst->Struct.fields[0]->type; break;
case 1: result_type = gst->Struct.fields[1]->type; break;
}
} else {
GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(s->type), index);
}
GB_ASSERT(result_type != NULL);
GB_ASSERT(result_type != nullptr);
return ssa_new_value1i(p, ssaOp_ValueIndex, result_type, index, s);
}
@@ -937,10 +929,10 @@ ssaValue *ssa_emit_deep_field_ptr_index(ssaProc *p, ssaValue *e, Selection sel)
if (is_type_raw_union(type)) {
type = type->Record.fields[index]->type;
type = type->Struct.fields[index]->type;
e = ssa_emit_conv(p, e, make_type_pointer(p->allocator, type));
} else if (type->kind == Type_Record) {
type = type->Record.fields[index]->type;
} else if (type->kind == Type_Struct) {
type = type->Struct.fields[index]->type;
e = ssa_emit_ptr_index(p, e, index);
} else if (type->kind == Type_Tuple) {
type = type->Tuple.variables[index]->type;
@@ -1008,7 +1000,7 @@ ssaValue *ssa_emit_deep_field_value_index(ssaProc *p, ssaValue *e, Selection sel
if (is_type_raw_union(type)) {
GB_PANIC("TODO(bill): IS THIS EVEN CORRECT?");
type = type->Record.fields[index]->type;
type = type->Struct.fields[index]->type;
e = ssa_emit_conv(p, e, type);
} else if (type->kind == Type_Map) {
e = ssa_emit_value_index(p, e, 1);
@@ -1048,13 +1040,13 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
ssa_emit_comment(p, str_lit("SelectorExpr"));
AstNode *sel = unparen_expr(se->selector);
if (sel->kind == AstNode_Ident) {
String selector = sel->Ident.string;
String selector = sel->Ident.token.string;
TypeAndValue tav = type_and_value_of_expr(p->module->info, se->expr);
if (tav.mode == Addressing_Invalid) {
// NOTE(bill): Imports
Entity *imp = entity_of_ident(p->module->info, se->expr);
if (imp != NULL) {
if (imp != nullptr) {
GB_ASSERT(imp->kind == Entity_ImportName);
}
return ssa_build_addr(p, se->selector);
@@ -1072,14 +1064,14 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
// if (name == "names") {
// ssaValue *ti_ptr = ir_type_info(p, type);
// ssaValue *names_ptr = NULL;
// ssaValue *names_ptr = nullptr;
// if (is_type_enum(type)) {
// ssaValue *enum_info = ssa_emit_conv(p, ti_ptr, t_type_info_enum_ptr);
// names_ptr = ssa_emit_ptr_index(p, enum_info, 1);
// } else if (type->kind == Type_Record) {
// ssaValue *record_info = ssa_emit_conv(p, ti_ptr, t_type_info_record_ptr);
// names_ptr = ssa_emit_ptr_index(p, record_info, 1);
// } else if (type->kind == Type_Struct) {
// ssaValue *struct_info = ssa_emit_conv(p, ti_ptr, t_type_info_struct_ptr);
// names_ptr = ssa_emit_ptr_index(p, struct_info, 1);
// }
// return ssa_addr(names_ptr);
// } else {
@@ -1089,7 +1081,7 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
}
Selection sel = lookup_field(p->allocator, type, selector, false);
GB_ASSERT(sel.entity != NULL);
GB_ASSERT(sel.entity != nullptr);
ssaValue *a = ssa_build_addr(p, se->expr).addr;
a = ssa_emit_deep_field_ptr_index(p, a, sel);
@@ -1101,7 +1093,7 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
i64 index = i128_to_i64(val.value_integer);
Selection sel = lookup_field_from_index(p->allocator, type, index);
GB_ASSERT(sel.entity != NULL);
GB_ASSERT(sel.entity != nullptr);
ssaValue *a = ssa_build_addr(p, se->expr).addr;
a = ssa_emit_deep_field_ptr_index(p, a, sel);
@@ -1156,7 +1148,7 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
LIT(token_pos.file), token_pos.line, token_pos.column);
return ssa_addr(NULL);
return ssa_addr(nullptr);
}
@@ -1382,7 +1374,7 @@ ssaOp ssa_determine_op(TokenKind op, Type *t) {
ssaValue *ssa_emit_comp(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y) {
GB_ASSERT(x != NULL && y != NULL);
GB_ASSERT(x != nullptr && y != nullptr);
Type *a = core_type(x->type);
Type *b = core_type(y->type);
if (are_types_identical(a, b)) {
@@ -1486,7 +1478,7 @@ ssaValue *ssa_emit_unary_arith(ssaProc *p, TokenKind op, ssaValue *x, Type *type
GB_PANIC("unknown type for -x");
} break;
}
return NULL;
return nullptr;
}
ssaValue *ssa_emit_arith(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y, Type *type) {
if (is_type_vector(x->type)) {
@@ -1537,11 +1529,11 @@ ssaValue *ssa_emit_arith(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y, Typ
case Token_Or:
case Token_Xor:
case Token_AndNot:
GB_ASSERT(x != NULL && y != NULL);
GB_ASSERT(x != nullptr && y != nullptr);
return ssa_new_value2(p, ssa_determine_op(op, x->type), type, x, y);
}
return NULL;
return nullptr;
}
@@ -1589,7 +1581,7 @@ ssaValue *ssa_emit_logical_binary_expr(ssaProc *p, AstNode *expr) {
ssaBlock *rhs = ssa_new_block(p, ssaBlock_Plain, "logical.cmp.rhs");
ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "logical.cmp.done");
GB_ASSERT(p->curr_block != NULL);
GB_ASSERT(p->curr_block != nullptr);
Type *type = default_type(type_of_expr(p->module->info, expr));
@@ -1648,22 +1640,22 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
i64 s = 8*type_size_of(p->allocator, t);
switch (s) {
case 8: return ssa_const_i8 (p, tv.type, i128_to_i64(tv.value.value_integer));
case 16: return ssa_const_i16(p, tv.type, i128_to_i64(tv.value.value_integer));
case 32: return ssa_const_i32(p, tv.type, i128_to_i64(tv.value.value_integer));
case 64: return ssa_const_i64(p, tv.type, i128_to_i64(tv.value.value_integer));
case 8: return ssa_const_i8 (p, tv.type, cast (i8)i128_to_i64(tv.value.value_integer));
case 16: return ssa_const_i16(p, tv.type, cast(i16)i128_to_i64(tv.value.value_integer));
case 32: return ssa_const_i32(p, tv.type, cast(i32)i128_to_i64(tv.value.value_integer));
case 64: return ssa_const_i64(p, tv.type, cast(i64)i128_to_i64(tv.value.value_integer));
default: GB_PANIC("Unknown integer size");
}
} else if (is_type_float(t)) {
GB_ASSERT(tv.value.kind == ExactValue_Float);
i64 s = 8*type_size_of(p->allocator, t);
switch (s) {
case 32: return ssa_const_f32(p, tv.type, tv.value.value_float);
case 64: return ssa_const_f64(p, tv.type, tv.value.value_float);
case 32: return ssa_const_f32(p, tv.type, cast(f32)tv.value.value_float);
case 64: return ssa_const_f64(p, tv.type, cast(f64)tv.value.value_float);
default: GB_PANIC("Unknown float size");
}
}
// IMPORTANT TODO(bill): Do constant record/array literals correctly
// IMPORTANT TODO(bill): Do constant str/array literals correctly
return ssa_const_nil(p, tv.type);
}
@@ -1689,10 +1681,10 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
GB_PANIC("TODO(bill): ssa_build_expr Entity_Builtin `%.*s`\n"
"\t at %.*s(%td:%td)", LIT(builtin_procs[e->Builtin.id].name),
LIT(token.pos.file), token.pos.line, token.pos.column);
return NULL;
return nullptr;
} else if (e->kind == Entity_Nil) {
GB_PANIC("TODO(bill): nil");
return NULL;
return nullptr;
}
ssaValue **found = map_get(&p->module->values, hash_pointer(e));
@@ -1737,7 +1729,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
case Token_Shl:
case Token_Shr: {
GB_PANIC("TODO: shifts");
return NULL;
return nullptr;
}
case Token_CmpEq:
@@ -1772,29 +1764,29 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
case_ast_node(te, TernaryExpr, expr);
ssa_emit_comment(p, str_lit("TernaryExpr"));
ssaValue *yes = NULL;
ssaValue *no = NULL;
ssaValue *yes = nullptr;
ssaValue *no = nullptr;
GB_ASSERT(te->y != NULL);
GB_ASSERT(te->y != nullptr);
ssaBlock *then = ssa_new_block(p, ssaBlock_Plain, "if.then");
ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "if.done"); // NOTE(bill): Append later
ssaBlock *else_ = ssa_new_block(p, ssaBlock_Plain, "if.else");
ssaBlock *v = NULL;
ssaBlock *v = nullptr;
ssa_build_cond(p, te->cond, then, else_);
ssa_start_block(p, then);
// ssa_open_scope(p);
yes = ssa_build_expr(p, te->x);
// ssa_close_scope(p, ssaDeferExit_Default, NULL);
// ssa_close_scope(p, ssaDeferExit_Default, nullptr);
ssa_emit_jump(p, done);
ssa_start_block(p, else_);
// ssa_open_scope(p);
no = ssa_build_expr(p, te->y);
// ssa_close_scope(p, ssaDeferExit_Default, NULL);
// ssa_close_scope(p, ssaDeferExit_Default, nullptr);
ssa_emit_jump(p, done);
ssa_start_block(p, done);
@@ -1815,7 +1807,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
Type *type = type_of_expr(proc->module->info, expr);
irValue *value = ir_value_procedure(proc->module->allocator,
proc->module, NULL, type, pl->type, pl->body, name);
proc->module, nullptr, type, pl->type, pl->body, name);
value->Proc.tags = pl->tags;
value->Proc.parent = proc;
@@ -1854,7 +1846,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
GB_PANIC("Unexpected expression: %.*s", LIT(ast_node_strings[expr->kind]));
return NULL;
return nullptr;
}
@@ -1927,7 +1919,7 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) {
p->module->stmt_state_flags = prev_stmt_state_flags;
}
void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
if (p->curr_block == NULL) {
if (p->curr_block == nullptr) {
ssaBlock *dead_block = ssa_new_block(p, ssaBlock_Plain, "");
ssa_start_block(p, dead_block);
}
@@ -1939,22 +1931,17 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
case_ast_node(bs, BlockStmt, node);
ssa_open_scope(p);
ssa_build_stmt_list(p, bs->stmts);
ssa_close_scope(p, ssaDeferExit_Default, NULL);
ssa_close_scope(p, ssaDeferExit_Default, nullptr);
case_end;
case_ast_node(us, UsingStmt, node);
for_array(i, us->list) {
AstNode *decl = unparen_expr(us->list[i]);
if (decl->kind == AstNode_GenDecl) {
ssa_build_stmt(p, decl);
}
}
case_end;
case_ast_node(ws, WhenStmt, node);
ssa_build_when_stmt(p, ws);
case_end;
#if 0
case_ast_node(s, IncDecStmt, node);
TokenKind op = Token_Add;
if (s->op.kind == Token_Dec) {
@@ -1964,6 +1951,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
Type *t = ssa_addr_type(addr);
ssa_build_assign_op(p, addr, ssa_const_int(p, t, 1), op);
case_end;
#endif
case_ast_node(as, AssignStmt, node);
ssa_emit_comment(p, str_lit("AssignStmt"));
@@ -2012,7 +2000,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
Type *t = base_type(init->type);
// TODO(bill): refactor for code reuse as this is repeated a bit
if (t->kind == Type_Tuple) {
for (isize i = 0; i < t->Tuple.variable_count; i++) {
for_array(i, t->Tuple.variables) {
Entity *e = t->Tuple.variables[i];
ssaValue *v = ssa_emit_value_index(p, init, i);
array_add(&inits, v);
@@ -2064,7 +2052,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
case_ast_node(is, IfStmt, node);
ssa_emit_comment(p, str_lit("IfStmt"));
if (is->init != NULL) {
if (is->init != nullptr) {
ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "if.init");
ssa_emit_jump(p, init);
ssa_start_block(p, init);
@@ -2073,26 +2061,26 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
ssaBlock *then = ssa_new_block(p, ssaBlock_Plain, "if.then");
ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "if.done");
ssaBlock *else_ = done;
if (is->else_stmt != NULL) {
if (is->else_stmt != nullptr) {
else_ = ssa_new_block(p, ssaBlock_Plain, "if.else");
}
ssaBlock *b = NULL;
ssaBlock *b = nullptr;
ssa_build_cond(p, is->cond, then, else_);
ssa_start_block(p, then);
ssa_open_scope(p);
ssa_build_stmt(p, is->body);
ssa_close_scope(p, ssaDeferExit_Default, NULL);
ssa_close_scope(p, ssaDeferExit_Default, nullptr);
ssa_emit_jump(p, done);
if (is->else_stmt != NULL) {
if (is->else_stmt != nullptr) {
ssa_start_block(p, else_);
ssa_open_scope(p);
ssa_build_stmt(p, is->else_stmt);
ssa_close_scope(p, ssaDeferExit_Default, NULL);
ssa_close_scope(p, ssaDeferExit_Default, nullptr);
ssa_emit_jump(p, done);
}
@@ -2103,7 +2091,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
case_ast_node(fs, ForStmt, node);
ssa_emit_comment(p, str_lit("ForStmt"));
if (fs->init != NULL) {
if (fs->init != nullptr) {
ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "for.init");
ssa_emit_jump(p, init);
ssa_start_block(p, init);
@@ -2113,11 +2101,11 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
ssaBlock *body = ssa_new_block(p, ssaBlock_Plain, "for.body");
ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "for.done");
ssaBlock *loop = body;
if (fs->cond != NULL) {
if (fs->cond != nullptr) {
loop = ssa_new_block(p, ssaBlock_Plain, "for.loop");
}
ssaBlock *post = loop;
if (fs->post != NULL) {
if (fs->post != nullptr) {
post = ssa_new_block(p, ssaBlock_Plain, "for.post");
}
@@ -2129,15 +2117,15 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
ssa_start_block(p, body);
}
ssa_push_target_list(p, done, post, NULL);
ssa_push_target_list(p, done, post, nullptr);
ssa_open_scope(p);
ssa_build_stmt(p, fs->body);
ssa_close_scope(p, ssaDeferExit_Default, NULL);
ssa_close_scope(p, ssaDeferExit_Default, nullptr);
ssa_pop_target_list(p);
ssa_emit_jump(p, post);
if (fs->post != NULL) {
if (fs->post != nullptr) {
ssa_start_block(p, post);
ssa_build_stmt(p, fs->post);
ssa_emit_jump(p, post);
@@ -2150,34 +2138,34 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
GB_PANIC("TODO: RangeStmt");
case_end;
case_ast_node(rs, MatchStmt, node);
GB_PANIC("TODO: MatchStmt");
case_ast_node(rs, SwitchStmt, node);
GB_PANIC("TODO: SwitchStmt");
case_end;
case_ast_node(rs, TypeMatchStmt, node);
GB_PANIC("TODO: TypeMatchStmt");
case_ast_node(rs, TypeSwitchStmt, node);
GB_PANIC("TODO: TypeSwitchStmt");
case_end;
case_ast_node(bs, BranchStmt, node);
ssaBlock *b = NULL;
ssaBlock *b = nullptr;
switch (bs->token.kind) {
case Token_break:
for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) {
for (ssaTargetList *t = p->target_list; t != nullptr && b == nullptr; t = t->prev) {
b = t->break_;
}
break;
case Token_continue:
for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) {
for (ssaTargetList *t = p->target_list; t != nullptr && b == nullptr; t = t->prev) {
b = t->continue_;
}
break;
case Token_fallthrough:
for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) {
for (ssaTargetList *t = p->target_list; t != nullptr && b == nullptr; t = t->prev) {
b = t->fallthrough_;
}
break;
}
if (b != NULL) {
if (b != nullptr) {
ssa_emit_defer_stmts(p, ssaDeferExit_Branch, b);
}
switch (bs->token.kind) {
@@ -2188,9 +2176,6 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
ssa_emit_jump(p, b);
case_end;
case_ast_node(pa, PushAllocator, node);
GB_PANIC("TODO: PushAllocator");
case_end;
case_ast_node(pc, PushContext, node);
GB_PANIC("TODO: PushContext");
case_end;
@@ -2198,7 +2183,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
}
void ssa_print_value(gbFile *f, ssaValue *v) {
if (v == NULL) {
if (v == nullptr) {
gb_fprintf(f, "nil");
}
gb_fprintf(f, "v%d", v->id);
@@ -2249,7 +2234,7 @@ void ssa_print_reg_value(gbFile *f, ssaValue *v) {
gb_fprintf(f, " ");
gb_fprintf(f, "v%d = %.*s", v->id, LIT(ssa_op_strings[v->op]));
if (v->type != NULL) {
if (v->type != nullptr) {
gbString type_str = type_to_string(default_type(v->type));
gb_fprintf(f, " %s", type_str);
gb_string_free(type_str);
@@ -2313,7 +2298,7 @@ void ssa_print_proc(gbFile *f, ssaProc *p) {
bool skip = false;
for_array(k, v->args) {
ssaValue *w = v->args[k];
if (w != NULL && w->block == b && !printed[w->id]) {
if (w != nullptr && w->block == b && !printed[w->id]) {
skip = true;
break;
}
@@ -2377,13 +2362,13 @@ void ssa_build_proc(ssaModule *m, ssaProc *p) {
p->module = m;
m->proc = p;
if (p->decl_info->proc_decl == NULL ||
p->decl_info->proc_decl->kind != AstNode_ProcDecl) {
if (p->decl_info->proc_lit == nullptr ||
p->decl_info->proc_lit->kind != AstNode_ProcLit) {
return;
}
ast_node(pl, ProcLit, p->decl_info->proc_decl);
if (pl->body == NULL) {
ast_node(pl, ProcLit, p->decl_info->proc_lit);
if (pl->body == nullptr) {
return;
}
p->entry = ssa_new_block(p, ssaBlock_Entry, "entry");
@@ -2392,7 +2377,7 @@ void ssa_build_proc(ssaModule *m, ssaProc *p) {
ssa_build_stmt(p, pl->body);
if (p->entity->type->Proc.result_count == 0) {
ssa_emit_defer_stmts(p, ssaDeferExit_Return, NULL);
ssa_emit_defer_stmts(p, ssaDeferExit_Return, nullptr);
}
p->exit = ssa_new_block(p, ssaBlock_Exit, "exit");
@@ -2429,7 +2414,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
}
isize global_variable_max_count = 0;
Entity *entry_point = NULL;
Entity *entry_point = nullptr;
bool has_dll_main = false;
bool has_win_main = false;
@@ -2443,7 +2428,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
if (e->scope->is_init && name == "main") {
entry_point = e;
}
if ((e->Procedure.tags & ProcTag_export) != 0 ||
if (e->Procedure.is_export ||
(e->Procedure.link_name.len > 0) ||
(e->scope->is_file && e->Procedure.link_name.len > 0)) {
if (!has_dll_main && name == "DllMain") {
@@ -2457,7 +2442,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
m.entry_point_entity = entry_point;
m.min_dep_map = generate_minimum_dependency_map(info, entry_point);
m.min_dep_map = generate_minimum_dependency_set(info, entry_point);
for_array(i, info->entities.entries) {
auto *entry = &info->entities.entries[i];
@@ -2470,13 +2455,14 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
continue;
}
if (map_get(&m.min_dep_map, hash_pointer(e)) == NULL) {
if (!ptr_set_exists(&m.min_dep_map, e)) {
// NOTE(bill): Nothing depends upon it so doesn't need to be built
continue;
}
if (!scope->is_global) {
if (e->kind == Entity_Procedure && (e->Procedure.tags & ProcTag_export) != 0) {
if (e->kind == Entity_Procedure && e->Procedure.is_export) {
} else if (e->kind == Entity_Variable && e->Variable.is_export) {
} else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
// Handle later
} else if (scope->is_init && e->kind == Entity_Procedure && name == "main") {
@@ -2495,14 +2481,14 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
} break;
case Entity_Procedure: {
ast_node(pd, ProcDecl, decl->proc_decl);
ast_node(pl, ProcLit, decl->proc_lit);
String original_name = name;
AstNode *body = pd->body;
AstNode *body = pl->body;
if (e->Procedure.is_foreign) {
name = e->token.string; // NOTE(bill): Don't use the mangled name
}
if (pd->link_name.len > 0) {
name = pd->link_name;
if (e->Procedure.link_name.len > 0) {
name = e->Procedure.link_name;
}
if (e == entry_point) {
@@ -2511,11 +2497,11 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
}
// ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
// p->Proc.tags = pd->tags;
// p->Proc.tags = pl->tags;
// ssa_module_add_value(m, e, p);
// HashKey hash_name = hash_string(name);
// if (map_get(&m.members, hash_name) == NULL) {
// if (map_get(&m.members, hash_name) == nullptr) {
// map_set(&m.members, hash_name, p);
// }
} break;
@@ -2562,7 +2548,7 @@ String ssa_mangle_name(ssaModule *m, String path, Entity *e) {
cast(char *)new_name, max_len,
"%.*s-%u.%.*s",
cast(int)base_len, base,
file->id,
cast(u32)file->id,
LIT(name));
if (is_overloaded) {
char *str = cast(char *)new_name + new_name_len-1;
+78 -40
View File
@@ -1,10 +1,12 @@
gb_global gbArena string_buffer_arena = {};
gb_global gbArena string_buffer_arena = {};
gb_global gbAllocator string_buffer_allocator = {};
gb_global gbMutex string_buffer_mutex = {};
void init_string_buffer_memory(void) {
// NOTE(bill): This should be enough memory for file systems
gb_arena_init_from_allocator(&string_buffer_arena, heap_allocator(), gb_megabytes(1));
string_buffer_allocator = gb_arena_allocator(&string_buffer_arena);
gb_mutex_init(&string_buffer_mutex);
}
@@ -14,11 +16,11 @@ struct String {
isize len;
u8 &operator[](isize i) {
GB_ASSERT(0 <= i && i < len);
GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
return text[i];
}
u8 const &operator[](isize i) const {
GB_ASSERT(0 <= i && i < len);
GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
return text[i];
}
};
@@ -36,11 +38,11 @@ struct String16 {
wchar_t *text;
isize len;
wchar_t &operator[](isize i) {
GB_ASSERT(0 <= i && i < len);
GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
return text[i];
}
wchar_t const &operator[](isize i) const {
GB_ASSERT(0 <= i && i < len);
GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
return text[i];
}
};
@@ -65,7 +67,7 @@ gb_inline String16 make_string16(wchar_t *text, isize len) {
}
isize string16_len(wchar_t *s) {
if (s == NULL) {
if (s == nullptr) {
return 0;
}
wchar_t *p = s;
@@ -104,9 +106,8 @@ gb_inline bool str_eq_ignore_case(String a, String b) {
return false;
}
int string_compare(String x, String y) {
if (!(x.len == y.len &&
x.text == y.text)) {
int string_compare(String const &x, String const &y) {
if (x.len != y.len || x.text != y.text) {
isize n, fast, offset, curr_block;
isize *la, *lb;
isize pos;
@@ -148,26 +149,34 @@ GB_COMPARE_PROC(string_cmp_proc) {
return string_compare(x, y);
}
gb_inline bool str_eq(String a, String b) { return a.len == b.len ? gb_memcompare(a.text, b.text, a.len) == 0 : false; }
gb_inline bool str_ne(String a, String b) { return !str_eq(a, b); }
gb_inline bool str_lt(String a, String b) { return string_compare(a, b) < 0; }
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; }
gb_inline bool str_eq(String const &a, String const &b) {
if (a.len != b.len) return false;
for (isize i = 0; i < a.len; i++) {
if (a.text[i] != b.text[i]) {
return false;
}
}
return true;
}
gb_inline bool str_ne(String const &a, String const &b) { return !str_eq(a, b); }
gb_inline bool str_lt(String const &a, String const &b) { return string_compare(a, b) < 0; }
gb_inline bool str_gt(String const &a, String const &b) { return string_compare(a, b) > 0; }
gb_inline bool str_le(String const &a, String const &b) { return string_compare(a, b) <= 0; }
gb_inline bool str_ge(String const &a, String const &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); }
gb_inline bool operator == (String const &a, String const &b) { return str_eq(a, b); }
gb_inline bool operator != (String const &a, String const &b) { return str_ne(a, b); }
gb_inline bool operator < (String const &a, String const &b) { return str_lt(a, b); }
gb_inline bool operator > (String const &a, String const &b) { return str_gt(a, b); }
gb_inline bool operator <= (String const &a, String const &b) { return str_le(a, b); }
gb_inline bool operator >= (String const &a, String const &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)); }
template <isize N> bool operator == (String const &a, char const (&b)[N]) { return str_eq(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator != (String const &a, char const (&b)[N]) { return str_ne(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator < (String const &a, char const (&b)[N]) { return str_lt(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator > (String const &a, char const (&b)[N]) { return str_gt(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator <= (String const &a, char const (&b)[N]) { return str_le(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> bool operator >= (String const &a, char const (&b)[N]) { return str_ge(a, make_string(cast(u8 *)b, N-1)); }
@@ -187,7 +196,6 @@ gb_inline bool str_has_prefix(String s, String prefix) {
gb_inline isize string_extension_position(String str) {
isize dot_pos = -1;
isize i = str.len;
bool seen_dot = false;
while (i --> 0) {
if (str[i] == GB_PATH_SEPARATOR)
break;
@@ -205,6 +213,10 @@ String string_trim_whitespace(String str) {
str.len--;
}
while (str.len > 0 && str[str.len-1] == 0) {
str.len--;
}
while (str.len > 0 && rune_is_whitespace(str[0])) {
str.text++;
str.len--;
@@ -256,11 +268,37 @@ String filename_from_path(String s) {
s.text += j+1;
s.len = i-j-1;
}
return make_string(NULL, 0);
return make_string(nullptr, 0);
}
String remove_directory_from_path(String s) {
isize len = 0;
for (isize i = s.len-1; i >= 0; i--) {
if (s[i] == '/' ||
s[i] == '\\') {
break;
}
len += 1;
}
return substring(s, s.len-len, s.len);
}
String concatenate_strings(gbAllocator a, String x, String y) {
isize len = x.len+y.len;
u8 *data = gb_alloc_array(a, u8, len+1);
gb_memmove(data, x.text, x.len);
gb_memmove(data+x.len, y.text, y.len);
data[len] = 0;
return make_string(data, len);
}
String copy_string(gbAllocator a, String s) {
u8 *data = gb_alloc_array(a, u8, s.len+1);
gb_memmove(data, s.text, s.len);
data[s.len] = 0;
return make_string(data, s.len);
}
@@ -271,7 +309,7 @@ String filename_from_path(String s) {
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);
return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, nullptr, nullptr);
}
#elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX)
@@ -305,20 +343,20 @@ String16 string_to_string16(gbAllocator a, String s) {
wchar_t *text;
if (s.len < 1) {
return make_string16(NULL, 0);
return make_string16(nullptr, 0);
}
len = convert_multibyte_to_widechar(cast(char *)s.text, s.len, NULL, 0);
len = convert_multibyte_to_widechar(cast(char *)s.text, cast(int)s.len, nullptr, 0);
if (len == 0) {
return make_string16(NULL, 0);
return make_string16(nullptr, 0);
}
text = gb_alloc_array(a, wchar_t, len+1);
len1 = convert_multibyte_to_widechar(cast(char *)s.text, s.len, text, len);
len1 = convert_multibyte_to_widechar(cast(char *)s.text, cast(int)s.len, text, cast(int)len);
if (len1 == 0) {
gb_free(a, text);
return make_string16(NULL, 0);
return make_string16(nullptr, 0);
}
text[len] = 0;
@@ -331,21 +369,21 @@ String string16_to_string(gbAllocator a, String16 s) {
u8 *text;
if (s.len < 1) {
return make_string(NULL, 0);
return make_string(nullptr, 0);
}
len = convert_widechar_to_multibyte(s.text, s.len, NULL, 0);
len = convert_widechar_to_multibyte(s.text, cast(int)s.len, nullptr, 0);
if (len == 0) {
return make_string(NULL, 0);
return make_string(nullptr, 0);
}
len += 1; // NOTE(bill): It needs an extra 1 for some reason
text = gb_alloc_array(a, u8, len+1);
len1 = convert_widechar_to_multibyte(s.text, s.len, cast(char *)text, len);
len1 = convert_widechar_to_multibyte(s.text, cast(int)s.len, cast(char *)text, cast(int)len);
if (len1 == 0) {
gb_free(a, text);
return make_string(NULL, 0);
return make_string(nullptr, 0);
}
text[len] = 0;
+184
View File
@@ -0,0 +1,184 @@
struct StringSetFindResult {
isize hash_index;
isize entry_prev;
isize entry_index;
};
struct StringSetEntry {
HashKey key;
isize next;
String value;
};
struct StringSet {
Array<isize> hashes;
Array<StringSetEntry> entries;
};
void string_set_init (StringSet *s, gbAllocator a, isize capacity = 16);
void string_set_destroy(StringSet *s);
void string_set_add (StringSet *s, String str);
bool string_set_exists (StringSet *s, String str);
void string_set_remove (StringSet *s, String str);
void string_set_clear (StringSet *s);
void string_set_grow (StringSet *s);
void string_set_rehash (StringSet *s, isize new_count);
gb_inline void string_set_init(StringSet *s, gbAllocator a, isize capacity) {
array_init(&s->hashes, a);
array_init(&s->entries, a);
}
gb_inline void string_set_destroy(StringSet *s) {
array_free(&s->entries);
array_free(&s->hashes);
}
gb_internal isize string_set__add_entry(StringSet *s, HashKey key) {
StringSetEntry e = {};
e.key = key;
e.next = -1;
array_add(&s->entries, e);
return s->entries.count-1;
}
gb_internal StringSetFindResult string_set__find(StringSet *s, HashKey key) {
StringSetFindResult fr = {-1, -1, -1};
if (s->hashes.count > 0) {
// fr.hash_index = u128_to_i64(key.key % u128_from_i64(s->hashes.count));
fr.hash_index = key.key % s->hashes.count;
fr.entry_index = s->hashes[fr.hash_index];
while (fr.entry_index >= 0) {
if (hash_key_equal(s->entries[fr.entry_index].key, key)) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = s->entries[fr.entry_index].next;
}
}
return fr;
}
gb_internal StringSetFindResult string_set__find_from_entry(StringSet *s, StringSetEntry *e) {
StringSetFindResult fr = {-1, -1, -1};
if (s->hashes.count > 0) {
fr.hash_index = e->key.key % s->hashes.count;
fr.entry_index = s->hashes[fr.hash_index];
while (fr.entry_index >= 0) {
if (&s->entries[fr.entry_index] == e) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = s->entries[fr.entry_index].next;
}
}
return fr;
}
gb_internal b32 string_set__full(StringSet *s) {
return 0.75f * s->hashes.count <= s->entries.count;
}
gb_inline void string_set_grow(StringSet *s) {
isize new_count = ARRAY_GROW_FORMULA(s->entries.count);
string_set_rehash(s, new_count);
}
void string_set_rehash(StringSet *s, isize new_count) {
isize i, j;
StringSet ns = {};
string_set_init(&ns, s->hashes.allocator);
array_resize(&ns.hashes, new_count);
array_reserve(&ns.entries, s->entries.count);
for (i = 0; i < new_count; i++) {
ns.hashes[i] = -1;
}
for (i = 0; i < s->entries.count; i++) {
StringSetEntry *e = &s->entries[i];
StringSetFindResult fr;
if (ns.hashes.count == 0) {
string_set_grow(&ns);
}
fr = string_set__find(&ns, e->key);
j = string_set__add_entry(&ns, e->key);
if (fr.entry_prev < 0) {
ns.hashes[fr.hash_index] = j;
} else {
ns.entries[fr.entry_prev].next = j;
}
ns.entries[j].next = fr.entry_index;
ns.entries[j].value = e->value;
if (string_set__full(&ns)) {
string_set_grow(&ns);
}
}
string_set_destroy(s);
*s = ns;
}
gb_inline bool string_set_exists(StringSet *s, String str) {
HashKey key = hash_string(str);
isize index = string_set__find(s, key).entry_index;
return index >= 0;
}
void string_set_add(StringSet *s, String str) {
isize index;
StringSetFindResult fr;
HashKey key = hash_string(str);
if (s->hashes.count == 0) {
string_set_grow(s);
}
fr = string_set__find(s, key);
if (fr.entry_index >= 0) {
index = fr.entry_index;
} else {
index = string_set__add_entry(s, key);
if (fr.entry_prev >= 0) {
s->entries[fr.entry_prev].next = index;
} else {
s->hashes[fr.hash_index] = index;
}
}
s->entries[index].value = str;
if (string_set__full(s)) {
string_set_grow(s);
}
}
void string_set__erase(StringSet *s, StringSetFindResult fr) {
StringSetFindResult last;
if (fr.entry_prev < 0) {
s->hashes[fr.hash_index] = s->entries[fr.entry_index].next;
} else {
s->entries[fr.entry_prev].next = s->entries[fr.entry_index].next;
}
if (fr.entry_index == s->entries.count-1) {
array_pop(&s->entries);
return;
}
s->entries[fr.entry_index] = s->entries[s->entries.count-1];
last = string_set__find(s, s->entries[fr.entry_index].key);
if (last.entry_prev >= 0) {
s->entries[last.entry_prev].next = fr.entry_index;
} else {
s->hashes[last.hash_index] = fr.entry_index;
}
}
void string_set_remove(StringSet *s, String str) {
HashKey key = hash_string(str);
StringSetFindResult fr = string_set__find(s, key);
if (fr.entry_index >= 0) {
string_set__erase(s, fr);
}
}
gb_inline void string_set_clear(StringSet *s) {
array_clear(&s->hashes);
array_clear(&s->entries);
}
+17 -6
View File
@@ -8,6 +8,7 @@ struct Timings {
TimeStamp total;
Array<TimeStamp> sections;
u64 freq;
f64 total_time_seconds;
};
@@ -103,9 +104,13 @@ void timings_start_section(Timings *t, String label) {
array_add(&t->sections, make_time_stamp(label));
}
f64 time_stamp_as_ms(TimeStamp ts, u64 freq) {
f64 time_stamp_as_second(TimeStamp ts, u64 freq) {
GB_ASSERT_MSG(ts.finish >= ts.start, "time_stamp_as_ms - %.*s", LIT(ts.label));
return 1000.0 * cast(f64)(ts.finish - ts.start) / cast(f64)freq;
return cast(f64)(ts.finish - ts.start) / cast(f64)freq;
}
f64 time_stamp_as_ms(TimeStamp ts, u64 freq) {
return 1000.0*time_stamp_as_second(ts, freq);
}
void timings_print_all(Timings *t) {
@@ -123,16 +128,22 @@ void timings_print_all(Timings *t) {
GB_ASSERT(max_len <= gb_size_of(SPACES)-1);
gb_printf("%.*s%.*s - %.3f ms\n",
t->total_time_seconds = time_stamp_as_second(t->total, t->freq);
f64 total_ms = time_stamp_as_ms(t->total, t->freq);
gb_printf("%.*s%.*s - % 9.3f ms - %6.2f%%\n",
LIT(t->total.label),
cast(int)(max_len-t->total.label.len), SPACES,
time_stamp_as_ms(t->total, t->freq));
total_ms,
cast(f64)100.0);
for_array(i, t->sections) {
TimeStamp ts = t->sections[i];
gb_printf("%.*s%.*s - %.3f ms\n",
f64 section_ms = time_stamp_as_ms(ts, t->freq);
gb_printf("%.*s%.*s - % 9.3f ms - %6.2f%%\n",
LIT(ts.label),
cast(int)(max_len-ts.label.len), SPACES,
time_stamp_as_ms(ts, t->freq));
section_ms, 100*section_ms/total_ms);
}
}
+82 -62
View File
@@ -37,26 +37,25 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
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_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_Inc, "++"), \
TOKEN_KIND(Token_Dec, "--"), \
TOKEN_KIND(Token_Undef, "---"), \
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_DoubleArrowRight, "=>"), \
TOKEN_KIND(Token_Undef, "---"), \
\
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
TOKEN_KIND(Token_CmpEq, "=="), \
@@ -77,26 +76,23 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
TOKEN_KIND(Token_Semicolon, ";"), \
TOKEN_KIND(Token_Period, "."), \
TOKEN_KIND(Token_Comma, ","), \
TOKEN_KIND(Token_Ellipsis, ".."), \
TOKEN_KIND(Token_HalfClosed, "..<"), \
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_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_export, "export"), \
TOKEN_KIND(Token_foreign, "foreign"), \
TOKEN_KIND(Token_foreign_library, "foreign_library"), \
TOKEN_KIND(Token_foreign_system_library, "foreign_system_library"), \
TOKEN_KIND(Token_type, "type"), \
TOKEN_KIND(Token_when, "when"), \
TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_else, "else"), \
TOKEN_KIND(Token_for, "for"), \
TOKEN_KIND(Token_switch, "switch"), \
TOKEN_KIND(Token_in, "in"), \
TOKEN_KIND(Token_match, "match"), \
TOKEN_KIND(Token_do, "do"), \
TOKEN_KIND(Token_case, "case"), \
TOKEN_KIND(Token_break, "break"), \
TOKEN_KIND(Token_continue, "continue"), \
@@ -107,21 +103,26 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
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_map, "map"), \
TOKEN_KIND(Token_static, "static"), \
TOKEN_KIND(Token_dynamic, "dynamic"), \
TOKEN_KIND(Token_map, "map"), \
TOKEN_KIND(Token_cast, "cast"), \
TOKEN_KIND(Token_transmute, "transmute"), \
TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_inline, "inline"), \
TOKEN_KIND(Token_no_inline, "no_inline"), \
TOKEN_KIND(Token_context, "context"), \
TOKEN_KIND(Token_push_context, "push_context"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
TOKEN_KIND(Token_size_of, "size_of"), \
TOKEN_KIND(Token_align_of, "align_of"), \
TOKEN_KIND(Token_offset_of, "offset_of"), \
TOKEN_KIND(Token_type_of, "type_of"), \
TOKEN_KIND(Token_type_info_of, "type_info_of"), \
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, "")
@@ -144,21 +145,27 @@ struct TokenPos {
isize column;
};
i32 token_pos_cmp(TokenPos a, TokenPos b) {
if (a.line == b.line) {
if (a.column == b.column) {
isize min_len = gb_min(a.file.len, b.file.len);
return gb_memcompare(a.file.text, b.file.text, min_len);
}
TokenPos token_pos(String file, isize line, isize column) {
TokenPos pos = {file, line, column};
return pos;
}
i32 token_pos_cmp(TokenPos const &a, TokenPos const &b) {
if (a.line != b.line) {
return (a.line < b.line) ? -1 : +1;
}
if (a.column != b.column) {
return (a.column < b.column) ? -1 : +1;
}
return (a.line < b.line) ? -1 : +1;
return string_compare(a.file, b.file);
}
bool token_pos_eq(TokenPos a, TokenPos b) {
return token_pos_cmp(a, b) == 0;
}
bool operator==(TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a, b) == 0; }
bool operator!=(TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a, b) != 0; }
bool operator< (TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a, b) < 0; }
bool operator<=(TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a, b) <= 0; }
bool operator> (TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a, b) > 0; }
bool operator>=(TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a, b) >= 0; }
struct Token {
TokenKind kind;
@@ -192,7 +199,7 @@ void 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)) {
if (global_error_collector.prev != token.pos) {
global_error_collector.prev = token.pos;
gb_printf_err("%.*s(%td:%td) Warning: %s\n",
LIT(token.pos.file), token.pos.line, token.pos.column,
@@ -206,7 +213,7 @@ void error_va(Token token, char *fmt, va_list va) {
gb_mutex_lock(&global_error_collector.mutex);
global_error_collector.count++;
// NOTE(bill): Duplicate error, skip it
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
if (global_error_collector.prev != token.pos) {
global_error_collector.prev = token.pos;
gb_printf_err("%.*s(%td:%td) %s\n",
LIT(token.pos.file), token.pos.line, token.pos.column,
@@ -222,7 +229,7 @@ void syntax_error_va(Token token, char *fmt, va_list va) {
gb_mutex_lock(&global_error_collector.mutex);
global_error_collector.count++;
// NOTE(bill): Duplicate error, skip it
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
if (global_error_collector.prev != token.pos) {
global_error_collector.prev = token.pos;
gb_printf_err("%.*s(%td:%td) Syntax Error: %s\n",
LIT(token.pos.file), token.pos.line, token.pos.column,
@@ -238,7 +245,7 @@ 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)) {
if (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,
@@ -423,18 +430,22 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
TokenizerInitError err = TokenizerInit_None;
char *c_str = gb_alloc_array(heap_allocator(), char, fullpath.len+1);
defer (gb_free(heap_allocator(), c_str));
gb_memcopy(c_str, fullpath.text, fullpath.len);
c_str[fullpath.len] = '\0';
// TODO(bill): Memory map rather than copy contents
gbFileContents fc = gb_file_read_contents(heap_allocator(), true, c_str);
gb_zero_item(t);
if (fc.data != NULL) {
t->fullpath = fullpath;
t->line_count = 1;
if (fc.data != nullptr) {
t->start = cast(u8 *)fc.data;
t->line = t->read_curr = t->curr = t->start;
t->end = t->start + fc.size;
t->fullpath = fullpath;
t->line_count = 1;
advance_to_next_rune(t);
if (t->curr_rune == GB_RUNE_BOM) {
@@ -445,6 +456,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
} else {
gbFile f = {};
gbFileError file_err = gb_file_open(&f, c_str);
defer (gb_file_close(&f));
switch (file_err) {
case gbFileError_Invalid: err = TokenizerInit_Invalid; break;
@@ -455,16 +467,13 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
if (err == TokenizerInit_None && gb_file_size(&f) == 0) {
err = TokenizerInit_Empty;
}
gb_file_close(&f);
}
gb_free(heap_allocator(), c_str);
return err;
}
gb_inline void destroy_tokenizer(Tokenizer *t) {
if (t->start != NULL) {
if (t->start != nullptr) {
gb_free(heap_allocator(), t->start);
}
for_array(i, t->allocated_strings) {
@@ -881,10 +890,10 @@ Token tokenizer_get_token(Tokenizer *t) {
token.kind = Token_Period; // Default
if (t->curr_rune == '.') { // Could be an ellipsis
advance_to_next_rune(t);
token.kind = Token_Ellipsis;
if (t->curr_rune == '<') {
token.kind = Token_HalfClosed;
if (t->curr_rune == '.') {
advance_to_next_rune(t);
token.kind = Token_HalfClosed;
token.kind = Token_Ellipsis;
}
}
break;
@@ -912,10 +921,20 @@ Token tokenizer_get_token(Tokenizer *t) {
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_Eq;
if (t->curr_rune == '>') {
advance_to_next_rune(t);
token.kind = Token_DoubleArrowRight;
} else if (t->curr_rune == '=') {
advance_to_next_rune(t);
token.kind = Token_CmpEq;
}
break;
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
// case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
case '+': token.kind = token_kind_variant2(t, Token_Add, Token_AddEq); break;
case '-':
token.kind = Token_Sub;
if (t->curr_rune == '=') {
@@ -923,7 +942,7 @@ Token tokenizer_get_token(Tokenizer *t) {
token.kind = Token_SubEq;
} else if (t->curr_rune == '-') {
advance_to_next_rune(t);
token.kind = Token_Dec;
token.kind = Token_Invalid;
if (t->curr_rune == '-') {
advance_to_next_rune(t);
token.kind = Token_Undef;
@@ -970,6 +989,7 @@ Token tokenizer_get_token(Tokenizer *t) {
case '<':
if (t->curr_rune == '-') {
advance_to_next_rune(t);
token.kind = Token_ArrowLeft;
} else {
token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
+778 -720
View File
File diff suppressed because it is too large Load Diff