mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-13 06:41:26 -07:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ec9c8fb8a4 | |||
| 3e79ec4aef | |||
| 3e257ef8d0 | |||
| 626f91f307 | |||
| e86c990b75 | |||
| 31aacd5bf4 | |||
| 92453369c5 | |||
| 832009f33a | |||
| d3d3bfd455 | |||
| ce3582fd89 | |||
| e3e16f5d05 | |||
| f47f25f942 | |||
| e85458919c | |||
| b59a052e32 | |||
| 12498b2d39 | |||
| 6d93aa429f | |||
| 3f023509a7 | |||
| 563b1e2b28 | |||
| 4603d2525e | |||
| 2af9fb79dc | |||
| 367d307dc4 | |||
| cb59c1cf08 | |||
| 383f5b55ad | |||
| 6dc6b6f8aa | |||
| ac736aa4ec | |||
| 6fe25badf0 | |||
| c29d433e38 | |||
| ff473e8342 | |||
| 659e5359b2 | |||
| d9ce0b9da0 |
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# The Odin Programming Language
|
# The Odin Programming Language
|
||||||
|
|
||||||
Odin is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
|
The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
|
||||||
* simplicity
|
* simplicity
|
||||||
* high performance
|
* high performance
|
||||||
* built for modern systems
|
* built for modern systems
|
||||||
@@ -18,6 +18,7 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
|
|||||||
* [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM)
|
* [Composition & Refactorability](https://www.youtube.com/watch?v=n1wemZfcbXM)
|
||||||
* [Introspection, Modules, and Record Layout](https://www.youtube.com/watch?v=UFq8rhWhx4s)
|
* [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)
|
* [push_allocator & Minimal Dependency Building](https://www.youtube.com/watch?v=f_LGVOAMb78)
|
||||||
|
* [when, for, & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
|
||||||
|
|
||||||
## Requirements to build and run
|
## Requirements to build and run
|
||||||
|
|
||||||
@@ -30,27 +31,27 @@ Odin is fast, concise, readable, pragmatic and open sourced. It is designed with
|
|||||||
## Warnings
|
## Warnings
|
||||||
|
|
||||||
* This is still highly in development and the language's design is quite volatile.
|
* This is still highly in development and the language's design is quite volatile.
|
||||||
* Syntax is definitely not fixed
|
* Syntax is not fixed.
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
Not in any particular order
|
Not in any particular order
|
||||||
|
|
||||||
* Custom backend to replace LLVM
|
* Compile Time Execution (CTE)
|
||||||
- Improve SSA design to accommodate for lowering to a "bytecode"
|
- More metaprogramming madness
|
||||||
- SSA optimizations
|
- Compiler as a library
|
||||||
- COFF generation
|
- AST inspection and modification
|
||||||
- linker
|
* CTE-based build system
|
||||||
* Type safe "macros"
|
* Replace LLVM backend with my own custom backend
|
||||||
* Documentation generator for "Entities"
|
* Improve SSA design to accommodate for lowering to a "bytecode"
|
||||||
* Multiple architecture support
|
* SSA optimizations
|
||||||
* Inline assembly
|
* Parametric Polymorphism ("Generics")
|
||||||
* Linking options
|
* Documentation Generator for "Entities"
|
||||||
- Executable
|
* Multiple Architecture support
|
||||||
- Static/Dynamic Library
|
* Language level atomics and concurrency support
|
||||||
* Debug information
|
* Debug Information
|
||||||
- pdb format too
|
- pdb format too
|
||||||
* Command line tooling
|
* Command Line Tooling
|
||||||
* Compiler internals:
|
* Compiler Internals:
|
||||||
- Big numbers library
|
- Big numbers library
|
||||||
|
- Multithreading for performance increase
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
set exe_name=odin.exe
|
set exe_name=odin.exe
|
||||||
|
|
||||||
:: Debug = 0, Release = 1
|
:: Debug = 0, Release = 1
|
||||||
set release_mode=0
|
set release_mode=1
|
||||||
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
||||||
|
|
||||||
if %release_mode% EQU 0 ( rem Debug
|
if %release_mode% EQU 0 ( rem Debug
|
||||||
@@ -46,7 +46,7 @@ cl %compiler_settings% "src\main.c" ^
|
|||||||
/link %linker_settings% -OUT:%exe_name% ^
|
/link %linker_settings% -OUT:%exe_name% ^
|
||||||
&& odin run code/demo.odin
|
&& odin run code/demo.odin
|
||||||
rem && odin build_dll code/example.odin ^
|
rem && odin build_dll code/example.odin ^
|
||||||
rem && odin run code/demo.odin
|
rem odin run code/demo.odin
|
||||||
|
|
||||||
rem pushd src\asm
|
rem pushd src\asm
|
||||||
rem nasm hellope.asm -fwin64 -o hellope.obj ^
|
rem nasm hellope.asm -fwin64 -o hellope.obj ^
|
||||||
|
|||||||
+278
-3
@@ -1,7 +1,282 @@
|
|||||||
#import "fmt.odin";
|
#import "fmt.odin";
|
||||||
|
#import "utf8.odin";
|
||||||
|
// #import "atomic.odin";
|
||||||
|
// #import "hash.odin";
|
||||||
|
// #import "math.odin";
|
||||||
|
// #import "mem.odin";
|
||||||
|
// #import "opengl.odin";
|
||||||
|
// #import "os.odin";
|
||||||
|
// #import "sync.odin";
|
||||||
|
// #import win32 "sys/windows.odin";
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
x := "-stats";
|
// syntax();
|
||||||
y := "-begin";
|
procedure_overloading();
|
||||||
fmt.println(x == y);
|
}
|
||||||
|
|
||||||
|
syntax :: proc() {
|
||||||
|
// Cyclic type checking
|
||||||
|
// Uncomment to see the error
|
||||||
|
// A :: struct {b: B};
|
||||||
|
// B :: struct {a: A};
|
||||||
|
|
||||||
|
x: int;
|
||||||
|
y := cast(f32)x;
|
||||||
|
z := transmute(u32)y;
|
||||||
|
// down_cast, union_cast are similar too
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Basic directives
|
||||||
|
fmt.printf("Basic directives = %s(%d): %s\n", #file, #line, #procedure);
|
||||||
|
// NOTE: new and improved `printf`
|
||||||
|
// TODO: It does need accurate float printing
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// record fields use the same syntax a procedure signatures
|
||||||
|
Thing1 :: struct {
|
||||||
|
x: f32,
|
||||||
|
y: int,
|
||||||
|
z: ^[]int,
|
||||||
|
};
|
||||||
|
Thing2 :: struct {x: f32, y: int, z: ^[]int};
|
||||||
|
|
||||||
|
// Slice interals are now just a `ptr+count`
|
||||||
|
slice: []int; compile_assert(size_of_val(slice) == 2*size_of(int));
|
||||||
|
|
||||||
|
// Helper type - Help the reader understand what it is quicker
|
||||||
|
My_Int :: type int;
|
||||||
|
My_Proc :: type proc(int) -> f32;
|
||||||
|
|
||||||
|
|
||||||
|
// All declarations with : are either variable or constant
|
||||||
|
// To make these declarations syntactically consistent
|
||||||
|
v_variable := 123;
|
||||||
|
c_constant :: 123;
|
||||||
|
c_type1 :: int;
|
||||||
|
c_type2 :: []int;
|
||||||
|
c_proc :: proc() { /* code here */ };
|
||||||
|
|
||||||
|
|
||||||
|
x += 1;
|
||||||
|
x -= 1;
|
||||||
|
// ++ and -- have been removed
|
||||||
|
// x++;
|
||||||
|
// x--;
|
||||||
|
// Question: Should they be added again?
|
||||||
|
// They were removed as they are redundant and statements, not expressions
|
||||||
|
// like in C/C++
|
||||||
|
|
||||||
|
|
||||||
|
// You can now build files as a `.dll`
|
||||||
|
// `odin build_dll demo.odin`
|
||||||
|
|
||||||
|
|
||||||
|
// New vector syntax
|
||||||
|
u, v: [vector 3]f32;
|
||||||
|
v[0] = 123;
|
||||||
|
v.x = 123; // valid for all vectors with count 1 to 4
|
||||||
|
|
||||||
|
// Next part
|
||||||
|
prefixes();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Prefix_Type :: struct {x: int, y: f32, z: rawptr};
|
||||||
|
|
||||||
|
thread_local my_tls: Prefix_Type;
|
||||||
|
|
||||||
|
prefixes :: proc() {
|
||||||
|
using var: Prefix_Type;
|
||||||
|
immutable const := Prefix_Type{1, 2, nil};
|
||||||
|
var.x = 123;
|
||||||
|
x = 123;
|
||||||
|
// const.x = 123; // const is immutable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) {
|
||||||
|
// int_ptr = nil; // Not valid
|
||||||
|
int_ptr^ = 123; // Is valid
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Same as C99's `restrict`
|
||||||
|
bar :: proc(no_alias a, b: ^int) {
|
||||||
|
// Assumes a never equals b so it can perform optimizations with that fact
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
when_statements();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
when_statements :: proc() {
|
||||||
|
X :: 123 + 12;
|
||||||
|
Y :: X/5;
|
||||||
|
COND :: Y > 0;
|
||||||
|
|
||||||
|
when COND {
|
||||||
|
fmt.println("Y > 0");
|
||||||
|
} else {
|
||||||
|
fmt.println("Y <= 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
when false {
|
||||||
|
this_code_does_not_exist(123, 321);
|
||||||
|
but_its_syntax_is_valid();
|
||||||
|
x :: ^^^^int;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreign_procedures();
|
||||||
|
}
|
||||||
|
|
||||||
|
#foreign_system_library win32_user "user32.lib" when ODIN_OS == "windows";
|
||||||
|
// NOTE: This is done on purpose for two reasons:
|
||||||
|
// * Makes it clear where the platform specific stuff is
|
||||||
|
// * Removes the need to solve the travelling salesman problem when importing files :P
|
||||||
|
|
||||||
|
foreign_procedures :: proc() {
|
||||||
|
ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user;
|
||||||
|
show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user "ShowWindow";
|
||||||
|
// NOTE: If that library doesn't get used, it doesn't get linked with
|
||||||
|
// NOTE: There is not link checking yet to see if that procedure does come from that library
|
||||||
|
|
||||||
|
// See sys/windows.odin for more examples
|
||||||
|
|
||||||
|
special_expressions();
|
||||||
|
}
|
||||||
|
|
||||||
|
special_expressions :: proc() {
|
||||||
|
// Block expression
|
||||||
|
x := {
|
||||||
|
a: f32 = 123;
|
||||||
|
b := a-123;
|
||||||
|
c := b/a;
|
||||||
|
give c;
|
||||||
|
}; // semicolon is required as it's an expression
|
||||||
|
|
||||||
|
y := if x < 50 {
|
||||||
|
give x;
|
||||||
|
} else {
|
||||||
|
// TODO: Type cohesion is not yet finished
|
||||||
|
give 123;
|
||||||
|
}; // semicolon is required as it's an expression
|
||||||
|
|
||||||
|
|
||||||
|
// This is allows for inline blocks of code and will be a useful feature to have when
|
||||||
|
// macros will be implemented into the language
|
||||||
|
|
||||||
|
loops();
|
||||||
|
}
|
||||||
|
|
||||||
|
loops :: proc() {
|
||||||
|
// The C-style for loop
|
||||||
|
for i := 0; i < 123; i += 1 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for i := 0; i < 123; {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for false {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..<123 { // 123 exclusive
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0...122 { // 122 inclusive
|
||||||
|
}
|
||||||
|
|
||||||
|
for val, idx in 12..<16 {
|
||||||
|
fmt.println(val, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19};
|
||||||
|
|
||||||
|
for p in primes {
|
||||||
|
fmt.println(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointers to arrays, slices, or strings are allowed
|
||||||
|
for _ in ^primes {
|
||||||
|
// ignore the value and just iterate across it
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
name := "你好,世界";
|
||||||
|
fmt.println(name);
|
||||||
|
for r in name {
|
||||||
|
compile_assert(type_of_val(r) == rune);
|
||||||
|
fmt.printf("%r\n", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
when false {
|
||||||
|
for i, size := 0; i < name.count; i += size {
|
||||||
|
r: rune;
|
||||||
|
r, size = utf8.decode_rune(name[i:]);
|
||||||
|
fmt.printf("%r\n", r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
procedure_overloading();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
procedure_overloading :: proc() {
|
||||||
|
THINGF :: 14451.1;
|
||||||
|
THINGI :: 14451;
|
||||||
|
|
||||||
|
foo :: proc() {
|
||||||
|
fmt.printf("Zero args\n");
|
||||||
|
}
|
||||||
|
foo :: proc(i: int) {
|
||||||
|
fmt.printf("int arg, i=%d\n", i);
|
||||||
|
}
|
||||||
|
foo :: proc(f: f64) {
|
||||||
|
i := cast(int)f;
|
||||||
|
fmt.printf("f64 arg, f=%d\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
foo();
|
||||||
|
foo(THINGF);
|
||||||
|
// foo(THINGI); // 14451 is just a number so it could go to either procedures
|
||||||
|
foo(cast(int)THINGI);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
foo :: proc(x: ^i32) -> (int, int) {
|
||||||
|
fmt.println("^int");
|
||||||
|
return 123, cast(int)(x^);
|
||||||
|
}
|
||||||
|
foo :: proc(x: rawptr) {
|
||||||
|
fmt.println("rawptr");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a: i32 = 123;
|
||||||
|
b: f32;
|
||||||
|
c: rawptr;
|
||||||
|
fmt.println(foo(^a));
|
||||||
|
foo(^b);
|
||||||
|
foo(c);
|
||||||
|
// foo(nil); // nil could go to numerous types thus the ambiguity
|
||||||
|
|
||||||
|
f: proc();
|
||||||
|
f = foo; // The correct `foo` to chosen
|
||||||
|
f();
|
||||||
|
|
||||||
|
|
||||||
|
// See math.odin and atomic.odin for more examples
|
||||||
}
|
}
|
||||||
|
|||||||
+86
-86
@@ -1,9 +1,9 @@
|
|||||||
#import "fmt.odin"
|
#import "fmt.odin";
|
||||||
#import "os.odin"
|
#import "os.odin";
|
||||||
#import "mem.odin"
|
#import "mem.odin";
|
||||||
// #import "http_test.odin" as ht
|
// #import "http_test.odin" as ht;
|
||||||
// #import "game.odin" as game
|
// #import "game.odin" as game;
|
||||||
// #import "punity.odin" as pn
|
// #import "punity.odin" as pn;
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
// struct_padding()
|
// struct_padding()
|
||||||
@@ -26,58 +26,58 @@ main :: proc() {
|
|||||||
struct_padding :: proc() {
|
struct_padding :: proc() {
|
||||||
{
|
{
|
||||||
A :: struct {
|
A :: struct {
|
||||||
a: u8
|
a: u8,
|
||||||
b: u32
|
b: u32,
|
||||||
c: u16
|
c: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
B :: struct {
|
B :: struct {
|
||||||
a: [7]u8
|
a: [7]u8,
|
||||||
b: [3]u16
|
b: [3]u16,
|
||||||
c: u8
|
c: u8,
|
||||||
d: u16
|
d: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.println("size_of(A):", size_of(A))
|
fmt.println("size_of(A):", size_of(A));
|
||||||
fmt.println("size_of(B):", size_of(B))
|
fmt.println("size_of(B):", size_of(B));
|
||||||
|
|
||||||
// n.b. http://cbloomrants.blogspot.co.uk/2012/07/07-23-12-structs-are-not-what-you-want.html
|
// n.b. http://cbloomrants.blogspot.co.uk/2012/07/07-23-12-structs-are-not-what-you-want.html
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
A :: struct #ordered {
|
A :: struct #ordered {
|
||||||
a: u8
|
a: u8,
|
||||||
b: u32
|
b: u32,
|
||||||
c: u16
|
c: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
B :: struct #ordered {
|
B :: struct #ordered {
|
||||||
a: [7]u8
|
a: [7]u8,
|
||||||
b: [3]u16
|
b: [3]u16,
|
||||||
c: u8
|
c: u8,
|
||||||
d: u16
|
d: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.println("size_of(A):", size_of(A))
|
fmt.println("size_of(A):", size_of(A));
|
||||||
fmt.println("size_of(B):", size_of(B))
|
fmt.println("size_of(B):", size_of(B));
|
||||||
|
|
||||||
// C-style structure layout
|
// C-style structure layout
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
A :: struct #packed {
|
A :: struct #packed {
|
||||||
a: u8
|
a: u8,
|
||||||
b: u32
|
b: u32,
|
||||||
c: u16
|
c: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
B :: struct #packed {
|
B :: struct #packed {
|
||||||
a: [7]u8
|
a: [7]u8,
|
||||||
b: [3]u16
|
b: [3]u16,
|
||||||
c: u8
|
c: u8,
|
||||||
d: u16
|
d: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.println("size_of(A):", size_of(A))
|
fmt.println("size_of(A):", size_of(A));
|
||||||
fmt.println("size_of(B):", size_of(B))
|
fmt.println("size_of(B):", size_of(B));
|
||||||
|
|
||||||
// Useful for explicit layout
|
// Useful for explicit layout
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ struct_padding :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bounds_checking :: proc() {
|
bounds_checking :: proc() {
|
||||||
x: [4]int
|
x: [4]int;
|
||||||
// x[-1] = 0; // Compile Time
|
// x[-1] = 0; // Compile Time
|
||||||
// x[4] = 0; // Compile Time
|
// x[4] = 0; // Compile Time
|
||||||
|
|
||||||
@@ -132,9 +132,9 @@ bounds_checking :: proc() {
|
|||||||
// Works for arrays, strings, slices, and related procedures & operations
|
// Works for arrays, strings, slices, and related procedures & operations
|
||||||
|
|
||||||
{
|
{
|
||||||
base: [10]int
|
base: [10]int;
|
||||||
s := base[2:6]
|
s := base[2:6];
|
||||||
a, b := -1, 6
|
a, b := -1, 6;
|
||||||
|
|
||||||
#no_bounds_check {
|
#no_bounds_check {
|
||||||
s[a] = 0;
|
s[a] = 0;
|
||||||
@@ -154,69 +154,69 @@ bounds_checking :: proc() {
|
|||||||
|
|
||||||
type_introspection :: proc() {
|
type_introspection :: proc() {
|
||||||
{
|
{
|
||||||
info: ^Type_Info
|
info: ^Type_Info;
|
||||||
x: int
|
x: int;
|
||||||
|
|
||||||
info = type_info(int) // by type
|
info = type_info(int); // by type
|
||||||
info = type_info_of_val(x) // by value
|
info = type_info_of_val(x); // by value
|
||||||
// See: runtime.odin
|
// See: runtime.odin
|
||||||
|
|
||||||
match type i : info {
|
match type i in info {
|
||||||
case Type_Info.Integer:
|
case Type_Info.Integer:
|
||||||
fmt.println("integer!")
|
fmt.println("integer!");
|
||||||
case Type_Info.Float:
|
case Type_Info.Float:
|
||||||
fmt.println("float!")
|
fmt.println("float!");
|
||||||
default:
|
default:
|
||||||
fmt.println("potato!")
|
fmt.println("potato!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsafe cast
|
// Unsafe cast
|
||||||
integer_info := info as ^Type_Info.Integer
|
integer_info := cast(^Type_Info.Integer)info;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Vector2 :: struct { x, y: f32 }
|
Vector2 :: struct { x, y: f32 }
|
||||||
Vector3 :: struct { x, y, z: f32 }
|
Vector3 :: struct { x, y, z: f32 }
|
||||||
|
|
||||||
v1: Vector2
|
v1: Vector2;
|
||||||
v2: Vector3
|
v2: Vector3;
|
||||||
v3: Vector3
|
v3: Vector3;
|
||||||
|
|
||||||
t1 := type_info_of_val(v1)
|
t1 := type_info_of_val(v1);
|
||||||
t2 := type_info_of_val(v2)
|
t2 := type_info_of_val(v2);
|
||||||
t3 := type_info_of_val(v3)
|
t3 := type_info_of_val(v3);
|
||||||
|
|
||||||
fmt.println()
|
fmt.println();
|
||||||
fmt.print("Type of v1 is:\n\t", t1)
|
fmt.print("Type of v1 is:\n\t", t1);
|
||||||
|
|
||||||
fmt.println()
|
fmt.println();
|
||||||
fmt.print("Type of v2 is:\n\t", t2)
|
fmt.print("Type of v2 is:\n\t", t2);
|
||||||
|
|
||||||
fmt.println("\n")
|
fmt.println("\n");
|
||||||
fmt.println("t1 == t2:", t1 == t2)
|
fmt.println("t1 == t2:", t1 == t2);
|
||||||
fmt.println("t2 == t3:", t2 == t3)
|
fmt.println("t2 == t3:", t2 == t3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
any_type :: proc() {
|
any_type :: proc() {
|
||||||
a: any
|
a: any;
|
||||||
|
|
||||||
x: int = 123
|
x: int = 123;
|
||||||
y: f64 = 6.28
|
y: f64 = 6.28;
|
||||||
z: string = "Yo-Yo Ma"
|
z: string = "Yo-Yo Ma";
|
||||||
// All types can be implicit cast to `any`
|
// All types can be implicit cast to `any`
|
||||||
a = x
|
a = x;
|
||||||
a = y
|
a = y;
|
||||||
a = z
|
a = z;
|
||||||
a = a // This the "identity" type, it doesn't get converted
|
a = a; // This the "identity" type, it doesn't get converted
|
||||||
|
|
||||||
a = 123 // Literals are copied onto the stack first
|
a = 123; // Literals are copied onto the stack first
|
||||||
|
|
||||||
// any has two members
|
// any has two members
|
||||||
// data - rawptr to the data
|
// data - rawptr to the data
|
||||||
// type_info - pointer to the type info
|
// type_info - pointer to the type info
|
||||||
|
|
||||||
fmt.println(x, y, z)
|
fmt.println(x, y, z);
|
||||||
// See: fmt.odin
|
// See: fmt.odin
|
||||||
// For variadic any procedures in action
|
// For variadic any procedures in action
|
||||||
}
|
}
|
||||||
@@ -232,15 +232,15 @@ crazy_introspection :: proc() {
|
|||||||
TOMATO,
|
TOMATO,
|
||||||
}
|
}
|
||||||
|
|
||||||
s: string
|
s: string;
|
||||||
s = enum_to_string(Fruit.PEACH)
|
// s = enum_to_string(Fruit.PEACH);
|
||||||
fmt.println(s)
|
fmt.println(s);
|
||||||
|
|
||||||
f := Fruit.GRAPE
|
f := Fruit.GRAPE;
|
||||||
s = enum_to_string(f)
|
// s = enum_to_string(f);
|
||||||
fmt.println(s)
|
fmt.println(s);
|
||||||
|
|
||||||
fmt.println(f)
|
fmt.println(f);
|
||||||
// See: runtime.odin
|
// See: runtime.odin
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,15 +259,15 @@ crazy_introspection :: proc() {
|
|||||||
TOMATO,
|
TOMATO,
|
||||||
}
|
}
|
||||||
|
|
||||||
fruit_ti := type_info(Fruit)
|
fruit_ti := type_info(Fruit);
|
||||||
name := (fruit_ti as ^Type_Info.Named).name // Unsafe casts
|
name := (cast(^Type_Info.Named)fruit_ti).name; // Unsafe casts
|
||||||
info := type_info_base(fruit_ti) as ^Type_Info.Enum // Unsafe casts
|
info := cast(^Type_Info.Enum)type_info_base(fruit_ti); // Unsafe casts
|
||||||
|
|
||||||
fmt.printf("% :: enum % {\n", name, info.base);
|
fmt.printf("% :: enum % {\n", name, info.base);
|
||||||
for i := 0; i < info.values.count; i++ {
|
for i := 0; i < info.values.count; i += 1 {
|
||||||
fmt.printf("\t%\t= %,\n", info.names[i], info.values[i])
|
fmt.printf("\t%\t= %,\n", info.names[i], info.values[i]);
|
||||||
}
|
}
|
||||||
fmt.printf("}\n")
|
fmt.printf("}\n");
|
||||||
|
|
||||||
// NOTE(bill): look at that type-safe printf!
|
// NOTE(bill): look at that type-safe printf!
|
||||||
}
|
}
|
||||||
@@ -275,10 +275,10 @@ crazy_introspection :: proc() {
|
|||||||
{
|
{
|
||||||
Vector3 :: struct {x, y, z: f32}
|
Vector3 :: struct {x, y, z: f32}
|
||||||
|
|
||||||
a := Vector3{x = 1, y = 4, z = 9}
|
a := Vector3{x = 1, y = 4, z = 9};
|
||||||
fmt.println(a)
|
fmt.println(a);
|
||||||
b := Vector3{x = 9, y = 3, z = 1}
|
b := Vector3{x = 9, y = 3, z = 1};
|
||||||
fmt.println(b)
|
fmt.println(b);
|
||||||
|
|
||||||
// NOTE(bill): See fmt.odin
|
// NOTE(bill): See fmt.odin
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,282 @@
|
|||||||
|
#import "fmt.odin";
|
||||||
|
#import "utf8.odin";
|
||||||
|
// #import "atomic.odin";
|
||||||
|
// #import "hash.odin";
|
||||||
|
// #import "math.odin";
|
||||||
|
// #import "mem.odin";
|
||||||
|
// #import "opengl.odin";
|
||||||
|
// #import "os.odin";
|
||||||
|
// #import "sync.odin";
|
||||||
|
// #import win32 "sys/windows.odin";
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
// syntax();
|
||||||
|
procedure_overloading();
|
||||||
|
}
|
||||||
|
|
||||||
|
syntax :: proc() {
|
||||||
|
// Cyclic type checking
|
||||||
|
// Uncomment to see the error
|
||||||
|
// A :: struct {b: B};
|
||||||
|
// B :: struct {a: A};
|
||||||
|
|
||||||
|
x: int;
|
||||||
|
y := cast(f32)x;
|
||||||
|
z := transmute(u32)y;
|
||||||
|
// down_cast, union_cast are similar too
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Basic directives
|
||||||
|
fmt.printf("Basic directives = %s(%d): %s\n", #file, #line, #procedure);
|
||||||
|
// NOTE: new and improved `printf`
|
||||||
|
// TODO: It does need accurate float printing
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// record fields use the same syntax a procedure signatures
|
||||||
|
Thing1 :: struct {
|
||||||
|
x: f32,
|
||||||
|
y: int,
|
||||||
|
z: ^[]int,
|
||||||
|
};
|
||||||
|
Thing2 :: struct {x: f32, y: int, z: ^[]int};
|
||||||
|
|
||||||
|
// Slice interals are now just a `ptr+count`
|
||||||
|
slice: []int; compile_assert(size_of_val(slice) == 2*size_of(int));
|
||||||
|
|
||||||
|
// Helper type - Help the reader understand what it is quicker
|
||||||
|
My_Int :: type int;
|
||||||
|
My_Proc :: type proc(int) -> f32;
|
||||||
|
|
||||||
|
|
||||||
|
// All declarations with : are either variable or constant
|
||||||
|
// To make these declarations syntactically consistent
|
||||||
|
v_variable := 123;
|
||||||
|
c_constant :: 123;
|
||||||
|
c_type1 :: int;
|
||||||
|
c_type2 :: []int;
|
||||||
|
c_proc :: proc() { /* code here */ };
|
||||||
|
|
||||||
|
|
||||||
|
x += 1;
|
||||||
|
x -= 1;
|
||||||
|
// ++ and -- have been removed
|
||||||
|
// x++;
|
||||||
|
// x--;
|
||||||
|
// Question: Should they be added again?
|
||||||
|
// They were removed as they are redundant and statements, not expressions
|
||||||
|
// like in C/C++
|
||||||
|
|
||||||
|
|
||||||
|
// You can now build files as a `.dll`
|
||||||
|
// `odin build_dll demo.odin`
|
||||||
|
|
||||||
|
|
||||||
|
// New vector syntax
|
||||||
|
u, v: [vector 3]f32;
|
||||||
|
v[0] = 123;
|
||||||
|
v.x = 123; // valid for all vectors with count 1 to 4
|
||||||
|
|
||||||
|
// Next part
|
||||||
|
prefixes();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Prefix_Type :: struct {x: int, y: f32, z: rawptr};
|
||||||
|
|
||||||
|
thread_local my_tls: Prefix_Type;
|
||||||
|
|
||||||
|
prefixes :: proc() {
|
||||||
|
using var: Prefix_Type;
|
||||||
|
immutable const := Prefix_Type{1, 2, nil};
|
||||||
|
var.x = 123;
|
||||||
|
x = 123;
|
||||||
|
// const.x = 123; // const is immutable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) {
|
||||||
|
// int_ptr = nil; // Not valid
|
||||||
|
int_ptr^ = 123; // Is valid
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Same as C99's `restrict`
|
||||||
|
bar :: proc(no_alias a, b: ^int) {
|
||||||
|
// Assumes a never equals b so it can perform optimizations with that fact
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
when_statements();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
when_statements :: proc() {
|
||||||
|
X :: 123 + 12;
|
||||||
|
Y :: X/5;
|
||||||
|
COND :: Y > 0;
|
||||||
|
|
||||||
|
when COND {
|
||||||
|
fmt.println("Y > 0");
|
||||||
|
} else {
|
||||||
|
fmt.println("Y <= 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
when false {
|
||||||
|
this_code_does_not_exist(123, 321);
|
||||||
|
but_its_syntax_is_valid();
|
||||||
|
x :: ^^^^int;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreign_procedures();
|
||||||
|
}
|
||||||
|
|
||||||
|
#foreign_system_library win32_user "user32.lib" when ODIN_OS == "windows";
|
||||||
|
// NOTE: This is done on purpose for two reasons:
|
||||||
|
// * Makes it clear where the platform specific stuff is
|
||||||
|
// * Removes the need to solve the travelling salesman problem when importing files :P
|
||||||
|
|
||||||
|
foreign_procedures :: proc() {
|
||||||
|
ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user;
|
||||||
|
show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user "ShowWindow";
|
||||||
|
// NOTE: If that library doesn't get used, it doesn't get linked with
|
||||||
|
// NOTE: There is not link checking yet to see if that procedure does come from that library
|
||||||
|
|
||||||
|
// See sys/windows.odin for more examples
|
||||||
|
|
||||||
|
special_expressions();
|
||||||
|
}
|
||||||
|
|
||||||
|
special_expressions :: proc() {
|
||||||
|
// Block expression
|
||||||
|
x := {
|
||||||
|
a: f32 = 123;
|
||||||
|
b := a-123;
|
||||||
|
c := b/a;
|
||||||
|
give c;
|
||||||
|
}; // semicolon is required as it's an expression
|
||||||
|
|
||||||
|
y := if x < 50 {
|
||||||
|
give x;
|
||||||
|
} else {
|
||||||
|
// TODO: Type cohesion is not yet finished
|
||||||
|
give 123;
|
||||||
|
}; // semicolon is required as it's an expression
|
||||||
|
|
||||||
|
|
||||||
|
// This is allows for inline blocks of code and will be a useful feature to have when
|
||||||
|
// macros will be implemented into the language
|
||||||
|
|
||||||
|
loops();
|
||||||
|
}
|
||||||
|
|
||||||
|
loops :: proc() {
|
||||||
|
// The C-style for loop
|
||||||
|
for i := 0; i < 123; i += 1 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for i := 0; i < 123; {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for false {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..<123 { // 123 exclusive
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0...122 { // 122 inclusive
|
||||||
|
}
|
||||||
|
|
||||||
|
for val, idx in 12..<16 {
|
||||||
|
fmt.println(val, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19};
|
||||||
|
|
||||||
|
for p in primes {
|
||||||
|
fmt.println(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointers to arrays, slices, or strings are allowed
|
||||||
|
for _ in ^primes {
|
||||||
|
// ignore the value and just iterate across it
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
name := "你好,世界";
|
||||||
|
fmt.println(name);
|
||||||
|
for r in name {
|
||||||
|
compile_assert(type_of_val(r) == rune);
|
||||||
|
fmt.printf("%r\n", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
when false {
|
||||||
|
for i, size := 0; i < name.count; i += size {
|
||||||
|
r: rune;
|
||||||
|
r, size = utf8.decode_rune(name[i:]);
|
||||||
|
fmt.printf("%r\n", r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
procedure_overloading();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
procedure_overloading :: proc() {
|
||||||
|
THINGF :: 14451.1;
|
||||||
|
THINGI :: 14451;
|
||||||
|
|
||||||
|
foo :: proc() {
|
||||||
|
fmt.printf("Zero args\n");
|
||||||
|
}
|
||||||
|
foo :: proc(i: int) {
|
||||||
|
fmt.printf("int arg, i=%d\n", i);
|
||||||
|
}
|
||||||
|
foo :: proc(f: f64) {
|
||||||
|
i := cast(int)f;
|
||||||
|
fmt.printf("f64 arg, f=%d\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
foo();
|
||||||
|
foo(THINGF);
|
||||||
|
// foo(THINGI); // 14451 is just a number so it could go to either procedures
|
||||||
|
foo(cast(int)THINGI);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
foo :: proc(x: ^i32) -> (int, int) {
|
||||||
|
fmt.println("^int");
|
||||||
|
return 123, cast(int)(x^);
|
||||||
|
}
|
||||||
|
foo :: proc(x: rawptr) {
|
||||||
|
fmt.println("rawptr");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a: i32 = 123;
|
||||||
|
b: f32;
|
||||||
|
c: rawptr;
|
||||||
|
fmt.println(foo(^a));
|
||||||
|
foo(^b);
|
||||||
|
foo(c);
|
||||||
|
// foo(nil); // nil could go to numerous types thus the ambiguity
|
||||||
|
|
||||||
|
f: proc();
|
||||||
|
f = foo; // The correct `foo` to chosen
|
||||||
|
f();
|
||||||
|
|
||||||
|
|
||||||
|
// See math.odin and atomic.odin for more examples
|
||||||
|
}
|
||||||
+167
-160
@@ -1,34 +1,35 @@
|
|||||||
#import "win32.odin"
|
#import win32 "sys/windows.odin";
|
||||||
#import "fmt.odin"
|
#import "fmt.odin";
|
||||||
#import "os.odin"
|
#import "os.odin";
|
||||||
|
#import "mem.odin";
|
||||||
|
|
||||||
CANVAS_WIDTH :: 128
|
CANVAS_WIDTH :: 128;
|
||||||
CANVAS_HEIGHT :: 128
|
CANVAS_HEIGHT :: 128;
|
||||||
CANVAS_SCALE :: 3
|
CANVAS_SCALE :: 3;
|
||||||
FRAME_TIME :: 1.0/30.0
|
FRAME_TIME :: 1.0/30.0;
|
||||||
WINDOW_TITLE :: "Punity\x00"
|
WINDOW_TITLE :: "Punity\x00";
|
||||||
|
|
||||||
_ := compile_assert(CANVAS_WIDTH % 16 == 0)
|
_ := compile_assert(CANVAS_WIDTH % 16 == 0);
|
||||||
|
|
||||||
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE
|
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE;
|
||||||
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE
|
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE;
|
||||||
|
|
||||||
|
|
||||||
STACK_CAPACITY :: 1<<20
|
STACK_CAPACITY :: 1<<20;
|
||||||
STORAGE_CAPACITY :: 1<<20
|
STORAGE_CAPACITY :: 1<<20;
|
||||||
|
|
||||||
DRAW_LIST_RESERVE :: 128
|
DRAW_LIST_RESERVE :: 128;
|
||||||
|
|
||||||
MAX_KEYS :: 256
|
MAX_KEYS :: 256;
|
||||||
|
|
||||||
Core :: struct {
|
Core :: struct {
|
||||||
stack: ^Bank
|
stack: ^Bank,
|
||||||
storage: ^Bank
|
storage: ^Bank,
|
||||||
|
|
||||||
running: bool
|
running: bool,
|
||||||
key_modifiers: u32
|
key_modifiers: u32,
|
||||||
key_states: [MAX_KEYS]byte
|
key_states: [MAX_KEYS]byte,
|
||||||
key_deltas: [MAX_KEYS]byte
|
key_deltas: [MAX_KEYS]byte,
|
||||||
|
|
||||||
perf_frame,
|
perf_frame,
|
||||||
perf_frame_inner,
|
perf_frame_inner,
|
||||||
@@ -36,70 +37,66 @@ Core :: struct {
|
|||||||
perf_audio,
|
perf_audio,
|
||||||
perf_blit,
|
perf_blit,
|
||||||
perf_blit_cvt,
|
perf_blit_cvt,
|
||||||
perf_blit_gdi: Perf_Span
|
perf_blit_gdi: Perf_Span,
|
||||||
|
|
||||||
frame: i64
|
frame: i64,
|
||||||
|
|
||||||
canvas: Canvas
|
canvas: Canvas,
|
||||||
draw_list: ^Draw_List
|
draw_list: ^Draw_List,
|
||||||
}
|
}
|
||||||
|
|
||||||
Perf_Span :: struct {
|
Perf_Span :: struct {
|
||||||
stamp: f64
|
stamp: f64,
|
||||||
delta: f32
|
delta: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Bank :: struct {
|
Bank :: struct {
|
||||||
memory: []byte
|
memory: []byte,
|
||||||
cursor: int
|
cursor: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
Bank_State :: struct {
|
Bank_State :: struct {
|
||||||
state: Bank
|
state: Bank,
|
||||||
bank: ^Bank
|
bank: ^Bank,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Color :: raw_union {
|
Color :: raw_union {
|
||||||
using channels: struct{ a, b, g, r: byte; }
|
using channels: struct{a, b, g, r: byte},
|
||||||
rgba: u32
|
rgba: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Palette :: struct {
|
Palette :: struct {
|
||||||
colors: [256]Color
|
colors: [256]Color,
|
||||||
colors_count: byte
|
colors_count: byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Rect :: raw_union {
|
Rect :: raw_union {
|
||||||
using minmax: struct {
|
using minmax: struct {min_x, min_y, max_x, max_y: int},
|
||||||
min_x, min_y, max_x, max_y: int
|
using pos: struct {left, top, right, bottom: int},
|
||||||
}
|
e: [4]int,
|
||||||
using pos: struct {
|
|
||||||
left, top, right, bottom: int
|
|
||||||
}
|
|
||||||
e: [4]int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bitmap :: struct {
|
Bitmap :: struct {
|
||||||
pixels: []byte
|
pixels: []byte,
|
||||||
width: int
|
width: int,
|
||||||
height: int
|
height: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
Font :: struct {
|
Font :: struct {
|
||||||
using bitmap: Bitmap
|
using bitmap: Bitmap,
|
||||||
char_width: int
|
char_width: int,
|
||||||
char_height: int
|
char_height: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
Canvas :: struct {
|
Canvas :: struct {
|
||||||
using bitmap: ^Bitmap
|
using bitmap: ^Bitmap,
|
||||||
palette: Palette
|
palette: Palette,
|
||||||
translate_x: int
|
translate_x: int,
|
||||||
translate_y: int
|
translate_y: int,
|
||||||
clip: Rect
|
clip: Rect,
|
||||||
font: ^Font
|
font: ^Font,
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawFlag :: enum {
|
DrawFlag :: enum {
|
||||||
@@ -109,12 +106,9 @@ DrawFlag :: enum {
|
|||||||
MASK = 1<<2,
|
MASK = 1<<2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Draw_Item :: struct {}
|
||||||
Draw_List :: struct {
|
Draw_List :: struct {
|
||||||
Item :: struct {
|
items: []Draw_Item,
|
||||||
|
|
||||||
}
|
|
||||||
items: []Item
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Key :: enum {
|
Key :: enum {
|
||||||
@@ -268,112 +262,112 @@ Key :: enum {
|
|||||||
BACKSLASH = 92, /* \ */
|
BACKSLASH = 92, /* \ */
|
||||||
RIGHT_BRACKET = 93, /* ] */
|
RIGHT_BRACKET = 93, /* ] */
|
||||||
GRAVE_ACCENT = 96, /* ` */
|
GRAVE_ACCENT = 96, /* ` */
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
key_down :: proc(k: Key) -> bool {
|
key_down :: proc(k: Key) -> bool {
|
||||||
return _core.key_states[k] != 0
|
return _core.key_states[k] != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
key_pressed :: proc(k: Key) -> bool {
|
key_pressed :: proc(k: Key) -> bool {
|
||||||
return (_core.key_deltas[k] != 0) && key_down(k)
|
return (_core.key_deltas[k] != 0) && key_down(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
win32_perf_count_freq := win32.GetQueryPerformanceFrequency()
|
win32_perf_count_freq := win32.GetQueryPerformanceFrequency();
|
||||||
time_now :: proc() -> f64 {
|
time_now :: proc() -> f64 {
|
||||||
assert(win32_perf_count_freq != 0)
|
assert(win32_perf_count_freq != 0);
|
||||||
|
|
||||||
counter: i64
|
counter: i64;
|
||||||
win32.QueryPerformanceCounter(^counter)
|
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
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
_core: Core
|
_core: Core;
|
||||||
|
|
||||||
run :: proc(user_init, user_step: proc(c: ^Core)) {
|
run :: proc(user_init, user_step: proc(c: ^Core)) {
|
||||||
using win32
|
using win32;
|
||||||
|
|
||||||
_core.running = true
|
_core.running = true;
|
||||||
|
|
||||||
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline #stdcall {
|
win32_proc :: proc(hwnd: win32.HWND, msg: u32, wparam: win32.WPARAM, lparam: win32.LPARAM) -> win32.LRESULT #no_inline #cc_c {
|
||||||
win32_app_key_mods :: proc() -> u32 {
|
win32_app_key_mods :: proc() -> u32 {
|
||||||
mods: u32 = 0
|
mods: u32 = 0;
|
||||||
|
|
||||||
if is_key_down(Key_Code.SHIFT) {
|
if is_key_down(Key_Code.SHIFT) {
|
||||||
mods |= Key.MOD_SHIFT as u32
|
mods |= cast(u32)Key.MOD_SHIFT;
|
||||||
}
|
}
|
||||||
if is_key_down(Key_Code.CONTROL) {
|
if is_key_down(Key_Code.CONTROL) {
|
||||||
mods |= Key.MOD_CONTROL as u32
|
mods |= cast(u32)Key.MOD_CONTROL;
|
||||||
}
|
}
|
||||||
if is_key_down(Key_Code.MENU) {
|
if is_key_down(Key_Code.MENU) {
|
||||||
mods |= Key.MOD_ALT as u32
|
mods |= cast(u32)Key.MOD_ALT;
|
||||||
}
|
}
|
||||||
if is_key_down(Key_Code.LWIN) || is_key_down(Key_Code.RWIN) {
|
if is_key_down(Key_Code.LWIN) || is_key_down(Key_Code.RWIN) {
|
||||||
mods |= Key.MOD_SUPER as u32
|
mods |= cast(u32)Key.MOD_SUPER;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mods
|
return mods;
|
||||||
}
|
}
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
case WM_KEYDOWN:
|
case WM_KEYDOWN:
|
||||||
_core.key_modifiers = win32_app_key_mods()
|
_core.key_modifiers = win32_app_key_mods();
|
||||||
if wparam < MAX_KEYS {
|
if wparam < MAX_KEYS {
|
||||||
_core.key_states[wparam] = 1
|
_core.key_states[wparam] = 1;
|
||||||
_core.key_deltas[wparam] = 1
|
_core.key_deltas[wparam] = 1;
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
|
|
||||||
case WM_KEYUP:
|
case WM_KEYUP:
|
||||||
_core.key_modifiers = win32_app_key_mods()
|
_core.key_modifiers = win32_app_key_mods();
|
||||||
if wparam < MAX_KEYS {
|
if wparam < MAX_KEYS {
|
||||||
_core.key_states[wparam] = 0
|
_core.key_states[wparam] = 0;
|
||||||
_core.key_deltas[wparam] = 1
|
_core.key_deltas[wparam] = 1;
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
|
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
PostQuitMessage(0)
|
PostQuitMessage(0);
|
||||||
_core.running = false
|
_core.running = false;
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefWindowProcA(hwnd, msg, wparam, lparam)
|
return DefWindowProcA(hwnd, msg, wparam, lparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
window_class := WNDCLASSEXA{
|
window_class := WNDCLASSEXA{
|
||||||
class_name = ("Punity\x00" as string).data, // C-style string
|
class_name = (cast(string)"Punity\x00").data, // C-style string
|
||||||
size = size_of(WNDCLASSEXA) as u32,
|
size = size_of(WNDCLASSEXA),
|
||||||
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
||||||
instance = GetModuleHandleA(nil) as HINSTANCE,
|
instance = cast(HINSTANCE)GetModuleHandleA(nil),
|
||||||
wnd_proc = win32_proc,
|
wnd_proc = win32_proc,
|
||||||
// wnd_proc = DefWindowProcA,
|
// wnd_proc = DefWindowProcA,
|
||||||
background = GetStockObject(BLACK_BRUSH) as HBRUSH,
|
background = cast(HBRUSH)GetStockObject(BLACK_BRUSH),
|
||||||
}
|
};
|
||||||
|
|
||||||
if RegisterClassExA(^window_class) == 0 {
|
if RegisterClassExA(^window_class) == 0 {
|
||||||
fmt.fprintln(os.stderr, "RegisterClassExA failed")
|
fmt.fprintln(os.stderr, "RegisterClassExA failed");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
screen_width := GetSystemMetrics(SM_CXSCREEN)
|
screen_width := GetSystemMetrics(SM_CXSCREEN);
|
||||||
screen_height := GetSystemMetrics(SM_CYSCREEN)
|
screen_height := GetSystemMetrics(SM_CYSCREEN);
|
||||||
|
|
||||||
rc: RECT
|
rc: RECT;
|
||||||
rc.left = (screen_width - WINDOW_WIDTH) / 2
|
rc.left = (screen_width - WINDOW_WIDTH) / 2;
|
||||||
rc.top = (screen_height - WINDOW_HEIGHT) / 2
|
rc.top = (screen_height - WINDOW_HEIGHT) / 2;
|
||||||
rc.right = rc.left + WINDOW_WIDTH
|
rc.right = rc.left + WINDOW_WIDTH;
|
||||||
rc.bottom = rc.top + WINDOW_HEIGHT
|
rc.bottom = rc.top + WINDOW_HEIGHT;
|
||||||
|
|
||||||
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
|
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
||||||
assert(AdjustWindowRect(^rc, style, 0) != 0)
|
assert(AdjustWindowRect(^rc, style, 0) != 0);
|
||||||
|
|
||||||
wt := WINDOW_TITLE
|
wt := WINDOW_TITLE;
|
||||||
|
|
||||||
win32_window := CreateWindowExA(0,
|
win32_window := CreateWindowExA(0,
|
||||||
window_class.class_name,
|
window_class.class_name,
|
||||||
@@ -382,101 +376,114 @@ run :: proc(user_init, user_step: proc(c: ^Core)) {
|
|||||||
rc.left, rc.top,
|
rc.left, rc.top,
|
||||||
rc.right-rc.left, rc.bottom-rc.top,
|
rc.right-rc.left, rc.bottom-rc.top,
|
||||||
nil, nil, window_class.instance,
|
nil, nil, window_class.instance,
|
||||||
nil)
|
nil);
|
||||||
|
|
||||||
if win32_window == nil {
|
if win32_window == nil {
|
||||||
fmt.fprintln(os.stderr, "CreateWindowExA failed")
|
fmt.fprintln(os.stderr, "CreateWindowExA failed");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
window_bmi: BITMAPINFO
|
window_bmi: BITMAPINFO;
|
||||||
window_bmi.size = size_of(BITMAPINFO.HEADER) as u32
|
window_bmi.size = size_of(BITMAPINFOHEADER);
|
||||||
window_bmi.width = CANVAS_WIDTH
|
window_bmi.width = CANVAS_WIDTH;
|
||||||
window_bmi.height = CANVAS_HEIGHT
|
window_bmi.height = CANVAS_HEIGHT;
|
||||||
window_bmi.planes = 1
|
window_bmi.planes = 1;
|
||||||
window_bmi.bit_count = 32
|
window_bmi.bit_count = 32;
|
||||||
window_bmi.compression = BI_RGB
|
window_bmi.compression = BI_RGB;
|
||||||
|
|
||||||
|
|
||||||
user_init(^_core)
|
user_init(^_core);
|
||||||
|
|
||||||
|
ShowWindow(win32_window, SW_SHOW);
|
||||||
|
|
||||||
|
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT);
|
||||||
|
defer free(window_buffer);
|
||||||
|
|
||||||
|
|
||||||
ShowWindow(win32_window, SW_SHOW)
|
for i := 0; i < window_buffer.count; i += 1 {
|
||||||
|
window_buffer[i] = 0xff00ff;
|
||||||
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT)
|
|
||||||
assert(window_buffer.data != nil)
|
|
||||||
defer free(window_buffer.data)
|
|
||||||
|
|
||||||
for i := 0; i < window_buffer.count; i++ {
|
|
||||||
window_buffer[i] = 0xff00ff
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
prev_time, curr_time,dt: f64
|
dt: f64;
|
||||||
prev_time = time_now()
|
prev_time := time_now();
|
||||||
curr_time = time_now()
|
curr_time := time_now();
|
||||||
total_time : f64 = 0
|
total_time : f64 = 0;
|
||||||
offset_x := 0
|
offset_x := 0;
|
||||||
offset_y := 0
|
offset_y := 0;
|
||||||
|
|
||||||
message: MSG
|
message: MSG;
|
||||||
for _core.running {
|
for _core.running {
|
||||||
curr_time = time_now()
|
curr_time = time_now();
|
||||||
dt = curr_time - prev_time
|
dt = curr_time - prev_time;
|
||||||
prev_time = curr_time
|
prev_time = curr_time;
|
||||||
total_time += dt
|
total_time += dt;
|
||||||
|
|
||||||
offset_x += 1
|
offset_x += 1;
|
||||||
offset_y += 2
|
offset_y += 2;
|
||||||
|
|
||||||
{
|
{
|
||||||
data: [128]byte
|
data: [128]byte;
|
||||||
buf := data[:0]
|
buf: fmt.Buffer;
|
||||||
fmt.bprintf(^buf, "Punity: % ms\x00", dt*1000)
|
buf.data = data[:];
|
||||||
win32.SetWindowTextA(win32_window, buf.data)
|
fmt.bprintf(^buf, "Punity: %.4f ms\x00", dt*1000);
|
||||||
|
win32.SetWindowTextA(win32_window, ^buf[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for y := 0; y < CANVAS_HEIGHT; y++ {
|
for y := 0; y < CANVAS_HEIGHT; y += 1 {
|
||||||
for x := 0; x < CANVAS_WIDTH; x++ {
|
for x := 0; x < CANVAS_WIDTH; x += 1 {
|
||||||
g := (x % 32) * 8
|
g := (x % 32) * 8;
|
||||||
b := (y % 32) * 8
|
b := (y % 32) * 8;
|
||||||
window_buffer[x + y*CANVAS_WIDTH] = (g << 8 | b) as u32
|
window_buffer[x + y*CANVAS_WIDTH] = cast(u32)(g << 8 | b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_core.key_deltas = nil
|
mem.zero(^_core.key_deltas[0], size_of_val(_core.key_deltas));
|
||||||
|
|
||||||
for PeekMessageA(^message, nil, 0, 0, PM_REMOVE) != 0 {
|
for PeekMessageA(^message, nil, 0, 0, PM_REMOVE) != 0 {
|
||||||
if message.message == WM_QUIT {
|
if message.message == WM_QUIT {
|
||||||
_core.running = false
|
_core.running = false;
|
||||||
}
|
}
|
||||||
TranslateMessage(^message)
|
TranslateMessage(^message);
|
||||||
DispatchMessageA(^message)
|
DispatchMessageA(^message);
|
||||||
}
|
}
|
||||||
|
|
||||||
user_step(^_core)
|
user_step(^_core);
|
||||||
|
|
||||||
dc := GetDC(win32_window)
|
dc := GetDC(win32_window);
|
||||||
StretchDIBits(dc,
|
StretchDIBits(dc,
|
||||||
0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
|
0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
|
||||||
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
|
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
|
||||||
window_buffer.data,
|
window_buffer.data,
|
||||||
^window_bmi,
|
^window_bmi,
|
||||||
DIB_RGB_COLORS,
|
DIB_RGB_COLORS,
|
||||||
SRCCOPY)
|
SRCCOPY);
|
||||||
ReleaseDC(win32_window, dc)
|
ReleaseDC(win32_window, dc);
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
delta := time_now() - prev_time
|
delta := time_now() - prev_time;
|
||||||
ms := ((FRAME_TIME - delta) * 1000) as i32
|
ms := cast(i32)((FRAME_TIME - delta) * 1000);
|
||||||
if ms > 0 {
|
if ms > 0 {
|
||||||
win32.Sleep(ms)
|
win32.Sleep(ms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_core.frame++
|
_core.frame += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
user_init :: proc(c: ^Core) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
user_step :: proc(c: ^Core) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
run(user_init, user_step);
|
||||||
|
}
|
||||||
|
|||||||
+86
-84
@@ -14,76 +14,93 @@
|
|||||||
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
||||||
// The compiler relies upon this _exact_ order
|
// The compiler relies upon this _exact_ order
|
||||||
Type_Info_Member :: struct #ordered {
|
Type_Info_Member :: struct #ordered {
|
||||||
name: string; // can be empty if tuple
|
name: string, // can be empty if tuple
|
||||||
type_info: ^Type_Info;
|
type_info: ^Type_Info,
|
||||||
offset: int; // offsets are not used in tuples
|
offset: int, // offsets are not used in tuples
|
||||||
}
|
}
|
||||||
Type_Info_Record :: struct #ordered {
|
Type_Info_Record :: struct #ordered {
|
||||||
fields: []Type_Info_Member;
|
fields: []Type_Info_Member,
|
||||||
size: int; // in bytes
|
size: int, // in bytes
|
||||||
align: int; // in bytes
|
align: int, // in bytes
|
||||||
packed: bool;
|
packed: bool,
|
||||||
ordered: bool;
|
ordered: bool,
|
||||||
|
}
|
||||||
|
Type_Info_Enum_Value :: raw_union {
|
||||||
|
f: f64,
|
||||||
|
i: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): This much the same as the compiler's
|
||||||
|
Calling_Convention :: enum {
|
||||||
|
ODIN = 0,
|
||||||
|
C = 1,
|
||||||
|
STD = 2,
|
||||||
|
FAST = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
Type_Info :: union {
|
Type_Info :: union {
|
||||||
Named: struct #ordered {
|
Named: struct #ordered {
|
||||||
name: string;
|
name: string,
|
||||||
base: ^Type_Info; // This will _not_ be a Type_Info.Named
|
base: ^Type_Info, // This will _not_ be a Type_Info.Named
|
||||||
};
|
},
|
||||||
Integer: struct #ordered {
|
Integer: struct #ordered {
|
||||||
size: int; // in bytes
|
size: int, // in bytes
|
||||||
signed: bool;
|
signed: bool,
|
||||||
};
|
},
|
||||||
Float: struct #ordered {
|
Float: struct #ordered {
|
||||||
size: int; // in bytes
|
size: int, // in bytes
|
||||||
};
|
},
|
||||||
Any: struct #ordered {};
|
Any: struct #ordered {},
|
||||||
String: struct #ordered {};
|
String: struct #ordered {},
|
||||||
Boolean: struct #ordered {};
|
Boolean: struct #ordered {},
|
||||||
Pointer: struct #ordered {
|
Pointer: struct #ordered {
|
||||||
elem: ^Type_Info; // nil -> rawptr
|
elem: ^Type_Info, // nil -> rawptr
|
||||||
};
|
},
|
||||||
Maybe: struct #ordered {
|
Maybe: struct #ordered {
|
||||||
elem: ^Type_Info;
|
elem: ^Type_Info,
|
||||||
};
|
},
|
||||||
Procedure: struct #ordered {
|
Procedure: struct #ordered {
|
||||||
params: ^Type_Info; // Type_Info.Tuple
|
params: ^Type_Info, // Type_Info.Tuple
|
||||||
results: ^Type_Info; // Type_Info.Tuple
|
results: ^Type_Info, // Type_Info.Tuple
|
||||||
variadic: bool;
|
variadic: bool,
|
||||||
};
|
convention: Calling_Convention,
|
||||||
|
},
|
||||||
Array: struct #ordered {
|
Array: struct #ordered {
|
||||||
elem: ^Type_Info;
|
elem: ^Type_Info,
|
||||||
elem_size: int;
|
elem_size: int,
|
||||||
count: int;
|
count: int,
|
||||||
};
|
},
|
||||||
Slice: struct #ordered {
|
Slice: struct #ordered {
|
||||||
elem: ^Type_Info;
|
elem: ^Type_Info,
|
||||||
elem_size: int;
|
elem_size: int,
|
||||||
};
|
},
|
||||||
Vector: struct #ordered {
|
Vector: struct #ordered {
|
||||||
elem: ^Type_Info;
|
elem: ^Type_Info,
|
||||||
elem_size: int;
|
elem_size: int,
|
||||||
count: int;
|
count: int,
|
||||||
align: int;
|
align: int,
|
||||||
};
|
},
|
||||||
Tuple: Type_Info_Record;
|
Tuple: Type_Info_Record,
|
||||||
Struct: Type_Info_Record;
|
Struct: Type_Info_Record,
|
||||||
Union: Type_Info_Record;
|
Union: Type_Info_Record,
|
||||||
Raw_Union: Type_Info_Record;
|
Raw_Union: Type_Info_Record,
|
||||||
Enum: struct #ordered {
|
Enum: struct #ordered {
|
||||||
base: ^Type_Info;
|
base: ^Type_Info,
|
||||||
names: []string;
|
names: []string,
|
||||||
// TODO(bill): store values some how. Maybe using a raw_union
|
values: []Type_Info_Enum_Value,
|
||||||
};
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // NOTE(bill): only the ones that are needed (not all types)
|
||||||
|
// // This will be set by the compiler
|
||||||
|
// immutable __type_infos: []Type_Info;
|
||||||
|
|
||||||
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
||||||
if info == nil {
|
if info == nil {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
base := info;
|
base := info;
|
||||||
match type i : base {
|
match type i in base {
|
||||||
case Type_Info.Named:
|
case Type_Info.Named:
|
||||||
base = i.base;
|
base = i.base;
|
||||||
}
|
}
|
||||||
@@ -92,30 +109,15 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
assume :: proc(cond: bool) #foreign "llvm.assume"
|
assume :: proc(cond: bool) #foreign __llvm_core "llvm.assume";
|
||||||
|
|
||||||
__debug_trap :: proc() #foreign "llvm.debugtrap"
|
|
||||||
__trap :: proc() #foreign "llvm.trap"
|
|
||||||
read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
|
|
||||||
|
|
||||||
bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
|
|
||||||
bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
|
|
||||||
bit_reverse64 :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
|
|
||||||
|
|
||||||
byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
|
|
||||||
byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
|
|
||||||
byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
|
|
||||||
|
|
||||||
fmuladd32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
|
|
||||||
fmuladd64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
__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";
|
||||||
|
|
||||||
|
|
||||||
Allocator_Mode :: enum u8 {
|
Allocator_Mode :: enum u8 {
|
||||||
ALLOC = iota,
|
ALLOC,
|
||||||
FREE,
|
FREE,
|
||||||
FREE_ALL,
|
FREE_ALL,
|
||||||
RESIZE,
|
RESIZE,
|
||||||
@@ -124,20 +126,20 @@ Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
|
old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
|
||||||
Allocator :: struct #ordered {
|
Allocator :: struct #ordered {
|
||||||
procedure: Allocator_Proc;
|
procedure: Allocator_Proc,
|
||||||
data: rawptr;
|
data: rawptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Context :: struct #ordered {
|
Context :: struct #ordered {
|
||||||
thread_id: int;
|
thread_id: int,
|
||||||
|
|
||||||
allocator: Allocator;
|
allocator: Allocator,
|
||||||
|
|
||||||
user_data: rawptr;
|
user_data: rawptr,
|
||||||
user_index: int;
|
user_index: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
#thread_local __context: Context;
|
thread_local __context: Context;
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
|
DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
|
||||||
@@ -162,7 +164,7 @@ alloc_align :: proc(size, alignment: int) -> rawptr #inline {
|
|||||||
return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
|
return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
free :: proc(ptr: rawptr) #inline {
|
free_ptr :: proc(ptr: rawptr) #inline {
|
||||||
__check_context();
|
__check_context();
|
||||||
a := context.allocator;
|
a := context.allocator;
|
||||||
if ptr != nil {
|
if ptr != nil {
|
||||||
@@ -220,7 +222,7 @@ default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
case ALLOC:
|
case ALLOC:
|
||||||
total_size := size + alignment + size_of(mem.AllocationHeader);
|
total_size := size + alignment + size_of(mem.AllocationHeader);
|
||||||
ptr := os.heap_alloc(total_size);
|
ptr := os.heap_alloc(total_size);
|
||||||
header := ptr as ^mem.AllocationHeader;
|
header := (^mem.AllocationHeader)(ptr);
|
||||||
ptr = mem.align_forward(header+1, alignment);
|
ptr = mem.align_forward(header+1, alignment);
|
||||||
mem.allocation_header_fill(header, ptr, size);
|
mem.allocation_header_fill(header, ptr, size);
|
||||||
return mem.zero(ptr, size);
|
return mem.zero(ptr, size);
|
||||||
@@ -235,7 +237,7 @@ default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
case RESIZE:
|
case RESIZE:
|
||||||
total_size := size + alignment + size_of(mem.AllocationHeader);
|
total_size := size + alignment + size_of(mem.AllocationHeader);
|
||||||
ptr := os.heap_resize(mem.allocation_header(old_memory), total_size);
|
ptr := os.heap_resize(mem.allocation_header(old_memory), total_size);
|
||||||
header := ptr as ^mem.AllocationHeader;
|
header := (^mem.AllocationHeader)(ptr);
|
||||||
ptr = mem.align_forward(header+1, alignment);
|
ptr = mem.align_forward(header+1, alignment);
|
||||||
mem.allocation_header_fill(header, ptr, size);
|
mem.allocation_header_fill(header, ptr, size);
|
||||||
return mem.zero(ptr, size);
|
return mem.zero(ptr, size);
|
||||||
@@ -284,11 +286,11 @@ __string_eq :: proc(a, b: string) -> bool {
|
|||||||
if a.data == b.data {
|
if a.data == b.data {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return mem.compare(a.data, b.data, a.count) == 0;
|
return mem.compare(cast(rawptr)a.data, cast(rawptr)b.data, a.count) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__string_cmp :: proc(a, b: string) -> int {
|
__string_cmp :: proc(a, b: string) -> int {
|
||||||
return mem.compare(a.data, b.data, min(a.count, b.count));
|
return mem.compare(cast(rawptr)a.data, cast(rawptr)b.data, min(a.count, b.count));
|
||||||
}
|
}
|
||||||
|
|
||||||
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }
|
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }
|
||||||
@@ -299,7 +301,7 @@ __string_ge :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) >=
|
|||||||
|
|
||||||
|
|
||||||
__assert :: proc(file: string, line, column: int, msg: string) #inline {
|
__assert :: proc(file: string, line, column: int, msg: string) #inline {
|
||||||
fmt.fprintf(os.stderr, "%(%:%) Runtime assertion: %\n",
|
fmt.fprintf(os.stderr, "%s(%d:%d) Runtime assertion: %s\n",
|
||||||
file, line, column, msg);
|
file, line, column, msg);
|
||||||
__debug_trap();
|
__debug_trap();
|
||||||
}
|
}
|
||||||
@@ -308,7 +310,7 @@ __bounds_check_error :: proc(file: string, line, column: int, index, count: int)
|
|||||||
if 0 <= index && index < count {
|
if 0 <= index && index < count {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fmt.fprintf(os.stderr, "%(%:%) Index % is out of bounds range 0..<%\n",
|
fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..<%d\n",
|
||||||
file, line, column, index, count);
|
file, line, column, index, count);
|
||||||
__debug_trap();
|
__debug_trap();
|
||||||
}
|
}
|
||||||
@@ -317,7 +319,7 @@ __slice_expr_error :: proc(file: string, line, column: int, low, high: int) {
|
|||||||
if 0 <= low && low <= high {
|
if 0 <= low && low <= high {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fmt.fprintf(os.stderr, "%(%:%) Invalid slice indices: [%:%]\n",
|
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d:%d]\n",
|
||||||
file, line, column, low, high);
|
file, line, column, low, high);
|
||||||
__debug_trap();
|
__debug_trap();
|
||||||
}
|
}
|
||||||
@@ -325,7 +327,7 @@ __substring_expr_error :: proc(file: string, line, column: int, low, high: int)
|
|||||||
if 0 <= low && low <= high {
|
if 0 <= low && low <= high {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fmt.fprintf(os.stderr, "%(%:%) Invalid substring indices: [%:%]\n",
|
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d:%d]\n",
|
||||||
file, line, column, low, high);
|
file, line, column, low, high);
|
||||||
__debug_trap();
|
__debug_trap();
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-31
@@ -11,91 +11,90 @@ sfence :: proc() { win32.WriteBarrier(); }
|
|||||||
lfence :: proc() { win32.ReadBarrier(); }
|
lfence :: proc() { win32.ReadBarrier(); }
|
||||||
|
|
||||||
|
|
||||||
load32 :: proc(a: ^i32) -> i32 {
|
load :: proc(a: ^i32) -> i32 {
|
||||||
return a^;
|
return a^;
|
||||||
}
|
}
|
||||||
store32 :: proc(a: ^i32, value: i32) {
|
store :: proc(a: ^i32, value: i32) {
|
||||||
a^ = value;
|
a^ = value;
|
||||||
}
|
}
|
||||||
compare_exchange32 :: proc(a: ^i32, expected, desired: i32) -> i32 {
|
compare_exchange :: proc(a: ^i32, expected, desired: i32) -> i32 {
|
||||||
return win32.InterlockedCompareExchange(a, desired, expected);
|
return win32.InterlockedCompareExchange(a, desired, expected);
|
||||||
}
|
}
|
||||||
exchanged32 :: proc(a: ^i32, desired: i32) -> i32 {
|
exchanged :: proc(a: ^i32, desired: i32) -> i32 {
|
||||||
return win32.InterlockedExchange(a, desired);
|
return win32.InterlockedExchange(a, desired);
|
||||||
}
|
}
|
||||||
fetch_add32 :: proc(a: ^i32, operand: i32) -> i32 {
|
fetch_add :: proc(a: ^i32, operand: i32) -> i32 {
|
||||||
return win32.InterlockedExchangeAdd(a, operand);
|
return win32.InterlockedExchangeAdd(a, operand);
|
||||||
|
|
||||||
}
|
}
|
||||||
fetch_and32 :: proc(a: ^i32, operand: i32) -> i32 {
|
fetch_and :: proc(a: ^i32, operand: i32) -> i32 {
|
||||||
return win32.InterlockedAnd(a, operand);
|
return win32.InterlockedAnd(a, operand);
|
||||||
|
|
||||||
}
|
}
|
||||||
fetch_or32 :: proc(a: ^i32, operand: i32) -> i32 {
|
fetch_or :: proc(a: ^i32, operand: i32) -> i32 {
|
||||||
return win32.InterlockedOr(a, operand);
|
return win32.InterlockedOr(a, operand);
|
||||||
}
|
}
|
||||||
spin_lock32 :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||||
old_value := compare_exchange32(a, 1, 0);
|
old_value := compare_exchange(a, 1, 0);
|
||||||
counter := 0;
|
counter := 0;
|
||||||
while old_value != 0 && (time_out < 0 || counter < time_out) {
|
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
yield_thread();
|
yield_thread();
|
||||||
old_value = compare_exchange32(a, 1, 0);
|
old_value = compare_exchange(a, 1, 0);
|
||||||
mfence();
|
mfence();
|
||||||
}
|
}
|
||||||
return old_value == 0;
|
return old_value == 0;
|
||||||
}
|
}
|
||||||
spin_unlock32 :: proc(a: ^i32) {
|
spin_unlock :: proc(a: ^i32) {
|
||||||
store32(a, 0);
|
store(a, 0);
|
||||||
mfence();
|
mfence();
|
||||||
}
|
}
|
||||||
try_acquire_lock32 :: proc(a: ^i32) -> bool {
|
try_acquire_lock :: proc(a: ^i32) -> bool {
|
||||||
yield_thread();
|
yield_thread();
|
||||||
old_value := compare_exchange32(a, 1, 0);
|
old_value := compare_exchange(a, 1, 0);
|
||||||
mfence();
|
mfence();
|
||||||
return old_value == 0;
|
return old_value == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
load64 :: proc(a: ^i64) -> i64 {
|
load :: proc(a: ^i64) -> i64 {
|
||||||
return a^;
|
return a^;
|
||||||
}
|
}
|
||||||
store64 :: proc(a: ^i64, value: i64) {
|
store :: proc(a: ^i64, value: i64) {
|
||||||
a^ = value;
|
a^ = value;
|
||||||
}
|
}
|
||||||
compare_exchange64 :: proc(a: ^i64, expected, desired: i64) -> i64 {
|
compare_exchange :: proc(a: ^i64, expected, desired: i64) -> i64 {
|
||||||
return win32.InterlockedCompareExchange64(a, desired, expected);
|
return win32.InterlockedCompareExchange64(a, desired, expected);
|
||||||
}
|
}
|
||||||
exchanged64 :: proc(a: ^i64, desired: i64) -> i64 {
|
exchanged :: proc(a: ^i64, desired: i64) -> i64 {
|
||||||
return win32.InterlockedExchange64(a, desired);
|
return win32.InterlockedExchange64(a, desired);
|
||||||
}
|
}
|
||||||
fetch_add64 :: proc(a: ^i64, operand: i64) -> i64 {
|
fetch_add :: proc(a: ^i64, operand: i64) -> i64 {
|
||||||
return win32.InterlockedExchangeAdd64(a, operand);
|
return win32.InterlockedExchangeAdd64(a, operand);
|
||||||
}
|
}
|
||||||
fetch_and64 :: proc(a: ^i64, operand: i64) -> i64 {
|
fetch_and :: proc(a: ^i64, operand: i64) -> i64 {
|
||||||
return win32.InterlockedAnd64(a, operand);
|
return win32.InterlockedAnd64(a, operand);
|
||||||
}
|
}
|
||||||
fetch_or64 :: proc(a: ^i64, operand: i64) -> i64 {
|
fetch_or :: proc(a: ^i64, operand: i64) -> i64 {
|
||||||
return win32.InterlockedOr64(a, operand);
|
return win32.InterlockedOr64(a, operand);
|
||||||
}
|
}
|
||||||
spin_lock64 :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||||
old_value := compare_exchange64(a, 1, 0);
|
old_value := compare_exchange(a, 1, 0);
|
||||||
counter := 0;
|
counter := 0;
|
||||||
while old_value != 0 && (time_out < 0 || counter < time_out) {
|
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
yield_thread();
|
yield_thread();
|
||||||
old_value = compare_exchange64(a, 1, 0);
|
old_value = compare_exchange(a, 1, 0);
|
||||||
mfence();
|
mfence();
|
||||||
}
|
}
|
||||||
return old_value == 0;
|
return old_value == 0;
|
||||||
}
|
}
|
||||||
spin_unlock64 :: proc(a: ^i64) {
|
spin_unlock :: proc(a: ^i64) {
|
||||||
store64(a, 0);
|
store(a, 0);
|
||||||
mfence();
|
mfence();
|
||||||
}
|
}
|
||||||
try_acquire_lock64 :: proc(a: ^i64) -> bool {
|
try_acquire_lock :: proc(a: ^i64) -> bool {
|
||||||
yield_thread();
|
yield_thread();
|
||||||
old_value := compare_exchange64(a, 1, 0);
|
old_value := compare_exchange(a, 1, 0);
|
||||||
mfence();
|
mfence();
|
||||||
return old_value == 0;
|
return old_value == 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+838
-391
File diff suppressed because it is too large
Load Diff
+39
-39
@@ -1,58 +1,58 @@
|
|||||||
crc32 :: proc(data: rawptr, len: int) -> u32 {
|
crc32 :: proc(data: rawptr, len: int) -> u32 {
|
||||||
result := ~(0 as u32);
|
result := ~cast(u32)0;
|
||||||
s := slice_ptr(data as ^u8, len);
|
s := slice_ptr(cast(^u8)data, len);
|
||||||
for i : 0..<len {
|
for i in 0..<len {
|
||||||
b := s[i] as u32;
|
b := cast(u32)s[i];
|
||||||
result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff];
|
result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff];
|
||||||
}
|
}
|
||||||
return ~result;
|
return ~result;
|
||||||
}
|
}
|
||||||
crc64 :: proc(data: rawptr, len: int) -> u64 {
|
crc64 :: proc(data: rawptr, len: int) -> u64 {
|
||||||
result := ~(0 as u64);
|
result := ~cast(u64)0;
|
||||||
s := slice_ptr(data as ^u8, len);
|
s := slice_ptr(cast(^u8)data, len);
|
||||||
for i : 0..<len {
|
for i in 0..<len {
|
||||||
b := s[i] as u64;
|
b := cast(u64)s[i];
|
||||||
result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff];
|
result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff];
|
||||||
}
|
}
|
||||||
return ~result;
|
return ~result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv32 :: proc(data: rawptr, len: int) -> u32 {
|
fnv32 :: proc(data: rawptr, len: int) -> u32 {
|
||||||
s := slice_ptr(data as ^u8, len);
|
s := slice_ptr(cast(^u8)data, len);
|
||||||
|
|
||||||
h: u32 = 0x811c9dc5;
|
h: u32 = 0x811c9dc5;
|
||||||
for i : 0..<len {
|
for i in 0..<len {
|
||||||
h = (h * 0x01000193) ~ s[i] as u32;
|
h = (h * 0x01000193) ~ cast(u32)s[i];
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv64 :: proc(data: rawptr, len: int) -> u64 {
|
fnv64 :: proc(data: rawptr, len: int) -> u64 {
|
||||||
s := slice_ptr(data as ^u8, len);
|
s := slice_ptr(cast(^u8)data, len);
|
||||||
|
|
||||||
h: u64 = 0xcbf29ce484222325;
|
h: u64 = 0xcbf29ce484222325;
|
||||||
for i : 0..<len {
|
for i in 0..<len {
|
||||||
h = (h * 0x100000001b3) ~ s[i] as u64;
|
h = (h * 0x100000001b3) ~ cast(u64)s[i];
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv32a :: proc(data: rawptr, len: int) -> u32 {
|
fnv32a :: proc(data: rawptr, len: int) -> u32 {
|
||||||
s := slice_ptr(data as ^u8, len);
|
s := slice_ptr(cast(^u8)data, len);
|
||||||
|
|
||||||
h: u32 = 0x811c9dc5;
|
h: u32 = 0x811c9dc5;
|
||||||
for i : 0..<len {
|
for i in 0..<len {
|
||||||
h = (h ~ s[i] as u32) * 0x01000193;
|
h = (h ~ cast(u32)s[i]) * 0x01000193;
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv64a :: proc(data: rawptr, len: int) -> u64 {
|
fnv64a :: proc(data: rawptr, len: int) -> u64 {
|
||||||
s := slice_ptr(data as ^u8, len);
|
s := slice_ptr(cast(^u8)data, len);
|
||||||
|
|
||||||
h :u64 = 0xcbf29ce484222325;
|
h :u64 = 0xcbf29ce484222325;
|
||||||
for i : 0..<len {
|
for i in 0..<len {
|
||||||
h = (h ~ s[i] as u64) * 0x100000001b3;
|
h = (h ~ cast(u64)s[i]) * 0x100000001b3;
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
@@ -65,12 +65,12 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
|||||||
m :: 0xc6a4a7935bd1e995;
|
m :: 0xc6a4a7935bd1e995;
|
||||||
r :: 47;
|
r :: 47;
|
||||||
|
|
||||||
h: u64 = SEED ~ (len as u64 * m);
|
h: u64 = SEED ~ (cast(u64)len * m);
|
||||||
|
|
||||||
data := slice_ptr(data_ as ^u64, len/size_of(u64));
|
data := slice_ptr(cast(^u64)data_, len/size_of(u64));
|
||||||
data2 := slice_ptr(data_ as ^u8, len);
|
data2 := slice_ptr(cast(^u8)data_, len);
|
||||||
|
|
||||||
for i : 0 ..< data.count {
|
for i in 0 ..< data.count {
|
||||||
k := data[i];
|
k := data[i];
|
||||||
|
|
||||||
k *= m;
|
k *= m;
|
||||||
@@ -82,14 +82,14 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match len & 7 {
|
match len & 7 {
|
||||||
case 7: h ~= data2[6] as u64 << 48; fallthrough;
|
case 7: h ~= cast(u64)data2[6] << 48; fallthrough;
|
||||||
case 6: h ~= data2[5] as u64 << 40; fallthrough;
|
case 6: h ~= cast(u64)data2[5] << 40; fallthrough;
|
||||||
case 5: h ~= data2[4] as u64 << 32; fallthrough;
|
case 5: h ~= cast(u64)data2[4] << 32; fallthrough;
|
||||||
case 4: h ~= data2[3] as u64 << 24; fallthrough;
|
case 4: h ~= cast(u64)data2[3] << 24; fallthrough;
|
||||||
case 3: h ~= data2[2] as u64 << 16; fallthrough;
|
case 3: h ~= cast(u64)data2[2] << 16; fallthrough;
|
||||||
case 2: h ~= data2[1] as u64 << 8; fallthrough;
|
case 2: h ~= cast(u64)data2[1] << 8; fallthrough;
|
||||||
case 1:
|
case 1:
|
||||||
h ~= data2[0] as u64;
|
h ~= cast(u64)data2[0];
|
||||||
h *= m;
|
h *= m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,13 +102,13 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
|||||||
m :: 0x5bd1e995;
|
m :: 0x5bd1e995;
|
||||||
r :: 24;
|
r :: 24;
|
||||||
|
|
||||||
h1: u32 = SEED as u32 ~ len as u32;
|
h1: u32 = cast(u32)SEED ~ cast(u32)len;
|
||||||
h2: u32 = SEED >> 32;
|
h2: u32 = SEED >> 32;
|
||||||
|
|
||||||
data := slice_ptr(data_ as ^u32, len/size_of(u32));
|
data := slice_ptr(cast(^u32)data_, len/size_of(u32));
|
||||||
|
|
||||||
i := 0;
|
i := 0;
|
||||||
while len >= 8 {
|
for len >= 8 {
|
||||||
k1, k2: u32;
|
k1, k2: u32;
|
||||||
k1 = data[i]; i += 1;
|
k1 = data[i]; i += 1;
|
||||||
k1 *= m;
|
k1 *= m;
|
||||||
@@ -138,13 +138,13 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
|||||||
len -= 4;
|
len -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
data8 := slice_ptr((data.data+i) as ^u8, 3); // NOTE(bill): This is unsafe
|
data8 := slice_ptr(cast(^u8)(data.data+i), 3); // NOTE(bill): This is unsafe
|
||||||
|
|
||||||
match len {
|
match len {
|
||||||
case 3: h2 ~= data8[2] as u32 << 16; fallthrough;
|
case 3: h2 ~= cast(u32)data8[2] << 16; fallthrough;
|
||||||
case 2: h2 ~= data8[1] as u32 << 8; fallthrough;
|
case 2: h2 ~= cast(u32)data8[1] << 8; fallthrough;
|
||||||
case 1:
|
case 1:
|
||||||
h2 ~= data8[0] as u32;
|
h2 ~= cast(u32)data8[0];
|
||||||
h2 *= m;
|
h2 *= m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
|||||||
h2 ~= h1>>19;
|
h2 ~= h1>>19;
|
||||||
h2 *= m;
|
h2 *= m;
|
||||||
|
|
||||||
h := (h1 as u64)<<32 | h2 as u64;
|
h := cast(u64)(h1)<<32 | cast(u64)(h2);
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+75
-65
@@ -24,63 +24,73 @@ Mat2 :: [2]Vec2;
|
|||||||
Mat3 :: [3]Vec3;
|
Mat3 :: [3]Vec3;
|
||||||
Mat4 :: [4]Vec4;
|
Mat4 :: [4]Vec4;
|
||||||
|
|
||||||
sqrt32 :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
|
sqrt :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32";
|
||||||
sqrt64 :: proc(x: f64) -> f64 #foreign "llvm.sqrt.f64"
|
sqrt :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64";
|
||||||
|
|
||||||
sin32 :: proc(x: f32) -> f32 #foreign "llvm.sin.f32"
|
sin :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sin.f32";
|
||||||
sin64 :: proc(x: f64) -> f64 #foreign "llvm.sin.f64"
|
sin :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sin.f64";
|
||||||
|
|
||||||
cos32 :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
|
cos :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.cos.f32";
|
||||||
cos64 :: proc(x: f64) -> f64 #foreign "llvm.cos.f64"
|
cos :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.cos.f64";
|
||||||
|
|
||||||
tan32 :: proc(x: f32) -> f32 #inline { return sin32(x)/cos32(x); }
|
tan :: proc(x: f32) -> f32 #inline { return sin(x)/cos(x); }
|
||||||
tan64 :: proc(x: f64) -> f64 #inline { return sin64(x)/cos64(x); }
|
tan :: proc(x: f64) -> f64 #inline { return sin(x)/cos(x); }
|
||||||
|
|
||||||
lerp32 :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
|
lerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
|
||||||
lerp64 :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
|
lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
|
||||||
|
|
||||||
sign32 :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
|
sign :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
|
||||||
sign64 :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
|
sign :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
|
||||||
|
|
||||||
|
bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16";
|
||||||
|
bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32";
|
||||||
|
bit_reverse :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bitreverse.i64";
|
||||||
|
|
||||||
|
byte_swap :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bswap.i16";
|
||||||
|
byte_swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32";
|
||||||
|
byte_swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64";
|
||||||
|
|
||||||
|
fmuladd :: proc(a, b, c: f32) -> f32 #foreign __llvm_core "llvm.fmuladd.f32";
|
||||||
|
fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64";
|
||||||
|
|
||||||
|
|
||||||
|
copy_sign :: proc(x, y: f32) -> f32 {
|
||||||
copy_sign32 :: proc(x, y: f32) -> f32 {
|
ix := transmute(u32)x;
|
||||||
ix := x transmute u32;
|
iy := transmute(u32)y;
|
||||||
iy := y transmute u32;
|
|
||||||
ix &= 0x7fffffff;
|
ix &= 0x7fffffff;
|
||||||
ix |= iy & 0x80000000;
|
ix |= iy & 0x80000000;
|
||||||
return ix transmute f32;
|
return transmute(f32)ix;
|
||||||
}
|
}
|
||||||
round32 :: proc(x: f32) -> f32 {
|
round :: proc(x: f32) -> f32 {
|
||||||
if x >= 0 {
|
if x >= 0 {
|
||||||
return floor32(x + 0.5);
|
return floor(x + 0.5);
|
||||||
}
|
}
|
||||||
return ceil32(x - 0.5);
|
return ceil(x - 0.5);
|
||||||
}
|
}
|
||||||
floor32 :: proc(x: f32) -> f32 {
|
floor :: proc(x: f32) -> f32 {
|
||||||
if x >= 0 {
|
if x >= 0 {
|
||||||
return x as int as f32;
|
return cast(f32)cast(int)x;
|
||||||
}
|
}
|
||||||
return (x-0.5) as int as f32;
|
return cast(f32)cast(int)(x-0.5);
|
||||||
}
|
}
|
||||||
ceil32 :: proc(x: f32) -> f32 {
|
ceil :: proc(x: f32) -> f32 {
|
||||||
if x < 0 {
|
if x < 0 {
|
||||||
return x as int as f32;
|
return cast(f32)cast(int)x;
|
||||||
}
|
}
|
||||||
return ((x as int)+1) as f32;
|
return cast(f32)cast(int)(x+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
remainder32 :: proc(x, y: f32) -> f32 {
|
remainder32 :: proc(x, y: f32) -> f32 {
|
||||||
return x - round32(x/y) * y;
|
return x - round(x/y) * y;
|
||||||
}
|
}
|
||||||
|
|
||||||
fmod32 :: proc(x, y: f32) -> f32 {
|
fmod32 :: proc(x, y: f32) -> f32 {
|
||||||
y = abs(y);
|
y = abs(y);
|
||||||
result := remainder32(abs(x), y);
|
result := remainder32(abs(x), y);
|
||||||
if sign32(result) < 0 {
|
if sign(result) < 0 {
|
||||||
result += y;
|
result += y;
|
||||||
}
|
}
|
||||||
return copy_sign32(result, x);
|
return copy_sign(result, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -90,43 +100,43 @@ to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
dot2 :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y; }
|
dot :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y; }
|
||||||
dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
|
dot :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
|
||||||
dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
|
dot :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
|
||||||
|
|
||||||
cross3 :: proc(x, y: Vec3) -> Vec3 {
|
cross :: proc(x, y: Vec3) -> Vec3 {
|
||||||
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
|
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
|
||||||
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
|
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
|
||||||
return a - b;
|
return a - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vec2_mag :: proc(v: Vec2) -> f32 { return sqrt32(dot2(v, v)); }
|
mag :: proc(v: Vec2) -> f32 { return sqrt(dot(v, v)); }
|
||||||
vec3_mag :: proc(v: Vec3) -> f32 { return sqrt32(dot3(v, v)); }
|
mag :: proc(v: Vec3) -> f32 { return sqrt(dot(v, v)); }
|
||||||
vec4_mag :: proc(v: Vec4) -> f32 { return sqrt32(dot4(v, v)); }
|
mag :: proc(v: Vec4) -> f32 { return sqrt(dot(v, v)); }
|
||||||
|
|
||||||
vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; }
|
norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{mag(v)}; }
|
||||||
vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; }
|
norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{mag(v)}; }
|
||||||
vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; }
|
norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{mag(v)}; }
|
||||||
|
|
||||||
vec2_norm0 :: proc(v: Vec2) -> Vec2 {
|
norm0 :: proc(v: Vec2) -> Vec2 {
|
||||||
m := vec2_mag(v);
|
m := mag(v);
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
return Vec2{0};
|
return Vec2{0};
|
||||||
}
|
}
|
||||||
return v / Vec2{m};
|
return v / Vec2{m};
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3_norm0 :: proc(v: Vec3) -> Vec3 {
|
norm0 :: proc(v: Vec3) -> Vec3 {
|
||||||
m := vec3_mag(v);
|
m := mag(v);
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
return Vec3{0};
|
return Vec3{0};
|
||||||
}
|
}
|
||||||
return v / Vec3{m};
|
return v / Vec3{m};
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4_norm0 :: proc(v: Vec4) -> Vec4 {
|
norm0 :: proc(v: Vec4) -> Vec4 {
|
||||||
m := vec4_mag(v);
|
m := mag(v);
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
return Vec4{0};
|
return Vec4{0};
|
||||||
}
|
}
|
||||||
@@ -145,18 +155,18 @@ mat4_identity :: proc() -> Mat4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
||||||
for j : 0..<4 {
|
for j in 0..<4 {
|
||||||
for i : 0..<4 {
|
for i in 0..<4 {
|
||||||
m[i][j], m[j][i] = m[j][i], m[i][j];
|
m[i][j], m[j][i] = m[j][i], m[i][j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
|
mul :: proc(a, b: Mat4) -> Mat4 {
|
||||||
c: Mat4;
|
c: Mat4;
|
||||||
for j : 0..<4 {
|
for j in 0..<4 {
|
||||||
for i : 0..<4 {
|
for i in 0..<4 {
|
||||||
c[j][i] = a[0][i]*b[j][0] +
|
c[j][i] = a[0][i]*b[j][0] +
|
||||||
a[1][i]*b[j][1] +
|
a[1][i]*b[j][1] +
|
||||||
a[2][i]*b[j][2] +
|
a[2][i]*b[j][2] +
|
||||||
@@ -166,7 +176,7 @@ mat4_mul :: proc(a, b: Mat4) -> Mat4 {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
mul :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||||
return Vec4{
|
return Vec4{
|
||||||
m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
|
m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
|
||||||
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
|
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
|
||||||
@@ -175,7 +185,7 @@ mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_inverse :: proc(m: Mat4) -> Mat4 {
|
inverse :: proc(m: Mat4) -> Mat4 {
|
||||||
o: Mat4;
|
o: Mat4;
|
||||||
|
|
||||||
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
|
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
|
||||||
@@ -254,10 +264,10 @@ mat4_translate :: proc(v: Vec3) -> Mat4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
||||||
c := cos32(angle_radians);
|
c := cos(angle_radians);
|
||||||
s := sin32(angle_radians);
|
s := sin(angle_radians);
|
||||||
|
|
||||||
a := vec3_norm(v);
|
a := norm(v);
|
||||||
t := a * Vec3{1-c};
|
t := a * Vec3{1-c};
|
||||||
|
|
||||||
rot := mat4_identity();
|
rot := mat4_identity();
|
||||||
@@ -280,14 +290,14 @@ mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
|||||||
return rot;
|
return rot;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
||||||
m[0][0] *= v.x;
|
m[0][0] *= v.x;
|
||||||
m[1][1] *= v.y;
|
m[1][1] *= v.y;
|
||||||
m[2][2] *= v.z;
|
m[2][2] *= v.z;
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_scalef :: proc(m: Mat4, s: f32) -> Mat4 {
|
scale :: proc(m: Mat4, s: f32) -> Mat4 {
|
||||||
m[0][0] *= s;
|
m[0][0] *= s;
|
||||||
m[1][1] *= s;
|
m[1][1] *= s;
|
||||||
m[2][2] *= s;
|
m[2][2] *= s;
|
||||||
@@ -295,23 +305,23 @@ mat4_scalef :: proc(m: Mat4, s: f32) -> Mat4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mat4_look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
||||||
f := vec3_norm(centre - eye);
|
f := norm(centre - eye);
|
||||||
s := vec3_norm(cross3(f, up));
|
s := norm(cross(f, up));
|
||||||
u := cross3(s, f);
|
u := cross(s, f);
|
||||||
|
|
||||||
m: Mat4;
|
m: Mat4;
|
||||||
|
|
||||||
m[0] = Vec4{+s.x, +s.y, +s.z, 0};
|
m[0] = Vec4{+s.x, +s.y, +s.z, 0};
|
||||||
m[1] = Vec4{+u.x, +u.y, +u.z, 0};
|
m[1] = Vec4{+u.x, +u.y, +u.z, 0};
|
||||||
m[2] = Vec4{-f.x, -f.y, -f.z, 0};
|
m[2] = Vec4{-f.x, -f.y, -f.z, 0};
|
||||||
m[3] = Vec4{dot3(s, eye), dot3(u, eye), dot3(f, eye), 1};
|
m[3] = Vec4{dot(s, eye), dot(u, eye), dot(f, eye), 1};
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
||||||
m: Mat4;
|
m: Mat4;
|
||||||
tan_half_fovy := tan32(0.5 * fovy);
|
tan_half_fovy := tan(0.5 * fovy);
|
||||||
m[0][0] = 1.0 / (aspect*tan_half_fovy);
|
m[0][0] = 1.0 / (aspect*tan_half_fovy);
|
||||||
m[1][1] = 1.0 / (tan_half_fovy);
|
m[1][1] = 1.0 / (tan_half_fovy);
|
||||||
m[2][2] = -(far + near) / (far - near);
|
m[2][2] = -(far + near) / (far - near);
|
||||||
@@ -321,7 +331,7 @@ mat4_perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mat4_ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
|
ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
|
||||||
m := mat4_identity();
|
m := mat4_identity();
|
||||||
m[0][0] = +2.0 / (right - left);
|
m[0][0] = +2.0 / (right - left);
|
||||||
m[1][1] = +2.0 / (top - bottom);
|
m[1][1] = +2.0 / (top - bottom);
|
||||||
|
|||||||
+29
-30
@@ -2,8 +2,8 @@
|
|||||||
#import "os.odin";
|
#import "os.odin";
|
||||||
|
|
||||||
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
|
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
|
||||||
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
|
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memset.p0i8.i64";
|
||||||
llvm_memset_64bit(data, value as byte, len, 1, false);
|
llvm_memset_64bit(data, cast(byte)value, len, 1, false);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,22 +13,22 @@ zero :: proc(data: rawptr, len: int) -> rawptr #link_name "__mem_zero" {
|
|||||||
|
|
||||||
copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
|
copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
|
||||||
// NOTE(bill): This _must_ implemented like C's memmove
|
// NOTE(bill): This _must_ implemented like C's memmove
|
||||||
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
|
llvm_memmove_64bit :: 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);
|
llvm_memmove_64bit(dst, src, len, 1, false);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
|
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
|
||||||
// NOTE(bill): This _must_ implemented like C's memcpy
|
// NOTE(bill): This _must_ implemented like C's memcpy
|
||||||
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
|
llvm_memcpy_64bit :: 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);
|
llvm_memcpy_64bit(dst, src, len, 1, false);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
|
compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
|
||||||
a := slice_ptr(dst as ^byte, n);
|
a := slice_ptr(cast(^byte)dst, n);
|
||||||
b := slice_ptr(src as ^byte, n);
|
b := slice_ptr(cast(^byte)src, n);
|
||||||
for i : 0..<n {
|
for i in 0..<n {
|
||||||
match {
|
match {
|
||||||
case a[i] < b[i]:
|
case a[i] < b[i]:
|
||||||
return -1;
|
return -1;
|
||||||
@@ -56,36 +56,35 @@ is_power_of_two :: proc(x: int) -> bool {
|
|||||||
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
|
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
|
||||||
assert(is_power_of_two(align));
|
assert(is_power_of_two(align));
|
||||||
|
|
||||||
a := align as uint;
|
a := cast(uint)align;
|
||||||
p := ptr as uint;
|
p := cast(uint)ptr;
|
||||||
modulo := p & (a-1);
|
modulo := p & (a-1);
|
||||||
if modulo != 0 {
|
if modulo != 0 {
|
||||||
p += a - modulo;
|
p += a - modulo;
|
||||||
}
|
}
|
||||||
return p as rawptr;
|
return cast(rawptr)p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Allocation_Header :: struct {
|
Allocation_Header :: struct {
|
||||||
size: int;
|
size: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) {
|
allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) {
|
||||||
header.size = size;
|
header.size = size;
|
||||||
ptr := (header+1) as ^int;
|
ptr := cast(^int)(header+1);
|
||||||
|
|
||||||
while i := 0; ptr as rawptr < data {
|
for i := 0; cast(rawptr)ptr < data; i += 1 {
|
||||||
(ptr+i)^ = -1;
|
(ptr+i)^ = -1;
|
||||||
i += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
|
allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
|
||||||
p := data as ^int;
|
p := cast(^int)data;
|
||||||
while (p-1)^ == -1 {
|
for (p-1)^ == -1 {
|
||||||
p = (p-1);
|
p = (p-1);
|
||||||
}
|
}
|
||||||
return (p as ^Allocation_Header)-1;
|
return cast(^Allocation_Header)p-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -94,15 +93,15 @@ allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
|
|||||||
|
|
||||||
// Custom allocators
|
// Custom allocators
|
||||||
Arena :: struct {
|
Arena :: struct {
|
||||||
backing: Allocator;
|
backing: Allocator,
|
||||||
offset: int;
|
offset: int,
|
||||||
memory: []byte;
|
memory: []byte,
|
||||||
temp_count: int;
|
temp_count: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
Arena_Temp_Memory :: struct {
|
Arena_Temp_Memory :: struct {
|
||||||
arena: ^Arena;
|
arena: ^Arena,
|
||||||
original_count: int;
|
original_count: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -124,8 +123,8 @@ init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
|||||||
free_arena :: proc(using a: ^Arena) {
|
free_arena :: proc(using a: ^Arena) {
|
||||||
if backing.procedure != nil {
|
if backing.procedure != nil {
|
||||||
push_allocator backing {
|
push_allocator backing {
|
||||||
free(memory.data);
|
free(memory);
|
||||||
memory = memory[0:0];
|
memory = nil;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,7 +141,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||||
using Allocator_Mode;
|
using Allocator_Mode;
|
||||||
arena := allocator_data as ^Arena;
|
arena := cast(^Arena)allocator_data;
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
case ALLOC:
|
case ALLOC:
|
||||||
@@ -212,7 +211,7 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
|||||||
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
|
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
|
||||||
using Type_Info;
|
using Type_Info;
|
||||||
|
|
||||||
match type info : type_info {
|
match type info in type_info {
|
||||||
case Named:
|
case Named:
|
||||||
return align_of_type_info(info.base);
|
return align_of_type_info(info.base);
|
||||||
case Integer:
|
case Integer:
|
||||||
@@ -235,7 +234,7 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
|||||||
return WORD_SIZE;
|
return WORD_SIZE;
|
||||||
case Vector:
|
case Vector:
|
||||||
size := size_of_type_info(info.elem);
|
size := size_of_type_info(info.elem);
|
||||||
count := max(prev_pow2(info.count as i64), 1) as int;
|
count := cast(int)max(prev_pow2(cast(i64)info.count), 1);
|
||||||
total := size * count;
|
total := size * count;
|
||||||
return clamp(total, 1, MAX_ALIGN);
|
return clamp(total, 1, MAX_ALIGN);
|
||||||
case Struct:
|
case Struct:
|
||||||
@@ -257,7 +256,7 @@ align_formula :: proc(size, align: int) -> int {
|
|||||||
size_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
size_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||||
WORD_SIZE :: size_of(int);
|
WORD_SIZE :: size_of(int);
|
||||||
using Type_Info;
|
using Type_Info;
|
||||||
match type info : type_info {
|
match type info in type_info {
|
||||||
case Named:
|
case Named:
|
||||||
return size_of_type_info(info.base);
|
return size_of_type_info(info.base);
|
||||||
case Integer:
|
case Integer:
|
||||||
@@ -289,7 +288,7 @@ size_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
|||||||
return 3*WORD_SIZE;
|
return 3*WORD_SIZE;
|
||||||
case Vector:
|
case Vector:
|
||||||
is_bool :: proc(type_info: ^Type_Info) -> bool {
|
is_bool :: proc(type_info: ^Type_Info) -> bool {
|
||||||
match type info : type_info {
|
match type info in type_info {
|
||||||
case Named:
|
case Named:
|
||||||
return is_bool(info.base);
|
return is_bool(info.base);
|
||||||
case Boolean:
|
case Boolean:
|
||||||
|
|||||||
+26
-25
@@ -1,36 +1,37 @@
|
|||||||
#foreign_system_library "opengl32" when ODIN_OS == "windows";
|
#foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
|
||||||
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
||||||
#include "opengl_constants.odin";
|
#include "opengl_constants.odin";
|
||||||
|
|
||||||
Clear :: proc(mask: u32) #foreign "glClear"
|
Clear :: proc(mask: u32) #foreign lib "glClear";
|
||||||
ClearColor :: proc(r, g, b, a: f32) #foreign "glClearColor"
|
ClearColor :: proc(r, g, b, a: f32) #foreign lib "glClearColor";
|
||||||
Begin :: proc(mode: i32) #foreign "glBegin"
|
Begin :: proc(mode: i32) #foreign lib "glBegin";
|
||||||
End :: proc() #foreign "glEnd"
|
End :: proc() #foreign lib "glEnd";
|
||||||
Finish :: proc() #foreign "glFinish"
|
Finish :: proc() #foreign lib "glFinish";
|
||||||
BlendFunc :: proc(sfactor, dfactor: i32) #foreign "glBlendFunc"
|
BlendFunc :: proc(sfactor, dfactor: i32) #foreign lib "glBlendFunc";
|
||||||
Enable :: proc(cap: i32) #foreign "glEnable"
|
Enable :: proc(cap: i32) #foreign lib "glEnable";
|
||||||
Disable :: proc(cap: i32) #foreign "glDisable"
|
Disable :: proc(cap: i32) #foreign lib "glDisable";
|
||||||
GenTextures :: proc(count: i32, result: ^u32) #foreign "glGenTextures"
|
GenTextures :: proc(count: i32, result: ^u32) #foreign lib "glGenTextures";
|
||||||
DeleteTextures:: proc(count: i32, result: ^u32) #foreign "glDeleteTextures"
|
DeleteTextures:: proc(count: i32, result: ^u32) #foreign lib "glDeleteTextures";
|
||||||
TexParameteri :: proc(target, pname, param: i32) #foreign "glTexParameteri"
|
TexParameteri :: proc(target, pname, param: i32) #foreign lib "glTexParameteri";
|
||||||
TexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign "glTexParameterf"
|
TexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign lib "glTexParameterf";
|
||||||
BindTexture :: proc(target: i32, texture: u32) #foreign "glBindTexture"
|
BindTexture :: proc(target: i32, texture: u32) #foreign lib "glBindTexture";
|
||||||
LoadIdentity :: proc() #foreign "glLoadIdentity"
|
LoadIdentity :: proc() #foreign lib "glLoadIdentity";
|
||||||
Viewport :: proc(x, y, width, height: i32) #foreign "glViewport"
|
Viewport :: proc(x, y, width, height: i32) #foreign lib "glViewport";
|
||||||
Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign "glOrtho"
|
Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign lib "glOrtho";
|
||||||
Color3f :: proc(r, g, b: f32) #foreign "glColor3f"
|
Color3f :: proc(r, g, b: f32) #foreign lib "glColor3f";
|
||||||
Vertex3f :: proc(x, y, z: f32) #foreign "glVertex3f"
|
Vertex3f :: proc(x, y, z: f32) #foreign lib "glVertex3f";
|
||||||
TexImage2D :: proc(target, level, internal_format,
|
TexImage2D :: proc(target, level, internal_format,
|
||||||
width, height, border,
|
width, height, border,
|
||||||
format, _type: i32, pixels: rawptr) #foreign "glTexImage2D"
|
format, _type: i32, pixels: rawptr) #foreign lib "glTexImage2D";
|
||||||
|
|
||||||
GetError :: proc() -> i32 #foreign "glGetError"
|
GetError :: proc() -> i32 #foreign lib "glGetError";
|
||||||
GetString :: proc(name: i32) -> ^byte #foreign "glGetString"
|
GetString :: proc(name: i32) -> ^byte #foreign lib "glGetString";
|
||||||
GetIntegerv :: proc(name: i32, v: ^i32) #foreign "glGetIntegerv"
|
GetIntegerv :: proc(name: i32, v: ^i32) #foreign lib "glGetIntegerv";
|
||||||
|
|
||||||
|
|
||||||
|
string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; }
|
||||||
|
|
||||||
_libgl := win32.LoadLibraryA(("opengl32.dll\x00" as string).data);
|
_libgl := win32.LoadLibraryA(string_data("opengl32.dll\x00"));
|
||||||
|
|
||||||
GetProcAddress :: proc(name: string) -> proc() #cc_c {
|
GetProcAddress :: proc(name: string) -> proc() #cc_c {
|
||||||
assert(name[name.count-1] == 0);
|
assert(name[name.count-1] == 0);
|
||||||
@@ -100,7 +101,7 @@ UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c
|
|||||||
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
|
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
|
||||||
|
|
||||||
init :: proc() {
|
init :: proc() {
|
||||||
set_proc_address :: proc(p: rawptr, name: string) #inline { (p as ^(proc() #cc_c))^ = GetProcAddress(name); }
|
set_proc_address :: proc(p: rawptr, name: string) #inline { (cast(^(proc() #cc_c))p)^ = GetProcAddress(name); }
|
||||||
|
|
||||||
set_proc_address(^GenBuffers, "glGenBuffers\x00");
|
set_proc_address(^GenBuffers, "glGenBuffers\x00");
|
||||||
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
|
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
|
||||||
|
|||||||
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
#include "os_windows.odin" when ODIN_OS == "windows"
|
#include "os_windows.odin" when ODIN_OS == "windows";
|
||||||
|
|
||||||
|
|||||||
+34
-35
@@ -73,7 +73,7 @@ open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
|
|||||||
access |= FILE_APPEND_DATA;
|
access |= FILE_APPEND_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
share_mode := (FILE_SHARE_READ|FILE_SHARE_WRITE) as u32;
|
share_mode := cast(u32)(FILE_SHARE_READ|FILE_SHARE_WRITE);
|
||||||
sa: ^SECURITY_ATTRIBUTES = nil;
|
sa: ^SECURITY_ATTRIBUTES = nil;
|
||||||
sa_inherit := SECURITY_ATTRIBUTES{length = size_of(SECURITY_ATTRIBUTES), inherit_handle = 1};
|
sa_inherit := SECURITY_ATTRIBUTES{length = size_of(SECURITY_ATTRIBUTES), inherit_handle = 1};
|
||||||
if mode&O_CLOEXEC == 0 {
|
if mode&O_CLOEXEC == 0 {
|
||||||
@@ -95,38 +95,38 @@ open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf: [300]byte;
|
buf: [300]byte;
|
||||||
copy(buf[:], path as []byte);
|
copy(buf[:], cast([]byte)path);
|
||||||
|
|
||||||
handle := CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil) as Handle;
|
handle := cast(Handle)CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil);
|
||||||
if handle != INVALID_HANDLE {
|
if handle != INVALID_HANDLE {
|
||||||
return handle, ERROR_NONE;
|
return handle, ERROR_NONE;
|
||||||
}
|
}
|
||||||
err := GetLastError();
|
err := GetLastError();
|
||||||
return INVALID_HANDLE, err as Errno;
|
return INVALID_HANDLE, cast(Errno)err;
|
||||||
}
|
}
|
||||||
|
|
||||||
close :: proc(fd: Handle) {
|
close :: proc(fd: Handle) {
|
||||||
win32.CloseHandle(fd as win32.HANDLE);
|
win32.CloseHandle(cast(win32.HANDLE)fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
bytes_written: i32;
|
bytes_written: i32;
|
||||||
e := win32.WriteFile(fd as win32.HANDLE, data.data, data.count as i32, ^bytes_written, nil);
|
e := win32.WriteFile(cast(win32.HANDLE)fd, data.data, cast(i32)data.count, ^bytes_written, nil);
|
||||||
if e == win32.FALSE {
|
if e == win32.FALSE {
|
||||||
err := win32.GetLastError();
|
err := win32.GetLastError();
|
||||||
return 0, err as Errno;
|
return 0, cast(Errno)err;
|
||||||
}
|
}
|
||||||
return bytes_written as int, ERROR_NONE;
|
return cast(int)bytes_written, ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
bytes_read: i32;
|
bytes_read: i32;
|
||||||
e := win32.ReadFile(fd as win32.HANDLE, data.data, data.count as u32, ^bytes_read, nil);
|
e := win32.ReadFile(cast(win32.HANDLE)fd, data.data, cast(u32)data.count, ^bytes_read, nil);
|
||||||
if e == win32.FALSE {
|
if e == win32.FALSE {
|
||||||
err := win32.GetLastError();
|
err := win32.GetLastError();
|
||||||
return 0, err as Errno;
|
return 0, cast(Errno)err;
|
||||||
}
|
}
|
||||||
return bytes_read as int, ERROR_NONE;
|
return cast(int)bytes_read, ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||||
@@ -137,18 +137,18 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
|||||||
case 1: w = FILE_CURRENT;
|
case 1: w = FILE_CURRENT;
|
||||||
case 2: w = FILE_END;
|
case 2: w = FILE_END;
|
||||||
}
|
}
|
||||||
hi := (offset>>32) as i32;
|
hi := cast(i32)(offset>>32);
|
||||||
lo := offset as i32;
|
lo := cast(i32)(offset);
|
||||||
ft := GetFileType(fd as HANDLE);
|
ft := GetFileType(cast(HANDLE)fd);
|
||||||
if ft == FILE_TYPE_PIPE {
|
if ft == FILE_TYPE_PIPE {
|
||||||
return 0, ERROR_FILE_IS_PIPE;
|
return 0, ERROR_FILE_IS_PIPE;
|
||||||
}
|
}
|
||||||
dw_ptr := SetFilePointer(fd as HANDLE, lo, ^hi, w);
|
dw_ptr := SetFilePointer(cast(HANDLE)fd, lo, ^hi, w);
|
||||||
if dw_ptr == INVALID_SET_FILE_POINTER {
|
if dw_ptr == INVALID_SET_FILE_POINTER {
|
||||||
err := GetLastError();
|
err := GetLastError();
|
||||||
return 0, err as Errno;
|
return 0, cast(Errno)err;
|
||||||
}
|
}
|
||||||
return (hi as i64)<<32 + (dw_ptr as i64), ERROR_NONE;
|
return cast(i64)hi<<32 + cast(i64)dw_ptr, ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -159,9 +159,9 @@ stderr := get_std_handle(win32.STD_ERROR_HANDLE);
|
|||||||
|
|
||||||
|
|
||||||
get_std_handle :: proc(h: int) -> Handle {
|
get_std_handle :: proc(h: int) -> Handle {
|
||||||
fd := win32.GetStdHandle(h as i32);
|
fd := win32.GetStdHandle(cast(i32)h);
|
||||||
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
|
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
|
||||||
return fd as Handle;
|
return cast(Handle)fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -171,9 +171,9 @@ get_std_handle :: proc(h: int) -> Handle {
|
|||||||
|
|
||||||
last_write_time :: proc(fd: Handle) -> File_Time {
|
last_write_time :: proc(fd: Handle) -> File_Time {
|
||||||
file_info: win32.BY_HANDLE_FILE_INFORMATION;
|
file_info: win32.BY_HANDLE_FILE_INFORMATION;
|
||||||
win32.GetFileInformationByHandle(fd as win32.HANDLE, ^file_info);
|
win32.GetFileInformationByHandle(cast(win32.HANDLE)fd, ^file_info);
|
||||||
lo := file_info.last_write_time.lo as File_Time;
|
lo := cast(File_Time)file_info.last_write_time.lo;
|
||||||
hi := file_info.last_write_time.hi as File_Time;
|
hi := cast(File_Time)file_info.last_write_time.hi;
|
||||||
return lo | hi << 32;
|
return lo | hi << 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,14 +184,14 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
|
|||||||
|
|
||||||
assert(buf.count > name.count);
|
assert(buf.count > name.count);
|
||||||
|
|
||||||
copy(buf[:], name as []byte);
|
copy(buf[:], cast([]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;
|
last_write_time = data.last_write_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
l := last_write_time.lo as File_Time;
|
l := cast(File_Time)last_write_time.lo;
|
||||||
h := last_write_time.hi as File_Time;
|
h := cast(File_Time)last_write_time.hi;
|
||||||
return l | h << 32;
|
return l | h << 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
|
|||||||
|
|
||||||
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||||
buf: [300]byte;
|
buf: [300]byte;
|
||||||
copy(buf[:], name as []byte);
|
copy(buf[:], cast([]byte)name);
|
||||||
|
|
||||||
fd, err := open(name, O_RDONLY, 0);
|
fd, err := open(name, O_RDONLY, 0);
|
||||||
if err != ERROR_NONE {
|
if err != ERROR_NONE {
|
||||||
@@ -210,7 +210,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
|||||||
defer close(fd);
|
defer close(fd);
|
||||||
|
|
||||||
length: i64;
|
length: i64;
|
||||||
file_size_ok := win32.GetFileSizeEx(fd as win32.HANDLE, ^length) != 0;
|
file_size_ok := win32.GetFileSizeEx(cast(win32.HANDLE)fd, ^length) != 0;
|
||||||
if !file_size_ok {
|
if !file_size_ok {
|
||||||
return nil, false;
|
return nil, false;
|
||||||
}
|
}
|
||||||
@@ -223,23 +223,23 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
|||||||
single_read_length: i32;
|
single_read_length: i32;
|
||||||
total_read: i64;
|
total_read: i64;
|
||||||
|
|
||||||
while total_read < length {
|
for total_read < length {
|
||||||
remaining := length - total_read;
|
remaining := length - total_read;
|
||||||
to_read: u32;
|
to_read: u32;
|
||||||
MAX :: 1<<32-1;
|
MAX :: 1<<32-1;
|
||||||
if remaining <= MAX {
|
if remaining <= MAX {
|
||||||
to_read = remaining as u32;
|
to_read = cast(u32)remaining;
|
||||||
} else {
|
} else {
|
||||||
to_read = MAX;
|
to_read = MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
win32.ReadFile(fd as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil);
|
win32.ReadFile(cast(win32.HANDLE)fd, ^data[total_read], to_read, ^single_read_length, nil);
|
||||||
if single_read_length <= 0 {
|
if single_read_length <= 0 {
|
||||||
free(data.data);
|
free(data);
|
||||||
return nil, false;
|
return nil, false;
|
||||||
}
|
}
|
||||||
|
|
||||||
total_read += single_read_length as i64;
|
total_read += cast(i64)single_read_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data, true;
|
return data, true;
|
||||||
@@ -259,14 +259,13 @@ heap_free :: proc(ptr: rawptr) {
|
|||||||
|
|
||||||
|
|
||||||
exit :: proc(code: int) {
|
exit :: proc(code: int) {
|
||||||
win32.ExitProcess(code as u32);
|
win32.ExitProcess(cast(u32)code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
current_thread_id :: proc() -> int {
|
current_thread_id :: proc() -> int {
|
||||||
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
return cast(int)win32.GetCurrentThreadId();
|
||||||
return GetCurrentThreadId() as int;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+20
-20
@@ -2,18 +2,18 @@
|
|||||||
#import "atomic.odin";
|
#import "atomic.odin";
|
||||||
|
|
||||||
Semaphore :: struct {
|
Semaphore :: struct {
|
||||||
handle: win32.HANDLE;
|
handle: win32.HANDLE,
|
||||||
}
|
}
|
||||||
|
|
||||||
Mutex :: struct {
|
Mutex :: struct {
|
||||||
semaphore: Semaphore;
|
semaphore: Semaphore,
|
||||||
counter: i32;
|
counter: i32,
|
||||||
owner: i32;
|
owner: i32,
|
||||||
recursion: i32;
|
recursion: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
current_thread_id :: proc() -> i32 {
|
current_thread_id :: proc() -> i32 {
|
||||||
return win32.GetCurrentThreadId() as i32;
|
return cast(i32)win32.GetCurrentThreadId();
|
||||||
}
|
}
|
||||||
|
|
||||||
semaphore_init :: proc(s: ^Semaphore) {
|
semaphore_init :: proc(s: ^Semaphore) {
|
||||||
@@ -25,7 +25,7 @@ semaphore_destroy :: proc(s: ^Semaphore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
semaphore_post :: proc(s: ^Semaphore, count: int) {
|
semaphore_post :: proc(s: ^Semaphore, count: int) {
|
||||||
win32.ReleaseSemaphore(s.handle, count as i32, nil);
|
win32.ReleaseSemaphore(s.handle, cast(i32)count, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
|
semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
|
||||||
@@ -36,8 +36,8 @@ semaphore_wait :: proc(s: ^Semaphore) {
|
|||||||
|
|
||||||
|
|
||||||
mutex_init :: proc(m: ^Mutex) {
|
mutex_init :: proc(m: ^Mutex) {
|
||||||
atomic.store32(^m.counter, 0);
|
atomic.store(^m.counter, 0);
|
||||||
atomic.store32(^m.owner, current_thread_id());
|
atomic.store(^m.owner, current_thread_id());
|
||||||
semaphore_init(^m.semaphore);
|
semaphore_init(^m.semaphore);
|
||||||
m.recursion = 0;
|
m.recursion = 0;
|
||||||
}
|
}
|
||||||
@@ -46,27 +46,27 @@ mutex_destroy :: proc(m: ^Mutex) {
|
|||||||
}
|
}
|
||||||
mutex_lock :: proc(m: ^Mutex) {
|
mutex_lock :: proc(m: ^Mutex) {
|
||||||
thread_id := current_thread_id();
|
thread_id := current_thread_id();
|
||||||
if atomic.fetch_add32(^m.counter, 1) > 0 {
|
if atomic.fetch_add(^m.counter, 1) > 0 {
|
||||||
if thread_id != atomic.load32(^m.owner) {
|
if thread_id != atomic.load(^m.owner) {
|
||||||
semaphore_wait(^m.semaphore);
|
semaphore_wait(^m.semaphore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
atomic.store32(^m.owner, thread_id);
|
atomic.store(^m.owner, thread_id);
|
||||||
m.recursion += 1;
|
m.recursion += 1;
|
||||||
}
|
}
|
||||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||||
thread_id := current_thread_id();
|
thread_id := current_thread_id();
|
||||||
if atomic.load32(^m.owner) == thread_id {
|
if atomic.load(^m.owner) == thread_id {
|
||||||
atomic.fetch_add32(^m.counter, 1);
|
atomic.fetch_add(^m.counter, 1);
|
||||||
} else {
|
} else {
|
||||||
expected: i32 = 0;
|
expected: i32 = 0;
|
||||||
if atomic.load32(^m.counter) != 0 {
|
if atomic.load(^m.counter) != 0 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if atomic.compare_exchange32(^m.counter, expected, 1) == 0 {
|
if atomic.compare_exchange(^m.counter, expected, 1) == 0 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
atomic.store32(^m.owner, thread_id);
|
atomic.store(^m.owner, thread_id);
|
||||||
}
|
}
|
||||||
m.recursion += 1;
|
m.recursion += 1;
|
||||||
return true;
|
return true;
|
||||||
@@ -74,15 +74,15 @@ mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
|||||||
mutex_unlock :: proc(m: ^Mutex) {
|
mutex_unlock :: proc(m: ^Mutex) {
|
||||||
recursion: i32;
|
recursion: i32;
|
||||||
thread_id := current_thread_id();
|
thread_id := current_thread_id();
|
||||||
assert(thread_id == atomic.load32(^m.owner));
|
assert(thread_id == atomic.load(^m.owner));
|
||||||
|
|
||||||
m.recursion -= 1;
|
m.recursion -= 1;
|
||||||
recursion = m.recursion;
|
recursion = m.recursion;
|
||||||
if recursion == 0 {
|
if recursion == 0 {
|
||||||
atomic.store32(^m.owner, thread_id);
|
atomic.store(^m.owner, thread_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if atomic.fetch_add32(^m.counter, -1) > 1 {
|
if atomic.fetch_add(^m.counter, -1) > 1 {
|
||||||
if recursion == 0 {
|
if recursion == 0 {
|
||||||
semaphore_release(^m.semaphore);
|
semaphore_release(^m.semaphore);
|
||||||
}
|
}
|
||||||
|
|||||||
+143
-132
@@ -1,5 +1,8 @@
|
|||||||
#foreign_system_library "user32" when ODIN_OS == "windows";
|
#foreign_system_library "kernel32.lib";
|
||||||
#foreign_system_library "gdi32" when ODIN_OS == "windows";
|
#foreign_system_library "user32.lib";
|
||||||
|
#foreign_system_library "gdi32.lib";
|
||||||
|
#foreign_system_library "winmm.lib";
|
||||||
|
#foreign_system_library "opengl32.lib";
|
||||||
|
|
||||||
HANDLE :: rawptr;
|
HANDLE :: rawptr;
|
||||||
HWND :: HANDLE;
|
HWND :: HANDLE;
|
||||||
@@ -16,10 +19,10 @@ LPARAM :: int;
|
|||||||
LRESULT :: int;
|
LRESULT :: int;
|
||||||
ATOM :: i16;
|
ATOM :: i16;
|
||||||
BOOL :: i32;
|
BOOL :: i32;
|
||||||
WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT;
|
WNDPROC :: type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c;
|
||||||
|
|
||||||
|
|
||||||
INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE;
|
INVALID_HANDLE_VALUE :: cast(HANDLE)(~cast(int)0);
|
||||||
|
|
||||||
FALSE: BOOL : 0;
|
FALSE: BOOL : 0;
|
||||||
TRUE: BOOL : 1;
|
TRUE: BOOL : 1;
|
||||||
@@ -46,7 +49,7 @@ WM_KEYUP :: 0x0101;
|
|||||||
|
|
||||||
PM_REMOVE :: 1;
|
PM_REMOVE :: 1;
|
||||||
|
|
||||||
COLOR_BACKGROUND :: 1 as HBRUSH;
|
COLOR_BACKGROUND :: cast(HBRUSH)(cast(int)1);
|
||||||
BLACK_BRUSH :: 4;
|
BLACK_BRUSH :: 4;
|
||||||
|
|
||||||
SM_CXSCREEN :: 0;
|
SM_CXSCREEN :: 0;
|
||||||
@@ -56,61 +59,67 @@ SW_SHOW :: 5;
|
|||||||
|
|
||||||
|
|
||||||
POINT :: struct #ordered {
|
POINT :: struct #ordered {
|
||||||
x, y: i32;
|
x, y: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
WNDCLASSEXA :: struct #ordered {
|
WNDCLASSEXA :: struct #ordered {
|
||||||
size, style: u32;
|
size, style: u32,
|
||||||
wnd_proc: WNDPROC;
|
wnd_proc: WNDPROC,
|
||||||
cls_extra, wnd_extra: i32;
|
cls_extra, wnd_extra: i32,
|
||||||
instance: HINSTANCE;
|
instance: HINSTANCE,
|
||||||
icon: HICON;
|
icon: HICON,
|
||||||
cursor: HCURSOR;
|
cursor: HCURSOR,
|
||||||
background: HBRUSH;
|
background: HBRUSH,
|
||||||
menu_name, class_name: ^u8;
|
menu_name, class_name: ^u8,
|
||||||
sm: HICON;
|
sm: HICON,
|
||||||
}
|
}
|
||||||
|
|
||||||
MSG :: struct #ordered {
|
MSG :: struct #ordered {
|
||||||
hwnd: HWND;
|
hwnd: HWND,
|
||||||
message: u32;
|
message: u32,
|
||||||
wparam: WPARAM;
|
wparam: WPARAM,
|
||||||
lparam: LPARAM;
|
lparam: LPARAM,
|
||||||
time: u32;
|
time: u32,
|
||||||
pt: POINT;
|
pt: POINT,
|
||||||
}
|
}
|
||||||
|
|
||||||
RECT :: struct #ordered {
|
RECT :: struct #ordered {
|
||||||
left: i32;
|
left: i32,
|
||||||
top: i32;
|
top: i32,
|
||||||
right: i32;
|
right: i32,
|
||||||
bottom: i32;
|
bottom: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
FILETIME :: struct #ordered {
|
FILETIME :: struct #ordered {
|
||||||
lo, hi: u32;
|
lo, hi: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
file_attributes: u32,
|
||||||
creation_time,
|
creation_time,
|
||||||
last_access_time,
|
last_access_time,
|
||||||
last_write_time: FILETIME;
|
last_write_time: FILETIME,
|
||||||
volume_serial_number,
|
volume_serial_number,
|
||||||
file_size_high,
|
file_size_high,
|
||||||
file_size_low,
|
file_size_low,
|
||||||
number_of_links,
|
number_of_links,
|
||||||
file_index_high,
|
file_index_high,
|
||||||
file_index_low: u32;
|
file_index_low: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE_ATTRIBUTE_DATA :: struct #ordered {
|
FILE_ATTRIBUTE_DATA :: struct #ordered {
|
||||||
file_attributes: u32;
|
file_attributes: u32,
|
||||||
creation_time,
|
creation_time,
|
||||||
last_access_time,
|
last_access_time,
|
||||||
last_write_time: FILETIME;
|
last_write_time: FILETIME,
|
||||||
file_size_high,
|
file_size_high,
|
||||||
file_size_low: u32;
|
file_size_low: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
GET_FILEEX_INFO_LEVELS :: i32;
|
GET_FILEEX_INFO_LEVELS :: i32;
|
||||||
@@ -118,43 +127,43 @@ GET_FILEEX_INFO_LEVELS :: i32;
|
|||||||
GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0;
|
GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0;
|
||||||
GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1;
|
GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1;
|
||||||
|
|
||||||
GetLastError :: proc() -> i32 #foreign #dll_import
|
GetLastError :: proc() -> i32 #foreign kernel32;
|
||||||
ExitProcess :: proc(exit_code: u32) #foreign #dll_import
|
ExitProcess :: proc(exit_code: u32) #foreign kernel32;
|
||||||
GetDesktopWindow :: proc() -> HWND #foreign #dll_import
|
GetDesktopWindow :: proc() -> HWND #foreign user32;
|
||||||
GetCursorPos :: proc(p: ^POINT) -> i32 #foreign #dll_import
|
GetCursorPos :: proc(p: ^POINT) -> i32 #foreign user32;
|
||||||
ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign #dll_import
|
ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign user32;
|
||||||
GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign #dll_import
|
GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign kernel32;
|
||||||
GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign #dll_import
|
GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign gdi32;
|
||||||
PostQuitMessage :: proc(exit_code: i32) #foreign #dll_import
|
PostQuitMessage :: proc(exit_code: i32) #foreign user32;
|
||||||
SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign #dll_import
|
SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign user32;
|
||||||
|
|
||||||
QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign #dll_import
|
QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign kernel32;
|
||||||
QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign #dll_import
|
QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign kernel32;
|
||||||
|
|
||||||
Sleep :: proc(ms: i32) -> i32 #foreign #dll_import
|
Sleep :: proc(ms: i32) -> i32 #foreign kernel32;
|
||||||
|
|
||||||
OutputDebugStringA :: proc(c_str: ^u8) #foreign #dll_import
|
OutputDebugStringA :: proc(c_str: ^u8) #foreign kernel32;
|
||||||
|
|
||||||
|
|
||||||
RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign #dll_import
|
RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign user32;
|
||||||
CreateWindowExA :: proc(ex_style: u32,
|
CreateWindowExA :: proc(ex_style: u32,
|
||||||
class_name, title: ^u8,
|
class_name, title: ^u8,
|
||||||
style: u32,
|
style: u32,
|
||||||
x, y, w, h: i32,
|
x, y, w, h: i32,
|
||||||
parent: HWND, menu: HMENU, instance: HINSTANCE,
|
parent: HWND, menu: HMENU, instance: HINSTANCE,
|
||||||
param: rawptr) -> HWND #foreign #dll_import
|
param: rawptr) -> HWND #foreign user32;
|
||||||
|
|
||||||
ShowWindow :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign #dll_import
|
ShowWindow :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign user32;
|
||||||
TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign #dll_import
|
TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign user32;
|
||||||
DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign #dll_import
|
DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign user32;
|
||||||
UpdateWindow :: proc(hwnd: HWND) -> BOOL #foreign #dll_import
|
UpdateWindow :: proc(hwnd: HWND) -> BOOL #foreign user32;
|
||||||
PeekMessageA :: proc(msg: ^MSG, hwnd: HWND,
|
PeekMessageA :: proc(msg: ^MSG, hwnd: HWND,
|
||||||
msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign #dll_import
|
msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign user32;
|
||||||
|
|
||||||
DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign #dll_import
|
DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign user32;
|
||||||
|
|
||||||
AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign #dll_import
|
AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign user32;
|
||||||
GetActiveWindow :: proc() -> HWND #foreign #dll_import
|
GetActiveWindow :: proc() -> HWND #foreign user32;
|
||||||
|
|
||||||
|
|
||||||
GetQueryPerformanceFrequency :: proc() -> i64 {
|
GetQueryPerformanceFrequency :: proc() -> i64 {
|
||||||
@@ -163,28 +172,34 @@ GetQueryPerformanceFrequency :: proc() -> i64 {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetCommandLineA :: proc() -> ^u8 #foreign #dll_import
|
GetCommandLineA :: proc() -> ^u8 #foreign kernel32;
|
||||||
GetSystemMetrics :: proc(index: i32) -> i32 #foreign #dll_import
|
GetSystemMetrics :: proc(index: i32) -> i32 #foreign kernel32;
|
||||||
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
GetCurrentThreadId :: proc() -> u32 #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
|
// File Stuff
|
||||||
|
|
||||||
CloseHandle :: proc(h: HANDLE) -> i32 #foreign #dll_import
|
CloseHandle :: proc(h: HANDLE) -> i32 #foreign kernel32;
|
||||||
GetStdHandle :: proc(h: i32) -> HANDLE #foreign #dll_import
|
GetStdHandle :: proc(h: i32) -> HANDLE #foreign kernel32;
|
||||||
CreateFileA :: proc(filename: ^u8, desired_access, share_mode: u32,
|
CreateFileA :: proc(filename: ^u8, desired_access, share_mode: u32,
|
||||||
security: rawptr,
|
security: rawptr,
|
||||||
creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign #dll_import
|
creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign kernel32;
|
||||||
ReadFile :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign #dll_import
|
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 #dll_import
|
WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> BOOL #foreign kernel32;
|
||||||
|
|
||||||
GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign #dll_import
|
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 #dll_import
|
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 #dll_import
|
GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign kernel32;
|
||||||
|
|
||||||
GetFileType :: proc(file_handle: HANDLE) -> u32 #foreign #dll_import
|
GetFileType :: proc(file_handle: HANDLE) -> u32 #foreign kernel32;
|
||||||
SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign #dll_import
|
SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign kernel32;
|
||||||
|
|
||||||
SetHandleInformation :: proc(obj: HANDLE, mask, flags: u32) -> BOOL #foreign #dll_import
|
SetHandleInformation :: proc(obj: HANDLE, mask, flags: u32) -> BOOL #foreign kernel32;
|
||||||
|
|
||||||
HANDLE_FLAG_INHERIT :: 1;
|
HANDLE_FLAG_INHERIT :: 1;
|
||||||
HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
|
HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
|
||||||
@@ -233,15 +248,15 @@ FILE_TYPE_DISK :: 0x0001;
|
|||||||
FILE_TYPE_CHAR :: 0x0002;
|
FILE_TYPE_CHAR :: 0x0002;
|
||||||
FILE_TYPE_PIPE :: 0x0003;
|
FILE_TYPE_PIPE :: 0x0003;
|
||||||
|
|
||||||
INVALID_SET_FILE_POINTER :: ~(0 as u32);
|
INVALID_SET_FILE_POINTER :: ~cast(u32)0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HeapAlloc :: proc (h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign #dll_import
|
HeapAlloc :: proc (h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign kernel32;
|
||||||
HeapReAlloc :: proc (h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign #dll_import
|
HeapReAlloc :: proc (h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign kernel32;
|
||||||
HeapFree :: proc (h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign #dll_import
|
HeapFree :: proc (h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign kernel32;
|
||||||
GetProcessHeap :: proc () -> HANDLE #foreign #dll_import
|
GetProcessHeap :: proc () -> HANDLE #foreign kernel32;
|
||||||
|
|
||||||
|
|
||||||
HEAP_ZERO_MEMORY :: 0x00000008;
|
HEAP_ZERO_MEMORY :: 0x00000008;
|
||||||
@@ -249,57 +264,55 @@ HEAP_ZERO_MEMORY :: 0x00000008;
|
|||||||
// Synchronization
|
// Synchronization
|
||||||
|
|
||||||
SECURITY_ATTRIBUTES :: struct #ordered {
|
SECURITY_ATTRIBUTES :: struct #ordered {
|
||||||
length: u32;
|
length: u32,
|
||||||
security_descriptor: rawptr;
|
security_descriptor: rawptr,
|
||||||
inherit_handle: BOOL;
|
inherit_handle: BOOL,
|
||||||
}
|
}
|
||||||
|
|
||||||
INFINITE :: 0xffffffff;
|
INFINITE :: 0xffffffff;
|
||||||
|
|
||||||
CreateSemaphoreA :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign #dll_import
|
CreateSemaphoreA :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign kernel32;
|
||||||
ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign #dll_import
|
ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign kernel32;
|
||||||
WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign #dll_import
|
WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign kernel32;
|
||||||
|
|
||||||
|
|
||||||
InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign
|
InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign kernel32;
|
||||||
InterlockedExchange :: proc(dst: ^i32, desired: i32) -> i32 #foreign
|
InterlockedExchange :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
|
||||||
InterlockedExchangeAdd :: proc(dst: ^i32, desired: i32) -> i32 #foreign
|
InterlockedExchangeAdd :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
|
||||||
InterlockedAnd :: proc(dst: ^i32, desired: i32) -> i32 #foreign
|
InterlockedAnd :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
|
||||||
InterlockedOr :: proc(dst: ^i32, desired: i32) -> i32 #foreign
|
InterlockedOr :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
|
||||||
|
|
||||||
InterlockedCompareExchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #foreign
|
InterlockedCompareExchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #foreign kernel32;
|
||||||
InterlockedExchange64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
|
InterlockedExchange64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
|
||||||
InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
|
InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
|
||||||
InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
|
InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
|
||||||
InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign
|
InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
|
||||||
|
|
||||||
|
_mm_pause :: proc() #foreign kernel32;
|
||||||
|
ReadWriteBarrier :: proc() #foreign kernel32;
|
||||||
|
WriteBarrier :: proc() #foreign kernel32;
|
||||||
|
ReadBarrier :: proc() #foreign kernel32;
|
||||||
|
|
||||||
_mm_pause :: proc() #foreign
|
|
||||||
ReadWriteBarrier :: proc() #foreign
|
|
||||||
WriteBarrier :: proc() #foreign
|
|
||||||
ReadBarrier :: proc() #foreign
|
|
||||||
|
|
||||||
|
|
||||||
// GDI
|
|
||||||
BITMAPINFOHEADER :: struct #ordered {
|
BITMAPINFOHEADER :: struct #ordered {
|
||||||
size: u32;
|
size: u32,
|
||||||
width, height: i32;
|
width, height: i32,
|
||||||
planes, bit_count: i16;
|
planes, bit_count: i16,
|
||||||
compression: u32;
|
compression: u32,
|
||||||
size_image: u32;
|
size_image: u32,
|
||||||
x_pels_per_meter: i32;
|
x_pels_per_meter: i32,
|
||||||
y_pels_per_meter: i32;
|
y_pels_per_meter: i32,
|
||||||
clr_used: u32;
|
clr_used: u32,
|
||||||
clr_important: u32;
|
clr_important: u32,
|
||||||
}
|
}
|
||||||
BITMAPINFO :: struct #ordered {
|
BITMAPINFO :: struct #ordered {
|
||||||
using header: BITMAPINFOHEADER;
|
using header: BITMAPINFOHEADER,
|
||||||
colors: [1]RGBQUAD;
|
colors: [1]RGBQUAD,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RGBQUAD :: struct #ordered {
|
RGBQUAD :: struct #ordered { blue, green, red, reserved: byte }
|
||||||
blue, green, red, reserved: byte;
|
|
||||||
}
|
|
||||||
|
|
||||||
BI_RGB :: 0;
|
BI_RGB :: 0;
|
||||||
DIB_RGB_COLORS :: 0x00;
|
DIB_RGB_COLORS :: 0x00;
|
||||||
@@ -311,17 +324,15 @@ StretchDIBits :: proc (hdc: HDC,
|
|||||||
x_src, y_src, width_src, header_src: i32,
|
x_src, y_src, width_src, header_src: i32,
|
||||||
bits: rawptr, bits_info: ^BITMAPINFO,
|
bits: rawptr, bits_info: ^BITMAPINFO,
|
||||||
usage: u32,
|
usage: u32,
|
||||||
rop: u32) -> i32 #foreign #dll_import
|
rop: u32) -> i32 #foreign gdi32;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
LoadLibraryA :: proc (c_str: ^u8) -> HMODULE #foreign
|
LoadLibraryA :: proc (c_str: ^u8) -> HMODULE #foreign kernel32;
|
||||||
FreeLibrary :: proc (h: HMODULE) #foreign
|
FreeLibrary :: proc (h: HMODULE) #foreign kernel32;
|
||||||
GetProcAddress :: proc (h: HMODULE, c_str: ^u8) -> PROC #foreign
|
GetProcAddress :: proc (h: HMODULE, c_str: ^u8) -> PROC #foreign kernel32;
|
||||||
|
|
||||||
GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign
|
|
||||||
|
|
||||||
|
|
||||||
|
GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign user32;
|
||||||
|
|
||||||
// Windows OpenGL
|
// Windows OpenGL
|
||||||
PFD_TYPE_RGBA :: 0;
|
PFD_TYPE_RGBA :: 0;
|
||||||
@@ -348,13 +359,13 @@ PFD_STEREO_DONTCARE :: 0x80000000;
|
|||||||
|
|
||||||
HGLRC :: HANDLE;
|
HGLRC :: HANDLE;
|
||||||
PROC :: type proc() #cc_c;
|
PROC :: type proc() #cc_c;
|
||||||
wglCreateContextAttribsARBType :: proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
|
wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
|
||||||
|
|
||||||
|
|
||||||
PIXELFORMATDESCRIPTOR :: struct #ordered {
|
PIXELFORMATDESCRIPTOR :: struct #ordered {
|
||||||
size,
|
size,
|
||||||
version,
|
version,
|
||||||
flags: u32;
|
flags: u32,
|
||||||
|
|
||||||
pixel_type,
|
pixel_type,
|
||||||
color_bits,
|
color_bits,
|
||||||
@@ -375,18 +386,18 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
|
|||||||
stencil_bits,
|
stencil_bits,
|
||||||
aux_buffers,
|
aux_buffers,
|
||||||
layer_type,
|
layer_type,
|
||||||
reserved: byte;
|
reserved: byte,
|
||||||
|
|
||||||
layer_mask,
|
layer_mask,
|
||||||
visible_mask,
|
visible_mask,
|
||||||
damage_mask: u32;
|
damage_mask: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
GetDC :: proc(h: HANDLE) -> HDC #foreign
|
GetDC :: proc(h: HANDLE) -> HDC #foreign user32;
|
||||||
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import
|
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign gdi32;
|
||||||
ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll_import
|
ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32;
|
||||||
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign #dll_import
|
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign gdi32;
|
||||||
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign #dll_import
|
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign user32;
|
||||||
|
|
||||||
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
|
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
|
||||||
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092;
|
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092;
|
||||||
@@ -394,17 +405,17 @@ WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126;
|
|||||||
WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001;
|
WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001;
|
||||||
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002;
|
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002;
|
||||||
|
|
||||||
wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign #dll_import
|
wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign opengl32;
|
||||||
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign #dll_import
|
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32;
|
||||||
wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign #dll_import
|
wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32;
|
||||||
wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign #dll_import
|
wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GetKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
GetKeyState :: proc(v_key: i32) -> i16 #foreign user32;
|
||||||
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign user32;
|
||||||
|
|
||||||
is_key_down :: proc(key: Key_Code) -> bool #inline { return GetAsyncKeyState(key as i32) < 0; }
|
is_key_down :: proc(key: Key_Code) -> bool #inline { return GetAsyncKeyState(cast(i32)key) < 0; }
|
||||||
|
|
||||||
Key_Code :: enum i32 {
|
Key_Code :: enum i32 {
|
||||||
LBUTTON = 0x01,
|
LBUTTON = 0x01,
|
||||||
|
|||||||
+56
-46
@@ -1,18 +1,36 @@
|
|||||||
RUNE_ERROR :: '\ufffd';
|
RUNE_ERROR :: '\ufffd';
|
||||||
RUNE_SELF :: 0x80;
|
RUNE_SELF :: 0x80;
|
||||||
RUNE_BOM :: 0xfeff;
|
RUNE_BOM :: 0xfeff;
|
||||||
RUNE_EOF :: ~(0 as rune);
|
RUNE_EOF :: ~cast(rune)0;
|
||||||
MAX_RUNE :: '\U0010ffff';
|
MAX_RUNE :: '\U0010ffff';
|
||||||
UTF_MAX :: 4;
|
UTF_MAX :: 4;
|
||||||
|
|
||||||
SURROGATE_MIN :: 0xd800;
|
SURROGATE_MIN :: 0xd800;
|
||||||
SURROGATE_MAX :: 0xdfff;
|
SURROGATE_MAX :: 0xdfff;
|
||||||
|
|
||||||
Accept_Range :: struct {
|
T1 :: 0b0000_0000;
|
||||||
lo, hi: u8;
|
TX :: 0b1000_0000;
|
||||||
}
|
T2 :: 0b1100_0000;
|
||||||
|
T3 :: 0b1110_0000;
|
||||||
|
T4 :: 0b1111_0000;
|
||||||
|
T5 :: 0b1111_1000;
|
||||||
|
|
||||||
accept_ranges := [5]Accept_Range{
|
MASKX :: 0b0011_1111;
|
||||||
|
MASK2 :: 0b0001_1111;
|
||||||
|
MASK3 :: 0b0000_1111;
|
||||||
|
MASK4 :: 0b0000_0111;
|
||||||
|
|
||||||
|
RUNE1_MAX :: 1<<7 - 1;
|
||||||
|
RUNE2_MAX :: 1<<11 - 1;
|
||||||
|
RUNE3_MAX :: 1<<16 - 1;
|
||||||
|
|
||||||
|
// The default lowest and highest continuation byte.
|
||||||
|
LOCB :: 0b1000_0000;
|
||||||
|
HICB :: 0b1011_1111;
|
||||||
|
|
||||||
|
Accept_Range :: struct { lo, hi: u8 }
|
||||||
|
|
||||||
|
immutable accept_ranges := [5]Accept_Range{
|
||||||
{0x80, 0xbf},
|
{0x80, 0xbf},
|
||||||
{0xa0, 0xbf},
|
{0xa0, 0xbf},
|
||||||
{0x80, 0x9f},
|
{0x80, 0x9f},
|
||||||
@@ -20,7 +38,7 @@ accept_ranges := [5]Accept_Range{
|
|||||||
{0x80, 0x8f},
|
{0x80, 0x8f},
|
||||||
};
|
};
|
||||||
|
|
||||||
accept_sizes := [256]byte{
|
immutable accept_sizes := [256]byte{
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
||||||
@@ -42,15 +60,15 @@ accept_sizes := [256]byte{
|
|||||||
|
|
||||||
encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
||||||
buf: [4]byte;
|
buf: [4]byte;
|
||||||
i := r as u32;
|
i := cast(u32)r;
|
||||||
mask: byte : 0x3f;
|
mask: byte : 0x3f;
|
||||||
if i <= 1<<7-1 {
|
if i <= 1<<7-1 {
|
||||||
buf[0] = r as byte;
|
buf[0] = cast(byte)r;
|
||||||
return buf, 1;
|
return buf, 1;
|
||||||
}
|
}
|
||||||
if i <= 1<<11-1 {
|
if i <= 1<<11-1 {
|
||||||
buf[0] = 0xc0 | (r>>6) as byte;
|
buf[0] = 0xc0 | cast(byte)(r>>6);
|
||||||
buf[1] = 0x80 | (r) as byte & mask;
|
buf[1] = 0x80 | cast(byte)r & mask;
|
||||||
return buf, 2;
|
return buf, 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,16 +79,16 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if i <= 1<<16-1 {
|
if i <= 1<<16-1 {
|
||||||
buf[0] = 0xe0 | (r>>12) as byte;
|
buf[0] = 0xe0 | cast(byte)(r>>12);
|
||||||
buf[1] = 0x80 | (r>>6) as byte & mask;
|
buf[1] = 0x80 | cast(byte)(r>>6) & mask;
|
||||||
buf[2] = 0x80 | (r) as byte & mask;
|
buf[2] = 0x80 | cast(byte)r & mask;
|
||||||
return buf, 3;
|
return buf, 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[0] = 0xf0 | (r>>18) as byte;
|
buf[0] = 0xf0 | cast(byte)(r>>18);
|
||||||
buf[1] = 0x80 | (r>>12) as byte & mask;
|
buf[1] = 0x80 | cast(byte)(r>>12) & mask;
|
||||||
buf[2] = 0x80 | (r>>6) as byte & mask;
|
buf[2] = 0x80 | cast(byte)(r>>6) & mask;
|
||||||
buf[3] = 0x80 | (r) as byte & mask;
|
buf[3] = 0x80 | cast(byte)r & mask;
|
||||||
return buf, 4;
|
return buf, 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,43 +97,36 @@ decode_rune :: proc(s: string) -> (rune, int) {
|
|||||||
if n < 1 {
|
if n < 1 {
|
||||||
return RUNE_ERROR, 0;
|
return RUNE_ERROR, 0;
|
||||||
}
|
}
|
||||||
b0 := s[0];
|
s0 := s[0];
|
||||||
x := accept_sizes[b0];
|
x := accept_sizes[s0];
|
||||||
if x >= 0xf0 {
|
if x >= 0xF0 {
|
||||||
mask := (x as rune << 31) >> 31; // all zeros or all ones
|
mask := cast(rune)(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
|
||||||
return (b0 as rune) &~ mask | RUNE_ERROR&mask, 1;
|
return cast(rune)(s[0])&~mask | RUNE_ERROR&mask, 1;
|
||||||
}
|
}
|
||||||
size := x & 7;
|
sz := x & 7;
|
||||||
ar := accept_ranges[x>>4];
|
accept := accept_ranges[x>>4];
|
||||||
if n < size as int {
|
if n < cast(int)sz {
|
||||||
return RUNE_ERROR, 1;
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
b1 := s[1];
|
b1 := s[1];
|
||||||
if b1 < ar.lo || ar.hi < b1 {
|
if b1 < accept.lo || accept.hi < b1 {
|
||||||
return RUNE_ERROR, 1;
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
|
if sz == 2 {
|
||||||
MASK_X :: 0b00111111;
|
return cast(rune)(s0&MASK2)<<6 | cast(rune)(b1&MASKX), 2;
|
||||||
MASK_2 :: 0b00011111;
|
|
||||||
MASK_3 :: 0b00001111;
|
|
||||||
MASK_4 :: 0b00000111;
|
|
||||||
|
|
||||||
if size == 2 {
|
|
||||||
return (b0&MASK_2) as rune <<6 | (b1&MASK_X) as rune, 2;
|
|
||||||
}
|
}
|
||||||
b2 := s[2];
|
b2 := s[2];
|
||||||
if b2 < 0x80 || 0xbf < b2 {
|
if b2 < LOCB || HICB < b2 {
|
||||||
return RUNE_ERROR, 1;
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
if size == 3 {
|
if sz == 3 {
|
||||||
return (b0&MASK_3) as rune <<12 | (b1&MASK_X) as rune <<6 | (b2&MASK_X) as rune, 3;
|
return cast(rune)(s0&MASK3)<<12 | cast(rune)(b1&MASKX)<<6 | cast(rune)(b2&MASKX), 3;
|
||||||
}
|
}
|
||||||
b3 := s[3];
|
b3 := s[3];
|
||||||
if b3 < 0x80 || 0xbf < b3 {
|
if b3 < LOCB || HICB < b3 {
|
||||||
return RUNE_ERROR, 1;
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
return (b0&MASK_4) as rune <<18 | (b1&MASK_X) as rune <<12 | (b3&MASK_X) as rune <<6 | (b3&MASK_X) as rune, 4;
|
return cast(rune)(s0&MASK4)<<18 | cast(rune)(b1&MASKX)<<12 | cast(rune)(b2&MASKX)<<6 | cast(rune)(b3&MASKX), 4;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -132,8 +143,7 @@ valid_rune :: proc(r: rune) -> bool {
|
|||||||
|
|
||||||
valid_string :: proc(s: string) -> bool {
|
valid_string :: proc(s: string) -> bool {
|
||||||
n := s.count;
|
n := s.count;
|
||||||
i := 0;
|
for i := 0; i < n; {
|
||||||
while i < n {
|
|
||||||
si := s[i];
|
si := s[i];
|
||||||
if si < RUNE_SELF { // ascii
|
if si < RUNE_SELF { // ascii
|
||||||
i += 1;
|
i += 1;
|
||||||
@@ -143,7 +153,7 @@ valid_string :: proc(s: string) -> bool {
|
|||||||
if x == 0xf1 {
|
if x == 0xf1 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
size := (x & 7) as int;
|
size := cast(int)(x & 7);
|
||||||
if i+size > n {
|
if i+size > n {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -167,8 +177,8 @@ valid_string :: proc(s: string) -> bool {
|
|||||||
rune_count :: proc(s: string) -> int {
|
rune_count :: proc(s: string) -> int {
|
||||||
count := 0;
|
count := 0;
|
||||||
n := s.count;
|
n := s.count;
|
||||||
i := 0;
|
|
||||||
while i < n {
|
for i := 0; i < n; {
|
||||||
defer count += 1;
|
defer count += 1;
|
||||||
si := s[i];
|
si := s[i];
|
||||||
if si < RUNE_SELF { // ascii
|
if si < RUNE_SELF { // ascii
|
||||||
@@ -180,7 +190,7 @@ rune_count :: proc(s: string) -> int {
|
|||||||
i += 1;
|
i += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
size := (x & 7) as int;
|
size := cast(int)(x & 7);
|
||||||
if i+size > n {
|
if i+size > n {
|
||||||
i += 1;
|
i += 1;
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
+1
-1
@@ -148,7 +148,7 @@ String get_filepath_extension(String path) {
|
|||||||
|
|
||||||
void init_build_context(BuildContext *bc) {
|
void init_build_context(BuildContext *bc) {
|
||||||
bc->ODIN_VENDOR = str_lit("odin");
|
bc->ODIN_VENDOR = str_lit("odin");
|
||||||
bc->ODIN_VERSION = str_lit("0.0.5e");
|
bc->ODIN_VERSION = str_lit("0.0.6b");
|
||||||
bc->ODIN_ROOT = odin_root_dir();
|
bc->ODIN_ROOT = odin_root_dir();
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
|||||||
}
|
}
|
||||||
t = default_type(t);
|
t = default_type(t);
|
||||||
}
|
}
|
||||||
|
GB_ASSERT(is_type_typed(t));
|
||||||
e->type = t;
|
e->type = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +64,7 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
|
|||||||
Array(Operand) operands;
|
Array(Operand) operands;
|
||||||
array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count);
|
array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count);
|
||||||
|
|
||||||
|
// TODO(bill): Allow for type hints from the entities
|
||||||
for_array(i, inits) {
|
for_array(i, inits) {
|
||||||
AstNode *rhs = inits.e[i];
|
AstNode *rhs = inits.e[i];
|
||||||
Operand o = {0};
|
Operand o = {0};
|
||||||
@@ -107,78 +109,6 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
|
|||||||
gb_temp_arena_memory_end(tmp);
|
gb_temp_arena_memory_end(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_var_decl_node(Checker *c, AstNodeValueDecl *vd) {
|
|
||||||
GB_ASSERT(vd->is_var == true);
|
|
||||||
isize entity_count = vd->names.count;
|
|
||||||
isize entity_index = 0;
|
|
||||||
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
|
||||||
|
|
||||||
for_array(i, vd->names) {
|
|
||||||
AstNode *name = vd->names.e[i];
|
|
||||||
Entity *entity = NULL;
|
|
||||||
if (name->kind == AstNode_Ident) {
|
|
||||||
Token token = name->Ident;
|
|
||||||
String str = token.string;
|
|
||||||
Entity *found = NULL;
|
|
||||||
// NOTE(bill): Ignore assignments to `_`
|
|
||||||
if (str_ne(str, str_lit("_"))) {
|
|
||||||
found = current_scope_lookup_entity(c->context.scope, str);
|
|
||||||
}
|
|
||||||
if (found == NULL) {
|
|
||||||
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
|
|
||||||
add_entity_definition(&c->info, name, entity);
|
|
||||||
} else {
|
|
||||||
TokenPos pos = found->token.pos;
|
|
||||||
error(token,
|
|
||||||
"Redeclaration of `%.*s` in this scope\n"
|
|
||||||
"\tat %.*s(%td:%td)",
|
|
||||||
LIT(str), LIT(pos.file), pos.line, pos.column);
|
|
||||||
entity = found;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error_node(name, "A variable declaration must be an identifier");
|
|
||||||
}
|
|
||||||
if (entity == NULL) {
|
|
||||||
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
|
|
||||||
}
|
|
||||||
entities[entity_index++] = entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type *init_type = NULL;
|
|
||||||
if (vd->type) {
|
|
||||||
init_type = check_type_extra(c, vd->type, NULL);
|
|
||||||
if (init_type == NULL) {
|
|
||||||
init_type = t_invalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (isize i = 0; i < entity_count; i++) {
|
|
||||||
Entity *e = entities[i];
|
|
||||||
GB_ASSERT(e != NULL);
|
|
||||||
if (e->flags & EntityFlag_Visited) {
|
|
||||||
e->type = t_invalid;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
e->flags |= EntityFlag_Visited;
|
|
||||||
|
|
||||||
if (e->type == NULL) {
|
|
||||||
e->type = init_type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
check_arity_match(c, vd);
|
|
||||||
check_init_variables(c, entities, entity_count, vd->values, str_lit("variable declaration"));
|
|
||||||
|
|
||||||
for_array(i, vd->names) {
|
|
||||||
if (entities[i] != NULL) {
|
|
||||||
add_entity(c, c->context.scope, vd->names.e[i], entities[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
||||||
if (operand->mode == Addressing_Invalid ||
|
if (operand->mode == Addressing_Invalid ||
|
||||||
operand->type == t_invalid ||
|
operand->type == t_invalid ||
|
||||||
@@ -249,9 +179,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
|||||||
}
|
}
|
||||||
e->flags |= EntityFlag_Visited;
|
e->flags |= EntityFlag_Visited;
|
||||||
|
|
||||||
c->context.iota = e->Constant.value;
|
|
||||||
e->Constant.value = (ExactValue){0};
|
|
||||||
|
|
||||||
if (type_expr) {
|
if (type_expr) {
|
||||||
Type *t = check_type(c, type_expr);
|
Type *t = check_type(c, type_expr);
|
||||||
if (!is_type_constant_type(t)) {
|
if (!is_type_constant_type(t)) {
|
||||||
@@ -259,7 +186,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
|||||||
error_node(type_expr, "Invalid constant type `%s`", str);
|
error_node(type_expr, "Invalid constant type `%s`", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
c->context.iota = (ExactValue){0};
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
e->type = t;
|
e->type = t;
|
||||||
@@ -270,9 +196,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
|||||||
check_expr_or_type(c, &operand, init);
|
check_expr_or_type(c, &operand, init);
|
||||||
}
|
}
|
||||||
if (operand.mode == Addressing_Type) {
|
if (operand.mode == Addressing_Type) {
|
||||||
c->context.iota = (ExactValue){0};
|
|
||||||
|
|
||||||
e->Constant.value = (ExactValue){0};
|
|
||||||
e->kind = Entity_TypeName;
|
e->kind = Entity_TypeName;
|
||||||
|
|
||||||
DeclInfo *d = c->context.decl;
|
DeclInfo *d = c->context.decl;
|
||||||
@@ -282,10 +205,10 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
|||||||
}
|
}
|
||||||
|
|
||||||
check_init_constant(c, e, &operand);
|
check_init_constant(c, e, &operand);
|
||||||
c->context.iota = (ExactValue){0};
|
|
||||||
|
|
||||||
if (operand.mode == Addressing_Invalid) {
|
if (operand.mode == Addressing_Invalid ||
|
||||||
error(e->token, "Illegal cyclic declaration");
|
base_type(operand.type) == t_invalid) {
|
||||||
|
error(e->token, "Invalid declaration type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,10 +302,11 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
|
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proc_type->Proc.calling_convention != ProcCC_Odin) {
|
// TODO(bill): Is this the best option? What about passing to external shit?!
|
||||||
error_node(d->proc_lit, "An internal procedure may only have the Odin calling convention");
|
// if (proc_type->Proc.calling_convention != ProcCC_Odin) {
|
||||||
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;
|
d->scope = c->context.scope;
|
||||||
|
|
||||||
@@ -397,6 +321,29 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
name = pd->foreign_name;
|
name = pd->foreign_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstNode *foreign_library = d->proc_lit->ProcLit.foreign_library;
|
||||||
|
if (foreign_library == NULL) {
|
||||||
|
error(e->token, "#foreign procedures must declare which library they are from");
|
||||||
|
} else if (foreign_library->kind != AstNode_Ident) {
|
||||||
|
error_node(foreign_library, "#foreign library names must be an identifier");
|
||||||
|
} else {
|
||||||
|
String name = foreign_library->Ident.string;
|
||||||
|
Entity *found = scope_lookup_entity(c->context.scope, name);
|
||||||
|
if (found == NULL) {
|
||||||
|
if (str_eq(name, str_lit("_"))) {
|
||||||
|
error_node(foreign_library, "`_` cannot be used as a value type");
|
||||||
|
} else {
|
||||||
|
error_node(foreign_library, "Undeclared name: %.*s", LIT(name));
|
||||||
|
}
|
||||||
|
} else if (found->kind != Entity_LibraryName) {
|
||||||
|
error_node(foreign_library, "`_` cannot be used as a library name");
|
||||||
|
} else {
|
||||||
|
// TODO(bill): Extra stuff to do with library names?
|
||||||
|
e->Procedure.foreign_library = found;
|
||||||
|
add_entity_use(c, foreign_library, found);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
e->Procedure.is_foreign = true;
|
e->Procedure.is_foreign = true;
|
||||||
e->Procedure.foreign_name = name;
|
e->Procedure.foreign_name = name;
|
||||||
|
|
||||||
@@ -532,9 +479,19 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
|||||||
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
|
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
|
||||||
GB_ASSERT(body->kind == AstNode_BlockStmt);
|
GB_ASSERT(body->kind == AstNode_BlockStmt);
|
||||||
|
|
||||||
|
String proc_name = {0};
|
||||||
|
if (token.kind == Token_Ident) {
|
||||||
|
proc_name = token.string;
|
||||||
|
} else {
|
||||||
|
// TODO(bill): Better name
|
||||||
|
proc_name = str_lit("(anonymous-procedure)");
|
||||||
|
}
|
||||||
|
|
||||||
CheckerContext old_context = c->context;
|
CheckerContext old_context = c->context;
|
||||||
c->context.scope = decl->scope;
|
c->context.scope = decl->scope;
|
||||||
c->context.decl = decl;
|
c->context.decl = decl;
|
||||||
|
c->context.proc_name = proc_name;
|
||||||
|
|
||||||
|
|
||||||
GB_ASSERT(type->kind == Type_Proc);
|
GB_ASSERT(type->kind == Type_Proc);
|
||||||
if (type->Proc.param_count > 0) {
|
if (type->Proc.param_count > 0) {
|
||||||
@@ -545,6 +502,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
|||||||
if (!(e->flags & EntityFlag_Anonymous)) {
|
if (!(e->flags & EntityFlag_Anonymous)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
bool is_immutable = e->Variable.is_immutable;
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
Type *t = base_type(type_deref(e->type));
|
Type *t = base_type(type_deref(e->type));
|
||||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||||
@@ -554,6 +512,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
|||||||
Entity *f = (*found)->elements.entries.e[i].value;
|
Entity *f = (*found)->elements.entries.e[i].value;
|
||||||
if (f->kind == Entity_Variable) {
|
if (f->kind == Entity_Variable) {
|
||||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||||
|
uvar->Variable.is_immutable = is_immutable;
|
||||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||||
if (prev != NULL) {
|
if (prev != NULL) {
|
||||||
error(e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
error(e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
||||||
+1239
-803
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_scope_decls(c, stmts, 1.2*stmts.count, NULL);
|
check_scope_decls(c, stmts, 1.2*stmts.count);
|
||||||
|
|
||||||
bool ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
|
bool ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
|
||||||
flags &= ~Stmt_FallthroughAllowed;
|
flags &= ~Stmt_FallthroughAllowed;
|
||||||
@@ -127,13 +127,13 @@ bool check_is_terminating(AstNode *node) {
|
|||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ws, WhileStmt, node);
|
case_ast_node(fs, ForStmt, node);
|
||||||
if (ws->cond != NULL && !check_has_break(ws->body, true)) {
|
if (!check_has_break(fs->body, true)) {
|
||||||
return check_is_terminating(ws->body);
|
return check_is_terminating(fs->body);
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(rs, ForStmt, node);
|
case_ast_node(rs, RangeStmt, node);
|
||||||
if (!check_has_break(rs->body, true)) {
|
if (!check_has_break(rs->body, true)) {
|
||||||
return check_is_terminating(rs->body);
|
return check_is_terminating(rs->body);
|
||||||
}
|
}
|
||||||
@@ -184,7 +184,7 @@ bool check_is_terminating(AstNode *node) {
|
|||||||
|
|
||||||
Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
||||||
if (op_a->mode == Addressing_Invalid ||
|
if (op_a->mode == Addressing_Invalid ||
|
||||||
op_a->type == t_invalid) {
|
(op_a->type == t_invalid && op_a->mode != Addressing_Overload)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,33 +195,67 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
|||||||
str_eq(node->Ident.string, str_lit("_"))) {
|
str_eq(node->Ident.string, str_lit("_"))) {
|
||||||
add_entity_definition(&c->info, node, NULL);
|
add_entity_definition(&c->info, node, NULL);
|
||||||
check_assignment(c, op_a, NULL, str_lit("assignment to `_` identifier"));
|
check_assignment(c, op_a, NULL, str_lit("assignment to `_` identifier"));
|
||||||
if (op_a->mode == Addressing_Invalid)
|
if (op_a->mode == Addressing_Invalid) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
return op_a->type;
|
return op_a->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *e = NULL;
|
Entity *e = NULL;
|
||||||
bool used = false;
|
bool used = false;
|
||||||
if (node->kind == AstNode_Ident) {
|
|
||||||
ast_node(i, Ident, node);
|
|
||||||
e = scope_lookup_entity(c->context.scope, i->string);
|
|
||||||
if (e != NULL && e->kind == Entity_Variable) {
|
|
||||||
used = (e->flags & EntityFlag_Used) != 0; // TODO(bill): Make backup just in case
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Operand op_b = {Addressing_Invalid};
|
Operand op_b = {Addressing_Invalid};
|
||||||
check_expr(c, &op_b, lhs);
|
|
||||||
if (e) {
|
|
||||||
e->flags |= EntityFlag_Used*used;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
check_expr(c, &op_b, lhs);
|
||||||
if (op_b.mode == Addressing_Invalid ||
|
if (op_b.mode == Addressing_Invalid ||
|
||||||
op_b.type == t_invalid) {
|
op_b.type == t_invalid) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (op_a->mode == Addressing_Overload) {
|
||||||
|
isize overload_count = op_a->overload_count;
|
||||||
|
Entity **procs = op_a->overload_entities;
|
||||||
|
GB_ASSERT(procs != NULL && overload_count > 0);
|
||||||
|
|
||||||
|
// NOTE(bill): These should be done
|
||||||
|
for (isize i = 0; i < overload_count; i++) {
|
||||||
|
Type *t = base_type(procs[i]->type);
|
||||||
|
if (t == t_invalid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Operand x = {0};
|
||||||
|
x.mode = Addressing_Value;
|
||||||
|
x.type = t;
|
||||||
|
if (check_is_assignable_to(c, &x, op_b.type)) {
|
||||||
|
e = procs[i];
|
||||||
|
add_entity_use(c, op_a->expr, e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e != NULL) {
|
||||||
|
// HACK TODO(bill): Should the entities be freed as it's technically a leak
|
||||||
|
op_a->mode = Addressing_Value;
|
||||||
|
op_a->type = e->type;
|
||||||
|
op_a->overload_count = 0;
|
||||||
|
op_a->overload_entities = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (node->kind == AstNode_Ident) {
|
||||||
|
ast_node(i, Ident, node);
|
||||||
|
e = scope_lookup_entity(c->context.scope, i->string);
|
||||||
|
if (e != NULL && e->kind == Entity_Variable) {
|
||||||
|
used = (e->flags & EntityFlag_Used) != 0; // TODO(bill): Make backup just in case
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e != NULL && used) {
|
||||||
|
e->flags |= EntityFlag_Used;
|
||||||
|
}
|
||||||
|
|
||||||
switch (op_b.mode) {
|
switch (op_b.mode) {
|
||||||
case Addressing_Invalid:
|
case Addressing_Invalid:
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -236,13 +270,10 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gbString str = expr_to_string(op_b.expr);
|
gbString str = expr_to_string(op_b.expr);
|
||||||
switch (op_b.mode) {
|
if (e != NULL && e->kind == Entity_Variable && e->Variable.is_immutable) {
|
||||||
case Addressing_Value:
|
error_node(op_b.expr, "Cannot assign to an immutable: `%s`", str);
|
||||||
|
} else {
|
||||||
error_node(op_b.expr, "Cannot assign to `%s`", str);
|
error_node(op_b.expr, "Cannot assign to `%s`", str);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
error_node(op_b.expr, "Cannot assign to `%s`", str);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
} break;
|
} break;
|
||||||
@@ -276,12 +307,13 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
u32 in = node->stmt_state_flags;
|
u32 in = node->stmt_state_flags;
|
||||||
u32 out = c->context.stmt_state_flags;
|
u32 out = c->context.stmt_state_flags;
|
||||||
|
|
||||||
if (in & StmtStateFlag_bounds_check) {
|
if (in & StmtStateFlag_no_bounds_check) {
|
||||||
out |= StmtStateFlag_bounds_check;
|
|
||||||
out &= ~StmtStateFlag_no_bounds_check;
|
|
||||||
} else if (in & StmtStateFlag_no_bounds_check) {
|
|
||||||
out |= StmtStateFlag_no_bounds_check;
|
out |= StmtStateFlag_no_bounds_check;
|
||||||
out &= ~StmtStateFlag_bounds_check;
|
out &= ~StmtStateFlag_bounds_check;
|
||||||
|
} else {
|
||||||
|
// if (in & StmtStateFlag_bounds_check) {
|
||||||
|
out |= StmtStateFlag_bounds_check;
|
||||||
|
out &= ~StmtStateFlag_no_bounds_check;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->context.stmt_state_flags = out;
|
c->context.stmt_state_flags = out;
|
||||||
@@ -302,7 +334,7 @@ typedef struct TypeAndToken {
|
|||||||
#define MAP_TYPE TypeAndToken
|
#define MAP_TYPE TypeAndToken
|
||||||
#define MAP_PROC map_type_and_token_
|
#define MAP_PROC map_type_and_token_
|
||||||
#define MAP_NAME MapTypeAndToken
|
#define MAP_NAME MapTypeAndToken
|
||||||
#include "../map.c"
|
#include "map.c"
|
||||||
|
|
||||||
void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
|
void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
|
||||||
Operand operand = {Addressing_Invalid};
|
Operand operand = {Addressing_Invalid};
|
||||||
@@ -495,7 +527,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
case_ast_node(rs, ReturnStmt, node);
|
case_ast_node(rs, ReturnStmt, node);
|
||||||
GB_ASSERT(c->proc_stack.count > 0);
|
GB_ASSERT(c->proc_stack.count > 0);
|
||||||
|
|
||||||
if (c->in_defer) {
|
if (c->context.in_defer) {
|
||||||
error(rs->token, "You cannot `return` within a defer statement");
|
error(rs->token, "You cannot `return` within a defer statement");
|
||||||
// TODO(bill): Should I break here?
|
// TODO(bill): Should I break here?
|
||||||
break;
|
break;
|
||||||
@@ -517,35 +549,50 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
if (rs->results.count == 0) {
|
if (rs->results.count == 0) {
|
||||||
error_node(node, "Expected %td return values, got 0", result_count);
|
error_node(node, "Expected %td return values, got 0", result_count);
|
||||||
} else {
|
} else {
|
||||||
|
// TokenPos pos = rs->token.pos;
|
||||||
|
// if (pos.line == 10) {
|
||||||
|
// gb_printf_err("%s\n", type_to_string(variables[0]->type));
|
||||||
|
// }
|
||||||
check_init_variables(c, variables, result_count,
|
check_init_variables(c, variables, result_count,
|
||||||
rs->results, str_lit("return statement"));
|
rs->results, str_lit("return statement"));
|
||||||
|
// if (pos.line == 10) {
|
||||||
|
// AstNode *x = rs->results.e[0];
|
||||||
|
// gb_printf_err("%s\n", expr_to_string(x));
|
||||||
|
// gb_printf_err("%s\n", type_to_string(type_of_expr(&c->info, x)));
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
} else if (rs->results.count > 0) {
|
} else if (rs->results.count > 0) {
|
||||||
error_node(rs->results.e[0], "No return values expected");
|
error_node(rs->results.e[0], "No return values expected");
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ws, WhileStmt, node);
|
case_ast_node(fs, ForStmt, node);
|
||||||
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
|
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
|
||||||
check_open_scope(c, node);
|
check_open_scope(c, node);
|
||||||
|
|
||||||
if (ws->init != NULL) {
|
if (fs->init != NULL) {
|
||||||
check_stmt(c, ws->init, 0);
|
check_stmt(c, fs->init, 0);
|
||||||
}
|
}
|
||||||
if (ws->cond) {
|
if (fs->cond != NULL) {
|
||||||
Operand operand = {Addressing_Invalid};
|
Operand o = {Addressing_Invalid};
|
||||||
check_expr(c, &operand, ws->cond);
|
check_expr(c, &o, fs->cond);
|
||||||
if (operand.mode != Addressing_Invalid &&
|
if (o.mode != Addressing_Invalid && !is_type_boolean(o.type)) {
|
||||||
!is_type_boolean(operand.type)) {
|
error_node(fs->cond, "Non-boolean condition in `for` statement");
|
||||||
error_node(ws->cond, "Non-boolean condition in `while` statement");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check_stmt(c, ws->body, new_flags);
|
if (fs->post != NULL) {
|
||||||
|
check_stmt(c, fs->post, 0);
|
||||||
|
|
||||||
|
if (fs->post->kind != AstNode_AssignStmt) {
|
||||||
|
error_node(fs->post, "`for` statement post statement must be an assignment");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check_stmt(c, fs->body, new_flags);
|
||||||
|
|
||||||
check_close_scope(c);
|
check_close_scope(c);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(rs, ForStmt, node);
|
case_ast_node(rs, RangeStmt, node);
|
||||||
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
|
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
|
||||||
check_open_scope(c, node);
|
check_open_scope(c, node);
|
||||||
|
|
||||||
@@ -602,9 +649,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Type *type = x.type;
|
Type *type = x.type;
|
||||||
Type *bt = base_type(base_enum_type(type));
|
if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type)) {
|
||||||
|
|
||||||
if (!is_type_integer(bt) && !is_type_float(bt) && !is_type_pointer(bt)) {
|
|
||||||
error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
|
error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
|
||||||
goto skip_expr;
|
goto skip_expr;
|
||||||
}
|
}
|
||||||
@@ -616,6 +661,12 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
|
|
||||||
GB_ASSERT(are_types_identical(x.type, y.type));
|
GB_ASSERT(are_types_identical(x.type, y.type));
|
||||||
|
|
||||||
|
TokenKind op = Token_Lt;
|
||||||
|
switch (ie->op.kind) {
|
||||||
|
case Token_HalfOpenRange: op = Token_Lt; break;
|
||||||
|
case Token_Ellipsis: op = Token_LtEq; break;
|
||||||
|
default: error(ie->op, "Invalid range operator"); break;
|
||||||
|
}
|
||||||
bool ok = compare_exact_values(Token_Lt, a, b);
|
bool ok = compare_exact_values(Token_Lt, a, b);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
// TODO(bill): Better error message
|
// TODO(bill): Better error message
|
||||||
@@ -642,11 +693,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Type_Array:
|
case Type_Array:
|
||||||
|
// val = make_type_pointer(c->allocator, t->Array.elem);
|
||||||
val = t->Array.elem;
|
val = t->Array.elem;
|
||||||
idx = t_int;
|
idx = t_int;
|
||||||
break;
|
break;
|
||||||
case Type_Slice:
|
case Type_Slice:
|
||||||
val = t->Array.elem;
|
// val = make_type_pointer(c->allocator, t->Slice.elem);
|
||||||
|
val = t->Slice.elem;
|
||||||
idx = t_int;
|
idx = t_int;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -682,8 +735,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
found = current_scope_lookup_entity(c->context.scope, str);
|
found = current_scope_lookup_entity(c->context.scope, str);
|
||||||
}
|
}
|
||||||
if (found == NULL) {
|
if (found == NULL) {
|
||||||
entity = make_entity_variable(c->allocator, c->context.scope, token, type);
|
entity = make_entity_variable(c->allocator, c->context.scope, token, type, true);
|
||||||
entity->Variable.is_immutable = true;
|
|
||||||
add_entity_definition(&c->info, name, entity);
|
add_entity_definition(&c->info, name, entity);
|
||||||
} else {
|
} else {
|
||||||
TokenPos pos = found->token.pos;
|
TokenPos pos = found->token.pos;
|
||||||
@@ -784,21 +836,21 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
for_array(j, cc->list) {
|
for_array(j, cc->list) {
|
||||||
AstNode *expr = cc->list.e[j];
|
AstNode *expr = cc->list.e[j];
|
||||||
Operand y = {0};
|
Operand y = {0};
|
||||||
Operand z = {0};
|
|
||||||
Token eq = {Token_CmpEq};
|
|
||||||
|
|
||||||
check_expr(c, &y, expr);
|
check_expr(c, &y, expr);
|
||||||
if (x.mode == Addressing_Invalid ||
|
if (x.mode == Addressing_Invalid ||
|
||||||
y.mode == Addressing_Invalid) {
|
y.mode == Addressing_Invalid) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
convert_to_typed(c, &y, x.type, 0);
|
convert_to_typed(c, &y, x.type, 0);
|
||||||
if (y.mode == Addressing_Invalid) {
|
if (y.mode == Addressing_Invalid) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
z = y;
|
// NOTE(bill): the ordering here matters
|
||||||
check_comparison(c, &z, &x, eq);
|
Operand z = y;
|
||||||
|
check_comparison(c, &z, &x, Token_CmpEq);
|
||||||
if (z.mode == Addressing_Invalid) {
|
if (z.mode == Addressing_Invalid) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -806,6 +858,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (y.value.kind != ExactValue_Invalid) {
|
if (y.value.kind != ExactValue_Invalid) {
|
||||||
HashKey key = hash_exact_value(y.value);
|
HashKey key = hash_exact_value(y.value);
|
||||||
TypeAndToken *found = map_type_and_token_get(&seen, key);
|
TypeAndToken *found = map_type_and_token_get(&seen, key);
|
||||||
@@ -981,9 +1034,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
tt = make_type_pointer(c->allocator, case_type);
|
tt = make_type_pointer(c->allocator, case_type);
|
||||||
add_type_info_type(c, tt);
|
add_type_info_type(c, tt);
|
||||||
}
|
}
|
||||||
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, ms->var->Ident, tt);
|
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, ms->var->Ident, tt, true);
|
||||||
tag_var->flags |= EntityFlag_Used;
|
tag_var->flags |= EntityFlag_Used;
|
||||||
tag_var->Variable.is_immutable = true;
|
|
||||||
add_entity(c, c->context.scope, ms->var, tag_var);
|
add_entity(c, c->context.scope, ms->var, tag_var);
|
||||||
add_entity_use(c, ms->var, tag_var);
|
add_entity_use(c, ms->var, tag_var);
|
||||||
}
|
}
|
||||||
@@ -1000,10 +1052,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
if (is_ast_node_decl(ds->stmt)) {
|
if (is_ast_node_decl(ds->stmt)) {
|
||||||
error(ds->token, "You cannot defer a declaration");
|
error(ds->token, "You cannot defer a declaration");
|
||||||
} else {
|
} else {
|
||||||
bool out_in_defer = c->in_defer;
|
bool out_in_defer = c->context.in_defer;
|
||||||
c->in_defer = true;
|
c->context.in_defer = true;
|
||||||
check_stmt(c, ds->stmt, 0);
|
check_stmt(c, ds->stmt, 0);
|
||||||
c->in_defer = out_in_defer;
|
c->context.in_defer = out_in_defer;
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
@@ -1033,6 +1085,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
|
|
||||||
case_ast_node(us, UsingStmt, node);
|
case_ast_node(us, UsingStmt, node);
|
||||||
switch (us->node->kind) {
|
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);
|
case_ast_node(es, ExprStmt, us->node);
|
||||||
// TODO(bill): Allow for just a LHS expression list rather than this silly code
|
// TODO(bill): Allow for just a LHS expression list rather than this silly code
|
||||||
Entity *e = NULL;
|
Entity *e = NULL;
|
||||||
@@ -1044,7 +1100,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
e = scope_lookup_entity(c->context.scope, name);
|
e = scope_lookup_entity(c->context.scope, name);
|
||||||
} else if (expr->kind == AstNode_SelectorExpr) {
|
} else if (expr->kind == AstNode_SelectorExpr) {
|
||||||
Operand o = {0};
|
Operand o = {0};
|
||||||
e = check_selector(c, &o, expr);
|
e = check_selector(c, &o, expr, NULL);
|
||||||
is_selector = true;
|
is_selector = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1160,52 +1216,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(vd, ValueDecl, us->node);
|
|
||||||
if (!vd->is_var) {
|
|
||||||
error_node(us->node, "`using` can only be applied to a variable declaration");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vd->names.count > 1 && vd->type != NULL) {
|
|
||||||
error(us->token, "`using` can only be applied to one variable of the same type");
|
|
||||||
}
|
|
||||||
|
|
||||||
check_var_decl_node(c, vd);
|
|
||||||
|
|
||||||
for_array(name_index, vd->names) {
|
|
||||||
AstNode *item = vd->names.e[name_index];
|
|
||||||
if (item->kind != AstNode_Ident) {
|
|
||||||
// TODO(bill): Handle error here???
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ast_node(i, Ident, item);
|
|
||||||
String name = i->string;
|
|
||||||
Entity *e = scope_lookup_entity(c->context.scope, name);
|
|
||||||
Type *t = base_type(type_deref(e->type));
|
|
||||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
|
||||||
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
|
|
||||||
GB_ASSERT(found != NULL);
|
|
||||||
for_array(i, (*found)->elements.entries) {
|
|
||||||
Entity *f = (*found)->elements.entries.e[i].value;
|
|
||||||
if (f->kind == Entity_Variable) {
|
|
||||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
|
||||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
|
||||||
if (prev != NULL) {
|
|
||||||
error(us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error(us->token, "`using` can only be applied to variables of type struct or raw_union");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case_end;
|
|
||||||
|
|
||||||
default:
|
|
||||||
error(us->token, "Invalid AST: Using Statement");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
@@ -1228,15 +1238,22 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
|
|
||||||
|
|
||||||
case_ast_node(vd, ValueDecl, node);
|
case_ast_node(vd, ValueDecl, node);
|
||||||
|
GB_ASSERT(!c->context.scope->is_file);
|
||||||
if (vd->is_var) {
|
if (vd->is_var) {
|
||||||
isize entity_count = vd->names.count;
|
Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count);
|
||||||
isize entity_index = 0;
|
isize entity_count = 0;
|
||||||
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
|
||||||
|
if (vd->flags & VarDeclFlag_thread_local) {
|
||||||
|
vd->flags &= ~VarDeclFlag_thread_local;
|
||||||
|
error_node(node, "`thread_local` may only be applied to a variable declaration");
|
||||||
|
}
|
||||||
|
|
||||||
for_array(i, vd->names) {
|
for_array(i, vd->names) {
|
||||||
AstNode *name = vd->names.e[i];
|
AstNode *name = vd->names.e[i];
|
||||||
Entity *entity = NULL;
|
Entity *entity = NULL;
|
||||||
if (name->kind == AstNode_Ident) {
|
if (name->kind != AstNode_Ident) {
|
||||||
|
error_node(name, "A variable declaration must be an identifier");
|
||||||
|
} else {
|
||||||
Token token = name->Ident;
|
Token token = name->Ident;
|
||||||
String str = token.string;
|
String str = token.string;
|
||||||
Entity *found = NULL;
|
Entity *found = NULL;
|
||||||
@@ -1245,8 +1262,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
found = current_scope_lookup_entity(c->context.scope, str);
|
found = current_scope_lookup_entity(c->context.scope, str);
|
||||||
}
|
}
|
||||||
if (found == NULL) {
|
if (found == NULL) {
|
||||||
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
|
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL, vd->flags&VarDeclFlag_immutable);
|
||||||
add_entity_definition(&c->info, name, entity);
|
entity->identifier = name;
|
||||||
} else {
|
} else {
|
||||||
TokenPos pos = found->token.pos;
|
TokenPos pos = found->token.pos;
|
||||||
error(token,
|
error(token,
|
||||||
@@ -1255,13 +1272,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
LIT(str), LIT(pos.file), pos.line, pos.column);
|
LIT(str), LIT(pos.file), pos.line, pos.column);
|
||||||
entity = found;
|
entity = found;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
error_node(name, "A variable declaration must be an identifier");
|
|
||||||
}
|
}
|
||||||
if (entity == NULL) {
|
if (entity == NULL) {
|
||||||
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
|
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
|
||||||
}
|
}
|
||||||
entities[entity_index++] = entity;
|
entities[entity_count++] = entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *init_type = NULL;
|
Type *init_type = NULL;
|
||||||
@@ -1281,18 +1296,60 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
e->flags |= EntityFlag_Visited;
|
e->flags |= EntityFlag_Visited;
|
||||||
|
|
||||||
if (e->type == NULL)
|
if (e->type == NULL) {
|
||||||
e->type = init_type;
|
e->type = init_type;
|
||||||
}
|
|
||||||
check_arity_match(c, vd);
|
|
||||||
|
|
||||||
check_init_variables(c, entities, entity_count, vd->values, str_lit("variable declaration"));
|
|
||||||
|
|
||||||
for_array(i, vd->names) {
|
|
||||||
if (entities[i] != NULL) {
|
|
||||||
add_entity(c, c->context.scope, vd->names.e[i], entities[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_arity_match(c, vd);
|
||||||
|
check_init_variables(c, entities, entity_count, vd->values, str_lit("variable declaration"));
|
||||||
|
|
||||||
|
for (isize i = 0; i < entity_count; i++) {
|
||||||
|
add_entity(c, c->context.scope, entities[i]->identifier, entities[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((vd->flags & VarDeclFlag_using) != 0) {
|
||||||
|
Token token = ast_node_token(node);
|
||||||
|
if (vd->type != NULL && entity_count > 1) {
|
||||||
|
error(token, "`using` can only be applied to one variable of the same type");
|
||||||
|
// TODO(bill): Should a `continue` happen here?
|
||||||
|
}
|
||||||
|
|
||||||
|
for (isize entity_index = 0; entity_index < entity_count; entity_index++) {
|
||||||
|
Entity *e = entities[entity_index];
|
||||||
|
if (e == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (e->kind != Entity_Variable) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool is_immutable = e->Variable.is_immutable;
|
||||||
|
String name = e->token.string;
|
||||||
|
Type *t = base_type(type_deref(e->type));
|
||||||
|
|
||||||
|
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||||
|
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||||
|
GB_ASSERT(found != NULL);
|
||||||
|
for_array(i, (*found)->elements.entries) {
|
||||||
|
Entity *f = (*found)->elements.entries.e[i].value;
|
||||||
|
if (f->kind == Entity_Variable) {
|
||||||
|
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||||
|
uvar->Variable.is_immutable = is_immutable;
|
||||||
|
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||||
|
if (prev != NULL) {
|
||||||
|
error(token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// NOTE(bill): skip the rest to remove extra errors
|
||||||
|
error(token, "`using` can only be applied to variables of type struct or raw_union");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// NOTE(bill): Handled elsewhere
|
// NOTE(bill): Handled elsewhere
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,17 @@ gbAllocator heap_allocator(void) {
|
|||||||
gb_global String global_module_path = {0};
|
gb_global String global_module_path = {0};
|
||||||
gb_global bool global_module_path_set = false;
|
gb_global bool global_module_path_set = false;
|
||||||
|
|
||||||
|
gb_global gbScratchMemory scratch_memory = {0};
|
||||||
|
|
||||||
|
void init_scratch_memory(isize size) {
|
||||||
|
void *memory = gb_alloc(heap_allocator(), size);
|
||||||
|
gb_scratch_memory_init(&scratch_memory, memory, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
gbAllocator scratch_allocator(void) {
|
||||||
|
return gb_scratch_allocator(&scratch_memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
i64 next_pow2(i64 n) {
|
i64 next_pow2(i64 n) {
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ typedef enum ImplicitValueId ImplicitValueId;
|
|||||||
ENTITY_KIND(Procedure) \
|
ENTITY_KIND(Procedure) \
|
||||||
ENTITY_KIND(Builtin) \
|
ENTITY_KIND(Builtin) \
|
||||||
ENTITY_KIND(ImportName) \
|
ENTITY_KIND(ImportName) \
|
||||||
|
ENTITY_KIND(LibraryName) \
|
||||||
ENTITY_KIND(Nil) \
|
ENTITY_KIND(Nil) \
|
||||||
ENTITY_KIND(ImplicitValue) \
|
ENTITY_KIND(ImplicitValue) \
|
||||||
ENTITY_KIND(Count)
|
ENTITY_KIND(Count)
|
||||||
@@ -35,8 +36,16 @@ typedef enum EntityFlag {
|
|||||||
EntityFlag_Field = 1<<3,
|
EntityFlag_Field = 1<<3,
|
||||||
EntityFlag_Param = 1<<4,
|
EntityFlag_Param = 1<<4,
|
||||||
EntityFlag_VectorElem = 1<<5,
|
EntityFlag_VectorElem = 1<<5,
|
||||||
|
EntityFlag_Ellipsis = 1<<6,
|
||||||
|
EntityFlag_NoAlias = 1<<7,
|
||||||
} EntityFlag;
|
} EntityFlag;
|
||||||
|
|
||||||
|
typedef enum OverloadKind {
|
||||||
|
Overload_No = -1,
|
||||||
|
Overload_Unknown = 0,
|
||||||
|
Overload_Yes = +1,
|
||||||
|
} OverloadKind;
|
||||||
|
|
||||||
typedef struct Entity Entity;
|
typedef struct Entity Entity;
|
||||||
struct Entity {
|
struct Entity {
|
||||||
EntityKind kind;
|
EntityKind kind;
|
||||||
@@ -58,13 +67,16 @@ struct Entity {
|
|||||||
i32 field_index;
|
i32 field_index;
|
||||||
i32 field_src_index;
|
i32 field_src_index;
|
||||||
bool is_immutable;
|
bool is_immutable;
|
||||||
|
bool is_thread_local;
|
||||||
} Variable;
|
} Variable;
|
||||||
i32 TypeName;
|
i32 TypeName;
|
||||||
struct {
|
struct {
|
||||||
bool is_foreign;
|
bool is_foreign;
|
||||||
String foreign_name;
|
String foreign_name;
|
||||||
String link_name;
|
Entity * foreign_library;
|
||||||
u64 tags;
|
String link_name;
|
||||||
|
u64 tags;
|
||||||
|
OverloadKind overload_kind;
|
||||||
} Procedure;
|
} Procedure;
|
||||||
struct {
|
struct {
|
||||||
BuiltinProcId id;
|
BuiltinProcId id;
|
||||||
@@ -75,6 +87,11 @@ struct Entity {
|
|||||||
Scope *scope;
|
Scope *scope;
|
||||||
bool used;
|
bool used;
|
||||||
} ImportName;
|
} ImportName;
|
||||||
|
struct {
|
||||||
|
String path;
|
||||||
|
String name;
|
||||||
|
bool used;
|
||||||
|
} LibraryName;
|
||||||
i32 Nil;
|
i32 Nil;
|
||||||
struct {
|
struct {
|
||||||
// TODO(bill): Should this be a user-level construct rather than compiler-level?
|
// TODO(bill): Should this be a user-level construct rather than compiler-level?
|
||||||
@@ -85,9 +102,6 @@ struct Entity {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Entity *e_iota = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
|
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
|
||||||
Entity *entity = gb_alloc_item(a, Entity);
|
Entity *entity = gb_alloc_item(a, Entity);
|
||||||
entity->kind = kind;
|
entity->kind = kind;
|
||||||
@@ -97,13 +111,15 @@ Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token,
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *type) {
|
Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *type, bool is_immutable) {
|
||||||
Entity *entity = alloc_entity(a, Entity_Variable, scope, token, type);
|
Entity *entity = alloc_entity(a, Entity_Variable, scope, token, type);
|
||||||
|
entity->Variable.is_immutable = is_immutable;
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
|
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
|
||||||
GB_ASSERT(parent != NULL);
|
GB_ASSERT(parent != NULL);
|
||||||
|
token.pos = parent->token.pos;
|
||||||
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
|
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
|
||||||
entity->using_parent = parent;
|
entity->using_parent = parent;
|
||||||
entity->flags |= EntityFlag_Anonymous;
|
entity->flags |= EntityFlag_Anonymous;
|
||||||
@@ -122,16 +138,16 @@ Entity *make_entity_type_name(gbAllocator a, Scope *scope, Token token, Type *ty
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous) {
|
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous, bool is_immutable) {
|
||||||
Entity *entity = make_entity_variable(a, scope, token, type);
|
Entity *entity = make_entity_variable(a, scope, token, type, is_immutable);
|
||||||
entity->flags |= EntityFlag_Used;
|
entity->flags |= EntityFlag_Used;
|
||||||
entity->flags |= EntityFlag_Anonymous*(anonymous != 0);
|
if (anonymous) entity->flags |= EntityFlag_Anonymous;
|
||||||
entity->flags |= EntityFlag_Param;
|
entity->flags |= EntityFlag_Param;
|
||||||
return entity;
|
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 anonymous, i32 field_src_index) {
|
||||||
Entity *entity = make_entity_variable(a, scope, token, type);
|
Entity *entity = make_entity_variable(a, scope, token, type, false);
|
||||||
entity->Variable.field_src_index = field_src_index;
|
entity->Variable.field_src_index = field_src_index;
|
||||||
entity->Variable.field_index = field_src_index;
|
entity->Variable.field_index = field_src_index;
|
||||||
entity->flags |= EntityFlag_Field;
|
entity->flags |= EntityFlag_Field;
|
||||||
@@ -140,7 +156,7 @@ Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Entity *make_entity_vector_elem(gbAllocator a, Scope *scope, Token token, Type *type, i32 field_src_index) {
|
Entity *make_entity_vector_elem(gbAllocator a, Scope *scope, Token token, Type *type, i32 field_src_index) {
|
||||||
Entity *entity = make_entity_variable(a, scope, token, type);
|
Entity *entity = make_entity_variable(a, scope, token, type, false);
|
||||||
entity->Variable.field_src_index = field_src_index;
|
entity->Variable.field_src_index = field_src_index;
|
||||||
entity->Variable.field_index = field_src_index;
|
entity->Variable.field_index = field_src_index;
|
||||||
entity->flags |= EntityFlag_Field;
|
entity->flags |= EntityFlag_Field;
|
||||||
@@ -169,6 +185,14 @@ Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||||
|
String path, String name) {
|
||||||
|
Entity *entity = alloc_entity(a, Entity_LibraryName, scope, token, type);
|
||||||
|
entity->LibraryName.path = path;
|
||||||
|
entity->LibraryName.name = name;
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
|
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
|
||||||
Token token = make_token_ident(name);
|
Token token = make_token_ident(name);
|
||||||
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type);
|
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type);
|
||||||
@@ -185,6 +209,6 @@ Entity *make_entity_implicit_value(gbAllocator a, String name, Type *type, Impli
|
|||||||
|
|
||||||
Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
|
Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
|
||||||
token.string = str_lit("_");
|
token.string = str_lit("_");
|
||||||
return make_entity_variable(a, scope, token, NULL);
|
return make_entity_variable(a, scope, token, NULL, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
+45
-18
@@ -54,30 +54,57 @@ ExactValue make_exact_value_string(String string) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue make_exact_value_integer_from_string(String string) {
|
|
||||||
// TODO(bill): Allow for numbers with underscores in them
|
|
||||||
ExactValue result = {ExactValue_Integer};
|
|
||||||
i32 base = 10;
|
|
||||||
if (string.len > 2 && string.text[0] == '0') {
|
|
||||||
switch (string.text[1]) {
|
|
||||||
case 'b': base = 2; break;
|
|
||||||
case 'o': base = 8; break;
|
|
||||||
case 'd': base = 10; break;
|
|
||||||
case 'x': base = 16; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.value_integer = gb_str_to_i64(cast(char *)string.text, NULL, base);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExactValue make_exact_value_integer(i64 i) {
|
ExactValue make_exact_value_integer(i64 i) {
|
||||||
ExactValue result = {ExactValue_Integer};
|
ExactValue result = {ExactValue_Integer};
|
||||||
result.value_integer = i;
|
result.value_integer = i;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExactValue make_exact_value_integer_from_string(String string) {
|
||||||
|
// TODO(bill): Allow for numbers with underscores in them
|
||||||
|
i32 base = 10;
|
||||||
|
bool has_prefix = false;
|
||||||
|
if (string.len > 2 && string.text[0] == '0') {
|
||||||
|
switch (string.text[1]) {
|
||||||
|
case 'b': base = 2; has_prefix = true; break;
|
||||||
|
case 'o': base = 8; has_prefix = true; break;
|
||||||
|
case 'd': base = 10; has_prefix = true; break;
|
||||||
|
case 'x': base = 16; has_prefix = true; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *text = string.text;
|
||||||
|
isize len = string.len;
|
||||||
|
if (has_prefix) {
|
||||||
|
text += 2;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
i64 result = 0;
|
||||||
|
for (isize i = 0; i < len; i++) {
|
||||||
|
Rune r = cast(Rune)text[i];
|
||||||
|
if (r == '_') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
i64 v = 0;
|
||||||
|
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 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result *= base;
|
||||||
|
result += v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return make_exact_value_integer(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ExactValue make_exact_value_float_from_string(String string) {
|
ExactValue make_exact_value_float_from_string(String string) {
|
||||||
// TODO(bill): Allow for numbers with underscores in them
|
// TODO(bill): Allow for numbers with underscores in them
|
||||||
ExactValue result = {ExactValue_Float};
|
ExactValue result = {ExactValue_Float};
|
||||||
|
|||||||
+3
-7
@@ -4819,14 +4819,10 @@ GB_ALLOCATOR_PROC(gb_heap_allocator_proc) {
|
|||||||
#else
|
#else
|
||||||
// TODO(bill): *nix version that's decent
|
// TODO(bill): *nix version that's decent
|
||||||
case gbAllocation_Alloc: {
|
case gbAllocation_Alloc: {
|
||||||
gbAllocationHeader *header;
|
ptr = aligned_alloc(alignment, size);
|
||||||
isize total_size = size + alignment + gb_size_of(gbAllocationHeader);
|
if (flags & gbAllocatorFlag_ClearToZero) {
|
||||||
ptr = malloc(total_size);
|
|
||||||
header = cast(gbAllocationHeader *)ptr;
|
|
||||||
ptr = gb_align_forward(header+1, alignment);
|
|
||||||
gb_allocation_header_fill(header, ptr, size);
|
|
||||||
if (flags & gbAllocatorFlag_ClearToZero)
|
|
||||||
gb_zero_size(ptr, size);
|
gb_zero_size(ptr, size);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case gbAllocation_Free: {
|
case gbAllocation_Free: {
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
|
|||||||
array_add(ops, i->PtrOffset.address);
|
array_add(ops, i->PtrOffset.address);
|
||||||
array_add(ops, i->PtrOffset.offset);
|
array_add(ops, i->PtrOffset.offset);
|
||||||
break;
|
break;
|
||||||
case irInstr_ArrayExtractValue:
|
|
||||||
array_add(ops, i->ArrayExtractValue.address);
|
|
||||||
break;
|
|
||||||
case irInstr_StructExtractValue:
|
case irInstr_StructExtractValue:
|
||||||
array_add(ops, i->StructExtractValue.address);
|
array_add(ops, i->StructExtractValue.address);
|
||||||
break;
|
break;
|
||||||
|
|||||||
+43
-46
@@ -141,58 +141,59 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
i64 word_bits = 8*s.word_size;
|
i64 word_bits = 8*s.word_size;
|
||||||
GB_ASSERT_NOT_NULL(t);
|
GB_ASSERT_NOT_NULL(t);
|
||||||
t = default_type(t);
|
t = default_type(t);
|
||||||
|
GB_ASSERT(is_type_typed(t));
|
||||||
|
|
||||||
switch (t->kind) {
|
switch (t->kind) {
|
||||||
case Type_Basic:
|
case Type_Basic:
|
||||||
switch (t->Basic.kind) {
|
switch (t->Basic.kind) {
|
||||||
case Basic_bool: ir_fprintf(f, "i1"); break;
|
case Basic_bool: ir_fprintf(f, "i1"); return;
|
||||||
case Basic_i8: ir_fprintf(f, "i8"); break;
|
case Basic_i8: ir_fprintf(f, "i8"); return;
|
||||||
case Basic_u8: ir_fprintf(f, "i8"); break;
|
case Basic_u8: ir_fprintf(f, "i8"); return;
|
||||||
case Basic_i16: ir_fprintf(f, "i16"); break;
|
case Basic_i16: ir_fprintf(f, "i16"); return;
|
||||||
case Basic_u16: ir_fprintf(f, "i16"); break;
|
case Basic_u16: ir_fprintf(f, "i16"); return;
|
||||||
case Basic_i32: ir_fprintf(f, "i32"); break;
|
case Basic_i32: ir_fprintf(f, "i32"); return;
|
||||||
case Basic_u32: ir_fprintf(f, "i32"); break;
|
case Basic_u32: ir_fprintf(f, "i32"); return;
|
||||||
case Basic_i64: ir_fprintf(f, "i64"); break;
|
case Basic_i64: ir_fprintf(f, "i64"); return;
|
||||||
case Basic_u64: ir_fprintf(f, "i64"); break;
|
case Basic_u64: ir_fprintf(f, "i64"); return;
|
||||||
// case Basic_i128: ir_fprintf(f, "i128"); break;
|
// case Basic_i128: ir_fprintf(f, "i128"); return;
|
||||||
// case Basic_u128: ir_fprintf(f, "i128"); break;
|
// case Basic_u128: ir_fprintf(f, "i128"); return;
|
||||||
// case Basic_f16: ir_fprintf(f, "half"); break;
|
// case Basic_f16: ir_fprintf(f, "half"); return;
|
||||||
case Basic_f32: ir_fprintf(f, "float"); break;
|
case Basic_f32: ir_fprintf(f, "float"); return;
|
||||||
case Basic_f64: ir_fprintf(f, "double"); break;
|
case Basic_f64: ir_fprintf(f, "double"); return;
|
||||||
// case Basic_f128: ir_fprintf(f, "fp128"); break;
|
// case Basic_f128: ir_fprintf(f, "fp128"); return;
|
||||||
case Basic_rawptr: ir_fprintf(f, "%%..rawptr"); break;
|
case Basic_rawptr: ir_fprintf(f, "%%..rawptr"); return;
|
||||||
case Basic_string: ir_fprintf(f, "%%..string"); break;
|
case Basic_string: ir_fprintf(f, "%%..string"); return;
|
||||||
case Basic_uint: ir_fprintf(f, "i%lld", word_bits); break;
|
case Basic_uint: ir_fprintf(f, "i%lld", word_bits); return;
|
||||||
case Basic_int: ir_fprintf(f, "i%lld", word_bits); break;
|
case Basic_int: ir_fprintf(f, "i%lld", word_bits); return;
|
||||||
case Basic_any: ir_fprintf(f, "%%..any"); break;
|
case Basic_any: ir_fprintf(f, "%%..any"); return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Type_Pointer:
|
case Type_Pointer:
|
||||||
ir_print_type(f, m, t->Pointer.elem);
|
ir_print_type(f, m, t->Pointer.elem);
|
||||||
ir_fprintf(f, "*");
|
ir_fprintf(f, "*");
|
||||||
break;
|
return;
|
||||||
case Type_Maybe:
|
case Type_Maybe:
|
||||||
ir_fprintf(f, "{");
|
ir_fprintf(f, "{");
|
||||||
ir_print_type(f, m, t->Maybe.elem);
|
ir_print_type(f, m, t->Maybe.elem);
|
||||||
ir_fprintf(f, ", ");
|
ir_fprintf(f, ", ");
|
||||||
ir_print_type(f, m, t_bool);
|
ir_print_type(f, m, t_bool);
|
||||||
ir_fprintf(f, "}");
|
ir_fprintf(f, "}");
|
||||||
break;
|
return;
|
||||||
case Type_Array:
|
case Type_Array:
|
||||||
ir_fprintf(f, "[%lld x ", t->Array.count);
|
ir_fprintf(f, "[%lld x ", t->Array.count);
|
||||||
ir_print_type(f, m, t->Array.elem);
|
ir_print_type(f, m, t->Array.elem);
|
||||||
ir_fprintf(f, "]");
|
ir_fprintf(f, "]");
|
||||||
break;
|
return;
|
||||||
case Type_Vector:
|
case Type_Vector:
|
||||||
ir_fprintf(f, "<%lld x ", t->Vector.count);
|
ir_fprintf(f, "<%lld x ", t->Vector.count);
|
||||||
ir_print_type(f, m, t->Vector.elem);
|
ir_print_type(f, m, t->Vector.elem);
|
||||||
ir_fprintf(f, ">");
|
ir_fprintf(f, ">");
|
||||||
break;
|
return;
|
||||||
case Type_Slice:
|
case Type_Slice:
|
||||||
ir_fprintf(f, "{");
|
ir_fprintf(f, "{");
|
||||||
ir_print_type(f, m, t->Slice.elem);
|
ir_print_type(f, m, t->Slice.elem);
|
||||||
ir_fprintf(f, "*, i%lld, i%lld}", word_bits, word_bits);
|
ir_fprintf(f, "*, i%lld, i%lld}", word_bits, word_bits);
|
||||||
break;
|
return;
|
||||||
case Type_Record: {
|
case Type_Record: {
|
||||||
switch (t->Record.kind) {
|
switch (t->Record.kind) {
|
||||||
case TypeRecord_Struct:
|
case TypeRecord_Struct:
|
||||||
@@ -210,24 +211,24 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
if (t->Record.struct_is_packed) {
|
if (t->Record.struct_is_packed) {
|
||||||
ir_fprintf(f, ">");
|
ir_fprintf(f, ">");
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
case TypeRecord_Union: {
|
case TypeRecord_Union: {
|
||||||
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
|
// 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)
|
// LLVM takes the first element's alignment as the entire alignment (like C)
|
||||||
i64 size_of_union = type_size_of(s, heap_allocator(), t) - s.word_size;
|
i64 size_of_union = type_size_of(s, heap_allocator(), t) - s.word_size;
|
||||||
i64 align_of_union = type_align_of(s, heap_allocator(), t);
|
i64 align_of_union = type_align_of(s, heap_allocator(), t);
|
||||||
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align_of_union, size_of_union, word_bits);
|
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align_of_union, size_of_union, word_bits);
|
||||||
} break;
|
} return;
|
||||||
case TypeRecord_RawUnion: {
|
case TypeRecord_RawUnion: {
|
||||||
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
|
// 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)
|
// LLVM takes the first element's alignment as the entire alignment (like C)
|
||||||
i64 size_of_union = type_size_of(s, heap_allocator(), t);
|
i64 size_of_union = type_size_of(s, heap_allocator(), t);
|
||||||
i64 align_of_union = type_align_of(s, heap_allocator(), t);
|
i64 align_of_union = type_align_of(s, heap_allocator(), t);
|
||||||
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
|
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
|
||||||
} break;
|
} return;
|
||||||
case TypeRecord_Enum:
|
case TypeRecord_Enum:
|
||||||
ir_print_type(f, m, base_enum_type(t));
|
ir_print_type(f, m, base_enum_type(t));
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -240,7 +241,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
} else {
|
} else {
|
||||||
ir_print_type(f, m, base_type(t));
|
ir_print_type(f, m, base_type(t));
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
case Type_Tuple:
|
case Type_Tuple:
|
||||||
if (t->Tuple.variable_count == 1) {
|
if (t->Tuple.variable_count == 1) {
|
||||||
ir_print_type(f, m, t->Tuple.variables[0]->type);
|
ir_print_type(f, m, t->Tuple.variables[0]->type);
|
||||||
@@ -254,7 +255,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
}
|
}
|
||||||
ir_fprintf(f, "}");
|
ir_fprintf(f, "}");
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
case Type_Proc: {
|
case Type_Proc: {
|
||||||
if (t->Proc.result_count == 0) {
|
if (t->Proc.result_count == 0) {
|
||||||
ir_fprintf(f, "void");
|
ir_fprintf(f, "void");
|
||||||
@@ -270,7 +271,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
ir_print_type(f, m, params->variables[i]->type);
|
ir_print_type(f, m, params->variables[i]->type);
|
||||||
}
|
}
|
||||||
ir_fprintf(f, ")*");
|
ir_fprintf(f, ")*");
|
||||||
} break;
|
} return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,7 +685,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case irInstr_Store: {
|
case irInstr_Store: {
|
||||||
Type *type = ir_type(instr->Store.value);
|
Type *type = type_deref(ir_type(instr->Store.address));
|
||||||
ir_fprintf(f, "store ");
|
ir_fprintf(f, "store ");
|
||||||
ir_print_type(f, m, type);
|
ir_print_type(f, m, type);
|
||||||
ir_fprintf(f, " ");
|
ir_fprintf(f, " ");
|
||||||
@@ -789,16 +790,6 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_fprintf(f, "\n");
|
ir_fprintf(f, "\n");
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case irInstr_ArrayExtractValue: {
|
|
||||||
Type *et = ir_type(instr->ArrayExtractValue.address);
|
|
||||||
ir_fprintf(f, "%%%d = extractvalue ", value->index);
|
|
||||||
|
|
||||||
ir_print_type(f, m, et);
|
|
||||||
ir_fprintf(f, " ");
|
|
||||||
ir_print_value(f, m, instr->ArrayExtractValue.address, et);
|
|
||||||
ir_fprintf(f, ", %d\n", instr->ArrayExtractValue.index);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case irInstr_StructExtractValue: {
|
case irInstr_StructExtractValue: {
|
||||||
Type *et = ir_type(instr->StructExtractValue.address);
|
Type *et = ir_type(instr->StructExtractValue.address);
|
||||||
ir_fprintf(f, "%%%d = extractvalue ", value->index);
|
ir_fprintf(f, "%%%d = extractvalue ", value->index);
|
||||||
@@ -1078,6 +1069,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_fprintf(f, ", ");
|
ir_fprintf(f, ", ");
|
||||||
}
|
}
|
||||||
ir_print_type(f, m, t);
|
ir_print_type(f, m, t);
|
||||||
|
if (e->flags&EntityFlag_NoAlias) {
|
||||||
|
ir_fprintf(f, " noalias");
|
||||||
|
}
|
||||||
ir_fprintf(f, " ");
|
ir_fprintf(f, " ");
|
||||||
irValue *arg = call->args[i];
|
irValue *arg = call->args[i];
|
||||||
ir_print_value(f, m, arg, t);
|
ir_print_value(f, m, arg, t);
|
||||||
@@ -1241,9 +1235,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||||
if (proc->body == NULL) {
|
if (proc->body == NULL) {
|
||||||
ir_fprintf(f, "declare ");
|
ir_fprintf(f, "declare ");
|
||||||
if (proc->tags & ProcTag_dll_import) {
|
// if (proc->tags & ProcTag_dll_import) {
|
||||||
ir_fprintf(f, "dllimport ");
|
// ir_fprintf(f, "dllimport ");
|
||||||
}
|
// }
|
||||||
} else {
|
} else {
|
||||||
ir_fprintf(f, "\n");
|
ir_fprintf(f, "\n");
|
||||||
ir_fprintf(f, "define ");
|
ir_fprintf(f, "define ");
|
||||||
@@ -1277,6 +1271,9 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
|||||||
ir_fprintf(f, ", ");
|
ir_fprintf(f, ", ");
|
||||||
}
|
}
|
||||||
ir_print_type(f, m, e->type);
|
ir_print_type(f, m, e->type);
|
||||||
|
if (e->flags&EntityFlag_NoAlias) {
|
||||||
|
ir_fprintf(f, " noalias");
|
||||||
|
}
|
||||||
if (proc->body != NULL) {
|
if (proc->body != NULL) {
|
||||||
if (!str_eq(e->token.string, str_lit("")) &&
|
if (!str_eq(e->token.string, str_lit("")) &&
|
||||||
!str_eq(e->token.string, str_lit("_"))) {
|
!str_eq(e->token.string, str_lit("_"))) {
|
||||||
|
|||||||
+10
-8
@@ -9,7 +9,7 @@ extern "C" {
|
|||||||
#include "tokenizer.c"
|
#include "tokenizer.c"
|
||||||
#include "parser.c"
|
#include "parser.c"
|
||||||
// #include "printer.c"
|
// #include "printer.c"
|
||||||
#include "checker/checker.c"
|
#include "checker.c"
|
||||||
// #include "ssa.c"
|
// #include "ssa.c"
|
||||||
#include "ir.c"
|
#include "ir.c"
|
||||||
#include "ir_opt.c"
|
#include "ir_opt.c"
|
||||||
@@ -92,6 +92,7 @@ int main(int argc, char **argv) {
|
|||||||
timings_init(&timings, str_lit("Total Time"), 128);
|
timings_init(&timings, str_lit("Total Time"), 128);
|
||||||
// defer (timings_destroy(&timings));
|
// defer (timings_destroy(&timings));
|
||||||
init_string_buffer_memory();
|
init_string_buffer_memory();
|
||||||
|
init_scratch_memory(gb_megabytes(10));
|
||||||
init_global_error_collector();
|
init_global_error_collector();
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
@@ -202,7 +203,7 @@ int main(int argc, char **argv) {
|
|||||||
i32 exit_code = 0;
|
i32 exit_code = 0;
|
||||||
// For more passes arguments: http://llvm.org/docs/Passes.html
|
// For more passes arguments: http://llvm.org/docs/Passes.html
|
||||||
exit_code = win32_exec_command_line_app("llvm-opt", false,
|
exit_code = win32_exec_command_line_app("llvm-opt", false,
|
||||||
"%.*sbin/opt %s -o %.*s.bc "
|
"\"%.*sbin/opt\" \"%s\" -o \"%.*s\".bc "
|
||||||
"-mem2reg "
|
"-mem2reg "
|
||||||
"-memcpyopt "
|
"-memcpyopt "
|
||||||
"-die "
|
"-die "
|
||||||
@@ -220,7 +221,7 @@ int main(int argc, char **argv) {
|
|||||||
timings_start_section(&timings, str_lit("llvm-llc"));
|
timings_start_section(&timings, str_lit("llvm-llc"));
|
||||||
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
||||||
exit_code = win32_exec_command_line_app("llvm-llc", false,
|
exit_code = win32_exec_command_line_app("llvm-llc", false,
|
||||||
"%.*sbin/llc %.*s.bc -filetype=obj -O%d "
|
"\"%.*sbin/llc\" \"%.*s.bc\" -filetype=obj -O%d "
|
||||||
"%.*s "
|
"%.*s "
|
||||||
// "-debug-pass=Arguments "
|
// "-debug-pass=Arguments "
|
||||||
"",
|
"",
|
||||||
@@ -234,13 +235,14 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
timings_start_section(&timings, str_lit("msvc-link"));
|
timings_start_section(&timings, str_lit("msvc-link"));
|
||||||
|
|
||||||
gbString lib_str = gb_string_make(heap_allocator(), "Kernel32.lib");
|
gbString lib_str = gb_string_make(heap_allocator(), "");
|
||||||
// defer (gb_string_free(lib_str));
|
// defer (gb_string_free(lib_str));
|
||||||
char lib_str_buf[1024] = {0};
|
char lib_str_buf[1024] = {0};
|
||||||
for_array(i, checker.info.foreign_libraries) {
|
for_array(i, ir_gen.module.foreign_library_paths) {
|
||||||
String lib = checker.info.foreign_libraries.e[i];
|
String lib = ir_gen.module.foreign_library_paths.e[i];
|
||||||
|
// gb_printf_err("Linking lib: %.*s\n", LIT(lib));
|
||||||
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
||||||
" %.*s.lib", LIT(lib));
|
" \"%.*s\"", LIT(lib));
|
||||||
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +256,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exit_code = win32_exec_command_line_app("msvc-link", true,
|
exit_code = win32_exec_command_line_app("msvc-link", true,
|
||||||
"link %.*s.obj -OUT:%.*s.%s %s "
|
"link \"%.*s\".obj -OUT:\"%.*s.%s\" %s "
|
||||||
"/defaultlib:libcmt "
|
"/defaultlib:libcmt "
|
||||||
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
|
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
|
||||||
" %.*s "
|
" %.*s "
|
||||||
|
|||||||
@@ -320,6 +320,7 @@ void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
|
|||||||
if (h->hashes.count == 0) {
|
if (h->hashes.count == 0) {
|
||||||
_J2(MAP_PROC,grow)(h);
|
_J2(MAP_PROC,grow)(h);
|
||||||
}
|
}
|
||||||
|
// Make
|
||||||
fr = _J2(MAP_PROC,_find)(h, key);
|
fr = _J2(MAP_PROC,_find)(h, key);
|
||||||
i = _J2(MAP_PROC,_add_entry)(h, key);
|
i = _J2(MAP_PROC,_add_entry)(h, key);
|
||||||
if (fr.entry_prev < 0) {
|
if (fr.entry_prev < 0) {
|
||||||
@@ -329,6 +330,7 @@ void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
|
|||||||
}
|
}
|
||||||
h->entries.e[i].next = fr.entry_index;
|
h->entries.e[i].next = fr.entry_index;
|
||||||
h->entries.e[i].value = value;
|
h->entries.e[i].value = value;
|
||||||
|
// Grow if needed
|
||||||
if (_J2(MAP_PROC,_full)(h)) {
|
if (_J2(MAP_PROC,_full)(h)) {
|
||||||
_J2(MAP_PROC,grow)(h);
|
_J2(MAP_PROC,grow)(h);
|
||||||
}
|
}
|
||||||
|
|||||||
+617
-281
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -46,7 +46,7 @@ gb_inline String make_string_c(char *text) {
|
|||||||
return make_string(cast(u8 *)cast(void *)text, gb_strlen(text));
|
return make_string(cast(u8 *)cast(void *)text, gb_strlen(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define str_lit(c_str) make_string(cast(u8 *)c_str, gb_size_of(c_str)-1)
|
#define str_lit(c_str) (String){cast(u8 *)c_str, gb_size_of(c_str)-1}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+93
-86
@@ -1,82 +1,82 @@
|
|||||||
#define TOKEN_KINDS \
|
#define TOKEN_KINDS \
|
||||||
TOKEN_KIND(Token_Invalid, "Invalid"), \
|
TOKEN_KIND(Token_Invalid, "Invalid"), \
|
||||||
TOKEN_KIND(Token_EOF, "EOF"), \
|
TOKEN_KIND(Token_EOF, "EOF"), \
|
||||||
TOKEN_KIND(Token_Comment, "Comment"), \
|
TOKEN_KIND(Token_Comment, "Comment"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__LiteralBegin, "_LiteralBegin"), \
|
TOKEN_KIND(Token__LiteralBegin, "_LiteralBegin"), \
|
||||||
TOKEN_KIND(Token_Ident, "identifier"), \
|
TOKEN_KIND(Token_Ident, "identifier"), \
|
||||||
TOKEN_KIND(Token_Integer, "integer"), \
|
TOKEN_KIND(Token_Integer, "integer"), \
|
||||||
TOKEN_KIND(Token_Float, "float"), \
|
TOKEN_KIND(Token_Float, "float"), \
|
||||||
TOKEN_KIND(Token_Rune, "rune"), \
|
TOKEN_KIND(Token_Rune, "rune"), \
|
||||||
TOKEN_KIND(Token_String, "string"), \
|
TOKEN_KIND(Token_String, "string"), \
|
||||||
TOKEN_KIND(Token__LiteralEnd, "_LiteralEnd"), \
|
TOKEN_KIND(Token__LiteralEnd, "_LiteralEnd"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
|
TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
|
||||||
TOKEN_KIND(Token_Eq, "="), \
|
TOKEN_KIND(Token_Eq, "="), \
|
||||||
TOKEN_KIND(Token_Not, "!"), \
|
TOKEN_KIND(Token_Not, "!"), \
|
||||||
TOKEN_KIND(Token_Hash, "#"), \
|
TOKEN_KIND(Token_Hash, "#"), \
|
||||||
TOKEN_KIND(Token_At, "@"), \
|
TOKEN_KIND(Token_At, "@"), \
|
||||||
TOKEN_KIND(Token_Pointer, "^"), \
|
TOKEN_KIND(Token_Pointer, "^"), \
|
||||||
TOKEN_KIND(Token_Maybe, "?"), \
|
TOKEN_KIND(Token_Maybe, "?"), \
|
||||||
TOKEN_KIND(Token_Add, "+"), \
|
TOKEN_KIND(Token_Add, "+"), \
|
||||||
TOKEN_KIND(Token_Sub, "-"), \
|
TOKEN_KIND(Token_Sub, "-"), \
|
||||||
TOKEN_KIND(Token_Mul, "*"), \
|
TOKEN_KIND(Token_Mul, "*"), \
|
||||||
TOKEN_KIND(Token_Quo, "/"), \
|
TOKEN_KIND(Token_Quo, "/"), \
|
||||||
TOKEN_KIND(Token_Mod, "%"), \
|
TOKEN_KIND(Token_Mod, "%"), \
|
||||||
TOKEN_KIND(Token_And, "&"), \
|
TOKEN_KIND(Token_And, "&"), \
|
||||||
TOKEN_KIND(Token_Or, "|"), \
|
TOKEN_KIND(Token_Or, "|"), \
|
||||||
TOKEN_KIND(Token_Xor, "~"), \
|
TOKEN_KIND(Token_Xor, "~"), \
|
||||||
TOKEN_KIND(Token_AndNot, "&~"), \
|
TOKEN_KIND(Token_AndNot, "&~"), \
|
||||||
TOKEN_KIND(Token_Shl, "<<"), \
|
TOKEN_KIND(Token_Shl, "<<"), \
|
||||||
TOKEN_KIND(Token_Shr, ">>"), \
|
TOKEN_KIND(Token_Shr, ">>"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token_as, "as"), \
|
/*TOKEN_KIND(Token_as, "as"), */\
|
||||||
TOKEN_KIND(Token_transmute, "transmute"), \
|
/*TOKEN_KIND(Token_transmute, "transmute"), */\
|
||||||
TOKEN_KIND(Token_down_cast, "down_cast"), \
|
/*TOKEN_KIND(Token_down_cast, "down_cast"), */\
|
||||||
TOKEN_KIND(Token_union_cast, "union_cast"), \
|
/*TOKEN_KIND(Token_union_cast, "union_cast"), */\
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token_CmpAnd, "&&"), \
|
TOKEN_KIND(Token_CmpAnd, "&&"), \
|
||||||
TOKEN_KIND(Token_CmpOr, "||"), \
|
TOKEN_KIND(Token_CmpOr, "||"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
|
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
|
||||||
TOKEN_KIND(Token_AddEq, "+="), \
|
TOKEN_KIND(Token_AddEq, "+="), \
|
||||||
TOKEN_KIND(Token_SubEq, "-="), \
|
TOKEN_KIND(Token_SubEq, "-="), \
|
||||||
TOKEN_KIND(Token_MulEq, "*="), \
|
TOKEN_KIND(Token_MulEq, "*="), \
|
||||||
TOKEN_KIND(Token_QuoEq, "/="), \
|
TOKEN_KIND(Token_QuoEq, "/="), \
|
||||||
TOKEN_KIND(Token_ModEq, "%="), \
|
TOKEN_KIND(Token_ModEq, "%="), \
|
||||||
TOKEN_KIND(Token_AndEq, "&="), \
|
TOKEN_KIND(Token_AndEq, "&="), \
|
||||||
TOKEN_KIND(Token_OrEq, "|="), \
|
TOKEN_KIND(Token_OrEq, "|="), \
|
||||||
TOKEN_KIND(Token_XorEq, "~="), \
|
TOKEN_KIND(Token_XorEq, "~="), \
|
||||||
TOKEN_KIND(Token_AndNotEq, "&~="), \
|
TOKEN_KIND(Token_AndNotEq, "&~="), \
|
||||||
TOKEN_KIND(Token_ShlEq, "<<="), \
|
TOKEN_KIND(Token_ShlEq, "<<="), \
|
||||||
TOKEN_KIND(Token_ShrEq, ">>="), \
|
TOKEN_KIND(Token_ShrEq, ">>="), \
|
||||||
TOKEN_KIND(Token_CmpAndEq, "&&="), \
|
TOKEN_KIND(Token_CmpAndEq, "&&="), \
|
||||||
TOKEN_KIND(Token_CmpOrEq, "||="), \
|
TOKEN_KIND(Token_CmpOrEq, "||="), \
|
||||||
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
||||||
TOKEN_KIND(Token_ArrowRight, "->"), \
|
TOKEN_KIND(Token_ArrowRight, "->"), \
|
||||||
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
|
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
|
||||||
TOKEN_KIND(Token_CmpEq, "=="), \
|
TOKEN_KIND(Token_CmpEq, "=="), \
|
||||||
TOKEN_KIND(Token_NotEq, "!="), \
|
TOKEN_KIND(Token_NotEq, "!="), \
|
||||||
TOKEN_KIND(Token_Lt, "<"), \
|
TOKEN_KIND(Token_Lt, "<"), \
|
||||||
TOKEN_KIND(Token_Gt, ">"), \
|
TOKEN_KIND(Token_Gt, ">"), \
|
||||||
TOKEN_KIND(Token_LtEq, "<="), \
|
TOKEN_KIND(Token_LtEq, "<="), \
|
||||||
TOKEN_KIND(Token_GtEq, ">="), \
|
TOKEN_KIND(Token_GtEq, ">="), \
|
||||||
TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
|
TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token_OpenParen, "("), \
|
TOKEN_KIND(Token_OpenParen, "("), \
|
||||||
TOKEN_KIND(Token_CloseParen, ")"), \
|
TOKEN_KIND(Token_CloseParen, ")"), \
|
||||||
TOKEN_KIND(Token_OpenBracket, "["), \
|
TOKEN_KIND(Token_OpenBracket, "["), \
|
||||||
TOKEN_KIND(Token_CloseBracket, "]"), \
|
TOKEN_KIND(Token_CloseBracket, "]"), \
|
||||||
TOKEN_KIND(Token_OpenBrace, "{"), \
|
TOKEN_KIND(Token_OpenBrace, "{"), \
|
||||||
TOKEN_KIND(Token_CloseBrace, "}"), \
|
TOKEN_KIND(Token_CloseBrace, "}"), \
|
||||||
TOKEN_KIND(Token_Colon, ":"), \
|
TOKEN_KIND(Token_Colon, ":"), \
|
||||||
TOKEN_KIND(Token_Semicolon, ";"), \
|
TOKEN_KIND(Token_Semicolon, ";"), \
|
||||||
TOKEN_KIND(Token_Period, "."), \
|
TOKEN_KIND(Token_Period, "."), \
|
||||||
TOKEN_KIND(Token_Comma, ","), \
|
TOKEN_KIND(Token_Comma, ","), \
|
||||||
TOKEN_KIND(Token_Ellipsis, "..."), \
|
TOKEN_KIND(Token_Ellipsis, "..."), \
|
||||||
TOKEN_KIND(Token_Interval, "..<"), \
|
TOKEN_KIND(Token_HalfOpenRange, "..<"), \
|
||||||
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
|
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||||
@@ -92,8 +92,8 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
|||||||
TOKEN_KIND(Token_then, "then"), \
|
TOKEN_KIND(Token_then, "then"), \
|
||||||
TOKEN_KIND(Token_if, "if"), \
|
TOKEN_KIND(Token_if, "if"), \
|
||||||
TOKEN_KIND(Token_else, "else"), \
|
TOKEN_KIND(Token_else, "else"), \
|
||||||
TOKEN_KIND(Token_while, "while"), \
|
|
||||||
TOKEN_KIND(Token_for, "for"), \
|
TOKEN_KIND(Token_for, "for"), \
|
||||||
|
TOKEN_KIND(Token_in, "in"), \
|
||||||
TOKEN_KIND(Token_when, "when"), \
|
TOKEN_KIND(Token_when, "when"), \
|
||||||
TOKEN_KIND(Token_range, "range"), \
|
TOKEN_KIND(Token_range, "range"), \
|
||||||
TOKEN_KIND(Token_defer, "defer"), \
|
TOKEN_KIND(Token_defer, "defer"), \
|
||||||
@@ -105,9 +105,16 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
|||||||
TOKEN_KIND(Token_enum, "enum"), \
|
TOKEN_KIND(Token_enum, "enum"), \
|
||||||
TOKEN_KIND(Token_vector, "vector"), \
|
TOKEN_KIND(Token_vector, "vector"), \
|
||||||
TOKEN_KIND(Token_using, "using"), \
|
TOKEN_KIND(Token_using, "using"), \
|
||||||
|
TOKEN_KIND(Token_no_alias, "no_alias"), \
|
||||||
|
TOKEN_KIND(Token_immutable, "immutable"), \
|
||||||
|
TOKEN_KIND(Token_thread_local, "thread_local"), \
|
||||||
TOKEN_KIND(Token_asm, "asm"), \
|
TOKEN_KIND(Token_asm, "asm"), \
|
||||||
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
|
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
|
||||||
TOKEN_KIND(Token_push_context, "push_context"), \
|
TOKEN_KIND(Token_push_context, "push_context"), \
|
||||||
|
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__KeywordEnd, "_KeywordEnd"), \
|
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
|
||||||
TOKEN_KIND(Token_Count, "")
|
TOKEN_KIND(Token_Count, "")
|
||||||
|
|
||||||
@@ -146,7 +153,6 @@ bool token_pos_eq(TokenPos a, TokenPos b) {
|
|||||||
return token_pos_cmp(a, b) == 0;
|
return token_pos_cmp(a, b) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): Text is UTF-8, thus why u8 and not char
|
|
||||||
typedef struct Token {
|
typedef struct Token {
|
||||||
TokenKind kind;
|
TokenKind kind;
|
||||||
String string;
|
String string;
|
||||||
@@ -456,12 +462,15 @@ gb_inline i32 digit_value(Rune r) {
|
|||||||
return 16; // NOTE(bill): Larger than highest possible
|
return 16; // NOTE(bill): Larger than highest possible
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_inline void scan_mantissa(Tokenizer *t, i32 base) {
|
gb_inline void scan_mantissa(Tokenizer *t, i32 base, bool allow_underscore) {
|
||||||
// TODO(bill): Allow for underscores in numbers as a number separator
|
if (allow_underscore) {
|
||||||
// TODO(bill): Is this a good idea?
|
while (digit_value(t->curr_rune) < base || t->curr_rune == '_') {
|
||||||
// while (digit_value(t->curr_rune) < base || t->curr_rune == '_')
|
advance_to_next_rune(t);
|
||||||
while (digit_value(t->curr_rune) < base) {
|
}
|
||||||
advance_to_next_rune(t);
|
} else {
|
||||||
|
while (digit_value(t->curr_rune) < base) {
|
||||||
|
advance_to_next_rune(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,7 +485,7 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
|||||||
|
|
||||||
if (seen_decimal_point) {
|
if (seen_decimal_point) {
|
||||||
token.kind = Token_Float;
|
token.kind = Token_Float;
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
goto exponent;
|
goto exponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,31 +494,31 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
|||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
if (t->curr_rune == 'b') { // Binary
|
if (t->curr_rune == 'b') { // Binary
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_mantissa(t, 2);
|
scan_mantissa(t, 2, true);
|
||||||
if (t->curr - prev <= 2) {
|
if (t->curr - prev <= 2) {
|
||||||
token.kind = Token_Invalid;
|
token.kind = Token_Invalid;
|
||||||
}
|
}
|
||||||
} else if (t->curr_rune == 'o') { // Octal
|
} else if (t->curr_rune == 'o') { // Octal
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_mantissa(t, 8);
|
scan_mantissa(t, 8, true);
|
||||||
if (t->curr - prev <= 2) {
|
if (t->curr - prev <= 2) {
|
||||||
token.kind = Token_Invalid;
|
token.kind = Token_Invalid;
|
||||||
}
|
}
|
||||||
} else if (t->curr_rune == 'd') { // Decimal
|
} else if (t->curr_rune == 'd') { // Decimal
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
if (t->curr - prev <= 2) {
|
if (t->curr - prev <= 2) {
|
||||||
token.kind = Token_Invalid;
|
token.kind = Token_Invalid;
|
||||||
}
|
}
|
||||||
} else if (t->curr_rune == 'x') { // Hexadecimal
|
} else if (t->curr_rune == 'x') { // Hexadecimal
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_mantissa(t, 16);
|
scan_mantissa(t, 16, true);
|
||||||
if (t->curr - prev <= 2) {
|
if (t->curr - prev <= 2) {
|
||||||
token.kind = Token_Invalid;
|
token.kind = Token_Invalid;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
seen_decimal_point = false;
|
seen_decimal_point = false;
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
|
|
||||||
if (t->curr_rune == '.' || t->curr_rune == 'e' || t->curr_rune == 'E') {
|
if (t->curr_rune == '.' || t->curr_rune == 'e' || t->curr_rune == 'E') {
|
||||||
seen_decimal_point = true;
|
seen_decimal_point = true;
|
||||||
@@ -521,20 +530,20 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
|
|
||||||
fraction:
|
fraction:
|
||||||
if (t->curr_rune == '.') {
|
if (t->curr_rune == '.') {
|
||||||
// HACK(bill): This may be inefficient
|
// HACK(bill): This may be inefficient
|
||||||
TokenizerState state = save_tokenizer_state(t);
|
TokenizerState state = save_tokenizer_state(t);
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
if (t->curr_rune == '.') {
|
if (digit_value(t->curr_rune) >= 10) {
|
||||||
// TODO(bill): Clean up this shit
|
// TODO(bill): Clean up this shit
|
||||||
restore_tokenizer_state(t, &state);
|
restore_tokenizer_state(t, &state);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
token.kind = Token_Float;
|
token.kind = Token_Float;
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
exponent:
|
exponent:
|
||||||
@@ -544,7 +553,7 @@ exponent:
|
|||||||
if (t->curr_rune == '-' || t->curr_rune == '+') {
|
if (t->curr_rune == '-' || t->curr_rune == '+') {
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
}
|
}
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
@@ -721,7 +730,7 @@ Token tokenizer_get_token(Tokenizer *t) {
|
|||||||
|
|
||||||
// NOTE(bill): All keywords are > 1
|
// NOTE(bill): All keywords are > 1
|
||||||
if (token.string.len > 1) {
|
if (token.string.len > 1) {
|
||||||
if (str_eq(token.string, token_strings[Token_as])) {
|
/* if (str_eq(token.string, token_strings[Token_as])) {
|
||||||
token.kind = Token_as;
|
token.kind = Token_as;
|
||||||
} else if (str_eq(token.string, token_strings[Token_transmute])) {
|
} else if (str_eq(token.string, token_strings[Token_transmute])) {
|
||||||
token.kind = Token_transmute;
|
token.kind = Token_transmute;
|
||||||
@@ -729,7 +738,7 @@ Token tokenizer_get_token(Tokenizer *t) {
|
|||||||
token.kind = Token_down_cast;
|
token.kind = Token_down_cast;
|
||||||
} else if (str_eq(token.string, token_strings[Token_union_cast])) {
|
} else if (str_eq(token.string, token_strings[Token_union_cast])) {
|
||||||
token.kind = Token_union_cast;
|
token.kind = Token_union_cast;
|
||||||
} else {
|
} else */{
|
||||||
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
|
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
|
||||||
if (str_eq(token.string, token_strings[k])) {
|
if (str_eq(token.string, token_strings[k])) {
|
||||||
token.kind = cast(TokenKind)k;
|
token.kind = cast(TokenKind)k;
|
||||||
@@ -836,16 +845,14 @@ Token tokenizer_get_token(Tokenizer *t) {
|
|||||||
|
|
||||||
case '.':
|
case '.':
|
||||||
token.kind = Token_Period; // Default
|
token.kind = Token_Period; // Default
|
||||||
if (gb_is_between(t->curr_rune, '0', '9')) { // Might be a number
|
if (t->curr_rune == '.') { // Could be an ellipsis
|
||||||
token = scan_number_to_token(t, true);
|
|
||||||
} else if (t->curr_rune == '.') { // Could be an ellipsis
|
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
if (t->curr_rune == '.') {
|
if (t->curr_rune == '<') {
|
||||||
|
advance_to_next_rune(t);
|
||||||
|
token.kind = Token_HalfOpenRange;
|
||||||
|
} else if (t->curr_rune == '.') {
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
token.kind = Token_Ellipsis;
|
token.kind = Token_Ellipsis;
|
||||||
} else if (t->curr_rune == '<') {
|
|
||||||
advance_to_next_rune(t);
|
|
||||||
token.kind = Token_Interval;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -74,8 +74,11 @@ typedef struct TypeRecord {
|
|||||||
|
|
||||||
// All record types
|
// All record types
|
||||||
// Theses are arrays
|
// Theses are arrays
|
||||||
Entity **fields; // Entity_Variable (otherwise Entity_TypeName if union)
|
// Entity_Variable - struct/raw_union
|
||||||
i32 field_count; // == offset_count is struct
|
// Entity_TypeName - union
|
||||||
|
// Entity_Constant - enum
|
||||||
|
Entity **fields;
|
||||||
|
i32 field_count; // == struct_offsets count
|
||||||
AstNode *node;
|
AstNode *node;
|
||||||
|
|
||||||
i64 * struct_offsets;
|
i64 * struct_offsets;
|
||||||
@@ -85,6 +88,9 @@ typedef struct TypeRecord {
|
|||||||
Entity **fields_in_src_order; // Entity_Variable
|
Entity **fields_in_src_order; // Entity_Variable
|
||||||
|
|
||||||
Type * enum_base_type;
|
Type * enum_base_type;
|
||||||
|
Entity * enum_count;
|
||||||
|
Entity * enum_min_value;
|
||||||
|
Entity * enum_max_value;
|
||||||
} TypeRecord;
|
} TypeRecord;
|
||||||
|
|
||||||
#define TYPE_KINDS \
|
#define TYPE_KINDS \
|
||||||
@@ -253,11 +259,15 @@ gb_global Type *t_rune = &basic_type_aliases[1];
|
|||||||
|
|
||||||
gb_global Type *t_u8_ptr = NULL;
|
gb_global Type *t_u8_ptr = NULL;
|
||||||
gb_global Type *t_int_ptr = NULL;
|
gb_global Type *t_int_ptr = NULL;
|
||||||
|
gb_global Type *t_i64_ptr = NULL;
|
||||||
|
gb_global Type *t_f64_ptr = NULL;
|
||||||
|
|
||||||
gb_global Type *t_type_info = NULL;
|
gb_global Type *t_type_info = NULL;
|
||||||
gb_global Type *t_type_info_ptr = NULL;
|
gb_global Type *t_type_info_member = NULL;
|
||||||
gb_global Type *t_type_info_member = NULL;
|
gb_global Type *t_type_info_enum_value = NULL;
|
||||||
gb_global Type *t_type_info_member_ptr = NULL;
|
gb_global Type *t_type_info_ptr = NULL;
|
||||||
|
gb_global Type *t_type_info_member_ptr = NULL;
|
||||||
|
gb_global Type *t_type_info_enum_value_ptr = NULL;
|
||||||
|
|
||||||
gb_global Type *t_type_info_named = NULL;
|
gb_global Type *t_type_info_named = NULL;
|
||||||
gb_global Type *t_type_info_integer = NULL;
|
gb_global Type *t_type_info_integer = NULL;
|
||||||
@@ -474,31 +484,32 @@ bool is_type_named(Type *t) {
|
|||||||
return t->kind == Type_Named;
|
return t->kind == Type_Named;
|
||||||
}
|
}
|
||||||
bool is_type_boolean(Type *t) {
|
bool is_type_boolean(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(base_enum_type(t));
|
||||||
if (t->kind == Type_Basic) {
|
if (t->kind == Type_Basic) {
|
||||||
return (t->Basic.flags & BasicFlag_Boolean) != 0;
|
return (t->Basic.flags & BasicFlag_Boolean) != 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool is_type_integer(Type *t) {
|
bool is_type_integer(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(base_enum_type(t));
|
||||||
if (t->kind == Type_Basic) {
|
if (t->kind == Type_Basic) {
|
||||||
return (t->Basic.flags & BasicFlag_Integer) != 0;
|
return (t->Basic.flags & BasicFlag_Integer) != 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool is_type_unsigned(Type *t) {
|
bool is_type_unsigned(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(base_enum_type(t));
|
||||||
if (t->kind == Type_Basic) {
|
if (t->kind == Type_Basic) {
|
||||||
return (t->Basic.flags & BasicFlag_Unsigned) != 0;
|
return (t->Basic.flags & BasicFlag_Unsigned) != 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool is_type_numeric(Type *t) {
|
bool is_type_numeric(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(base_enum_type(t));
|
||||||
if (t->kind == Type_Basic) {
|
if (t->kind == Type_Basic) {
|
||||||
return (t->Basic.flags & BasicFlag_Numeric) != 0;
|
return (t->Basic.flags & BasicFlag_Numeric) != 0;
|
||||||
}
|
}
|
||||||
|
// TODO(bill): Should this be here?
|
||||||
if (t->kind == Type_Vector) {
|
if (t->kind == Type_Vector) {
|
||||||
return is_type_numeric(t->Vector.elem);
|
return is_type_numeric(t->Vector.elem);
|
||||||
}
|
}
|
||||||
@@ -529,7 +540,7 @@ bool is_type_untyped(Type *t) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool is_type_ordered(Type *t) {
|
bool is_type_ordered(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(base_enum_type(t));
|
||||||
if (t->kind == Type_Basic) {
|
if (t->kind == Type_Basic) {
|
||||||
return (t->Basic.flags & BasicFlag_Ordered) != 0;
|
return (t->Basic.flags & BasicFlag_Ordered) != 0;
|
||||||
}
|
}
|
||||||
@@ -546,21 +557,21 @@ bool is_type_constant_type(Type *t) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool is_type_float(Type *t) {
|
bool is_type_float(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(base_enum_type(t));
|
||||||
if (t->kind == Type_Basic) {
|
if (t->kind == Type_Basic) {
|
||||||
return (t->Basic.flags & BasicFlag_Float) != 0;
|
return (t->Basic.flags & BasicFlag_Float) != 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool is_type_f32(Type *t) {
|
bool is_type_f32(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(base_enum_type(t));
|
||||||
if (t->kind == Type_Basic) {
|
if (t->kind == Type_Basic) {
|
||||||
return t->Basic.kind == Basic_f32;
|
return t->Basic.kind == Basic_f32;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool is_type_f64(Type *t) {
|
bool is_type_f64(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(base_enum_type(t));
|
||||||
if (t->kind == Type_Basic) {
|
if (t->kind == Type_Basic) {
|
||||||
return t->Basic.kind == Basic_f64;
|
return t->Basic.kind == Basic_f64;
|
||||||
}
|
}
|
||||||
@@ -670,8 +681,14 @@ bool is_type_indexable(Type *t) {
|
|||||||
bool type_has_nil(Type *t) {
|
bool type_has_nil(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
switch (t->kind) {
|
switch (t->kind) {
|
||||||
case Type_Basic:
|
case Type_Basic: {
|
||||||
return is_type_rawptr(t);
|
switch (t->Basic.kind) {
|
||||||
|
case Basic_rawptr:
|
||||||
|
case Basic_any:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} break;
|
||||||
case Type_Slice:
|
case Type_Slice:
|
||||||
case Type_Proc:
|
case Type_Proc:
|
||||||
case Type_Pointer:
|
case Type_Pointer:
|
||||||
@@ -686,24 +703,22 @@ bool is_type_comparable(Type *t) {
|
|||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
switch (t->kind) {
|
switch (t->kind) {
|
||||||
case Type_Basic:
|
case Type_Basic:
|
||||||
return t->kind != Basic_UntypedNil;
|
switch (t->Basic.kind) {
|
||||||
|
case Basic_UntypedNil:
|
||||||
|
case Basic_any:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
case Type_Pointer:
|
case Type_Pointer:
|
||||||
return true;
|
return true;
|
||||||
case Type_Record: {
|
case Type_Record: {
|
||||||
if (false && is_type_struct(t)) {
|
if (is_type_enum(t)) {
|
||||||
// TODO(bill): Should I even allow this?
|
|
||||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
|
||||||
if (!is_type_comparable(t->Record.fields[i]->type))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (is_type_enum(t)) {
|
|
||||||
return is_type_comparable(base_enum_type(t));
|
return is_type_comparable(base_enum_type(t));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} break;
|
} break;
|
||||||
case Type_Array:
|
case Type_Array:
|
||||||
return false;
|
return false;
|
||||||
// return is_type_comparable(t->Array.elem);
|
|
||||||
case Type_Vector:
|
case Type_Vector:
|
||||||
return is_type_comparable(t->Vector.elem);
|
return is_type_comparable(t->Vector.elem);
|
||||||
case Type_Proc:
|
case Type_Proc:
|
||||||
@@ -809,6 +824,7 @@ bool are_types_identical(Type *x, Type *y) {
|
|||||||
case Type_Proc:
|
case Type_Proc:
|
||||||
if (y->kind == Type_Proc) {
|
if (y->kind == Type_Proc) {
|
||||||
return x->Proc.calling_convention == y->Proc.calling_convention &&
|
return x->Proc.calling_convention == y->Proc.calling_convention &&
|
||||||
|
x->Proc.variadic == y->Proc.variadic &&
|
||||||
are_types_identical(x->Proc.params, y->Proc.params) &&
|
are_types_identical(x->Proc.params, y->Proc.params) &&
|
||||||
are_types_identical(x->Proc.results, y->Proc.results);
|
are_types_identical(x->Proc.results, y->Proc.results);
|
||||||
}
|
}
|
||||||
@@ -895,6 +911,60 @@ bool is_type_cte_safe(Type *type) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef enum ProcTypeOverloadKind {
|
||||||
|
ProcOverload_Identical, // The types are identical
|
||||||
|
|
||||||
|
ProcOverload_CallingConvention,
|
||||||
|
ProcOverload_ParamCount,
|
||||||
|
ProcOverload_ParamVariadic,
|
||||||
|
ProcOverload_ParamTypes,
|
||||||
|
ProcOverload_ResultCount,
|
||||||
|
ProcOverload_ResultTypes,
|
||||||
|
|
||||||
|
} ProcTypeOverloadKind;
|
||||||
|
|
||||||
|
|
||||||
|
ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
|
||||||
|
GB_ASSERT(is_type_proc(x));
|
||||||
|
GB_ASSERT(is_type_proc(y));
|
||||||
|
TypeProc *px = &base_type(x)->Proc;
|
||||||
|
TypeProc *py = &base_type(y)->Proc;
|
||||||
|
|
||||||
|
if (px->calling_convention != py->calling_convention) {
|
||||||
|
return ProcOverload_CallingConvention;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (px->param_count != py->param_count) {
|
||||||
|
return ProcOverload_ParamCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (isize i = 0; i < px->param_count; i++) {
|
||||||
|
Entity *ex = px->params->Tuple.variables[i];
|
||||||
|
Entity *ey = py->params->Tuple.variables[i];
|
||||||
|
if (!are_types_identical(ex->type, ey->type)) {
|
||||||
|
return ProcOverload_ParamTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// IMPORTANT TODO(bill): Determine the rules for overloading procedures with variadic parameters
|
||||||
|
if (px->variadic != py->variadic) {
|
||||||
|
return ProcOverload_ParamVariadic;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (px->result_count != py->result_count) {
|
||||||
|
return ProcOverload_ResultCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (isize i = 0; i < px->result_count; i++) {
|
||||||
|
Entity *ex = px->results->Tuple.variables[i];
|
||||||
|
Entity *ey = py->results->Tuple.variables[i];
|
||||||
|
if (!are_types_identical(ex->type, ey->type)) {
|
||||||
|
return ProcOverload_ResultTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ProcOverload_Identical;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -911,6 +981,51 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, bool is_ty
|
|||||||
return lookup_field_with_selection(a, type_, field_name, is_type, empty_selection);
|
return lookup_field_with_selection(a, type_, field_name, is_type, empty_selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) {
|
||||||
|
GB_ASSERT(is_type_struct(type) || is_type_tuple(type));
|
||||||
|
type = base_type(type);
|
||||||
|
|
||||||
|
i64 max_count = 0;
|
||||||
|
switch (type->kind) {
|
||||||
|
case Type_Record: max_count = type->Record.field_count; break;
|
||||||
|
case Type_Tuple: max_count = type->Tuple.variable_count; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= max_count) {
|
||||||
|
return empty_selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type->kind) {
|
||||||
|
case Type_Record:
|
||||||
|
for (isize i = 0; i < max_count; i++) {
|
||||||
|
Entity *f = type->Record.fields[i];
|
||||||
|
if (f->kind == Entity_Variable) {
|
||||||
|
if (f->Variable.field_src_index == index) {
|
||||||
|
Array_isize sel_array = {0};
|
||||||
|
array_init_count(&sel_array, a, 1);
|
||||||
|
sel_array.e[0] = i;
|
||||||
|
return make_selection(f, sel_array, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Type_Tuple:
|
||||||
|
for (isize i = 0; i < max_count; i++) {
|
||||||
|
Entity *f = type->Tuple.variables[i];
|
||||||
|
if (i == index) {
|
||||||
|
Array_isize sel_array = {0};
|
||||||
|
array_init_count(&sel_array, a, 1);
|
||||||
|
sel_array.e[0] = i;
|
||||||
|
return make_selection(f, sel_array, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_PANIC("Illegal index");
|
||||||
|
return empty_selection;
|
||||||
|
}
|
||||||
|
|
||||||
Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel) {
|
Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel) {
|
||||||
GB_ASSERT(type_ != NULL);
|
GB_ASSERT(type_ != NULL);
|
||||||
|
|
||||||
@@ -1043,11 +1158,27 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
|||||||
|
|
||||||
if (str_eq(field_name, str)) {
|
if (str_eq(field_name, str)) {
|
||||||
sel.entity = f;
|
sel.entity = f;
|
||||||
selection_add_index(&sel, i);
|
// selection_add_index(&sel, i);
|
||||||
return sel;
|
return sel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (is_type_enum(type)) {
|
} else if (is_type_enum(type)) {
|
||||||
|
// NOTE(bill): These may not have been added yet, so check in case
|
||||||
|
if (type->Record.enum_count != NULL) {
|
||||||
|
if (str_eq(field_name, str_lit("count"))) {
|
||||||
|
sel.entity = type->Record.enum_count;
|
||||||
|
return sel;
|
||||||
|
}
|
||||||
|
if (str_eq(field_name, str_lit("min_value"))) {
|
||||||
|
sel.entity = type->Record.enum_min_value;
|
||||||
|
return sel;
|
||||||
|
}
|
||||||
|
if (str_eq(field_name, str_lit("max_value"))) {
|
||||||
|
sel.entity = type->Record.enum_max_value;
|
||||||
|
return sel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||||
Entity *f = type->Record.fields[i];
|
Entity *f = type->Record.fields[i];
|
||||||
GB_ASSERT(f->kind == Entity_Constant);
|
GB_ASSERT(f->kind == Entity_Constant);
|
||||||
@@ -1055,7 +1186,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
|||||||
|
|
||||||
if (str_eq(field_name, str)) {
|
if (str_eq(field_name, str)) {
|
||||||
sel.entity = f;
|
sel.entity = f;
|
||||||
selection_add_index(&sel, i);
|
// selection_add_index(&sel, i);
|
||||||
return sel;
|
return sel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1063,7 +1194,9 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
|||||||
} else if (!is_type_union(type)) {
|
} else if (!is_type_union(type)) {
|
||||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||||
Entity *f = type->Record.fields[i];
|
Entity *f = type->Record.fields[i];
|
||||||
GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
|
if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String str = f->token.string;
|
String str = f->token.string;
|
||||||
if (str_eq(field_name, str)) {
|
if (str_eq(field_name, str)) {
|
||||||
selection_add_index(&sel, i); // HACK(bill): Leaky memory
|
selection_add_index(&sel, i); // HACK(bill): Leaky memory
|
||||||
@@ -1166,6 +1299,9 @@ i64 align_formula(i64 size, i64 align) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||||
|
if (t == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
i64 size;
|
i64 size;
|
||||||
TypePath path = {0};
|
TypePath path = {0};
|
||||||
type_path_init(&path);
|
type_path_init(&path);
|
||||||
@@ -1175,6 +1311,9 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||||
|
if (t == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
i64 align;
|
i64 align;
|
||||||
TypePath path = {0};
|
TypePath path = {0};
|
||||||
type_path_init(&path);
|
type_path_init(&path);
|
||||||
@@ -1191,6 +1330,17 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
|
|||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
|
|
||||||
switch (t->kind) {
|
switch (t->kind) {
|
||||||
|
case Type_Basic: {
|
||||||
|
GB_ASSERT(is_type_typed(t));
|
||||||
|
switch (t->kind) {
|
||||||
|
case Basic_string: return s.word_size;
|
||||||
|
case Basic_any: return s.word_size;
|
||||||
|
|
||||||
|
case Basic_int: case Basic_uint: case Basic_rawptr:
|
||||||
|
return s.word_size;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
case Type_Array: {
|
case Type_Array: {
|
||||||
Type *elem = t->Array.elem;
|
Type *elem = t->Array.elem;
|
||||||
type_path_push(path, elem);
|
type_path_push(path, elem);
|
||||||
@@ -1657,9 +1807,17 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
Entity *var = type->Tuple.variables[i];
|
Entity *var = type->Tuple.variables[i];
|
||||||
if (var != NULL) {
|
if (var != NULL) {
|
||||||
GB_ASSERT(var->kind == Entity_Variable);
|
GB_ASSERT(var->kind == Entity_Variable);
|
||||||
if (i > 0)
|
if (i > 0) {
|
||||||
str = gb_string_appendc(str, ", ");
|
str = gb_string_appendc(str, ", ");
|
||||||
str = write_type_to_string(str, var->type);
|
}
|
||||||
|
if (var->flags&EntityFlag_Ellipsis) {
|
||||||
|
Type *slice = base_type(var->type);
|
||||||
|
str = gb_string_appendc(str, "...");
|
||||||
|
GB_ASSERT(is_type_slice(var->type));
|
||||||
|
str = write_type_to_string(str, slice->Slice.elem);
|
||||||
|
} else {
|
||||||
|
str = write_type_to_string(str, var->type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1696,8 +1854,7 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
|
|
||||||
|
|
||||||
gbString type_to_string(Type *type) {
|
gbString type_to_string(Type *type) {
|
||||||
gbString str = gb_string_make(gb_heap_allocator(), "");
|
return write_type_to_string(gb_string_make(heap_allocator(), ""), type);
|
||||||
return write_type_to_string(str, type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user