Compare commits

...

132 Commits

Author SHA1 Message Date
Ginger Bill 7057034b75 v0.2.0 2017-04-30 16:28:13 +01:00
Ginger Bill 1430ca30a3 Fix subtype polymorphism implicit conversion 2017-04-30 16:22:24 +01:00
Ginger Bill e63393e394 Add type assertion for any 2017-04-30 15:29:46 +01:00
Ginger Bill 784f3ecf7e Syntax change: cast(T)x => T(x); union_cast(T)x => x.(T); transmute(T)x => transmute(T, x); y:=^x => y:=&x;
Sorry for all the code breaking in this commit :(
2017-04-30 15:09:36 +01:00
Ginger Bill 54ea70df98 Fix issues #50 and #55 2017-04-29 20:06:29 +01:00
Ginger Bill c7575164cc Revert to previous demo 2017-04-28 11:03:19 +01:00
Ginger Bill 99125dc743 Fix issue #51; begin work on atomic types 2017-04-28 11:01:46 +01:00
Ginger Bill b78e970698 Fix issue #48 dependency issue 2017-04-26 23:51:13 +01:00
Ginger Bill 5b8be25938 fmt.String_Buffer, Fix issue #44, Tweak overloading rules 2017-04-26 19:43:17 +01:00
Ginger Bill 29efdc5fc1 Fix initialization of global any types 2017-04-25 15:02:35 +01:00
Ginger Bill a80872b60d Fix checking if a procedure terminates for for loops. 2017-04-25 09:46:30 +01:00
Ginger Bill 822bb51b55 Swap memory layout of any 2017-04-23 18:03:29 +01:00
Ginger Bill c2fa79012e Fix find_using_index_expr 2017-04-23 11:04:22 +01:00
Ginger Bill 3fd37c6dc5 Internal change: IntervalExpr is now a BinaryExpr 2017-04-22 10:10:49 +01:00
Ginger Bill 0ea815db49 Fix constant bounds checking for slicing 2017-04-22 09:40:32 +01:00
Ginger Bill 91ed51ff5c Continue work on custom SSA; Fix double declaration in when statements 2017-04-21 17:56:29 +01:00
Ginger Bill 4d0afc55c3 Making slicing a little more robust 2017-04-21 10:03:27 +01:00
Ginger Bill 9a1566d665 Interval expressions for match statements 2017-04-21 00:13:20 +01:00
Ginger Bill a713e33007 Change interval syntax: .. open range, ..< half-closed range 2017-04-20 23:22:45 +01:00
Ginger Bill c5411a25a9 Change Union representation for LLVM IR; fix dynamic array size 2017-04-19 18:58:23 +01:00
Ginger Bill 95692fda52 Fix bug with union literal checking crashing the compiler 2017-04-18 21:20:41 +01:00
Ginger Bill 813a028ed0 Fix procedure calls from non-regular addressing modes 2017-04-17 22:17:16 +01:00
Ginger Bill 0c22081e5f Fix error printing for basic directives 2017-04-17 19:58:43 +01:00
Ginger Bill 6d9fadf351 Make the ABI changes only affect windows
TODO: decide upon rules for *nix systems
2017-04-17 12:01:04 +01:00
Ginger Bill a213061f33 Change tag checking order 2017-04-16 23:08:48 +01:00
Ginger Bill d1a0a46141 Fix issue #37 for procedure literal scopes 2017-04-16 22:48:29 +01:00
Ginger Bill 187b186112 Add #require_results for procedures 2017-04-16 22:30:48 +01:00
Ginger Bill 5041a35b95 Fix ir printing of constant slices 2017-04-16 22:07:26 +01:00
Ginger Bill 92d4fcedee Update ir type aggregate rules for transmute 2017-04-16 16:44:45 +01:00
Ginger Bill c69df7cd3a Exit program if there were syntax errors 2017-04-16 16:38:05 +01:00
Ginger Bill 67d8f48553 Calling convention, change from bitcast to transmute 2017-04-16 16:28:39 +01:00
Ginger Bill b4a339f2e3 Call convention, pass by pointer: pointers are 16 byte aligned 2017-04-16 10:54:05 +01:00
Ginger Bill 0d7bf58b60 Revert to the old demo 2017-04-16 10:40:24 +01:00
Ginger Bill abb9930725 IR emit C ABI compatible types for calling conventions (Only for x86/amd64 like processors at the moment) 2017-04-16 10:38:42 +01:00
Ginger Bill 169310a9f6 Fix non-ascii function parameters in LLVM IR 2017-04-15 23:14:14 +01:00
Ginger Bill 23a0a6de4b Add parse_int; Fix union bugs with size, alignment, and recursive definition checking 2017-04-14 21:47:59 +01:00
Ginger Bill 0d2dbee84e Fix addressing mode rules for match in statements 2017-04-13 22:42:36 +01:00
Ginger Bill d8d22e34dd Fix fmt for type; remove dead stuff 2017-04-13 19:29:17 +01:00
Ginger Bill 627ee002e8 Fix: map key not getting transferred on rehash 2017-04-11 23:11:05 +01:00
Ginger Bill 8e73d1ce1f Fix map bug which removed N values from the beginning 2017-04-11 22:43:33 +01:00
Ginger Bill b53d16d1d5 Remove debug text 2017-04-11 21:24:10 +01:00
Ginger Bill f5819eafa9 Fix map assignment bug due to growth 2017-04-11 21:13:21 +01:00
Ginger Bill 5916e71d4f Fix slicing bug on dynamic arrays 2017-04-11 16:00:49 +01:00
Ginger Bill 913b9b6447 Remove odin.exe 2017-04-10 22:30:38 +01:00
Ginger Bill 8e55bb2a6c Fix append crash when pointer is passed 2017-04-10 21:09:04 +01:00
root 98d493504b Fix segfault with heap allocation 2017-04-10 20:48:56 +01:00
Ginger Bill 3a3202fbc6 Change code to match original MSVC 2017-04-10 13:27:09 +01:00
Ginger Bill aaf355e750 Basic Linux Build! 2017-04-09 22:33:32 +01:00
gingerBill 0683d2b4f4 Merge pull request #33 from zangent/master
Base of *nix port
2017-04-09 22:01:22 +01:00
Ginger Bill d7fdd3d7b8 Add raw.odin
Forgot to do this in the previous commit, whoops :P
2017-04-09 11:45:41 +01:00
Ginger Bill 83ebb24015 Move to Raw_* types to raw.odin; Add size and align members to Type_Info 2017-04-07 14:05:28 +01:00
Ginger Bill 70f9cacdce Fix cast to any of untyped constants 2017-04-07 09:55:19 +01:00
Zachary Pierson 6b33b254e9 Merged from upstream, fixed 'args' name colission 2017-04-06 18:14:42 -05:00
Zachary Pierson c0019cc305 Merge https://github.com/gingerBill/Odin 2017-04-06 17:50:23 -05:00
Ginger Bill c067a1f0ec Fix ir bugs: global variable names, untyped to any assignment 2017-04-06 11:12:11 +01:00
Zachary Pierson 63345cd0d8 Bridged a bugfix from os_windows to other os's. 2017-04-04 18:51:36 -05:00
Zachary Pierson e41d6261c2 Merge https://github.com/gingerBill/Odin 2017-04-04 18:46:05 -05:00
Ginger Bill 3e80411d37 Fix issue #31; Removed down_cast 2017-04-04 21:54:55 +01:00
Zachary Pierson f952c7c747 Merge https://github.com/gingerBill/Odin 2017-04-03 00:08:00 -05:00
Zachary Pierson 642256f9ba I accidentally left debug stuff (like abs paths) in! Whoops! 2017-04-02 18:46:31 -05:00
Zachary Pierson c9c82da1f3 It's terrible, but I added _some_ form of launch args support for Linux/macOS 2017-04-02 18:42:58 -05:00
Ginger Bill 382a5ca6a2 Update and regression test old demos 2017-04-02 22:03:52 +01:00
Ginger Bill 96e8bb5b6f Add website to README.md 2017-04-02 20:20:14 +01:00
Ginger Bill 22afac2b90 Update README.md with latest demo 2017-04-02 20:10:56 +01:00
Ginger Bill 01da0d1377 Fix make for dynamic arrays 2017-04-02 18:28:45 +01:00
Ginger Bill 8ce58573df len, cap, make; remove .count, .capacity, new_slice 2017-04-02 18:16:45 +01:00
Zachary Pierson ce0d874efd Merge https://github.com/gingerBill/Odin 2017-04-02 03:29:51 -05:00
Ginger Bill 2c8b99337b Fix conj 2017-04-01 22:55:33 +01:00
Ginger Bill 5008e2c88b Add Quaternions: quaternion128, quaternion256 2017-04-01 22:41:23 +01:00
Ginger Bill 90fc9abeae Fix constant conversion for complex numbers from integers 2017-04-01 12:12:08 +01:00
Ginger Bill dc303cde21 Complex numbers: complex64 complex128 2017-04-01 12:07:41 +01:00
Zachary Pierson 24b33374b7 Reverted the main proc changed, after a chat with Bill about better solutions. 2017-03-31 05:31:45 -05:00
Zachary Pierson 3315dc7f25 Literally just a commit to revert a previous one. 2017-03-31 05:30:09 -05:00
Zachary Pierson 77b3295de5 Added checking for params and return values in main 2017-03-30 01:21:05 -05:00
Zachary Pierson 1349aa6f2c Merge https://github.com/gingerBill/Odin, cleaned up a bit, fixed the object file version message on macOS 2017-03-30 00:26:46 -05:00
Ginger Bill a75ccb6fbc v0.1.3 2017-03-27 20:32:36 +01:00
Zachary Pierson 7a28827602 Forgot to include stdio.h since Win32 won't resolve it otherwise. 2017-03-21 19:30:54 -05:00
Zachary Pierson c61015b1fe Updated shell.bat for Visual Studio 2017 2017-03-21 19:17:41 -05:00
Zac Pierson e935f8e2ff Fixed os_linux and os_x read_entire_file function not null-terminating data. 2017-03-21 16:00:11 -05:00
Zac Pierson 690c682847 Remember kids, always test your code. There was a variable name colission in dlsym D: 2017-03-21 14:57:09 -05:00
Zac Pierson f541dd40db Fixed some memory leaks and made os_* use strings.odin 2017-03-21 14:54:29 -05:00
Zac Pierson c7bb861d3c Merge https://github.com/gingerBill/Odin
"Fixed" a proc overload bug. Still needs a *real* fix.
2017-03-21 14:16:42 -05:00
Ginger Bill 188b290dd5 Update version number 2017-03-19 21:03:56 +00:00
Ginger Bill c6ff961088 Add base 12 in strconv.odin 2017-03-19 21:03:29 +00:00
Ginger Bill c26990c22d Multiple type cases for match in 2017-03-19 20:55:39 +00:00
Ginger Bill c34d839f9f Add named branches for match statements 2017-03-19 17:36:08 +00:00
Ginger Bill 5562364a98 Add branch labels for loops; using list 2017-03-19 16:59:11 +00:00
Ginger Bill 32150e401e Update gb.h 2017-03-17 12:30:59 +00:00
Ginger Bill aaec8bf423 windows.odin TYPE_NAME to Type_Name; More SSA work and SSA printing for debugging 2017-03-12 16:42:51 +00:00
Ginger Bill 0fcbda951a Finally fix signed integer conversion and printing 2017-03-10 10:34:25 +00:00
Ginger Bill e2734a2dc6 Begin work on the custom backend 2017-03-05 21:22:33 +00:00
Ginger Bill 5adfbec847 Refactoring of code: remove make prefix on many procedures 2017-03-05 15:03:01 +00:00
Ginger Bill 4ef4605d6d Move files to misc 2017-03-03 11:20:22 +00:00
Ginger Bill 2aa402f462 Cleanup root directory 2017-03-03 11:19:12 +00:00
Ginger Bill 00f6bee454 Update README.md 2017-03-03 11:15:34 +00:00
Zac Pierson d890731716 Merge https://github.com/gingerBill/Odin 2017-03-02 15:41:19 -06:00
Zachary Pierson 231ea8b026 Merge https://github.com/gingerBill/Odin 2017-02-27 23:25:47 -06:00
Zachary Pierson 5bbdb3a3a3 Merge https://github.com/gingerBill/Odin 2017-02-25 02:07:58 -06:00
Zachary Pierson 27aa07307b Merge https://github.com/gingerBill/Odin 2017-02-24 15:53:56 -06:00
Zac Pierson 20b9f1ff59 Added getenv to the *nix stdlib. 2017-02-23 15:29:41 -06:00
Zac Pierson 561c583b3f Merge https://github.com/gingerBill/Odin 2017-02-22 10:57:30 -06:00
Zac Pierson 8d5896ab7e Merge https://github.com/gingerBill/Odin 2017-02-20 10:14:52 -06:00
Zac Pierson 802b1a70f8 Fixed an error in function naming in os_linux 2017-02-15 11:20:11 -06:00
Zac Pierson aaa4dd5c36 Merge https://github.com/gingerBill/odin 2017-02-15 10:21:38 -06:00
Zachary Pierson 9d19ee7e4c Changed standard libraries for MacOS and Linux to be closer to os_windows. 2017-02-12 18:25:58 -06:00
Zachary Pierson 8df3175f10 Updated Linux standard library to convert c strs 2017-02-12 17:22:27 -06:00
Zachary Pierson ebb10e5597 One of the warning flags was misspelled. Oops! 2017-02-12 16:09:21 -06:00
Zachary Pierson 047f883078 Updated warning removal list, and made system_exec_command_line_app in main.c return the exit code. 2017-02-12 16:08:09 -06:00
Zachary Pierson 320c22e08a Merge https://github.com/gingerBill/Odin 2017-02-12 16:04:13 -06:00
Zachary Pierson a9398bf30f Tested MacOS. If a commit doesn't follow in 15 minutes, Linux works too! 2017-02-12 00:21:25 -06:00
Zachary Pierson 7829421085 Fixed Windows (updated gb.h) | Need to test on MacOS and Linux now! 2017-02-11 23:52:56 -06:00
Zachary Pierson c50aabd916 Merging from gingerBill's master 2017-02-11 23:35:07 -06:00
Zachary Pierson 3f3122bccc Temporary fix for an Odin bug. 2017-02-11 18:54:54 -06:00
Zachary Pierson fc1a006de1 Added support for reading files on MacOS and Linux 2017-02-11 17:24:47 -06:00
Zachary Pierson 754b368140 Added dynamic library loading to Linux and MacOS's standard libraries. 2017-02-11 15:09:53 -06:00
Zachary Pierson a49e888ce6 Merge https://github.com/gingerBill/Odin 2017-02-11 13:48:16 -06:00
Zac Pierson 99c663d9f3 Questioning whether MacOS libraries should be .dylib or .so 2017-02-11 01:10:03 -06:00
Zachary Pierson afac95e092 Oh, I left math.odin open when I merged gingerBill's changes. Oops. Updated to his version. 2017-02-11 00:33:12 -06:00
Zachary Pierson 05486f9fa3 I'm not sure what I changed here, to be honest. I've ctrl-z'd everything, but git's still complaining. 2017-02-11 00:30:04 -06:00
Zachary Pierson cad46ae51c Merge https://github.com/gingerBill/Odin 2017-02-10 23:41:23 -06:00
Zachary Pierson 3424b2badd Added ability to use -framework on MacOS 2017-02-10 23:33:30 -06:00
Zachary Pierson 3445a28c4a Code quality upkeep. Fixed a broken thread finding assembly instruction in gb.h 2017-02-09 01:40:45 -06:00
Zac Pierson 7f6b83d50c Fixed gb.h - the file handle for /proc/cpuinfo is needed to read chars. 2017-02-08 11:59:54 -06:00
Zac Pierson 72d4bfb32a Merge https://github.com/gingerBill/Odin 2017-02-08 11:50:33 -06:00
Zachary Pierson 37f7630a9e Updated README.md to reflect Linux's dependancy on clang for now. 2017-02-07 23:33:36 -06:00
Zachary Pierson 73c5c5d5d3 Linker on MacOS and GNU/Linux now includes foreign_system_libraries. Fixed foreign_system_library not respecting 'when' condition. 2017-02-07 23:21:52 -06:00
Zac Pierson 584869730a Linux can build now! Woo! 2017-02-07 15:07:20 -06:00
Zachary Pierson 90ab448bca Modified the test program to see where the compiler inserted the code. 2017-02-07 12:26:15 -06:00
Zachary Pierson 8becbdc1b2 Added a very basic Linux standard library shamelessly stolen from the MacOS one.
Made Linux (almost) work. The generated binaries segfault, but it's so close I can almost taste it.
2017-02-07 00:28:21 -06:00
Zachary Pierson eeeb90c441 MacOS is able to run Hello World! 2017-02-06 21:47:58 -06:00
Zac Pierson 6efd400c98 Updated build script in an attempt to track down a segfault. It's not helping, though. 2017-02-06 15:45:51 -06:00
Zac Pierson 5cfa4ba580 Added Linux functions throughout the code, but it segfaults. 2017-02-06 12:26:41 -06:00
58 changed files with 11195 additions and 4573 deletions
+9 -4
View File
@@ -251,8 +251,13 @@ paket-files/
# Project Specific
# - Windows
*.sln
!misc/llvm-bim/lli.exe
!misc/llvm-bim/opt.exe
builds
bin
builds/
bin/
*.exe
# - Linux/MacOS
odin
odin.dSYM
+22 -6
View File
@@ -1,4 +1,4 @@
<img src="logo-slim.png" alt="Odin logo" height="74">
<img src="misc/logo-slim.png" alt="Odin logo" height="74">
# The Odin Programming Language
@@ -10,6 +10,8 @@ The Odin programming language is fast, concise, readable, pragmatic and open sou
* metaprogramming
* designed for good programmers
Website: [https://odin.handmade.network/](https://odin.handmade.network/)
## Demonstrations:
* First Talk & Demo
- [Talk](https://youtu.be/TMCkT-uASaE?t=338)
@@ -19,14 +21,28 @@ The Odin programming language is fast, concise, readable, pragmatic and open sou
* [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s)
* [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78)
* [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
* [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
* [Context Types, Unexported Entities, Labelled Branches](https://www.youtube.com/watch?v=CkHVwT1Qk-g)
## Requirements to build and run
* Windows
* x86-64
* MSVC 2015 installed (C99 support)
* Requires MSVC's link.exe as the linker
- run `vcvarsall.bat` to setup the path
- Windows
* x86-64
* MSVC 2015 installed (C99 support)
* [LLVM binaries](https://github.com/gingerBill/Odin/releases/tag/llvm-4.0-windows) for `opt.exe` and `llc.exe`
* Requires MSVC's link.exe as the linker
* run `vcvarsall.bat` to setup the path
- MacOS
* x86-64
* LLVM explicitly installed (`brew install llvm`)
* XCode installed (for the linker)
- GNU/Linux
* x86-64
* Build tools (ld)
* LLVM installed
* Clang installed (temporary - this is calling the linker for now)
## Warnings
+4 -8
View File
@@ -45,15 +45,11 @@ del *.ilk > NUL 2> NUL
cl %compiler_settings% "src\main.c" ^
/link %linker_settings% -OUT:%exe_name% ^
&& odin run code/demo.odin
rem && odin build code/Jaze/src/main.odin
rem && odin build_dll code/example.odin ^
rem odin run code/demo.odin
rem && odin build code/metagen.odin ^
rem && call "code\metagen.exe" "src\ast_nodes.metagen"
rem && odin run code/Jaze/src/main.odin
rem pushd src\asm
rem nasm hellope.asm -fwin64 -o hellope.obj ^
rem && cl /nologo hellope.obj /link kernel32.lib /entry:main ^
rem && hellope.exe
rem popd
del *.obj > NUL 2> NUL
:end_of_build
Executable
+24
View File
@@ -0,0 +1,24 @@
#!/bin/bash
release_mode=0
warnings_to_disable="-std=c11 -Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined"
libraries="-pthread -ldl -lm"
other_args=""
compiler="clang"
if [ "$release_mode" -eq "0" ]; then
other_args="${other_args} -g -fno-inline-functions"
fi
if [[ "$(uname)" == "Darwin" ]]; then
# Set compiler to clang on MacOS
# MacOS provides a symlink to clang called gcc, but it's nice to be explicit here.
compiler="clang"
other_args="${other_args} -liconv"
fi
${compiler} src/main.c ${warnings_to_disable} ${libraries} ${other_args} -o odin
./odin run code/demo.odin
+10 -159
View File
@@ -1,167 +1,18 @@
#import "fmt.odin";
#import "atomic.odin";
#import "hash.odin";
#import "math.odin";
#import "mem.odin";
#import "opengl.odin";
#import "os.odin";
#import "strconv.odin";
#import "sync.odin";
main :: proc() {
// buf: [64]byte;
// // len := strconv.generic_ftoa(buf[..], 123.5431, 'f', 4, 64);
// x := 624.123;
// s := strconv.format_float(buf[..], x, 'f', 6, 64);
// fmt.println(s);
// fmt.printf("%3d\n", 102);
immutable program := "+ + * - /";
accumulator := 0;
s := new_slice(int, 0, 10);
append(s, 1, 2, 6, 3, 6, 5, 5, 5, 5, 1, 2);
fmt.println(s);
when false {
/*
Version 0.1.1
Added:
* Dynamic Arrays `[dynamic]Type`
* Dynamic Maps `map[Key]Value`
* Dynamic array and map literals
* Custom struct alignemnt `struct #align 8 { bar: i8 }`
* Allow `_` in numbers
* Variadic `append`
* fmt.sprint*
* Entities prefixes with an underscore do not get exported on imports
* Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps
* enum types have an implict `names` field, a []string of all the names in that enum
* immutable variables are "completely immutable" - rules need a full explanation
* `slice_to_bytes` - convert any slice to a slice of bytes
* `union_cast` allows for optional ok check
* Record type field `names` (struct/raw_union/enum)
* ?: ternary operator
* Unions with variants and common fields
* New built-in procedures
- `delete` to delete map entries `delete(m, key)`
- `clear` to clear dynamic maps and arrays `clear(map_or_array)`
- `reserve` to reserve space for the dynamic maps and arrays `reserve(map_or_array)`
* Unexported entities and fields using an underscore prefix
Removed:
* Maybe/option types
* Remove `type` keyword and other "reserved" keywords
* `compile_assert` and `assert`return the value of the condition for semantic reasons
Changed:
* thread_local -> #thread_local
* #include -> #load
* Files only get checked if they are actually used
* match x in y {} // For type match statements
* Version numbering now starts from 0.1.0 and uses the convention:
- major.minor.patch
* Core library additions to Windows specific stuff
Fixes:
* Many fmt.* fixes
* Overloading bug due to comparison of named types
* Overloading bug due to `#import .` collision
* disallow a `cast` from pointers of unions
* Minor bugs in generated IR code for slices
To come very Soon:
* Linux and OS X builds (unofficial ones do exist already)
*/
{
}
{
Fruit :: enum {
APPLE,
BANANA,
COCONUT,
for token in program {
match token {
case '+': accumulator += 1;
case '-': accumulator -= 1;
case '*': accumulator *= 2;
case '/': accumulator /= 2;
default: // Ignore everything else
}
fmt.println(Fruit.names);
}
{
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);
}
{
x: [dynamic]f64;
reserve(x, 16);
defer free(x);
append(x, 2_000_000.500_000, 3, 5, 7);
for p, i in x {
if i > 0 { fmt.print(", "); }
fmt.print(p);
}
fmt.println();
}
{
x := [dynamic]f64{2_000_000.500_000, 3, 5, 7};
defer free(x);
fmt.println(x);
}
{
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.printf("The program \"%s\" calculates the value %d\n", program, accumulator);
}
}
+46 -39
View File
@@ -1,4 +1,5 @@
#import "win32.odin" when ODIN_OS == "windows";
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
#import wgl "sys/wgl.odin" when ODIN_OS == "windows";
#import "fmt.odin";
#import "math.odin";
#import "os.odin";
@@ -12,11 +13,11 @@ time_now :: proc() -> f64 {
counter: i64;
win32.QueryPerformanceCounter(^counter);
result := counter as f64 / win32_perf_count_freq as f64;
result := cast(f64)counter / cast(f64)win32_perf_count_freq;
return result;
}
win32_print_last_error :: proc() {
err_code := win32.GetLastError() as int;
err_code := cast(int)win32.GetLastError();
if err_code != 0 {
fmt.println("GetLastError: %", err_code);
}
@@ -24,42 +25,42 @@ win32_print_last_error :: proc() {
// Yuk!
to_c_string :: proc(s: string) -> []u8 {
c_str := new_slice(u8, s.count+1);
copy(c_str, s as []byte);
c_str[s.count] = 0;
c_str := make([]u8, len(s)+1);
copy(c_str, cast([]byte)s);
c_str[len(s)] = 0;
return c_str;
}
Window :: struct {
width, height: int;
wc: win32.WNDCLASSEXA;
dc: win32.HDC;
hwnd: win32.HWND;
opengl_context, rc: win32.HGLRC;
c_title: []u8;
width, height: int,
wc: win32.WndClassExA,
dc: win32.Hdc,
hwnd: win32.Hwnd,
opengl_context, rc: wgl.Hglrc,
c_title: []u8,
}
make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) -> (Window, bool) {
make_window :: proc(title: string, msg, height: int, window_proc: win32.Wnd_Proc) -> (Window, bool) {
using win32;
w: Window;
w.width, w.height = msg, height;
class_name := "Win32-Odin-Window\x00";
c_class_name := class_name.data;
if title[title.count-1] != 0 {
c_class_name := ^class_name[0];
if title[len(title)-1] != 0 {
w.c_title = to_c_string(title);
} else {
w.c_title = title as []u8;
w.c_title = cast([]u8)title;
}
instance := GetModuleHandleA(nil);
w.wc = WNDCLASSEXA{
size = size_of(WNDCLASSEXA) as u32,
w.wc = WndClassExA{
size = size_of(WndClassExA),
style = CS_VREDRAW | CS_HREDRAW,
instance = instance as HINSTANCE,
instance = cast(Hinstance)instance,
class_name = c_class_name,
wnd_proc = window_proc,
};
@@ -70,10 +71,10 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
}
w.hwnd = CreateWindowExA(0,
c_class_name, w.c_title.data,
c_class_name, ^w.c_title[0],
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT,
w.width as i32, w.height as i32,
cast(i32)w.width, cast(i32)w.height,
nil, nil, instance, nil);
if w.hwnd == nil {
@@ -85,7 +86,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
{
pfd := PIXELFORMATDESCRIPTOR{
size = size_of(PIXELFORMATDESCRIPTOR) as u32,
size = size_of(PIXELFORMATDESCRIPTOR),
version = 1,
flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
pixel_type = PFD_TYPE_RGBA,
@@ -97,19 +98,20 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
};
SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), nil);
w.opengl_context = wglCreateContext(w.dc);
wglMakeCurrent(w.dc, w.opengl_context);
w.opengl_context = wgl.CreateContext(w.dc);
wgl.MakeCurrent(w.dc, w.opengl_context);
attribs := [8]i32{
WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
WGL_CONTEXT_MINOR_VERSION_ARB, 1,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
wgl.CONTEXT_MAJOR_VERSION_ARB, 2,
wgl.CONTEXT_MINOR_VERSION_ARB, 1,
wgl.CONTEXT_PROFILE_MASK_ARB, wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
0, // NOTE(bill): tells the proc that this is the end of attribs
};
wglCreateContextAttribsARB := wglGetProcAddress(("wglCreateContextAttribsARB\x00" as string).data) as wglCreateContextAttribsARBType;
w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0]);
wglMakeCurrent(w.dc, w.rc);
wgl_str := "wglCreateContextAttribsARB\x00";
wglCreateContextAttribsARB := cast(wgl.Create_Context_Attribs_ARB_Type)wgl.GetProcAddress(^wgl_str[0]);
w.rc = wglCreateContextAttribsARB(w.dc, nil, ^attribs[0]);
wgl.MakeCurrent(w.dc, w.rc);
SwapBuffers(w.dc);
}
@@ -117,7 +119,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
}
destroy_window :: proc(w: ^Window) {
free(w.c_title.data);
free(w.c_title);
}
display_window :: proc(w: ^Window) {
@@ -129,7 +131,7 @@ run :: proc() {
using win32;
using math;
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
win32_proc :: proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline {
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
os.exit(0);
return 0;
@@ -137,7 +139,7 @@ run :: proc() {
return DefWindowProcA(hwnd, msg, wparam, lparam);
}
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc);
window, window_success := make_window("Odin Language Demo", 854, 480, cast(Wnd_Proc)win32_proc);
if !window_success {
return;
}
@@ -153,10 +155,10 @@ run :: proc() {
for running {
curr_time := time_now();
dt := (curr_time - prev_time) as f32;
dt := cast(f32)(curr_time - prev_time);
prev_time = curr_time;
msg: MSG;
msg: Msg;
for PeekMessageA(^msg, nil, 0, 0, PM_REMOVE) > 0 {
if msg.message == WM_QUIT {
running = false;
@@ -178,7 +180,7 @@ run :: proc() {
if is_key_down(Key_Code.UP) { v[1] += 1; }
if is_key_down(Key_Code.DOWN) { v[1] -= 1; }
v = vec2_norm0(v);
v = norm(v);
pos += v * Vec2{SPEED * dt};
}
@@ -188,8 +190,8 @@ run :: proc() {
gl.Clear(gl.COLOR_BUFFER_BIT);
gl.LoadIdentity();
gl.Ortho(0, window.width as f64,
0, window.height as f64, 0, 1);
gl.Ortho(0, cast(f64)window.width,
0, cast(f64)window.height, 0, 1);
draw_rect :: proc(x, y, w, h: f32) {
gl.Begin(gl.TRIANGLES);
@@ -207,9 +209,14 @@ run :: proc() {
draw_rect(pos.x, pos.y, 50, 50);
display_window(^window);
ms_to_sleep := (16 - 1000*dt) as i32;
ms_to_sleep := cast(i32)(16 - 1000*dt);
if ms_to_sleep > 0 {
win32.Sleep(ms_to_sleep);
}
}
}
main :: proc() {
run();
}
+8 -8
View File
@@ -136,7 +136,7 @@ bounds_checking :: proc() {
{
base: [10]int;
s := base[2:6];
s := base[2..6];
a, b := -1, 6;
#no_bounds_check {
@@ -164,7 +164,7 @@ type_introspection :: proc() {
info = type_info_of_val(x); // by value
// See: runtime.odin
match type i in info {
match i in info {
case Type_Info.Integer:
fmt.println("integer!");
case Type_Info.Float:
@@ -174,7 +174,7 @@ type_introspection :: proc() {
}
// Unsafe cast
integer_info := cast(^Type_Info.Integer)info;
integer_info := cast(^Type_Info.Integer)cast(rawptr)info;
}
{
@@ -263,12 +263,12 @@ crazy_introspection :: proc() {
}
fruit_ti := type_info(Fruit);
name := (cast(^Type_Info.Named)fruit_ti).name; // Unsafe casts
info := cast(^Type_Info.Enum)type_info_base(fruit_ti); // Unsafe casts
name := (union_cast(^Type_Info.Named)fruit_ti).name; // Unsafe casts
info, _ := union_cast(^Type_Info.Enum)type_info_base(fruit_ti); // Unsafe casts
fmt.printf("% :: enum % {\n", name, info.base);
for i := 0; i < info.values.count; i += 1 {
fmt.printf("\t%\t= %,\n", info.names[i], info.values[i]);
fmt.printf("%s :: enum %T {\n", name, info.base);
for i := 0; i < len(info.values); i++ {
fmt.printf("\t%s\t= %v,\n", info.names[i], info.values[i]);
}
fmt.printf("}\n");
File diff suppressed because it is too large Load Diff
+17 -17
View File
@@ -1,14 +1,14 @@
#import "fmt.odin"
#import "utf8.odin"
#import "hash.odin"
#import "mem.odin"
#import "fmt.odin";
#import "utf8.odin";
#import "hash.odin";
#import "mem.odin";
main :: proc() {
{ // New Standard Library stuff
s := "Hello"
s := "Hello";
fmt.println(s,
utf8.valid_string(s),
hash.murmur64(s.data, s.count))
hash.murmur64(cast([]byte)s));
// utf8.odin
// hash.odin
@@ -19,15 +19,15 @@ main :: proc() {
}
{
arena: mem.Arena
mem.init_arena_from_context(^arena, mem.megabytes(16)) // Uses default allocator
defer mem.free_arena(^arena)
arena: mem.Arena;
mem.init_arena_from_context(^arena, mem.megabytes(16)); // Uses default allocator
defer mem.free_arena(^arena);
push_allocator mem.arena_allocator(^arena) {
x := new(int)
x^ = 1337
x := new(int);
x^ = 1337;
fmt.println(x^)
fmt.println(x^);
}
/*
@@ -48,14 +48,14 @@ main :: proc() {
// You can also "push" a context
c := current_context() // Create copy of the allocator
c.allocator = mem.arena_allocator(^arena)
c := context; // Create copy of the allocator
c.allocator = mem.arena_allocator(^arena);
push_context c {
x := new(int)
x^ = 365
x := new(int);
x^ = 365;
fmt.println(x^)
fmt.println(x^);
}
}
+15 -13
View File
@@ -42,12 +42,12 @@ syntax :: proc() {
};
Thing2 :: struct {x: f32, y: int, z: ^[]int};
// Slice interals are now just a `ptr+count`
slice: []int; compile_assert(size_of_val(slice) == 2*size_of(int));
// Slice interals are now just a `ptr+len+cap`
slice: []int; compile_assert(size_of_val(slice) == 3*size_of(int));
// Helper type - Help the reader understand what it is quicker
My_Int :: type int;
My_Proc :: type proc(int) -> f32;
My_Int :: #type int;
My_Proc :: #type proc(int) -> f32;
// All declarations with : are either variable or constant
@@ -59,6 +59,7 @@ syntax :: proc() {
c_proc :: proc() { /* code here */ };
/*
x += 1;
x -= 1;
// ++ and -- have been removed
@@ -67,7 +68,7 @@ syntax :: proc() {
// Question: Should they be added again?
// They were removed as they are redundant and statements, not expressions
// like in C/C++
*/
// You can now build files as a `.dll`
// `odin build_dll demo.odin`
@@ -85,7 +86,7 @@ syntax :: proc() {
Prefix_Type :: struct {x: int, y: f32, z: rawptr};
thread_local my_tls: Prefix_Type;
#thread_local my_tls: Prefix_Type;
prefixes :: proc() {
using var: Prefix_Type;
@@ -98,7 +99,7 @@ prefixes :: proc() {
foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) {
// int_ptr = nil; // Not valid
int_ptr^ = 123; // Is valid
// int_ptr^ = 123; // Not valid
}
@@ -154,6 +155,7 @@ foreign_procedures :: proc() {
}
special_expressions :: proc() {
/*
// Block expression
x := {
a: f32 = 123;
@@ -168,7 +170,7 @@ special_expressions :: proc() {
// TODO: Type cohesion is not yet finished
give 123;
}; // semicolon is required as it's an expression
*/
// This is allows for inline blocks of code and will be a useful feature to have when
// macros will be implemented into the language
@@ -191,17 +193,17 @@ loops :: proc() {
break;
}
for i in 0..<123 { // 123 exclusive
for i in 0..123 { // 123 exclusive
}
for i in 0...122 { // 122 inclusive
for i in 0..123-1 { // 122 inclusive
}
for val, idx in 12..<16 {
for val, idx in 12..16 {
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);
@@ -224,7 +226,7 @@ loops :: proc() {
when false {
for i, size := 0; i < name.count; i += size {
r: rune;
r, size = utf8.decode_rune(name[i:]);
r, size = utf8.decode_rune(name[i..]);
fmt.printf("%r\n", r);
}
}
+211 -124
View File
@@ -2,9 +2,8 @@
#import "os.odin";
#import "fmt.odin";
#import "mem.odin";
#import "utf8.odin";
#import "hash.odin";
#import "raw.odin";
// IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a
// #shared_global_scope due to the internals of the compiler.
@@ -29,24 +28,29 @@ Calling_Convention :: enum {
Type_Info_Record :: struct #ordered {
types: []^Type_Info,
names: []string,
offsets: []int, // offsets may not be used in tuples
size: int, // in bytes
align: int, // in bytes
offsets: []int, // offsets may not be used in tuples
usings: []bool, // usings may not be used in tuples
packed: bool,
ordered: bool,
custom_align: bool,
}
Type_Info :: union {
size: int,
align: int,
Named{name: string, base: ^Type_Info},
Integer{size: int, signed: bool},
Float{size: int},
Integer{signed: bool},
Float{},
Complex{},
Quaternion{},
String{},
Boolean{},
Any{},
Pointer{
elem: ^Type_Info, // nil -> rawptr
},
Atomic{elem: ^Type_Info},
Procedure{
params: ^Type_Info, // Type_Info.Tuple
results: ^Type_Info, // Type_Info.Tuple
@@ -60,20 +64,18 @@ Type_Info :: union {
},
Dynamic_Array{elem: ^Type_Info, elem_size: int},
Slice {elem: ^Type_Info, elem_size: int},
Vector {elem: ^Type_Info, elem_size, count, align: int},
Vector {elem: ^Type_Info, elem_size, count: int},
Tuple {using record: Type_Info_Record}, // Only really used for procedures
Struct {using record: Type_Info_Record},
Raw_Union {using record: Type_Info_Record},
Union{
common_fields: struct {
types: []^Type_Info,
names: []string,
offsets: []int, // offsets may not be used in tuples
types: []^Type_Info,
names: []string,
offsets: []int, // offsets may not be used in tuples
},
variant_names: []string,
variant_types: []^Type_Info,
size: int,
align: int,
},
Enum{
base: ^Type_Info,
@@ -93,6 +95,9 @@ Type_Info :: union {
// This will be set by the compiler
__type_table: []Type_Info;
__argv__: ^^byte;
__argc__: i32;
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
if info == nil {
return nil;
@@ -128,11 +133,6 @@ __debug_trap :: proc() #foreign __llvm_core "llvm.debugtrap";
__trap :: proc() #foreign __llvm_core "llvm.trap";
read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter";
__cpuid :: proc(level: u32, sig: ^u32) -> i32 #foreign __llvm_core "__get_cpuid";
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
Allocator_Mode :: enum u8 {
@@ -149,6 +149,7 @@ Allocator :: struct #ordered {
data: rawptr,
}
Context :: struct #ordered {
thread_id: int,
@@ -165,7 +166,7 @@ DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
__check_context :: proc() {
c := ^__context;
c := &__context;
if c.allocator.procedure == nil {
c.allocator = default_allocator();
@@ -233,7 +234,7 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment:
return nil;
}
mem.copy(new_memory, old_memory, min(old_size, new_size));;
__mem_copy(new_memory, old_memory, min(old_size, new_size));;
free(old_memory);
return new_memory;
}
@@ -279,20 +280,21 @@ default_allocator :: proc() -> Allocator {
__string_eq :: proc(a, b: string) -> bool {
if a.count != b.count {
if len(a) != len(b) {
return false;
}
if a.data == b.data {
if len(a) == 0 {
return true;
}
if &a[0] == &b[0] {
return true;
}
return __string_cmp(a, b) == 0;
}
__string_cmp :: proc(a, b: string) -> int {
return mem.compare(cast([]byte)a, cast([]byte)b);
return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
}
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }
@@ -302,6 +304,26 @@ __string_le :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) <=
__string_ge :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) >= 0; }
__complex64_eq :: proc(a, b: complex64) -> bool #inline { return real(a) == real(b) && imag(a) == imag(b); }
__complex64_ne :: proc(a, b: complex64) -> bool #inline { return real(a) != real(b) || imag(a) != imag(b); }
__complex128_eq :: proc(a, b: complex128) -> bool #inline { return real(a) == real(b) && imag(a) == imag(b); }
__complex128_ne :: proc(a, b: complex128) -> bool #inline { return real(a) != real(b) || imag(a) != imag(b); }
__quaternion128_eq :: proc(a, b: quaternion128) -> bool #inline {
return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b);
}
__quaternion128_ne :: proc(a, b: quaternion128) -> bool #inline {
return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b);
}
__quaternion256_eq :: proc(a, b: quaternion256) -> bool #inline {
return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b);
}
__quaternion256_ne :: proc(a, b: quaternion256) -> bool #inline {
return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b);
}
__assert :: proc(file: string, line, column: int, msg: string) #inline {
fmt.fprintf(os.stderr, "%s(%d:%d) Runtime assertion: %s\n",
file, line, column, msg);
@@ -316,7 +338,7 @@ __bounds_check_error :: proc(file: string, line, column: int, index, count: int)
if 0 <= index && index < count {
return;
}
fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..%d\n",
fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..<%d\n",
file, line, column, index, count);
__debug_trap();
}
@@ -325,21 +347,22 @@ __slice_expr_error :: proc(file: string, line, column: int, low, high, max: int)
if 0 <= low && low <= high && high <= max {
return;
}
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..%d..%d]\n",
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..<%d..<%d]\n",
file, line, column, low, high, max);
__debug_trap();
}
__substring_expr_error :: proc(file: string, line, column: int, low, high: int) {
if 0 <= low && low <= high {
return;
}
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d..%d]\n",
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d..<%d]\n",
file, line, column, low, high);
__debug_trap();
}
__union_cast_check :: proc(ok: bool, file: string, line, column: int, from, to: ^Type_Info) {
__type_assertion_check :: proc(ok: bool, file: string, line, column: int, from, to: ^Type_Info) {
if !ok {
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid `union_cast` from %T to %T\n",
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid type_assertion from %T to %T\n",
file, line, column, from, to);
__debug_trap();
}
@@ -350,40 +373,77 @@ __string_decode_rune :: proc(s: string) -> (rune, int) #inline {
}
Raw_Any :: struct #ordered {
type_info: ^Type_Info,
data: rawptr,
__mem_set :: proc(data: rawptr, value: i32, len: int) -> rawptr {
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memset.p0i8.i64";
llvm_memset_64bit(data, byte(value), len, 1, false);
return data;
}
__mem_zero :: proc(data: rawptr, len: int) -> rawptr {
return __mem_set(data, 0, len);
}
__mem_copy :: proc(dst, src: rawptr, len: int) -> rawptr {
// NOTE(bill): This _must_ be implemented like C's memmove
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memmove.p0i8.p0i8.i64";
llvm_memmove_64bit(dst, src, len, 1, false);
return dst;
}
__mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr {
// NOTE(bill): This _must_ be implemented like C's memcpy
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memcpy.p0i8.p0i8.i64";
llvm_memcpy_64bit(dst, src, len, 1, false);
return dst;
}
Raw_String :: struct #ordered {
data: ^byte,
count: int,
};
__mem_compare :: proc(a, b: ^byte, n: int) -> int {
for i in 0..<n {
match {
case (a+i)^ < (b+i)^:
return -1;
case (a+i)^ > (b+i)^:
return +1;
}
}
return 0;
}
Raw_Slice :: struct #ordered {
data: rawptr,
count: int,
capacity: int,
};
Raw_Dynamic_Array :: struct #ordered {
data: rawptr,
count: int,
capacity: int,
allocator: Allocator,
};
Raw_Dynamic_Map :: struct #ordered {
hashes: [dynamic]int,
entries: Raw_Dynamic_Array,
};
__sqrt_f32 :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32";
__sqrt_f64 :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64";
__abs_complex64 :: proc(x: complex64) -> f32 #inline {
r, i := real(x), imag(x);
return __sqrt_f32(r*r + i*i);
}
__abs_complex128 :: proc(x: complex128) -> f64 #inline {
r, i := real(x), imag(x);
return __sqrt_f64(r*r + i*i);
}
__abs_quaternion128 :: proc(x: quaternion128) -> f32 #inline {
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
return __sqrt_f32(r*r + i*i + j*j + k*k);
}
__abs_quaternion256 :: proc(x: quaternion256) -> f64 #inline {
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
return __sqrt_f64(r*r + i*i + j*j + k*k);
}
__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, capacity: int) -> bool {
array := cast(^Raw_Dynamic_Array)array_;
if capacity <= array.capacity {
__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int) {
array := ^raw.Dynamic_Array(array_);
__check_context();
array.allocator = context.allocator;
assert(array.allocator.procedure != nil);
if cap > 0 {
__dynamic_array_reserve(array_, elem_size, elem_align, cap);
array.len = len;
}
}
__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int) -> bool {
array := ^raw.Dynamic_Array(array_);
if cap <= array.cap {
return true;
}
@@ -393,8 +453,8 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, capa
}
assert(array.allocator.procedure != nil);
old_size := array.capacity * elem_size;
new_size := capacity * elem_size;
old_size := array.cap * elem_size;
new_size := cap * elem_size;
allocator := array.allocator;
new_data := allocator.procedure(allocator.data, Allocator_Mode.RESIZE, new_size, elem_align, array.data, old_size, 0);
@@ -403,83 +463,102 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, capa
}
array.data = new_data;
array.capacity = capacity;
array.cap = cap;
return true;
}
__dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int) -> bool {
array := ^raw.Dynamic_Array(array_);
ok := __dynamic_array_reserve(array_, elem_size, elem_align, len);
if ok {
array.len = len;
}
return ok;
}
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
items: rawptr, item_count: int) -> int {
array := cast(^Raw_Dynamic_Array)array_;
array := ^raw.Dynamic_Array(array_);
if item_count <= 0 || items == nil {
return array.count;
return array.len;
}
ok := true;
if array.capacity <= array.count+item_count {
capacity := 2 * array.capacity + max(8, item_count);
ok = __dynamic_array_reserve(array, elem_size, elem_align, capacity);
if array.cap <= array.len+item_count {
cap := 2 * array.cap + max(8, item_count);
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
}
if !ok {
// TODO(bill): Better error handling for failed reservation
return array.count;
return array.len;
}
data := cast(^byte)array.data;
data := ^byte(array.data);
assert(data != nil);
mem.copy(data + (elem_size*array.count), items, elem_size * item_count);
array.count += item_count;
return array.count;
__mem_copy(data + (elem_size*array.len), items, elem_size * item_count);
array.len += item_count;
return array.len;
}
__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int) -> int {
array := cast(^Raw_Dynamic_Array)array_;
array := ^raw.Dynamic_Array(array_);
ok := true;
if array.capacity <= array.count+1 {
capacity := 2 * array.capacity + max(8, 1);
ok = __dynamic_array_reserve(array, elem_size, elem_align, capacity);
if array.cap <= array.len+1 {
cap := 2 * array.cap + max(8, 1);
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap);
}
if !ok {
// TODO(bill): Better error handling for failed reservation
return array.count;
return array.len;
}
data := cast(^byte)array.data;
data := ^byte(array.data);
assert(data != nil);
mem.zero(data + (elem_size*array.count), elem_size);
array.count++;
return array.count;
__mem_zero(data + (elem_size*array.len), elem_size);
array.len++;
return array.len;
}
__slice_append :: proc(slice_: rawptr, elem_size, elem_align: int,
items: rawptr, item_count: int) -> int {
slice := cast(^Raw_Slice)slice_;
slice := ^raw.Slice(slice_);
if item_count <= 0 || items == nil {
return slice.count;
return slice.len;
}
item_count = min(slice.capacity-slice.count, item_count);
item_count = min(slice.cap-slice.len, item_count);
if item_count > 0 {
data := cast(^byte)slice.data;
data := ^byte(slice.data);
assert(data != nil);
mem.copy(data + (elem_size*slice.count), items, elem_size * item_count);
slice.count += item_count;
__mem_copy(data + (elem_size*slice.len), items, elem_size * item_count);
slice.len += item_count;
}
return slice.count;
return slice.len;
}
// Map stuff
__default_hash :: proc(data: []byte) -> u64 {
return hash.fnv64a(data);
fnv64a :: proc(data: []byte) -> u64 {
h: u64 = 0xcbf29ce484222325;
for b in data {
h = (h ~ u64(b)) * 0x100000001b3;
}
return h;
}
return fnv64a(data);
}
__default_hash_string :: proc(s: string) -> u64 {
return __default_hash(cast([]byte)s);
return __default_hash([]byte(s));
}
__INITIAL_MAP_CAP :: 16;
__Map_Key :: struct #ordered {
hash: u64,
str: string,
@@ -500,39 +579,41 @@ __Map_Entry_Header :: struct #ordered {
}
__Map_Header :: struct #ordered {
m: ^Raw_Dynamic_Map,
m: ^raw.Dynamic_Map,
is_key_string: bool,
entry_size: int,
entry_align: int,
value_offset: int,
value_size: int,
}
__dynamic_map_reserve :: proc(using header: __Map_Header, capacity: int) -> bool {
h := __dynamic_array_reserve(^m.hashes, size_of(int), align_of(int), capacity);
e := __dynamic_array_reserve(^m.entries, entry_size, entry_align, capacity);
return h && e;
__dynamic_map_reserve :: proc(using header: __Map_Header, cap: int) {
__dynamic_array_reserve(&m.hashes, size_of(int), align_of(int), cap);
__dynamic_array_reserve(&m.entries, entry_size, entry_align, cap);
}
__dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
new_header := header;
nm: Raw_Dynamic_Map;
new_header.m = ^nm;
new_header: __Map_Header = header;
nm: raw.Dynamic_Map;
new_header.m = &nm;
reserve(nm.hashes, new_count);
nm.hashes.count = nm.hashes.capacity;
__dynamic_array_reserve(^nm.entries, entry_size, entry_align, m.entries.count);
for _, i in nm.hashes {
header_hashes := ^raw.Dynamic_Array(&header.m.hashes);
nm_hashes := ^raw.Dynamic_Array(&nm.hashes);
__dynamic_array_resize(nm_hashes, size_of(int), align_of(int), new_count);
__dynamic_array_reserve(&nm.entries, entry_size, entry_align, m.entries.len);
for i in 0..<new_count {
nm.hashes[i] = -1;
}
for i := 0; i < nm.entries.count; i++ {
entry_header := __dynamic_map_get_entry(new_header, i);
data := cast(^byte)entry_header;
if nm.hashes.count == 0 {
for i := 0; i < m.entries.len; i++ {
if len(nm.hashes) == 0 {
__dynamic_map_grow(new_header);
}
entry_header := __dynamic_map_get_entry(header, i);
data := ^byte(entry_header);
fr := __dynamic_map_find(new_header, entry_header.key);
j := __dynamic_map_add_entry(new_header, entry_header.key);
if fr.entry_prev < 0 {
@@ -544,13 +625,14 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
e := __dynamic_map_get_entry(new_header, j);
e.next = fr.entry_index;
ndata := cast(^byte)e;
mem.copy(ndata+value_offset, data+value_offset, entry_size-value_offset);
ndata := ^byte(e);
__mem_copy(ndata+value_offset, data+value_offset, value_size);
if __dynamic_map_full(new_header) {
__dynamic_map_grow(new_header);
}
}
free_ptr_with_allocator(header.m.hashes.allocator, header.m.hashes.data);
free_ptr_with_allocator(header_hashes.allocator, header_hashes.data);
free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data);
header.m^ = nm;
}
@@ -558,7 +640,7 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
__dynamic_map_get :: proc(h: __Map_Header, key: __Map_Key) -> rawptr {
index := __dynamic_map_find(h, key).entry_index;
if index >= 0 {
data := cast(^byte)__dynamic_map_get_entry(h, index);
data := ^byte(__dynamic_map_get_entry(h, index));
val := data + h.value_offset;
return val;
}
@@ -567,10 +649,14 @@ __dynamic_map_get :: proc(h: __Map_Header, key: __Map_Key) -> rawptr {
__dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr) {
index: int;
assert(value != nil);
if m.hashes.count == 0 {
if len(m.hashes) == 0 {
__dynamic_map_reserve(h, __INITIAL_MAP_CAP);
__dynamic_map_grow(h);
}
fr := __dynamic_map_find(h, key);
if fr.entry_index >= 0 {
index = fr.entry_index;
@@ -584,9 +670,10 @@ __dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr)
}
}
{
data := cast(^byte)__dynamic_map_get_entry(h, index);
val := data+value_offset;
mem.copy(val, value, entry_size-value_offset);
e := __dynamic_map_get_entry(h, index);
e.key = key;
val := ^byte(e) + value_offset;
__mem_copy(val, value, value_size);
}
if __dynamic_map_full(h) {
@@ -596,12 +683,12 @@ __dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr)
__dynamic_map_grow :: proc(using h: __Map_Header) {
new_count := 2*m.entries.count + 8;
new_count := max(2*m.entries.cap + 8, __INITIAL_MAP_CAP);
__dynamic_map_rehash(h, new_count);
}
__dynamic_map_full :: proc(using h: __Map_Header) -> bool {
return cast(int)(0.75 * cast(f64)m.hashes.count) <= m.entries.count;
return int(0.75 * f64(len(m.hashes))) <= m.entries.cap;
}
@@ -617,8 +704,8 @@ __dynamic_map_hash_equal :: proc(h: __Map_Header, a, b: __Map_Key) -> bool {
__dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_Result {
fr := __Map_Find_Result{-1, -1, -1};
if m.hashes.count > 0 {
fr.hash_index = cast(int)(key.hash % cast(u64)m.hashes.count);
if len(m.hashes) > 0 {
fr.hash_index = int(key.hash % u64(len(m.hashes)));
fr.entry_index = m.hashes[fr.hash_index];
for fr.entry_index >= 0 {
entry := __dynamic_map_get_entry(h, fr.entry_index);
@@ -633,8 +720,8 @@ __dynamic_map_find :: proc(using h: __Map_Header, key: __Map_Key) -> __Map_Find_
}
__dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int {
prev := m.entries.count;
c := __dynamic_array_append_nothing(^m.entries, entry_size, entry_align);
prev := m.entries.len;
c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align);
if c != prev {
end := __dynamic_map_get_entry(h, c-1);
end.key = key;
@@ -652,8 +739,8 @@ __dynamic_map_delete :: proc(using h: __Map_Header, key: __Map_Key) {
}
__dynamic_map_get_entry :: proc(using h: __Map_Header, index: int) -> ^__Map_Entry_Header {
data := cast(^byte)m.entries.data + index*entry_size;
return cast(^__Map_Entry_Header)data;
data := ^byte(m.entries.data) + index*entry_size;
return ^__Map_Entry_Header(data);
}
__dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
@@ -663,10 +750,10 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
__dynamic_map_get_entry(h, fr.entry_prev).next = __dynamic_map_get_entry(h, fr.entry_index).next;
}
if fr.entry_index == m.entries.count-1 {
m.entries.count--;
if fr.entry_index == m.entries.len-1 {
m.entries.len--;
}
mem.copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.count-1), entry_size);
__mem_copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.len-1), entry_size);
last := __dynamic_map_find(h, __dynamic_map_get_entry(h, fr.entry_index).key);
if last.entry_prev >= 0 {
__dynamic_map_get_entry(h, last.entry_prev).next = fr.entry_index;
-100
View File
@@ -1,100 +0,0 @@
// TODO(bill): Use assembly instead here to implement atomics
// Inline vs external file?
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
yield_thread :: proc() { win32.mm_pause(); }
mfence :: proc() { win32.ReadWriteBarrier(); }
sfence :: proc() { win32.WriteBarrier(); }
lfence :: proc() { win32.ReadBarrier(); }
load :: proc(a: ^i32) -> i32 {
return a^;
}
store :: proc(a: ^i32, value: i32) {
a^ = value;
}
compare_exchange :: proc(a: ^i32, expected, desired: i32) -> i32 {
return win32.InterlockedCompareExchange(a, desired, expected);
}
exchanged :: proc(a: ^i32, desired: i32) -> i32 {
return win32.InterlockedExchange(a, desired);
}
fetch_add :: proc(a: ^i32, operand: i32) -> i32 {
return win32.InterlockedExchangeAdd(a, operand);
}
fetch_and :: proc(a: ^i32, operand: i32) -> i32 {
return win32.InterlockedAnd(a, operand);
}
fetch_or :: proc(a: ^i32, operand: i32) -> i32 {
return win32.InterlockedOr(a, operand);
}
spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange(a, 1, 0);
counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter++;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
}
return old_value == 0;
}
spin_unlock :: proc(a: ^i32) {
store(a, 0);
mfence();
}
try_acquire_lock :: proc(a: ^i32) -> bool {
yield_thread();
old_value := compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}
load :: proc(a: ^i64) -> i64 {
return a^;
}
store :: proc(a: ^i64, value: i64) {
a^ = value;
}
compare_exchange :: proc(a: ^i64, expected, desired: i64) -> i64 {
return win32.InterlockedCompareExchange64(a, desired, expected);
}
exchanged :: proc(a: ^i64, desired: i64) -> i64 {
return win32.InterlockedExchange64(a, desired);
}
fetch_add :: proc(a: ^i64, operand: i64) -> i64 {
return win32.InterlockedExchangeAdd64(a, operand);
}
fetch_and :: proc(a: ^i64, operand: i64) -> i64 {
return win32.InterlockedAnd64(a, operand);
}
fetch_or :: proc(a: ^i64, operand: i64) -> i64 {
return win32.InterlockedOr64(a, operand);
}
spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange(a, 1, 0);
counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter++;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
}
return old_value == 0;
}
spin_unlock :: proc(a: ^i64) {
store(a, 0);
mfence();
}
try_acquire_lock :: proc(a: ^i64) -> bool {
yield_thread();
old_value := compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}
+27 -27
View File
@@ -14,37 +14,37 @@ decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
for _, i in buf {
buf[i] = '0';
}
return buf.count;
return len(buf);
}
n := 10 + a.count + abs(a.decimal_point);
// TODO(bill): make this work with a buffer that's not big enough
assert(buf.count >= n);
buf = buf[..n];
assert(len(buf) >= n);
buf = buf[0..<n];
if a.count == 0 {
buf[0] = '0';
return cast(string)buf[0..1];
return string(buf[0..<1]);
}
w := 0;
if a.decimal_point <= 0 {
buf[w] = '0'; w++;
buf[w] = '.'; w++;
w += digit_zero(buf[w .. w-a.decimal_point]);
w += copy(buf[w..], a.digits[0..a.count]);
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]);
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[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 cast(string)buf[0..w];
return string(buf[0..<w]);
}
// trim trailing zeros
@@ -64,7 +64,7 @@ assign :: proc(a: ^Decimal, i: u64) {
for i > 0 {
j := i/10;
i -= 10*j;
buf[n] = cast(byte)('0'+i);
buf[n] = byte('0'+i);
n++;
i = j;
}
@@ -99,7 +99,7 @@ shift_right :: proc(a: ^Decimal, k: uint) {
}
break;
}
c := cast(uint)a.digits[r];
c := uint(a.digits[r]);
n = n*10 + c - '0';
}
a.decimal_point -= r-1;
@@ -107,10 +107,10 @@ shift_right :: proc(a: ^Decimal, k: uint) {
mask: uint = (1<<k) - 1;
for ; r < a.count; r++ {
c := cast(uint)a.digits[r];
c := uint(a.digits[r]);
dig := n>>k;
n &= mask;
a.digits[w] = cast(byte)('0' + dig);
a.digits[w] = byte('0' + dig);
w++;
n = n*10 + c - '0';
}
@@ -118,8 +118,8 @@ shift_right :: proc(a: ^Decimal, k: uint) {
for n > 0 {
dig := n>>k;
n &= mask;
if w < a.digits.count {
a.digits[w] = cast(byte)('0' + dig);
if w < len(a.digits) {
a.digits[w] = byte('0' + dig);
w++;
} else if dig > 0 {
a.trunc = true;
@@ -133,19 +133,19 @@ shift_right :: proc(a: ^Decimal, k: uint) {
}
shift_left :: proc(a: ^Decimal, k: uint) {
delta := cast(int)(k/4);
delta := int(k/4);
r := a.count; // read index
w := a.count+delta; // write index
n: uint;
for r--; r >= 0; r-- {
n += (cast(uint)a.digits[r] - '0') << k;
n += (uint(a.digits[r]) - '0') << k;
quo := n/10;
rem := n - 10*quo;
w--;
if w < a.digits.count {
a.digits[w] = cast(byte)('0' + rem);
if w < len(a.digits) {
a.digits[w] = byte('0' + rem);
} else if rem != 0 {
a.trunc = true;
}
@@ -156,8 +156,8 @@ shift_left :: proc(a: ^Decimal, k: uint) {
quo := n/10;
rem := n - 10*quo;
w--;
if w < a.digits.count {
a.digits[w] = cast(byte)('0' + rem);
if 0 <= w && w < len(a.digits) {
a.digits[w] = byte('0' + rem);
} else if rem != 0 {
a.trunc = true;
}
@@ -165,7 +165,7 @@ shift_left :: proc(a: ^Decimal, k: uint) {
}
a.count += delta;
a.count = min(a.count, a.digits.count);
a.count = min(a.count, len(a.digits));
a.decimal_point += delta;
trim(a);
}
@@ -179,7 +179,7 @@ shift :: proc(a: ^Decimal, k: int) {
shift_left(a, max_shift);
k -= max_shift;
}
shift_left(a, cast(uint)k);
shift_left(a, uint(k));
case k < 0:
@@ -187,7 +187,7 @@ shift :: proc(a: ^Decimal, k: int) {
shift_right(a, max_shift);
k += max_shift;
}
shift_right(a, cast(uint)-k);
shift_right(a, uint(-k));
}
}
@@ -245,7 +245,7 @@ rounded_integer :: proc(a: ^Decimal) -> u64 {
n: u64 = 0;
m := min(a.decimal_point, a.count);
for i = 0; i < m; i++ {
n = n*10 + cast(u64)(a.digits[i]-'0');
n = n*10 + u64(a.digits[i]-'0');
}
for ; i < a.decimal_point; i++ {
n *= 10;
+405 -227
View File
File diff suppressed because it is too large Load Diff
+36 -35
View File
@@ -1,14 +1,14 @@
crc32 :: proc(data: []byte) -> u32 {
result := ~cast(u32)0;
result := ~u32(0);
for b in data {
result = result>>8 ~ _crc32_table[(result ~ cast(u32)b) & 0xff];
result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff];
}
return ~result;
}
crc64 :: proc(data: []byte) -> u64 {
result := ~cast(u64)0;
result := ~u64(0);
for b in data {
result = result>>8 ~ _crc64_table[(result ~ cast(u64)b) & 0xff];
result = result>>8 ~ _crc64_table[(result ~ u64(b)) & 0xff];
}
return ~result;
}
@@ -16,7 +16,7 @@ crc64 :: proc(data: []byte) -> u64 {
fnv32 :: proc(data: []byte) -> u32 {
h: u32 = 0x811c9dc5;
for b in data {
h = (h * 0x01000193) ~ cast(u32)b;
h = (h * 0x01000193) ~ u32(b);
}
return h;
}
@@ -24,7 +24,7 @@ fnv32 :: proc(data: []byte) -> u32 {
fnv64 :: proc(data: []byte) -> u64 {
h: u64 = 0xcbf29ce484222325;
for b in data {
h = (h * 0x100000001b3) ~ cast(u64)b;
h = (h * 0x100000001b3) ~ u64(b);
}
return h;
}
@@ -32,7 +32,7 @@ fnv64 :: proc(data: []byte) -> u64 {
fnv32a :: proc(data: []byte) -> u32 {
h: u32 = 0x811c9dc5;
for b in data {
h = (h ~ cast(u32)b) * 0x01000193;
h = (h ~ u32(b)) * 0x01000193;
}
return h;
}
@@ -40,7 +40,7 @@ fnv32a :: proc(data: []byte) -> u32 {
fnv64a :: proc(data: []byte) -> u64 {
h: u64 = 0xcbf29ce484222325;
for b in data {
h = (h ~ cast(u64)b) * 0x100000001b3;
h = (h ~ u64(b)) * 0x100000001b3;
}
return h;
}
@@ -50,12 +50,12 @@ murmur32 :: proc(data: []byte) -> u32 {
c2_32: u32 : 0x1b873593;
h1: u32 = 0;
nblocks := data.count/4;
p := data.data;
nblocks := len(data)/4;
p := &data[0];
p1 := p + 4*nblocks;
for ; p < p1; p += 4 {
k1 := (cast(^u32)p)^;
k1 := ^u32(p)^;
k1 *= c1_32;
k1 = (k1 << 15) | (k1 >> 17);
@@ -69,22 +69,22 @@ murmur32 :: proc(data: []byte) -> u32 {
tail := data[nblocks*4 ..];
k1: u32;
match tail.count&3 {
match len(tail)&3 {
case 3:
k1 ~= cast(u32)tail[2] << 16;
k1 ~= u32(tail[2]) << 16;
fallthrough;
case 2:
k1 ~= cast(u32)tail[2] << 8;
k1 ~= u32(tail[2]) << 8;
fallthrough;
case 1:
k1 ~= cast(u32)tail[0];
k1 ~= u32(tail[0]);
k1 *= c1_32;
k1 = (k1 << 15) | (k1 >> 17) ;
k1 *= c2_32;
h1 ~= k1;
}
h1 ~= cast(u32)data.count;
h1 ~= u32(len(data));
h1 ~= h1 >> 16;
h1 *= 0x85ebca6b;
@@ -98,12 +98,12 @@ murmur32 :: proc(data: []byte) -> u32 {
murmur64 :: proc(data: []byte) -> u64 {
SEED :: 0x9747b28c;
when false && size_of(int) == 8 {
when size_of(int) == 8 {
m :: 0xc6a4a7935bd1e995;
r :: 47;
h: u64 = SEED ~ (cast(u64)data.count * m);
data64 := slice_ptr(cast(^u64)^data[0], data.count/size_of(u64));
h: u64 = SEED ~ (u64(len(data)) * m);
data64 := slice_ptr(^u64(&data[0]), len(data)/size_of(u64));
for _, i in data64 {
k := data64[i];
@@ -116,15 +116,15 @@ murmur64 :: proc(data: []byte) -> u64 {
h *= m;
}
match data.count&7 {
case 7: h ~= cast(u64)data[6] << 48; fallthrough;
case 6: h ~= cast(u64)data[5] << 40; fallthrough;
case 5: h ~= cast(u64)data[4] << 32; fallthrough;
case 4: h ~= cast(u64)data[3] << 24; fallthrough;
case 3: h ~= cast(u64)data[2] << 16; fallthrough;
case 2: h ~= cast(u64)data[1] << 8; fallthrough;
match len(data)&7 {
case 7: h ~= u64(data[6]) << 48; fallthrough;
case 6: h ~= u64(data[5]) << 40; fallthrough;
case 5: h ~= u64(data[4]) << 32; fallthrough;
case 4: h ~= u64(data[3]) << 24; fallthrough;
case 3: h ~= u64(data[2]) << 16; fallthrough;
case 2: h ~= u64(data[1]) << 8; fallthrough;
case 1:
h ~= cast(u64)data[0];
h ~= u64(data[0]);
h *= m;
}
@@ -137,11 +137,11 @@ murmur64 :: proc(data: []byte) -> u64 {
m :: 0x5bd1e995;
r :: 24;
h1: u32 = cast(u32)SEED ~ cast(u32)data.count;
h2: u32 = SEED >> 32;
h1 := u32(SEED) ~ u32(len(data));
h2 := u32(SEED) >> 32;
data32 := slice_ptr(cast(^u32)^data[0], data.count/size_of(u32));
len := data.count;
data32 := slice_ptr(cast(^u32)&data[0], len(data)/size_of(u32));
len := len(data);
i := 0;
for len >= 8 {
@@ -174,16 +174,17 @@ murmur64 :: proc(data: []byte) -> u64 {
len -= 4;
}
data8 := slice_to_bytes(data32[i..])[..3];
// TODO(bill): Fix this
#no_bounds_check data8 := slice_to_bytes(data32[i..])[0..<3];
match len {
case 3:
h2 ~= cast(u32)data8[2] << 16;
h2 ~= u32(data8[2]) << 16;
fallthrough;
case 2:
h2 ~= cast(u32)data8[1] << 8;
h2 ~= u32(data8[1]) << 8;
fallthrough;
case 1:
h2 ~= cast(u32)data8[0];
h2 ~= u32(data8[0]);
h2 *= m;
}
+49 -43
View File
@@ -27,20 +27,24 @@ Mat4 :: [4]Vec4;
sqrt :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32";
sqrt :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64";
sin :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sin.f32";
sin :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sin.f64";
sin :: proc(θ: f32) -> f32 #foreign __llvm_core "llvm.sin.f32";
sin :: proc(θ: f64) -> f64 #foreign __llvm_core "llvm.sin.f64";
cos :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.cos.f32";
cos :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.cos.f64";
cos :: proc(θ: f32) -> f32 #foreign __llvm_core "llvm.cos.f32";
cos :: proc(θ: f64) -> f64 #foreign __llvm_core "llvm.cos.f64";
tan :: proc(θ: f32) -> f32 #inline { return sin(θ)/cos(θ); }
tan :: proc(θ: f64) -> f64 #inline { return sin(θ)/cos(θ); }
pow :: proc(x, power: f32) -> f32 #foreign __llvm_core "llvm.pow.f32";
pow :: proc(x, power: f64) -> f64 #foreign __llvm_core "llvm.pow.f64";
tan :: proc(x: f32) -> f32 #inline { return sin(x)/cos(x); }
tan :: proc(x: f64) -> f64 #inline { return sin(x)/cos(x); }
lerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
sign :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
sign :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
sign :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
sign :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16";
bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32";
@@ -51,38 +55,44 @@ fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64";
copy_sign :: proc(x, y: f32) -> f32 {
ix := transmute(u32)x;
iy := transmute(u32)y;
ix &= 0x7fffffff;
ix |= iy & 0x80000000;
return transmute(f32)ix;
}
round :: proc(x: f32) -> f32 {
if x >= 0 {
return floor(x + 0.5);
}
return ceil(x - 0.5);
}
floor :: proc(x: f32) -> f32 {
if x >= 0 {
return cast(f32)cast(int)x;
}
return cast(f32)cast(int)(x-0.5);
}
ceil :: proc(x: f32) -> f32 {
if x < 0 {
return cast(f32)cast(int)x;
}
return cast(f32)cast(int)(x+1);
ix := transmute(u32, x);
iy := transmute(u32, y);
ix &= 0x7fff_ffff;
ix |= iy & 0x8000_0000;
return transmute(f32, ix);
}
remainder32 :: proc(x, y: f32) -> f32 {
return x - round(x/y) * y;
copy_sign :: proc(x, y: f64) -> f64 {
ix := transmute(u64, x);
iy := transmute(u64, y);
ix &= 0x7fff_ffff_ffff_ff;
ix |= iy & 0x8000_0000_0000_0000;
return transmute(f64, ix);
}
fmod32 :: proc(x, y: f32) -> f32 {
round :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
round :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
floor :: proc(x: f32) -> f32 { return x >= 0 ? f32(i64(x)) : f32(i64(x-0.5)); } // TODO: Get accurate versions
floor :: proc(x: f64) -> f64 { return x >= 0 ? f64(i64(x)) : f64(i64(x-0.5)); } // TODO: Get accurate versions
ceil :: proc(x: f32) -> f32 { return x < 0 ? f32(i64(x)) : f32(i64(x+1)); } // TODO: Get accurate versions
ceil :: proc(x: f64) -> f64 { return x < 0 ? f64(i64(x)) : f64(i64(x+1)); } // TODO: Get accurate versions
remainder :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
remainder :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
mod :: proc(x, y: f32) -> f32 {
y = abs(y);
result := remainder32(abs(x), y);
result := remainder(abs(x), y);
if sign(result) < 0 {
result += y;
}
return copy_sign(result, x);
}
mod :: proc(x, y: f64) -> f64 {
y = abs(y);
result := remainder(abs(x), y);
if sign(result) < 0 {
result += y;
}
@@ -95,7 +105,6 @@ to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
dot :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y; }
dot :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
dot :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
@@ -151,8 +160,8 @@ mat4_identity :: proc() -> Mat4 {
}
mat4_transpose :: proc(m: Mat4) -> Mat4 {
for j in 0..4 {
for i in 0..4 {
for j in 0..<4 {
for i in 0..<4 {
m[i][j], m[j][i] = m[j][i], m[i][j];
}
}
@@ -161,8 +170,8 @@ mat4_transpose :: proc(m: Mat4) -> Mat4 {
mul :: proc(a, b: Mat4) -> Mat4 {
c: Mat4;
for j in 0..4 {
for i in 0..4 {
for j in 0..<4 {
for i in 0..<4 {
c[j][i] = a[0][i]*b[j][0] +
a[1][i]*b[j][1] +
a[2][i]*b[j][2] +
@@ -367,6 +376,3 @@ F64_MIN_10_EXP :: -307; // min decimal exponent
F64_MIN_EXP :: -1021; // min binary exponent
F64_RADIX :: 2; // exponent radix
F64_ROUNDS :: 1; // addition rounding: near
+26 -47
View File
@@ -6,41 +6,20 @@ swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32";
swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64";
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memset.p0i8.i64";
llvm_memset_64bit(data, cast(byte)value, len, 1, false);
return data;
set :: proc(data: rawptr, value: i32, len: int) -> rawptr {
return __mem_set(data, value, len);
}
zero :: proc(data: rawptr, len: int) -> rawptr #link_name "__mem_zero" {
return set(data, 0, len);
zero :: proc(data: rawptr, len: int) -> rawptr {
return __mem_zero(data, len);
}
copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
// NOTE(bill): This _must_ be implemented like C's memmove
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memmove.p0i8.p0i8.i64";
llvm_memmove_64bit(dst, src, len, 1, false);
return dst;
copy :: proc(dst, src: rawptr, len: int) -> rawptr {
return __mem_copy(dst, src, len);
}
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
// NOTE(bill): This _must_ be implemented like C's memcpy
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memcpy.p0i8.p0i8.i64";
llvm_memcpy_64bit(dst, src, len, 1, false);
return dst;
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr {
return __mem_copy_non_overlapping(dst, src, len);
}
compare :: proc(a, b: []byte) -> int #link_name "__mem_compare" {
n := min(a.count, b.count);
for i in 0..n {
match {
case a[i] < b[i]:
return -1;
case a[i] > b[i]:
return +1;
}
}
return 0;
compare :: proc(a, b: []byte) -> int {
return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
}
@@ -60,13 +39,13 @@ is_power_of_two :: proc(x: int) -> bool {
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
assert(is_power_of_two(align));
a := cast(uint)align;
p := cast(uint)ptr;
a := uint(align);
p := uint(ptr);
modulo := p & (a-1);
if modulo != 0 {
p += a - modulo;
}
return cast(rawptr)p;
return rawptr(p);
}
@@ -77,9 +56,9 @@ Allocation_Header :: struct {
allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) {
header.size = size;
ptr := cast(^int)(header+1);
ptr := ^int(header+1);
for i := 0; cast(rawptr)ptr < data; i++ {
for i := 0; rawptr(ptr) < data; i++ {
(ptr+i)^ = -1;
}
}
@@ -87,11 +66,11 @@ allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
if data == nil {
return nil;
}
p := cast(^int)data;
p := ^int(data);
for (p-1)^ == -1 {
p = (p-1);
}
return cast(^Allocation_Header)p-1;
return ^Allocation_Header(p-1);
}
@@ -117,13 +96,13 @@ Arena_Temp_Memory :: struct {
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
backing = Allocator{};
memory = data[..0];
memory = data[0..<0];
temp_count = 0;
}
init_arena_from_context :: proc(using a: ^Arena, size: int) {
backing = context.allocator;
memory = new_slice(byte, size);
memory = make([]byte, size);
temp_count = 0;
}
@@ -148,18 +127,18 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
using Allocator_Mode;
arena := cast(^Arena)allocator_data;
arena := ^Arena(allocator_data);
match mode {
case ALLOC:
total_size := size + alignment;
if arena.offset + total_size > arena.memory.count {
if arena.offset + total_size > len(arena.memory) {
fmt.fprintln(os.stderr, "Arena out of memory");
return nil;
}
#no_bounds_check end := ^arena.memory[arena.offset];
#no_bounds_check end := &arena.memory[arena.offset];
ptr := align_forward(end, alignment);
arena.offset += total_size;
@@ -182,15 +161,15 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
tmp: Arena_Temp_Memory;
tmp.arena = a;
tmp.original_count = a.memory.count;
tmp.original_count = len(a.memory);
a.temp_count++;
return tmp;
}
end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
assert(arena.memory.count >= original_count);
assert(len(arena.memory) >= original_count);
assert(arena.temp_count > 0);
arena.memory.count = original_count;
arena.memory = arena.memory[0..<original_count];
arena.temp_count--;
}
@@ -242,7 +221,7 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
return WORD_SIZE;
case Vector:
size := size_of_type_info(info.elem);
count := cast(int)max(prev_pow2(cast(i64)info.count), 1);
count := int(max(prev_pow2(i64(info.count)), 1));
total := size * count;
return clamp(total, 1, MAX_ALIGN);
case Tuple:
+55 -45
View File
@@ -1,4 +1,5 @@
#foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
#foreign_system_library lib "gl" when ODIN_OS == "linux";
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
#import "sys/wgl.odin" when ODIN_OS == "windows";
#load "opengl_constants.odin";
@@ -30,15 +31,19 @@ TexImage2D :: proc(target, level, internal_format,
format, type: i32, pixels: rawptr) #foreign lib "glTexImage2D";
string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; }
_string_data :: proc(s: string) -> ^u8 #inline { return &s[0]; }
_libgl := win32.LoadLibraryA(string_data("opengl32.dll\x00"));
_libgl := win32.LoadLibraryA(_string_data("opengl32.dll\x00"));
GetProcAddress :: proc(name: string) -> proc() #cc_c {
assert(name[name.count-1] == 0);
res := wgl.GetProcAddress(name.data);
if name[len(name)-1] == 0 {
name = name[0..<len(name)-1];
}
// NOTE(bill): null terminated
assert((&name[0] + len(name))^ == 0);
res := wgl.GetProcAddress(&name[0]);
if res == nil {
res = win32.GetProcAddress(_libgl, name.data);
res = win32.GetProcAddress(_libgl, &name[0]);
}
return res;
}
@@ -46,6 +51,7 @@ GetProcAddress :: proc(name: string) -> proc() #cc_c {
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
DeleteBuffers: proc(count: i32, buffers: ^u32) #cc_c;
BindBuffer: proc(target: i32, buffer: u32) #cc_c;
BindVertexArray: proc(buffer: u32) #cc_c;
BindSampler: proc(position: i32, sampler: u32) #cc_c;
@@ -102,55 +108,59 @@ UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
init :: proc() {
set_proc_address :: proc(p: rawptr, name: string) #inline { (cast(^(proc() #cc_c))p)^ = GetProcAddress(name); }
set_proc_address :: proc(p: rawptr, name: string) #inline {
x := ^(proc() #cc_c)(p);
x^ = GetProcAddress(name);
}
set_proc_address(^GenBuffers, "glGenBuffers\x00");
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
set_proc_address(^GenSamplers, "glGenSamplers\x00");
set_proc_address(^BindBuffer, "glBindBuffer\x00");
set_proc_address(^BindSampler, "glBindSampler\x00");
set_proc_address(^BindVertexArray, "glBindVertexArray\x00");
set_proc_address(^BufferData, "glBufferData\x00");
set_proc_address(^BufferSubData, "glBufferSubData\x00");
set_proc_address(&GenBuffers, "glGenBuffers\x00");
set_proc_address(&GenVertexArrays, "glGenVertexArrays\x00");
set_proc_address(&GenSamplers, "glGenSamplers\x00");
set_proc_address(&DeleteBuffers, "glDeleteBuffers\x00");
set_proc_address(&BindBuffer, "glBindBuffer\x00");
set_proc_address(&BindSampler, "glBindSampler\x00");
set_proc_address(&BindVertexArray, "glBindVertexArray\x00");
set_proc_address(&BufferData, "glBufferData\x00");
set_proc_address(&BufferSubData, "glBufferSubData\x00");
set_proc_address(^DrawArrays, "glDrawArrays\x00");
set_proc_address(^DrawElements, "glDrawElements\x00");
set_proc_address(&DrawArrays, "glDrawArrays\x00");
set_proc_address(&DrawElements, "glDrawElements\x00");
set_proc_address(^MapBuffer, "glMapBuffer\x00");
set_proc_address(^UnmapBuffer, "glUnmapBuffer\x00");
set_proc_address(&MapBuffer, "glMapBuffer\x00");
set_proc_address(&UnmapBuffer, "glUnmapBuffer\x00");
set_proc_address(^VertexAttribPointer, "glVertexAttribPointer\x00");
set_proc_address(^EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
set_proc_address(&VertexAttribPointer, "glVertexAttribPointer\x00");
set_proc_address(&EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
set_proc_address(^CreateShader, "glCreateShader\x00");
set_proc_address(^ShaderSource, "glShaderSource\x00");
set_proc_address(^CompileShader, "glCompileShader\x00");
set_proc_address(^CreateProgram, "glCreateProgram\x00");
set_proc_address(^AttachShader, "glAttachShader\x00");
set_proc_address(^DetachShader, "glDetachShader\x00");
set_proc_address(^DeleteShader, "glDeleteShader\x00");
set_proc_address(^LinkProgram, "glLinkProgram\x00");
set_proc_address(^UseProgram, "glUseProgram\x00");
set_proc_address(^DeleteProgram, "glDeleteProgram\x00");
set_proc_address(&CreateShader, "glCreateShader\x00");
set_proc_address(&ShaderSource, "glShaderSource\x00");
set_proc_address(&CompileShader, "glCompileShader\x00");
set_proc_address(&CreateProgram, "glCreateProgram\x00");
set_proc_address(&AttachShader, "glAttachShader\x00");
set_proc_address(&DetachShader, "glDetachShader\x00");
set_proc_address(&DeleteShader, "glDeleteShader\x00");
set_proc_address(&LinkProgram, "glLinkProgram\x00");
set_proc_address(&UseProgram, "glUseProgram\x00");
set_proc_address(&DeleteProgram, "glDeleteProgram\x00");
set_proc_address(^GetShaderiv, "glGetShaderiv\x00");
set_proc_address(^GetProgramiv, "glGetProgramiv\x00");
set_proc_address(^GetShaderInfoLog, "glGetShaderInfoLog\x00");
set_proc_address(^GetProgramInfoLog, "glGetProgramInfoLog\x00");
set_proc_address(&GetShaderiv, "glGetShaderiv\x00");
set_proc_address(&GetProgramiv, "glGetProgramiv\x00");
set_proc_address(&GetShaderInfoLog, "glGetShaderInfoLog\x00");
set_proc_address(&GetProgramInfoLog, "glGetProgramInfoLog\x00");
set_proc_address(^ActiveTexture, "glActiveTexture\x00");
set_proc_address(^GenerateMipmap, "glGenerateMipmap\x00");
set_proc_address(&ActiveTexture, "glActiveTexture\x00");
set_proc_address(&GenerateMipmap, "glGenerateMipmap\x00");
set_proc_address(^Uniform1i, "glUniform1i\x00");
set_proc_address(^UniformMatrix4fv, "glUniformMatrix4fv\x00");
set_proc_address(&Uniform1i, "glUniform1i\x00");
set_proc_address(&UniformMatrix4fv, "glUniformMatrix4fv\x00");
set_proc_address(^GetUniformLocation, "glGetUniformLocation\x00");
set_proc_address(&GetUniformLocation, "glGetUniformLocation\x00");
set_proc_address(^SamplerParameteri, "glSamplerParameteri\x00");
set_proc_address(^SamplerParameterf, "glSamplerParameterf\x00");
set_proc_address(^SamplerParameteriv, "glSamplerParameteriv\x00");
set_proc_address(^SamplerParameterfv, "glSamplerParameterfv\x00");
set_proc_address(^SamplerParameterIiv, "glSamplerParameterIiv\x00");
set_proc_address(^SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
set_proc_address(&SamplerParameteri, "glSamplerParameteri\x00");
set_proc_address(&SamplerParameterf, "glSamplerParameterf\x00");
set_proc_address(&SamplerParameteriv, "glSamplerParameteriv\x00");
set_proc_address(&SamplerParameterfv, "glSamplerParameterfv\x00");
set_proc_address(&SamplerParameterIiv, "glSamplerParameterIiv\x00");
set_proc_address(&SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
}
+1 -1
View File
@@ -1,3 +1,3 @@
#load "os_windows.odin" when ODIN_OS == "windows";
#load "os_x.odin" when ODIN_OS == "osx";
#load "os_linux.odin" when ODIN_OS == "linux";
+303
View File
@@ -0,0 +1,303 @@
#import "fmt.odin";
#import "strings.odin";
Handle :: i32;
File_Time :: u64;
Errno :: i32;
// INVALID_HANDLE: Handle : -1;
O_RDONLY :: 0x00000;
O_WRONLY :: 0x00001;
O_RDWR :: 0x00002;
O_CREAT :: 0x00040;
O_EXCL :: 0x00080;
O_NOCTTY :: 0x00100;
O_TRUNC :: 0x00200;
O_NONBLOCK :: 0x00800;
O_APPEND :: 0x00400;
O_SYNC :: 0x01000;
O_ASYNC :: 0x02000;
O_CLOEXEC :: 0x80000;
SEEK_SET :: 0;
SEEK_CUR :: 1;
SEEK_END :: 2;
SEEK_DATA :: 3;
SEEK_HOLE :: 4;
SEEK_MAX :: SEEK_HOLE;
// NOTE(zangent): These are OS specific!
// Do not mix these up!
RTLD_LAZY :: 0x001;
RTLD_NOW :: 0x002;
RTLD_BINDING_MASK :: 0x3;
RTLD_GLOBAL :: 0x100;
// "Argv" arguments converted to Odin strings
immutable args := _alloc_command_line_arguments();
_File_Time :: struct #ordered {
seconds: i64,
nanoseconds: i32,
reserved: i32,
}
// Translated from
// https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/+/jb-dev/sysroot/usr/include/bits/stat.h
// Validity is not guaranteed.
Stat :: struct #ordered {
device_id: u64, // ID of device containing file
serial: u64, // File serial number
nlink: u32, // Number of hard links
mode: u32, // Mode of the file
uid: u32, // User ID of the file's owner
gid: u32, // Group ID of the file's group
_padding: i32, // 32 bits of padding
rdev: u64, // Device ID, if device
size: i64, // Size of the file, in bytes
block_size: i64, // Optimal bllocksize for I/O
blocks: i64, // Number of 512-byte blocks allocated
last_access: _File_Time, // Time of last access
modified: _File_Time, // Time of last modification
status_change: _File_Time, // Time of last status change
_reserve1,
_reserve2,
_reserve3: i64,
serial_numbe: u64, // File serial number...? Maybe.
_reserve4: i64,
};
// File type
S_IFMT :: 0170000; // Type of file mask
S_IFIFO :: 0010000; // Named pipe (fifo)
S_IFCHR :: 0020000; // Character special
S_IFDIR :: 0040000; // Directory
S_IFBLK :: 0060000; // Block special
S_IFREG :: 0100000; // Regular
S_IFLNK :: 0120000; // Symbolic link
S_IFSOCK :: 0140000; // Socket
// File mode
// Read, write, execute/search by owner
S_IRWXU :: 0000700; // RWX mask for owner
S_IRUSR :: 0000400; // R for owner
S_IWUSR :: 0000200; // W for owner
S_IXUSR :: 0000100; // X for owner
// Read, write, execute/search by group
S_IRWXG :: 0000070; // RWX mask for group
S_IRGRP :: 0000040; // R for group
S_IWGRP :: 0000020; // W for group
S_IXGRP :: 0000010; // X for group
// Read, write, execute/search by others
S_IRWXO :: 0000007; // RWX mask for other
S_IROTH :: 0000004; // R for other
S_IWOTH :: 0000002; // W for other
S_IXOTH :: 0000001; // X for other
S_ISUID :: 0004000; // Set user id on execution
S_ISGID :: 0002000; // Set group id on execution
S_ISVTX :: 0001000; // Directory restrcted delete
S_ISLNK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFLNK; }
S_ISREG :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFREG; }
S_ISDIR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFDIR; }
S_ISCHR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFCHR; }
S_ISBLK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFBLK; }
S_ISFIFO :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFIFO; }
S_ISSOCK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFSOCK;}
R_OK :: 4; // Test for read permission
W_OK :: 2; // Test for write permission
X_OK :: 1; // Test for execute permission
F_OK :: 0; // Test for file existance
#foreign_system_library dl "dl";
#foreign_system_library libc "c";
_unix_open :: proc(path: ^u8, mode: int) -> Handle #foreign libc "open";
_unix_close :: proc(fd: Handle) -> i32 #foreign libc "close";
_unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int #foreign libc "read";
_unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int #foreign libc "write";
_unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 #foreign libc "lseek64";
_unix_gettid :: proc() -> u64 #foreign libc "gettid";
_unix_stat :: proc(path: ^u8, stat: ^Stat) -> i32 #foreign libc "stat";
_unix_access :: proc(path: ^u8, mask: int) -> i32 #foreign libc "access";
_unix_malloc :: proc(size: int) -> rawptr #foreign libc "malloc";
_unix_free :: proc(ptr: rawptr) #foreign libc "free";
_unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #foreign libc "realloc";
_unix_getenv :: proc(^u8) -> ^u8 #foreign libc "getenv";
_unix_exit :: proc(status: int) #foreign libc "exit";
_unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #foreign dl "dlopen";
_unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #foreign dl "dlsym";
_unix_dlclose :: proc(handle: rawptr) -> int #foreign dl "dlclose";
_unix_dlerror :: proc() -> ^u8 #foreign dl "dlerror";
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
cstr := strings.new_c_string(path);
handle := _unix_open(cstr, mode);
free(cstr);
if(handle == -1) {
return 0, 1;
}
return handle, 0;
}
// NOTE(zangent): This is here for compatability reasons. Should this be here?
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
return open_simple(path, mode);
}
close :: proc(fd: Handle) {
_unix_close(fd);
}
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
sz := _unix_read(fd, &data[0], len(data));
return sz, 0;
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
sz := _unix_write(fd, &data[0], len(data));
return sz, 0;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
res := _unix_seek(fd, offset, i32(whence));
return res, 0;
}
// NOTE(bill): Uses startup to initialize it
stdin: Handle = 0;
stdout: Handle = 1;
stderr: Handle = 2;
/* TODO(zangent): Implement these!
last_write_time :: proc(fd: Handle) -> File_Time {}
last_write_time_by_name :: proc(name: string) -> File_Time {}
*/
stat :: proc(path: string) -> (Stat, int) #inline {
s: Stat;
cstr := strings.new_c_string(path);
defer free(cstr);
ret_int := _unix_stat(cstr, &s);
return s, int(ret_int);
}
access :: proc(path: string, mask: int) -> bool #inline {
cstr := strings.new_c_string(path);
defer free(cstr);
return _unix_access(cstr, mask) == 0;
}
read_entire_file :: proc(name: string) -> ([]byte, bool) {
fd: Handle;
err: Errno;
size: i64;
fd, err = open_simple(name, O_RDONLY);
if(err != 0) {
fmt.println("Failed to open file.");
return nil, false;
}
defer close(fd);
// We have a file
size, err = seek(fd, 0, SEEK_END);
if(err != 0) {
fmt.println("Failed to seek to end of file.");
return nil, false;
}
_, err = seek(fd, 0, SEEK_SET);
if(err != 0) {
fmt.println("Failed to seek to beginning of file.");
return nil, false;
}
// We have a file size!
data := make([]u8, size+1);
if data == nil {
fmt.println("Failed to allocate file buffer.");
return nil, false;
}
read(fd, data);
data[size] = 0;
return data, true;
}
heap_alloc :: proc(size: int) -> rawptr {
assert(size > 0);
return _unix_malloc(size);
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
return _unix_realloc(ptr, new_size);
}
heap_free :: proc(ptr: rawptr) {
_unix_free(ptr);
}
getenv :: proc(name: string) -> (string, bool) {
path_str := strings.new_c_string(name);
cstr: ^u8 = _unix_getenv(path_str);
free(path_str);
if(cstr == nil) {
return "", false;
}
return strings.to_odin_string(cstr), true;
}
exit :: proc(code: int) {
_unix_exit(code);
}
current_thread_id :: proc() -> int {
// return int(_unix_gettid());
return 0;
}
dlopen :: proc(filename: string, flags: int) -> rawptr #inline {
cstr := strings.new_c_string(filename);
handle := _unix_dlopen(cstr, flags);
free(cstr);
return handle;
}
dlsym :: proc(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
assert(handle != nil);
cstr := strings.new_c_string(symbol);
proc_handle := _unix_dlsym(handle, cstr);
free(cstr);
return proc_handle;
}
dlclose :: proc(handle: rawptr) -> bool #inline {
assert(handle != nil);
return _unix_dlclose(handle) == 0;
}
dlerror :: proc() -> string {
return strings.to_odin_string(_unix_dlerror());
}
_alloc_command_line_arguments :: proc() -> []string {
// TODO(bill):
return nil;
}
+140 -70
View File
@@ -1,6 +1,5 @@
#import win32 "sys/windows.odin";
#import "fmt.odin";
#import fmt "fmt.odin";
Handle :: int;
File_Time :: u64;
@@ -50,105 +49,114 @@ WSAECONNRESET: Errno : 10054;
ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
// "Argv" arguments converted to Odin strings
immutable args := _alloc_command_line_arguments();
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
using win32;
if path.count == 0 {
if len(path) == 0 {
return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
}
access: u32;
match mode & (O_RDONLY|O_WRONLY|O_RDWR) {
case O_RDONLY: access = FILE_GENERIC_READ;
case O_WRONLY: access = FILE_GENERIC_WRITE;
case O_RDWR: access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
case O_RDONLY: access = win32.FILE_GENERIC_READ;
case O_WRONLY: access = win32.FILE_GENERIC_WRITE;
case O_RDWR: access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE;
}
if mode&O_CREAT != 0 {
access |= FILE_GENERIC_WRITE;
access |= win32.FILE_GENERIC_WRITE;
}
if mode&O_APPEND != 0 {
access &~= FILE_GENERIC_WRITE;
access |= FILE_APPEND_DATA;
access &~= win32.FILE_GENERIC_WRITE;
access |= win32.FILE_APPEND_DATA;
}
share_mode := cast(u32)(FILE_SHARE_READ|FILE_SHARE_WRITE);
sa: ^SECURITY_ATTRIBUTES = nil;
sa_inherit := SECURITY_ATTRIBUTES{length = size_of(SECURITY_ATTRIBUTES), inherit_handle = 1};
share_mode := u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE);
sa: ^win32.Security_Attributes = nil;
sa_inherit := win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = 1};
if mode&O_CLOEXEC == 0 {
sa = ^sa_inherit;
sa = &sa_inherit;
}
create_mode: u32;
match {
case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
create_mode = CREATE_NEW;
create_mode = win32.CREATE_NEW;
case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
create_mode = CREATE_ALWAYS;
create_mode = win32.CREATE_ALWAYS;
case mode&O_CREAT == O_CREAT:
create_mode = OPEN_ALWAYS;
create_mode = win32.OPEN_ALWAYS;
case mode&O_TRUNC == O_TRUNC:
create_mode = TRUNCATE_EXISTING;
create_mode = win32.TRUNCATE_EXISTING;
default:
create_mode = OPEN_EXISTING;
create_mode = win32.OPEN_EXISTING;
}
buf: [300]byte;
copy(buf[..], cast([]byte)path);
copy(buf[..], []byte(path));
handle := cast(Handle)CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil);
handle := Handle(win32.CreateFileA(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
if handle != INVALID_HANDLE {
return handle, ERROR_NONE;
}
err := GetLastError();
return INVALID_HANDLE, cast(Errno)err;
err := win32.GetLastError();
return INVALID_HANDLE, Errno(err);
}
close :: proc(fd: Handle) {
win32.CloseHandle(cast(win32.HANDLE)fd);
win32.CloseHandle(win32.Handle(fd));
}
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
return write(fd, []byte(str));
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
}
bytes_written: i32;
e := win32.WriteFile(cast(win32.HANDLE)fd, data.data, cast(i32)data.count, ^bytes_written, nil);
e := win32.WriteFile(win32.Handle(fd), &data[0], i32(len(data)), &bytes_written, nil);
if e == win32.FALSE {
err := win32.GetLastError();
return 0, cast(Errno)err;
return 0, Errno(err);
}
return cast(int)bytes_written, ERROR_NONE;
return int(bytes_written), ERROR_NONE;
}
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE;
}
bytes_read: i32;
e := win32.ReadFile(cast(win32.HANDLE)fd, data.data, cast(u32)data.count, ^bytes_read, nil);
e := win32.ReadFile(win32.Handle(fd), &data[0], u32(len(data)), &bytes_read, nil);
if e == win32.FALSE {
err := win32.GetLastError();
return 0, cast(Errno)err;
return 0, Errno(err);
}
return cast(int)bytes_read, ERROR_NONE;
return int(bytes_read), ERROR_NONE;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
using win32;
w: u32;
match whence {
case 0: w = FILE_BEGIN;
case 1: w = FILE_CURRENT;
case 2: w = FILE_END;
case 0: w = win32.FILE_BEGIN;
case 1: w = win32.FILE_CURRENT;
case 2: w = win32.FILE_END;
}
hi := cast(i32)(offset>>32);
lo := cast(i32)(offset);
ft := GetFileType(cast(HANDLE)fd);
if ft == FILE_TYPE_PIPE {
hi := i32(offset>>32);
lo := i32(offset);
ft := win32.GetFileType(win32.Handle(fd));
if ft == win32.FILE_TYPE_PIPE {
return 0, ERROR_FILE_IS_PIPE;
}
dw_ptr := SetFilePointer(cast(HANDLE)fd, lo, ^hi, w);
if dw_ptr == INVALID_SET_FILE_POINTER {
err := GetLastError();
return 0, cast(Errno)err;
dw_ptr := win32.SetFilePointer(win32.Handle(fd), lo, &hi, w);
if dw_ptr == win32.INVALID_SET_FILE_POINTER {
err := win32.GetLastError();
return 0, Errno(err);
}
return cast(i64)hi<<32 + cast(i64)dw_ptr, ERROR_NONE;
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
}
@@ -159,9 +167,9 @@ stderr := get_std_handle(win32.STD_ERROR_HANDLE);
get_std_handle :: proc(h: int) -> Handle {
fd := win32.GetStdHandle(cast(i32)h);
fd := win32.GetStdHandle(i32(h));
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
return cast(Handle)fd;
return Handle(fd);
}
@@ -170,38 +178,35 @@ get_std_handle :: proc(h: int) -> Handle {
last_write_time :: proc(fd: Handle) -> File_Time {
file_info: win32.BY_HANDLE_FILE_INFORMATION;
win32.GetFileInformationByHandle(cast(win32.HANDLE)fd, ^file_info);
lo := cast(File_Time)file_info.last_write_time.lo;
hi := cast(File_Time)file_info.last_write_time.hi;
file_info: win32.By_Handle_File_Information;
win32.GetFileInformationByHandle(win32.Handle(fd), &file_info);
lo := File_Time(file_info.last_write_time.lo);
hi := File_Time(file_info.last_write_time.hi);
return lo | hi << 32;
}
last_write_time_by_name :: proc(name: string) -> File_Time {
last_write_time: win32.FILETIME;
data: win32.FILE_ATTRIBUTE_DATA;
last_write_time: win32.Filetime;
data: win32.File_Attribute_Data;
buf: [1024]byte;
assert(buf.count > name.count);
assert(len(buf) > len(name));
copy(buf[..], cast([]byte)name);
copy(buf[..], []byte(name));
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
if win32.GetFileAttributesExA(&buf[0], win32.GetFileExInfoStandard, &data) != 0 {
last_write_time = data.last_write_time;
}
l := cast(File_Time)last_write_time.lo;
h := cast(File_Time)last_write_time.hi;
l := File_Time(last_write_time.lo);
h := File_Time(last_write_time.hi);
return l | h << 32;
}
read_entire_file :: proc(name: string) -> ([]byte, bool) {
buf: [300]byte;
copy(buf[..], cast([]byte)name);
copy(buf[..], []byte(name));
fd, err := open(name, O_RDONLY, 0);
if err != ERROR_NONE {
@@ -210,13 +215,16 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
defer close(fd);
length: i64;
file_size_ok := win32.GetFileSizeEx(cast(win32.HANDLE)fd, ^length) != 0;
if !file_size_ok {
if ok := win32.GetFileSizeEx(win32.Handle(fd), &length) != 0; !ok {
return nil, false;
}
data := new_slice(u8, length);
if data.data == nil {
if length == 0 {
return nil, true;
}
data := make([]byte, length);
if data == nil {
return nil, false;
}
@@ -228,18 +236,18 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
to_read: u32;
MAX :: 1<<32-1;
if remaining <= MAX {
to_read = cast(u32)remaining;
to_read = u32(remaining);
} else {
to_read = MAX;
}
win32.ReadFile(cast(win32.HANDLE)fd, ^data[total_read], to_read, ^single_read_length, nil);
win32.ReadFile(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
if single_read_length <= 0 {
free(data);
return nil, false;
}
total_read += cast(i64)single_read_length;
total_read += i64(single_read_length);
}
return data, true;
@@ -248,7 +256,6 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
heap_alloc :: proc(size: int) -> rawptr {
assert(size > 0);
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size);
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
@@ -270,14 +277,77 @@ heap_free :: proc(ptr: rawptr) {
exit :: proc(code: int) {
win32.ExitProcess(cast(u32)code);
win32.ExitProcess(u32(code));
}
current_thread_id :: proc() -> int {
return cast(int)win32.GetCurrentThreadId();
return int(win32.GetCurrentThreadId());
}
_alloc_command_line_arguments :: proc() -> []string {
alloc_ucs2_to_utf8 :: proc(wstr: ^u16) -> string {
wstr_len := 0;
for (wstr+wstr_len)^ != 0 {
wstr_len++;
}
len := 2*wstr_len-1;
buf := make([]byte, len+1);
str := slice_ptr(wstr, wstr_len+1);
i, j := 0, 0;
for str[j] != 0 {
match {
case str[j] < 0x80:
if i+1 > len {
return "";
}
buf[i] = byte(str[j]); i++;
j++;
case str[j] < 0x800:
if i+2 > len {
return "";
}
buf[i] = byte(0xc0 + (str[j]>>6)); i++;
buf[i] = byte(0x80 + (str[j]&0x3f)); i++;
j++;
case 0xd800 <= str[j] && str[j] < 0xdc00:
if i+4 > len {
return "";
}
c := rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000;
buf[i] = byte(0xf0 + (c >> 18)); i++;
buf[i] = byte(0x80 + ((c >> 12) & 0x3f)); i++;
buf[i] = byte(0x80 + ((c >> 6) & 0x3f)); i++;
buf[i] = byte(0x80 + ((c ) & 0x3f)); i++;
j += 2;
case 0xdc00 <= str[j] && str[j] < 0xe000:
return "";
default:
if i+3 > len {
return "";
}
buf[i] = 0xe0 + byte (str[j] >> 12); i++;
buf[i] = 0x80 + byte((str[j] >> 6) & 0x3f); i++;
buf[i] = 0x80 + byte((str[j] ) & 0x3f); i++;
j++;
}
}
return string(buf[0..<i]);
}
arg_count: i32;
arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count);
arg_list := make([]string, arg_count);
for _, i in arg_list {
arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^);
}
return arg_list;
}
+221 -139
View File
@@ -1,11 +1,14 @@
#import "fmt.odin";
#import "strings.odin";
Handle :: i32;
File_Time :: u64;
Errno :: int;
// INVALID_HANDLE: Handle : -1;
// TODO(zangent): Find out how to make this work on x64 and x32.
AddressSize :: i64;
// INVALID_HANDLE: Handle : -1;
O_RDONLY :: 0x00000;
O_WRONLY :: 0x00001;
@@ -19,91 +22,178 @@ 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;
// 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;
// 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;
// Windows reserves errors >= 1<<29 for application use
// ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
args: [dynamic]string;
FileTime :: struct #ordered {
seconds: i64,
nanoseconds: i64
}
Stat :: struct #ordered {
device_id : i32, // ID of device containing file
mode : u16, // Mode of the file
nlink : u16, // Number of hard links
serial : u64, // File serial number
uid : u32, // User ID of the file's owner
gid : u32, // Group ID of the file's group
rdev : i32, // Device ID, if device
last_access : FileTime, // Time of last access
modified : FileTime, // Time of last modification
status_change : FileTime, // Time of last status change
created : FileTime, // Time of creation
size : i64, // Size of the file, in bytes
blocks : i64, // Number of blocks allocated for the file
block_size: i32, // Optimal blocksize for I/O
flags : u32, // User-defined flags for the file
gen_num : u32, // File generation number ...?
_spare : i32, // RESERVED
_reserve1,
_reserve2 : i64, // RESERVED
};
// File type
S_IFMT :: 0170000; // Type of file mask
S_IFIFO :: 0010000; // Named pipe (fifo)
S_IFCHR :: 0020000; // Character special
S_IFDIR :: 0040000; // Directory
S_IFBLK :: 0060000; // Block special
S_IFREG :: 0100000; // Regular
S_IFLNK :: 0120000; // Symbolic link
S_IFSOCK :: 0140000; // Socket
// File mode
// Read, write, execute/search by owner
S_IRWXU :: 0000700; // RWX mask for owner
S_IRUSR :: 0000400; // R for owner
S_IWUSR :: 0000200; // W for owner
S_IXUSR :: 0000100; // X for owner
// Read, write, execute/search by group
S_IRWXG :: 0000070; // RWX mask for group
S_IRGRP :: 0000040; // R for group
S_IWGRP :: 0000020; // W for group
S_IXGRP :: 0000010; // X for group
// Read, write, execute/search by others
S_IRWXO :: 0000007; // RWX mask for other
S_IROTH :: 0000004; // R for other
S_IWOTH :: 0000002; // W for other
S_IXOTH :: 0000001; // X for other
S_ISUID :: 0004000; // Set user id on execution
S_ISGID :: 0002000; // Set group id on execution
S_ISVTX :: 0001000; // Directory restrcted delete
S_ISLNK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFLNK; }
S_ISREG :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFREG; }
S_ISDIR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFDIR; }
S_ISCHR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFCHR; }
S_ISBLK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFBLK; }
S_ISFIFO :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFIFO; }
S_ISSOCK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFSOCK;}
R_OK :: 4; // Test for read permission
W_OK :: 2; // Test for write permission
X_OK :: 1; // Test for execute permission
F_OK :: 0; // Test for file existance
#foreign_system_library dl "dl";
#foreign_system_library libc "c";
unix_open :: proc(path: ^u8, mode: int, perm: u32) -> Handle #foreign libc "open";
unix_close :: proc(handle: Handle) #foreign libc "close";
unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int #foreign libc "read";
unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int #foreign libc "write";
unix_gettid :: proc() -> u64 #foreign libc "gettid";
unix_open :: proc(path: ^u8, mode: int) -> Handle #foreign libc "open";
unix_close :: proc(handle: Handle) #foreign libc "close";
unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> AddressSize #foreign libc "read";
unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> AddressSize #foreign libc "write";
unix_lseek :: proc(fs: Handle, offset: AddressSize, whence: int) -> AddressSize #foreign libc "lseek";
unix_gettid :: proc() -> u64 #foreign libc "gettid";
unix_stat :: proc(path: ^u8, stat: ^Stat) -> int #foreign libc "stat";
unix_access :: proc(path: ^u8, mask: int) -> int #foreign libc "access";
unix_malloc :: proc(size: int) -> rawptr #foreign libc "malloc";
unix_free :: proc(ptr: rawptr) #foreign libc "free";
unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #foreign libc "realloc";
unix_malloc :: proc(size: int) -> rawptr #foreign libc "malloc";
unix_free :: proc(ptr: rawptr) #foreign libc "free";
unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #foreign libc "realloc";
unix_getenv :: proc(^u8) -> ^u8 #foreign libc "getenv";
unix_exit :: proc(status: int) #foreign libc "exit";
unix_exit :: proc(status: int) #foreign libc "exit";
unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #foreign dl "dlopen";
unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #foreign dl "dlsym";
unix_dlclose :: proc(handle: rawptr) -> int #foreign dl "dlclose";
unix_dlerror :: proc() -> ^u8 #foreign dl "dlerror";
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
cstr := strings.new_c_string(path);
handle := unix_open(cstr, mode);
free(cstr);
if(handle == -1) {
return 0, 1;
}
return handle, 0;
}
// NOTE(zangent): This is here for compatability reasons. Should this be here?
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
return unix_open(path.data, mode, perm), 0;
return open_simple(path, mode);
}
close :: proc(fd: Handle) {
unix_close(fd);
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
return unix_write(fd, data.data, data.count), 0;
write :: proc(fd: Handle, data: []byte) -> (AddressSize, Errno) {
assert(fd != -1);
bytes_written := unix_write(fd, &data[0], len(data));
if(bytes_written == -1) {
return 0, 1;
}
return bytes_written, 0;
}
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
return unix_read(fd, data.data, data.count), 0;
read :: proc(fd: Handle, data: []byte) -> (AddressSize, Errno) {
assert(fd != -1);
bytes_read := unix_read(fd, &data[0], len(data));
if(bytes_read == -1) {
return 0, 1;
}
return bytes_read, 0;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
/*
using win32;
w: u32;
match whence {
case 0: w = FILE_BEGIN;
case 1: w = FILE_CURRENT;
case 2: w = FILE_END;
}
hi := cast(i32)(offset>>32);
lo := cast(i32)(offset);
ft := GetFileType(cast(HANDLE)fd);
if ft == FILE_TYPE_PIPE {
return 0, ERROR_FILE_IS_PIPE;
}
dw_ptr := SetFilePointer(cast(HANDLE)fd, lo, ^hi, w);
if dw_ptr == INVALID_SET_FILE_POINTER {
err := GetLastError();
return 0, cast(Errno)err;
}
return cast(i64)hi<<32 + cast(i64)dw_ptr, ERROR_NONE;
seek :: proc(fd: Handle, offset: AddressSize, whence: int) -> (AddressSize, Errno) {
assert(fd != -1);
*/
return 0, 0;
final_offset := unix_lseek(fd, offset, whence);
if(final_offset == -1) {
return 0, 1;
}
return final_offset, 0;
}
@@ -112,111 +202,85 @@ stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE);
stdout: Handle = 1; // get_std_handle(win32.STD_OUTPUT_HANDLE);
stderr: Handle = 2; // get_std_handle(win32.STD_ERROR_HANDLE);
/* TODO(zangent): Implement these!
last_write_time :: proc(fd: Handle) -> File_Time {}
last_write_time_by_name :: proc(name: string) -> File_Time {}
*/
/*
get_std_handle :: proc(h: int) -> Handle {
fd := win32.GetStdHandle(cast(i32)h);
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
return cast(Handle)fd;
stat :: proc(path: string) -> (Stat, bool) #inline {
s: Stat;
cstr := strings.new_c_string(path);
defer free(cstr);
ret_int := unix_stat(cstr, &s);
return s, ret_int==0;
}
last_write_time :: proc(fd: Handle) -> File_Time {
file_info: win32.BY_HANDLE_FILE_INFORMATION;
win32.GetFileInformationByHandle(cast(win32.HANDLE)fd, ^file_info);
lo := cast(File_Time)file_info.last_write_time.lo;
hi := cast(File_Time)file_info.last_write_time.hi;
return lo | hi << 32;
access :: proc(path: string, mask: int) -> bool #inline {
cstr := strings.new_c_string(path);
defer free(cstr);
return unix_access(cstr, mask) == 0;
}
last_write_time_by_name :: proc(name: string) -> File_Time {
last_write_time: win32.FILETIME;
data: win32.FILE_ATTRIBUTE_DATA;
buf: [1024]byte;
assert(buf.count > name.count);
copy(buf[:], cast([]byte)name);
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
last_write_time = data.last_write_time;
}
l := cast(File_Time)last_write_time.lo;
h := cast(File_Time)last_write_time.hi;
return l | h << 32;
}
read_entire_file :: proc(name: string) -> ([]byte, bool) {
buf: [300]byte;
copy(buf[:], cast([]byte)name);
fd, err := open(name, O_RDONLY, 0);
if err != ERROR_NONE {
handle, err := open_simple(name, O_RDONLY);
if(err != 0) {
fmt.println("Failed to open file.");
return nil, false;
}
defer close(fd);
defer(close(handle));
length: i64;
file_size_ok := win32.GetFileSizeEx(cast(win32.HANDLE)fd, ^length) != 0;
if !file_size_ok {
// We have a file!
size: AddressSize;
size, err = seek(handle, 0, SEEK_END);
if(err != 0) {
fmt.println("Failed to seek to end of file.");
return nil, false;
}
data := new_slice(u8, length);
if data.data == nil {
_, err = seek(handle, 0, SEEK_SET);
if(err != 0) {
fmt.println("Failed to seek to beginning of file.");
return nil, false;
}
single_read_length: i32;
total_read: i64;
// We have a file size!
for total_read < length {
remaining := length - total_read;
to_read: u32;
MAX :: 1<<32-1;
if remaining <= MAX {
to_read = cast(u32)remaining;
} else {
to_read = MAX;
}
win32.ReadFile(cast(win32.HANDLE)fd, ^data[total_read], to_read, ^single_read_length, nil);
if single_read_length <= 0 {
free(data);
return nil, false;
}
total_read += cast(i64)single_read_length;
data := make([]u8, size+1);
if data == nil {
fmt.println("Failed to allocate file buffer.");
return nil, false;
}
read(handle, data);
data[size] = 0;
return data, true;
}
*/
heap_alloc :: proc(size: int) -> rawptr {
heap_alloc :: proc(size: int) -> rawptr #inline {
assert(size > 0);
return unix_malloc(size);
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr #inline {
return unix_realloc(ptr, new_size);
}
heap_free :: proc(ptr: rawptr) {
heap_free :: proc(ptr: rawptr) #inline {
unix_free(ptr);
}
getenv :: proc(name: string) -> (string, bool) {
path_str := strings.new_c_string(name);
cstr: ^u8 = unix_getenv(path_str);
free(path_str);
if(cstr == nil) {
return "", false;
}
return strings.to_odin_string(cstr), true;
}
exit :: proc(code: int) {
exit :: proc(code: int) #inline {
unix_exit(code);
}
@@ -226,5 +290,23 @@ current_thread_id :: proc() -> int {
return 0;
}
dlopen :: proc(filename: string, flags: int) -> rawptr #inline {
cstr := strings.new_c_string(filename);
handle := unix_dlopen(cstr, flags);
free(cstr);
return handle;
}
dlsym :: proc(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
assert(handle != nil);
cstr := strings.new_c_string(symbol);
proc_handle := unix_dlsym(handle, cstr);
free(cstr);
return proc_handle;
}
dlclose :: proc(handle: rawptr) -> bool #inline {
assert(handle != nil);
return unix_dlclose(handle) == 0;
}
dlerror :: proc() -> string {
return strings.to_odin_string(unix_dlerror());
}
+27
View File
@@ -0,0 +1,27 @@
Any :: struct #ordered {
data: rawptr,
type_info: ^Type_Info,
}
String :: struct #ordered {
data: ^byte,
len: int,
};
Slice :: struct #ordered {
data: rawptr,
len: int,
cap: int,
};
Dynamic_Array :: struct #ordered {
data: rawptr,
len: int,
cap: int,
allocator: Allocator,
};
Dynamic_Map :: struct #ordered {
hashes: [dynamic]int,
entries: Dynamic_Array,
};
+119 -75
View File
@@ -18,24 +18,65 @@ parse_bool :: proc(s: string) -> (result: bool, ok: bool) {
return false, false;
}
_digit_value :: proc(r: rune) -> (int) {
ri := int(r);
v: int = 16;
match r {
case '0'..'9': v = ri-'0';
case 'a'..'z': v = ri-'a'+10;
case 'A'..'Z': v = ri-'A'+10;
}
return v;
}
parse_i64 :: proc(s: string, base: int) -> i64 {
result: i64;
for r in s {
v := _digit_value(r);
if v >= base {
break;
}
result *= i64(base);
result += i64(v);
}
return result;
}
parse_u64 :: proc(s: string, base: int) -> u64 {
result: u64;
for r in s {
v := _digit_value(r);
if v >= base {
break;
}
result *= u64(base);
result += u64(v);
}
return result;
}
parse_int :: proc(s: string, base: int) -> int {
return int(parse_i64(s, base));
}
parse_uint :: proc(s: string, base: int) -> uint {
return uint(parse_u64(s, base));
}
append_bool :: proc(buf: []byte, b: bool) -> string {
s := b ? "true" : "false";
append(buf, ..cast([]byte)s);
return cast(string)buf;
append(buf, ..[]byte(s));
return string(buf);
}
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
return append_bits(buf, u, base, false, digits, 0);
return append_bits(buf, u, base, false, 8*size_of(uint), digits, 0);
}
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
return append_bits(buf, cast(u64)i, base, i < 0, digits, 0);
}
itoa :: proc(buf: []byte, i: int) -> string {
return append_int(buf, cast(i64)i, 10);
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, 0);
}
itoa :: proc(buf: []byte, i: int) -> string { return append_int(buf, i64(i), 10); }
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
return cast(string)generic_ftoa(buf, f, fmt, prec, bit_size);
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
}
@@ -63,18 +104,18 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
flt: ^Float_Info;
match bit_size {
case 32:
bits = cast(u64)transmute(u32)cast(f32)val;
flt = ^f32_info;
bits = u64(transmute(u32, f32(val)));
flt = &f32_info;
case 64:
bits = transmute(u64)val;
flt = ^f64_info;
bits = transmute(u64, val);
flt = &f64_info;
default:
panic("strconv: invalid bit_size");
}
neg := bits>>(flt.expbits+flt.mantbits) != 0;
exp := cast(int)(bits>>flt.mantbits) & (1<<flt.expbits - 1);
mant := bits & (cast(u64)1 << flt.mantbits - 1);
exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
mant := bits & (u64(1) << flt.mantbits - 1);
match exp {
case 1<<flt.expbits - 1:
@@ -86,22 +127,22 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
} else {
s = "+Inf";
}
append(buf, ..cast([]byte)s);
append(buf, ..[]byte(s));
return buf;
case 0: // denormalized
exp++;
default:
mant |= cast(u64)1 << flt.mantbits;
mant |= u64(1) << flt.mantbits;
}
exp += flt.bias;
d_: Decimal;
d := ^d_;
d := &d_;
assign(d, mant);
shift(d, exp - cast(int)flt.mantbits);
shift(d, exp - int(flt.mantbits));
digs: Decimal_Slice;
shortest := prec < 0;
if shortest {
@@ -133,50 +174,33 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte {
match fmt {
case 'f', 'F':
add_bytes :: proc(dst: ^[]byte, w: ^int, bytes: ..byte) {
for b in bytes {
if dst.capacity <= w^ {
break;
}
dst.count++;
dst[w^] = b;
w^++;
}
}
dst := buf[..];
w := 0;
if neg {
add_bytes(^dst, ^w, '-');
} else {
add_bytes(^dst, ^w, '+');
}
append(buf, neg ? '-' : '+');
// integer, padded with zeros when needed
if digs.decimal_point > 0 {
m := min(digs.count, digs.decimal_point);
add_bytes(^dst, ^w, ..digs.digits[..m]);
append(buf, ..digs.digits[0..<m]);
for ; m < digs.decimal_point; m++ {
add_bytes(^dst, ^w, '0');
append(buf, '0');
}
} else {
add_bytes(^dst, ^w, '0');
append(buf, '0');
}
// fractional part
if prec > 0 {
add_bytes(^dst, ^w, '.');
append(buf, '.');
for i in 0..prec {
c: byte = '0';
if j := digs.decimal_point + i; 0 <= j && j < digs.count {
c = digs.digits[j];
}
add_bytes(^dst, ^w, c);
append(buf, c);
}
}
return buf[..w];
return buf;
case 'e', 'E':
panic("strconv: e/E float printing is not yet supported");
@@ -207,14 +231,14 @@ round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
332*(dp-nd) >= 100*(exp-mantbits)
*/
minexp := flt.bias+1;
if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - cast(int)flt.mantbits) {
if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - int(flt.mantbits)) {
// Number is already its shortest
return;
}
upper_: Decimal; upper: = ^upper_;
upper_: Decimal; upper: = &upper_;
assign(upper, 2*mant - 1);
shift(upper, exp - cast(int)flt.mantbits - 1);
shift(upper, exp - int(flt.mantbits) - 1);
mantlo: u64;
explo: int;
@@ -225,13 +249,13 @@ round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
mantlo = 2*mant - 1;
explo = exp-1;
}
lower_: Decimal; lower: = ^lower_;
lower_: Decimal; lower: = &lower_;
assign(lower, 2*mantlo + 1);
shift(lower, explo - cast(int)flt.mantbits - 1);
shift(lower, explo - int(flt.mantbits) - 1);
inclusive := mant%2 == 0;
for i in 0..d.count {
for i in 0..<d.count {
l: byte = '0'; // lower digit
if i < lower.count {
l = lower.digits[i];
@@ -265,7 +289,39 @@ MAX_BASE :: 32;
immutable digits := "0123456789abcdefghijklmnopqrstuvwxyz";
append_bits :: proc(buf: []byte, u: u64, base: int, neg: bool, digits: string, flags: Int_Flag) -> string {
is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) {
neg := false;
if is_signed {
match bit_size {
case 8:
i := i8(u);
neg = i < 0;
if neg { i = -i; }
u = u64(i);
case 16:
i := i16(u);
neg = i < 0;
if neg { i = -i; }
u = u64(i);
case 32:
i := i32(u);
neg = i < 0;
if neg { i = -i; }
u = u64(i);
case 64:
i := i64(u);
neg = i < 0;
if neg { i = -i; }
u = u64(i);
default:
panic("is_integer_negative: Unknown integer size");
}
}
return u, neg;
}
append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> string {
is_pow2 :: proc(x: i64) -> bool {
if (x <= 0) {
return false;
@@ -278,33 +334,20 @@ append_bits :: proc(buf: []byte, u: u64, base: int, neg: bool, digits: string, f
}
a: [65]byte;
i := a.count;
if neg {
u = -u;
i := len(a);
neg: bool;
u, neg = is_integer_negative(u, is_signed, bit_size);
for b := u64(base); u >= b; {
i--;
q := u / b;
a[i] = digits[uint(u-q*b)];
u = q;
}
if is_pow2(cast(i64)base) {
b := cast(u64)base;
m := cast(uint)b - 1;
for u >= b {
i--;
a[i] = digits[cast(uint)u & m];
u >>= b;
}
i--;
a[i] = digits[cast(uint)u];
} else {
b := cast(u64)base;
for u >= b {
i--;
q := u / b;
a[i] = digits[cast(uint)(u-q*b)];
u = q;
}
i--;
a[i] = digits[cast(uint)u];
}
i--;
a[i] = digits[uint(u)];
if flags&Int_Flag.PREFIX != 0 {
ok := true;
@@ -312,6 +355,7 @@ append_bits :: proc(buf: []byte, u: u64, base: int, neg: bool, digits: string, f
case 2: i--; a[i] = 'b';
case 8: i--; a[i] = 'o';
case 10: i--; a[i] = 'd';
case 12: i--; a[i] = 'z';
case 16: i--; a[i] = 'x';
default: ok = false;
}
@@ -331,6 +375,6 @@ append_bits :: proc(buf: []byte, u: u64, base: int, neg: bool, digits: string, f
append(buf, ..a[i..]);
return cast(string)buf;
return string(buf);
}
+8 -9
View File
@@ -1,15 +1,14 @@
new_c_string :: proc(s: string) -> ^byte {
c := new_slice(byte, s.count+1);
copy(c, cast([]byte)s);
c[s.count] = 0;
return c.data;
c := make([]byte, len(s)+1);
copy(c, []byte(s));
c[len(s)] = 0;
return &c[0];
}
to_odin_string :: proc(c: ^byte) -> string {
s: string;
s.data = c;
for (c+s.count)^ != 0 {
s.count++;
len := 0;
for (c+len)^ != 0 {
len++;
}
return s;
return string(slice_ptr(c, len));
}
+2 -91
View File
@@ -1,91 +1,2 @@
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
#import "atomic.odin";
Semaphore :: struct {
_handle: win32.HANDLE,
}
Mutex :: struct {
_semaphore: Semaphore,
_counter: i32,
_owner: i32,
_recursion: i32,
}
current_thread_id :: proc() -> i32 {
return cast(i32)win32.GetCurrentThreadId();
}
semaphore_init :: proc(s: ^Semaphore) {
s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
}
semaphore_destroy :: proc(s: ^Semaphore) {
win32.CloseHandle(s._handle);
}
semaphore_post :: proc(s: ^Semaphore, count: int) {
win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
}
semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
semaphore_wait :: proc(s: ^Semaphore) {
win32.WaitForSingleObject(s._handle, win32.INFINITE);
}
mutex_init :: proc(m: ^Mutex) {
atomic.store(^m._counter, 0);
atomic.store(^m._owner, current_thread_id());
semaphore_init(^m._semaphore);
m._recursion = 0;
}
mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(^m._semaphore);
}
mutex_lock :: proc(m: ^Mutex) {
thread_id := current_thread_id();
if atomic.fetch_add(^m._counter, 1) > 0 {
if thread_id != atomic.load(^m._owner) {
semaphore_wait(^m._semaphore);
}
}
atomic.store(^m._owner, thread_id);
m._recursion++;
}
mutex_try_lock :: proc(m: ^Mutex) -> bool {
thread_id := current_thread_id();
if atomic.load(^m._owner) == thread_id {
atomic.fetch_add(^m._counter, 1);
} else {
expected: i32 = 0;
if atomic.load(^m._counter) != 0 {
return false;
}
if atomic.compare_exchange(^m._counter, expected, 1) == 0 {
return false;
}
atomic.store(^m._owner, thread_id);
}
m._recursion++;
return true;
}
mutex_unlock :: proc(m: ^Mutex) {
recursion: i32;
thread_id := current_thread_id();
assert(thread_id == atomic.load(^m._owner));
m._recursion--;
recursion = m._recursion;
if recursion == 0 {
atomic.store(^m._owner, thread_id);
}
if atomic.fetch_add(^m._counter, -1) > 1 {
if recursion == 0 {
semaphore_release(^m._semaphore);
}
}
}
#load "sync_windows.odin" when ODIN_OS == "windows";
#load "sync_linux.odin" when ODIN_OS == "linux";
+35 -25
View File
@@ -7,11 +7,12 @@ CONTEXT_FLAGS_ARB :: 0x2094;
CONTEXT_PROFILE_MASK_ARB :: 0x9126;
CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002;
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001;
CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x00000002;
HGLRC :: HANDLE;
COLORREF :: u32;
Hglrc :: Handle;
Color_Ref :: u32;
LAYERPLANEDESCRIPTOR :: struct #ordered {
Layer_Plane_Descriptor :: struct #ordered {
size: u16,
version: u16,
flags: u32,
@@ -35,38 +36,47 @@ LAYERPLANEDESCRIPTOR :: struct #ordered {
aux_buffers: byte,
layer_type: byte,
reserved: byte,
transparent: COLORREF,
transparent: Color_Ref,
}
POINTFLOAT :: struct #ordered {
Point_Float :: struct #ordered {
x, y: f32,
}
GLYPHMETRICSFLOAT :: struct #ordered {
Glyph_Metrics_Float :: struct #ordered {
black_box_x: f32,
black_box_y: f32,
glyph_origin: POINTFLOAT,
glyph_origin: Point_Float,
cell_inc_x: f32,
cell_inc_y: f32,
}
CreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
ChoosePixelFormatARBType :: #type proc(hdc: HDC, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> BOOL #cc_c;
CreateContextAttribsARB_Type :: #type proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
ChoosePixelFormatARB_Type :: #type proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c;
SwapIntervalEXT_Type :: #type proc(interval : i32) -> bool #cc_c;
GetExtensionsStringARB_Type :: #type proc(Hdc) -> ^byte #cc_c;
CreateContext :: proc(hdc: HDC) -> HGLRC #foreign opengl32 "wglCreateContext";
MakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32 "wglMakeCurrent";
GetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32 "wglGetProcAddress";
DeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32 "wglDeleteContext";
CopyContext :: proc(src, dst: HGLRC, mask: u32) -> BOOL #foreign opengl32 "wglCopyContext";
CreateLayerContext :: proc(hdc: HDC, layer_plane: i32) -> HGLRC #foreign opengl32 "wglCreateLayerContext";
DescribeLayerPlane :: proc(hdc: HDC, pixel_format, layer_plane: i32, bytes: u32, pd: ^LAYERPLANEDESCRIPTOR) -> BOOL #foreign opengl32 "wglDescribeLayerPlane";
GetCurrentContext :: proc() -> HGLRC #foreign opengl32 "wglGetCurrentContext";
GetCurrentDC :: proc() -> HDC #foreign opengl32 "wglGetCurrentDC";
GetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglGetLayerPaletteEntries";
RealizeLayerPalette :: proc(hdc: HDC, layer_plane: i32, realize: BOOL) -> BOOL #foreign opengl32 "wglRealizeLayerPalette";
SetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglSetLayerPaletteEntries";
ShareLists :: proc(hglrc1, hglrc2: HGLRC) -> BOOL #foreign opengl32 "wglShareLists";
SwapLayerBuffers :: proc(hdc: HDC, planes: u32) -> BOOL #foreign opengl32 "wglSwapLayerBuffers";
UseFontBitmaps :: proc(hdc: HDC, first, count, list_base: u32) -> BOOL #foreign opengl32 "wglUseFontBitmaps";
UseFontOutlines :: proc(hdc: HDC, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^GLYPHMETRICSFLOAT) -> BOOL #foreign opengl32 "wglUseFontOutlines";
CreateContextAttribsARB: CreateContextAttribsARB_Type;
ChoosePixelFormatARB: ChoosePixelFormatARB_Type;
SwapIntervalEXT: SwapIntervalEXT_Type;
GetExtensionsStringARB: GetExtensionsStringARB_Type;
CreateContext :: proc(hdc: Hdc) -> Hglrc #foreign opengl32 "wglCreateContext";
MakeCurrent :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool #foreign opengl32 "wglMakeCurrent";
GetProcAddress :: proc(c_str: ^u8) -> Proc #foreign opengl32 "wglGetProcAddress";
DeleteContext :: proc(hglrc: Hglrc) -> Bool #foreign opengl32 "wglDeleteContext";
CopyContext :: proc(src, dst: Hglrc, mask: u32) -> Bool #foreign opengl32 "wglCopyContext";
CreateLayerContext :: proc(hdc: Hdc, layer_plane: i32) -> Hglrc #foreign opengl32 "wglCreateLayerContext";
DescribeLayerPlane :: proc(hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^Layer_Plane_Descriptor) -> Bool #foreign opengl32 "wglDescribeLayerPlane";
GetCurrentContext :: proc() -> Hglrc #foreign opengl32 "wglGetCurrentContext";
GetCurrentDC :: proc() -> Hdc #foreign opengl32 "wglGetCurrentDC";
GetLayerPaletteEntries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #foreign opengl32 "wglGetLayerPaletteEntries";
RealizeLayerPalette :: proc(hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool #foreign opengl32 "wglRealizeLayerPalette";
SetLayerPaletteEntries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #foreign opengl32 "wglSetLayerPaletteEntries";
ShareLists :: proc(hglrc1, hglrc2: Hglrc) -> Bool #foreign opengl32 "wglShareLists";
SwapLayerBuffers :: proc(hdc: Hdc, planes: u32) -> Bool #foreign opengl32 "wglSwapLayerBuffers";
UseFontBitmaps :: proc(hdc: Hdc, first, count, list_base: u32) -> Bool #foreign opengl32 "wglUseFontBitmaps";
UseFontOutlines :: proc(hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_Metrics_Float) -> Bool #foreign opengl32 "wglUseFontOutlines";
+135 -133
View File
@@ -2,29 +2,29 @@
#foreign_system_library "user32.lib" when ODIN_OS == "windows";
#foreign_system_library "gdi32.lib" when ODIN_OS == "windows";
#foreign_system_library "winmm.lib" when ODIN_OS == "windows";
#foreign_system_library "shell32.lib" when ODIN_OS == "windows";
HANDLE :: rawptr;
HWND :: HANDLE;
HDC :: HANDLE;
HINSTANCE :: HANDLE;
HICON :: HANDLE;
HCURSOR :: HANDLE;
HMENU :: HANDLE;
HBRUSH :: HANDLE;
HGDIOBJ :: HANDLE;
HMODULE :: HANDLE;
WPARAM :: uint;
LPARAM :: int;
LRESULT :: int;
ATOM :: i16;
BOOL :: i32;
WNDPROC :: #type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c;
Handle :: rawptr;
Hwnd :: Handle;
Hdc :: Handle;
Hinstance :: Handle;
Hicon :: Handle;
Hcursor :: Handle;
Hmenu :: Handle;
Hbrush :: Handle;
Hgdiobj :: Handle;
Hmodule :: Handle;
Wparam :: uint;
Lparam :: int;
Lresult :: int;
Bool :: i32;
Wnd_Proc :: #type proc(Hwnd, u32, Wparam, Lparam) -> Lresult #cc_c;
INVALID_HANDLE_VALUE :: cast(HANDLE)~cast(int)0;
INVALID_HANDLE :: Handle(~int(0));
FALSE: BOOL : 0;
TRUE: BOOL : 1;
FALSE: Bool : 0;
TRUE: Bool : 1;
CS_VREDRAW :: 0x0001;
CS_HREDRAW :: 0x0002;
@@ -56,7 +56,7 @@ WM_CHAR :: 0x0102;
PM_REMOVE :: 1;
COLOR_BACKGROUND :: cast(HBRUSH)(cast(int)1);
COLOR_BACKGROUND :: Hbrush(int(1));
BLACK_BRUSH :: 4;
SM_CXSCREEN :: 0;
@@ -65,53 +65,53 @@ SM_CYSCREEN :: 1;
SW_SHOW :: 5;
POINT :: struct #ordered {
Point :: struct #ordered {
x, y: i32,
}
WNDCLASSEXA :: struct #ordered {
WndClassExA :: struct #ordered {
size, style: u32,
wnd_proc: WNDPROC,
wnd_proc: Wnd_Proc,
cls_extra, wnd_extra: i32,
instance: HINSTANCE,
icon: HICON,
cursor: HCURSOR,
background: HBRUSH,
instance: Hinstance,
icon: Hicon,
cursor: Hcursor,
background: Hbrush,
menu_name, class_name: ^u8,
sm: HICON,
sm: Hicon,
}
MSG :: struct #ordered {
hwnd: HWND,
Msg :: struct #ordered {
hwnd: Hwnd,
message: u32,
wparam: WPARAM,
lparam: LPARAM,
wparam: Wparam,
lparam: Lparam,
time: u32,
pt: POINT,
pt: Point,
}
RECT :: struct #ordered {
Rect :: struct #ordered {
left: i32,
top: i32,
right: i32,
bottom: i32,
}
FILETIME :: struct #ordered {
Filetime :: struct #ordered {
lo, hi: u32,
}
SYSTEMTIME :: struct #ordered {
Systemtime :: struct #ordered {
year, month: u16,
day_of_week, day: u16,
hour, minute, second, millisecond: u16,
}
BY_HANDLE_FILE_INFORMATION :: struct #ordered {
By_Handle_File_Information :: struct #ordered {
file_attributes: u32,
creation_time,
last_access_time,
last_write_time: FILETIME,
last_write_time: Filetime,
volume_serial_number,
file_size_high,
file_size_low,
@@ -120,11 +120,11 @@ BY_HANDLE_FILE_INFORMATION :: struct #ordered {
file_index_low: u32,
}
FILE_ATTRIBUTE_DATA :: struct #ordered {
File_Attribute_Data :: struct #ordered {
file_attributes: u32,
creation_time,
last_access_time,
last_write_time: FILETIME,
last_write_time: Filetime,
file_size_high,
file_size_low: u32,
}
@@ -136,13 +136,13 @@ GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1;
GetLastError :: proc() -> i32 #foreign kernel32;
ExitProcess :: proc(exit_code: u32) #foreign kernel32;
GetDesktopWindow :: proc() -> HWND #foreign user32;
GetCursorPos :: proc(p: ^POINT) -> i32 #foreign user32;
ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign user32;
GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign kernel32;
GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign gdi32;
GetDesktopWindow :: proc() -> Hwnd #foreign user32;
GetCursorPos :: proc(p: ^Point) -> i32 #foreign user32;
ScreenToClient :: proc(h: Hwnd, p: ^Point) -> i32 #foreign user32;
GetModuleHandleA :: proc(module_name: ^u8) -> Hinstance #foreign kernel32;
GetStockObject :: proc(fn_object: i32) -> Hgdiobj #foreign gdi32;
PostQuitMessage :: proc(exit_code: i32) #foreign user32;
SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign user32;
SetWindowTextA :: proc(hwnd: Hwnd, c_string: ^u8) -> Bool #foreign user32;
QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign kernel32;
QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign kernel32;
@@ -152,64 +152,66 @@ Sleep :: proc(ms: i32) -> i32 #foreign kernel32;
OutputDebugStringA :: proc(c_str: ^u8) #foreign kernel32;
RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign user32;
RegisterClassExA :: proc(wc: ^WndClassExA) -> i16 #foreign user32;
CreateWindowExA :: proc(ex_style: u32,
class_name, title: ^u8,
style: u32,
x, y, w, h: i32,
parent: HWND, menu: HMENU, instance: HINSTANCE,
param: rawptr) -> HWND #foreign user32;
parent: Hwnd, menu: Hmenu, instance: Hinstance,
param: rawptr) -> Hwnd #foreign user32;
ShowWindow :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign user32;
TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign user32;
DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign user32;
UpdateWindow :: proc(hwnd: HWND) -> BOOL #foreign user32;
PeekMessageA :: proc(msg: ^MSG, hwnd: HWND,
msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign user32;
ShowWindow :: proc(hwnd: Hwnd, cmd_show: i32) -> Bool #foreign user32;
TranslateMessage :: proc(msg: ^Msg) -> Bool #foreign user32;
DispatchMessageA :: proc(msg: ^Msg) -> Lresult #foreign user32;
UpdateWindow :: proc(hwnd: Hwnd) -> Bool #foreign user32;
PeekMessageA :: proc(msg: ^Msg, hwnd: Hwnd,
msg_filter_min, msg_filter_max, remove_msg: u32) -> Bool #foreign user32;
DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign user32;
DefWindowProcA :: proc(hwnd: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Lresult #foreign user32;
AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign user32;
GetActiveWindow :: proc() -> HWND #foreign user32;
AdjustWindowRect :: proc(rect: ^Rect, style: u32, menu: Bool) -> Bool #foreign user32;
GetActiveWindow :: proc() -> Hwnd #foreign user32;
DestroyWindow :: proc(wnd: HWND) -> BOOL #foreign user32;
DescribePixelFormat :: proc(dc: HDC, pixel_format: i32, bytes : u32, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32;
DestroyWindow :: proc(wnd: Hwnd) -> Bool #foreign user32;
DescribePixelFormat :: proc(dc: Hdc, pixel_format: i32, bytes : u32, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32;
GetQueryPerformanceFrequency :: proc() -> i64 {
r: i64;
QueryPerformanceFrequency(^r);
QueryPerformanceFrequency(&r);
return r;
}
GetCommandLineA :: proc() -> ^u8 #foreign kernel32;
GetSystemMetrics :: proc(index: i32) -> i32 #foreign kernel32;
GetCurrentThreadId :: proc() -> u32 #foreign kernel32;
GetCommandLineA :: proc() -> ^u8 #foreign kernel32;
GetCommandLineW :: proc() -> ^u16 #foreign kernel32;
GetSystemMetrics :: proc(index: i32) -> i32 #foreign kernel32;
GetCurrentThreadId :: proc() -> u32 #foreign kernel32;
CommandLineToArgvW :: proc(cmd_list: ^u16, num_args: ^i32) -> ^^u16 #foreign shell32;
timeGetTime :: proc() -> u32 #foreign winmm;
GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^FILETIME) #foreign kernel32;
FileTimeToLocalFileTime :: proc(file_time: ^FILETIME, local_file_time: ^FILETIME) -> BOOL #foreign kernel32;
FileTimeToSystemTime :: proc(file_time: ^FILETIME, system_time: ^SYSTEMTIME) -> BOOL #foreign kernel32;
SystemTimeToFileTime :: proc(system_time: ^SYSTEMTIME, file_time: ^FILETIME) -> BOOL #foreign kernel32;
timeGetTime :: proc() -> u32 #foreign winmm;
GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^Filetime) #foreign kernel32;
FileTimeToLocalFileTime :: proc(file_time: ^Filetime, local_file_time: ^Filetime) -> Bool #foreign kernel32;
FileTimeToSystemTime :: proc(file_time: ^Filetime, system_time: ^Systemtime) -> Bool #foreign kernel32;
SystemTimeToFileTime :: proc(system_time: ^Systemtime, file_time: ^Filetime) -> Bool #foreign kernel32;
// File Stuff
CloseHandle :: proc(h: HANDLE) -> i32 #foreign kernel32;
GetStdHandle :: proc(h: i32) -> HANDLE #foreign kernel32;
CloseHandle :: proc(h: Handle) -> i32 #foreign kernel32;
GetStdHandle :: proc(h: i32) -> Handle #foreign kernel32;
CreateFileA :: proc(filename: ^u8, desired_access, share_mode: u32,
security: rawptr,
creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign kernel32;
ReadFile :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign kernel32;
WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> BOOL #foreign kernel32;
creation, flags_and_attribs: u32, template_file: Handle) -> Handle #foreign kernel32;
ReadFile :: proc(h: Handle, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> Bool #foreign kernel32;
WriteFile :: proc(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool #foreign kernel32;
GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign kernel32;
GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign kernel32;
GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign kernel32;
GetFileSizeEx :: proc(file_handle: Handle, file_size: ^i64) -> Bool #foreign kernel32;
GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool #foreign kernel32;
GetFileInformationByHandle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool #foreign kernel32;
GetFileType :: proc(file_handle: HANDLE) -> u32 #foreign kernel32;
SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign kernel32;
GetFileType :: proc(file_handle: Handle) -> u32 #foreign kernel32;
SetFilePointer :: proc(file_handle: Handle, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign kernel32;
SetHandleInformation :: proc(obj: HANDLE, mask, flags: u32) -> BOOL #foreign kernel32;
SetHandleInformation :: proc(obj: Handle, mask, flags: u32) -> Bool #foreign kernel32;
HANDLE_FLAG_INHERIT :: 1;
HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
@@ -242,13 +244,13 @@ TRUNCATE_EXISTING :: 5;
FILE_ATTRIBUTE_READONLY :: 0x00000001;
FILE_ATTRIBUTE_HIDDEN :: 0x00000002;
FILE_ATTRIBUTE_SYSTEM :: 0x00000004;
FILE_ATTRIBUTE_DIRECTORY :: 0x00000010;
FILE_ATTRIBUTE_DIRectORY :: 0x00000010;
FILE_ATTRIBUTE_ARCHIVE :: 0x00000020;
FILE_ATTRIBUTE_DEVICE :: 0x00000040;
FILE_ATTRIBUTE_NORMAL :: 0x00000080;
FILE_ATTRIBUTE_TEMPORARY :: 0x00000100;
FILE_ATTRIBUTE_SPARSE_FILE :: 0x00000200;
FILE_ATTRIBUTE_REPARSE_POINT :: 0x00000400;
FILE_ATTRIBUTE_REPARSE_Point :: 0x00000400;
FILE_ATTRIBUTE_COMPRESSED :: 0x00000800;
FILE_ATTRIBUTE_OFFLINE :: 0x00001000;
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED :: 0x00002000;
@@ -258,32 +260,32 @@ FILE_TYPE_DISK :: 0x0001;
FILE_TYPE_CHAR :: 0x0002;
FILE_TYPE_PIPE :: 0x0003;
INVALID_SET_FILE_POINTER :: ~cast(u32)0;
INVALID_SET_FILE_POINTER :: ~u32(0);
HeapAlloc :: proc (h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign kernel32;
HeapReAlloc :: proc (h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign kernel32;
HeapFree :: proc (h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign kernel32;
GetProcessHeap :: proc () -> HANDLE #foreign kernel32;
HeapAlloc :: proc (h: Handle, flags: u32, bytes: int) -> rawptr #foreign kernel32;
HeapReAlloc :: proc (h: Handle, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign kernel32;
HeapFree :: proc (h: Handle, flags: u32, memory: rawptr) -> Bool #foreign kernel32;
GetProcessHeap :: proc () -> Handle #foreign kernel32;
HEAP_ZERO_MEMORY :: 0x00000008;
// Synchronization
SECURITY_ATTRIBUTES :: struct #ordered {
Security_Attributes :: struct #ordered {
length: u32,
security_descriptor: rawptr,
inherit_handle: BOOL,
inherit_handle: Bool,
}
INFINITE :: 0xffffffff;
CreateSemaphoreA :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign kernel32;
ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign kernel32;
WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign kernel32;
CreateSemaphoreA :: proc(attributes: ^Security_Attributes, initial_count, maximum_count: i32, name: ^byte) -> Handle #foreign kernel32;
ReleaseSemaphore :: proc(semaphore: Handle, release_count: i32, previous_count: ^i32) -> Bool #foreign kernel32;
WaitForSingleObject :: proc(handle: Handle, milliseconds: u32) -> u32 #foreign kernel32;
InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign kernel32;
@@ -307,11 +309,11 @@ ReadBarrier :: proc() #foreign kernel32;
HMONITOR :: HANDLE;
Hmonitor :: Handle;
GWL_STYLE :: -16;
HWND_TOP :: cast(HWND)cast(uint)0;
Hwnd_TOP :: Hwnd(uint(0));
MONITOR_DEFAULTTONULL :: 0x00000000;
MONITOR_DEFAULTTOPRIMARY :: 0x00000001;
@@ -324,39 +326,40 @@ SWP_NOSIZE :: 0x0001;
SWP_NOMOVE :: 0x0002;
MONITORINFO :: struct #ordered {
Monitor_Info :: struct #ordered {
size: u32,
monitor: RECT,
work: RECT,
monitor: Rect,
work: Rect,
flags: u32,
}
WINDOWPLACEMENT :: struct #ordered {
Window_Placement :: struct #ordered {
length: u32,
flags: u32,
show_cmd: u32,
min_pos: POINT,
max_pos: POINT,
normal_pos: RECT,
min_pos: Point,
max_pos: Point,
normal_pos: Rect,
}
GetMonitorInfoA :: proc(monitor: HMONITOR, mi: ^MONITORINFO) -> BOOL #foreign user32;
MonitorFromWindow :: proc(wnd: HWND, flags : u32) -> HMONITOR #foreign user32;
GetMonitorInfoA :: proc(monitor: Hmonitor, mi: ^Monitor_Info) -> Bool #foreign user32;
MonitorFromWindow :: proc(wnd: Hwnd, flags : u32) -> Hmonitor #foreign user32;
SetWindowPos :: proc(wnd: HWND, wndInsertAfter: HWND, x, y, width, height: i32, flags: u32) #foreign user32 "SetWindowPos";
SetWindowPos :: proc(wnd: Hwnd, wndInsertAfter: Hwnd, x, y, width, height: i32, flags: u32) #foreign user32 "SetWindowPos";
GetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
SetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
GetWindowPlacement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool #foreign user32;
SetWindowPlacement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool #foreign user32;
GetWindowRect :: proc(wnd: Hwnd, rect: ^Rect) -> Bool #foreign user32;
GetWindowLongPtrA :: proc(wnd: HWND, index: i32) -> i64 #foreign user32;
SetWindowLongPtrA :: proc(wnd: HWND, index: i32, new: i64) -> i64 #foreign user32;
GetWindowLongPtrA :: proc(wnd: Hwnd, index: i32) -> i64 #foreign user32;
SetWindowLongPtrA :: proc(wnd: Hwnd, index: i32, new: i64) -> i64 #foreign user32;
GetWindowText :: proc(wnd: HWND, str: ^byte, maxCount: i32) -> i32 #foreign user32;
GetWindowText :: proc(wnd: Hwnd, str: ^byte, maxCount: i32) -> i32 #foreign user32;
HIWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)((cast(u32)wParam >> 16) & 0xffff); }
HIWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)((cast(u32)lParam >> 16) & 0xffff); }
LOWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)wParam; }
LOWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)lParam; }
HIWORD :: proc(wParam: Wparam) -> u16 { return u16((u32(wParam) >> 16) & 0xffff); }
HIWORD :: proc(lParam: Lparam) -> u16 { return u16((u32(lParam) >> 16) & 0xffff); }
LOWORD :: proc(wParam: Wparam) -> u16 { return u16(wParam); }
LOWORD :: proc(lParam: Lparam) -> u16 { return u16(lParam); }
@@ -367,7 +370,7 @@ LOWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)lParam; }
BITMAPINFOHEADER :: struct #ordered {
Bitmap_Info_Header :: struct #ordered {
size: u32,
width, height: i32,
planes, bit_count: i16,
@@ -378,33 +381,33 @@ BITMAPINFOHEADER :: struct #ordered {
clr_used: u32,
clr_important: u32,
}
BITMAPINFO :: struct #ordered {
using header: BITMAPINFOHEADER,
colors: [1]RGBQUAD,
Bitmap_Info :: struct #ordered {
using header: Bitmap_Info_Header,
colors: [1]Rgb_Quad,
}
RGBQUAD :: struct #ordered { blue, green, red, reserved: byte }
Rgb_Quad :: struct #ordered { blue, green, red, reserved: byte }
BI_RGB :: 0;
DIB_RGB_COLORS :: 0x00;
SRCCOPY: u32 : 0x00cc0020;
StretchDIBits :: proc (hdc: HDC,
StretchDIBits :: proc (hdc: Hdc,
x_dst, y_dst, width_dst, height_dst: i32,
x_src, y_src, width_src, header_src: i32,
bits: rawptr, bits_info: ^BITMAPINFO,
bits: rawptr, bits_info: ^Bitmap_Info,
usage: u32,
rop: u32) -> i32 #foreign gdi32;
LoadLibraryA :: proc (c_str: ^u8) -> HMODULE #foreign kernel32;
FreeLibrary :: proc (h: HMODULE) #foreign kernel32;
GetProcAddress :: proc (h: HMODULE, c_str: ^u8) -> PROC #foreign kernel32;
LoadLibraryA :: proc (c_str: ^u8) -> Hmodule #foreign kernel32;
FreeLibrary :: proc (h: Hmodule) #foreign kernel32;
GetProcAddress :: proc (h: Hmodule, c_str: ^u8) -> Proc #foreign kernel32;
GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign user32;
GetClientRect :: proc(hwnd: Hwnd, rect: ^Rect) -> Bool #foreign user32;
// Windows OpenGL
PFD_TYPE_RGBA :: 0;
@@ -461,20 +464,20 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
damage_mask: u32,
}
GetDC :: proc(h: HWND) -> HDC #foreign user32;
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR) -> BOOL #foreign gdi32;
ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32;
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign gdi32;
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign user32;
GetDC :: proc(h: Hwnd) -> Hdc #foreign user32;
SetPixelFormat :: proc(hdc: Hdc, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR) -> Bool #foreign gdi32;
ChoosePixelFormat :: proc(hdc: Hdc, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32;
SwapBuffers :: proc(hdc: Hdc) -> Bool #foreign gdi32;
ReleaseDC :: proc(wnd: Hwnd, hdc: Hdc) -> i32 #foreign user32;
PROC :: #type proc() #cc_c;
Proc :: #type proc() #cc_c;
GetKeyState :: proc(v_key: i32) -> i16 #foreign user32;
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign user32;
is_key_down :: proc(key: Key_Code) -> bool #inline { return GetAsyncKeyState(cast(i32)key) < 0; }
is_key_down :: proc(key: Key_Code) -> bool #inline { return GetAsyncKeyState(i32(key)) < 0; }
Key_Code :: enum i32 {
LBUTTON = 0x01,
@@ -611,7 +614,7 @@ Key_Code :: enum i32 {
RCONTROL = 0xA3,
LMENU = 0xA4,
RMENU = 0xA5,
PROCESSKEY = 0xE5,
ProcESSKEY = 0xE5,
ATTN = 0xF6,
CRSEL = 0xF7,
EXSEL = 0xF8,
@@ -622,4 +625,3 @@ Key_Code :: enum i32 {
PA1 = 0xFD,
OEM_CLEAR = 0xFE,
}
+43 -91
View File
@@ -1,146 +1,98 @@
is_signed :: proc(info: ^Type_Info) -> bool {
if is_integer(info) {
i := union_cast(^Type_Info.Integer)info;
return i.signed;
}
if is_float(info) {
return true;
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Integer: return i.signed;
case Type_Info.Float: return true;
}
return false;
}
is_integer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Integer: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Integer);
return ok;
}
is_float :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Float: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Float);
return ok;
}
is_complex :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
_, ok := type_info_base(info).(^Type_Info.Complex);
return ok;
}
is_any :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Any: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Any);
return ok;
}
is_string :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.String: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.String);
return ok;
}
is_boolean :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Boolean: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Boolean);
return ok;
}
is_pointer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Pointer: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Pointer);
return ok;
}
is_procedure :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Procedure: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Procedure);
return ok;
}
is_array :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Array: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Array);
return ok;
}
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Dynamic_Array: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Dynamic_Array);
return ok;
}
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Map: return i.count == 0;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Map);
return ok;
}
is_slice :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Slice: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Slice);
return ok;
}
is_vector :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Vector: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Vector);
return ok;
}
is_tuple :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Tuple: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Tuple);
return ok;
}
is_struct :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Struct: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Struct);
return ok;
}
is_union :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Union: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Union);
return ok;
}
is_raw_union :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Raw_Union: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Raw_Union);
return ok;
}
is_enum :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; }
match i in type_info_base(info) {
case Type_Info.Enum: return true;
}
return false;
_, ok := type_info_base(info).(^Type_Info.Enum);
return ok;
}
+58
View File
@@ -0,0 +1,58 @@
REPLACEMENT_CHAR :: '\uFFFD';
MAX_RUNE :: '\U0010FFFF';
_surr1 :: 0xd800;
_surr2 :: 0xdc00;
_surr3 :: 0xe000;
_surr_self :: 0x10000;
is_surrogate :: proc(r: rune) -> bool {
return _surr1 <= r && r < _surr3;
}
decode_surrogate_pair :: proc(r1, r2: rune) -> rune {
if _surr1 <= r1 && r1 < _surr2 && _surr2 <= r2 && r2 < _surr3 {
return (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self;
}
return REPLACEMENT_CHAR;
}
encode_surrogate_pair :: proc(r: rune) -> (r1, r2: rune) {
if r < _surr_self || r > MAX_RUNE {
return REPLACEMENT_CHAR, REPLACEMENT_CHAR;
}
r -= _surr_self;
return _surr1 + (r>>10)&0x3ff, _surr2 + r&0x3ff;
}
encode :: proc(d: []u16, s: []rune) {
n := len(s);
for r in s {
if r >= _surr_self {
n++;
}
}
max_n := min(len(d), n);
n = 0;
for r in s {
match r {
case 0..<_surr1, _surr3..<_surr_self:
d[n] = u16(r);
n++;
case _surr_self..MAX_RUNE:
r1, r2 := encode_surrogate_pair(r);
d[n] = u16(r1);
d[n+1] = u16(r2);
n += 2;
default:
d[n] = u16(REPLACEMENT_CHAR);
n++;
}
}
}
+29 -29
View File
@@ -1,7 +1,7 @@
RUNE_ERROR :: '\ufffd';
RUNE_SELF :: 0x80;
RUNE_BOM :: 0xfeff;
RUNE_EOF :: ~cast(rune)0;
RUNE_EOF :: ~rune(0);
MAX_RUNE :: '\U0010ffff';
UTF_MAX :: 4;
@@ -60,15 +60,15 @@ immutable accept_sizes := [256]byte{
encode_rune :: proc(r: rune) -> ([4]byte, int) {
buf: [4]byte;
i := cast(u32)r;
i := u32(r);
mask: byte : 0x3f;
if i <= 1<<7-1 {
buf[0] = cast(byte)r;
buf[0] = byte(r);
return buf, 1;
}
if i <= 1<<11-1 {
buf[0] = 0xc0 | cast(byte)(r>>6);
buf[1] = 0x80 | cast(byte)r & mask;
buf[0] = 0xc0 | byte(r>>6);
buf[1] = 0x80 | byte(r) & mask;
return buf, 2;
}
@@ -79,34 +79,34 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) {
}
if i <= 1<<16-1 {
buf[0] = 0xe0 | cast(byte)(r>>12);
buf[1] = 0x80 | cast(byte)(r>>6) & mask;
buf[2] = 0x80 | cast(byte)r & mask;
buf[0] = 0xe0 | byte(r>>12);
buf[1] = 0x80 | byte(r>>6) & mask;
buf[2] = 0x80 | byte(r) & mask;
return buf, 3;
}
buf[0] = 0xf0 | cast(byte)(r>>18);
buf[1] = 0x80 | cast(byte)(r>>12) & mask;
buf[2] = 0x80 | cast(byte)(r>>6) & mask;
buf[3] = 0x80 | cast(byte)r & mask;
buf[0] = 0xf0 | byte(r>>18);
buf[1] = 0x80 | byte(r>>12) & mask;
buf[2] = 0x80 | byte(r>>6) & mask;
buf[3] = 0x80 | byte(r) & mask;
return buf, 4;
}
decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune(cast([]byte)s); }
decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune([]byte(s)); }
decode_rune :: proc(s: []byte) -> (rune, int) {
n := s.count;
n := len(s);
if n < 1 {
return RUNE_ERROR, 0;
}
s0 := s[0];
x := accept_sizes[s0];
if x >= 0xF0 {
mask := cast(rune)(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
return cast(rune)(s[0])&~mask | RUNE_ERROR&mask, 1;
mask := rune(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
return rune(s[0])&~mask | RUNE_ERROR&mask, 1;
}
sz := x & 7;
accept := accept_ranges[x>>4];
if n < cast(int)sz {
if n < int(sz) {
return RUNE_ERROR, 1;
}
b1 := s[1];
@@ -114,36 +114,36 @@ decode_rune :: proc(s: []byte) -> (rune, int) {
return RUNE_ERROR, 1;
}
if sz == 2 {
return cast(rune)(s0&MASK2)<<6 | cast(rune)(b1&MASKX), 2;
return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2;
}
b2 := s[2];
if b2 < LOCB || HICB < b2 {
return RUNE_ERROR, 1;
}
if sz == 3 {
return cast(rune)(s0&MASK3)<<12 | cast(rune)(b1&MASKX)<<6 | cast(rune)(b2&MASKX), 3;
return rune(s0&MASK3)<<12 | rune(b1&MASKX)<<6 | rune(b2&MASKX), 3;
}
b3 := s[3];
if b3 < LOCB || HICB < b3 {
return RUNE_ERROR, 1;
}
return cast(rune)(s0&MASK4)<<18 | cast(rune)(b1&MASKX)<<12 | cast(rune)(b2&MASKX)<<6 | cast(rune)(b3&MASKX), 4;
return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4;
}
decode_last_rune :: proc(s: string) -> (rune, int) #inline { return decode_last_rune(cast([]byte)s); }
decode_last_rune :: proc(s: string) -> (rune, int) #inline { return decode_last_rune([]byte(s)); }
decode_last_rune :: proc(s: []byte) -> (rune, int) {
r: rune;
size: int;
start, end, limit: int;
end = s.count;
end = len(s);
if end == 0 {
return RUNE_ERROR, 0;
}
start = end-1;
r = cast(rune)s[start];
r = rune(s[start]);
if r < RUNE_SELF {
return r, 1;
}
@@ -160,7 +160,7 @@ decode_last_rune :: proc(s: []byte) -> (rune, int) {
}
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;
}
@@ -183,7 +183,7 @@ valid_rune :: proc(r: rune) -> bool {
}
valid_string :: proc(s: string) -> bool {
n := s.count;
n := len(s);
for i := 0; i < n; {
si := s[i];
if si < RUNE_SELF { // ascii
@@ -194,7 +194,7 @@ valid_string :: proc(s: string) -> bool {
if x == 0xf1 {
return false;
}
size := cast(int)(x & 7);
size := int(x & 7);
if i+size > n {
return false;
}
@@ -217,10 +217,10 @@ valid_string :: proc(s: string) -> bool {
rune_start :: proc(b: byte) -> bool #inline { return b&0xc0 != 0x80; }
rune_count :: proc(s: string) -> int #inline { return rune_count(cast([]byte)s); }
rune_count :: proc(s: string) -> int #inline { return rune_count([]byte(s)); }
rune_count :: proc(s: []byte) -> int {
count := 0;
n := s.count;
n := len(s);
for i := 0; i < n; {
defer count++;
@@ -234,7 +234,7 @@ rune_count :: proc(s: []byte) -> int {
i++;
continue;
}
size := cast(int)(x & 7);
size := int(x & 7);
if i+size > n {
i++;
continue;
+11
View File
@@ -0,0 +1,11 @@
@echo off
setlocal EnableDelayedExpansion
set file_input=%1
set name=%1
FOR %%f IN (name) do (
FOR %%g in (!%%f!) do set "%%f=%%~ng"
)
call clang -O2 -c %file_input% -o %name%.o ^
&& call ar %name%.o -rcs %name%.lib
View File

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 246 KiB

View File
+1 -2
View File
@@ -1,8 +1,7 @@
@echo off
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
set _NO_DEBUG_HEAP=1
set path=w:\Odin\misc;%path%
View File
-4
View File
@@ -1,4 +0,0 @@
@echo off
rem call clang -c -emit-llvm -DGB_IMPLEMENTATION -DGB_DEF=GB_DLL_EXPORT ..\src\gb\gb.h
+2 -8
View File
@@ -87,14 +87,8 @@ void array__set_capacity(void *ptr, isize capacity, isize element_size) {
x->count = capacity;
}
{
// TODO(bill): Resize rather than copy and delete
void *new_data = gb_alloc(x->allocator, element_size*capacity);
gb_memmove(new_data, x->e, element_size*x->count);
gb_free(x->allocator, x->e);
x->capacity = capacity;
x->e = new_data;
}
x->e = gb_resize(x->allocator, x->e, element_size*x->capacity, element_size*capacity);
x->capacity = capacity;
}
+99 -9
View File
@@ -135,7 +135,62 @@ String odin_root_dir(void) {
return path;
}
#else
#error Implement system
// NOTE: Linux / Unix is unfinished and not tested very well.
#include <sys/stat.h>
String odin_root_dir(void) {
String path = global_module_path;
Array(char) path_buf;
isize len, i;
gbTempArenaMemory tmp;
u8 *text;
if (global_module_path_set) {
return global_module_path;
}
array_init_count(&path_buf, heap_allocator(), 300);
len = 0;
for (;;) {
// This is not a 100% reliable system, but for the purposes
// of this compiler, it should be _good enough_.
// That said, there's no solid 100% method on Linux to get the program's
// path without checking this link. Sorry.
len = readlink("/proc/self/exe", &path_buf.e[0], path_buf.count);
if(len == 0) {
return make_string(NULL, 0);
}
if (len < path_buf.count) {
break;
}
array_resize(&path_buf, 2*path_buf.count + 300);
}
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
gb_memmove(text, &path_buf.e[0], len);
path = make_string(text, len);
for (i = path.len-1; i >= 0; i--) {
u8 c = path.text[i];
if (c == '/' || c == '\\') {
break;
}
path.len--;
}
global_module_path = path;
global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
array_free(&path_buf);
return path;
}
#endif
@@ -157,11 +212,10 @@ 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(s.text, 0);
// GB_ASSERT(p && "file does not exist");
if(!p) return make_string_c("");
char *p = realpath(cast(char *)s.text, 0);
if(p == NULL) return make_string_c("");
return make_string(p, strlen(p));
return make_string_c(p);
}
#else
#error Implement system
@@ -209,7 +263,7 @@ String get_fullpath_core(gbAllocator a, String path) {
void init_build_context(void) {
BuildContext *bc = &build_context;
bc->ODIN_VENDOR = str_lit("odin");
bc->ODIN_VERSION = str_lit("0.1.1");
bc->ODIN_VERSION = str_lit("0.2.0");
bc->ODIN_ROOT = odin_root_dir();
#if defined(GB_SYSTEM_WINDOWS)
@@ -221,18 +275,54 @@ void init_build_context(void) {
bc->ODIN_ARCH = str_lit("amd64");
bc->ODIN_ENDIAN = str_lit("little");
#else
#error Implement system
bc->ODIN_OS = str_lit("linux");
bc->ODIN_ARCH = str_lit("amd64");
bc->ODIN_ENDIAN = str_lit("little");
#endif
// NOTE(zangent): The linker flags to set the build architecture are different
// across OSs. It doesn't make sense to allocate extra data on the heap
// here, so I just #defined the linker flags to keep things concise.
#if defined(GB_SYSTEM_WINDOWS)
#define LINK_FLAG_X64 "/machine:x64"
#define LINK_FLAG_X86 "/machine:x86"
#elif defined(GB_SYSTEM_OSX)
// NOTE(zangent): MacOS systems are x64 only, so ld doesn't have
// an architecture option. All compilation done on MacOS must be x64.
GB_ASSERT(str_eq(bc->ODIN_ARCH, str_lit("amd64")));
#define LINK_FLAG_X64 ""
#define LINK_FLAG_X86 ""
#else
// Linux, but also BSDs and the like.
// NOTE(zangent): When clang is swapped out with ld as the linker,
// the commented flags here should be used. Until then, we'll have
// to use alternative build flags made for clang.
/*
#define LINK_FLAG_X64 "-m elf_x86_64"
#define LINK_FLAG_X86 "-m elf_i386"
*/
#define LINK_FLAG_X64 "-arch x86-64"
#define LINK_FLAG_X86 "-arch x86"
#endif
if (str_eq(bc->ODIN_ARCH, str_lit("amd64"))) {
bc->word_size = 8;
bc->max_align = 16;
bc->llc_flags = str_lit("-march=x86-64 ");
bc->link_flags = str_lit("/machine:x64 ");
bc->link_flags = str_lit(LINK_FLAG_X64 " ");
} else if (str_eq(bc->ODIN_ARCH, str_lit("x86"))) {
bc->word_size = 4;
bc->max_align = 8;
bc->llc_flags = str_lit("-march=x86 ");
bc->link_flags = str_lit("/machine:x86 ");
bc->link_flags = str_lit(LINK_FLAG_X86 " ");
}
#undef LINK_FLAG_X64
#undef LINK_FLAG_X86
}
+108 -32
View File
@@ -1,21 +1,21 @@
bool check_is_terminating(AstNode *node);
void check_stmt (Checker *c, AstNode *node, u32 flags);
void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags);
// NOTE(bill): `content_name` is for debugging and error messages
Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid ||
e->type == t_invalid) {
operand->type == t_invalid ||
e->type == t_invalid) {
if (operand->mode == Addressing_Builtin) {
gbString expr_str = expr_to_string(operand->expr);
// TODO(bill): is this a good enough error message?
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
error_node(operand->expr,
"Cannot assign builtin procedure `%s` in %.*s",
expr_str,
LIT(context_name));
"Cannot assign builtin procedure `%s` in %.*s",
expr_str,
LIT(context_name));
operand->mode = Addressing_Invalid;
@@ -85,8 +85,8 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
void check_init_constant(Checker *c, Entity *e, Operand *operand) {
if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid ||
e->type == t_invalid) {
operand->type == t_invalid ||
e->type == t_invalid) {
if (e->type == NULL) {
e->type = t_invalid;
}
@@ -181,7 +181,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
check_init_constant(c, e, &operand);
if (operand.mode == Addressing_Invalid ||
base_type(operand.type) == t_invalid) {
base_type(operand.type) == t_invalid) {
error(e->token, "Invalid declaration type");
}
}
@@ -241,14 +241,15 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
check_open_scope(c, pd->type);
check_procedure_type(c, proc_type, pd->type);
bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
bool is_export = (pd->tags & ProcTag_export) != 0;
bool is_inline = (pd->tags & ProcTag_inline) != 0;
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
bool is_export = (pd->tags & ProcTag_export) != 0;
bool is_inline = (pd->tags & ProcTag_inline) != 0;
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
bool is_require_results = (pd->tags & ProcTag_require_results) != 0;
if ((d->scope->is_file || d->scope->is_global) &&
str_eq(e->token.string, str_lit("main"))) {
if (d->scope->is_file && str_eq(e->token.string, str_lit("main"))) {
if (proc_type != NULL) {
TypeProc *pt = &proc_type->Proc;
if (pt->param_count != 0 ||
@@ -276,18 +277,22 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
}
// TODO(bill): Is this the best option? What about passing to external shit?!
// if (proc_type->Proc.calling_convention != ProcCC_Odin) {
// error_node(d->proc_lit, "An internal procedure may only have the Odin calling convention");
// proc_type->Proc.calling_convention = ProcCC_Odin;
// }
d->scope = c->context.scope;
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
}
if (proc_type != NULL && is_type_proc(proc_type)) {
TypeProc *tp = &proc_type->Proc;
if (tp->result_count == 0 && is_require_results) {
error_node(pd->type, "`#require_results` is not needed on a procedure with no results");
} else {
tp->require_results = is_require_results;
}
}
if (is_foreign) {
MapEntity *fp = &c->info.foreigns;
String name = e->token.string;
@@ -330,9 +335,9 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
Type *other_type = base_type(f->type);
if (!are_signatures_similar_enough(this_type, other_type)) {
error_node(d->proc_lit,
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else {
map_entity_set(fp, key, e);
@@ -355,9 +360,9 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
TokenPos pos = f->token.pos;
// TODO(bill): Better error message?
error_node(d->proc_lit,
"Non unique linking name for procedure `%.*s`\n"
"\tother at %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
"Non unique linking name for procedure `%.*s`\n"
"\tother at %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
} else {
map_entity_set(fp, key, e);
}
@@ -408,6 +413,67 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
}
void check_alias_decl(Checker *c, Entity *e, AstNode *expr, Type *named_type) {
GB_ASSERT(e->type == NULL);
GB_ASSERT(e->kind == Entity_Alias);
if (e->flags & EntityFlag_Visited) {
e->type = t_invalid;
return;
}
e->flags |= EntityFlag_Visited;
e->type = t_invalid;
expr = unparen_expr(expr);
if (expr->kind == AstNode_Alias) {
error_node(expr, "#alias of an #alias is not allowed");
return;
}
Operand operand = {0};
check_expr_or_type(c, &operand, expr);
if (operand.mode != Addressing_Type) {
error_node(expr, "#alias declarations only allow types");
return;
}
e->kind = Entity_TypeName;
e->TypeName.is_type_alias = true;
e->type = NULL;
DeclInfo *d = c->context.decl;
d->type_expr = expr;
check_type_decl(c, e, d->type_expr, named_type);
// Operand o = {0};
// Entity *f = NULL;
// if (expr->kind == AstNode_Ident) {
// f = check_ident(c, &o, expr, NULL, NULL, true);
// } else if (expr->kind == AstNode_SelectorExpr) {
// f = check_selector(c, &o, expr, NULL);
// } else {
// check_expr_or_type(c, &o, expr);
// }
// if (o.mode == Addressing_Invalid) {
// return;
// }
// switch (o.mode) {
// case Addressing_Type:
// e->type = o.type;
// // e->kind = Entity_TypeName;
// // e->TypeName.is_type_alias = true;
// e->Alias.kind = EntityAlias_Type;
// e->Alias.original = f;
// break;
// default:
// error_node(expr, "#alias declarations only allow types");
// e->kind = Entity_Invalid;
// e->type = t_invalid;
// break;
// }
}
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
if (e->type != NULL) {
return;
@@ -440,6 +506,9 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
case Entity_TypeName:
check_type_decl(c, e, d->type_expr, named_type);
break;
case Entity_Alias:
check_alias_decl(c, e, d->init_expr, named_type);
break;
case Entity_Procedure:
check_proc_lit(c, e, d);
break;
@@ -466,14 +535,13 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
c->context.decl = decl;
c->context.proc_name = proc_name;
GB_ASSERT(type->kind == Type_Proc);
if (type->Proc.param_count > 0) {
TypeTuple *params = &type->Proc.params->Tuple;
for (isize i = 0; i < params->variable_count; i++) {
Entity *e = params->variables[i];
GB_ASSERT(e->kind == Entity_Variable);
if (!(e->flags & EntityFlag_Anonymous)) {
if (!(e->flags & EntityFlag_Using)) {
continue;
}
bool is_immutable = e->Variable.is_immutable;
@@ -504,7 +572,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
push_procedure(c, type);
{
ast_node(bs, BlockStmt, body);
check_stmt_list(c, bs->stmts, 0);
check_stmt_list(c, bs->stmts, Stmt_CheckScopeDecls);
if (type->Proc.result_count > 0) {
if (!check_is_terminating(body)) {
if (token.kind == Token_Ident) {
@@ -519,8 +587,16 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
check_scope_usage(c, c->context.scope);
c->context = old_context;
if (decl->parent != NULL) {
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
for_array(i, decl->deps.entries) {
HashKey key = decl->deps.entries.e[i].key;
Entity *e = cast(Entity *)key.ptr;
map_bool_set(&decl->parent->deps, key, true);
}
}
}
+1201 -576
View File
File diff suppressed because it is too large Load Diff
+422 -257
View File
@@ -3,7 +3,9 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
return;
}
check_scope_decls(c, stmts, 1.2*stmts.count);
if (flags&Stmt_CheckScopeDecls) {
check_scope_decls(c, stmts, 1.2*stmts.count);
}
bool ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
flags &= ~Stmt_FallthroughAllowed;
@@ -123,15 +125,13 @@ bool check_is_terminating(AstNode *node) {
case_end;
case_ast_node(fs, ForStmt, node);
if (!check_has_break(fs->body, true)) {
if (fs->cond == NULL && !check_has_break(fs->body, true)) {
return check_is_terminating(fs->body);
}
case_end;
case_ast_node(rs, RangeStmt, node);
if (!check_has_break(rs->body, true)) {
return check_is_terminating(rs->body);
}
return false;
case_end;
case_ast_node(ms, MatchStmt, node);
@@ -307,16 +307,21 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
return rhs->type;
}
bool check_valid_type_match_type(Type *type, bool *is_union_ptr, bool *is_any) {
if (is_type_pointer(type)) {
*is_union_ptr = is_type_union(type_deref(type));
return *is_union_ptr;
typedef enum MatchTypeKind {
MatchType_Invalid,
MatchType_Union,
MatchType_Any,
} MatchTypeKind;
MatchTypeKind check_valid_type_match_type(Type *type) {
type = type_deref(type);
if (is_type_union(type)) {
return MatchType_Union;
}
if (is_type_any(type)) {
*is_any = true;
return *is_any;
return MatchType_Any;
}
return false;
return MatchType_Invalid;
}
void check_stmt_internal(Checker *c, AstNode *node, u32 flags);
@@ -357,6 +362,7 @@ typedef struct TypeAndToken {
#include "map.c"
void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
flags &= ~Stmt_CheckScopeDecls;
Operand operand = {Addressing_Invalid};
check_expr(c, &operand, ws->cond);
if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) {
@@ -385,6 +391,175 @@ void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
}
}
void check_label(Checker *c, AstNode *label) {
if (label == NULL) {
return;
}
ast_node(l, Label, label);
if (l->name->kind != AstNode_Ident) {
error_node(l->name, "A label's name must be an identifier");
return;
}
String name = l->name->Ident.string;
if (str_eq(name, str_lit("_"))) {
error_node(l->name, "A label's name cannot be a blank identifier");
return;
}
if (c->proc_stack.count == 0) {
error_node(l->name, "A label is only allowed within a procedure");
return;
}
GB_ASSERT(c->context.decl != NULL);
bool ok = true;
for_array(i, c->context.decl->labels) {
BlockLabel bl = c->context.decl->labels.e[i];
if (str_eq(bl.name, name)) {
error_node(label, "Duplicate label with the name `%.*s`", LIT(name));
ok = false;
break;
}
}
Entity *e = make_entity_label(c->allocator, c->context.scope, l->name->Ident, t_invalid, label);
add_entity(c, c->context.scope, l->name, e);
if (ok) {
BlockLabel bl = {name, label};
array_add(&c->context.decl->labels, bl);
}
}
// Returns `true` for `continue`, `false` for `return`
bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bool is_selector, Entity *e) {
if (e == NULL) {
error(us->token, "`using` applied to an unknown entity");
return true;
}
switch (e->kind) {
case Entity_Alias: {
if (e->Alias.original != NULL) {
check_using_stmt_entity(c, us, expr, is_selector, e->Alias.original);
} else {
error(us->token, "`using` cannot be applied to the alias `%.*s`", LIT(e->token.string));
return false;
}
} break;
case Entity_TypeName: {
Type *t = base_type(e->type);
if (is_type_union(t)) {
TokenPos pos = ast_node_token(expr).pos;
for (isize i = 1; i < t->Record.variant_count; i++) {
Entity *f = t->Record.variants[i];
// gb_printf_err("%s\n", type_to_string(f->type));
Entity *found = scope_insert_entity(c->context.scope, f);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
gb_string_free(expr_str);
return false;
}
f->using_parent = e;
}
} else if (is_type_enum(t)) {
for (isize i = 0; i < t->Record.field_count; i++) {
Entity *f = t->Record.fields[i];
Entity *found = scope_insert_entity(c->context.scope, f);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
gb_string_free(expr_str);
return false;
}
f->using_parent = e;
}
} else {
error(us->token, "`using` can be only applied to `union` or `enum` type entities");
}
} break;
case Entity_ImportName: {
Scope *scope = e->ImportName.scope;
for_array(i, scope->elements.entries) {
Entity *decl = scope->elements.entries.e[i].value;
Entity *found = scope_insert_entity(c->context.scope, decl);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token,
"Namespace collision while `using` `%s` of: %.*s\n"
"\tat %.*s(%td:%td)\n"
"\tat %.*s(%td:%td)",
expr_str, LIT(found->token.string),
LIT(found->token.pos.file), found->token.pos.line, found->token.pos.column,
LIT(decl->token.pos.file), decl->token.pos.line, decl->token.pos.column
);
gb_string_free(expr_str);
return false;
}
}
} break;
case Entity_Variable: {
Type *t = base_type(type_deref(e->type));
if (is_type_struct(t) || is_type_raw_union(t)) {
// TODO(bill): Make it work for unions too
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
GB_ASSERT(found != NULL);
for_array(i, (*found)->elements.entries) {
Entity *f = (*found)->elements.entries.e[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
if (is_selector) {
uvar->using_expr = expr;
}
Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string));
gb_string_free(expr_str);
return false;
}
}
}
} else {
error(us->token, "`using` can only be applied to variables of type struct or raw_union");
return false;
}
} break;
case Entity_Constant:
error(us->token, "`using` cannot be applied to a constant");
break;
case Entity_Procedure:
case Entity_Builtin:
error(us->token, "`using` cannot be applied to a procedure");
break;
case Entity_Nil:
error(us->token, "`using` cannot be applied to `nil`");
break;
case Entity_Label:
error(us->token, "`using` cannot be applied to a label");
break;
case Entity_Invalid:
error(us->token, "`using` cannot be applied to an invalid entity");
break;
default:
GB_PANIC("TODO(bill): `using` other expressions?");
}
return true;
}
void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
u32 mod_flags = flags & (~Stmt_FallthroughAllowed);
switch (node->kind) {
@@ -396,9 +571,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Operand operand = {Addressing_Invalid};
ExprKind kind = check_expr_base(c, &operand, es->expr, NULL);
switch (operand.mode) {
case Addressing_Type:
error_node(node, "Is not an expression");
break;
case Addressing_Type: {
gbString str = type_to_string(operand.type);
error_node(node, "`%s` is not an expression", str);
gb_string_free(str);
} break;
case Addressing_NoValue:
return;
default: {
@@ -406,6 +583,15 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
return;
}
if (operand.expr->kind == AstNode_CallExpr) {
AstNodeCallExpr *ce = &operand.expr->CallExpr;
Type *t = type_of_expr(&c->info, ce->proc);
if (is_type_proc(t)) {
if (t->Proc.require_results) {
gbString expr_str = expr_to_string(ce->proc);
error_node(node, "`%s` requires that its results must be handled", expr_str);
gb_string_free(expr_str);
}
}
return;
}
gbString expr_str = expr_to_string(operand.expr);
@@ -475,9 +661,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
return;
}
// TODO(bill): This is a very similar to check_init_variables, should I merge the two some how or just
// leave it?
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
@@ -515,7 +698,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
error(op, "Unknown Assignment operation `%.*s`", LIT(op.string));
return;
}
// TODO(bill): Check if valid assignment operator
Operand operand = {Addressing_Invalid};
AstNode binary_expr = {AstNode_BinaryExpr};
ast_node(be, BinaryExpr, &binary_expr);
@@ -580,7 +762,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (c->context.in_defer) {
error(rs->token, "You cannot `return` within a defer statement");
// TODO(bill): Should I break here?
break;
}
@@ -619,7 +800,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_ast_node(fs, ForStmt, node);
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
check_open_scope(c, node);
check_label(c, fs->label); // TODO(bill): What should the label's "scope" be?
if (fs->init != NULL) {
check_stmt(c, fs->init, 0);
@@ -646,16 +829,20 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_ast_node(rs, RangeStmt, node);
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
check_open_scope(c, node);
check_label(c, rs->label);
Type *val = NULL;
Type *idx = NULL;
Entity *entities[2] = {0};
isize entity_count = 0;
AstNode *expr = unparen_expr(rs->expr);
if (rs->expr != NULL && rs->expr->kind == AstNode_IntervalExpr) {
ast_node(ie, IntervalExpr, rs->expr);
if (is_ast_node_a_range(expr)) {
ast_node(ie, BinaryExpr, expr);
Operand x = {Addressing_Invalid};
Operand y = {Addressing_Invalid};
@@ -715,10 +902,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
TokenKind op = Token_Lt;
switch (ie->op.kind) {
case Token_Ellipsis: op = Token_Lt; break;
case Token_Ellipsis: op = Token_LtEq; break;
case Token_HalfClosed: op = Token_Lt; break;
default: error(ie->op, "Invalid range operator"); break;
}
bool ok = compare_exact_values(Token_Lt, a, b);
bool ok = compare_exact_values(op, a, b);
if (!ok) {
// TODO(bill): Better error message
error(ie->op, "Invalid interval range");
@@ -840,6 +1028,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
mod_flags |= Stmt_BreakAllowed;
check_open_scope(c, node);
check_label(c, ms->label); // TODO(bill): What should the label's "scope" be?
if (ms->init != NULL) {
check_stmt(c, ms->init, 0);
@@ -850,13 +1039,20 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} else {
x.mode = Addressing_Constant;
x.type = t_bool;
x.value = make_exact_value_bool(true);
x.value = exact_value_bool(true);
Token token = {0};
token.pos = ast_node_token(ms->body).pos;
Token token = {0};
token.pos = ast_node_token(ms->body).pos;
token.string = str_lit("true");
x.expr = ast_ident(c->curr_ast_file, token);
}
if (is_type_vector(x.type)) {
gbString str = type_to_string(x.type);
error_node(x.expr, "Invalid match expression type: %s", str);
gb_string_free(str);
break;
}
// NOTE(bill): Check for multiple defaults
AstNode *first_default = NULL;
@@ -897,68 +1093,121 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
ast_node(cc, CaseClause, stmt);
for_array(j, cc->list) {
AstNode *expr = cc->list.e[j];
Operand y = {0};
AstNode *expr = unparen_expr(cc->list.e[j]);
check_expr(c, &y, expr);
if (x.mode == Addressing_Invalid ||
y.mode == Addressing_Invalid) {
continue;
}
if (is_ast_node_a_range(expr)) {
ast_node(ie, BinaryExpr, expr);
Operand lhs = {0};
Operand rhs = {0};
check_expr(c, &lhs, ie->left);
if (x.mode == Addressing_Invalid) {
continue;
}
if (lhs.mode == Addressing_Invalid) {
continue;
}
check_expr(c, &rhs, ie->right);
if (rhs.mode == Addressing_Invalid) {
continue;
}
convert_to_typed(c, &y, x.type, 0);
if (y.mode == Addressing_Invalid) {
continue;
}
// NOTE(bill): the ordering here matters
Operand z = y;
check_comparison(c, &z, &x, Token_CmpEq);
if (z.mode == Addressing_Invalid) {
continue;
}
if (y.mode != Addressing_Constant) {
continue;
}
if (!is_type_ordered(x.type)) {
gbString str = type_to_string(x.type);
error_node(x.expr, "Unordered type `%s`, is invalid for an interval expression", str);
gb_string_free(str);
continue;
}
if (y.value.kind != ExactValue_Invalid) {
HashKey key = hash_exact_value(y.value);
TypeAndToken *found = map_type_and_token_get(&seen, key);
if (found != NULL) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
isize count = map_type_and_token_multi_count(&seen, key);
TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count);
TokenKind op = {0};
map_type_and_token_multi_get_all(&seen, key, taps);
bool continue_outer = false;
Operand a = lhs;
Operand b = rhs;
check_comparison(c, &a, &x, Token_LtEq);
if (a.mode == Addressing_Invalid) {
continue;
}
switch (ie->op.kind) {
case Token_Ellipsis: op = Token_GtEq; break;
case Token_HalfClosed: op = Token_Gt; break;
default: error(ie->op, "Invalid interval operator"); continue;
}
for (isize i = 0; i < count; i++) {
TypeAndToken tap = taps[i];
if (are_types_identical(y.type, tap.type)) {
TokenPos pos = tap.token.pos;
gbString expr_str = expr_to_string(y.expr);
error_node(y.expr,
"Duplicate case `%s`\n"
"\tprevious case at %.*s(%td:%td)",
expr_str,
LIT(pos.file), pos.line, pos.column);
gb_string_free(expr_str);
continue_outer = true;
break;
check_comparison(c, &b, &x, op);
if (b.mode == Addressing_Invalid) {
continue;
}
switch (ie->op.kind) {
case Token_Ellipsis: op = Token_LtEq; break;
case Token_HalfClosed: op = Token_Lt; break;
default: error(ie->op, "Invalid interval operator"); continue;
}
Operand a1 = lhs;
Operand b1 = rhs;
check_comparison(c, &a1, &b1, op);
} else {
Operand y = {0};
check_expr(c, &y, expr);
if (x.mode == Addressing_Invalid ||
y.mode == Addressing_Invalid) {
continue;
}
convert_to_typed(c, &y, x.type, 0);
if (y.mode == Addressing_Invalid) {
continue;
}
// NOTE(bill): the ordering here matters
Operand z = y;
check_comparison(c, &z, &x, Token_CmpEq);
if (z.mode == Addressing_Invalid) {
continue;
}
if (y.mode != Addressing_Constant) {
continue;
}
if (y.value.kind != ExactValue_Invalid) {
HashKey key = hash_exact_value(y.value);
TypeAndToken *found = map_type_and_token_get(&seen, key);
if (found != NULL) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
isize count = map_type_and_token_multi_count(&seen, key);
TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count);
map_type_and_token_multi_get_all(&seen, key, taps);
bool continue_outer = false;
for (isize i = 0; i < count; i++) {
TypeAndToken tap = taps[i];
if (are_types_identical(y.type, tap.type)) {
TokenPos pos = tap.token.pos;
gbString expr_str = expr_to_string(y.expr);
error_node(y.expr,
"Duplicate case `%s`\n"
"\tprevious case at %.*s(%td:%td)",
expr_str,
LIT(pos.file), pos.line, pos.column);
gb_string_free(expr_str);
continue_outer = true;
break;
}
}
gb_temp_arena_memory_end(tmp);
if (continue_outer) {
continue;
}
}
gb_temp_arena_memory_end(tmp);
if (continue_outer) {
continue;
}
TypeAndToken tap = {y.type, ast_node_token(y.expr)};
map_type_and_token_multi_insert(&seen, key, tap);
}
TypeAndToken tap = {y.type, ast_node_token(y.expr)};
map_type_and_token_multi_insert(&seen, key, tap);
}
}
@@ -981,9 +1230,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
mod_flags |= Stmt_BreakAllowed;
check_open_scope(c, node);
check_label(c, ms->label); // TODO(bill): What should the label's "scope" be?
bool is_union_ptr = false;
bool is_any = false;
MatchTypeKind match_type_kind = MatchType_Invalid;
if (ms->tag->kind != AstNode_AssignStmt) {
error_node(ms->tag, "Expected an `in` assignment for this type match statement");
@@ -1005,14 +1254,15 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
check_expr(c, &x, rhs);
check_assignment(c, &x, NULL, str_lit("type match expression"));
if (!check_valid_type_match_type(x.type, &is_union_ptr, &is_any)) {
match_type_kind = check_valid_type_match_type(x.type);
if (check_valid_type_match_type(x.type) == MatchType_Invalid) {
gbString str = type_to_string(x.type);
error_node(x.expr,
"Invalid type for this type match expression, got `%s`", str);
error_node(x.expr, "Invalid type for this type match expression, got `%s`", str);
gb_string_free(str);
break;
}
bool is_ptr = is_type_pointer(x.type);
// NOTE(bill): Check for multiple defaults
AstNode *first_default = NULL;
@@ -1048,7 +1298,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
MapBool seen = {0};
MapBool seen = {0}; // Multimap
map_bool_init(&seen, heap_allocator());
for_array(i, bs->stmts) {
@@ -1062,74 +1312,76 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
// TODO(bill): Make robust
Type *bt = base_type(type_deref(x.type));
AstNode *type_expr = cc->list.count > 0 ? cc->list.e[0] : NULL;
Type *case_type = NULL;
if (type_expr != NULL) { // Otherwise it's a default expression
Operand y = {0};
check_expr_or_type(c, &y, type_expr);
for_array(type_index, cc->list) {
AstNode *type_expr = cc->list.e[type_index];
if (type_expr != NULL) { // Otherwise it's a default expression
Operand y = {0};
check_expr_or_type(c, &y, type_expr);
if (is_union_ptr) {
GB_ASSERT(is_type_union(bt));
bool tag_type_found = false;
for (isize i = 0; i < bt->Record.variant_count; i++) {
Entity *f = bt->Record.variants[i];
if (are_types_identical(f->type, y.type)) {
tag_type_found = true;
break;
if (match_type_kind == MatchType_Union) {
GB_ASSERT(is_type_union(bt));
bool tag_type_found = false;
for (isize i = 0; i < bt->Record.variant_count; i++) {
Entity *f = bt->Record.variants[i];
if (are_types_identical(f->type, y.type)) {
tag_type_found = true;
break;
}
}
if (!tag_type_found) {
gbString type_str = type_to_string(y.type);
error_node(y.expr, "Unknown tag type, got `%s`", type_str);
gb_string_free(type_str);
continue;
}
case_type = y.type;
} else if (match_type_kind == MatchType_Any) {
case_type = y.type;
} else {
GB_PANIC("Unknown type to type match statement");
}
if (!tag_type_found) {
gbString type_str = type_to_string(y.type);
error_node(y.expr, "Unknown tag type, got `%s`", type_str);
gb_string_free(type_str);
continue;
}
case_type = y.type;
} else if (is_any) {
case_type = y.type;
} else {
GB_PANIC("Unknown type to type match statement");
}
HashKey key = hash_pointer(y.type);
bool *found = map_bool_get(&seen, key);
if (found) {
TokenPos pos = cc->token.pos;
gbString expr_str = expr_to_string(y.expr);
error_node(y.expr,
"Duplicate type case `%s`\n"
"\tprevious type case at %.*s(%td:%td)",
expr_str,
LIT(pos.file), pos.line, pos.column);
gb_string_free(expr_str);
break;
HashKey key = hash_pointer(y.type);
bool *found = map_bool_get(&seen, key);
if (found) {
TokenPos pos = cc->token.pos;
gbString expr_str = expr_to_string(y.expr);
error_node(y.expr,
"Duplicate type case `%s`\n"
"\tprevious type case at %.*s(%td:%td)",
expr_str,
LIT(pos.file), pos.line, pos.column);
gb_string_free(expr_str);
break;
}
map_bool_set(&seen, key, cast(bool)true);
}
map_bool_set(&seen, key, cast(bool)true);
}
check_open_scope(c, stmt);
if (is_ptr &&
!is_type_any(type_deref(x.type)) &&
cc->list.count == 1 &&
case_type != NULL) {
case_type = make_type_pointer(c->allocator, case_type);
}
if (cc->list.count > 1) {
case_type = NULL;
}
if (case_type == NULL) {
if (is_union_ptr) {
case_type = type_deref(x.type);
} else {
case_type = x.type;
}
case_type = x.type;
}
add_type_info_type(c, case_type);
check_open_scope(c, stmt);
{
// NOTE(bill): Dummy type
Type *tt = case_type;
if (is_union_ptr) {
tt = make_type_pointer(c->allocator, case_type);
add_type_info_type(c, tt);
}
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident, tt, true);
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident, case_type, false);
tag_var->flags |= EntityFlag_Used;
tag_var->flags |= EntityFlag_Value;
add_entity(c, c->context.scope, lhs, tag_var);
add_entity_use(c, lhs, tag_var);
add_implicit_entity(c, stmt, tag_var);
}
check_stmt_list(c, cc->stmts, mod_flags);
check_close_scope(c);
@@ -1173,20 +1425,38 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
error(token, "Invalid AST: Branch Statement `%.*s`", LIT(token.string));
break;
}
if (bs->label != NULL) {
if (bs->label->kind != AstNode_Ident) {
error_node(bs->label, "A branch statement's label name must be an identifier");
return;
}
AstNode *ident = bs->label;
String name = ident->Ident.string;
Entity *e = scope_lookup_entity(c->context.scope, name);
if (e == NULL) {
error_node(ident, "Undeclared label name: %.*s", LIT(name));
return;
}
add_entity_use(c, ident, e);
if (e->kind != Entity_Label) {
error_node(ident, "`%.*s` is not a label", LIT(name));
return;
}
}
case_end;
case_ast_node(us, UsingStmt, node);
switch (us->node->kind) {
default:
// TODO(bill): Better error message for invalid using statement
error(us->token, "Invalid `using` statement");
break;
case_ast_node(es, ExprStmt, us->node);
// TODO(bill): Allow for just a LHS expression list rather than this silly code
if (us->list.count == 0) {
error(us->token, "Empty `using` list");
return;
}
for_array(i, us->list) {
AstNode *expr = unparen_expr(us->list.e[0]);
Entity *e = NULL;
bool is_selector = false;
AstNode *expr = unparen_expr(es->expr);
if (expr->kind == AstNode_Ident) {
String name = expr->Ident.string;
e = scope_lookup_entity(c->context.scope, name);
@@ -1194,122 +1464,18 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Operand o = {0};
e = check_selector(c, &o, expr, NULL);
is_selector = true;
} else if (expr->kind == AstNode_Implicit) {
error(us->token, "`using` applied to an implicit value");
continue;
}
if (e == NULL) {
error(us->token, "`using` applied to an unknown entity");
if (!check_using_stmt_entity(c, us, expr, is_selector, e)) {
return;
}
switch (e->kind) {
case Entity_TypeName: {
Type *t = base_type(e->type);
if (is_type_union(t)) {
for (isize i = 0; i < t->Record.variant_count; i++) {
Entity *f = t->Record.variants[i];
Entity *found = scope_insert_entity(c->context.scope, f);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
gb_string_free(expr_str);
return;
}
f->using_parent = e;
}
} else if (is_type_enum(t)) {
for (isize i = 0; i < t->Record.field_count; i++) {
Entity *f = t->Record.fields[i];
Entity *found = scope_insert_entity(c->context.scope, f);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
gb_string_free(expr_str);
return;
}
f->using_parent = e;
}
} else {
error(us->token, "`using` can be only applied to `union` or `enum` type entities");
}
} break;
case Entity_ImportName: {
Scope *scope = e->ImportName.scope;
for_array(i, scope->elements.entries) {
Entity *decl = scope->elements.entries.e[i].value;
Entity *found = scope_insert_entity(c->context.scope, decl);
if (found != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token,
"Namespace collision while `using` `%s` of: %.*s\n"
"\tat %.*s(%td:%td)\n"
"\tat %.*s(%td:%td)",
expr_str, LIT(found->token.string),
LIT(found->token.pos.file), found->token.pos.line, found->token.pos.column,
LIT(decl->token.pos.file), decl->token.pos.line, decl->token.pos.column
);
gb_string_free(expr_str);
return;
}
}
} break;
case Entity_Variable: {
Type *t = base_type(type_deref(e->type));
if (is_type_struct(t) || is_type_raw_union(t)) {
// TODO(bill): Make it work for unions too
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
GB_ASSERT(found != NULL);
for_array(i, (*found)->elements.entries) {
Entity *f = (*found)->elements.entries.e[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
if (is_selector) {
uvar->using_expr = expr;
}
Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != NULL) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string));
gb_string_free(expr_str);
return;
}
}
}
} else {
error(us->token, "`using` can only be applied to variables of type struct or raw_union");
return;
}
} break;
case Entity_Constant:
error(us->token, "`using` cannot be applied to a constant");
break;
case Entity_Procedure:
case Entity_Builtin:
error(us->token, "`using` cannot be applied to a procedure");
break;
case Entity_Nil:
error(us->token, "`using` cannot be applied to `nil`");
break;
case Entity_Invalid:
error(us->token, "`using` cannot be applied to an invalid entity");
break;
default:
GB_PANIC("TODO(bill): `using` other expressions?");
}
case_end;
}
case_end;
case_ast_node(pa, PushAllocator, node);
Operand op = {0};
check_expr(c, &op, pa->expr);
@@ -1328,7 +1494,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_ast_node(vd, ValueDecl, node);
GB_ASSERT(!c->context.scope->is_file);
if (vd->is_var) {
if (!vd->is_var) {
// NOTE(bill): Handled elsewhere
} else {
Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count);
isize entity_count = 0;
@@ -1438,9 +1606,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
}
}
} else {
// NOTE(bill): Handled elsewhere
}
case_end;
}
+188 -86
View File
@@ -11,7 +11,8 @@ typedef enum StmtFlag {
Stmt_BreakAllowed = 1<<0,
Stmt_ContinueAllowed = 1<<1,
Stmt_FallthroughAllowed = 1<<2,
Stmt_GiveAllowed = 1<<3,
Stmt_CheckScopeDecls = 1<<5,
} StmtFlag;
typedef struct BuiltinProc {
@@ -23,9 +24,12 @@ typedef struct BuiltinProc {
typedef enum BuiltinProcId {
BuiltinProc_Invalid,
BuiltinProc_len,
BuiltinProc_cap,
BuiltinProc_new,
BuiltinProc_new_slice,
BuiltinProc_free,
BuiltinProc_make,
BuiltinProc_reserve,
BuiltinProc_clear,
@@ -48,12 +52,17 @@ typedef enum BuiltinProcId {
BuiltinProc_panic,
BuiltinProc_copy,
// BuiltinProc_append,
BuiltinProc_swizzle,
// BuiltinProc_ptr_offset,
// BuiltinProc_ptr_sub,
BuiltinProc_complex,
BuiltinProc_quaternion,
BuiltinProc_real,
BuiltinProc_imag,
BuiltinProc_jmag,
BuiltinProc_kmag,
BuiltinProc_conj,
BuiltinProc_slice_ptr,
BuiltinProc_slice_to_bytes,
@@ -62,14 +71,19 @@ typedef enum BuiltinProcId {
BuiltinProc_abs,
BuiltinProc_clamp,
BuiltinProc_transmute,
BuiltinProc_Count,
} BuiltinProcId;
gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
{STR_LIT(""), 0, false, Expr_Stmt},
{STR_LIT("len"), 1, false, Expr_Expr},
{STR_LIT("cap"), 1, false, Expr_Expr},
{STR_LIT("new"), 1, false, Expr_Expr},
{STR_LIT("new_slice"), 2, true, Expr_Expr},
{STR_LIT("free"), 1, false, Expr_Stmt},
{STR_LIT("make"), 1, true, Expr_Expr},
{STR_LIT("reserve"), 2, false, Expr_Stmt},
{STR_LIT("clear"), 1, false, Expr_Stmt},
@@ -87,24 +101,31 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
{STR_LIT("type_info"), 1, false, Expr_Expr},
{STR_LIT("type_info_of_val"), 1, false, Expr_Expr},
{STR_LIT("compile_assert"), 1, false, Expr_Stmt},
{STR_LIT("assert"), 1, false, Expr_Stmt},
{STR_LIT("compile_assert"), 1, false, Expr_Expr},
{STR_LIT("assert"), 1, false, Expr_Expr},
{STR_LIT("panic"), 1, false, Expr_Stmt},
{STR_LIT("copy"), 2, false, Expr_Expr},
// {STR_LIT("append"), 2, false, Expr_Expr},
{STR_LIT("swizzle"), 1, true, Expr_Expr},
// {STR_LIT("ptr_offset"), 2, false, Expr_Expr},
// {STR_LIT("ptr_sub"), 2, false, Expr_Expr},
{STR_LIT("slice_ptr"), 2, false, Expr_Expr},
{STR_LIT("complex"), 2, false, Expr_Expr},
{STR_LIT("quaternion"), 4, false, Expr_Expr},
{STR_LIT("real"), 1, false, Expr_Expr},
{STR_LIT("imag"), 1, false, Expr_Expr},
{STR_LIT("jmag"), 1, false, Expr_Expr},
{STR_LIT("kmag"), 1, false, Expr_Expr},
{STR_LIT("conj"), 1, false, Expr_Expr},
{STR_LIT("slice_ptr"), 2, true, Expr_Expr},
{STR_LIT("slice_to_bytes"), 1, false, Expr_Stmt},
{STR_LIT("min"), 2, false, Expr_Expr},
{STR_LIT("max"), 2, false, Expr_Expr},
{STR_LIT("abs"), 1, false, Expr_Expr},
{STR_LIT("clamp"), 3, false, Expr_Expr},
{STR_LIT("transmute"), 2, false, Expr_Expr},
};
@@ -163,28 +184,38 @@ bool is_operand_nil(Operand o) {
}
typedef struct BlockLabel {
String name;
AstNode *label; // AstNode_Label;
} BlockLabel;
// DeclInfo is used to store information of certain declarations to allow for "any order" usage
typedef struct DeclInfo {
Scope *scope;
typedef struct DeclInfo DeclInfo;
struct DeclInfo {
DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment
Scope * scope;
Entity **entities;
isize entity_count;
Entity ** entities;
isize entity_count;
AstNode *type_expr;
AstNode *init_expr;
AstNode *proc_lit; // AstNode_ProcLit
AstNode * type_expr;
AstNode * init_expr;
AstNode * proc_lit; // AstNode_ProcLit
MapBool deps; // Key: Entity *
} DeclInfo;
MapBool deps; // Key: Entity *
Array(BlockLabel) labels;
};
// ProcedureInfo stores the information needed for checking a procedure
typedef struct ProcedureInfo {
AstFile * file;
Token token;
DeclInfo *decl;
Type * type; // Type_Procedure
AstNode * body; // AstNode_BlockStmt
u32 tags;
AstFile * file;
Token token;
DeclInfo * decl;
Type * type; // Type_Procedure
AstNode * body; // AstNode_BlockStmt
u32 tags;
} ProcedureInfo;
// ExprInfo stores information used for "untyped" expressions
@@ -208,21 +239,21 @@ ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue
#include "map.c"
typedef struct Scope {
Scope * parent;
Scope * prev, *next;
Scope * first_child;
Scope * last_child;
MapEntity elements; // Key: String
MapBool implicit; // Key: Entity *
Scope * parent;
Scope * prev, *next;
Scope * first_child;
Scope * last_child;
MapEntity elements; // Key: String
MapBool implicit; // Key: Entity *
Array(Scope *) shared;
Array(Scope *) imported;
bool is_proc;
bool is_global;
bool is_file;
bool is_init;
bool has_been_imported; // This is only applicable to file scopes
AstFile * file;
Array(Scope *) shared;
Array(Scope *) imported;
bool is_proc;
bool is_global;
bool is_file;
bool is_init;
bool has_been_imported; // This is only applicable to file scopes
AstFile * file;
} Scope;
gb_global Scope *universal_scope = NULL;
@@ -278,6 +309,7 @@ typedef struct CheckerInfo {
MapScope scopes; // Key: AstNode * | Node -> Scope
MapExprInfo untyped; // Key: AstNode * | Expression -> ExprInfo
MapDeclInfo entities; // Key: Entity *
MapEntity implicits; // Key: AstNode *
MapEntity foreigns; // Key: String
MapAstFile files; // Key: String (full path)
MapIsize type_info_map; // Key: Type *
@@ -317,14 +349,16 @@ typedef Array(DelayedEntity) DelayedEntities;
void init_declaration_info(DeclInfo *d, Scope *scope) {
d->scope = scope;
void init_declaration_info(DeclInfo *d, Scope *scope, DeclInfo *parent) {
d->parent = parent;
d->scope = scope;
map_bool_init(&d->deps, heap_allocator());
array_init(&d->labels, heap_allocator());
}
DeclInfo *make_declaration_info(gbAllocator a, Scope *scope) {
DeclInfo *make_declaration_info(gbAllocator a, Scope *scope, DeclInfo *parent) {
DeclInfo *d = gb_alloc_item(a, DeclInfo);
init_declaration_info(d, scope);
init_declaration_info(d, scope, parent);
return d;
}
@@ -357,9 +391,9 @@ Scope *make_scope(Scope *parent, gbAllocator allocator) {
Scope *s = gb_alloc_item(allocator, Scope);
s->parent = parent;
map_entity_init(&s->elements, heap_allocator());
map_bool_init(&s->implicit, heap_allocator());
array_init(&s->shared, heap_allocator());
array_init(&s->imported, heap_allocator());
map_bool_init(&s->implicit, heap_allocator());
array_init(&s->shared, heap_allocator());
array_init(&s->imported, heap_allocator());
if (parent != NULL && parent != universal_scope) {
DLIST_APPEND(parent->first_child, parent->last_child, s);
@@ -455,6 +489,9 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit
if (found) {
Entity *e = *found;
if (gone_thru_proc) {
if (e->kind == Entity_Label) {
continue;
}
if (e->kind == Entity_Variable &&
!e->scope->is_file &&
!e->scope->is_global) {
@@ -520,6 +557,10 @@ Entity *scope_lookup_entity(Scope *s, String name) {
Entity *scope_insert_entity(Scope *s, Entity *entity) {
String name = entity->token.string;
if (str_eq(name, str_lit("output"))) {
gb_printf_err("Here! %.*s\n", LIT(name));
}
HashKey key = hash_string(name);
Entity **found = map_entity_get(&s->elements, key);
@@ -596,7 +637,7 @@ void add_global_constant(gbAllocator a, String name, Type *type, ExactValue valu
void add_global_string_constant(gbAllocator a, String name, String value) {
add_global_constant(a, name, t_untyped_string, make_exact_value_string(value));
add_global_constant(a, name, t_untyped_string, exact_value_string(value));
}
@@ -616,8 +657,8 @@ void init_universal_scope(void) {
}
// Constants
add_global_constant(a, str_lit("true"), t_untyped_bool, make_exact_value_bool(true));
add_global_constant(a, str_lit("false"), t_untyped_bool, make_exact_value_bool(false));
add_global_constant(a, str_lit("true"), t_untyped_bool, exact_value_bool(true));
add_global_constant(a, str_lit("false"), t_untyped_bool, exact_value_bool(false));
add_global_entity(make_entity_nil(a, str_lit("nil"), t_untyped_nil));
add_global_entity(make_entity_library_name(a, universal_scope,
@@ -662,6 +703,7 @@ void init_checker_info(CheckerInfo *i) {
map_decl_info_init(&i->entities, a);
map_expr_info_init(&i->untyped, a);
map_entity_init(&i->foreigns, a);
map_entity_init(&i->implicits, a);
map_isize_init(&i->type_info_map, a);
map_ast_file_init(&i->files, a);
i->type_info_count = 0;
@@ -676,12 +718,17 @@ void destroy_checker_info(CheckerInfo *i) {
map_decl_info_destroy(&i->entities);
map_expr_info_destroy(&i->untyped);
map_entity_destroy(&i->foreigns);
map_entity_destroy(&i->implicits);
map_isize_destroy(&i->type_info_map);
map_ast_file_destroy(&i->files);
}
void init_checker(Checker *c, Parser *parser, BuildContext *bc) {
if (global_error_collector.count > 0) {
gb_exit(1);
}
gbAllocator a = heap_allocator();
c->parser = parser;
@@ -816,7 +863,7 @@ bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
return false;
}
error(entity->token,
"Redeclararation of `%.*s` in this scope through `using`\n"
"Redeclaration of `%.*s` in this scope through `using`\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
@@ -827,7 +874,7 @@ bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
return false;
}
error(entity->token,
"Redeclararation of `%.*s` in this scope\n"
"Redeclaration of `%.*s` in this scope\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(pos.file), pos.line, pos.column);
@@ -861,6 +908,12 @@ void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclIn
}
void add_implicit_entity(Checker *c, AstNode *node, Entity *e) {
GB_ASSERT(node != NULL);
GB_ASSERT(e != NULL);
map_entity_set(&c->info.implicits, hash_pointer(node), e);
}
void add_type_info_type(Checker *c, Type *t) {
if (t == NULL) {
@@ -919,6 +972,24 @@ void add_type_info_type(Checker *c, Type *t) {
add_type_info_type(c, t_type_info_ptr);
add_type_info_type(c, t_rawptr);
break;
case Basic_complex64:
add_type_info_type(c, t_type_info_float);
add_type_info_type(c, t_f32);
break;
case Basic_complex128:
add_type_info_type(c, t_type_info_float);
add_type_info_type(c, t_f64);
break;
case Basic_quaternion128:
add_type_info_type(c, t_type_info_float);
add_type_info_type(c, t_f32);
break;
case Basic_quaternion256:
add_type_info_type(c, t_type_info_float);
add_type_info_type(c, t_f64);
break;
}
} break;
@@ -926,6 +997,10 @@ void add_type_info_type(Checker *c, Type *t) {
add_type_info_type(c, bt->Pointer.elem);
break;
case Type_Atomic:
add_type_info_type(c, bt->Atomic.elem);
break;
case Type_Array:
add_type_info_type(c, bt->Array.elem);
add_type_info_type(c, make_type_pointer(c->allocator, bt->Array.elem));
@@ -1107,35 +1182,41 @@ void init_preload(Checker *c) {
if (record->variant_count != 19) {
if (record->variant_count != 22) {
compiler_error("Invalid `Type_Info` layout");
}
t_type_info_named = record->variants[ 1]->type;
t_type_info_integer = record->variants[ 2]->type;
t_type_info_float = record->variants[ 3]->type;
t_type_info_string = record->variants[ 4]->type;
t_type_info_boolean = record->variants[ 5]->type;
t_type_info_any = record->variants[ 6]->type;
t_type_info_pointer = record->variants[ 7]->type;
t_type_info_procedure = record->variants[ 8]->type;
t_type_info_array = record->variants[ 9]->type;
t_type_info_dynamic_array = record->variants[10]->type;
t_type_info_slice = record->variants[11]->type;
t_type_info_vector = record->variants[12]->type;
t_type_info_tuple = record->variants[13]->type;
t_type_info_struct = record->variants[14]->type;
t_type_info_raw_union = record->variants[15]->type;
t_type_info_union = record->variants[16]->type;
t_type_info_enum = record->variants[17]->type;
t_type_info_map = record->variants[18]->type;
t_type_info_complex = record->variants[ 4]->type;
t_type_info_quaternion = record->variants[ 5]->type;
t_type_info_string = record->variants[ 6]->type;
t_type_info_boolean = record->variants[ 7]->type;
t_type_info_any = record->variants[ 8]->type;
t_type_info_pointer = record->variants[ 9]->type;
t_type_info_atomic = record->variants[10]->type;
t_type_info_procedure = record->variants[11]->type;
t_type_info_array = record->variants[12]->type;
t_type_info_dynamic_array = record->variants[13]->type;
t_type_info_slice = record->variants[14]->type;
t_type_info_vector = record->variants[15]->type;
t_type_info_tuple = record->variants[16]->type;
t_type_info_struct = record->variants[17]->type;
t_type_info_raw_union = record->variants[18]->type;
t_type_info_union = record->variants[19]->type;
t_type_info_enum = record->variants[20]->type;
t_type_info_map = record->variants[21]->type;
t_type_info_named_ptr = make_type_pointer(c->allocator, t_type_info_named);
t_type_info_integer_ptr = make_type_pointer(c->allocator, t_type_info_integer);
t_type_info_float_ptr = make_type_pointer(c->allocator, t_type_info_float);
t_type_info_complex_ptr = make_type_pointer(c->allocator, t_type_info_complex);
t_type_info_quaternion_ptr = make_type_pointer(c->allocator, t_type_info_quaternion);
t_type_info_string_ptr = make_type_pointer(c->allocator, t_type_info_string);
t_type_info_boolean_ptr = make_type_pointer(c->allocator, t_type_info_boolean);
t_type_info_any_ptr = make_type_pointer(c->allocator, t_type_info_any);
t_type_info_pointer_ptr = make_type_pointer(c->allocator, t_type_info_pointer);
t_type_info_atomic_ptr = make_type_pointer(c->allocator, t_type_info_atomic);
t_type_info_procedure_ptr = make_type_pointer(c->allocator, t_type_info_procedure);
t_type_info_array_ptr = make_type_pointer(c->allocator, t_type_info_array);
t_type_info_dynamic_array_ptr = make_type_pointer(c->allocator, t_type_info_dynamic_array);
@@ -1162,12 +1243,6 @@ void init_preload(Checker *c) {
t_context_ptr = make_type_pointer(c->allocator, t_context);
}
if (t_raw_dynamic_array == NULL) {
Entity *e = find_core_entity(c, str_lit("Raw_Dynamic_Array"));
t_raw_dynamic_array = e->type;
t_raw_dynamic_array = make_type_pointer(c->allocator, t_raw_dynamic_array);
}
if (t_map_key == NULL) {
Entity *e = find_core_entity(c, str_lit("__Map_Key"));
t_map_key = e->type;
@@ -1234,7 +1309,6 @@ void check_procedure_overloading(Checker *c, Entity *e) {
continue;
}
String name = p->token.string;
GB_ASSERT(p->kind == Entity_Procedure);
@@ -1397,7 +1471,7 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_cap);
DeclInfo *di = NULL;
if (vd->values.count > 0) {
di = make_declaration_info(heap_allocator(), c->context.scope);
di = make_declaration_info(heap_allocator(), c->context.scope, c->context.decl);
di->entities = entities;
di->type_expr = vd->type;
di->init_expr = vd->values.e[0];
@@ -1432,7 +1506,7 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
DeclInfo *d = di;
if (d == NULL) {
AstNode *init_expr = value;
d = make_declaration_info(heap_allocator(), e->scope);
d = make_declaration_info(heap_allocator(), e->scope, c->context.decl);
d->type_expr = vd->type;
d->init_expr = init_expr;
}
@@ -1458,15 +1532,25 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
init = vd->values.e[i];
}
DeclInfo *d = make_declaration_info(c->allocator, c->context.scope);
DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, c->context.decl);
Entity *e = NULL;
AstNode *up_init = unparen_expr(init);
if (up_init != NULL && is_ast_node_type(up_init)) {
AstNode *type = up_init;
e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
// TODO(bill): What if vd->type != NULL??? How to handle this case?
d->type_expr = init;
d->init_expr = init;
d->type_expr = type;
d->init_expr = type;
} else if (up_init != NULL && up_init->kind == AstNode_Alias) {
#if 1
error_node(up_init, "#alias declarations are not yet supported");
continue;
#else
e = make_entity_alias(c->allocator, d->scope, name->Ident, NULL, EntityAlias_Invalid, NULL);
d->type_expr = vd->type;
d->init_expr = up_init->Alias.expr;
#endif
} else if (init != NULL && up_init->kind == AstNode_ProcLit) {
e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
d->proc_lit = up_init;
@@ -1512,6 +1596,19 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
continue;
}
if (fl->cond != NULL) {
Operand operand = {Addressing_Invalid};
check_expr(c, &operand, fl->cond);
if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) {
error_node(fl->cond, "Non-constant boolean `when` condition");
continue;
}
if (operand.value.kind == ExactValue_Bool &&
!operand.value.value_bool) {
continue;
}
}
DelayedDecl di = {c->context.scope, decl};
array_add(&c->delayed_foreign_libraries, di);
case_end;
@@ -1826,7 +1923,7 @@ void check_parsed_files(Checker *c) {
}
f->scope = scope;
f->decl_info = make_declaration_info(c->allocator, f->scope);
f->decl_info = make_declaration_info(c->allocator, f->scope, c->context.decl);
HashKey key = hash_string(f->tokenizer.fullpath);
map_scope_set(&file_scopes, key, scope);
map_ast_file_set(&c->info.files, key, f);
@@ -1903,17 +2000,25 @@ void check_parsed_files(Checker *c) {
}
}
// NOTE(bill): Check for illegal cyclic type declarations
for_array(i, c->info.definitions.entries) {
Entity *e = c->info.definitions.entries.e[i].value;
if (e->kind == Entity_TypeName) {
if (e->kind == Entity_TypeName ||
(e->kind == Entity_Alias && e->Alias.kind == EntityAlias_Type)) {
if (e->type != NULL) {
// i64 size = type_size_of(c->sizes, c->allocator, e->type);
i64 align = type_align_of(c->allocator, e->type);
if (align > 0) {
// add_type_info_type(c, e->type);
}
}
}
}
// gb_printf_err("Count: %td\n", c->info.type_info_count++);
for_array(i, file_scopes.entries) {
Scope *s = file_scopes.entries.e[i].value;
if (s->is_init) {
@@ -1938,6 +2043,3 @@ void check_parsed_files(Checker *c) {
map_scope_destroy(&file_scopes);
}
+99
View File
@@ -1,7 +1,14 @@
#if defined(GB_SYSTEM_UNIX)
// Required for intrinsics on GCC
#include <xmmintrin.h>
#endif
#define GB_NO_DEFER
#define GB_IMPLEMENTATION
#include "gb/gb.h"
#include <math.h>
gbAllocator heap_allocator(void) {
return gb_heap_allocator();
}
@@ -24,6 +31,94 @@ gbAllocator scratch_allocator(void) {
return gb_scratch_allocator(&scratch_memory);
}
typedef struct DynamicArenaBlock DynamicArenaBlock;
typedef struct DynamicArena DynamicArena;
struct DynamicArenaBlock {
DynamicArenaBlock *prev;
DynamicArenaBlock *next;
u8 * start;
isize count;
isize capacity;
gbVirtualMemory vm;
};
struct DynamicArena {
DynamicArenaBlock *start_block;
DynamicArenaBlock *current_block;
isize block_size;
};
DynamicArenaBlock *add_dynamic_arena_block(DynamicArena *a) {
GB_ASSERT(a != NULL);
GB_ASSERT(a->block_size > 0);
gbVirtualMemory vm = gb_vm_alloc(NULL, a->block_size);
DynamicArenaBlock *block = cast(DynamicArenaBlock *)vm.data;
u8 *start = cast(u8 *)gb_align_forward(cast(u8 *)(block + 1), GB_DEFAULT_MEMORY_ALIGNMENT);
u8 *end = cast(u8 *)vm.data + vm.size;
block->vm = vm;
block->start = start;
block->count = 0;
block->capacity = end-start;
if (a->current_block != NULL) {
a->current_block->next = block;
block->prev = a->current_block;
}
a->current_block = block;
return block;
}
void init_dynamic_arena(DynamicArena *a, isize block_size) {
isize size = gb_size_of(DynamicArenaBlock) + block_size;
size = cast(isize)gb_align_forward(cast(void *)cast(uintptr)size, GB_DEFAULT_MEMORY_ALIGNMENT);
a->block_size = size;
a->start_block = add_dynamic_arena_block(a);
}
void destroy_dynamic_arena(DynamicArena *a) {
DynamicArenaBlock *b = a->current_block;
while (b != NULL) {
gbVirtualMemory vm = b->vm;
b = b->prev;
gb_vm_free(b->vm);
}
}
GB_ALLOCATOR_PROC(dynamic_arena_allocator_proc) {
DynamicArena *a = cast(DynamicArena *)allocator_data;
void *ptr = NULL;
switch (type) {
case gbAllocation_Alloc: {
} break;
case gbAllocation_Free: {
} break;
case gbAllocation_Resize: {
} break;
case gbAllocation_FreeAll:
GB_PANIC("free_all is not supported by this allocator");
break;
}
return ptr;
}
gbAllocator dynamic_arena_allocator(DynamicArena *a) {
gbAllocator allocator = {dynamic_arena_allocator_proc, a};
return allocator;
}
i64 next_pow2(i64 n) {
if (n <= 0) {
@@ -104,6 +199,10 @@ i16 f32_to_f16(f32 value) {
}
}
f64 gb_sqrt(f64 x) {
return sqrt(x);
}
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
+47 -8
View File
@@ -13,13 +13,15 @@ typedef struct Type Type;
ENTITY_KIND(Builtin) \
ENTITY_KIND(ImportName) \
ENTITY_KIND(LibraryName) \
ENTITY_KIND(Alias) \
ENTITY_KIND(Nil) \
ENTITY_KIND(Count)
ENTITY_KIND(Label)
typedef enum EntityKind {
#define ENTITY_KIND(k) GB_JOIN2(Entity_, k),
ENTITY_KINDS
#undef ENTITY_KIND
Entity_Count,
} EntityKind;
String const entity_strings[] = {
@@ -31,13 +33,14 @@ String const entity_strings[] = {
typedef enum EntityFlag {
EntityFlag_Visited = 1<<0,
EntityFlag_Used = 1<<1,
EntityFlag_Anonymous = 1<<2,
EntityFlag_Using = 1<<2,
EntityFlag_Field = 1<<3,
EntityFlag_Param = 1<<4,
EntityFlag_VectorElem = 1<<5,
EntityFlag_Ellipsis = 1<<6,
EntityFlag_NoAlias = 1<<7,
EntityFlag_TypeField = 1<<8,
EntityFlag_Value = 1<<9,
} EntityFlag;
// Zero value means the overloading process is not yet done
@@ -47,11 +50,18 @@ typedef enum OverloadKind {
Overload_Yes,
} OverloadKind;
typedef enum EntityAliasKind {
EntityAlias_Invalid,
EntityAlias_Type,
EntityAlias_Entity,
} EntityAliasKind;
// An Entity is a named "thing" in the language
typedef struct Entity Entity;
struct Entity {
EntityKind kind;
u64 id;
u32 flags;
Token token;
Scope * scope;
@@ -72,7 +82,9 @@ struct Entity {
bool is_immutable;
bool is_thread_local;
} Variable;
i32 TypeName;
struct {
bool is_type_alias;
} TypeName;
struct {
bool is_foreign;
String foreign_name;
@@ -95,7 +107,15 @@ struct Entity {
String name;
bool used;
} LibraryName;
struct {
EntityAliasKind kind;
Entity * original;
} Alias;
i32 Nil;
struct {
String name;
AstNode *node;
} Label;
};
};
@@ -126,6 +146,7 @@ bool is_entity_exported(Entity *e) {
return name.text[0] != '_';
}
gb_global u64 global_entity_id = 0;
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
Entity *entity = gb_alloc_item(a, Entity);
@@ -133,6 +154,7 @@ Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token,
entity->scope = scope;
entity->token = token;
entity->type = type;
entity->id = ++global_entity_id;
return entity;
}
@@ -147,7 +169,7 @@ Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, T
token.pos = parent->token.pos;
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
entity->using_parent = parent;
entity->flags |= EntityFlag_Anonymous;
entity->flags |= EntityFlag_Using;
return entity;
}
@@ -163,20 +185,20 @@ Entity *make_entity_type_name(gbAllocator a, Scope *scope, Token token, Type *ty
return entity;
}
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous, bool is_immutable) {
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, bool is_immutable) {
Entity *entity = make_entity_variable(a, scope, token, type, is_immutable);
entity->flags |= EntityFlag_Used;
if (anonymous) entity->flags |= EntityFlag_Anonymous;
if (is_using) entity->flags |= EntityFlag_Using;
entity->flags |= EntityFlag_Param;
return entity;
}
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous, i32 field_src_index) {
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, i32 field_src_index) {
Entity *entity = make_entity_variable(a, scope, token, type, false);
entity->Variable.field_src_index = field_src_index;
entity->Variable.field_index = field_src_index;
if (is_using) entity->flags |= EntityFlag_Using;
entity->flags |= EntityFlag_Field;
entity->flags |= EntityFlag_Anonymous*(anonymous != 0);
return entity;
}
@@ -218,12 +240,29 @@ Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type
return entity;
}
Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type,
EntityAliasKind kind, Entity *original) {
Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type);
entity->Alias.kind = kind;
entity->Alias.original = original;
return entity;
}
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
Token token = make_token_ident(name);
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type);
return entity;
}
Entity *make_entity_label(gbAllocator a, Scope *scope, Token token, Type *type,
AstNode *node) {
Entity *entity = alloc_entity(a, Entity_Label, scope, token, type);
entity->Label.node = node;
return entity;
}
Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
token.string = str_lit("_");
return make_entity_variable(a, scope, token, NULL, false);
+368 -58
View File
@@ -5,6 +5,14 @@
typedef struct AstNode AstNode;
typedef struct Complex128 {
f64 real, imag;
} Complex128;
typedef struct Quaternion256 {
f64 real, imag, jmag, kmag;
} Quaternion256;
typedef enum ExactValueKind {
ExactValue_Invalid,
@@ -12,6 +20,8 @@ typedef enum ExactValueKind {
ExactValue_String,
ExactValue_Integer,
ExactValue_Float,
ExactValue_Complex,
ExactValue_Quaternion,
ExactValue_Pointer,
ExactValue_Compound, // TODO(bill): Is this good enough?
@@ -21,12 +31,14 @@ typedef enum ExactValueKind {
typedef struct ExactValue {
ExactValueKind kind;
union {
bool value_bool;
String value_string;
i64 value_integer; // NOTE(bill): This must be an integer and not a pointer
f64 value_float;
i64 value_pointer;
AstNode *value_compound;
bool value_bool;
String value_string;
i64 value_integer; // NOTE(bill): This must be an integer and not a pointer
f64 value_float;
i64 value_pointer;
Complex128 value_complex;
Quaternion256 value_quaternion;
AstNode * value_compound;
};
} ExactValue;
@@ -35,45 +47,62 @@ HashKey hash_exact_value(ExactValue v) {
}
ExactValue make_exact_value_compound(AstNode *node) {
ExactValue exact_value_compound(AstNode *node) {
ExactValue result = {ExactValue_Compound};
result.value_compound = node;
return result;
}
ExactValue make_exact_value_bool(bool b) {
ExactValue exact_value_bool(bool b) {
ExactValue result = {ExactValue_Bool};
result.value_bool = (b != 0);
return result;
}
ExactValue make_exact_value_string(String string) {
ExactValue exact_value_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
ExactValue result = {ExactValue_String};
result.value_string = string;
return result;
}
ExactValue make_exact_value_integer(i64 i) {
ExactValue exact_value_integer(i64 i) {
ExactValue result = {ExactValue_Integer};
result.value_integer = i;
return result;
}
ExactValue make_exact_value_float(f64 f) {
ExactValue exact_value_float(f64 f) {
ExactValue result = {ExactValue_Float};
result.value_float = f;
return result;
}
ExactValue make_exact_value_pointer(i64 ptr) {
ExactValue exact_value_complex(f64 real, f64 imag) {
ExactValue result = {ExactValue_Complex};
result.value_complex.real = real;
result.value_complex.imag = imag;
return result;
}
ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
ExactValue result = {ExactValue_Quaternion};
result.value_quaternion.real = real;
result.value_quaternion.imag = imag;
result.value_quaternion.jmag = jmag;
result.value_quaternion.kmag = kmag;
return result;
}
ExactValue exact_value_pointer(i64 ptr) {
ExactValue result = {ExactValue_Pointer};
result.value_pointer = ptr;
return result;
}
ExactValue make_exact_value_integer_from_string(String string) {
ExactValue exact_value_integer_from_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
i32 base = 10;
bool has_prefix = false;
@@ -82,6 +111,7 @@ ExactValue make_exact_value_integer_from_string(String string) {
case 'b': base = 2; has_prefix = true; break;
case 'o': base = 8; has_prefix = true; break;
case 'd': base = 10; has_prefix = true; break;
case 'z': base = 12; has_prefix = true; break;
case 'x': base = 16; has_prefix = true; break;
}
}
@@ -100,25 +130,19 @@ ExactValue make_exact_value_integer_from_string(String string) {
continue;
}
i64 v = 0;
if (gb_char_is_digit(r)) {
v = r - '0';
} else if (gb_char_is_hex_digit(r)) {
v = gb_hex_digit_to_int(r);
} else {
v = digit_value(r);
if (v >= base) {
break;
}
result *= base;
result += v;
}
return make_exact_value_integer(result);
return exact_value_integer(result);
}
ExactValue make_exact_value_float_from_string(String string) {
f64 float_from_string(String string) {
isize i = 0;
u8 *str = string.text;
isize len = string.len;
@@ -137,10 +161,10 @@ ExactValue make_exact_value_float_from_string(String string) {
if (r == '_') {
continue;
}
if (!gb_char_is_digit(r)) {
i64 v = digit_value(r);
if (v >= 10) {
break;
}
i64 v = r - '0';
value *= 10.0;
value += v;
}
@@ -153,29 +177,38 @@ ExactValue make_exact_value_float_from_string(String string) {
if (r == '_') {
continue;
}
if (!gb_char_is_digit(r)) {
i64 v = digit_value(r);
if (v >= 10) {
break;
}
value += (r-'0')/pow10;
value += v/pow10;
pow10 *= 10.0;
}
}
f64 frac = 0;
bool frac = false;
f64 scale = 1.0;
if ((str[i] == 'e') || (str[i] == 'E')) {
i++;
if (str[i] == '-') {
frac = 1;
frac = true;
i++;
} else if (str[i] == '+') {
i++;
}
u32 exp;
for (exp = 0; gb_char_is_digit(str[i]); i++) {
exp = exp * 10 + (str[i]-'0');
u32 exp = 0;
for (; i < len; i++) {
Rune r = cast(Rune)str[i];
if (r == '_') {
continue;
}
u32 d = cast(u32)digit_value(r);
if (d >= 10) {
break;
}
exp = exp * 10 + d;
}
if (exp > 308) exp = 308;
@@ -184,21 +217,36 @@ ExactValue make_exact_value_float_from_string(String string) {
while (exp > 0) { scale *= 10.0; exp -= 1; }
}
f64 result = sign * (frac ? (value / scale) : (value * scale));
return make_exact_value_float(result);
return sign * (frac ? (value / scale) : (value * scale));
}
ExactValue exact_value_float_from_string(String string) {
return exact_value_float(float_from_string(string));
}
ExactValue make_exact_value_from_basic_literal(Token token) {
ExactValue exact_value_from_basic_literal(Token token) {
switch (token.kind) {
case Token_String: return make_exact_value_string(token.string);
case Token_Integer: return make_exact_value_integer_from_string(token.string);
case Token_Float: return make_exact_value_float_from_string(token.string);
case Token_String: return exact_value_string(token.string);
case Token_Integer: return exact_value_integer_from_string(token.string);
case Token_Float: return exact_value_float_from_string(token.string);
case Token_Imag: {
String str = token.string;
Rune last_rune = cast(Rune)str.text[str.len-1];
str.len--; // Ignore the `i|j|k`
f64 imag = float_from_string(str);
switch (last_rune) {
case 'i': return exact_value_complex(0, imag);
case 'j': return exact_value_quaternion(0, 0, imag, 0);
case 'k': return exact_value_quaternion(0, 0, 0, imag);
}
}
case Token_Rune: {
Rune r = GB_RUNE_INVALID;
gb_utf8_decode(token.string.text, token.string.len, &r);
// gb_printf("%.*s rune: %d\n", LIT(token.string), r);
return make_exact_value_integer(r);
return exact_value_integer(r);
}
default:
GB_PANIC("Invalid token for basic literal");
@@ -217,12 +265,12 @@ ExactValue exact_value_to_integer(ExactValue v) {
i64 i = cast(i64)v.value_float;
f64 f = cast(f64)i;
if (f == v.value_float) {
return make_exact_value_integer(i);
return exact_value_integer(i);
}
} break;
case ExactValue_Pointer:
return make_exact_value_integer(cast(i64)cast(intptr)v.value_pointer);
return exact_value_integer(cast(i64)cast(intptr)v.value_pointer);
}
ExactValue r = {ExactValue_Invalid};
return r;
@@ -231,7 +279,7 @@ ExactValue exact_value_to_integer(ExactValue v) {
ExactValue exact_value_to_float(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return make_exact_value_float(cast(i64)v.value_integer);
return exact_value_float(cast(i64)v.value_integer);
case ExactValue_Float:
return v;
}
@@ -239,6 +287,128 @@ ExactValue exact_value_to_float(ExactValue v) {
return r;
}
ExactValue exact_value_to_complex(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_complex(cast(i64)v.value_integer, 0);
case ExactValue_Float:
return exact_value_complex(v.value_float, 0);
case ExactValue_Complex:
return v;
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_to_quaternion(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(cast(i64)v.value_integer, 0, 0, 0);
case ExactValue_Float:
return exact_value_quaternion(v.value_float, 0, 0, 0);
case ExactValue_Complex:
return exact_value_quaternion(v.value_complex.real, v.value_complex.imag, 0, 0);
case ExactValue_Quaternion:
return v;
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_real(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
return v;
case ExactValue_Complex:
return exact_value_float(v.value_complex.real);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.real);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_imag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
return exact_value_integer(0);
case ExactValue_Complex:
return exact_value_float(v.value_complex.imag);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.imag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
return exact_value_integer(0);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.jmag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
return exact_value_integer(0);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.kmag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_make_imag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_complex(0, exact_value_to_float(v).value_float);
case ExactValue_Float:
return exact_value_complex(0, v.value_float);
default:
GB_PANIC("Expected an integer or float type for `exact_value_make_imag`");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_make_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
case ExactValue_Float:
return exact_value_quaternion(0, 0, v.value_float, 0);
default:
GB_PANIC("Expected an integer or float type for `exact_value_make_jmag`");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_make_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
case ExactValue_Float:
return exact_value_quaternion(0, 0, 0, v.value_float);
default:
GB_PANIC("Expected an integer or float type for `exact_value_make_kmag`");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) {
switch (op) {
@@ -247,6 +417,8 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
case ExactValue_Invalid:
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
case ExactValue_Quaternion:
return v;
}
} break;
@@ -265,6 +437,18 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
i.value_float = -i.value_float;
return i;
}
case ExactValue_Complex: {
f64 real = v.value_complex.real;
f64 imag = v.value_complex.imag;
return exact_value_complex(-real, -imag);
}
case ExactValue_Quaternion: {
f64 real = v.value_quaternion.real;
f64 imag = v.value_quaternion.imag;
f64 jmag = v.value_quaternion.jmag;
f64 kmag = v.value_quaternion.kmag;
return exact_value_quaternion(-real, -imag, -jmag, -kmag);
}
}
} break;
@@ -287,14 +471,14 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
i &= ~((~0ll)<<precision);
}
return make_exact_value_integer(i);
return exact_value_integer(i);
} break;
case Token_Not: {
switch (v.kind) {
case ExactValue_Invalid: return v;
case ExactValue_Bool:
return make_exact_value_bool(!v.value_bool);
return exact_value_bool(!v.value_bool);
}
} break;
}
@@ -318,8 +502,12 @@ i32 exact_value_order(ExactValue v) {
return 2;
case ExactValue_Float:
return 3;
case ExactValue_Pointer:
case ExactValue_Complex:
return 4;
case ExactValue_Quaternion:
return 5;
case ExactValue_Pointer:
return 6;
default:
GB_PANIC("How'd you get here? Invalid Value.kind");
@@ -340,6 +528,8 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Bool:
case ExactValue_String:
case ExactValue_Complex:
case ExactValue_Quaternion:
return;
case ExactValue_Integer:
@@ -348,18 +538,32 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
return;
case ExactValue_Float:
// TODO(bill): Is this good enough?
*x = make_exact_value_float(cast(f64)x->value_integer);
*x = exact_value_float(cast(f64)x->value_integer);
return;
case ExactValue_Complex:
*x = exact_value_complex(cast(f64)x->value_integer, 0);
return;
case ExactValue_Quaternion:
*x = exact_value_quaternion(cast(f64)x->value_integer, 0, 0, 0);
return;
}
break;
case ExactValue_Float:
if (y->kind == ExactValue_Float)
switch (y->kind) {
case ExactValue_Float:
return;
case ExactValue_Complex:
*x = exact_value_to_complex(*x);
return;
case ExactValue_Quaternion:
*x = exact_value_to_quaternion(*x);
return;
}
break;
}
compiler_error("How'd you get here? Invalid ExactValueKind");
compiler_error("match_exact_values: How'd you get here? Invalid ExactValueKind %d", x->kind);
}
// TODO(bill): Allow for pointer arithmetic? Or are pointer slices good enough?
@@ -372,10 +576,10 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
case ExactValue_Bool:
switch (op) {
case Token_CmpAnd: return make_exact_value_bool(x.value_bool && y.value_bool);
case Token_CmpOr: return make_exact_value_bool(x.value_bool || y.value_bool);
case Token_And: return make_exact_value_bool(x.value_bool & y.value_bool);
case Token_Or: return make_exact_value_bool(x.value_bool | y.value_bool);
case Token_CmpAnd: return exact_value_bool(x.value_bool && y.value_bool);
case Token_CmpOr: return exact_value_bool(x.value_bool || y.value_bool);
case Token_And: return exact_value_bool(x.value_bool & y.value_bool);
case Token_Or: return exact_value_bool(x.value_bool | y.value_bool);
default: goto error;
}
break;
@@ -388,7 +592,7 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
case Token_Add: c = a + b; break;
case Token_Sub: c = a - b; break;
case Token_Mul: c = a * b; break;
case Token_Quo: return make_exact_value_float(fmod(cast(f64)a, cast(f64)b));
case Token_Quo: return exact_value_float(fmod(cast(f64)a, cast(f64)b));
case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division
case Token_Mod: c = a % b; break;
case Token_And: c = a & b; break;
@@ -400,20 +604,98 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
default: goto error;
}
return make_exact_value_integer(c);
return exact_value_integer(c);
} break;
case ExactValue_Float: {
f64 a = x.value_float;
f64 b = y.value_float;
switch (op) {
case Token_Add: return make_exact_value_float(a + b);
case Token_Sub: return make_exact_value_float(a - b);
case Token_Mul: return make_exact_value_float(a * b);
case Token_Quo: return make_exact_value_float(a / b);
case Token_Add: return exact_value_float(a + b);
case Token_Sub: return exact_value_float(a - b);
case Token_Mul: return exact_value_float(a * b);
case Token_Quo: return exact_value_float(a / b);
default: goto error;
}
} break;
case ExactValue_Complex: {
y = exact_value_to_complex(y);
f64 a = x.value_complex.real;
f64 b = x.value_complex.imag;
f64 c = y.value_complex.real;
f64 d = y.value_complex.imag;
f64 real = 0;
f64 imag = 0;
switch (op) {
case Token_Add:
real = a + c;
imag = b + d;
break;
case Token_Sub:
real = a - c;
imag = b - d;
break;
case Token_Mul:
real = (a*c - b*d);
imag = (b*c + a*d);
break;
case Token_Quo: {
f64 s = c*c + d*d;
real = (a*c + b*d)/s;
imag = (b*c - a*d)/s;
} break;
default: goto error;
}
return exact_value_complex(real, imag);
} break;
case ExactValue_Quaternion: {
y = exact_value_to_quaternion(y);
f64 a = x.value_quaternion.real;
f64 b = x.value_quaternion.imag;
f64 c = x.value_quaternion.jmag;
f64 d = x.value_quaternion.kmag;
f64 e = x.value_quaternion.real;
f64 f = x.value_quaternion.imag;
f64 g = x.value_quaternion.jmag;
f64 h = x.value_quaternion.kmag;
f64 real = 0;
f64 imag = 0;
f64 jmag = 0;
f64 kmag = 0;
switch (op) {
case Token_Add:
real = a + e;
imag = b + f;
jmag = c + g;
kmag = d + h;
break;
case Token_Sub:
real = a - e;
imag = b - f;
jmag = c - g;
kmag = d - h;
break;
case Token_Mul:
real = a*f + b*e + c*h - d*g;
imag = a*g - b*h + c*e + d*f;
jmag = a*h + b*g - c*f + d*e;
kmag = a*e - b*f - c*g - d*h;
break;
case Token_Quo: {
f64 s = e*e + f*f + g*g + h*h;
real = (+a*e + b*f + c*g + d*h)/s;
imag = (-a*f + b*e - c*h + d*h)/s;
jmag = (-a*g + b*h + c*e - d*f)/s;
kmag = (-a*h - b*g + c*f + d*e)/s;
} break;
default: goto error;
}
return exact_value_quaternion(real, imag, jmag, kmag);
} break;
}
error:
@@ -474,6 +756,34 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
}
} break;
case ExactValue_Complex: {
f64 a = x.value_complex.real;
f64 b = x.value_complex.imag;
f64 c = y.value_complex.real;
f64 d = y.value_complex.imag;
switch (op) {
case Token_CmpEq: return cmp_f64(a, c) == 0 && cmp_f64(b, d) == 0;
case Token_NotEq: return cmp_f64(a, c) != 0 || cmp_f64(b, d) != 0;
}
} break;
case ExactValue_Quaternion: {
f64 a = x.value_quaternion.real;
f64 b = x.value_quaternion.imag;
f64 c = x.value_quaternion.jmag;
f64 d = x.value_quaternion.kmag;
f64 e = y.value_quaternion.real;
f64 f = y.value_quaternion.imag;
f64 g = y.value_quaternion.jmag;
f64 h = y.value_quaternion.kmag;
switch (op) {
case Token_CmpEq: return cmp_f64(a, e) == 0 && cmp_f64(b, f) == 0 && cmp_f64(c, g) == 0 && cmp_f64(d, h) == 0;
case Token_NotEq: return cmp_f64(a, e) != 0 || cmp_f64(b, f) != 0 || cmp_f64(c, g) != 0 || cmp_f64(d, h) != 0;
}
} break;
case ExactValue_String: {
String a = x.value_string;
String b = y.value_string;
+429 -155
View File
File diff suppressed because it is too large Load Diff
+1753 -826
View File
File diff suppressed because it is too large Load Diff
+281 -85
View File
@@ -135,6 +135,28 @@ void ir_print_encoded_global(irFileBuffer *f, String name, bool remove_prefix) {
ir_print_escape_string(f, name, true);
}
void ir_print_type(irFileBuffer *f, irModule *m, Type *t);
void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
GB_ASSERT(is_type_proc(t));
t = base_type(t);
isize result_count = t->Proc.result_count;
if (result_count == 0) {
ir_fprintf(f, "void");
} else if (result_count == 1) {
ir_print_type(f, m, t->Proc.abi_compat_results[0]);
} else {
ir_fprintf(f, "{");
for (isize i = 0; i < result_count; i++) {
if (i > 0) {
ir_fprintf(f, ", ");
}
ir_print_type(f, m, t->Proc.abi_compat_results[i]);
}
ir_fprintf(f, "}");
}
}
void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
i64 word_bits = 8*build_context.word_size;
@@ -145,32 +167,39 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
switch (t->kind) {
case Type_Basic:
switch (t->Basic.kind) {
case Basic_bool: ir_fprintf(f, "i1"); return;
case Basic_i8: ir_fprintf(f, "i8"); return;
case Basic_u8: ir_fprintf(f, "i8"); return;
case Basic_i16: ir_fprintf(f, "i16"); return;
case Basic_u16: ir_fprintf(f, "i16"); return;
case Basic_i32: ir_fprintf(f, "i32"); return;
case Basic_u32: ir_fprintf(f, "i32"); return;
case Basic_i64: ir_fprintf(f, "i64"); return;
case Basic_u64: ir_fprintf(f, "i64"); return;
// case Basic_i128: ir_fprintf(f, "i128"); return;
// case Basic_u128: ir_fprintf(f, "i128"); return;
// case Basic_f16: ir_fprintf(f, "half"); return;
case Basic_f32: ir_fprintf(f, "float"); return;
case Basic_f64: ir_fprintf(f, "double"); return;
// case Basic_f128: ir_fprintf(f, "fp128"); return;
case Basic_rawptr: ir_fprintf(f, "%%..rawptr"); return;
case Basic_string: ir_fprintf(f, "%%..string"); return;
case Basic_uint: ir_fprintf(f, "i%lld", word_bits); return;
case Basic_int: ir_fprintf(f, "i%lld", word_bits); return;
case Basic_any: ir_fprintf(f, "%%..any"); return;
case Basic_bool: ir_fprintf(f, "i1"); return;
case Basic_i8: ir_fprintf(f, "i8"); return;
case Basic_u8: ir_fprintf(f, "i8"); return;
case Basic_i16: ir_fprintf(f, "i16"); return;
case Basic_u16: ir_fprintf(f, "i16"); return;
case Basic_i32: ir_fprintf(f, "i32"); return;
case Basic_u32: ir_fprintf(f, "i32"); return;
case Basic_i64: ir_fprintf(f, "i64"); return;
case Basic_u64: ir_fprintf(f, "i64"); return;
case Basic_f32: ir_fprintf(f, "float"); return;
case Basic_f64: ir_fprintf(f, "double"); return;
case Basic_complex64: ir_fprintf(f, "%%..complex64"); return;
case Basic_complex128: ir_fprintf(f, "%%..complex128"); return;
case Basic_quaternion128: ir_fprintf(f, "%%..quaternion128"); return;
case Basic_quaternion256: ir_fprintf(f, "%%..quaternion256"); return;
case Basic_rawptr: ir_fprintf(f, "%%..rawptr"); return;
case Basic_string: ir_fprintf(f, "%%..string"); return;
case Basic_uint: ir_fprintf(f, "i%lld", word_bits); return;
case Basic_int: ir_fprintf(f, "i%lld", word_bits); return;
case Basic_any: ir_fprintf(f, "%%..any"); return;
}
break;
case Type_Pointer:
ir_print_type(f, m, t->Pointer.elem);
ir_fprintf(f, "*");
return;
case Type_Atomic:
ir_print_type(f, m, t->Atomic.elem);
return;
case Type_Array:
ir_fprintf(f, "[%lld x ", t->Array.count);
ir_print_type(f, m, t->Array.elem);
@@ -227,9 +256,30 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
case TypeRecord_Union: {
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
// LLVM takes the first element's alignment as the entire alignment (like C)
i64 size_of_union = type_size_of(heap_allocator(), t) - build_context.word_size;
i64 align_of_union = type_align_of(heap_allocator(), t);
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align_of_union, size_of_union, word_bits);
i64 align = type_align_of(heap_allocator(), t);
i64 total_size = type_size_of(heap_allocator(), t);
#if 1
i64 fields_size = 0;
if (t->Record.field_count > 0) {
type_set_offsets(m->allocator, t);
isize end_index = t->Record.field_count-1;
i64 end_offset = t->Record.offsets[end_index];
isize end_size = type_size_of(m->allocator, t->Record.fields[end_index]->type);
fields_size = align_formula(end_offset + end_size, build_context.word_size);
}
i64 block_size = total_size - fields_size - build_context.word_size;
ir_fprintf(f, "{[0 x <%lld x i8>], ", align);
for (isize i = 0; i < t->Record.field_count; i++) {
ir_print_type(f, m, t->Record.fields[i]->type);
ir_fprintf(f, ", ");
}
ir_fprintf(f, "[%lld x i8], ", block_size);
ir_fprintf(f, "i%lld}", word_bits);
#else
i64 block_size = total_size - build_context.word_size;
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align, block_size, word_bits);
#endif
} return;
case TypeRecord_RawUnion: {
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
@@ -247,7 +297,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
case Type_Named:
if (is_type_struct(t) || is_type_union(t)) {
String *name = map_string_get(&m->type_names, hash_pointer(t));
String *name = map_string_get(&m->entity_names, hash_pointer(t->Named.type_name));
GB_ASSERT_MSG(name != NULL, "%.*s", LIT(t->Named.name));
ir_print_encoded_local(f, *name);
} else {
@@ -269,18 +319,15 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
}
return;
case Type_Proc: {
if (t->Proc.result_count == 0) {
ir_fprintf(f, "void");
} else {
ir_print_type(f, m, t->Proc.results);
}
isize param_count = t->Proc.param_count;
isize result_count = t->Proc.result_count;
ir_print_proc_results(f, m, t);
ir_fprintf(f, " (");
TypeTuple *params = &t->Proc.params->Tuple;
for (isize i = 0; i < t->Proc.param_count; i++) {
for (isize i = 0; i < param_count; i++) {
if (i > 0) {
ir_fprintf(f, ", ");
}
ir_print_type(f, m, params->variables[i]->type);
ir_print_type(f, m, t->Proc.abi_compat_params[i]);
}
ir_fprintf(f, ")*");
} return;
@@ -306,7 +353,7 @@ void ir_print_compound_element(irFileBuffer *f, irModule *m, ExactValue v, Type
}
void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type) {
type = base_type(base_enum_type(type));
type = core_type(type);
if (is_type_float(type)) {
value = exact_value_to_float(value);
} else if (is_type_integer(type)) {
@@ -334,7 +381,6 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
// HACK NOTE(bill): This is a hack but it works because strings are created at the very end
// of the .ll file
irValue *str_array = ir_add_global_string_array(m, str);
ir_fprintf(f, "{i8* getelementptr inbounds (");
ir_print_type(f, m, str_array->Global.entity->type);
ir_fprintf(f, ", ");
@@ -364,8 +410,8 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
}
} break;
case ExactValue_Float: {
GB_ASSERT(is_type_float(type));
type = base_type(type);
GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
type = core_type(type);
u64 u = *cast(u64*)&value.value_float;
switch (type->Basic.kind) {
case Basic_f32:
@@ -382,28 +428,52 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
switch (type->Basic.kind) {
case 0: break;
#if 0
case Basic_f16:
ir_fprintf(f, "bitcast (");
ir_print_type(f, m, t_u16);
ir_fprintf(f, " %u to ", cast(u16)f32_to_f16(cast(f32)value.value_float));
ir_print_type(f, m, t_f16);
ir_fprintf(f, ")");
break;
case Basic_f128:
ir_fprintf(f, "bitcast (");
ir_fprintf(f, "i128");
// TODO(bill): Actually support f128
ir_fprintf(f, " %llu to ", u);
ir_print_type(f, m, t_f128);
ir_fprintf(f, ")");
break;
#endif
default:
ir_fprintf(f, "0x%016llx", u);
break;
}
} break;
case ExactValue_Complex: {
type = core_type(type);
if (is_type_quaternion(type)) {
Type *ft = base_quaternion_elem_type(type);
ir_fprintf(f, " {"); ir_print_type(f, m, ft); ir_fprintf(f, " ");
ir_print_exact_value(f, m, exact_value_float(value.value_complex.real), ft);
ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " ");
ir_print_exact_value(f, m, exact_value_float(value.value_complex.imag), ft);
ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " ");
ir_print_exact_value(f, m, exact_value_float(0), ft);
ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " ");
ir_print_exact_value(f, m, exact_value_float(0), ft);
ir_fprintf(f, "}");
} else {
GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type));
Type *ft = base_complex_elem_type(type);
ir_fprintf(f, " {"); ir_print_type(f, m, ft); ir_fprintf(f, " ");
ir_print_exact_value(f, m, exact_value_float(value.value_complex.real), ft);
ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " ");
ir_print_exact_value(f, m, exact_value_float(value.value_complex.imag), ft);
ir_fprintf(f, "}");
}
} break;
case ExactValue_Quaternion: {
GB_ASSERT_MSG(is_type_quaternion(type), "%s", type_to_string(type));
type = core_type(type);
Type *ft = base_quaternion_elem_type(type);
ir_fprintf(f, " {"); ir_print_type(f, m, ft); ir_fprintf(f, " ");
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.real), ft);
ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " ");
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.imag), ft);
ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " ");
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.jmag), ft);
ir_fprintf(f, ", "); ir_print_type(f, m, ft); ir_fprintf(f, " ");
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.kmag), ft);
ir_fprintf(f, "}");
} break;
case ExactValue_Pointer:
if (value.value_pointer == 0) {
ir_fprintf(f, "null");
@@ -515,12 +585,15 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
}
} else {
for (isize i = 0; i < value_count; i++) {
TypeAndValue *tav = type_and_value_of_expression(m->info, cl->elems.e[i]);
GB_ASSERT(tav != NULL);
Entity *f = type->Record.fields_in_src_order[i];
values[f->Variable.field_index] = tav->value;
if (str_eq(f->token.string, str_lit("_"))) {
values[f->Variable.field_index] = (ExactValue){0};
} else {
TypeAndValue *tav = type_and_value_of_expression(m->info, cl->elems.e[i]);
GB_ASSERT(tav != NULL);
values[f->Variable.field_index] = tav->value;
}
}
}
@@ -616,6 +689,8 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
ir_print_type(f, m, t_int);
ir_fprintf(f, " 0, i32 0), ");
ir_print_type(f, m, t_int);
ir_fprintf(f, " %lld, ", cs->count);
ir_print_type(f, m, t_int);
ir_fprintf(f, " %lld}", cs->count);
}
} break;
@@ -631,9 +706,10 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
Scope *scope = value->Global.entity->scope;
bool in_global_scope = false;
if (scope != NULL) {
// TODO(bill): Fix this rule. What should it be?
in_global_scope = scope->is_global || scope->is_init;
}
ir_print_encoded_global(f, value->Global.entity->token.string, in_global_scope);
ir_print_encoded_global(f, ir_get_global_name(m, value), in_global_scope);
} break;
case irValue_Param:
ir_print_encoded_local(f, value->Param.entity->token.string);
@@ -681,9 +757,13 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
case irInstr_Local: {
Type *type = instr->Local.entity->type;
i64 align = instr->Local.alignment;
if (align <= 0) {
align = type_align_of(m->allocator, type);
}
ir_fprintf(f, "%%%d = alloca ", value->index);
ir_print_type(f, m, type);
ir_fprintf(f, ", align %lld\n", type_align_of(m->allocator, type));
ir_fprintf(f, ", align %lld\n", align);
} break;
case irInstr_ZeroInit: {
@@ -698,6 +778,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
case irInstr_Store: {
Type *type = type_deref(ir_type(instr->Store.address));
ir_fprintf(f, "store ");
if (instr->Store.atomic) {
ir_fprintf(f, "atomic ");
}
ir_print_type(f, m, type);
ir_fprintf(f, " ");
ir_print_value(f, m, instr->Store.value, type);
@@ -705,17 +788,29 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_print_type(f, m, type);
ir_fprintf(f, "* ");
ir_print_value(f, m, instr->Store.address, type);
if (is_type_atomic(type)) {
// TODO(bill): Do ordering
ir_fprintf(f, " unordered");
ir_fprintf(f, ", align %lld\n", type_align_of(m->allocator, type));
}
ir_fprintf(f, "\n");
} break;
case irInstr_Load: {
Type *type = instr->Load.type;
ir_fprintf(f, "%%%d = load ", value->index);
if (is_type_atomic(type)) {
ir_fprintf(f, "atomic ");
}
ir_print_type(f, m, type);
ir_fprintf(f, ", ");
ir_print_type(f, m, type);
ir_fprintf(f, "* ");
ir_print_value(f, m, instr->Load.address, type);
if (is_type_atomic(type)) {
// TODO(bill): Do ordering
ir_fprintf(f, " unordered");
}
ir_fprintf(f, ", align %lld\n", type_align_of(m->allocator, type));
} break;
@@ -753,6 +848,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
if (st->Record.custom_align > 0) {
index += 1;
}
} else if (is_type_union(st)) {
index += 1;
}
ir_print_type(f, m, type_deref(et));
@@ -821,6 +918,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
if (st->Record.custom_align > 0) {
index += 1;
}
} else if (is_type_union(st)) {
index += 1;
}
@@ -833,6 +932,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
case irInstr_UnionTagPtr: {
Type *et = ir_type(instr->UnionTagPtr.address);
ir_fprintf(f, "%%%d = getelementptr inbounds ", value->index);
Type *t = base_type(type_deref(et));
GB_ASSERT(is_type_union(t));
ir_print_type(f, m, type_deref(et));
ir_fprintf(f, ", ");
@@ -843,7 +944,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_print_type(f, m, t_int);
ir_fprintf(f, " 0, ");
ir_print_type(f, m, t_i32);
#if 1
ir_fprintf(f, " %d", 2 + t->Record.field_count);
#else
ir_fprintf(f, " %d", 2);
#endif
ir_fprintf(f, " ; UnionTagPtr");
ir_fprintf(f, "\n");
} break;
@@ -851,11 +956,19 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
case irInstr_UnionTagValue: {
Type *et = ir_type(instr->UnionTagValue.address);
ir_fprintf(f, "%%%d = extractvalue ", value->index);
Type *t = base_type(et);
GB_ASSERT(is_type_union(t));
ir_print_type(f, m, et);
ir_fprintf(f, " ");
ir_print_value(f, m, instr->UnionTagValue.address, et);
ir_fprintf(f, ", %d", 2);
ir_fprintf(f, ",");
#if 1
ir_fprintf(f, " %d", 2 + t->Record.field_count);
#else
ir_fprintf(f, " %d", 2);
#endif
ir_fprintf(f, ", %d", 2 + t->Record.field_count);
ir_fprintf(f, " ; UnionTagValue");
ir_fprintf(f, "\n");
} break;
@@ -942,7 +1055,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
switch (uo->op) {
case Token_Sub:
if (is_type_float(elem_type)) {
ir_print_exact_value(f, m, make_exact_value_float(0), type);
ir_print_exact_value(f, m, exact_value_float(0), elem_type);
} else {
ir_fprintf(f, "0");
}
@@ -1007,6 +1120,72 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
case Token_LtEq: ir_fprintf(f, "ole"); break;
case Token_GtEq: ir_fprintf(f, "oge"); break;
}
} else if (is_type_complex(elem_type)) {
ir_fprintf(f, "call ");
ir_print_calling_convention(f, m, ProcCC_Odin);
ir_print_type(f, m, t_bool);
char *runtime_proc = "";
i64 sz = 8*type_size_of(m->allocator, elem_type);
switch (sz) {
case 64:
switch (bo->op) {
case Token_CmpEq: runtime_proc = "__complex64_eq"; break;
case Token_NotEq: runtime_proc = "__complex64_ne"; break;
}
break;
case 128:
switch (bo->op) {
case Token_CmpEq: runtime_proc = "__complex128_eq"; break;
case Token_NotEq: runtime_proc = "__complex128_ne"; break;
}
break;
}
ir_fprintf(f, " ");
ir_print_encoded_global(f, make_string_c(runtime_proc), false);
ir_fprintf(f, "(");
ir_print_type(f, m, type);
ir_fprintf(f, " ");
ir_print_value(f, m, bo->left, type);
ir_fprintf(f, ", ");
ir_print_type(f, m, type);
ir_fprintf(f, " ");
ir_print_value(f, m, bo->right, type);
ir_fprintf(f, ")\n");
return;
} else if (is_type_quaternion(elem_type)) {
ir_fprintf(f, "call ");
ir_print_calling_convention(f, m, ProcCC_Odin);
ir_print_type(f, m, t_bool);
char *runtime_proc = "";
i64 sz = 8*type_size_of(m->allocator, elem_type);
switch (sz) {
case 128:
switch (bo->op) {
case Token_CmpEq: runtime_proc = "__quaternion128_eq"; break;
case Token_NotEq: runtime_proc = "__quaternion128_ne"; break;
}
break;
case 256:
switch (bo->op) {
case Token_CmpEq: runtime_proc = "__quaternion256_eq"; break;
case Token_NotEq: runtime_proc = "__quaternion256_ne"; break;
}
break;
}
ir_fprintf(f, " ");
ir_print_encoded_global(f, make_string_c(runtime_proc), false);
ir_fprintf(f, "(");
ir_print_type(f, m, type);
ir_fprintf(f, " ");
ir_print_value(f, m, bo->left, type);
ir_fprintf(f, ", ");
ir_print_type(f, m, type);
ir_fprintf(f, " ");
ir_print_value(f, m, bo->right, type);
ir_fprintf(f, ")\n");
return;
} else {
ir_fprintf(f, "icmp ");
if (bo->op != Token_CmpEq &&
@@ -1082,7 +1261,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, "call ");
ir_print_calling_convention(f, m, proc_type->Proc.calling_convention);
if (result_type) {
ir_print_type(f, m, result_type);
ir_print_proc_results(f, m, proc_type);
} else {
ir_fprintf(f, "void");
}
@@ -1098,7 +1277,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
for (isize i = 0; i < call->arg_count; i++) {
Entity *e = params->variables[i];
GB_ASSERT(e != NULL);
Type *t = e->type;
Type *t = proc_type->Proc.abi_compat_params[i];
if (i > 0) {
ir_fprintf(f, ", ");
}
@@ -1197,17 +1376,17 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, "call void ");
ir_print_encoded_global(f, str_lit("__bounds_check_error"), false);
ir_fprintf(f, "(");
ir_print_compound_element(f, m, make_exact_value_string(bc->pos.file), t_string);
ir_print_compound_element(f, m, exact_value_string(bc->pos.file), t_string);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
ir_fprintf(f, " ");
ir_print_exact_value(f, m, make_exact_value_integer(bc->pos.line), t_int);
ir_print_exact_value(f, m, exact_value_integer(bc->pos.line), t_int);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
ir_fprintf(f, " ");
ir_print_exact_value(f, m, make_exact_value_integer(bc->pos.column), t_int);
ir_print_exact_value(f, m, exact_value_integer(bc->pos.column), t_int);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
@@ -1232,17 +1411,17 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
}
ir_fprintf(f, "(");
ir_print_compound_element(f, m, make_exact_value_string(bc->pos.file), t_string);
ir_print_compound_element(f, m, exact_value_string(bc->pos.file), t_string);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
ir_fprintf(f, " ");
ir_print_exact_value(f, m, make_exact_value_integer(bc->pos.line), t_int);
ir_print_exact_value(f, m, exact_value_integer(bc->pos.line), t_int);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
ir_fprintf(f, " ");
ir_print_exact_value(f, m, make_exact_value_integer(bc->pos.column), t_int);
ir_print_exact_value(f, m, exact_value_integer(bc->pos.column), t_int);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
@@ -1311,31 +1490,39 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
ir_print_calling_convention(f, m, proc_type->calling_convention);
if (proc_type->result_count == 0) {
ir_fprintf(f, "void");
} else {
ir_print_type(f, m, proc_type->results);
}
isize param_count = proc_type->param_count;
isize result_count = proc_type->result_count;
ir_print_proc_results(f, m, proc->type);
ir_fprintf(f, " ");
// #ifndef GB_SYSTEM_WINDOWS
#if 0
if(uses_args)
ir_fprintf(f, "@.nix_argpatch_main");
else
#endif
ir_print_encoded_global(f, proc->name, ir_print_is_proc_global(m, proc));
ir_fprintf(f, "(");
if (proc_type->param_count > 0) {
if (param_count > 0) {
TypeTuple *params = &proc_type->params->Tuple;
for (isize i = 0; i < params->variable_count; i++) {
Entity *e = params->variables[i];
Type *original_type = e->type;
Type *abi_type = proc_type->abi_compat_params[i];
if (i > 0) {
ir_fprintf(f, ", ");
}
ir_print_type(f, m, e->type);
ir_print_type(f, m, abi_type);
if (e->flags&EntityFlag_NoAlias) {
ir_fprintf(f, " noalias");
}
if (proc->body != NULL) {
if (!str_eq(e->token.string, str_lit("")) &&
!str_eq(e->token.string, str_lit("_"))) {
ir_fprintf(f, " %%%.*s", LIT(e->token.string));
ir_fprintf(f, " ");
ir_print_encoded_local(f, e->token.string);
} else {
ir_fprintf(f, " %%_.param_%td", i);
}
@@ -1408,10 +1595,6 @@ void print_llvm_ir(irGen *ir) {
irFileBuffer buf = {0}, *f = &buf;
ir_file_buffer_init(f, &ir->output_file);
if (m->layout.len > 0) {
ir_fprintf(f, "target datalayout = \"%.*s\"\n", LIT(m->layout));
}
ir_print_encoded_local(f, str_lit("..string"));
ir_fprintf(f, " = type {i8*, ");
ir_print_type(f, m, t_int);
@@ -1419,11 +1602,21 @@ void print_llvm_ir(irGen *ir) {
ir_print_encoded_local(f, str_lit("..rawptr"));
ir_fprintf(f, " = type i8* ; Basic_rawptr\n");
ir_print_encoded_local(f, str_lit("..complex64"));
ir_fprintf(f, " = type {float, float} ; Basic_complex64\n");
ir_print_encoded_local(f, str_lit("..complex128"));
ir_fprintf(f, " = type {double, double} ; Basic_complex128\n");
ir_print_encoded_local(f, str_lit("..quaternion128"));
ir_fprintf(f, " = type {float, float, float, float} ; Basic_quaternion128\n");
ir_print_encoded_local(f, str_lit("..quaternion256"));
ir_fprintf(f, " = type {double, double, double, double} ; Basic_quaternion256\n");
ir_print_encoded_local(f, str_lit("..any"));
ir_fprintf(f, " = type {");
ir_print_type(f, m, t_type_info_ptr);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_rawptr);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_type_info_ptr);
ir_fprintf(f, "} ; Basic_any\n");
ir_fprintf(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone \n");
@@ -1476,9 +1669,12 @@ void print_llvm_ir(irGen *ir) {
Scope *scope = g->entity->scope;
bool in_global_scope = false;
if (scope != NULL) {
// TODO(bill): Fix this rule. What should it be?
in_global_scope = scope->is_global || scope->is_init;
// in_global_scope = value->Global.name_is_not_mangled;
}
ir_print_encoded_global(f, g->entity->token.string, in_global_scope);
ir_print_encoded_global(f, ir_get_global_name(m, v), in_global_scope);
ir_fprintf(f, " = ");
if (g->is_foreign) {
ir_fprintf(f, "external ");
+142 -13
View File
@@ -2,15 +2,15 @@
extern "C" {
#endif
#define USE_CUSTOM_BACKEND false
#include "common.c"
#include "timings.c"
#include "build_settings.c"
#include "tokenizer.c"
#include "parser.c"
// #include "printer.c"
#include "checker.c"
// #include "ssa.c"
#include "ssa.c"
#include "ir.c"
#include "ir_opt.c"
#include "ir_print.c"
@@ -102,6 +102,8 @@ i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
// }
// exit_code = status;
return exit_code;
}
#endif
@@ -144,6 +146,7 @@ int main(int argc, char **argv) {
init_scratch_memory(gb_megabytes(10));
init_global_error_collector();
#if 1
init_build_context();
@@ -208,7 +211,7 @@ int main(int argc, char **argv) {
#endif
#if 0
#if USE_CUSTOM_BACKEND
if (global_error_collector.count != 0) {
return 1;
}
@@ -217,7 +220,7 @@ int main(int argc, char **argv) {
return 1;
}
if (!ssa_generate(&checker.info)) {
if (!ssa_generate(&parser, &checker.info)) {
return 1;
}
#else
@@ -241,17 +244,19 @@ int main(int argc, char **argv) {
#if 1
timings_start_section(&timings, str_lit("llvm-opt"));
char const *output_name = ir_gen.output_file.filename;
isize base_name_len = gb_path_extension(output_name)-1 - output_name;
String output = make_string(cast(u8 *)output_name, base_name_len);
String output_name = ir_gen.output_name;
String output_base = ir_gen.output_base;
int base_name_len = output_base.len;
i32 optimization_level = 0;
optimization_level = gb_clamp(optimization_level, 0, 3);
i32 exit_code = 0;
#if defined(GB_SYSTEM_WINDOWS)
// For more passes arguments: http://llvm.org/docs/Passes.html
exit_code = system_exec_command_line_app("llvm-opt", false,
"\"%.*sbin/opt\" \"%s\" -o \"%.*s\".bc "
"\"%.*sbin/opt\" \"%.*s\".ll -o \"%.*s\".bc "
"-mem2reg "
"-memcpyopt "
"-die "
@@ -260,10 +265,33 @@ int main(int argc, char **argv) {
// "-S "
"",
LIT(build_context.ODIN_ROOT),
output_name, LIT(output));
LIT(output_base), LIT(output_base));
if (exit_code != 0) {
return exit_code;
}
#else
// NOTE(zangent): This is separate because it seems that LLVM tools are packaged
// with the Windows version, while they will be system-provided on MacOS and GNU/Linux
exit_code = system_exec_command_line_app("llvm-opt", false,
"opt \"%.*s\".ll -o \"%.*s\".bc "
"-mem2reg "
"-memcpyopt "
"-die "
#if defined(GB_SYSTEM_OSX)
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
// make sure to also change the `macosx_version_min` param passed to `llc`
"-mtriple=x86_64-apple-macosx10.8 "
#endif
// "-dse "
// "-dce "
// "-S "
"",
LIT(output_base), LIT(output_base));
if (exit_code != 0) {
return exit_code;
}
#endif
#if defined(GB_SYSTEM_WINDOWS)
timings_start_section(&timings, str_lit("llvm-llc"));
@@ -274,7 +302,7 @@ int main(int argc, char **argv) {
// "-debug-pass=Arguments "
"",
LIT(build_context.ODIN_ROOT),
LIT(output),
LIT(output_base),
optimization_level,
LIT(build_context.llc_flags));
if (exit_code != 0) {
@@ -310,7 +338,7 @@ int main(int argc, char **argv) {
" %.*s "
" %s "
"",
LIT(output), LIT(output), output_ext,
LIT(output_base), LIT(output_base), output_ext,
lib_str, LIT(build_context.link_flags),
link_settings
);
@@ -321,11 +349,112 @@ int main(int argc, char **argv) {
// timings_print_all(&timings);
if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s.exe", cast(int)base_name_len, output_name);
system_exec_command_line_app("odin run", false, "%.*s.exe", LIT(output_base));
}
#else
#error Implement build stuff for this platform
// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
timings_start_section(&timings, str_lit("llvm-llc"));
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
exit_code = system_exec_command_line_app("llc", false,
"llc \"%.*s.bc\" -filetype=obj -O%d "
"%.*s "
// "-debug-pass=Arguments "
"",
LIT(output_base),
optimization_level,
LIT(build_context.llc_flags));
if (exit_code != 0) {
return exit_code;
}
timings_start_section(&timings, str_lit("ld-link"));
gbString lib_str = gb_string_make(heap_allocator(), "");
// defer (gb_string_free(lib_str));
char lib_str_buf[1024] = {0};
for_array(i, ir_gen.module.foreign_library_paths) {
String lib = ir_gen.module.foreign_library_paths.e[i];
// NOTE(zangent): Sometimes, you have to use -framework on MacOS.
// This allows you to specify '-f' in a #foreign_system_library,
// without having to implement any new syntax specifically for MacOS.
#if defined(GB_SYSTEM_OSX)
isize len;
if(lib.len > 2 && lib.text[0] == '-' && lib.text[1] == 'f') {
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
} else {
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" -l%.*s ", LIT(lib));
}
#else
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
" -l%.*s ", LIT(lib));
#endif
lib_str = gb_string_appendc(lib_str, lib_str_buf);
}
// Unlike the Win32 linker code, the output_ext includes the dot, because
// typically executable files on *NIX systems don't have extensions.
char *output_ext = "";
char *link_settings = "";
char *linker;
if (build_context.is_dll) {
// Shared libraries are .dylib on MacOS and .so on Linux.
// TODO(zangent): Is that statement entirely truthful?
#if defined(GB_SYSTEM_OSX)
output_ext = ".dylib";
#else
output_ext = ".so";
#endif
link_settings = "-shared";
} else {
// TODO: Do I need anything here?
link_settings = "";
}
#if defined(GB_SYSTEM_OSX)
linker = "ld";
#else
// TODO(zangent): Figure out how to make ld work on Linux.
// It probably has to do with including the entire CRT, but
// that's quite a complicated issue to solve while remaining distro-agnostic.
// Clang can figure out linker flags for us, and that's good enough _for now_.
linker = "clang -Wno-unused-command-line-argument";
#endif
exit_code = system_exec_command_line_app("ld-link", true,
"%s \"%.*s\".o -o \"%.*s%s\" %s "
"-lc -lm "
" %.*s "
" %s "
#if defined(GB_SYSTEM_OSX)
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
// make sure to also change the `mtriple` param passed to `opt`
" -macosx_version_min 10.8.0 "
// This points the linker to where the entry point is
" -e _main "
#endif
, linker, LIT(output_base), LIT(output_base), output_ext,
lib_str, LIT(build_context.link_flags),
link_settings
);
if (exit_code != 0) {
return exit_code;
}
// timings_print_all(&timings);
if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base));
}
#endif
#endif
#endif
+287 -198
View File
@@ -17,6 +17,8 @@ typedef enum ParseFileError {
typedef Array(AstNode *) AstNodeArray;
gb_global i32 global_file_id = 0;
typedef struct AstFile {
i32 id;
gbArena arena;
@@ -30,6 +32,8 @@ typedef struct AstFile {
// < 0: In Control Clause
// NOTE(bill): Used to prevent type literals in control clauses
isize expr_level;
bool allow_range;
bool ignore_operand;
AstNodeArray decls;
bool is_global_scope;
@@ -65,6 +69,8 @@ typedef enum ProcTag {
ProcTag_bounds_check = 1<<0,
ProcTag_no_bounds_check = 1<<1,
ProcTag_require_results = 1<<4,
ProcTag_foreign = 1<<10,
ProcTag_export = 1<<11,
ProcTag_link_name = 1<<12,
@@ -103,6 +109,7 @@ typedef enum FieldFlag {
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_immutable,
} FieldListTag;
AstNodeArray make_ast_node_array(AstFile *f) {
AstNodeArray a;
// array_init(&a, gb_arena_allocator(&f->arena));
@@ -139,6 +146,10 @@ AstNodeArray make_ast_node_array(AstFile *f) {
AstNodeArray elems; \
Token open, close; \
}) \
AST_NODE_KIND(Alias, "alias", struct { \
Token token; \
AstNode *expr; \
}) \
AST_NODE_KIND(_ExprBegin, "", i32) \
AST_NODE_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \
AST_NODE_KIND(TagExpr, "tag expression", struct { Token token, name; AstNode *expr; }) \
@@ -149,9 +160,11 @@ AST_NODE_KIND(_ExprBegin, "", i32) \
AST_NODE_KIND(SelectorExpr, "selector expression", struct { Token token; AstNode *expr, *selector; }) \
AST_NODE_KIND(IndexExpr, "index expression", struct { AstNode *expr, *index; Token open, close; }) \
AST_NODE_KIND(DerefExpr, "dereference expression", struct { Token op; AstNode *expr; }) \
AST_NODE_KIND(SliceExpr, "slice expression", struct { \
AST_NODE_KIND(SliceExpr, "slice expression", struct { \
AstNode *expr; \
Token open, close; \
Token interval0; \
Token interval1; \
bool index3; \
AstNode *low, *high, *max; \
}) \
@@ -169,10 +182,9 @@ AST_NODE_KIND(_ExprBegin, "", i32) \
Token open; \
Token close; \
}) \
AST_NODE_KIND(CastExpr, "cast expression", struct { Token token; AstNode *type, *expr; Token open, close; }) \
AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
AST_NODE_KIND(TernaryExpr, "ternary expression", struct { AstNode *cond, *x, *y; }) \
AST_NODE_KIND(IntervalExpr, "interval expression", struct { Token op; AstNode *left, *right; }) \
AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
AST_NODE_KIND(TernaryExpr, "ternary expression", struct { AstNode *cond, *x, *y; }) \
AST_NODE_KIND(TypeAssertion, "type assertion", struct { AstNode *expr; Token dot; AstNode *type; }) \
AST_NODE_KIND(_ExprEnd, "", i32) \
AST_NODE_KIND(_StmtBegin, "", i32) \
AST_NODE_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \
@@ -215,6 +227,7 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
}) \
AST_NODE_KIND(ForStmt, "for statement", struct { \
Token token; \
AstNode *label; \
AstNode *init; \
AstNode *cond; \
AstNode *post; \
@@ -222,6 +235,7 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
}) \
AST_NODE_KIND(RangeStmt, "range statement", struct { \
Token token; \
AstNode *label; \
AstNode *value; \
AstNode *index; \
Token in_token; \
@@ -235,20 +249,22 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
}) \
AST_NODE_KIND(MatchStmt, "match statement", struct { \
Token token; \
AstNode *label; \
AstNode *init; \
AstNode *tag; \
AstNode *body; \
}) \
AST_NODE_KIND(TypeMatchStmt, "type match statement", struct { \
Token token; \
AstNode *label; \
AstNode *tag; \
AstNode *body; \
}) \
AST_NODE_KIND(DeferStmt, "defer statement", struct { Token token; AstNode *stmt; }) \
AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; }) \
AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; AstNode *label; }) \
AST_NODE_KIND(UsingStmt, "using statement", struct { \
Token token; \
AstNode *node; \
AstNodeArray list; \
}) \
AST_NODE_KIND(AsmOperand, "assembly operand", struct { \
Token string; \
@@ -301,6 +317,10 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
AstNode *cond; \
bool is_system; \
}) \
AST_NODE_KIND(Label, "label", struct { \
Token token; \
AstNode *name; \
}) \
AST_NODE_KIND(_DeclEnd, "", i32) \
AST_NODE_KIND(Field, "field", struct { \
AstNodeArray names; \
@@ -331,6 +351,10 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
Token token; \
AstNode *type; \
}) \
AST_NODE_KIND(AtomicType, "atomic type", struct { \
Token token; \
AstNode *type; \
}) \
AST_NODE_KIND(ArrayType, "array type", struct { \
Token token; \
AstNode *count; \
@@ -398,7 +422,6 @@ String const ast_node_strings[] = {
typedef struct AstNode {
AstNodeKind kind;
// AstNode *prev, *next; // NOTE(bill): allow for Linked list
u32 stmt_state_flags;
union {
#define AST_NODE_KIND(_kind_name_, name, ...) GB_JOIN2(AstNode, _kind_name_) _kind_name_;
@@ -410,7 +433,9 @@ typedef struct AstNode {
#define ast_node(n_, Kind_, node_) GB_JOIN2(AstNode, Kind_) *n_ = &(node_)->Kind_; GB_ASSERT((node_)->kind == GB_JOIN2(AstNode_, Kind_))
#define case_ast_node(n_, Kind_, node_) case GB_JOIN2(AstNode_, Kind_): { ast_node(n_, Kind_, node_);
#ifndef case_end
#define case_end } break;
#endif
gb_inline bool is_ast_node_expr(AstNode *node) {
@@ -445,6 +470,8 @@ Token ast_node_token(AstNode *node) {
return ast_node_token(node->CompoundLit.type);
}
return node->CompoundLit.open;
case AstNode_Alias: return node->Alias.token;
case AstNode_TagExpr: return node->TagExpr.token;
case AstNode_RunExpr: return node->RunExpr.token;
case AstNode_BadExpr: return node->BadExpr.begin;
@@ -458,14 +485,13 @@ Token ast_node_token(AstNode *node) {
return ast_node_token(node->SelectorExpr.selector);
}
return node->SelectorExpr.token;
case AstNode_IndexExpr: return node->IndexExpr.open;
case AstNode_SliceExpr: return node->SliceExpr.open;
case AstNode_Ellipsis: return node->Ellipsis.token;
case AstNode_CastExpr: return node->CastExpr.token;
case AstNode_FieldValue: return node->FieldValue.eq;
case AstNode_DerefExpr: return node->DerefExpr.op;
case AstNode_TernaryExpr: return ast_node_token(node->TernaryExpr.cond);
case AstNode_IntervalExpr: return ast_node_token(node->IntervalExpr.left);
case AstNode_IndexExpr: return node->IndexExpr.open;
case AstNode_SliceExpr: return node->SliceExpr.open;
case AstNode_Ellipsis: return node->Ellipsis.token;
case AstNode_FieldValue: return node->FieldValue.eq;
case AstNode_DerefExpr: return node->DerefExpr.op;
case AstNode_TernaryExpr: return ast_node_token(node->TernaryExpr.cond);
case AstNode_TypeAssertion: return ast_node_token(node->TypeAssertion.expr);
case AstNode_BadStmt: return node->BadStmt.begin;
case AstNode_EmptyStmt: return node->EmptyStmt.token;
@@ -492,6 +518,7 @@ Token ast_node_token(AstNode *node) {
case AstNode_ValueDecl: return ast_node_token(node->ValueDecl.names.e[0]);
case AstNode_ImportDecl: return node->ImportDecl.token;
case AstNode_ForeignLibrary: return node->ForeignLibrary.token;
case AstNode_Label: return node->Label.token;
case AstNode_Field:
@@ -507,6 +534,7 @@ Token ast_node_token(AstNode *node) {
case AstNode_HelperType: return node->HelperType.token;
case AstNode_ProcType: return node->ProcType.token;
case AstNode_PointerType: return node->PointerType.token;
case AstNode_AtomicType: return node->AtomicType.token;
case AstNode_ArrayType: return node->ArrayType.token;
case AstNode_DynamicArrayType: return node->DynamicArrayType.token;
case AstNode_VectorType: return node->VectorType.token;
@@ -668,11 +696,13 @@ AstNode *ast_index_expr(AstFile *f, AstNode *expr, AstNode *index, Token open, T
}
AstNode *ast_slice_expr(AstFile *f, AstNode *expr, Token open, Token close, bool index3, AstNode *low, AstNode *high, AstNode *max) {
AstNode *ast_slice_expr(AstFile *f, AstNode *expr, Token open, Token close, Token interval0, Token interval1, bool index3, AstNode *low, AstNode *high, AstNode *max) {
AstNode *result = make_ast_node(f, AstNode_SliceExpr);
result->SliceExpr.expr = expr;
result->SliceExpr.open = open;
result->SliceExpr.close = close;
result->SliceExpr.interval0 = interval0;
result->SliceExpr.interval1 = interval1;
result->SliceExpr.index3 = index3;
result->SliceExpr.low = low;
result->SliceExpr.high = high;
@@ -687,16 +717,6 @@ AstNode *ast_deref_expr(AstFile *f, AstNode *expr, Token op) {
return result;
}
AstNode *ast_interval_expr(AstFile *f, Token op, AstNode *left, AstNode *right) {
AstNode *result = make_ast_node(f, AstNode_IntervalExpr);
result->IntervalExpr.op = op;
result->IntervalExpr.left = left;
result->IntervalExpr.right = right;
return result;
}
@@ -753,16 +773,6 @@ AstNode *ast_field_value(AstFile *f, AstNode *field, AstNode *value, Token eq) {
return result;
}
AstNode *ast_cast_expr(AstFile *f, Token token, AstNode *type, AstNode *expr, Token open, Token close) {
AstNode *result = make_ast_node(f, AstNode_CastExpr);
result->CastExpr.token = token;
result->CastExpr.type = type;
result->CastExpr.expr = expr;
result->CastExpr.open = open;
result->CastExpr.close = close;
return result;
}
AstNode *ast_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token open, Token close) {
AstNode *result = make_ast_node(f, AstNode_CompoundLit);
result->CompoundLit.type = type;
@@ -771,6 +781,13 @@ AstNode *ast_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token o
result->CompoundLit.close = close;
return result;
}
AstNode *ast_alias(AstFile *f, Token token, AstNode *expr) {
AstNode *result = make_ast_node(f, AstNode_Alias);
result->Alias.token = token;
result->Alias.expr = expr;
return result;
}
AstNode *ast_ternary_expr(AstFile *f, AstNode *cond, AstNode *x, AstNode *y) {
AstNode *result = make_ast_node(f, AstNode_TernaryExpr);
@@ -779,6 +796,14 @@ AstNode *ast_ternary_expr(AstFile *f, AstNode *cond, AstNode *x, AstNode *y) {
result->TernaryExpr.y = y;
return result;
}
AstNode *ast_type_assertion(AstFile *f, AstNode *expr, Token dot, AstNode *type) {
AstNode *result = make_ast_node(f, AstNode_TypeAssertion);
result->TypeAssertion.expr = expr;
result->TypeAssertion.dot = dot;
result->TypeAssertion.type = type;
return result;
}
@@ -910,19 +935,21 @@ AstNode *ast_defer_stmt(AstFile *f, Token token, AstNode *stmt) {
return result;
}
AstNode *ast_branch_stmt(AstFile *f, Token token) {
AstNode *ast_branch_stmt(AstFile *f, Token token, AstNode *label) {
AstNode *result = make_ast_node(f, AstNode_BranchStmt);
result->BranchStmt.token = token;
result->BranchStmt.label = label;
return result;
}
AstNode *ast_using_stmt(AstFile *f, Token token, AstNode *node) {
AstNode *ast_using_stmt(AstFile *f, Token token, AstNodeArray list) {
AstNode *result = make_ast_node(f, AstNode_UsingStmt);
result->UsingStmt.token = token;
result->UsingStmt.node = node;
result->UsingStmt.list = list;
return result;
}
AstNode *ast_asm_operand(AstFile *f, Token string, AstNode *operand) {
AstNode *result = make_ast_node(f, AstNode_AsmOperand);
result->AsmOperand.string = string;
@@ -1022,6 +1049,13 @@ AstNode *ast_pointer_type(AstFile *f, Token token, AstNode *type) {
return result;
}
AstNode *ast_atomic_type(AstFile *f, Token token, AstNode *type) {
AstNode *result = make_ast_node(f, AstNode_AtomicType);
result->AtomicType.token = token;
result->AtomicType.type = type;
return result;
}
AstNode *ast_array_type(AstFile *f, Token token, AstNode *count, AstNode *elem) {
AstNode *result = make_ast_node(f, AstNode_ArrayType);
result->ArrayType.token = token;
@@ -1124,6 +1158,13 @@ AstNode *ast_foreign_library(AstFile *f, Token token, Token filepath, Token libr
return result;
}
AstNode *ast_label_decl(AstFile *f, Token token, AstNode *name) {
AstNode *result = make_ast_node(f, AstNode_Label);
result->Label.token = token;
result->Label.name = name;
return result;
}
bool next_token(AstFile *f) {
Token prev = f->curr_token;
@@ -1165,7 +1206,11 @@ Token expect_token(AstFile *f, TokenKind kind) {
syntax_error(f->curr_token, "Expected `%.*s`, got `%.*s`",
LIT(token_strings[kind]),
LIT(token_strings[prev.kind]));
if (prev.kind == Token_EOF) {
gb_exit(1);
}
}
next_token(f);
return prev;
}
@@ -1189,6 +1234,9 @@ Token expect_operator(AstFile *f) {
if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) {
syntax_error(f->curr_token, "Expected an operator, got `%.*s`",
LIT(token_strings[prev.kind]));
} else if (!f->allow_range && (prev.kind == Token_Ellipsis || prev.kind == Token_HalfClosed)) {
syntax_error(f->curr_token, "Expected an non-range operator, got `%.*s`",
LIT(token_strings[prev.kind]));
}
next_token(f);
return prev;
@@ -1293,6 +1341,9 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) {
case AstNode_PointerType:
return is_semicolon_optional_for_node(f, s->PointerType.type);
case AstNode_AtomicType:
return is_semicolon_optional_for_node(f, s->AtomicType.type);
case AstNode_StructType:
case AstNode_UnionType:
case AstNode_RawUnionType:
@@ -1534,6 +1585,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, AstNode **foreign_library_token, Str
expect_token(f, Token_String);
}
}
ELSE_IF_ADD_TAG(require_results)
ELSE_IF_ADD_TAG(export)
ELSE_IF_ADD_TAG(bounds_check)
ELSE_IF_ADD_TAG(no_bounds_check)
@@ -1692,17 +1744,14 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
AstNode *operand = NULL; // Operand
switch (f->curr_token.kind) {
case Token_Ident:
operand = parse_ident(f);
if (!lhs) {
// TODO(bill): Handle?
}
return operand;
return parse_ident(f);
case Token_context:
return ast_implicit(f, expect_token(f, Token_context));
case Token_Integer:
case Token_Float:
case Token_Imag:
case Token_Rune:
operand = ast_basic_lit(f, f->curr_token);
next_token(f);
@@ -1762,6 +1811,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
} else if (str_eq(name.string, str_lit("line"))) { return ast_basic_directive(f, token, name.string);
} else if (str_eq(name.string, str_lit("procedure"))) { return ast_basic_directive(f, token, name.string);
} else if (str_eq(name.string, str_lit("type"))) { return ast_helper_type(f, token, parse_type(f));
} else if (!lhs && str_eq(name.string, str_lit("alias"))) { return ast_alias(f, token, parse_expr(f, false));
} else {
operand = ast_tag_expr(f, token, name, parse_expr(f, false));
}
@@ -1800,17 +1850,6 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
return type;
}
// case Token_if:
// if (!lhs && f->expr_level >= 0) {
// return parse_if_expr(f);
// }
// break;
// case Token_OpenBrace:
// if (!lhs && f->expr_level >= 0) {
// return parse_block_expr(f);
// }
// break;
default: {
AstNode *type = parse_type_or_ident(f);
if (type != NULL) {
@@ -1824,10 +1863,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
}
}
Token begin = f->curr_token;
syntax_error(begin, "Expected an operand");
fix_advance_to_next_stmt(f);
return ast_bad_expr(f, begin, f->curr_token);
return NULL;
}
bool is_literal_type(AstNode *node) {
@@ -1912,6 +1948,12 @@ AstNode *parse_macro_call_expr(AstFile *f, AstNode *operand) {
AstNode *parse_atom_expr(AstFile *f, bool lhs) {
AstNode *operand = parse_operand(f, lhs);
if (operand == NULL) {
Token begin = f->curr_token;
syntax_error(begin, "Expected an operand");
fix_advance_to_next_stmt(f);
operand = ast_bad_expr(f, begin, f->curr_token);
}
bool loop = true;
while (loop) {
@@ -1933,6 +1975,13 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
// case Token_Integer:
// operand = ast_selector_expr(f, token, operand, parse_expr(f, lhs));
// break;
case Token_OpenParen: {
Token open = expect_token(f, Token_OpenParen);
AstNode *type = parse_type(f);
Token close = expect_token(f, Token_CloseParen);
operand = ast_type_assertion(f, operand, token, type);
} break;
default:
syntax_error(f->curr_token, "Expected a selector");
next_token(f);
@@ -1946,6 +1995,9 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
if (lhs) {
// TODO(bill): Handle this
}
bool prev_allow_range = f->allow_range;
f->allow_range = false;
Token open = {0}, close = {0}, interval = {0};
AstNode *indices[3] = {0};
isize ellipsis_count = 0;
@@ -1954,15 +2006,19 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
f->expr_level++;
open = expect_token(f, Token_OpenBracket);
if (f->curr_token.kind != Token_Ellipsis) {
if (f->curr_token.kind != Token_Ellipsis &&
f->curr_token.kind != Token_HalfClosed) {
indices[0] = parse_expr(f, false);
}
bool is_index = true;
while (f->curr_token.kind == Token_Ellipsis && ellipsis_count < gb_count_of(ellipses)) {
while ((f->curr_token.kind == Token_Ellipsis ||
f->curr_token.kind == Token_HalfClosed)
&& ellipsis_count < gb_count_of(ellipses)) {
ellipses[ellipsis_count++] = f->curr_token;
next_token(f);
if (f->curr_token.kind != Token_Ellipsis &&
f->curr_token.kind != Token_HalfClosed &&
f->curr_token.kind != Token_CloseBracket &&
f->curr_token.kind != Token_EOF) {
indices[ellipsis_count] = parse_expr(f, false);
@@ -1987,10 +2043,12 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
indices[2] = ast_bad_expr(f, ellipses[1], close);
}
}
operand = ast_slice_expr(f, operand, open, close, index3, indices[0], indices[1], indices[2]);
operand = ast_slice_expr(f, operand, open, close, ellipses[0], ellipses[1], index3, indices[0], indices[1], indices[2]);
} else {
operand = ast_index_expr(f, operand, indices[0], open, close);
}
f->allow_range = prev_allow_range;
} break;
case Token_Pointer: // Deference
@@ -2020,33 +2078,33 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
AstNode *parse_unary_expr(AstFile *f, bool lhs) {
switch (f->curr_token.kind) {
case Token_cast:
case Token_transmute:
case Token_down_cast:
case Token_union_cast:
{
Token token = f->curr_token; next_token(f);
Token open = expect_token(f, Token_OpenParen);
AstNode *type = parse_type(f);
Token close = expect_token(f, Token_CloseParen);
AstNode *expr = parse_unary_expr(f, lhs);
return ast_cast_expr(f, token, type, expr, open, close);
} break;
// case Token_cast:
// case Token_transmute:
// case Token_union_cast:
// {
// Token token = f->curr_token; next_token(f);
// Token open = expect_token(f, Token_OpenParen);
// AstNode *type = parse_type(f);
// Token close = expect_token(f, Token_CloseParen);
// AstNode *expr = parse_unary_expr(f, lhs);
// return ast_cast_expr(f, token, type, expr, open, close);
// } break;
// case Token_Pointer: {
// Token op = f->curr_token;
// next_token(f);
// AstNode *expr = parse_unary_expr(f, lhs);
// if (is_ast_node_type(expr)) {
// return ast_pointer_type(f, op, expr);
// }
// return ast_unary_expr(f, op, expr);
// } break;
case Token_Pointer: {
Token op = f->curr_token;
next_token(f);
AstNode *expr = parse_unary_expr(f, lhs);
if (is_ast_node_type(expr)) {
return ast_pointer_type(f, op, expr);
}
return ast_unary_expr(f, op, expr);
} break;
// case Token_Maybe:
case Token_Add:
case Token_Sub:
case Token_Not:
case Token_Xor: {
case Token_Xor:
case Token_And: {
Token op = f->curr_token;
next_token(f);
return ast_unary_expr(f, op, parse_unary_expr(f, lhs));
@@ -2056,27 +2114,49 @@ AstNode *parse_unary_expr(AstFile *f, bool lhs) {
return parse_atom_expr(f, lhs);
}
bool is_ast_node_a_range(AstNode *expr) {
if (expr == NULL) {
return false;
}
if (expr->kind != AstNode_BinaryExpr) {
return false;
}
TokenKind op = expr->BinaryExpr.op.kind;
switch (op) {
case Token_Ellipsis:
case Token_HalfClosed:
return true;
}
return false;
}
// NOTE(bill): result == priority
i32 token_precedence(TokenKind t) {
i32 token_precedence(AstFile *f, TokenKind t) {
switch (t) {
case Token_Question:
return 1;
case Token_Ellipsis:
case Token_HalfClosed:
if (f->allow_range) {
return 2;
}
return 0;
case Token_CmpOr:
return 2;
case Token_CmpAnd:
return 3;
case Token_CmpAnd:
return 4;
case Token_CmpEq:
case Token_NotEq:
case Token_Lt:
case Token_Gt:
case Token_LtEq:
case Token_GtEq:
return 4;
return 5;
case Token_Add:
case Token_Sub:
case Token_Or:
case Token_Xor:
return 5;
return 6;
case Token_Mul:
case Token_Quo:
case Token_Mod:
@@ -2084,17 +2164,17 @@ i32 token_precedence(TokenKind t) {
case Token_AndNot:
case Token_Shl:
case Token_Shr:
return 6;
return 7;
}
return 0;
}
AstNode *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
AstNode *expr = parse_unary_expr(f, lhs);
for (i32 prec = token_precedence(f->curr_token.kind); prec >= prec_in; prec--) {
for (i32 prec = token_precedence(f, f->curr_token.kind); prec >= prec_in; prec--) {
for (;;) {
Token op = f->curr_token;
i32 op_prec = token_precedence(op.kind);
i32 op_prec = token_precedence(f, op.kind);
if (op_prec != prec) {
// NOTE(bill): This will also catch operators that are not valid "binary" operators
break;
@@ -2110,7 +2190,7 @@ AstNode *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
expr = ast_ternary_expr(f, cond, x, y);
} else {
AstNode *right = parse_binary_expr(f, false, prec+1);
if (!right) {
if (right == NULL) {
syntax_error(op, "Expected expression on the right-hand side of the binary operator");
}
expr = ast_binary_expr(f, op, expr, right);
@@ -2129,7 +2209,7 @@ AstNode *parse_expr(AstFile *f, bool lhs) {
AstNodeArray parse_expr_list(AstFile *f, bool lhs) {
AstNodeArray list = make_ast_node_array(f);
do {
for (;;) {
AstNode *e = parse_expr(f, lhs);
array_add(&list, e);
if (f->curr_token.kind != Token_Comma ||
@@ -2137,7 +2217,7 @@ AstNodeArray parse_expr_list(AstFile *f, bool lhs) {
break;
}
next_token(f);
} while (true);
}
return list;
}
@@ -2238,6 +2318,7 @@ AstNode *parse_value_decl(AstFile *f, AstNodeArray lhs) {
}
AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) {
AstNodeArray lhs = parse_lhs_expr_list(f);
Token token = f->curr_token;
@@ -2273,15 +2354,10 @@ AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) {
case Token_in:
if (in_stmt_ok) {
allow_token(f, Token_in);
bool prev_allow_range = f->allow_range;
f->allow_range = true;
AstNode *expr = parse_expr(f, false);
switch (f->curr_token.kind) {
case Token_Ellipsis: {
Token op = f->curr_token;
next_token(f);
AstNode *right = parse_expr(f, false);
expr = ast_interval_expr(f, op, expr, right);
} break;
}
f->allow_range = prev_allow_range;
AstNodeArray rhs = {0};
array_init_count(&rhs, heap_allocator(), 1);
@@ -2320,7 +2396,7 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) {
return parse_body(f);
}
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow);
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow);
AstNode *parse_results(AstFile *f) {
@@ -2339,7 +2415,7 @@ AstNode *parse_results(AstFile *f) {
AstNode *list = NULL;
expect_token(f, Token_OpenParen);
list = parse_field_list(f, NULL, 0, Token_Comma, Token_CloseParen);
list = parse_field_list(f, NULL, 0, Token_CloseParen);
expect_token_after(f, Token_CloseParen, "parameter list");
return list;
}
@@ -2350,7 +2426,7 @@ AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign
Token proc_token = expect_token(f, Token_proc);
expect_token(f, Token_OpenParen);
params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen);
params = parse_field_list(f, NULL, FieldFlag_Signature, Token_CloseParen);
expect_token_after(f, Token_CloseParen, "parameter list");
results = parse_results(f);
@@ -2369,17 +2445,6 @@ AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign
return ast_proc_type(f, proc_token, params, results, tags, cc);
}
bool parse_expect_separator(AstFile *f, TokenKind separator, AstNode *param) {
if (separator == Token_Semicolon) {
expect_semicolon(f, param);
} else {
if (!allow_token(f, separator)) {
return true;
}
}
return false;
}
AstNode *parse_var_type(AstFile *f, bool allow_ellipsis) {
if (allow_ellipsis && f->curr_token.kind == Token_Ellipsis) {
Token tok = f->curr_token;
@@ -2490,7 +2555,22 @@ AstNodeArray convert_to_ident_list(AstFile *f, AstNodeAndFlagsArray list, bool i
return idents;
}
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow) {
bool parse_expect_field_separator(AstFile *f, AstNode *param) {
Token token = f->curr_token;
if (allow_token(f, Token_Comma)) {
return true;
}
if (token.kind == Token_Semicolon) {
next_token(f);
error(f->curr_token, "Expected a comma, got a semicolon");
return true;
}
return false;
}
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow) {
TokenKind separator = Token_Comma;
Token start_token = f->curr_token;
AstNodeArray params = make_ast_node_array(f);
@@ -2528,7 +2608,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
AstNode *param = ast_field(f, names, type, set_flags);
array_add(&params, param);
parse_expect_separator(f, separator, type);
parse_expect_field_separator(f, type);
while (f->curr_token.kind != follow &&
f->curr_token.kind != Token_EOF) {
@@ -2546,7 +2626,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
AstNode *param = ast_field(f, names, type, set_flags);
array_add(&params, param);
if (parse_expect_separator(f, separator, param)) {
if (!parse_expect_field_separator(f, param)) {
break;
}
}
@@ -2575,7 +2655,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
return parse_field_list(f, field_count_, flags, Token_Comma, Token_CloseBrace);
return parse_field_list(f, field_count_, flags, Token_CloseBrace);
}
AstNode *parse_type_or_ident(AstFile *f) {
@@ -2589,10 +2669,11 @@ AstNode *parse_type_or_ident(AstFile *f) {
AstNode *sel = parse_ident(f);
e = ast_selector_expr(f, token, e, sel);
}
if (f->curr_token.kind == Token_OpenParen) {
// TODO(bill): Merge type_or_ident into the general parsing for expressions
// if (f->curr_token.kind == Token_OpenParen) {
// HACK NOTE(bill): For type_of_val(expr) et al.
e = parse_call_expr(f, e);
}
// e = parse_call_expr(f, e);
// }
return e;
}
@@ -2614,6 +2695,12 @@ AstNode *parse_type_or_ident(AstFile *f) {
return ast_pointer_type(f, token, elem);
}
case Token_atomic: {
Token token = expect_token(f, Token_atomic);
AstNode *elem = parse_type(f);
return ast_atomic_type(f, token, elem);
}
case Token_OpenBracket: {
Token token = expect_token(f, Token_OpenBracket);
AstNode *count_expr = NULL;
@@ -3041,46 +3128,6 @@ AstNode *parse_for_stmt(AstFile *f) {
cond = convert_stmt_to_expr(f, cond, str_lit("boolean expression"));
return ast_for_stmt(f, token, init, cond, post, body);
#if 0
Token token = expect_token(f, Token_for);
AstNodeArray names = parse_ident_list(f);
parse_check_name_list_for_reserves(f, names);
Token colon = expect_token_after(f, Token_in, "for name list");
isize prev_level = f->expr_level;
f->expr_level = -1;
AstNode *expr = parse_expr(f, false);
switch (f->curr_token.kind) {
case Token_HalfOpenRange:
case Token_Ellipsis: {
Token op = f->curr_token;
next_token(f);
AstNode *right = parse_expr(f, false);
expr = ast_interval_expr(f, op, expr, right);
} break;
}
f->expr_level = prev_level;
AstNode *value = NULL;
AstNode *index = NULL;
AstNode *body = parse_block_stmt(f, false);
switch (names.count) {
case 1:
value = names.e[0];
break;
case 2:
value = names.e[0];
index = names.e[1];
break;
default:
error(token, "Expected at 1 or 2 identifiers");
return ast_bad_stmt(f, token, f->curr_token);
}
return ast_range_stmt(f, token, value, index, expr, body);
#endif
}
@@ -3088,7 +3135,10 @@ AstNode *parse_case_clause(AstFile *f) {
Token token = f->curr_token;
AstNodeArray list = make_ast_node_array(f);
if (allow_token(f, Token_case)) {
bool prev_allow_range = f->allow_range;
f->allow_range = true;
list = parse_rhs_expr_list(f);
f->allow_range = prev_allow_range;
} else {
expect_token(f, Token_default);
}
@@ -3102,9 +3152,17 @@ AstNode *parse_case_clause(AstFile *f) {
AstNode *parse_type_case_clause(AstFile *f) {
Token token = f->curr_token;
AstNodeArray clause = make_ast_node_array(f);
AstNodeArray list = make_ast_node_array(f);
if (allow_token(f, Token_case)) {
array_add(&clause, parse_type(f));
for (;;) {
AstNode *t = parse_type(f);
array_add(&list, t);
if (f->curr_token.kind != Token_Comma ||
f->curr_token.kind == Token_EOF) {
break;
}
next_token(f);
}
} else {
expect_token(f, Token_default);
}
@@ -3112,7 +3170,7 @@ AstNode *parse_type_case_clause(AstFile *f) {
// expect_token(f, Token_ArrowRight); // TODO(bill): Is this the best syntax?
AstNodeArray stmts = parse_stmt_list(f);
return ast_case_clause(f, token, clause, stmts);
return ast_case_clause(f, token, list, stmts);
}
@@ -3233,6 +3291,7 @@ AstNode *parse_stmt(AstFile *f) {
case Token_Ident:
case Token_Integer:
case Token_Float:
case Token_Imag:
case Token_Rune:
case Token_String:
case Token_OpenParen:
@@ -3256,43 +3315,51 @@ AstNode *parse_stmt(AstFile *f) {
case Token_break:
case Token_continue:
case Token_fallthrough:
case Token_fallthrough: {
AstNode *label = NULL;
next_token(f);
s = ast_branch_stmt(f, token);
if (token.kind != Token_fallthrough &&
f->curr_token.kind == Token_Ident) {
label = parse_ident(f);
}
s = ast_branch_stmt(f, token, label);
expect_semicolon(f, s);
return s;
}
case Token_using: {
// TODO(bill): Make using statements better
Token token = expect_token(f, Token_using);
AstNode *node = parse_stmt(f);
AstNodeArray list = parse_lhs_expr_list(f);
if (list.count == 0) {
syntax_error(token, "Illegal use of `using` statement");
expect_semicolon(f, NULL);
return ast_bad_stmt(f, token, f->curr_token);
}
switch (node->kind) {
case AstNode_ValueDecl:
if (!node->ValueDecl.is_var) {
if (f->curr_token.kind != Token_Colon) {
expect_semicolon(f, list.e[list.count-1]);
return ast_using_stmt(f, token, list);
}
AstNode *decl = parse_value_decl(f, list);
expect_semicolon(f, decl);
if (decl->kind == AstNode_ValueDecl) {
#if 1
if (!decl->ValueDecl.is_var) {
syntax_error(token, "`using` may not be applied to constant declarations");
return decl;
}
if (f->curr_proc == NULL) {
syntax_error(token, "`using` is not allowed at the file scope");
} else {
if (f->curr_proc == NULL) {
syntax_error(token, "`using` is not allowed at the file scope");
} else {
node->ValueDecl.flags |= VarDeclFlag_using;
}
decl->ValueDecl.flags |= VarDeclFlag_using;
}
return node;
case AstNode_ExprStmt: {
AstNode *e = unparen_expr(node->ExprStmt.expr);
while (e->kind == AstNode_SelectorExpr) {
e = unparen_expr(e->SelectorExpr.selector);
}
if (e->kind == AstNode_Ident) {
return ast_using_stmt(f, token, node);
} else if (e->kind == AstNode_Implicit) {
syntax_error(token, "Illegal use of `using` statement with implicit value `%.*s`", LIT(e->Implicit.string));
return ast_bad_stmt(f, token, f->curr_token);
}
} break;
#else
decl->ValueDecl.flags |= VarDeclFlag_using;
#endif
return decl;
}
syntax_error(token, "Illegal use of `using` statement");
@@ -3345,7 +3412,25 @@ AstNode *parse_stmt(AstFile *f) {
Token name = expect_token(f, Token_Ident);
String tag = name.string;
if (str_eq(tag, str_lit("import"))) {
if (str_eq(tag, str_lit("label"))) {
AstNode *name = parse_ident(f);
AstNode *label = ast_label_decl(f, token, name);
AstNode *stmt = parse_stmt(f);
#define _SET_LABEL(Kind_, label_) case GB_JOIN2(AstNode_, Kind_): (stmt->Kind_).label = label_; break
switch (stmt->kind) {
_SET_LABEL(ForStmt, label);
_SET_LABEL(RangeStmt, label);
_SET_LABEL(MatchStmt, label);
_SET_LABEL(TypeMatchStmt, label);
default:
syntax_error(token, "#label cannot only be applied to a loop or match statement");
break;
}
#undef _SET_LABEL
return stmt;
} else if (str_eq(tag, str_lit("import"))) {
AstNode *cond = NULL;
Token import_name = {0};
@@ -3505,7 +3590,6 @@ AstNode *parse_stmt(AstFile *f) {
return s;
}
if (str_eq(tag, str_lit("include"))) {
syntax_error(token, "#include is not a valid import declaration kind. Use #load instead");
s = ast_bad_stmt(f, token, f->curr_token);
@@ -3589,6 +3673,7 @@ ParseFileError init_ast_file(AstFile *f, String fullpath) {
gb_arena_init_from_allocator(&f->arena, heap_allocator(), arena_size);
f->curr_proc = NULL;
f->id = ++global_file_id;
return ParseFile_None;
}
@@ -3809,6 +3894,10 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
if (err != ParseFile_None) {
if (err == ParseFile_EmptyFile) {
if (str_eq(import_path, init_fullpath)) {
gb_printf_err("Initial file is empty - %.*s\n", LIT(init_fullpath));
gb_exit(1);
}
return ParseFile_None;
}
@@ -3827,7 +3916,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
gb_printf_err("File permissions problem");
break;
case ParseFile_NotFound:
gb_printf_err("File cannot be found");
gb_printf_err("File cannot be found (`%.*s`)", LIT(import_path));
break;
case ParseFile_InvalidToken:
gb_printf_err("Invalid token found in file");
+2636
View File
File diff suppressed because it is too large Load Diff
+276
View File
@@ -0,0 +1,276 @@
#define SSA_OPS \
SSA_OP(Invalid)\
\
SSA_OP(Unknown)\
\
SSA_OP(Comment) /* Does nothing */\
\
SSA_OP(SP) /* Stack Pointer */\
SSA_OP(SB) /* Stack Base */\
\
SSA_OP(Local)\
SSA_OP(Global)\
SSA_OP(Proc)\
\
SSA_OP(Load)\
SSA_OP(Store)\
SSA_OP(Move)\
SSA_OP(LoadReg)\
SSA_OP(StoreReg)\
SSA_OP(Zero) /* Zero initialize */\
\
SSA_OP(ArrayIndex) /* Index for a fixed array */\
SSA_OP(PtrIndex) /* Index for a struct/tuple/etc */\
SSA_OP(PtrOffset)\
SSA_OP(ValueIndex) /* Extract for a value from a register */\
\
SSA_OP(Phi)\
SSA_OP(Copy)\
\
/* TODO(bill): calling conventions */\
SSA_OP(CallOdin)\
SSA_OP(CallC)\
SSA_OP(CallStd)\
SSA_OP(CallFast)\
\
SSA_OP(BoundsCheck)\
SSA_OP(SliceBoundsCheck)\
\
/* Built in operations/procedures */\
SSA_OP(Bswap16)\
SSA_OP(Bswap32)\
SSA_OP(Bswap64)\
\
SSA_OP(Assume)\
SSA_OP(DebugTrap)\
SSA_OP(Trap)\
SSA_OP(ReadCycleCounter)\
\
\
SSA_OP(ConstBool)\
SSA_OP(ConstString)\
SSA_OP(ConstSlice)\
SSA_OP(ConstNil)\
SSA_OP(Const8)\
SSA_OP(Const16)\
SSA_OP(Const32)\
SSA_OP(Const64)\
SSA_OP(Const32F)\
SSA_OP(Const64F)\
\
/* These should be all the operations I could possibly need for the mean time */\
SSA_OP(Add8)\
SSA_OP(Add16)\
SSA_OP(Add32)\
SSA_OP(Add64)\
SSA_OP(AddPtr)\
SSA_OP(Add32F)\
SSA_OP(Add64F)\
SSA_OP(Sub8)\
SSA_OP(Sub16)\
SSA_OP(Sub32)\
SSA_OP(Sub64)\
SSA_OP(SubPtr)\
SSA_OP(Sub32F)\
SSA_OP(Sub64F)\
SSA_OP(Mul8)\
SSA_OP(Mul16)\
SSA_OP(Mul32)\
SSA_OP(Mul64)\
SSA_OP(Mul32F)\
SSA_OP(Mul64F)\
SSA_OP(Div8)\
SSA_OP(Div8U)\
SSA_OP(Div16)\
SSA_OP(Div16U)\
SSA_OP(Div32)\
SSA_OP(Div32U)\
SSA_OP(Div64)\
SSA_OP(Div64U)\
SSA_OP(Div32F)\
SSA_OP(Div64F)\
SSA_OP(Mod8)\
SSA_OP(Mod8U)\
SSA_OP(Mod16)\
SSA_OP(Mod16U)\
SSA_OP(Mod32)\
SSA_OP(Mod32U)\
SSA_OP(Mod64)\
SSA_OP(Mod64U)\
\
SSA_OP(And8)\
SSA_OP(And16)\
SSA_OP(And32)\
SSA_OP(And64)\
SSA_OP(Or8)\
SSA_OP(Or16)\
SSA_OP(Or32)\
SSA_OP(Or64)\
SSA_OP(Xor8)\
SSA_OP(Xor16)\
SSA_OP(Xor32)\
SSA_OP(Xor64)\
SSA_OP(AndNot8)\
SSA_OP(AndNot16)\
SSA_OP(AndNot32)\
SSA_OP(AndNot64)\
\
SSA_OP(Lsh8x8)\
SSA_OP(Lsh8x16)\
SSA_OP(Lsh8x32)\
SSA_OP(Lsh8x64)\
SSA_OP(Lsh16x8)\
SSA_OP(Lsh16x16)\
SSA_OP(Lsh16x32)\
SSA_OP(Lsh16x64)\
SSA_OP(Lsh32x8)\
SSA_OP(Lsh32x16)\
SSA_OP(Lsh32x32)\
SSA_OP(Lsh32x64)\
SSA_OP(Lsh64x8)\
SSA_OP(Lsh64x16)\
SSA_OP(Lsh64x32)\
SSA_OP(Lsh64x64)\
SSA_OP(Rsh8x8)\
SSA_OP(Rsh8x16)\
SSA_OP(Rsh8x32)\
SSA_OP(Rsh8x64)\
SSA_OP(Rsh16x8)\
SSA_OP(Rsh16x16)\
SSA_OP(Rsh16x32)\
SSA_OP(Rsh16x64)\
SSA_OP(Rsh32x8)\
SSA_OP(Rsh32x16)\
SSA_OP(Rsh32x32)\
SSA_OP(Rsh32x64)\
SSA_OP(Rsh64x8)\
SSA_OP(Rsh64x16)\
SSA_OP(Rsh64x32)\
SSA_OP(Rsh64x64)\
SSA_OP(Rsh8Ux8)\
SSA_OP(Rsh8Ux16)\
SSA_OP(Rsh8Ux32)\
SSA_OP(Rsh8Ux64)\
SSA_OP(Rsh16Ux8)\
SSA_OP(Rsh16Ux16)\
SSA_OP(Rsh16Ux32)\
SSA_OP(Rsh16Ux64)\
SSA_OP(Rsh32Ux8)\
SSA_OP(Rsh32Ux16)\
SSA_OP(Rsh32Ux32)\
SSA_OP(Rsh32Ux64)\
SSA_OP(Rsh64Ux8)\
SSA_OP(Rsh64Ux16)\
SSA_OP(Rsh64Ux32)\
SSA_OP(Rsh64Ux64)\
\
SSA_OP(Eq8)\
SSA_OP(Eq16)\
SSA_OP(Eq32)\
SSA_OP(Eq64)\
SSA_OP(EqPtr)\
SSA_OP(Eq32F)\
SSA_OP(Eq64F)\
SSA_OP(Ne8)\
SSA_OP(Ne16)\
SSA_OP(Ne32)\
SSA_OP(Ne64)\
SSA_OP(NePtr)\
SSA_OP(Ne32F)\
SSA_OP(Ne64F)\
SSA_OP(Lt8)\
SSA_OP(Lt16)\
SSA_OP(Lt32)\
SSA_OP(Lt64)\
SSA_OP(LtPtr)\
SSA_OP(Lt32F)\
SSA_OP(Lt64F)\
SSA_OP(Gt8)\
SSA_OP(Gt16)\
SSA_OP(Gt32)\
SSA_OP(Gt64)\
SSA_OP(GtPtr)\
SSA_OP(Gt32F)\
SSA_OP(Gt64F)\
SSA_OP(Le8)\
SSA_OP(Le16)\
SSA_OP(Le32)\
SSA_OP(Le64)\
SSA_OP(LePtr)\
SSA_OP(Le32F)\
SSA_OP(Le64F)\
SSA_OP(Ge8)\
SSA_OP(Ge16)\
SSA_OP(Ge32)\
SSA_OP(Ge64)\
SSA_OP(GePtr)\
SSA_OP(Ge32F)\
SSA_OP(Ge64F)\
\
SSA_OP(NotB)\
SSA_OP(EqB)\
SSA_OP(NeB)\
\
SSA_OP(Neg8)\
SSA_OP(Neg16)\
SSA_OP(Neg32)\
SSA_OP(Neg64)\
SSA_OP(Neg32F)\
SSA_OP(Neg64F)\
\
SSA_OP(Not8)\
SSA_OP(Not16)\
SSA_OP(Not32)\
SSA_OP(Not64)\
\
SSA_OP(SignExt8to16)\
SSA_OP(SignExt8to32)\
SSA_OP(SignExt8to64)\
SSA_OP(SignExt16to32)\
SSA_OP(SignExt16to64)\
SSA_OP(SignExt32to64)\
SSA_OP(ZeroExt8to16)\
SSA_OP(ZeroExt8to32)\
SSA_OP(ZeroExt8to64)\
SSA_OP(ZeroExt16to32)\
SSA_OP(ZeroExt16to64)\
SSA_OP(ZeroExt32to64)\
SSA_OP(Trunc16to8)\
SSA_OP(Trunc32to8)\
SSA_OP(Trunc32to16)\
SSA_OP(Trunc64to8)\
SSA_OP(Trunc64to16)\
SSA_OP(Trunc64to32)\
\
SSA_OP(Cvt32to32F)\
SSA_OP(Cvt32to64F)\
SSA_OP(Cvt64to32F)\
SSA_OP(Cvt64to64F)\
SSA_OP(Cvt32Fto32)\
SSA_OP(Cvt32Fto64)\
SSA_OP(Cvt64Fto32)\
SSA_OP(Cvt64Fto64)\
SSA_OP(Cvt32Fto64F)\
SSA_OP(Cvt64Fto32F)\
SSA_OP(Cvt32Uto32F)\
SSA_OP(Cvt32Uto64F)\
SSA_OP(Cvt32Fto32U)\
SSA_OP(Cvt64Fto32U)\
SSA_OP(Cvt64Uto32F)\
SSA_OP(Cvt64Uto64F)\
SSA_OP(Cvt32Fto64U)\
SSA_OP(Cvt64Fto64U)\
enum ssaOp {
#define SSA_OP(k) GB_JOIN2(ssaOp_, k),
SSA_OPS
#undef SSA_OP
};
typedef enum ssaOp ssaOp;
String const ssa_op_strings[] = {
#define SSA_OP(k) {cast(u8 *)#k, gb_size_of(#k)-1},
SSA_OPS
#undef SSA_OP
};
+18 -2
View File
@@ -188,6 +188,22 @@ bool string_contains_char(String s, u8 c) {
return false;
}
String filename_from_path(String s) {
isize i = string_extension_position(s);
if (i > 0) {
isize j = 0;
s.len = i;
for (j = i-1; j >= 0; j--) {
if (s.text[j] == '/' ||
s.text[j] == '\\') {
break;
}
}
s.text += j+1;
s.len = i-j-1;
}
return make_string(NULL, 0);
}
@@ -207,7 +223,7 @@ bool string_contains_char(String s, u8 c) {
#include <iconv.h>
int convert_multibyte_to_widechar(char *multibyte_input, int input_length, wchar_t *output, int output_size) {
int convert_multibyte_to_widechar(char *multibyte_input, usize input_length, wchar_t *output, usize output_size) {
iconv_t conv = iconv_open("WCHAR_T", "UTF-8");
size_t result = iconv(conv, cast(char **)&multibyte_input, &input_length, cast(char **)&output, &output_size);
iconv_close(conv);
@@ -215,7 +231,7 @@ bool string_contains_char(String s, u8 c) {
return (int) result;
}
int convert_widechar_to_multibyte(wchar_t* widechar_input, int input_length, char* output, int output_size) {
int convert_widechar_to_multibyte(wchar_t* widechar_input, usize input_length, char* output, usize output_size) {
iconv_t conv = iconv_open("UTF-8", "WCHAR_T");
size_t result = iconv(conv, (char**) &widechar_input, &input_length, (char**) &output, &output_size);
iconv_close(conv);
+73 -62
View File
@@ -7,6 +7,7 @@ TOKEN_KIND(Token__LiteralBegin, "_LiteralBegin"), \
TOKEN_KIND(Token_Ident, "identifier"), \
TOKEN_KIND(Token_Integer, "integer"), \
TOKEN_KIND(Token_Float, "float"), \
TOKEN_KIND(Token_Imag, "imaginary"), \
TOKEN_KIND(Token_Rune, "rune"), \
TOKEN_KIND(Token_String, "string"), \
TOKEN_KIND(Token__LiteralEnd, "_LiteralEnd"), \
@@ -63,18 +64,19 @@ TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
TOKEN_KIND(Token_GtEq, ">="), \
TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
\
TOKEN_KIND(Token_OpenParen, "("), \
TOKEN_KIND(Token_CloseParen, ")"), \
TOKEN_KIND(Token_OpenBracket, "["), \
TOKEN_KIND(Token_CloseBracket, "]"), \
TOKEN_KIND(Token_OpenBrace, "{"), \
TOKEN_KIND(Token_CloseBrace, "}"), \
TOKEN_KIND(Token_Colon, ":"), \
TOKEN_KIND(Token_Semicolon, ";"), \
TOKEN_KIND(Token_Period, "."), \
TOKEN_KIND(Token_Comma, ","), \
TOKEN_KIND(Token_Ellipsis, ".."), \
/* TOKEN_KIND(Token_HalfOpenRange, "..<"), */ \
TOKEN_KIND(Token_OpenParen, "("), \
TOKEN_KIND(Token_CloseParen, ")"), \
TOKEN_KIND(Token_OpenBracket, "["), \
TOKEN_KIND(Token_CloseBracket, "]"), \
TOKEN_KIND(Token_OpenBrace, "{"), \
TOKEN_KIND(Token_CloseBrace, "}"), \
TOKEN_KIND(Token_Colon, ":"), \
TOKEN_KIND(Token_Semicolon, ";"), \
TOKEN_KIND(Token_Period, "."), \
TOKEN_KIND(Token_Comma, ","), \
TOKEN_KIND(Token_Ellipsis, ".."), \
TOKEN_KIND(Token_HalfClosed, "..<"), \
TOKEN_KIND(Token_BackSlash, "\\"), \
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
\
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
@@ -105,14 +107,13 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_no_alias, "no_alias"), \
TOKEN_KIND(Token_immutable, "immutable"), \
TOKEN_KIND(Token_cast, "cast"), \
TOKEN_KIND(Token_transmute, "transmute"), \
TOKEN_KIND(Token_down_cast, "down_cast"), \
TOKEN_KIND(Token_union_cast, "union_cast"), \
TOKEN_KIND(Token_context, "context"), \
TOKEN_KIND(Token_push_context, "push_context"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
TOKEN_KIND(Token_asm, "asm"), \
TOKEN_KIND(Token_yield, "yield"), \
TOKEN_KIND(Token_await, "await"), \
TOKEN_KIND(Token_atomic, "atomic"), \
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
TOKEN_KIND(Token_Count, "")
@@ -168,8 +169,8 @@ Token make_token_ident(String s) {
typedef struct ErrorCollector {
TokenPos prev;
i64 count;
i64 warning_count;
i64 count;
i64 warning_count;
gbMutex mutex;
} ErrorCollector;
@@ -414,7 +415,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
TokenizerInitError err = TokenizerInit_None;
char *c_str = gb_alloc_array(heap_allocator(), char, fullpath.len+1);
memcpy(c_str, fullpath.text, fullpath.len);
gb_memcopy(c_str, fullpath.text, fullpath.len);
c_str[fullpath.len] = '\0';
// TODO(bill): Memory map rather than copy contents
@@ -484,15 +485,9 @@ gb_inline i32 digit_value(Rune r) {
return 16; // NOTE(bill): Larger than highest possible
}
gb_inline void scan_mantissa(Tokenizer *t, i32 base, bool allow_underscore) {
if (allow_underscore) {
while (digit_value(t->curr_rune) < base || t->curr_rune == '_') {
advance_to_next_rune(t);
}
} else {
while (digit_value(t->curr_rune) < base) {
advance_to_next_rune(t);
}
gb_inline void scan_mantissa(Tokenizer *t, i32 base) {
while (digit_value(t->curr_rune) < base || t->curr_rune == '_') {
advance_to_next_rune(t);
}
}
@@ -506,7 +501,7 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
if (seen_decimal_point) {
token.kind = Token_Float;
scan_mantissa(t, 10, true);
scan_mantissa(t, 10);
goto exponent;
}
@@ -515,31 +510,37 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
advance_to_next_rune(t);
if (t->curr_rune == 'b') { // Binary
advance_to_next_rune(t);
scan_mantissa(t, 2, true);
scan_mantissa(t, 2);
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} else if (t->curr_rune == 'o') { // Octal
advance_to_next_rune(t);
scan_mantissa(t, 8, true);
scan_mantissa(t, 8);
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} else if (t->curr_rune == 'd') { // Decimal
advance_to_next_rune(t);
scan_mantissa(t, 10, true);
scan_mantissa(t, 10);
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} else if (t->curr_rune == 'z') { // Dozenal
advance_to_next_rune(t);
scan_mantissa(t, 12);
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} else if (t->curr_rune == 'x') { // Hexadecimal
advance_to_next_rune(t);
scan_mantissa(t, 16, true);
scan_mantissa(t, 16);
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} else {
seen_decimal_point = false;
scan_mantissa(t, 10, true);
scan_mantissa(t, 10);
if (t->curr_rune == '.' || t->curr_rune == 'e' || t->curr_rune == 'E') {
seen_decimal_point = true;
@@ -547,24 +548,24 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
}
}
token.string.len = t->curr - token.string.text;
return token;
goto end;
}
scan_mantissa(t, 10, true);
scan_mantissa(t, 10);
fraction:
if (t->curr_rune == '.') {
// HACK(bill): This may be inefficient
TokenizerState state = save_tokenizer_state(t);
advance_to_next_rune(t);
if (digit_value(t->curr_rune) >= 10) {
if (t->curr_rune == '.') {
// TODO(bill): Clean up this shit
restore_tokenizer_state(t, &state);
goto end;
}
token.kind = Token_Float;
scan_mantissa(t, 10, true);
scan_mantissa(t, 10);
}
exponent:
@@ -574,7 +575,14 @@ exponent:
if (t->curr_rune == '-' || t->curr_rune == '+') {
advance_to_next_rune(t);
}
scan_mantissa(t, 10, false);
scan_mantissa(t, 10);
}
switch (t->curr_rune) {
case 'i': case 'j': case 'k':
token.kind = Token_Imag;
advance_to_next_rune(t);
break;
}
end:
@@ -611,20 +619,22 @@ bool scan_escape(Tokenizer *t, Rune quote) {
advance_to_next_rune(t);
len = 8; base = 16; max = GB_RUNE_MAX;
} else {
if (t->curr_rune < 0)
if (t->curr_rune < 0) {
tokenizer_err(t, "Escape sequence was not terminated");
else
} else {
tokenizer_err(t, "Unknown escape sequence");
}
return false;
}
while (len --> 0) {
u32 d = cast(u32)digit_value(t->curr_rune);
if (d >= base) {
if (t->curr_rune < 0)
if (t->curr_rune < 0) {
tokenizer_err(t, "Escape sequence was not terminated");
else
} else {
tokenizer_err(t, "Illegal character %d in escape sequence", t->curr_rune);
}
return false;
}
@@ -859,27 +869,28 @@ Token tokenizer_get_token(Tokenizer *t) {
if (t->curr_rune == '.') { // Could be an ellipsis
advance_to_next_rune(t);
token.kind = Token_Ellipsis;
// if (t->curr_rune == '<') {
// advance_to_next_rune(t);
// token.kind = Token_HalfOpenRange;
// }
if (t->curr_rune == '<') {
advance_to_next_rune(t);
token.kind = Token_HalfClosed;
}
}
break;
case '#': token.kind = Token_Hash; break;
case '@': token.kind = Token_At; break;
case '$': token.kind = Token_Dollar; break;
case '?': token.kind = Token_Question; break;
case '^': token.kind = Token_Pointer; break;
case ';': token.kind = Token_Semicolon; break;
case ',': token.kind = Token_Comma; break;
case ':': token.kind = Token_Colon; break;
case '(': token.kind = Token_OpenParen; break;
case ')': token.kind = Token_CloseParen; break;
case '[': token.kind = Token_OpenBracket; break;
case ']': token.kind = Token_CloseBracket; break;
case '{': token.kind = Token_OpenBrace; break;
case '}': token.kind = Token_CloseBrace; break;
case '#': token.kind = Token_Hash; break;
case '@': token.kind = Token_At; break;
case '$': token.kind = Token_Dollar; break;
case '?': token.kind = Token_Question; break;
case '^': token.kind = Token_Pointer; break;
case ';': token.kind = Token_Semicolon; break;
case ',': token.kind = Token_Comma; break;
case ':': token.kind = Token_Colon; break;
case '(': token.kind = Token_OpenParen; break;
case ')': token.kind = Token_CloseParen; break;
case '[': token.kind = Token_OpenBracket; break;
case ']': token.kind = Token_CloseBracket; break;
case '{': token.kind = Token_OpenBrace; break;
case '}': token.kind = Token_CloseBrace; break;
case '\\': token.kind = Token_BackSlash; break;
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break;
+308 -258
View File
@@ -12,25 +12,15 @@ typedef enum BasicKind {
Basic_i64,
Basic_u64,
/* Basic_i16le,
Basic_i16be,
Basic_u16le,
Basic_u16be,
Basic_i32le,
Basic_i32be,
Basic_u32le,
Basic_u32be,
Basic_i64le,
Basic_i64be,
Basic_u64le,
Basic_u64be, */
// Basic_i128,
// Basic_u128,
// Basic_f16,
Basic_f32,
Basic_f64,
// Basic_f128,
Basic_complex64,
Basic_complex128,
Basic_quaternion128,
Basic_quaternion256,
Basic_int,
Basic_uint,
Basic_rawptr,
@@ -40,6 +30,8 @@ typedef enum BasicKind {
Basic_UntypedBool,
Basic_UntypedInteger,
Basic_UntypedFloat,
Basic_UntypedComplex,
Basic_UntypedQuaternion,
Basic_UntypedString,
Basic_UntypedRune,
Basic_UntypedNil,
@@ -51,17 +43,19 @@ typedef enum BasicKind {
} BasicKind;
typedef enum BasicFlag {
BasicFlag_Boolean = GB_BIT(0),
BasicFlag_Integer = GB_BIT(1),
BasicFlag_Unsigned = GB_BIT(2),
BasicFlag_Float = GB_BIT(3),
BasicFlag_Pointer = GB_BIT(4),
BasicFlag_String = GB_BIT(5),
BasicFlag_Rune = GB_BIT(6),
BasicFlag_Untyped = GB_BIT(7),
BasicFlag_Boolean = GB_BIT(0),
BasicFlag_Integer = GB_BIT(1),
BasicFlag_Unsigned = GB_BIT(2),
BasicFlag_Float = GB_BIT(3),
BasicFlag_Complex = GB_BIT(4),
BasicFlag_Quaternion = GB_BIT(5),
BasicFlag_Pointer = GB_BIT(6),
BasicFlag_String = GB_BIT(7),
BasicFlag_Rune = GB_BIT(8),
BasicFlag_Untyped = GB_BIT(9),
BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float,
BasicFlag_Ordered = BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer,
BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex | BasicFlag_Quaternion,
BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer,
BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_Pointer | BasicFlag_String | BasicFlag_Rune,
} BasicFlag;
@@ -116,6 +110,7 @@ typedef struct TypeRecord {
#define TYPE_KINDS \
TYPE_KIND(Basic, BasicType) \
TYPE_KIND(Pointer, struct { Type *elem; }) \
TYPE_KIND(Atomic, struct { Type *elem; }) \
TYPE_KIND(Array, struct { Type *elem; i64 count; }) \
TYPE_KIND(DynamicArray, struct { Type *elem; }) \
TYPE_KIND(Vector, struct { Type *elem; i64 count; }) \
@@ -138,7 +133,10 @@ typedef struct TypeRecord {
Type * results; /* Type_Tuple */ \
i32 param_count; \
i32 result_count; \
Type **abi_compat_params; \
Type **abi_compat_results; \
bool variadic; \
bool require_results; \
ProcCallingConvention calling_convention; \
}) \
TYPE_KIND(Map, struct { \
@@ -209,33 +207,43 @@ void selection_add_index(Selection *s, isize index) {
gb_global Type basic_types[] = {
{Type_Basic, {Basic_Invalid, 0, 0, STR_LIT("invalid type")}},
{Type_Basic, {Basic_bool, BasicFlag_Boolean, 1, STR_LIT("bool")}},
{Type_Basic, {Basic_i8, BasicFlag_Integer, 1, STR_LIT("i8")}},
{Type_Basic, {Basic_u8, BasicFlag_Integer | BasicFlag_Unsigned, 1, STR_LIT("u8")}},
{Type_Basic, {Basic_i16, BasicFlag_Integer, 2, STR_LIT("i16")}},
{Type_Basic, {Basic_u16, BasicFlag_Integer | BasicFlag_Unsigned, 2, STR_LIT("u16")}},
{Type_Basic, {Basic_i32, BasicFlag_Integer, 4, STR_LIT("i32")}},
{Type_Basic, {Basic_u32, BasicFlag_Integer | BasicFlag_Unsigned, 4, STR_LIT("u32")}},
{Type_Basic, {Basic_i64, BasicFlag_Integer, 8, STR_LIT("i64")}},
{Type_Basic, {Basic_u64, BasicFlag_Integer | BasicFlag_Unsigned, 8, STR_LIT("u64")}},
// {Type_Basic, {Basic_i128, BasicFlag_Integer, 16, STR_LIT("i128")}},
// {Type_Basic, {Basic_u128, BasicFlag_Integer | BasicFlag_Unsigned, 16, STR_LIT("u128")}},
// {Type_Basic, {Basic_f16, BasicFlag_Float, 2, STR_LIT("f16")}},
{Type_Basic, {Basic_f32, BasicFlag_Float, 4, STR_LIT("f32")}},
{Type_Basic, {Basic_f64, BasicFlag_Float, 8, STR_LIT("f64")}},
// {Type_Basic, {Basic_f128, BasicFlag_Float, 16, STR_LIT("f128")}},
{Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}},
{Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}},
{Type_Basic, {Basic_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}},
{Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}},
{Type_Basic, {Basic_any, 0, -1, STR_LIT("any")}},
{Type_Basic, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, 0, STR_LIT("untyped bool")}},
{Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}},
{Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, 0, STR_LIT("untyped float")}},
{Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}},
{Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}},
{Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}},
{Type_Basic, {Basic_Invalid, 0, 0, STR_LIT("invalid type")}},
{Type_Basic, {Basic_bool, BasicFlag_Boolean, 1, STR_LIT("bool")}},
{Type_Basic, {Basic_i8, BasicFlag_Integer, 1, STR_LIT("i8")}},
{Type_Basic, {Basic_u8, BasicFlag_Integer | BasicFlag_Unsigned, 1, STR_LIT("u8")}},
{Type_Basic, {Basic_i16, BasicFlag_Integer, 2, STR_LIT("i16")}},
{Type_Basic, {Basic_u16, BasicFlag_Integer | BasicFlag_Unsigned, 2, STR_LIT("u16")}},
{Type_Basic, {Basic_i32, BasicFlag_Integer, 4, STR_LIT("i32")}},
{Type_Basic, {Basic_u32, BasicFlag_Integer | BasicFlag_Unsigned, 4, STR_LIT("u32")}},
{Type_Basic, {Basic_i64, BasicFlag_Integer, 8, STR_LIT("i64")}},
{Type_Basic, {Basic_u64, BasicFlag_Integer | BasicFlag_Unsigned, 8, STR_LIT("u64")}},
{Type_Basic, {Basic_f32, BasicFlag_Float, 4, STR_LIT("f32")}},
{Type_Basic, {Basic_f64, BasicFlag_Float, 8, STR_LIT("f64")}},
{Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}},
{Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}},
{Type_Basic, {Basic_quaternion128, BasicFlag_Quaternion, 16, STR_LIT("quaternion128")}},
{Type_Basic, {Basic_quaternion256, BasicFlag_Quaternion, 32, STR_LIT("quaternion256")}},
{Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}},
{Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}},
{Type_Basic, {Basic_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}},
{Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}},
{Type_Basic, {Basic_any, 0, -1, STR_LIT("any")}},
{Type_Basic, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, 0, STR_LIT("untyped bool")}},
{Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}},
{Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, 0, STR_LIT("untyped float")}},
{Type_Basic, {Basic_UntypedComplex, BasicFlag_Complex | BasicFlag_Untyped, 0, STR_LIT("untyped complex")}},
{Type_Basic, {Basic_UntypedQuaternion, BasicFlag_Quaternion | BasicFlag_Untyped, 0, STR_LIT("untyped quaternion")}},
{Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}},
{Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}},
{Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}},
};
gb_global Type basic_type_aliases[] = {
@@ -253,25 +261,33 @@ gb_global Type *t_i32 = &basic_types[Basic_i32];
gb_global Type *t_u32 = &basic_types[Basic_u32];
gb_global Type *t_i64 = &basic_types[Basic_i64];
gb_global Type *t_u64 = &basic_types[Basic_u64];
// gb_global Type *t_i128 = &basic_types[Basic_i128];
// gb_global Type *t_u128 = &basic_types[Basic_u128];
// gb_global Type *t_f16 = &basic_types[Basic_f16];
gb_global Type *t_f32 = &basic_types[Basic_f32];
gb_global Type *t_f64 = &basic_types[Basic_f64];
// gb_global Type *t_f128 = &basic_types[Basic_f128];
gb_global Type *t_complex64 = &basic_types[Basic_complex64];
gb_global Type *t_complex128 = &basic_types[Basic_complex128];
gb_global Type *t_quaternion128 = &basic_types[Basic_quaternion128];
gb_global Type *t_quaternion256 = &basic_types[Basic_quaternion256];
gb_global Type *t_int = &basic_types[Basic_int];
gb_global Type *t_uint = &basic_types[Basic_uint];
gb_global Type *t_rawptr = &basic_types[Basic_rawptr];
gb_global Type *t_string = &basic_types[Basic_string];
gb_global Type *t_any = &basic_types[Basic_any];
gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool];
gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger];
gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat];
gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString];
gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil];
gb_global Type *t_byte = &basic_type_aliases[0];
gb_global Type *t_rune = &basic_type_aliases[1];
gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool];
gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger];
gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat];
gb_global Type *t_untyped_complex = &basic_types[Basic_UntypedComplex];
gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion];
gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString];
gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil];
gb_global Type *t_byte = &basic_type_aliases[0];
gb_global Type *t_rune = &basic_type_aliases[1];
gb_global Type *t_u8_ptr = NULL;
@@ -293,10 +309,13 @@ gb_global Type *t_type_info_enum_value_ptr = NULL;
gb_global Type *t_type_info_named = NULL;
gb_global Type *t_type_info_integer = NULL;
gb_global Type *t_type_info_float = NULL;
gb_global Type *t_type_info_complex = NULL;
gb_global Type *t_type_info_quaternion = NULL;
gb_global Type *t_type_info_any = NULL;
gb_global Type *t_type_info_string = NULL;
gb_global Type *t_type_info_boolean = NULL;
gb_global Type *t_type_info_pointer = NULL;
gb_global Type *t_type_info_atomic = NULL;
gb_global Type *t_type_info_procedure = NULL;
gb_global Type *t_type_info_array = NULL;
gb_global Type *t_type_info_dynamic_array = NULL;
@@ -312,10 +331,13 @@ gb_global Type *t_type_info_map = NULL;
gb_global Type *t_type_info_named_ptr = NULL;
gb_global Type *t_type_info_integer_ptr = NULL;
gb_global Type *t_type_info_float_ptr = NULL;
gb_global Type *t_type_info_complex_ptr = NULL;
gb_global Type *t_type_info_quaternion_ptr = NULL;
gb_global Type *t_type_info_any_ptr = NULL;
gb_global Type *t_type_info_string_ptr = NULL;
gb_global Type *t_type_info_boolean_ptr = NULL;
gb_global Type *t_type_info_pointer_ptr = NULL;
gb_global Type *t_type_info_atomic_ptr = NULL;
gb_global Type *t_type_info_procedure_ptr = NULL;
gb_global Type *t_type_info_array_ptr = NULL;
gb_global Type *t_type_info_dynamic_array_ptr = NULL;
@@ -333,8 +355,6 @@ gb_global Type *t_allocator_ptr = NULL;
gb_global Type *t_context = NULL;
gb_global Type *t_context_ptr = NULL;
gb_global Type *t_raw_dynamic_array = NULL;
gb_global Type *t_raw_dynamic_array_ptr = NULL;
gb_global Type *t_map_key = NULL;
gb_global Type *t_map_header = NULL;
@@ -375,6 +395,34 @@ Type *base_enum_type(Type *t) {
return t;
}
Type *core_type(Type *t) {
for (;;) {
if (t == NULL) {
break;
}
switch (t->kind) {
case Type_Named:
if (t == t->Named.base) {
return t_invalid;
}
t = t->Named.base;
continue;
case Type_Record:
if (t->Record.kind == TypeRecord_Enum) {
t = t->Record.enum_base_type;
continue;
}
break;
case Type_Atomic:
t = t->Atomic.elem;
continue;
}
break;
}
return t;
}
void set_base_type(Type *t, Type *base) {
if (t && t->kind == Type_Named) {
t->Named.base = base;
@@ -384,6 +432,7 @@ void set_base_type(Type *t, Type *base) {
Type *alloc_type(gbAllocator a, TypeKind kind) {
Type *t = gb_alloc_item(a, Type);
gb_zero_item(t);
t->kind = kind;
return t;
}
@@ -401,6 +450,12 @@ Type *make_type_pointer(gbAllocator a, Type *elem) {
return t;
}
Type *make_type_atomic(gbAllocator a, Type *elem) {
Type *t = alloc_type(a, Type_Atomic);
t->Atomic.elem = elem;
return t;
}
Type *make_type_array(gbAllocator a, Type *elem, i64 count) {
Type *t = alloc_type(a, Type_Array);
t->Array.elem = elem;
@@ -510,8 +565,6 @@ Type *make_type_map(gbAllocator a, i64 count, Type *key, Type *value) {
Type *type_deref(Type *t) {
if (t != NULL) {
Type *bt = base_type(t);
@@ -529,29 +582,43 @@ bool is_type_named(Type *t) {
}
return t->kind == Type_Named;
}
bool is_type_named_alias(Type *t) {
if (!is_type_named(t)) {
return false;
}
Entity *e = t->Named.type_name;
if (e == NULL) {
return false;
}
if (e->kind != Entity_TypeName) {
return false;
}
return e->TypeName.is_type_alias;
}
bool is_type_boolean(Type *t) {
t = base_type(base_enum_type(t));
t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Boolean) != 0;
}
return false;
}
bool is_type_integer(Type *t) {
t = base_type(base_enum_type(t));
t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Integer) != 0;
}
return false;
}
bool is_type_unsigned(Type *t) {
t = base_type(base_enum_type(t));
t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Unsigned) != 0;
}
return false;
}
bool is_type_numeric(Type *t) {
t = base_type(base_enum_type(t));
t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Numeric) != 0;
}
@@ -586,7 +653,7 @@ bool is_type_untyped(Type *t) {
return false;
}
bool is_type_ordered(Type *t) {
t = base_type(base_enum_type(t));
t = core_type(t);
switch (t->kind) {
case Type_Basic:
return (t->Basic.flags & BasicFlag_Ordered) != 0;
@@ -598,28 +665,42 @@ bool is_type_ordered(Type *t) {
return false;
}
bool is_type_constant_type(Type *t) {
t = base_type(base_enum_type(t));
t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_ConstantType) != 0;
}
return false;
}
bool is_type_float(Type *t) {
t = base_type(base_enum_type(t));
t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Float) != 0;
}
return false;
}
bool is_type_complex(Type *t) {
t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Complex) != 0;
}
return false;
}
bool is_type_quaternion(Type *t) {
t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Quaternion) != 0;
}
return false;
}
bool is_type_f32(Type *t) {
t = base_type(base_enum_type(t));
t = core_type(t);
if (t->kind == Type_Basic) {
return t->Basic.kind == Basic_f32;
}
return false;
}
bool is_type_f64(Type *t) {
t = base_type(base_enum_type(t));
t = core_type(t);
if (t->kind == Type_Basic) {
return t->Basic.kind == Basic_f64;
}
@@ -632,6 +713,10 @@ bool is_type_pointer(Type *t) {
}
return t->kind == Type_Pointer;
}
bool is_type_atomic(Type *t) {
t = base_type(t);
return t->kind == Type_Atomic;
}
bool is_type_tuple(Type *t) {
t = base_type(t);
return t->kind == Type_Tuple;
@@ -691,6 +776,31 @@ Type *base_vector_type(Type *t) {
return t;
}
Type *base_complex_elem_type(Type *t) {
t = core_type(t);
if (is_type_complex(t)) {
switch (t->Basic.kind) {
case Basic_complex64: return t_f32;
case Basic_complex128: return t_f64;
case Basic_UntypedComplex: return t_untyped_float;
}
}
GB_PANIC("Invalid complex type");
return t_invalid;
}
Type *base_quaternion_elem_type(Type *t) {
t = core_type(t);
if (is_type_quaternion(t)) {
switch (t->Basic.kind) {
case Basic_quaternion128: return t_f32;
case Basic_quaternion256: return t_f64;
case Basic_UntypedQuaternion: return t_untyped_float;
}
}
GB_PANIC("Invalid quaternion type");
return t_invalid;
}
bool is_type_struct(Type *t) {
t = base_type(t);
@@ -737,7 +847,7 @@ bool is_type_untyped_nil(Type *t) {
bool is_type_valid_for_keys(Type *t) {
t = base_type(base_enum_type(t));
t = core_type(t);
if (is_type_untyped(t)) {
return false;
}
@@ -775,10 +885,17 @@ bool type_has_nil(Type *t) {
return false;
} break;
case Type_Slice:
case Type_DynamicArray:
case Type_Proc:
case Type_Pointer:
case Type_DynamicArray:
case Type_Map:
return true;
case Type_Record:
switch (t->Record.kind) {
case TypeRecord_Union:
return true;
}
return false;
}
return false;
}
@@ -798,7 +915,7 @@ bool is_type_comparable(Type *t) {
return true;
case Type_Record: {
if (is_type_enum(t)) {
return is_type_comparable(base_enum_type(t));
return is_type_comparable(core_type(t));
}
return false;
} break;
@@ -867,13 +984,21 @@ bool are_types_identical(Type *x, Type *y) {
x->Record.custom_align == y->Record.custom_align) {
// TODO(bill); Fix the custom alignment rule
for (isize i = 0; i < x->Record.field_count; i++) {
if (!are_types_identical(x->Record.fields[i]->type, y->Record.fields[i]->type)) {
Entity *xf = x->Record.fields[i];
Entity *yf = y->Record.fields[i];
if (!are_types_identical(xf->type, yf->type)) {
return false;
}
if (str_ne(x->Record.fields[i]->token.string, y->Record.fields[i]->token.string)) {
if (str_ne(xf->token.string, yf->token.string)) {
return false;
}
bool xf_is_using = (xf->flags&EntityFlag_Using) != 0;
bool yf_is_using = (yf->flags&EntityFlag_Using) != 0;
if (xf_is_using ^ yf_is_using) {
return false;
}
}
// NOTE(bill): zeroth variant is NULL
for (isize i = 1; i < x->Record.variant_count; i++) {
if (!are_types_identical(x->Record.variants[i]->type, y->Record.variants[i]->type)) {
return false;
@@ -946,11 +1071,13 @@ Type *default_type(Type *type) {
}
if (type->kind == Type_Basic) {
switch (type->Basic.kind) {
case Basic_UntypedBool: return t_bool;
case Basic_UntypedInteger: return t_int;
case Basic_UntypedFloat: return t_f64;
case Basic_UntypedString: return t_string;
case Basic_UntypedRune: return t_rune;
case Basic_UntypedBool: return t_bool;
case Basic_UntypedInteger: return t_int;
case Basic_UntypedFloat: return t_f64;
case Basic_UntypedComplex: return t_complex128;
case Basic_UntypedQuaternion: return t_quaternion256;
case Basic_UntypedString: return t_string;
case Basic_UntypedRune: return t_rune;
}
}
return type;
@@ -1031,10 +1158,13 @@ typedef enum ProcTypeOverloadKind {
} ProcTypeOverloadKind;
ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
if (!is_type_proc(x)) return ProcOverload_NotProcedure;
if (!is_type_proc(y)) return ProcOverload_NotProcedure;
if (x == NULL && y == NULL) return ProcOverload_NotProcedure;
if (x == NULL && y != NULL) return ProcOverload_NotProcedure;
if (x != NULL && y == NULL) return ProcOverload_NotProcedure;
if (!is_type_proc(x)) return ProcOverload_NotProcedure;
if (!is_type_proc(y)) return ProcOverload_NotProcedure;
TypeProc px = base_type(x)->Proc;
TypeProc py = base_type(y)->Proc;
@@ -1070,12 +1200,11 @@ ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
}
}
{
if (px.params != NULL && py.params != NULL) {
Entity *ex = px.params->Tuple.variables[0];
Entity *ey = py.params->Tuple.variables[0];
bool ok = are_types_identical(ex->type, ey->type);
if (ok) {
gb_printf_err("Here\n");
}
}
@@ -1085,20 +1214,6 @@ ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
gb_global Entity *entity__any_type_info = NULL;
gb_global Entity *entity__any_data = NULL;
gb_global Entity *entity__string_data = NULL;
gb_global Entity *entity__string_count = NULL;
gb_global Entity *entity__slice_count = NULL;
gb_global Entity *entity__slice_capacity = NULL;
gb_global Entity *entity__dynamic_array_count = NULL;
gb_global Entity *entity__dynamic_array_capacity = NULL;
gb_global Entity *entity__dynamic_array_allocator = NULL;
gb_global Entity *entity__dynamic_map_count = NULL;
gb_global Entity *entity__dynamic_map_capacity = NULL;
gb_global Entity *entity__dynamic_map_allocator = NULL;
Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel);
@@ -1151,6 +1266,10 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) {
return empty_selection;
}
gb_global Entity *entity__any_data = NULL;
gb_global Entity *entity__any_type_info = NULL;
Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel) {
GB_ASSERT(type_ != NULL);
@@ -1167,66 +1286,33 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
if (type->kind == Type_Basic) {
switch (type->Basic.kind) {
case Basic_any: {
#if 1
// IMPORTANT TODO(bill): Should these members be available to should I only allow them with
// `Raw_Any` type?
String data_str = str_lit("data");
String type_info_str = str_lit("type_info");
String data_str = str_lit("data");
if (entity__any_type_info == NULL) {
entity__any_type_info = make_entity_field(a, NULL, make_token_ident(type_info_str), t_type_info_ptr, false, 0);
}
if (entity__any_data == NULL) {
entity__any_data = make_entity_field(a, NULL, make_token_ident(data_str), t_rawptr, false, 1);
entity__any_data = make_entity_field(a, NULL, make_token_ident(data_str), t_rawptr, false, 0);
}
if (str_eq(field_name, type_info_str)) {
selection_add_index(&sel, 0);
sel.entity = entity__any_type_info;
return sel;
} else if (str_eq(field_name, data_str)) {
selection_add_index(&sel, 1);
sel.entity = entity__any_data;
return sel;
}
} break;
case Basic_string: {
String data_str = str_lit("data");
String count_str = str_lit("count");
if (entity__string_data == NULL) {
entity__string_data = make_entity_field(a, NULL, make_token_ident(data_str), make_type_pointer(a, t_u8), false, 0);
}
if (entity__string_count == NULL) {
entity__string_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 1);
if (entity__any_type_info == NULL) {
entity__any_type_info = make_entity_field(a, NULL, make_token_ident(type_info_str), t_type_info_ptr, false, 1);
}
if (str_eq(field_name, data_str)) {
selection_add_index(&sel, 0);
sel.entity = entity__string_data;
sel.entity = entity__any_data;;
return sel;
} else if (str_eq(field_name, count_str)) {
} else if (str_eq(field_name, type_info_str)) {
selection_add_index(&sel, 1);
sel.entity = entity__string_count;
sel.entity = entity__any_type_info;
return sel;
}
#endif
} break;
}
return sel;
} else if (type->kind == Type_Array) {
String count_str = str_lit("count");
// NOTE(bill): Underlying memory address cannot be changed
if (str_eq(field_name, count_str)) {
// HACK(bill): Memory leak
sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, make_exact_value_integer(type->Array.count));
return sel;
}
} else if (type->kind == Type_Vector) {
String count_str = str_lit("count");
// NOTE(bill): Vectors are not addressable
if (str_eq(field_name, count_str)) {
// HACK(bill): Memory leak
sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, make_exact_value_integer(type->Vector.count));
return sel;
}
if (type->Vector.count <= 4 && !is_type_boolean(type->Vector.elem)) {
// HACK(bill): Memory leak
switch (type->Vector.count) {
@@ -1248,98 +1334,6 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
#undef _VECTOR_FIELD_CASE
}
}
} else if (type->kind == Type_Slice) {
String data_str = str_lit("data");
String count_str = str_lit("count");
String capacity_str = str_lit("capacity");
if (str_eq(field_name, data_str)) {
selection_add_index(&sel, 0);
// HACK(bill): Memory leak
sel.entity = make_entity_field(a, NULL, make_token_ident(data_str), make_type_pointer(a, type->Slice.elem), false, 0);
return sel;
} else if (str_eq(field_name, count_str)) {
selection_add_index(&sel, 1);
if (entity__slice_count == NULL) {
entity__slice_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 1);
}
sel.entity = entity__slice_count;
return sel;
} else if (str_eq(field_name, capacity_str)) {
selection_add_index(&sel, 2);
if (entity__slice_capacity == NULL) {
entity__slice_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 2);
}
sel.entity = entity__slice_capacity;
return sel;
}
} else if (type->kind == Type_DynamicArray) {
String data_str = str_lit("data");
String count_str = str_lit("count");
String capacity_str = str_lit("capacity");
String allocator_str = str_lit("allocator");
if (str_eq(field_name, data_str)) {
selection_add_index(&sel, 0);
// HACK(bill): Memory leak
sel.entity = make_entity_field(a, NULL, make_token_ident(data_str), make_type_pointer(a, type->DynamicArray.elem), false, 0);
return sel;
} else if (str_eq(field_name, count_str)) {
selection_add_index(&sel, 1);
if (entity__dynamic_array_count == NULL) {
entity__dynamic_array_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 1);
}
sel.entity = entity__dynamic_array_count;
return sel;
} else if (str_eq(field_name, capacity_str)) {
selection_add_index(&sel, 2);
if (entity__dynamic_array_capacity == NULL) {
entity__dynamic_array_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 2);
}
sel.entity = entity__dynamic_array_capacity;
return sel;
} else if (str_eq(field_name, allocator_str)) {
selection_add_index(&sel, 3);
if (entity__dynamic_array_allocator == NULL) {
entity__dynamic_array_allocator = make_entity_field(a, NULL, make_token_ident(allocator_str), t_allocator, false, 3);
}
sel.entity = entity__dynamic_array_allocator;
return sel;
}
} else if (type->kind == Type_Map) {
String count_str = str_lit("count");
String capacity_str = str_lit("capacity");
String allocator_str = str_lit("allocator");
if (str_eq(field_name, count_str)) {
selection_add_index(&sel, 0);
if (entity__dynamic_map_count == NULL) {
entity__dynamic_map_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 0);
entity__dynamic_map_count->Variable.is_immutable = true;
}
sel.entity = entity__dynamic_map_count;
return sel;
} else if (str_eq(field_name, capacity_str)) {
selection_add_index(&sel, 1);
if (entity__dynamic_map_capacity == NULL) {
entity__dynamic_map_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 1);
entity__dynamic_map_capacity->Variable.is_immutable = true;
}
sel.entity = entity__dynamic_map_capacity;
return sel;
} else if (str_eq(field_name, allocator_str)) {
selection_add_index(&sel, 2);
if (entity__dynamic_map_allocator == NULL) {
entity__dynamic_map_allocator = make_entity_field(a, NULL, make_token_ident(allocator_str), t_allocator, false, 2);
entity__dynamic_map_allocator->Variable.is_immutable = true;
}
sel.entity = entity__dynamic_map_allocator;
return sel;
}
}
if (is_type) {
@@ -1405,7 +1399,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
return sel;
}
if (f->flags & EntityFlag_Anonymous) {
if (f->flags & EntityFlag_Using) {
isize prev_count = sel.index.count;
selection_add_index(&sel, i); // HACK(bill): Leaky memory
@@ -1443,7 +1437,7 @@ void type_path_free(TypePath *tp) {
TypePath *type_path_push(TypePath *tp, Type *t) {
GB_ASSERT(tp != NULL);
for_array(i, tp->path) {
for (isize i = 0; i < tp->path.count; i++) {
if (tp->path.e[i] == t) {
// TODO(bill):
GB_ASSERT(is_type_named(t));
@@ -1524,6 +1518,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
if (t->failure) {
return FAILURE_ALIGNMENT;
}
t = base_type(t);
switch (t->kind) {
@@ -1535,6 +1530,11 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
case Basic_int: case Basic_uint: case Basic_rawptr:
return build_context.word_size;
case Basic_complex64: case Basic_complex128:
return type_size_of_internal(allocator, t, path) / 2;
case Basic_quaternion128: case Basic_quaternion256:
return type_size_of_internal(allocator, t, path) / 4;
}
} break;
@@ -1623,6 +1623,18 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
break;
case TypeRecord_Union: {
i64 max = 1;
if (t->Record.field_count > 0) {
Type *field_type = t->Record.fields[0]->type;
type_path_push(path, field_type);
i64 align = type_align_of_internal(allocator, field_type, path);
if (path->failure) {
return FAILURE_ALIGNMENT;
}
type_path_pop(path);
if (max < align) {
max = align;
}
}
// NOTE(bill): field zero is null
for (isize i = 1; i < t->Record.variant_count; i++) {
Type *variant = t->Record.variants[i]->type;
@@ -1675,9 +1687,10 @@ i64 *type_set_offsets_of(gbAllocator allocator, Entity **fields, isize field_cou
} else {
for (isize i = 0; i < field_count; i++) {
i64 align = type_align_of(allocator, fields[i]->type);
i64 size = type_size_of(allocator, fields[i]->type);
curr_offset = align_formula(curr_offset, align);
offsets[i] = curr_offset;
curr_offset += type_size_of(allocator, fields[i]->type);
curr_offset += size;
}
}
return offsets;
@@ -1713,8 +1726,18 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
if (t->failure) {
return FAILURE_SIZE;
}
t = base_type(t);
switch (t->kind) {
case Type_Named: {
type_path_push(path, t);
if (path->failure) {
return FAILURE_ALIGNMENT;
}
i64 size = type_size_of_internal(allocator, t->Named.base, path);
type_path_pop(path);
return size;
} break;
case Type_Basic: {
GB_ASSERT(is_type_typed(t));
BasicKind kind = t->Basic.kind;
@@ -1747,7 +1770,8 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
} break;
case Type_DynamicArray:
return 3*build_context.word_size + type_size_of(allocator, t_allocator);
// data + len + cap + allocator(procedure+data)
return 3*build_context.word_size + 2*build_context.word_size;
case Type_Vector: {
#if 0
@@ -1825,15 +1849,35 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
} break;
case TypeRecord_Union: {
i64 count = t->Record.variant_count;
i64 align = type_align_of_internal(allocator, t, path);
if (path->failure) {
return FAILURE_SIZE;
}
i64 max = 0;
isize field_count = t->Record.field_count;
isize variant_count = t->Record.variant_count;
// Check for recursive types
for (isize i = 0; i < field_count; i++) {
i64 size = type_size_of_internal(allocator, t->Record.fields[i]->type, path);
if (path->failure) {
return FAILURE_SIZE;
}
}
// NOTE(bill): Zeroth field is invalid
for (isize i = 1; i < count; i++) {
i64 size = type_size_of_internal(allocator, t->Record.variants[i]->type, path);
type_set_offsets(allocator, t);
if (field_count > 0) {
Type *end_type = t->Record.fields[field_count-1]->type;
i64 end_offset = t->Record.offsets[field_count-1];
i64 end_size = type_size_of_internal(allocator, end_type, path);
max = end_offset + end_size ;
}
for (isize i = 1; i < variant_count; i++) {
Type *variant_type = t->Record.variants[i]->type;
i64 size = type_size_of_internal(allocator, variant_type, path);
if (max < size) {
max = size;
}
@@ -1841,7 +1885,8 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
// NOTE(bill): Align to int
i64 size = align_formula(max, build_context.word_size);
size += type_size_of_internal(allocator, t_int, path);
return align_formula(size, align);
size = align_formula(size, align);
return size;
} break;
case TypeRecord_RawUnion: {
@@ -1870,7 +1915,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
i64 type_offset_of(gbAllocator allocator, Type *t, i32 index) {
t = base_type(t);
if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) {
if (t->kind == Type_Record && (t->Record.kind == TypeRecord_Struct || t->Record.kind == TypeRecord_Union)) {
type_set_offsets(allocator, t);
if (gb_is_between(index, 0, t->Record.field_count-1)) {
return t->Record.offsets[index];
@@ -1975,13 +2020,18 @@ gbString write_type_to_string(gbString str, Type *type) {
str = write_type_to_string(str, type->Pointer.elem);
break;
case Type_Atomic:
str = gb_string_appendc(str, "atomic ");
str = write_type_to_string(str, type->Atomic.elem);
break;
case Type_Array:
str = gb_string_appendc(str, gb_bprintf("[%lld]", type->Array.count));
str = gb_string_appendc(str, gb_bprintf("[%d]", cast(int)type->Array.count));
str = write_type_to_string(str, type->Array.elem);
break;
case Type_Vector:
str = gb_string_appendc(str, gb_bprintf("[vector %lld]", type->Vector.count));
str = gb_string_appendc(str, gb_bprintf("[vector %d]", cast(int)type->Vector.count));
str = write_type_to_string(str, type->Vector.elem);
break;
@@ -2029,7 +2079,7 @@ gbString write_type_to_string(gbString str, Type *type) {
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, base_type(f->type));
str = write_type_to_string(str, f->type);
}
for (isize i = 1; i < type->Record.variant_count; i++) {
Entity *f = type->Record.variants[i];
@@ -2095,7 +2145,7 @@ gbString write_type_to_string(gbString str, Type *type) {
case Type_Map: {
str = gb_string_appendc(str, "map[");
if (type->Map.count > 0) {
str = gb_string_appendc(str, gb_bprintf("%lld, ", type->Map.count));
str = gb_string_appendc(str, gb_bprintf("%d, ", cast(int)type->Map.count));
}
str = write_type_to_string(str, type->Map.key);
str = gb_string_appendc(str, "]");