mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-05 03:01:38 -07:00
Compare commits
95 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c454ede184 | |||
| d854c5003c | |||
| 66d8776b83 | |||
| ba6ecf35cf | |||
| 10cc9cf661 | |||
| 2db971eedd | |||
| 1775e80b41 | |||
| e4a93619db | |||
| 4d14b3bcb4 | |||
| 9f4f5f9346 | |||
| 0fae31fb54 | |||
| 8987a6630c | |||
| 10ff8e0426 | |||
| a0ae02168a | |||
| a3c1ac2030 | |||
| 629b248f53 | |||
| 62a72f0163 | |||
| 655931f0ea | |||
| ca36fabfc0 | |||
| 7bd62481ad | |||
| fbd27d7c45 | |||
| 3546391311 | |||
| 24c812115e | |||
| 28be0ad69b | |||
| f0980c0a98 | |||
| 1df4aa90ce | |||
| 6b3cf051f8 | |||
| 4ecd6e592b | |||
| dbddec33c8 | |||
| 401a5955a4 | |||
| 9a3b4167bb | |||
| 13bc6eeea4 | |||
| 2da18b6d33 | |||
| 6d37ed12d2 | |||
| eab23cd5b7 | |||
| d233706a2d | |||
| f1ab17ed4e | |||
| 6113164211 | |||
| 4db462a703 | |||
| a22c6d6c0c | |||
| 59fb7b020a | |||
| 65f079ebc4 | |||
| d16aa79492 | |||
| 5af0acc4af | |||
| a459364de3 | |||
| 277ef1a68f | |||
| 193c7c82c8 | |||
| f7d8ba408c | |||
| 9a8759efef | |||
| 054948e701 | |||
| 1c5ddd65b4 | |||
| b8697fb4ed | |||
| 03570275c1 | |||
| b5587f1937 | |||
| c4c6975f1b | |||
| 0be0fb2a57 | |||
| 115e6e7f9e | |||
| 3868a9a0f0 | |||
| ba5050ac7c | |||
| d936ca1ea0 | |||
| fd8c4d58bb | |||
| ce4b7b8b7d | |||
| 069a47220e | |||
| 66e4aaffc5 | |||
| 81336b58cb | |||
| b201670f7a | |||
| 4b051a0d3b | |||
| 45353465a6 | |||
| c63cb98019 | |||
| 773cf5ca08 | |||
| 2db03cb4a5 | |||
| eed873c6ec | |||
| 3d2d461867 | |||
| 36392d658e | |||
| 82696179e8 | |||
| 188bc28f6a | |||
| 240da5c8e0 | |||
| 689a0c0b49 | |||
| bc16b290ba | |||
| 96d32680fe | |||
| d782b3d21d | |||
| ed089b44b9 | |||
| 33f4af2e19 | |||
| 69f7382eec | |||
| 7e3293fc20 | |||
| e4a8283327 | |||
| 001baf4419 | |||
| d167290b28 | |||
| f4879d4723 | |||
| fd81c06c35 | |||
| 94afcec757 | |||
| 4f28e9e1fb | |||
| 0622509807 | |||
| 9ca2246bac | |||
| 647e2cafd7 |
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2016 Ginger Bill. All rights reserved.
|
||||
Copyright (c) 2016-2017 Ginger Bill. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -17,10 +17,13 @@ if %release_mode% EQU 0 ( rem Debug
|
||||
set compiler_warnings= ^
|
||||
-W4 -WX ^
|
||||
-wd4100 -wd4101 -wd4127 -wd4189 ^
|
||||
-wd4201 -wd4204 -wd4244 ^
|
||||
-wd4306 ^
|
||||
-wd4456 -wd4457 -wd4480 ^
|
||||
-wd4505 -wd4512 -wd4550
|
||||
-wd4201 ^
|
||||
-wd4512
|
||||
rem -wd4100 -wd4101 -wd4127 -wd4189 ^
|
||||
rem -wd4201 -wd4204 -wd4244 ^
|
||||
rem -wd4306 ^
|
||||
rem -wd4456 -wd4457 -wd4480 ^
|
||||
rem -wd4505 -wd4512 -wd4550
|
||||
|
||||
set compiler_includes=
|
||||
set libs= ^
|
||||
@@ -38,7 +41,6 @@ if %release_mode% EQU 0 ( rem Debug
|
||||
set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings%
|
||||
set linker_settings=%libs% %linker_flags%
|
||||
|
||||
|
||||
del *.pdb > NUL 2> NUL
|
||||
del *.ilk > NUL 2> NUL
|
||||
|
||||
|
||||
+593
-425
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,430 @@
|
||||
import (
|
||||
"fmt.odin";
|
||||
"atomics.odin";
|
||||
"bits.odin";
|
||||
"decimal.odin";
|
||||
"hash.odin";
|
||||
"math.odin";
|
||||
"mem.odin";
|
||||
"opengl.odin";
|
||||
"os.odin";
|
||||
"raw.odin";
|
||||
"strconv.odin";
|
||||
"strings.odin";
|
||||
"sync.odin";
|
||||
"sort.odin";
|
||||
"types.odin";
|
||||
"utf8.odin";
|
||||
"utf16.odin";
|
||||
/*
|
||||
*/
|
||||
)
|
||||
|
||||
|
||||
general_stuff :: proc() {
|
||||
// Complex numbers
|
||||
a := 3 + 4i;
|
||||
b: complex64 = 3 + 4i;
|
||||
c: complex128 = 3 + 4i;
|
||||
d := complex(2, 3);
|
||||
|
||||
e := a / conj(a);
|
||||
fmt.println("(3+4i)/(3-4i) =", e);
|
||||
fmt.println(real(e), "+", imag(e), "i");
|
||||
|
||||
|
||||
// C-style variadic procedures
|
||||
foreign __llvm_core {
|
||||
// The variadic part allows for extra type checking too which C does not provide
|
||||
c_printf :: proc(fmt: ^u8, #c_vararg args: ...any) -> i32 #link_name "printf" ---;
|
||||
}
|
||||
str := "%d\n\x00";
|
||||
// c_printf(&str[0], i32(789456123));
|
||||
|
||||
|
||||
Foo :: struct {
|
||||
x: int;
|
||||
y: f32;
|
||||
z: string;
|
||||
}
|
||||
foo := Foo{123, 0.513, "A string"};
|
||||
x, y, z := expand_to_tuple(foo);
|
||||
fmt.println(x, y, z);
|
||||
compile_assert(type_of(x) == int);
|
||||
compile_assert(type_of(y) == f32);
|
||||
compile_assert(type_of(z) == string);
|
||||
|
||||
|
||||
// By default, all variables are zeroed
|
||||
// This can be overridden with the "uninitialized value"
|
||||
// This is similar to `nil` but applied to everything
|
||||
undef_int: int = ---;
|
||||
|
||||
|
||||
// Context system is now implemented using Implicit Parameter Passing (IPP)
|
||||
// The previous implementation was Thread Local Storage (TLS)
|
||||
// IPP has the advantage that it works on systems without TLS and that you can
|
||||
// link the context to the stack frame and thus look at previous contexts
|
||||
//
|
||||
// It does mean that a pointer is implicitly passed procedures with the default
|
||||
// Odin calling convention (#cc_odin)
|
||||
// This can be overridden with something like #cc_contextless or #cc_c if performance
|
||||
// is worried about
|
||||
|
||||
}
|
||||
|
||||
foreign_blocks :: proc() {
|
||||
// See sys/windows.odin
|
||||
}
|
||||
|
||||
default_arguments :: proc() {
|
||||
hello :: proc(a: int = 9, b: int = 9) do fmt.printf("a is %d; b is %d\n", a, b);
|
||||
fmt.println("\nTesting default arguments:");
|
||||
hello(1, 2);
|
||||
hello(1);
|
||||
hello();
|
||||
}
|
||||
|
||||
named_arguments :: proc() {
|
||||
Colour :: enum {
|
||||
Red,
|
||||
Orange,
|
||||
Yellow,
|
||||
Green,
|
||||
Blue,
|
||||
Octarine,
|
||||
};
|
||||
using Colour;
|
||||
|
||||
make_character :: proc(name, catch_phrase: string, favourite_colour, least_favourite_colour: Colour) {
|
||||
fmt.println();
|
||||
fmt.printf("My name is %v and I like %v. %v\n", name, favourite_colour, catch_phrase);
|
||||
}
|
||||
|
||||
make_character("Frank", "¡Ay, caramba!", Blue, Green);
|
||||
|
||||
|
||||
// As the procedures have more and more parameters, it is very easy
|
||||
// to get many of the arguments in the wrong order especialy if the
|
||||
// types are the same
|
||||
make_character("¡Ay, caramba!", "Frank", Green, Blue);
|
||||
|
||||
// Named arguments help to disambiguate this problem
|
||||
make_character(catch_phrase = "¡Ay, caramba!", name = "Frank",
|
||||
least_favourite_colour = Green, favourite_colour = Blue);
|
||||
|
||||
|
||||
// The named arguments can be specifed in any order.
|
||||
make_character(favourite_colour = Octarine, catch_phrase = "U wot m8!",
|
||||
least_favourite_colour = Green, name = "Dennis");
|
||||
|
||||
|
||||
// NOTE: You cannot mix named arguments with normal values
|
||||
/*
|
||||
make_character("Dennis",
|
||||
favourite_colour = Octarine, catch_phrase = "U wot m8!",
|
||||
least_favourite_colour = Green);
|
||||
*/
|
||||
|
||||
|
||||
// Named arguments can also aid with default arguments
|
||||
numerous_things :: proc(s: string, a := 1, b := 2, c := 3.14,
|
||||
d := "The Best String!", e := false, f := 10.3/3.1, g := false) {
|
||||
g_str := g ? "true" : "false";
|
||||
fmt.printf("How many?! %s: %v\n", s, g_str);
|
||||
}
|
||||
|
||||
numerous_things("First");
|
||||
numerous_things(s = "Second", g = true);
|
||||
|
||||
|
||||
// Default values can be placed anywhere, not just at the end like in other languages
|
||||
weird :: proc(pre: string, mid: int = 0, post: string) {
|
||||
fmt.println(pre, mid, post);
|
||||
}
|
||||
|
||||
weird("How many things", 42, "huh?");
|
||||
weird(pre = "Prefix", post = "Pat");
|
||||
|
||||
}
|
||||
|
||||
|
||||
default_return_values :: proc() {
|
||||
foo :: proc(x: int) -> (first: string = "Hellope", second := "world!") {
|
||||
match x {
|
||||
case 0: return;
|
||||
case 1: return "Goodbye";
|
||||
case 2: return "Goodbye", "cruel world...";
|
||||
case 3: return second = "cruel world...", first = "Goodbye";
|
||||
}
|
||||
|
||||
return second = "my old friend.";
|
||||
}
|
||||
|
||||
fmt.printf("%s %s\n", foo(0));
|
||||
fmt.printf("%s %s\n", foo(1));
|
||||
fmt.printf("%s %s\n", foo(2));
|
||||
fmt.printf("%s %s\n", foo(3));
|
||||
fmt.printf("%s %s\n", foo(4));
|
||||
fmt.println();
|
||||
|
||||
|
||||
// A more "real" example
|
||||
Error :: enum {
|
||||
None,
|
||||
WhyTheNumberThree,
|
||||
TenIsTooBig,
|
||||
};
|
||||
|
||||
Entity :: struct {
|
||||
name: string;
|
||||
id: u32;
|
||||
}
|
||||
|
||||
some_thing :: proc(input: int) -> (result: ^Entity = nil, err := Error.None) {
|
||||
match {
|
||||
case input == 3: return err = Error.WhyTheNumberThree;
|
||||
case input >= 10: return err = Error.TenIsTooBig;
|
||||
}
|
||||
|
||||
e := new(Entity);
|
||||
e.id = u32(input);
|
||||
|
||||
return result = e;
|
||||
}
|
||||
}
|
||||
|
||||
call_location :: proc() {
|
||||
amazing :: proc(n: int, using loc := #caller_location) {
|
||||
fmt.printf("%s(%d:%d) just asked to do something amazing.\n",
|
||||
fully_pathed_filename, line, column);
|
||||
fmt.printf("Normal -> %d\n", n);
|
||||
fmt.printf("Amazing -> %d\n", n+1);
|
||||
fmt.println();
|
||||
}
|
||||
|
||||
loc := #location(main);
|
||||
fmt.println("`main` is located at", loc);
|
||||
|
||||
fmt.println("This line is located at", #location());
|
||||
fmt.println();
|
||||
|
||||
amazing(3);
|
||||
amazing(4, #location(call_location));
|
||||
|
||||
// See _preload.odin for the implementations of `assert` and `panic`
|
||||
|
||||
}
|
||||
|
||||
|
||||
explicit_parametric_polymorphic_procedures :: proc() {
|
||||
// This is how `new` is actually implemented, see _preload.odin
|
||||
alloc_type :: proc(T: type) -> ^T do return cast(^T)alloc(size_of(T), align_of(T));
|
||||
|
||||
int_ptr := alloc_type(int);
|
||||
defer free(int_ptr);
|
||||
int_ptr^ = 137;
|
||||
fmt.println(int_ptr, int_ptr^);
|
||||
|
||||
// Named arguments work too!
|
||||
another_ptr := alloc_type(T = f32);
|
||||
defer free(another_ptr);
|
||||
|
||||
|
||||
add :: proc(T: type, args: ...T) -> T {
|
||||
res: T;
|
||||
for arg in args do res += arg;
|
||||
return res;
|
||||
}
|
||||
|
||||
fmt.println("add =", add(int, 1, 2, 3, 4, 5, 6));
|
||||
|
||||
swap :: proc(T: type, a, b: ^T) {
|
||||
tmp := a^;
|
||||
a^ = b^;
|
||||
b^ = tmp;
|
||||
}
|
||||
|
||||
a, b: int = 3, 4;
|
||||
fmt.println("Pre-swap:", a, b);
|
||||
swap(int, &a, &b);
|
||||
fmt.println("Post-swap:", a, b);
|
||||
a, b = b, a; // Or use this syntax for this silly example case
|
||||
|
||||
|
||||
Vector2 :: struct {x, y: f32;};
|
||||
{
|
||||
// A more complicated example using subtyping
|
||||
// Something like this could be used in a game
|
||||
|
||||
Entity :: struct {
|
||||
using position: Vector2;
|
||||
flags: u64;
|
||||
id: u64;
|
||||
derived: any;
|
||||
}
|
||||
|
||||
Rock :: struct {
|
||||
using entity: Entity;
|
||||
heavy: bool;
|
||||
}
|
||||
Door :: struct {
|
||||
using entity: Entity;
|
||||
open: bool;
|
||||
}
|
||||
Monster :: struct {
|
||||
using entity: Entity;
|
||||
is_robot: bool;
|
||||
is_zombie: bool;
|
||||
}
|
||||
|
||||
new_entity :: proc(T: type, x, y: f32) -> ^T {
|
||||
result := new(T);
|
||||
result.derived = result^;
|
||||
result.x = x;
|
||||
result.y = y;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
entities: [dynamic]^Entity;
|
||||
|
||||
rock := new_entity(Rock, 3, 5);
|
||||
|
||||
// Named arguments work too!
|
||||
door := new_entity(T = Door, x = 3, y = 6);
|
||||
|
||||
// And named arguments can be any order
|
||||
monster := new_entity(
|
||||
y = 1,
|
||||
x = 2,
|
||||
T = Monster,
|
||||
);
|
||||
|
||||
append(&entities, rock, door, monster);
|
||||
|
||||
fmt.println("Subtyping");
|
||||
for entity in entities {
|
||||
match e in entity.derived {
|
||||
case Rock: fmt.println("Rock", e.x, e.y);
|
||||
case Door: fmt.println("Door", e.x, e.y);
|
||||
case Monster: fmt.println("Monster", e.x, e.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
Entity :: struct {
|
||||
using position: Vector2;
|
||||
flags: u64;
|
||||
id: u64;
|
||||
variant: union { Rock, Door, Monster };
|
||||
}
|
||||
|
||||
Rock :: struct {
|
||||
using entity: ^Entity;
|
||||
heavy: bool;
|
||||
}
|
||||
Door :: struct {
|
||||
using entity: ^Entity;
|
||||
open: bool;
|
||||
}
|
||||
Monster :: struct {
|
||||
using entity: ^Entity;
|
||||
is_robot: bool;
|
||||
is_zombie: bool;
|
||||
}
|
||||
|
||||
new_entity :: proc(T: type, x, y: f32) -> ^T {
|
||||
result := new(Entity);
|
||||
result.variant = T{entity = result};
|
||||
result.x = x;
|
||||
result.y = y;
|
||||
|
||||
return cast(^T)&result.variant;
|
||||
}
|
||||
|
||||
entities: [dynamic]^Entity;
|
||||
|
||||
rock := new_entity(Rock, 3, 5);
|
||||
|
||||
// Named arguments work too!
|
||||
door := new_entity(T = Door, x = 3, y = 6);
|
||||
|
||||
// And named arguments can be any order
|
||||
monster := new_entity(
|
||||
y = 1,
|
||||
x = 2,
|
||||
T = Monster,
|
||||
);
|
||||
|
||||
append(&entities, rock, door, monster);
|
||||
|
||||
fmt.println("Union");
|
||||
for entity in entities {
|
||||
match e in entity.variant {
|
||||
case Rock: fmt.println("Rock", e.x, e.y);
|
||||
case Door: fmt.println("Door", e.x, e.y);
|
||||
case Monster: fmt.println("Monster", e.x, e.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
implicit_polymorphic_assignment :: proc() {
|
||||
yep :: proc(p: proc(x: int)) {
|
||||
p(123);
|
||||
}
|
||||
|
||||
frank :: proc(x: $T) do fmt.println("frank ->", x);
|
||||
tim :: proc(x, y: $T) do fmt.println("tim ->", x, y);
|
||||
yep(frank);
|
||||
// yep(tim);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
main :: proc() {
|
||||
/*
|
||||
foo :: proc(x: i64, y: f32) do fmt.println("#1", x, y);
|
||||
foo :: proc(x: type, y: f32) do fmt.println("#2", type_info(x), y);
|
||||
foo :: proc(x: type) do fmt.println("#3", type_info(x));
|
||||
|
||||
f :: foo;
|
||||
|
||||
f(y = 3785.1546, x = 123);
|
||||
f(x = int, y = 897.513);
|
||||
f(x = f32);
|
||||
|
||||
general_stuff();
|
||||
foreign_blocks();
|
||||
default_arguments();
|
||||
named_arguments();
|
||||
default_return_values();
|
||||
call_location();
|
||||
explicit_parametric_polymorphic_procedures();
|
||||
implicit_polymorphic_assignment();
|
||||
|
||||
|
||||
// Command line argument(s)!
|
||||
// -opt=0,1,2,3
|
||||
*/
|
||||
/*
|
||||
program := "+ + * - /";
|
||||
accumulator := 0;
|
||||
|
||||
for token in program {
|
||||
match token {
|
||||
case '+': accumulator += 1;
|
||||
case '-': accumulator -= 1;
|
||||
case '*': accumulator *= 2;
|
||||
case '/': accumulator /= 2;
|
||||
case: // Ignore everything else
|
||||
}
|
||||
}
|
||||
|
||||
fmt.printf("The program \"%s\" calculates the value %d\n",
|
||||
program, accumulator);
|
||||
*/
|
||||
}
|
||||
+646
-417
File diff suppressed because it is too large
Load Diff
+48
-49
@@ -1,88 +1,87 @@
|
||||
#shared_global_scope;
|
||||
|
||||
proc __multi3(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
|
||||
const bits_in_dword_2 = size_of(i64) * 4;
|
||||
const lower_mask = u128(~u64(0) >> bits_in_dword_2);
|
||||
__multi3 :: proc(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
|
||||
bits_in_dword_2 :: size_of(i64) * 4;
|
||||
lower_mask :: u128(~u64(0) >> bits_in_dword_2);
|
||||
|
||||
|
||||
when ODIN_ENDIAN == "bit" {
|
||||
type TWords raw_union {
|
||||
all: u128,
|
||||
using _: struct {lo, hi: u64},
|
||||
TWords :: struct #raw_union {
|
||||
all: u128;
|
||||
using _: struct {
|
||||
when ODIN_ENDIAN == "big" {
|
||||
lo, hi: u64;
|
||||
} else {
|
||||
hi, lo: u64;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
type TWords raw_union {
|
||||
all: u128,
|
||||
using _: struct {hi, lo: u64},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
var r: TWords;
|
||||
var t: u64;
|
||||
r: TWords;
|
||||
t: u64;
|
||||
|
||||
r.lo = u64(a & lower_mask) * u64(b & lower_mask);
|
||||
t = r.lo >> bits_in_dword_2;
|
||||
r.lo = u64(a & lower_mask) * u64(b & lower_mask);
|
||||
t = r.lo >> bits_in_dword_2;
|
||||
r.lo &= u64(lower_mask);
|
||||
t += u64(a >> bits_in_dword_2) * u64(b & lower_mask);
|
||||
t += u64(a >> bits_in_dword_2) * u64(b & lower_mask);
|
||||
r.lo += u64(t & u64(lower_mask)) << bits_in_dword_2;
|
||||
r.hi = t >> bits_in_dword_2;
|
||||
t = r.lo >> bits_in_dword_2;
|
||||
r.hi = t >> bits_in_dword_2;
|
||||
t = r.lo >> bits_in_dword_2;
|
||||
r.lo &= u64(lower_mask);
|
||||
t += u64(b >> bits_in_dword_2) * u64(a & lower_mask);
|
||||
t += u64(b >> bits_in_dword_2) * u64(a & lower_mask);
|
||||
r.lo += u64(t & u64(lower_mask)) << bits_in_dword_2;
|
||||
r.hi += t >> bits_in_dword_2;
|
||||
r.hi += u64(a >> bits_in_dword_2) * u64(b >> bits_in_dword_2);
|
||||
return r.all;
|
||||
}
|
||||
|
||||
proc __u128_mod(a, b: u128) -> u128 #cc_c #link_name "__umodti3" {
|
||||
var r: u128;
|
||||
__u128_mod :: proc(a, b: u128) -> u128 #cc_c #link_name "__umodti3" {
|
||||
r: u128;
|
||||
__u128_quo_mod(a, b, &r);
|
||||
return r;
|
||||
}
|
||||
|
||||
proc __u128_quo(a, b: u128) -> u128 #cc_c #link_name "__udivti3" {
|
||||
__u128_quo :: proc(a, b: u128) -> u128 #cc_c #link_name "__udivti3" {
|
||||
return __u128_quo_mod(a, b, nil);
|
||||
}
|
||||
|
||||
proc __i128_mod(a, b: i128) -> i128 #cc_c #link_name "__modti3" {
|
||||
var r: i128;
|
||||
__i128_mod :: proc(a, b: i128) -> i128 #cc_c #link_name "__modti3" {
|
||||
r: i128;
|
||||
__i128_quo_mod(a, b, &r);
|
||||
return r;
|
||||
}
|
||||
|
||||
proc __i128_quo(a, b: i128) -> i128 #cc_c #link_name "__divti3" {
|
||||
__i128_quo :: proc(a, b: i128) -> i128 #cc_c #link_name "__divti3" {
|
||||
return __i128_quo_mod(a, b, nil);
|
||||
}
|
||||
|
||||
proc __i128_quo_mod(a, b: i128, rem: ^i128) -> (quo: i128) #cc_c #link_name "__divmodti4" {
|
||||
var s: i128;
|
||||
__i128_quo_mod :: proc(a, b: i128, rem: ^i128) -> (quo: i128) #cc_c #link_name "__divmodti4" {
|
||||
s: i128;
|
||||
s = b >> 127;
|
||||
b = (b~s) - s;
|
||||
s = a >> 127;
|
||||
b = (a~s) - s;
|
||||
|
||||
var uquo: u128;
|
||||
var urem = __u128_quo_mod(transmute(u128, a), transmute(u128, b), &uquo);
|
||||
var iquo = transmute(i128, uquo);
|
||||
var irem = transmute(i128, urem);
|
||||
uquo: u128;
|
||||
urem := __u128_quo_mod(transmute(u128)a, transmute(u128)b, &uquo);
|
||||
iquo := transmute(i128)uquo;
|
||||
irem := transmute(i128)urem;
|
||||
|
||||
iquo = (iquo~s) - s;
|
||||
irem = (irem~s) - s;
|
||||
if rem != nil { rem^ = irem; }
|
||||
if rem != nil do rem^ = irem;
|
||||
return iquo;
|
||||
}
|
||||
|
||||
|
||||
proc __u128_quo_mod(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "__udivmodti4" {
|
||||
var alo, ahi = u64(a), u64(a>>64);
|
||||
var blo, bhi = u64(b), u64(b>>64);
|
||||
__u128_quo_mod :: proc(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "__udivmodti4" {
|
||||
alo, ahi := u64(a), u64(a>>64);
|
||||
blo, bhi := u64(b), u64(b>>64);
|
||||
if b == 0 {
|
||||
if rem != nil { rem^ = 0; }
|
||||
if rem != nil do rem^ = 0;
|
||||
return u128(alo/blo);
|
||||
}
|
||||
|
||||
var r, d, x, q: u128 = a, b, 1, 0;
|
||||
r, d, x, q: u128 = a, b, 1, 0;
|
||||
|
||||
for r >= d && (d>>127)&1 == 0 {
|
||||
x <<= 1;
|
||||
@@ -98,15 +97,15 @@ proc __u128_quo_mod(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "__u
|
||||
d >>= 1;
|
||||
}
|
||||
|
||||
if rem != nil { rem^ = r; }
|
||||
if rem != nil do rem^ = r;
|
||||
return q;
|
||||
}
|
||||
|
||||
/*
|
||||
proc __f16_to_f32(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee" {
|
||||
__f16_to_f32 :: proc(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee" {
|
||||
when true {
|
||||
// Source: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
|
||||
const FP32 = raw_union {u: u32, f: f32};
|
||||
FP32 :: struct #raw_union {u: u32, f: f32};
|
||||
|
||||
magic, was_infnan: FP32;
|
||||
magic.u = (254-15) << 23;
|
||||
@@ -127,19 +126,19 @@ proc __f16_to_f32(f: f16) -> f32 #cc_c #no_inline #link_name "__gnu_h2f_ieee" {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
proc __f32_to_f16(f_: f32) -> f16 #cc_c #no_inline #link_name "__gnu_f2h_ieee" {
|
||||
__f32_to_f16 :: proc(f_: f32) -> f16 #cc_c #no_inline #link_name "__gnu_f2h_ieee" {
|
||||
when false {
|
||||
// Source: https://gist.github.com/rygorous/2156668
|
||||
const FP16 = raw_union {u: u16, f: f16};
|
||||
const FP32 = raw_union {u: u32, f: f32};
|
||||
FP16 :: struct #raw_union {u: u16, f: f16};
|
||||
FP32 :: struct #raw_union {u: u32, f: f32};
|
||||
|
||||
f32infty, f16infty, magic: FP32;
|
||||
f32infty.u = 255<<23;
|
||||
f16infty.u = 31<<23;
|
||||
magic.u = 15<<23;
|
||||
|
||||
const sign_mask = u32(0x80000000);
|
||||
const round_mask = ~u32(0x0fff);
|
||||
sign_mask :: u32(0x80000000);
|
||||
round_mask :: ~u32(0x0fff);
|
||||
|
||||
f := transmute(FP32, f_);
|
||||
|
||||
@@ -217,11 +216,11 @@ proc __f32_to_f16(f_: f32) -> f16 #cc_c #no_inline #link_name "__gnu_f2h_ieee" {
|
||||
}
|
||||
}
|
||||
|
||||
proc __f64_to_f16(f: f64) -> f16 #cc_c #no_inline #link_name "__truncdfhf2" {
|
||||
__f64_to_f16 :: proc(f: f64) -> f16 #cc_c #no_inline #link_name "__truncdfhf2" {
|
||||
return __f32_to_f16(f32(f));
|
||||
}
|
||||
|
||||
proc __f16_to_f64(f: f16) -> f64 #cc_c #no_inline {
|
||||
__f16_to_f64 :: proc(f: f16) -> f64 #cc_c #no_inline {
|
||||
return f64(__f16_to_f32(f));
|
||||
}
|
||||
*/
|
||||
|
||||
+33
-33
@@ -2,99 +2,99 @@
|
||||
// Inline vs external file?
|
||||
|
||||
import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
||||
var _ = compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
|
||||
_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
|
||||
|
||||
|
||||
proc yield_thread() { win32.mm_pause(); }
|
||||
proc mfence () { win32.read_write_barrier(); }
|
||||
proc sfence () { win32.write_barrier(); }
|
||||
proc lfence () { win32.read_barrier(); }
|
||||
yield_thread :: proc() { win32.mm_pause(); }
|
||||
mfence :: proc() { win32.read_write_barrier(); }
|
||||
sfence :: proc() { win32.write_barrier(); }
|
||||
lfence :: proc() { win32.read_barrier(); }
|
||||
|
||||
|
||||
proc load(a: ^i32) -> i32 {
|
||||
load :: proc(a: ^i32) -> i32 {
|
||||
return a^;
|
||||
}
|
||||
proc store(a: ^i32, value: i32) {
|
||||
store :: proc(a: ^i32, value: i32) {
|
||||
a^ = value;
|
||||
}
|
||||
proc compare_exchange(a: ^i32, expected, desired: i32) -> i32 {
|
||||
compare_exchange :: proc(a: ^i32, expected, desired: i32) -> i32 {
|
||||
return win32.interlocked_compare_exchange(a, desired, expected);
|
||||
}
|
||||
proc exchanged(a: ^i32, desired: i32) -> i32 {
|
||||
exchanged :: proc(a: ^i32, desired: i32) -> i32 {
|
||||
return win32.interlocked_exchange(a, desired);
|
||||
}
|
||||
proc fetch_add(a: ^i32, operand: i32) -> i32 {
|
||||
fetch_add :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
return win32.interlocked_exchange_add(a, operand);
|
||||
|
||||
}
|
||||
proc fetch_and(a: ^i32, operand: i32) -> i32 {
|
||||
fetch_and :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
return win32.interlocked_and(a, operand);
|
||||
}
|
||||
proc fetch_or(a: ^i32, operand: i32) -> i32 {
|
||||
fetch_or :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
return win32.interlocked_or(a, operand);
|
||||
}
|
||||
proc spin_lock(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||
var old_value = compare_exchange(a, 1, 0);
|
||||
var counter = 0;
|
||||
spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||
old_value := compare_exchange(a, 1, 0);
|
||||
counter := 0;
|
||||
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||
counter++;
|
||||
counter += 1;
|
||||
yield_thread();
|
||||
old_value = compare_exchange(a, 1, 0);
|
||||
mfence();
|
||||
}
|
||||
return old_value == 0;
|
||||
}
|
||||
proc spin_unlock(a: ^i32) {
|
||||
spin_unlock :: proc(a: ^i32) {
|
||||
store(a, 0);
|
||||
mfence();
|
||||
}
|
||||
proc try_acquire_lock(a: ^i32) -> bool {
|
||||
try_acquire_lock :: proc(a: ^i32) -> bool {
|
||||
yield_thread();
|
||||
var old_value = compare_exchange(a, 1, 0);
|
||||
old_value := compare_exchange(a, 1, 0);
|
||||
mfence();
|
||||
return old_value == 0;
|
||||
}
|
||||
|
||||
|
||||
proc load(a: ^i64) -> i64 {
|
||||
load :: proc(a: ^i64) -> i64 {
|
||||
return a^;
|
||||
}
|
||||
proc store(a: ^i64, value: i64) {
|
||||
store :: proc(a: ^i64, value: i64) {
|
||||
a^ = value;
|
||||
}
|
||||
proc compare_exchange(a: ^i64, expected, desired: i64) -> i64 {
|
||||
compare_exchange :: proc(a: ^i64, expected, desired: i64) -> i64 {
|
||||
return win32.interlocked_compare_exchange64(a, desired, expected);
|
||||
}
|
||||
proc exchanged(a: ^i64, desired: i64) -> i64 {
|
||||
exchanged :: proc(a: ^i64, desired: i64) -> i64 {
|
||||
return win32.interlocked_exchange64(a, desired);
|
||||
}
|
||||
proc fetch_add(a: ^i64, operand: i64) -> i64 {
|
||||
fetch_add :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
return win32.interlocked_exchange_add64(a, operand);
|
||||
}
|
||||
proc fetch_and(a: ^i64, operand: i64) -> i64 {
|
||||
fetch_and :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
return win32.interlocked_and64(a, operand);
|
||||
}
|
||||
proc fetch_or(a: ^i64, operand: i64) -> i64 {
|
||||
fetch_or :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
return win32.interlocked_or64(a, operand);
|
||||
}
|
||||
proc spin_lock(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||
var old_value = compare_exchange(a, 1, 0);
|
||||
var counter = 0;
|
||||
spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||
old_value := compare_exchange(a, 1, 0);
|
||||
counter := 0;
|
||||
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||
counter++;
|
||||
counter += 1;
|
||||
yield_thread();
|
||||
old_value = compare_exchange(a, 1, 0);
|
||||
mfence();
|
||||
}
|
||||
return old_value == 0;
|
||||
}
|
||||
proc spin_unlock(a: ^i64) {
|
||||
spin_unlock :: proc(a: ^i64) {
|
||||
store(a, 0);
|
||||
mfence();
|
||||
}
|
||||
proc try_acquire_lock(a: ^i64) -> bool {
|
||||
try_acquire_lock :: proc(a: ^i64) -> bool {
|
||||
yield_thread();
|
||||
var old_value = compare_exchange(a, 1, 0);
|
||||
old_value := compare_exchange(a, 1, 0);
|
||||
mfence();
|
||||
return old_value == 0;
|
||||
}
|
||||
|
||||
+222
-224
@@ -1,287 +1,285 @@
|
||||
const (
|
||||
U8_MIN = u8(0);
|
||||
U16_MIN = u16(0);
|
||||
U32_MIN = u32(0);
|
||||
U64_MIN = u64(0);
|
||||
U128_MIN = u128(0);
|
||||
U8_MIN :: u8(0);
|
||||
U16_MIN :: u16(0);
|
||||
U32_MIN :: u32(0);
|
||||
U64_MIN :: u64(0);
|
||||
U128_MIN :: u128(0);
|
||||
|
||||
I8_MIN = i8(-0x80);
|
||||
I16_MIN = i16(-0x8000);
|
||||
I32_MIN = i32(-0x8000_0000);
|
||||
I64_MIN = i64(-0x8000_0000_0000_0000);
|
||||
I128_MIN = i128(-0x8000_0000_0000_0000_0000_0000_0000_0000);
|
||||
I8_MIN :: i8(-0x80);
|
||||
I16_MIN :: i16(-0x8000);
|
||||
I32_MIN :: i32(-0x8000_0000);
|
||||
I64_MIN :: i64(-0x8000_0000_0000_0000);
|
||||
I128_MIN :: i128(-0x8000_0000_0000_0000_0000_0000_0000_0000);
|
||||
|
||||
U8_MAX = ~u8(0);
|
||||
U16_MAX = ~u16(0);
|
||||
U32_MAX = ~u32(0);
|
||||
U64_MAX = ~u64(0);
|
||||
U128_MAX = ~u128(0);
|
||||
U8_MAX :: ~u8(0);
|
||||
U16_MAX :: ~u16(0);
|
||||
U32_MAX :: ~u32(0);
|
||||
U64_MAX :: ~u64(0);
|
||||
U128_MAX :: ~u128(0);
|
||||
|
||||
I8_MAX = i8(0x7f);
|
||||
I16_MAX = i16(0x7fff);
|
||||
I32_MAX = i32(0x7fff_ffff);
|
||||
I64_MAX = i64(0x7fff_ffff_ffff_ffff);
|
||||
I128_MAX = i128(0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ffff);
|
||||
)
|
||||
I8_MAX :: i8(0x7f);
|
||||
I16_MAX :: i16(0x7fff);
|
||||
I32_MAX :: i32(0x7fff_ffff);
|
||||
I64_MAX :: i64(0x7fff_ffff_ffff_ffff);
|
||||
I128_MAX :: i128(0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ffff);
|
||||
|
||||
proc count_ones(i: u8) -> u8 { foreign __llvm_core proc __llvm_ctpop(u8) -> u8 #link_name "llvm.ctpop.i8"; return __llvm_ctpop(i); }
|
||||
proc count_ones(i: i8) -> i8 { foreign __llvm_core proc __llvm_ctpop(i8) -> i8 #link_name "llvm.ctpop.i8"; return __llvm_ctpop(i); }
|
||||
proc count_ones(i: u16) -> u16 { foreign __llvm_core proc __llvm_ctpop(u16) -> u16 #link_name "llvm.ctpop.i16"; return __llvm_ctpop(i); }
|
||||
proc count_ones(i: i16) -> i16 { foreign __llvm_core proc __llvm_ctpop(i16) -> i16 #link_name "llvm.ctpop.i16"; return __llvm_ctpop(i); }
|
||||
proc count_ones(i: u32) -> u32 { foreign __llvm_core proc __llvm_ctpop(u32) -> u32 #link_name "llvm.ctpop.i32"; return __llvm_ctpop(i); }
|
||||
proc count_ones(i: i32) -> i32 { foreign __llvm_core proc __llvm_ctpop(i32) -> i32 #link_name "llvm.ctpop.i32"; return __llvm_ctpop(i); }
|
||||
proc count_ones(i: u64) -> u64 { foreign __llvm_core proc __llvm_ctpop(u64) -> u64 #link_name "llvm.ctpop.i64"; return __llvm_ctpop(i); }
|
||||
proc count_ones(i: i64) -> i64 { foreign __llvm_core proc __llvm_ctpop(i64) -> i64 #link_name "llvm.ctpop.i64"; return __llvm_ctpop(i); }
|
||||
proc count_ones(i: u128) -> u128 { foreign __llvm_core proc __llvm_ctpop(u128) -> u128 #link_name "llvm.ctpop.i128";return __llvm_ctpop(i); }
|
||||
proc count_ones(i: i128) -> i128 { foreign __llvm_core proc __llvm_ctpop(i128) -> i128 #link_name "llvm.ctpop.i128";return __llvm_ctpop(i); }
|
||||
proc count_ones(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(count_ones(u32(i))); } else { return uint(count_ones(u64(i))); } }
|
||||
proc count_ones(i: int) -> int { when size_of(int) == size_of(i32) { return int(count_ones(i32(i))); } else { return int(count_ones(i64(i))); } }
|
||||
count_ones :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_ctpop :: proc(u8) -> u8 #link_name "llvm.ctpop.i8" ---; return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_ctpop :: proc(i8) -> i8 #link_name "llvm.ctpop.i8" ---; return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_ctpop :: proc(u16) -> u16 #link_name "llvm.ctpop.i16" ---; return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_ctpop :: proc(i16) -> i16 #link_name "llvm.ctpop.i16" ---; return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_ctpop :: proc(u32) -> u32 #link_name "llvm.ctpop.i32" ---; return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_ctpop :: proc(i32) -> i32 #link_name "llvm.ctpop.i32" ---; return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_ctpop :: proc(u64) -> u64 #link_name "llvm.ctpop.i64" ---; return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_ctpop :: proc(i64) -> i64 #link_name "llvm.ctpop.i64" ---; return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_ctpop :: proc(u128) -> u128 #link_name "llvm.ctpop.i128" ---;return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_ctpop :: proc(i128) -> i128 #link_name "llvm.ctpop.i128" ---;return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(count_ones(u32(i))); } else { return uint(count_ones(u64(i))); } }
|
||||
count_ones :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(count_ones(i32(i))); } else { return int(count_ones(i64(i))); } }
|
||||
|
||||
proc count_zeros(i: u8) -> u8 { return 8 - count_ones(i); }
|
||||
proc count_zeros(i: i8) -> i8 { return 8 - count_ones(i); }
|
||||
proc count_zeros(i: u16) -> u16 { return 16 - count_ones(i); }
|
||||
proc count_zeros(i: i16) -> i16 { return 16 - count_ones(i); }
|
||||
proc count_zeros(i: u32) -> u32 { return 32 - count_ones(i); }
|
||||
proc count_zeros(i: i32) -> i32 { return 32 - count_ones(i); }
|
||||
proc count_zeros(i: u64) -> u64 { return 64 - count_ones(i); }
|
||||
proc count_zeros(i: i64) -> i64 { return 64 - count_ones(i); }
|
||||
proc count_zeros(i: u128) -> u128 { return 128 - count_ones(i); }
|
||||
proc count_zeros(i: i128) -> i128 { return 128 - count_ones(i); }
|
||||
proc count_zeros(i: uint) -> uint { return 8*size_of(uint) - count_ones(i); }
|
||||
proc count_zeros(i: int) -> int { return 8*size_of(int) - count_ones(i); }
|
||||
count_zeros :: proc(i: u8) -> u8 { return 8 - count_ones(i); }
|
||||
count_zeros :: proc(i: i8) -> i8 { return 8 - count_ones(i); }
|
||||
count_zeros :: proc(i: u16) -> u16 { return 16 - count_ones(i); }
|
||||
count_zeros :: proc(i: i16) -> i16 { return 16 - count_ones(i); }
|
||||
count_zeros :: proc(i: u32) -> u32 { return 32 - count_ones(i); }
|
||||
count_zeros :: proc(i: i32) -> i32 { return 32 - count_ones(i); }
|
||||
count_zeros :: proc(i: u64) -> u64 { return 64 - count_ones(i); }
|
||||
count_zeros :: proc(i: i64) -> i64 { return 64 - count_ones(i); }
|
||||
count_zeros :: proc(i: u128) -> u128 { return 128 - count_ones(i); }
|
||||
count_zeros :: proc(i: i128) -> i128 { return 128 - count_ones(i); }
|
||||
count_zeros :: proc(i: uint) -> uint { return 8*size_of(uint) - count_ones(i); }
|
||||
count_zeros :: proc(i: int) -> int { return 8*size_of(int) - count_ones(i); }
|
||||
|
||||
|
||||
proc rotate_left(i: u8, s: uint) -> u8 { return (i << s)|(i >> (8*size_of(u8) - s)); }
|
||||
proc rotate_left(i: i8, s: uint) -> i8 { return (i << s)|(i >> (8*size_of(i8) - s)); }
|
||||
proc rotate_left(i: u16, s: uint) -> u16 { return (i << s)|(i >> (8*size_of(u16) - s)); }
|
||||
proc rotate_left(i: i16, s: uint) -> i16 { return (i << s)|(i >> (8*size_of(i16) - s)); }
|
||||
proc rotate_left(i: u32, s: uint) -> u32 { return (i << s)|(i >> (8*size_of(u32) - s)); }
|
||||
proc rotate_left(i: i32, s: uint) -> i32 { return (i << s)|(i >> (8*size_of(i32) - s)); }
|
||||
proc rotate_left(i: u64, s: uint) -> u64 { return (i << s)|(i >> (8*size_of(u64) - s)); }
|
||||
proc rotate_left(i: i64, s: uint) -> i64 { return (i << s)|(i >> (8*size_of(i64) - s)); }
|
||||
proc rotate_left(i: u128, s: uint) -> u128 { return (i << s)|(i >> (8*size_of(u128) - s)); }
|
||||
proc rotate_left(i: i128, s: uint) -> i128 { return (i << s)|(i >> (8*size_of(i128) - s)); }
|
||||
proc rotate_left(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_left(u32(i), s)); } else { return uint(rotate_left(u64(i), s)); } }
|
||||
proc rotate_left(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_left(i32(i), s)); } else { return int(rotate_left(i64(i), s)); } }
|
||||
rotate_left :: proc(i: u8, s: uint) -> u8 { return (i << s)|(i >> (8*size_of(u8) - s)); }
|
||||
rotate_left :: proc(i: i8, s: uint) -> i8 { return (i << s)|(i >> (8*size_of(i8) - s)); }
|
||||
rotate_left :: proc(i: u16, s: uint) -> u16 { return (i << s)|(i >> (8*size_of(u16) - s)); }
|
||||
rotate_left :: proc(i: i16, s: uint) -> i16 { return (i << s)|(i >> (8*size_of(i16) - s)); }
|
||||
rotate_left :: proc(i: u32, s: uint) -> u32 { return (i << s)|(i >> (8*size_of(u32) - s)); }
|
||||
rotate_left :: proc(i: i32, s: uint) -> i32 { return (i << s)|(i >> (8*size_of(i32) - s)); }
|
||||
rotate_left :: proc(i: u64, s: uint) -> u64 { return (i << s)|(i >> (8*size_of(u64) - s)); }
|
||||
rotate_left :: proc(i: i64, s: uint) -> i64 { return (i << s)|(i >> (8*size_of(i64) - s)); }
|
||||
rotate_left :: proc(i: u128, s: uint) -> u128 { return (i << s)|(i >> (8*size_of(u128) - s)); }
|
||||
rotate_left :: proc(i: i128, s: uint) -> i128 { return (i << s)|(i >> (8*size_of(i128) - s)); }
|
||||
rotate_left :: proc(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_left(u32(i), s)); } else { return uint(rotate_left(u64(i), s)); } }
|
||||
rotate_left :: proc(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_left(i32(i), s)); } else { return int(rotate_left(i64(i), s)); } }
|
||||
|
||||
|
||||
proc rotate_right(i: u8, s: uint) -> u8 { return (i >> s)|(i << (8*size_of(u8) - s)); }
|
||||
proc rotate_right(i: i8, s: uint) -> i8 { return (i >> s)|(i << (8*size_of(i8) - s)); }
|
||||
proc rotate_right(i: u16, s: uint) -> u16 { return (i >> s)|(i << (8*size_of(u16) - s)); }
|
||||
proc rotate_right(i: i16, s: uint) -> i16 { return (i >> s)|(i << (8*size_of(i16) - s)); }
|
||||
proc rotate_right(i: u32, s: uint) -> u32 { return (i >> s)|(i << (8*size_of(u32) - s)); }
|
||||
proc rotate_right(i: i32, s: uint) -> i32 { return (i >> s)|(i << (8*size_of(i32) - s)); }
|
||||
proc rotate_right(i: u64, s: uint) -> u64 { return (i >> s)|(i << (8*size_of(u64) - s)); }
|
||||
proc rotate_right(i: i64, s: uint) -> i64 { return (i >> s)|(i << (8*size_of(i64) - s)); }
|
||||
proc rotate_right(i: u128, s: uint) -> u128 { return (i >> s)|(i << (8*size_of(u128) - s)); }
|
||||
proc rotate_right(i: i128, s: uint) -> i128 { return (i >> s)|(i << (8*size_of(i128) - s)); }
|
||||
proc rotate_right(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_right(u32(i), s)); } else { return uint(rotate_right(u64(i), s)); } }
|
||||
proc rotate_right(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_right(i32(i), s)); } else { return int(rotate_right(i64(i), s)); } }
|
||||
rotate_right :: proc(i: u8, s: uint) -> u8 { return (i >> s)|(i << (8*size_of(u8) - s)); }
|
||||
rotate_right :: proc(i: i8, s: uint) -> i8 { return (i >> s)|(i << (8*size_of(i8) - s)); }
|
||||
rotate_right :: proc(i: u16, s: uint) -> u16 { return (i >> s)|(i << (8*size_of(u16) - s)); }
|
||||
rotate_right :: proc(i: i16, s: uint) -> i16 { return (i >> s)|(i << (8*size_of(i16) - s)); }
|
||||
rotate_right :: proc(i: u32, s: uint) -> u32 { return (i >> s)|(i << (8*size_of(u32) - s)); }
|
||||
rotate_right :: proc(i: i32, s: uint) -> i32 { return (i >> s)|(i << (8*size_of(i32) - s)); }
|
||||
rotate_right :: proc(i: u64, s: uint) -> u64 { return (i >> s)|(i << (8*size_of(u64) - s)); }
|
||||
rotate_right :: proc(i: i64, s: uint) -> i64 { return (i >> s)|(i << (8*size_of(i64) - s)); }
|
||||
rotate_right :: proc(i: u128, s: uint) -> u128 { return (i >> s)|(i << (8*size_of(u128) - s)); }
|
||||
rotate_right :: proc(i: i128, s: uint) -> i128 { return (i >> s)|(i << (8*size_of(i128) - s)); }
|
||||
rotate_right :: proc(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_right(u32(i), s)); } else { return uint(rotate_right(u64(i), s)); } }
|
||||
rotate_right :: proc(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_right(i32(i), s)); } else { return int(rotate_right(i64(i), s)); } }
|
||||
|
||||
|
||||
proc leading_zeros(i: u8) -> u8 { foreign __llvm_core proc __llvm_ctlz(u8, bool) -> u8 #link_name "llvm.ctlz.i8"; return __llvm_ctlz(i, false); }
|
||||
proc leading_zeros(i: i8) -> i8 { foreign __llvm_core proc __llvm_ctlz(i8, bool) -> i8 #link_name "llvm.ctlz.i8"; return __llvm_ctlz(i, false); }
|
||||
proc leading_zeros(i: u16) -> u16 { foreign __llvm_core proc __llvm_ctlz(u16, bool) -> u16 #link_name "llvm.ctlz.i16"; return __llvm_ctlz(i, false); }
|
||||
proc leading_zeros(i: i16) -> i16 { foreign __llvm_core proc __llvm_ctlz(i16, bool) -> i16 #link_name "llvm.ctlz.i16"; return __llvm_ctlz(i, false); }
|
||||
proc leading_zeros(i: u32) -> u32 { foreign __llvm_core proc __llvm_ctlz(u32, bool) -> u32 #link_name "llvm.ctlz.i32"; return __llvm_ctlz(i, false); }
|
||||
proc leading_zeros(i: i32) -> i32 { foreign __llvm_core proc __llvm_ctlz(i32, bool) -> i32 #link_name "llvm.ctlz.i32"; return __llvm_ctlz(i, false); }
|
||||
proc leading_zeros(i: u64) -> u64 { foreign __llvm_core proc __llvm_ctlz(u64, bool) -> u64 #link_name "llvm.ctlz.i64"; return __llvm_ctlz(i, false); }
|
||||
proc leading_zeros(i: i64) -> i64 { foreign __llvm_core proc __llvm_ctlz(i64, bool) -> i64 #link_name "llvm.ctlz.i64"; return __llvm_ctlz(i, false); }
|
||||
proc leading_zeros(i: u128) -> u128 { foreign __llvm_core proc __llvm_ctlz(u128, bool) -> u128 #link_name "llvm.ctlz.i128";return __llvm_ctlz(i, false); }
|
||||
proc leading_zeros(i: i128) -> i128 { foreign __llvm_core proc __llvm_ctlz(i128, bool) -> i128 #link_name "llvm.ctlz.i128";return __llvm_ctlz(i, false); }
|
||||
proc leading_zeros(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(leading_zeros(u32(i))); } else { return uint(leading_zeros(u64(i))); } }
|
||||
proc leading_zeros(i: int) -> int { when size_of(int) == size_of(i32) { return int(leading_zeros(i32(i))); } else { return int(leading_zeros(i64(i))); } }
|
||||
leading_zeros :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_ctlz :: proc(u8, bool) -> u8 #link_name "llvm.ctlz.i8" ---; return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_ctlz :: proc(i8, bool) -> i8 #link_name "llvm.ctlz.i8" ---; return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_ctlz :: proc(u16, bool) -> u16 #link_name "llvm.ctlz.i16" ---; return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_ctlz :: proc(i16, bool) -> i16 #link_name "llvm.ctlz.i16" ---; return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_ctlz :: proc(u32, bool) -> u32 #link_name "llvm.ctlz.i32" ---; return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_ctlz :: proc(i32, bool) -> i32 #link_name "llvm.ctlz.i32" ---; return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_ctlz :: proc(u64, bool) -> u64 #link_name "llvm.ctlz.i64" ---; return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_ctlz :: proc(i64, bool) -> i64 #link_name "llvm.ctlz.i64" ---; return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_ctlz :: proc(u128, bool) -> u128 #link_name "llvm.ctlz.i128" ---;return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_ctlz :: proc(i128, bool) -> i128 #link_name "llvm.ctlz.i128" ---;return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(leading_zeros(u32(i))); } else { return uint(leading_zeros(u64(i))); } }
|
||||
leading_zeros :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(leading_zeros(i32(i))); } else { return int(leading_zeros(i64(i))); } }
|
||||
|
||||
proc trailing_zeros(i: u8) -> u8 { foreign __llvm_core proc __llvm_cttz(u8, bool) -> u8 #link_name "llvm.cttz.i8"; return __llvm_cttz(i, false); }
|
||||
proc trailing_zeros(i: i8) -> i8 { foreign __llvm_core proc __llvm_cttz(i8, bool) -> i8 #link_name "llvm.cttz.i8"; return __llvm_cttz(i, false); }
|
||||
proc trailing_zeros(i: u16) -> u16 { foreign __llvm_core proc __llvm_cttz(u16, bool) -> u16 #link_name "llvm.cttz.i16"; return __llvm_cttz(i, false); }
|
||||
proc trailing_zeros(i: i16) -> i16 { foreign __llvm_core proc __llvm_cttz(i16, bool) -> i16 #link_name "llvm.cttz.i16"; return __llvm_cttz(i, false); }
|
||||
proc trailing_zeros(i: u32) -> u32 { foreign __llvm_core proc __llvm_cttz(u32, bool) -> u32 #link_name "llvm.cttz.i32"; return __llvm_cttz(i, false); }
|
||||
proc trailing_zeros(i: i32) -> i32 { foreign __llvm_core proc __llvm_cttz(i32, bool) -> i32 #link_name "llvm.cttz.i32"; return __llvm_cttz(i, false); }
|
||||
proc trailing_zeros(i: u64) -> u64 { foreign __llvm_core proc __llvm_cttz(u64, bool) -> u64 #link_name "llvm.cttz.i64"; return __llvm_cttz(i, false); }
|
||||
proc trailing_zeros(i: i64) -> i64 { foreign __llvm_core proc __llvm_cttz(i64, bool) -> i64 #link_name "llvm.cttz.i64"; return __llvm_cttz(i, false); }
|
||||
proc trailing_zeros(i: u128) -> u128 { foreign __llvm_core proc __llvm_cttz(u128, bool) -> u128 #link_name "llvm.cttz.i128";return __llvm_cttz(i, false); }
|
||||
proc trailing_zeros(i: i128) -> i128 { foreign __llvm_core proc __llvm_cttz(i128, bool) -> i128 #link_name "llvm.cttz.i128";return __llvm_cttz(i, false); }
|
||||
proc trailing_zeros(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(trailing_zeros(u32(i))); } else { return uint(trailing_zeros(u64(i))); } }
|
||||
proc trailing_zeros(i: int) -> int { when size_of(int) == size_of(i32) { return int(trailing_zeros(i32(i))); } else { return int(trailing_zeros(i64(i))); } }
|
||||
trailing_zeros :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_cttz :: proc(u8, bool) -> u8 #link_name "llvm.cttz.i8" ---; return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_cttz :: proc(i8, bool) -> i8 #link_name "llvm.cttz.i8" ---; return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_cttz :: proc(u16, bool) -> u16 #link_name "llvm.cttz.i16" ---; return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_cttz :: proc(i16, bool) -> i16 #link_name "llvm.cttz.i16" ---; return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_cttz :: proc(u32, bool) -> u32 #link_name "llvm.cttz.i32" ---; return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_cttz :: proc(i32, bool) -> i32 #link_name "llvm.cttz.i32" ---; return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_cttz :: proc(u64, bool) -> u64 #link_name "llvm.cttz.i64" ---; return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_cttz :: proc(i64, bool) -> i64 #link_name "llvm.cttz.i64" ---; return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_cttz :: proc(u128, bool) -> u128 #link_name "llvm.cttz.i128" ---;return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_cttz :: proc(i128, bool) -> i128 #link_name "llvm.cttz.i128" ---;return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(trailing_zeros(u32(i))); } else { return uint(trailing_zeros(u64(i))); } }
|
||||
trailing_zeros :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(trailing_zeros(i32(i))); } else { return int(trailing_zeros(i64(i))); } }
|
||||
|
||||
|
||||
proc reverse_bits(i: u8) -> u8 { foreign __llvm_core proc __llvm_bitreverse(u8) -> u8 #link_name "llvm.bitreverse.i8"; return __llvm_bitreverse(i); }
|
||||
proc reverse_bits(i: i8) -> i8 { foreign __llvm_core proc __llvm_bitreverse(i8) -> i8 #link_name "llvm.bitreverse.i8"; return __llvm_bitreverse(i); }
|
||||
proc reverse_bits(i: u16) -> u16 { foreign __llvm_core proc __llvm_bitreverse(u16) -> u16 #link_name "llvm.bitreverse.i16"; return __llvm_bitreverse(i); }
|
||||
proc reverse_bits(i: i16) -> i16 { foreign __llvm_core proc __llvm_bitreverse(i16) -> i16 #link_name "llvm.bitreverse.i16"; return __llvm_bitreverse(i); }
|
||||
proc reverse_bits(i: u32) -> u32 { foreign __llvm_core proc __llvm_bitreverse(u32) -> u32 #link_name "llvm.bitreverse.i32"; return __llvm_bitreverse(i); }
|
||||
proc reverse_bits(i: i32) -> i32 { foreign __llvm_core proc __llvm_bitreverse(i32) -> i32 #link_name "llvm.bitreverse.i32"; return __llvm_bitreverse(i); }
|
||||
proc reverse_bits(i: u64) -> u64 { foreign __llvm_core proc __llvm_bitreverse(u64) -> u64 #link_name "llvm.bitreverse.i64"; return __llvm_bitreverse(i); }
|
||||
proc reverse_bits(i: i64) -> i64 { foreign __llvm_core proc __llvm_bitreverse(i64) -> i64 #link_name "llvm.bitreverse.i64"; return __llvm_bitreverse(i); }
|
||||
proc reverse_bits(i: u128) -> u128 { foreign __llvm_core proc __llvm_bitreverse(u128) -> u128 #link_name "llvm.bitreverse.i128";return __llvm_bitreverse(i); }
|
||||
proc reverse_bits(i: i128) -> i128 { foreign __llvm_core proc __llvm_bitreverse(i128) -> i128 #link_name "llvm.bitreverse.i128";return __llvm_bitreverse(i); }
|
||||
proc reverse_bits(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(reverse_bits(u32(i))); } else { return uint(reverse_bits(u64(i))); } }
|
||||
proc reverse_bits(i: int) -> int { when size_of(int) == size_of(i32) { return int(reverse_bits(i32(i))); } else { return int(reverse_bits(i64(i))); } }
|
||||
reverse_bits :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_bitreverse :: proc(u8) -> u8 #link_name "llvm.bitreverse.i8" ---; return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_bitreverse :: proc(i8) -> i8 #link_name "llvm.bitreverse.i8" ---; return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_bitreverse :: proc(u16) -> u16 #link_name "llvm.bitreverse.i16" ---; return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_bitreverse :: proc(i16) -> i16 #link_name "llvm.bitreverse.i16" ---; return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_bitreverse :: proc(u32) -> u32 #link_name "llvm.bitreverse.i32" ---; return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_bitreverse :: proc(i32) -> i32 #link_name "llvm.bitreverse.i32" ---; return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_bitreverse :: proc(u64) -> u64 #link_name "llvm.bitreverse.i64" ---; return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_bitreverse :: proc(i64) -> i64 #link_name "llvm.bitreverse.i64" ---; return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_bitreverse :: proc(u128) -> u128 #link_name "llvm.bitreverse.i128" ---;return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_bitreverse :: proc(i128) -> i128 #link_name "llvm.bitreverse.i128" ---;return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(reverse_bits(u32(i))); } else { return uint(reverse_bits(u64(i))); } }
|
||||
reverse_bits :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(reverse_bits(i32(i))); } else { return int(reverse_bits(i64(i))); } }
|
||||
|
||||
foreign __llvm_core {
|
||||
proc byte_swap(u16) -> u16 #link_name "llvm.bswap.i16";
|
||||
proc byte_swap(i16) -> i16 #link_name "llvm.bswap.i16";
|
||||
proc byte_swap(u32) -> u32 #link_name "llvm.bswap.i32";
|
||||
proc byte_swap(i32) -> i32 #link_name "llvm.bswap.i32";
|
||||
proc byte_swap(u64) -> u64 #link_name "llvm.bswap.i64";
|
||||
proc byte_swap(i64) -> i64 #link_name "llvm.bswap.i64";
|
||||
proc byte_swap(u128) -> u128 #link_name "llvm.bswap.i128";
|
||||
proc byte_swap(i128) -> i128 #link_name "llvm.bswap.i128";
|
||||
byte_swap :: proc(u16) -> u16 #link_name "llvm.bswap.i16" ---;
|
||||
byte_swap :: proc(i16) -> i16 #link_name "llvm.bswap.i16" ---;
|
||||
byte_swap :: proc(u32) -> u32 #link_name "llvm.bswap.i32" ---;
|
||||
byte_swap :: proc(i32) -> i32 #link_name "llvm.bswap.i32" ---;
|
||||
byte_swap :: proc(u64) -> u64 #link_name "llvm.bswap.i64" ---;
|
||||
byte_swap :: proc(i64) -> i64 #link_name "llvm.bswap.i64" ---;
|
||||
byte_swap :: proc(u128) -> u128 #link_name "llvm.bswap.i128" ---;
|
||||
byte_swap :: proc(i128) -> i128 #link_name "llvm.bswap.i128" ---;
|
||||
}
|
||||
proc byte_swap(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(byte_swap(u32(i))); } else { return uint(byte_swap(u64(i))); } }
|
||||
proc byte_swap(i: int) -> int { when size_of(int) == size_of(i32) { return int(byte_swap(i32(i))); } else { return int(byte_swap(i64(i))); } }
|
||||
byte_swap :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(byte_swap(u32(i))); } else { return uint(byte_swap(u64(i))); } }
|
||||
byte_swap :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(byte_swap(i32(i))); } else { return int(byte_swap(i64(i))); } }
|
||||
|
||||
proc from_be(i: u8) -> u8 { return i; }
|
||||
proc from_be(i: i8) -> i8 { return i; }
|
||||
proc from_be(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc from_be(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc from_be(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc from_be(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc from_be(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc from_be(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc from_be(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc from_be(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc from_be(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc from_be(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: u8) -> u8 { return i; }
|
||||
from_be :: proc(i: i8) -> i8 { return i; }
|
||||
from_be :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
proc from_le(i: u8) -> u8 { return i; }
|
||||
proc from_le(i: i8) -> i8 { return i; }
|
||||
proc from_le(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc from_le(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc from_le(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc from_le(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc from_le(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc from_le(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc from_le(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc from_le(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc from_le(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc from_le(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: u8) -> u8 { return i; }
|
||||
from_le :: proc(i: i8) -> i8 { return i; }
|
||||
from_le :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
proc to_be(i: u8) -> u8 { return i; }
|
||||
proc to_be(i: i8) -> i8 { return i; }
|
||||
proc to_be(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc to_be(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc to_be(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc to_be(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc to_be(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc to_be(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc to_be(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc to_be(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc to_be(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
proc to_be(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: u8) -> u8 { return i; }
|
||||
to_be :: proc(i: i8) -> i8 { return i; }
|
||||
to_be :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
|
||||
proc to_le(i: u8) -> u8 { return i; }
|
||||
proc to_le(i: i8) -> i8 { return i; }
|
||||
proc to_le(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc to_le(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc to_le(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc to_le(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc to_le(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc to_le(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc to_le(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc to_le(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc to_le(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
proc to_le(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: u8) -> u8 { return i; }
|
||||
to_le :: proc(i: i8) -> i8 { return i; }
|
||||
to_le :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
|
||||
proc overflowing_add(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core proc op(u8, u8) -> (u8, bool) #link_name "llvm.uadd.with.overflow.i8"; return op(lhs, rhs); }
|
||||
proc overflowing_add(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core proc op(i8, i8) -> (i8, bool) #link_name "llvm.sadd.with.overflow.i8"; return op(lhs, rhs); }
|
||||
proc overflowing_add(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core proc op(u16, u16) -> (u16, bool) #link_name "llvm.uadd.with.overflow.i16"; return op(lhs, rhs); }
|
||||
proc overflowing_add(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core proc op(i16, i16) -> (i16, bool) #link_name "llvm.sadd.with.overflow.i16"; return op(lhs, rhs); }
|
||||
proc overflowing_add(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core proc op(u32, u32) -> (u32, bool) #link_name "llvm.uadd.with.overflow.i32"; return op(lhs, rhs); }
|
||||
proc overflowing_add(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core proc op(i32, i32) -> (i32, bool) #link_name "llvm.sadd.with.overflow.i32"; return op(lhs, rhs); }
|
||||
proc overflowing_add(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core proc op(u64, u64) -> (u64, bool) #link_name "llvm.uadd.with.overflow.i64"; return op(lhs, rhs); }
|
||||
proc overflowing_add(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core proc op(i64, i64) -> (i64, bool) #link_name "llvm.sadd.with.overflow.i64"; return op(lhs, rhs); }
|
||||
proc overflowing_add(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core proc op(u128, u128) -> (u128, bool) #link_name "llvm.uadd.with.overflow.i128"; return op(lhs, rhs); }
|
||||
proc overflowing_add(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core proc op(i128, i128) -> (i128, bool) #link_name "llvm.sadd.with.overflow.i128"; return op(lhs, rhs); }
|
||||
proc overflowing_add(lhs, rhs: uint) -> (uint, bool) {
|
||||
overflowing_add :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core op :: proc(u8, u8) -> (u8, bool) #link_name "llvm.uadd.with.overflow.i8" ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core op :: proc(i8, i8) -> (i8, bool) #link_name "llvm.sadd.with.overflow.i8" ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core op :: proc(u16, u16) -> (u16, bool) #link_name "llvm.uadd.with.overflow.i16" ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core op :: proc(i16, i16) -> (i16, bool) #link_name "llvm.sadd.with.overflow.i16" ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core op :: proc(u32, u32) -> (u32, bool) #link_name "llvm.uadd.with.overflow.i32" ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core op :: proc(i32, i32) -> (i32, bool) #link_name "llvm.sadd.with.overflow.i32" ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core op :: proc(u64, u64) -> (u64, bool) #link_name "llvm.uadd.with.overflow.i64" ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core op :: proc(i64, i64) -> (i64, bool) #link_name "llvm.sadd.with.overflow.i64" ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core op :: proc(u128, u128) -> (u128, bool) #link_name "llvm.uadd.with.overflow.i128" ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core op :: proc(i128, i128) -> (i128, bool) #link_name "llvm.sadd.with.overflow.i128" ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
var x, ok = overflowing_add(u32(lhs), u32(rhs));
|
||||
x, ok := overflowing_add(u32(lhs), u32(rhs));
|
||||
return uint(x), ok;
|
||||
} else {
|
||||
var x, ok = overflowing_add(u64(lhs), u64(rhs));
|
||||
x, ok := overflowing_add(u64(lhs), u64(rhs));
|
||||
return uint(x), ok;
|
||||
}
|
||||
}
|
||||
proc overflowing_add(lhs, rhs: int) -> (int, bool) {
|
||||
overflowing_add :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
when size_of(int) == size_of(i32) {
|
||||
var x, ok = overflowing_add(i32(lhs), i32(rhs));
|
||||
x, ok := overflowing_add(i32(lhs), i32(rhs));
|
||||
return int(x), ok;
|
||||
} else {
|
||||
var x, ok = overflowing_add(i64(lhs), i64(rhs));
|
||||
x, ok := overflowing_add(i64(lhs), i64(rhs));
|
||||
return int(x), ok;
|
||||
}
|
||||
}
|
||||
|
||||
proc overflowing_sub(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core proc op(u8, u8) -> (u8, bool) #link_name "llvm.usub.with.overflow.i8"; return op(lhs, rhs); }
|
||||
proc overflowing_sub(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core proc op(i8, i8) -> (i8, bool) #link_name "llvm.ssub.with.overflow.i8"; return op(lhs, rhs); }
|
||||
proc overflowing_sub(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core proc op(u16, u16) -> (u16, bool) #link_name "llvm.usub.with.overflow.i16"; return op(lhs, rhs); }
|
||||
proc overflowing_sub(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core proc op(i16, i16) -> (i16, bool) #link_name "llvm.ssub.with.overflow.i16"; return op(lhs, rhs); }
|
||||
proc overflowing_sub(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core proc op(u32, u32) -> (u32, bool) #link_name "llvm.usub.with.overflow.i32"; return op(lhs, rhs); }
|
||||
proc overflowing_sub(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core proc op(i32, i32) -> (i32, bool) #link_name "llvm.ssub.with.overflow.i32"; return op(lhs, rhs); }
|
||||
proc overflowing_sub(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core proc op(u64, u64) -> (u64, bool) #link_name "llvm.usub.with.overflow.i64"; return op(lhs, rhs); }
|
||||
proc overflowing_sub(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core proc op(i64, i64) -> (i64, bool) #link_name "llvm.ssub.with.overflow.i64"; return op(lhs, rhs); }
|
||||
proc overflowing_sub(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core proc op(u128, u128) -> (u128, bool) #link_name "llvm.usub.with.overflow.i128"; return op(lhs, rhs); }
|
||||
proc overflowing_sub(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core proc op(i128, i128) -> (i128, bool) #link_name "llvm.ssub.with.overflow.i128"; return op(lhs, rhs); }
|
||||
proc overflowing_sub(lhs, rhs: uint) -> (uint, bool) {
|
||||
overflowing_sub :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core op :: proc(u8, u8) -> (u8, bool) #link_name "llvm.usub.with.overflow.i8" ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core op :: proc(i8, i8) -> (i8, bool) #link_name "llvm.ssub.with.overflow.i8" ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core op :: proc(u16, u16) -> (u16, bool) #link_name "llvm.usub.with.overflow.i16" ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core op :: proc(i16, i16) -> (i16, bool) #link_name "llvm.ssub.with.overflow.i16" ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core op :: proc(u32, u32) -> (u32, bool) #link_name "llvm.usub.with.overflow.i32" ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core op :: proc(i32, i32) -> (i32, bool) #link_name "llvm.ssub.with.overflow.i32" ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core op :: proc(u64, u64) -> (u64, bool) #link_name "llvm.usub.with.overflow.i64" ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core op :: proc(i64, i64) -> (i64, bool) #link_name "llvm.ssub.with.overflow.i64" ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core op :: proc(u128, u128) -> (u128, bool) #link_name "llvm.usub.with.overflow.i128" ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core op :: proc(i128, i128) -> (i128, bool) #link_name "llvm.ssub.with.overflow.i128" ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
var x, ok = overflowing_sub(u32(lhs), u32(rhs));
|
||||
x, ok := overflowing_sub(u32(lhs), u32(rhs));
|
||||
return uint(x), ok;
|
||||
} else {
|
||||
var x, ok = overflowing_sub(u64(lhs), u64(rhs));
|
||||
x, ok := overflowing_sub(u64(lhs), u64(rhs));
|
||||
return uint(x), ok;
|
||||
}
|
||||
}
|
||||
proc overflowing_sub(lhs, rhs: int) -> (int, bool) {
|
||||
overflowing_sub :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
when size_of(int) == size_of(i32) {
|
||||
var x, ok = overflowing_sub(i32(lhs), i32(rhs));
|
||||
x, ok := overflowing_sub(i32(lhs), i32(rhs));
|
||||
return int(x), ok;
|
||||
} else {
|
||||
var x, ok = overflowing_sub(i64(lhs), i64(rhs));
|
||||
x, ok := overflowing_sub(i64(lhs), i64(rhs));
|
||||
return int(x), ok;
|
||||
}
|
||||
}
|
||||
|
||||
proc overflowing_mul(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core proc op(u8, u8) -> (u8, bool) #link_name "llvm.umul.with.overflow.i8"; return op(lhs, rhs); }
|
||||
proc overflowing_mul(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core proc op(i8, i8) -> (i8, bool) #link_name "llvm.smul.with.overflow.i8"; return op(lhs, rhs); }
|
||||
proc overflowing_mul(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core proc op(u16, u16) -> (u16, bool) #link_name "llvm.umul.with.overflow.i16"; return op(lhs, rhs); }
|
||||
proc overflowing_mul(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core proc op(i16, i16) -> (i16, bool) #link_name "llvm.smul.with.overflow.i16"; return op(lhs, rhs); }
|
||||
proc overflowing_mul(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core proc op(u32, u32) -> (u32, bool) #link_name "llvm.umul.with.overflow.i32"; return op(lhs, rhs); }
|
||||
proc overflowing_mul(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core proc op(i32, i32) -> (i32, bool) #link_name "llvm.smul.with.overflow.i32"; return op(lhs, rhs); }
|
||||
proc overflowing_mul(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core proc op(u64, u64) -> (u64, bool) #link_name "llvm.umul.with.overflow.i64"; return op(lhs, rhs); }
|
||||
proc overflowing_mul(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core proc op(i64, i64) -> (i64, bool) #link_name "llvm.smul.with.overflow.i64"; return op(lhs, rhs); }
|
||||
proc overflowing_mul(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core proc op(u128, u128) -> (u128, bool) #link_name "llvm.umul.with.overflow.i128"; return op(lhs, rhs); }
|
||||
proc overflowing_mul(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core proc op(i128, i128) -> (i128, bool) #link_name "llvm.smul.with.overflow.i128"; return op(lhs, rhs); }
|
||||
proc overflowing_mul(lhs, rhs: uint) -> (uint, bool) {
|
||||
overflowing_mul :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core op :: proc(u8, u8) -> (u8, bool) #link_name "llvm.umul.with.overflow.i8" ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core op :: proc(i8, i8) -> (i8, bool) #link_name "llvm.smul.with.overflow.i8" ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core op :: proc(u16, u16) -> (u16, bool) #link_name "llvm.umul.with.overflow.i16" ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core op :: proc(i16, i16) -> (i16, bool) #link_name "llvm.smul.with.overflow.i16" ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core op :: proc(u32, u32) -> (u32, bool) #link_name "llvm.umul.with.overflow.i32" ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core op :: proc(i32, i32) -> (i32, bool) #link_name "llvm.smul.with.overflow.i32" ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core op :: proc(u64, u64) -> (u64, bool) #link_name "llvm.umul.with.overflow.i64" ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core op :: proc(i64, i64) -> (i64, bool) #link_name "llvm.smul.with.overflow.i64" ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core op :: proc(u128, u128) -> (u128, bool) #link_name "llvm.umul.with.overflow.i128" ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core op :: proc(i128, i128) -> (i128, bool) #link_name "llvm.smul.with.overflow.i128" ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
var x, ok = overflowing_mul(u32(lhs), u32(rhs));
|
||||
x, ok := overflowing_mul(u32(lhs), u32(rhs));
|
||||
return uint(x), ok;
|
||||
} else {
|
||||
var x, ok = overflowing_mul(u64(lhs), u64(rhs));
|
||||
x, ok := overflowing_mul(u64(lhs), u64(rhs));
|
||||
return uint(x), ok;
|
||||
}
|
||||
}
|
||||
proc overflowing_mul(lhs, rhs: int) -> (int, bool) {
|
||||
overflowing_mul :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
when size_of(int) == size_of(i32) {
|
||||
var x, ok = overflowing_mul(i32(lhs), i32(rhs));
|
||||
x, ok := overflowing_mul(i32(lhs), i32(rhs));
|
||||
return int(x), ok;
|
||||
} else {
|
||||
var x, ok = overflowing_mul(i64(lhs), i64(rhs));
|
||||
x, ok := overflowing_mul(i64(lhs), i64(rhs));
|
||||
return int(x), ok;
|
||||
}
|
||||
}
|
||||
|
||||
proc is_power_of_two(i: u8) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
proc is_power_of_two(i: i8) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
proc is_power_of_two(i: u16) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
proc is_power_of_two(i: i16) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
proc is_power_of_two(i: u32) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
proc is_power_of_two(i: i32) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
proc is_power_of_two(i: u64) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
proc is_power_of_two(i: i64) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
proc is_power_of_two(i: u128) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
proc is_power_of_two(i: i128) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
proc is_power_of_two(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
proc is_power_of_two(i: int) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: u8) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: i8) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: u16) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: i16) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: u32) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: i32) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: u64) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: i64) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: u128) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: i128) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: int) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
CHAR_BIT :: 8;
|
||||
|
||||
c_bool :: bool;
|
||||
|
||||
c_char :: u8;
|
||||
|
||||
c_schar :: i8;
|
||||
c_uchar :: i8;
|
||||
|
||||
c_short :: i16;
|
||||
c_ushort :: i16;
|
||||
|
||||
c_int :: i32;
|
||||
c_uint :: u32;
|
||||
|
||||
c_long :: ODIN_OS == "windows" ?
|
||||
i32 :
|
||||
(size_of(int) == 4) ?
|
||||
i32 :
|
||||
i64;
|
||||
|
||||
c_ulong :: ODIN_OS == "windows" ?
|
||||
u32 :
|
||||
(size_of(int) == 4) ?
|
||||
u32 :
|
||||
u64;
|
||||
|
||||
c_longlong :: i64;
|
||||
c_ulonglong :: u64;
|
||||
|
||||
c_float :: f32;
|
||||
c_double :: f64;
|
||||
|
||||
c_complex_float :: complex64;
|
||||
c_complex_double :: complex128;
|
||||
|
||||
c_size_t :: uint;
|
||||
c_ssize_t :: int;
|
||||
c_ptrdiff_t :: int;
|
||||
c_uintptr_t :: uint;
|
||||
c_intptr_t :: int;
|
||||
+76
-78
@@ -2,53 +2,53 @@
|
||||
// Multiple precision decimal numbers
|
||||
// NOTE: This is only for floating point printing and nothing else
|
||||
|
||||
type Decimal struct {
|
||||
digits: [384]u8, // big-endian digits
|
||||
count: int,
|
||||
decimal_point: int,
|
||||
neg, trunc: bool,
|
||||
Decimal :: struct {
|
||||
digits: [384]u8; // big-endian digits
|
||||
count: int;
|
||||
decimal_point: int;
|
||||
neg, trunc: bool;
|
||||
}
|
||||
|
||||
proc decimal_to_string(buf: []u8, a: ^Decimal) -> string {
|
||||
proc digit_zero(buf: []u8) -> int {
|
||||
for _, i in buf -> buf[i] = '0';
|
||||
decimal_to_string :: proc(buf: []u8, a: ^Decimal) -> string {
|
||||
digit_zero :: proc(buf: []u8) -> int {
|
||||
for _, i in buf do buf[i] = '0';
|
||||
return len(buf);
|
||||
}
|
||||
|
||||
|
||||
var n = 10 + a.count + abs(a.decimal_point);
|
||||
n := 10 + a.count + abs(a.decimal_point);
|
||||
|
||||
// TODO(bill): make this work with a buffer that's not big enough
|
||||
assert(len(buf) >= n);
|
||||
buf = buf[0..<n];
|
||||
buf = buf[0..n];
|
||||
|
||||
if a.count == 0 {
|
||||
buf[0] = '0';
|
||||
return string(buf[0..<1]);
|
||||
return string(buf[0..1]);
|
||||
}
|
||||
|
||||
var w = 0;
|
||||
w := 0;
|
||||
if a.decimal_point <= 0 {
|
||||
buf[w] = '0'; w++;
|
||||
buf[w] = '.'; w++;
|
||||
w += digit_zero(buf[w ..< w-a.decimal_point]);
|
||||
w += copy(buf[w..], a.digits[0..<a.count]);
|
||||
buf[w] = '0'; w+=1;
|
||||
buf[w] = '.'; w+=1;
|
||||
w += digit_zero(buf[w .. w-a.decimal_point]);
|
||||
w += copy(buf[w..], a.digits[0..a.count]);
|
||||
} else if a.decimal_point < a.count {
|
||||
w += copy(buf[w..], a.digits[0..<a.decimal_point]);
|
||||
buf[w] = '.'; w++;
|
||||
w += copy(buf[w..], a.digits[a.decimal_point ..< a.count]);
|
||||
w += copy(buf[w..], a.digits[0..a.decimal_point]);
|
||||
buf[w] = '.'; w+=1;
|
||||
w += copy(buf[w..], a.digits[a.decimal_point .. a.count]);
|
||||
} else {
|
||||
w += copy(buf[w..], a.digits[0..<a.count]);
|
||||
w += digit_zero(buf[w ..< w+a.decimal_point-a.count]);
|
||||
w += copy(buf[w..], a.digits[0..a.count]);
|
||||
w += digit_zero(buf[w .. w+a.decimal_point-a.count]);
|
||||
}
|
||||
|
||||
return string(buf[0..<w]);
|
||||
return string(buf[0..w]);
|
||||
}
|
||||
|
||||
// trim trailing zeros
|
||||
proc trim(a: ^Decimal) {
|
||||
trim :: proc(a: ^Decimal) {
|
||||
for a.count > 0 && a.digits[a.count-1] == '0' {
|
||||
a.count--;
|
||||
a.count -= 1;
|
||||
}
|
||||
if a.count == 0 {
|
||||
a.decimal_point = 0;
|
||||
@@ -56,21 +56,21 @@ proc trim(a: ^Decimal) {
|
||||
}
|
||||
|
||||
|
||||
proc assign(a: ^Decimal, i: u64) {
|
||||
var buf: [32]u8;
|
||||
var n = 0;
|
||||
assign :: proc(a: ^Decimal, i: u64) {
|
||||
buf: [32]u8;
|
||||
n := 0;
|
||||
for i > 0 {
|
||||
var j = i/10;
|
||||
j := i/10;
|
||||
i -= 10*j;
|
||||
buf[n] = u8('0'+i);
|
||||
n++;
|
||||
n+=1;
|
||||
i = j;
|
||||
}
|
||||
|
||||
a.count = 0;
|
||||
for n--; n >= 0; n-- {
|
||||
for n -= 1; n >= 0; n -= 1 {
|
||||
a.digits[a.count] = buf[n];
|
||||
a.count++;
|
||||
a.count+=1;
|
||||
}
|
||||
a.decimal_point = a.count;
|
||||
trim(a);
|
||||
@@ -78,12 +78,12 @@ proc assign(a: ^Decimal, i: u64) {
|
||||
|
||||
|
||||
|
||||
proc shift_right(a: ^Decimal, k: uint) {
|
||||
var r = 0; // read index
|
||||
var w = 0; // write index
|
||||
shift_right :: proc(a: ^Decimal, k: uint) {
|
||||
r := 0; // read index
|
||||
w := 0; // write index
|
||||
|
||||
var n: uint;
|
||||
for ; n>>k == 0; r++ {
|
||||
n: uint;
|
||||
for ; n>>k == 0; r+=1 {
|
||||
if r >= a.count {
|
||||
if n == 0 {
|
||||
// Just in case
|
||||
@@ -92,32 +92,32 @@ proc shift_right(a: ^Decimal, k: uint) {
|
||||
}
|
||||
for n>>k == 0 {
|
||||
n = n * 10;
|
||||
r++;
|
||||
r+=1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
var c = uint(a.digits[r]);
|
||||
c := uint(a.digits[r]);
|
||||
n = n*10 + c - '0';
|
||||
}
|
||||
a.decimal_point -= r-1;
|
||||
|
||||
var mask: uint = (1<<k) - 1;
|
||||
mask: uint = (1<<k) - 1;
|
||||
|
||||
for ; r < a.count; r++ {
|
||||
var c = uint(a.digits[r]);
|
||||
var dig = n>>k;
|
||||
for ; r < a.count; r+=1 {
|
||||
c := uint(a.digits[r]);
|
||||
dig := n>>k;
|
||||
n &= mask;
|
||||
a.digits[w] = u8('0' + dig);
|
||||
w++;
|
||||
w+=1;
|
||||
n = n*10 + c - '0';
|
||||
}
|
||||
|
||||
for n > 0 {
|
||||
var dig = n>>k;
|
||||
dig := n>>k;
|
||||
n &= mask;
|
||||
if w < len(a.digits) {
|
||||
a.digits[w] = u8('0' + dig);
|
||||
w++;
|
||||
w+=1;
|
||||
} else if dig > 0 {
|
||||
a.trunc = true;
|
||||
}
|
||||
@@ -129,18 +129,18 @@ proc shift_right(a: ^Decimal, k: uint) {
|
||||
trim(a);
|
||||
}
|
||||
|
||||
proc shift_left(a: ^Decimal, k: uint) {
|
||||
var delta = int(k/4);
|
||||
shift_left :: proc(a: ^Decimal, k: uint) {
|
||||
delta := int(k/4);
|
||||
|
||||
var r = a.count; // read index
|
||||
var w = a.count+delta; // write index
|
||||
r := a.count; // read index
|
||||
w := a.count+delta; // write index
|
||||
|
||||
var n: uint;
|
||||
for r--; r >= 0; r-- {
|
||||
n: uint;
|
||||
for r -= 1; r >= 0; r -= 1 {
|
||||
n += (uint(a.digits[r]) - '0') << k;
|
||||
var quo = n/10;
|
||||
var rem = n - 10*quo;
|
||||
w--;
|
||||
quo := n/10;
|
||||
rem := n - 10*quo;
|
||||
w -= 1;
|
||||
if w < len(a.digits) {
|
||||
a.digits[w] = u8('0' + rem);
|
||||
} else if rem != 0 {
|
||||
@@ -150,9 +150,9 @@ proc shift_left(a: ^Decimal, k: uint) {
|
||||
}
|
||||
|
||||
for n > 0 {
|
||||
var quo = n/10;
|
||||
var rem = n - 10*quo;
|
||||
w--;
|
||||
quo := n/10;
|
||||
rem := n - 10*quo;
|
||||
w -= 1;
|
||||
if 0 <= w && w < len(a.digits) {
|
||||
a.digits[w] = u8('0' + rem);
|
||||
} else if rem != 0 {
|
||||
@@ -167,11 +167,9 @@ proc shift_left(a: ^Decimal, k: uint) {
|
||||
trim(a);
|
||||
}
|
||||
|
||||
proc shift(a: ^Decimal, k: int) {
|
||||
const (
|
||||
uint_size = 8*size_of(uint);
|
||||
max_shift = uint_size-4;
|
||||
)
|
||||
shift :: proc(a: ^Decimal, k: int) {
|
||||
uint_size :: 8*size_of(uint);
|
||||
max_shift :: uint_size-4;
|
||||
|
||||
match {
|
||||
case a.count == 0:
|
||||
@@ -193,17 +191,17 @@ proc shift(a: ^Decimal, k: int) {
|
||||
}
|
||||
}
|
||||
|
||||
proc can_round_up(a: ^Decimal, nd: int) -> bool {
|
||||
can_round_up :: proc(a: ^Decimal, nd: int) -> bool {
|
||||
if nd < 0 || nd >= a.count { return false ; }
|
||||
if a.digits[nd] == '5' && nd+1 == a.count {
|
||||
if a.trunc -> return true;
|
||||
if a.trunc do return true;
|
||||
return nd > 0 && (a.digits[nd-1]-'0')%2 != 0;
|
||||
}
|
||||
|
||||
return a.digits[nd] >= '5';
|
||||
}
|
||||
|
||||
proc round(a: ^Decimal, nd: int) {
|
||||
round :: proc(a: ^Decimal, nd: int) {
|
||||
if nd < 0 || nd >= a.count { return; }
|
||||
if can_round_up(a, nd) {
|
||||
round_up(a, nd);
|
||||
@@ -212,12 +210,12 @@ proc round(a: ^Decimal, nd: int) {
|
||||
}
|
||||
}
|
||||
|
||||
proc round_up(a: ^Decimal, nd: int) {
|
||||
round_up :: proc(a: ^Decimal, nd: int) {
|
||||
if nd < 0 || nd >= a.count { return; }
|
||||
|
||||
for var i = nd-1; i >= 0; i-- {
|
||||
if var c = a.digits[i]; c < '9' {
|
||||
a.digits[i]++;
|
||||
for i := nd-1; i >= 0; i -= 1 {
|
||||
if c := a.digits[i]; c < '9' {
|
||||
a.digits[i]+=1;
|
||||
a.count = i+1;
|
||||
return;
|
||||
}
|
||||
@@ -226,10 +224,10 @@ proc round_up(a: ^Decimal, nd: int) {
|
||||
// Number is just 9s
|
||||
a.digits[0] = '1';
|
||||
a.count = 1;
|
||||
a.decimal_point++;
|
||||
a.decimal_point+=1;
|
||||
}
|
||||
|
||||
proc round_down(a: ^Decimal, nd: int) {
|
||||
round_down :: proc(a: ^Decimal, nd: int) {
|
||||
if nd < 0 || nd >= a.count { return; }
|
||||
a.count = nd;
|
||||
trim(a);
|
||||
@@ -237,21 +235,21 @@ proc round_down(a: ^Decimal, nd: int) {
|
||||
|
||||
|
||||
// Extract integer part, rounded appropriately. There are no guarantees about overflow.
|
||||
proc rounded_integer(a: ^Decimal) -> u64 {
|
||||
rounded_integer :: proc(a: ^Decimal) -> u64 {
|
||||
if a.decimal_point > 20 {
|
||||
return 0xffff_ffff_ffff_ffff;
|
||||
}
|
||||
var i: int;
|
||||
var n: u64 = 0;
|
||||
var m = min(a.decimal_point, a.count);
|
||||
for i = 0; i < m; i++ {
|
||||
i: int = 0;
|
||||
n: u64 = 0;
|
||||
m := min(a.decimal_point, a.count);
|
||||
for ; i < m; i += 1 {
|
||||
n = n*10 + u64(a.digits[i]-'0');
|
||||
}
|
||||
for ; i < a.decimal_point; i++ {
|
||||
for ; i < a.decimal_point; i += 1 {
|
||||
n *= 10;
|
||||
}
|
||||
if can_round_up(a, a.decimal_point) {
|
||||
n++;
|
||||
n+=1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
+394
-383
File diff suppressed because it is too large
Load Diff
+46
-54
@@ -1,65 +1,63 @@
|
||||
proc crc32(data: []u8) -> u32 {
|
||||
var result = ~u32(0);
|
||||
import "mem.odin";
|
||||
|
||||
crc32 :: proc(data: []u8) -> u32 {
|
||||
result := ~u32(0);
|
||||
for b in data {
|
||||
result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff];
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
proc crc64(data: []u8) -> u64 {
|
||||
var result = ~u64(0);
|
||||
crc64 :: proc(data: []u8) -> u64 {
|
||||
result := ~u64(0);
|
||||
for b in data {
|
||||
result = result>>8 ~ _crc64_table[(result ~ u64(b)) & 0xff];
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
|
||||
proc fnv32(data: []u8) -> u32 {
|
||||
var h: u32 = 0x811c9dc5;
|
||||
fnv32 :: proc(data: []u8) -> u32 {
|
||||
h: u32 = 0x811c9dc5;
|
||||
for b in data {
|
||||
h = (h * 0x01000193) ~ u32(b);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
proc fnv64(data: []u8) -> u64 {
|
||||
var h: u64 = 0xcbf29ce484222325;
|
||||
fnv64 :: proc(data: []u8) -> u64 {
|
||||
h: u64 = 0xcbf29ce484222325;
|
||||
for b in data {
|
||||
h = (h * 0x100000001b3) ~ u64(b);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
proc fnv32a(data: []u8) -> u32 {
|
||||
var h: u32 = 0x811c9dc5;
|
||||
fnv32a :: proc(data: []u8) -> u32 {
|
||||
h: u32 = 0x811c9dc5;
|
||||
for b in data {
|
||||
h = (h ~ u32(b)) * 0x01000193;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
proc fnv64a(data: []u8) -> u64 {
|
||||
var h: u64 = 0xcbf29ce484222325;
|
||||
fnv64a :: proc(data: []u8) -> u64 {
|
||||
h: u64 = 0xcbf29ce484222325;
|
||||
for b in data {
|
||||
h = (h ~ u64(b)) * 0x100000001b3;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
proc murmur32(data: []u8) -> u32 {
|
||||
const (
|
||||
c1_32: u32 = 0xcc9e2d51;
|
||||
c2_32: u32 = 0x1b873593;
|
||||
)
|
||||
murmur32 :: proc(data: []u8) -> u32 {
|
||||
c1_32: u32 : 0xcc9e2d51;
|
||||
c2_32: u32 : 0x1b873593;
|
||||
|
||||
var (
|
||||
h1: u32 = 0;
|
||||
nblocks = len(data)/4;
|
||||
p = &data[0];
|
||||
p1 = p + 4*nblocks;
|
||||
)
|
||||
h1: u32 = 0;
|
||||
nblocks := len(data)/4;
|
||||
p := &data[0];
|
||||
p1 := p + 4*nblocks;
|
||||
|
||||
for ; p < p1; p += 4 {
|
||||
var k1 = ^u32(p)^;
|
||||
k1 := (cast(^u32)p)^;
|
||||
|
||||
k1 *= c1_32;
|
||||
k1 = (k1 << 15) | (k1 >> 17);
|
||||
@@ -70,8 +68,8 @@ proc murmur32(data: []u8) -> u32 {
|
||||
h1 = h1*5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
var tail = data[nblocks*4 ..];
|
||||
var k1: u32;
|
||||
tail := data[nblocks*4 ..];
|
||||
k1: u32;
|
||||
match len(tail)&3 {
|
||||
case 3:
|
||||
k1 ~= u32(tail[2]) << 16;
|
||||
@@ -98,20 +96,18 @@ proc murmur32(data: []u8) -> u32 {
|
||||
return h1;
|
||||
}
|
||||
|
||||
proc murmur64(data: []u8) -> u64 {
|
||||
const SEED = 0x9747b28c;
|
||||
murmur64 :: proc(data: []u8) -> u64 {
|
||||
SEED :: 0x9747b28c;
|
||||
|
||||
when size_of(int) == 8 {
|
||||
const (
|
||||
m = 0xc6a4a7935bd1e995;
|
||||
r = 47;
|
||||
)
|
||||
m :: 0xc6a4a7935bd1e995;
|
||||
r :: 47;
|
||||
|
||||
var h: u64 = SEED ~ (u64(len(data)) * m);
|
||||
var data64 = slice_ptr(^u64(&data[0]), len(data)/size_of(u64));
|
||||
h: u64 = SEED ~ (u64(len(data)) * m);
|
||||
data64 := mem.slice_ptr(cast(^u64)&data[0], len(data)/size_of(u64));
|
||||
|
||||
for _, i in data64 {
|
||||
var k = data64[i];
|
||||
k := data64[i];
|
||||
|
||||
k *= m;
|
||||
k ~= k>>r;
|
||||
@@ -139,22 +135,18 @@ proc murmur64(data: []u8) -> u64 {
|
||||
|
||||
return h;
|
||||
} else {
|
||||
const (
|
||||
m = 0x5bd1e995;
|
||||
r = 24;
|
||||
)
|
||||
m :: 0x5bd1e995;
|
||||
r :: 24;
|
||||
|
||||
var (
|
||||
h1 = u32(SEED) ~ u32(len(data));
|
||||
h2 = u32(SEED) >> 32;
|
||||
data32 = slice_ptr(^u32(&data[0]), len(data)/size_of(u32));
|
||||
len = len(data);
|
||||
i = 0;
|
||||
)
|
||||
h1 := u32(SEED) ~ u32(len(data));
|
||||
h2 := u32(SEED) >> 32;
|
||||
data32 := mem.slice_ptr(cast(^u32)&data[0], len(data)/size_of(u32));
|
||||
len := len(data);
|
||||
i := 0;
|
||||
|
||||
for len >= 8 {
|
||||
var k1, k2: u32;
|
||||
k1 = data32[i]; i++;
|
||||
k1, k2: u32;
|
||||
k1 = data32[i]; i += 1;
|
||||
k1 *= m;
|
||||
k1 ~= k1>>r;
|
||||
k1 *= m;
|
||||
@@ -162,7 +154,7 @@ proc murmur64(data: []u8) -> u64 {
|
||||
h1 ~= k1;
|
||||
len -= 4;
|
||||
|
||||
k2 = data32[i]; i++;
|
||||
k2 = data32[i]; i += 1;
|
||||
k2 *= m;
|
||||
k2 ~= k2>>r;
|
||||
k2 *= m;
|
||||
@@ -172,8 +164,8 @@ proc murmur64(data: []u8) -> u64 {
|
||||
}
|
||||
|
||||
if len >= 4 {
|
||||
var k1: u32;
|
||||
k1 = data32[i]; i++;
|
||||
k1: u32;
|
||||
k1 = data32[i]; i += 1;
|
||||
k1 *= m;
|
||||
k1 ~= k1>>r;
|
||||
k1 *= m;
|
||||
@@ -183,7 +175,7 @@ proc murmur64(data: []u8) -> u64 {
|
||||
}
|
||||
|
||||
// TODO(bill): Fix this
|
||||
#no_bounds_check var data8 = slice_to_bytes(data32[i..])[0..<3];
|
||||
#no_bounds_check data8 := slice_to_bytes(data32[i..])[..3];
|
||||
match len {
|
||||
case 3:
|
||||
h2 ~= u32(data8[2]) << 16;
|
||||
@@ -210,7 +202,7 @@ proc murmur64(data: []u8) -> u64 {
|
||||
}
|
||||
|
||||
|
||||
var _crc32_table = [256]u32{
|
||||
_crc32_table := [256]u32{
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
@@ -276,7 +268,7 @@ var _crc32_table = [256]u32{
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
|
||||
};
|
||||
var _crc64_table = [256]u64{
|
||||
_crc64_table := [256]u64{
|
||||
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
|
||||
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
|
||||
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
|
||||
|
||||
+163
-180
@@ -1,97 +1,94 @@
|
||||
const (
|
||||
TAU = 6.28318530717958647692528676655900576;
|
||||
PI = 3.14159265358979323846264338327950288;
|
||||
ONE_OVER_TAU = 0.636619772367581343075535053490057448;
|
||||
ONE_OVER_PI = 0.159154943091895335768883763372514362;
|
||||
TAU :: 6.28318530717958647692528676655900576;
|
||||
PI :: 3.14159265358979323846264338327950288;
|
||||
ONE_OVER_TAU :: 0.636619772367581343075535053490057448;
|
||||
ONE_OVER_PI :: 0.159154943091895335768883763372514362;
|
||||
|
||||
E = 2.71828182845904523536;
|
||||
SQRT_TWO = 1.41421356237309504880168872420969808;
|
||||
SQRT_THREE = 1.73205080756887729352744634150587236;
|
||||
SQRT_FIVE = 2.23606797749978969640917366873127623;
|
||||
E :: 2.71828182845904523536;
|
||||
SQRT_TWO :: 1.41421356237309504880168872420969808;
|
||||
SQRT_THREE :: 1.73205080756887729352744634150587236;
|
||||
SQRT_FIVE :: 2.23606797749978969640917366873127623;
|
||||
|
||||
LOG_TWO = 0.693147180559945309417232121458176568;
|
||||
LOG_TEN = 2.30258509299404568401799145468436421;
|
||||
LOG_TWO :: 0.693147180559945309417232121458176568;
|
||||
LOG_TEN :: 2.30258509299404568401799145468436421;
|
||||
|
||||
EPSILON = 1.19209290e-7;
|
||||
EPSILON :: 1.19209290e-7;
|
||||
|
||||
τ = TAU;
|
||||
π = PI;
|
||||
)
|
||||
type (
|
||||
Vec2 [vector 2]f32;
|
||||
Vec3 [vector 3]f32;
|
||||
Vec4 [vector 4]f32;
|
||||
τ :: TAU;
|
||||
π :: PI;
|
||||
|
||||
// Column major
|
||||
Mat2 [2][2]f32;
|
||||
Mat3 [3][3]f32;
|
||||
Mat4 [4][4]f32;
|
||||
Vec2 :: [vector 2]f32;
|
||||
Vec3 :: [vector 3]f32;
|
||||
Vec4 :: [vector 4]f32;
|
||||
|
||||
Complex complex64;
|
||||
)
|
||||
// Column major
|
||||
Mat2 :: [2][2]f32;
|
||||
Mat3 :: [3][3]f32;
|
||||
Mat4 :: [4][4]f32;
|
||||
|
||||
Complex :: complex64;
|
||||
|
||||
foreign __llvm_core {
|
||||
proc sqrt(x: f32) -> f32 #link_name "llvm.sqrt.f32";
|
||||
proc sqrt(x: f64) -> f64 #link_name "llvm.sqrt.f64";
|
||||
sqrt :: proc(x: f32) -> f32 #link_name "llvm.sqrt.f32" ---;
|
||||
sqrt :: proc(x: f64) -> f64 #link_name "llvm.sqrt.f64" ---;
|
||||
|
||||
proc sin (θ: f32) -> f32 #link_name "llvm.sin.f32";
|
||||
proc sin (θ: f64) -> f64 #link_name "llvm.sin.f64";
|
||||
sin :: proc(θ: f32) -> f32 #link_name "llvm.sin.f32" ---;
|
||||
sin :: proc(θ: f64) -> f64 #link_name "llvm.sin.f64" ---;
|
||||
|
||||
proc cos (θ: f32) -> f32 #link_name "llvm.cos.f32";
|
||||
proc cos (θ: f64) -> f64 #link_name "llvm.cos.f64";
|
||||
cos :: proc(θ: f32) -> f32 #link_name "llvm.cos.f32" ---;
|
||||
cos :: proc(θ: f64) -> f64 #link_name "llvm.cos.f64" ---;
|
||||
|
||||
proc pow (x, power: f32) -> f32 #link_name "llvm.pow.f32";
|
||||
proc pow (x, power: f64) -> f64 #link_name "llvm.pow.f64";
|
||||
pow :: proc(x, power: f32) -> f32 #link_name "llvm.pow.f32" ---;
|
||||
pow :: proc(x, power: f64) -> f64 #link_name "llvm.pow.f64" ---;
|
||||
|
||||
proc fmuladd(a, b, c: f32) -> f32 #link_name "llvm.fmuladd.f32";
|
||||
proc fmuladd(a, b, c: f64) -> f64 #link_name "llvm.fmuladd.f64";
|
||||
fmuladd :: proc(a, b, c: f32) -> f32 #link_name "llvm.fmuladd.f32" ---;
|
||||
fmuladd :: proc(a, b, c: f64) -> f64 #link_name "llvm.fmuladd.f64" ---;
|
||||
}
|
||||
|
||||
proc tan (θ: f32) -> f32 #inline { return sin(θ)/cos(θ); }
|
||||
proc tan (θ: f64) -> f64 #inline { return sin(θ)/cos(θ); }
|
||||
tan :: proc(θ: f32) -> f32 #inline do return sin(θ)/cos(θ);
|
||||
tan :: proc(θ: f64) -> f64 #inline do return sin(θ)/cos(θ);
|
||||
|
||||
|
||||
proc lerp (a, b, t: f32) -> (x: f32) { return a*(1-t) + b*t; }
|
||||
proc lerp (a, b, t: f64) -> (x: f64) { return a*(1-t) + b*t; }
|
||||
proc unlerp(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); }
|
||||
proc unlerp(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); }
|
||||
lerp :: proc(a, b, t: f32) -> (x: f32) do return a*(1-t) + b*t;
|
||||
lerp :: proc(a, b, t: f64) -> (x: f64) do return a*(1-t) + b*t;
|
||||
unlerp :: proc(a, b, x: f32) -> (t: f32) do return (x-a)/(b-a);
|
||||
unlerp :: proc(a, b, x: f64) -> (t: f64) do return (x-a)/(b-a);
|
||||
|
||||
|
||||
proc sign(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
|
||||
proc sign(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
|
||||
sign :: proc(x: f32) -> f32 { if x >= 0 do return +1; return -1; }
|
||||
sign :: proc(x: f64) -> f64 { if x >= 0 do return +1; return -1; }
|
||||
|
||||
|
||||
|
||||
proc copy_sign(x, y: f32) -> f32 {
|
||||
var ix = transmute(u32, x);
|
||||
var iy = transmute(u32, y);
|
||||
copy_sign :: proc(x, y: f32) -> f32 {
|
||||
ix := transmute(u32)x;
|
||||
iy := transmute(u32)y;
|
||||
ix &= 0x7fff_ffff;
|
||||
ix |= iy & 0x8000_0000;
|
||||
return transmute(f32, ix);
|
||||
return transmute(f32)ix;
|
||||
}
|
||||
|
||||
proc copy_sign(x, y: f64) -> f64 {
|
||||
var ix = transmute(u64, x);
|
||||
var iy = transmute(u64, y);
|
||||
copy_sign :: proc(x, y: f64) -> f64 {
|
||||
ix := transmute(u64)x;
|
||||
iy := transmute(u64)y;
|
||||
ix &= 0x7fff_ffff_ffff_ff;
|
||||
ix |= iy & 0x8000_0000_0000_0000;
|
||||
return transmute(f64, ix);
|
||||
return transmute(f64)ix;
|
||||
}
|
||||
|
||||
proc round (x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||
proc round (x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||
round :: proc(x: f32) -> f32 { if x >= 0 do return floor(x + 0.5); return ceil(x - 0.5); }
|
||||
round :: proc(x: f64) -> f64 { if x >= 0 do return floor(x + 0.5); return ceil(x - 0.5); }
|
||||
|
||||
proc floor (x: f32) -> f32 { return x >= 0 ? f32(i64(x)) : f32(i64(x-0.5)); } // TODO: Get accurate versions
|
||||
proc floor (x: f64) -> f64 { return x >= 0 ? f64(i64(x)) : f64(i64(x-0.5)); } // TODO: Get accurate versions
|
||||
floor :: proc(x: f32) -> f32 { if x >= 0 do return f32(i64(x)); return f32(i64(x-0.5)); } // TODO: Get accurate versions
|
||||
floor :: proc(x: f64) -> f64 { if x >= 0 do return f64(i64(x)); return f64(i64(x-0.5)); } // TODO: Get accurate versions
|
||||
|
||||
proc ceil (x: f32) -> f32 { return x < 0 ? f32(i64(x)) : f32(i64(x+1)); } // TODO: Get accurate versions
|
||||
proc ceil (x: f64) -> f64 { return x < 0 ? f64(i64(x)) : f64(i64(x+1)); } // TODO: Get accurate versions
|
||||
ceil :: proc(x: f32) -> f32 { if x < 0 do return f32(i64(x)); return f32(i64(x+1)); }// TODO: Get accurate versions
|
||||
ceil :: proc(x: f64) -> f64 { if x < 0 do return f64(i64(x)); return f64(i64(x+1)); }// TODO: Get accurate versions
|
||||
|
||||
proc remainder(x, y: f32) -> f32 { return x - round(x/y) * y; }
|
||||
proc remainder(x, y: f64) -> f64 { return x - round(x/y) * y; }
|
||||
remainder :: proc(x, y: f32) -> f32 do return x - round(x/y) * y;
|
||||
remainder :: proc(x, y: f64) -> f64 do return x - round(x/y) * y;
|
||||
|
||||
proc mod(x, y: f32) -> f32 {
|
||||
var result: f32;
|
||||
mod :: proc(x, y: f32) -> f32 {
|
||||
result: f32;
|
||||
y = abs(y);
|
||||
result = remainder(abs(x), y);
|
||||
if sign(result) < 0 {
|
||||
@@ -99,8 +96,8 @@ proc mod(x, y: f32) -> f32 {
|
||||
}
|
||||
return copy_sign(result, x);
|
||||
}
|
||||
proc mod(x, y: f64) -> f64 {
|
||||
var result: f64;
|
||||
mod :: proc(x, y: f64) -> f64 {
|
||||
result: f64;
|
||||
y = abs(y);
|
||||
result = remainder(abs(x), y);
|
||||
if sign(result) < 0 {
|
||||
@@ -110,57 +107,51 @@ proc mod(x, y: f64) -> f64 {
|
||||
}
|
||||
|
||||
|
||||
proc to_radians(degrees: f32) -> f32 { return degrees * TAU / 360; }
|
||||
proc to_degrees(radians: f32) -> f32 { return radians * 360 / TAU; }
|
||||
to_radians :: proc(degrees: f32) -> f32 do return degrees * TAU / 360;
|
||||
to_degrees :: proc(radians: f32) -> f32 do return radians * 360 / TAU;
|
||||
|
||||
|
||||
|
||||
proc dot(a, b: Vec2) -> f32 { var c = a*b; return c.x + c.y; }
|
||||
proc dot(a, b: Vec3) -> f32 { var c = a*b; return c.x + c.y + c.z; }
|
||||
proc dot(a, b: Vec4) -> f32 { var c = a*b; return c.x + c.y + c.z + c.w; }
|
||||
dot :: proc(a, b: $T/[vector 2]$E) -> E { c := a*b; return c.x + c.y; }
|
||||
dot :: proc(a, b: $T/[vector 3]$E) -> E { c := a*b; return c.x + c.y + c.z; }
|
||||
dot :: proc(a, b: $T/[vector 4]$E) -> E { c := a*b; return c.x + c.y + c.z + c.w; }
|
||||
|
||||
proc cross(x, y: Vec3) -> Vec3 {
|
||||
var a = swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
|
||||
var b = swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
|
||||
return a - b;
|
||||
cross :: proc(x, y: $T/[vector 3]$E) -> T {
|
||||
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
|
||||
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
|
||||
return T(a - b);
|
||||
}
|
||||
|
||||
|
||||
proc mag(v: Vec2) -> f32 { return sqrt(dot(v, v)); }
|
||||
proc mag(v: Vec3) -> f32 { return sqrt(dot(v, v)); }
|
||||
proc mag(v: Vec4) -> f32 { return sqrt(dot(v, v)); }
|
||||
mag :: proc(v: $T/[vector 2]$E) -> E do return sqrt(dot(v, v));
|
||||
mag :: proc(v: $T/[vector 3]$E) -> E do return sqrt(dot(v, v));
|
||||
mag :: proc(v: $T/[vector 4]$E) -> E do return sqrt(dot(v, v));
|
||||
|
||||
proc norm(v: Vec2) -> Vec2 { return v / mag(v); }
|
||||
proc norm(v: Vec3) -> Vec3 { return v / mag(v); }
|
||||
proc norm(v: Vec4) -> Vec4 { return v / mag(v); }
|
||||
norm :: proc(v: $T/[vector 2]$E) -> T do return v / mag(v);
|
||||
norm :: proc(v: $T/[vector 3]$E) -> T do return v / mag(v);
|
||||
norm :: proc(v: $T/[vector 4]$E) -> T do return v / mag(v);
|
||||
|
||||
proc norm0(v: Vec2) -> Vec2 {
|
||||
var m = mag(v);
|
||||
if m == 0 {
|
||||
return 0;
|
||||
}
|
||||
return v / m;
|
||||
norm0 :: proc(v: $T/[vector 2]$E) -> T {
|
||||
m := mag(v);
|
||||
if m == 0 do return 0;
|
||||
return v/m;
|
||||
}
|
||||
|
||||
proc norm0(v: Vec3) -> Vec3 {
|
||||
var m = mag(v);
|
||||
if m == 0 {
|
||||
return 0;
|
||||
}
|
||||
return v / m;
|
||||
norm0 :: proc(v: $T/[vector 3]$E) -> T {
|
||||
m := mag(v);
|
||||
if m == 0 do return 0;
|
||||
return v/m;
|
||||
}
|
||||
|
||||
proc norm0(v: Vec4) -> Vec4 {
|
||||
var m = mag(v);
|
||||
if m == 0 {
|
||||
return 0;
|
||||
}
|
||||
return v / m;
|
||||
norm0 :: proc(v: $T/[vector 4]$E) -> T {
|
||||
m := mag(v);
|
||||
if m == 0 do return 0;
|
||||
return v/m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
proc mat4_identity() -> Mat4 {
|
||||
mat4_identity :: proc() -> Mat4 {
|
||||
return Mat4{
|
||||
{1, 0, 0, 0},
|
||||
{0, 1, 0, 0},
|
||||
@@ -169,19 +160,19 @@ proc mat4_identity() -> Mat4 {
|
||||
};
|
||||
}
|
||||
|
||||
proc mat4_transpose(m: Mat4) -> Mat4 {
|
||||
for j in 0..<4 {
|
||||
for i in 0..<4 {
|
||||
mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
||||
for j in 0..4 {
|
||||
for i in 0..4 {
|
||||
m[i][j], m[j][i] = m[j][i], m[i][j];
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
proc mul(a, b: Mat4) -> Mat4 {
|
||||
var c: Mat4;
|
||||
for j in 0..<4 {
|
||||
for i in 0..<4 {
|
||||
mul :: proc(a, b: Mat4) -> Mat4 {
|
||||
c: Mat4;
|
||||
for j in 0..4 {
|
||||
for i in 0..4 {
|
||||
c[j][i] = a[0][i]*b[j][0] +
|
||||
a[1][i]*b[j][1] +
|
||||
a[2][i]*b[j][2] +
|
||||
@@ -191,7 +182,7 @@ proc mul(a, b: Mat4) -> Mat4 {
|
||||
return c;
|
||||
}
|
||||
|
||||
proc mul(m: Mat4, v: Vec4) -> Vec4 {
|
||||
mul :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||
return Vec4{
|
||||
m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
|
||||
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
|
||||
@@ -200,30 +191,29 @@ proc mul(m: Mat4, v: Vec4) -> Vec4 {
|
||||
};
|
||||
}
|
||||
|
||||
proc inverse(m: Mat4) -> Mat4 {
|
||||
var o: Mat4;
|
||||
inverse :: proc(m: Mat4) -> Mat4 {
|
||||
o: Mat4;
|
||||
|
||||
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
|
||||
sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3];
|
||||
sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2];
|
||||
sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3];
|
||||
sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2];
|
||||
sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1];
|
||||
sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3];
|
||||
sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||
sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2];
|
||||
sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3];
|
||||
sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2];
|
||||
sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||
sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1];
|
||||
sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3];
|
||||
sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3];
|
||||
sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2];
|
||||
sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3];
|
||||
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2];
|
||||
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1];
|
||||
|
||||
var (
|
||||
sf00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
|
||||
sf01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
|
||||
sf02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
|
||||
sf03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
|
||||
sf04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
|
||||
sf05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
|
||||
sf06 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
|
||||
sf07 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||
sf08 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
|
||||
sf09 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
|
||||
sf10 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
|
||||
sf11 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||
sf12 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
|
||||
sf13 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
|
||||
sf14 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
|
||||
sf15 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
|
||||
sf16 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
|
||||
sf17 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
|
||||
sf18 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
|
||||
)
|
||||
|
||||
o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02);
|
||||
o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04);
|
||||
@@ -245,7 +235,7 @@ proc inverse(m: Mat4) -> Mat4 {
|
||||
o[3][2] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18);
|
||||
o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18);
|
||||
|
||||
var ood = 1.0 / (m[0][0] * o[0][0] +
|
||||
ood := 1.0 / (m[0][0] * o[0][0] +
|
||||
m[0][1] * o[0][1] +
|
||||
m[0][2] * o[0][2] +
|
||||
m[0][3] * o[0][3]);
|
||||
@@ -271,8 +261,8 @@ proc inverse(m: Mat4) -> Mat4 {
|
||||
}
|
||||
|
||||
|
||||
proc mat4_translate(v: Vec3) -> Mat4 {
|
||||
var m = mat4_identity();
|
||||
mat4_translate :: proc(v: Vec3) -> Mat4 {
|
||||
m := mat4_identity();
|
||||
m[3][0] = v.x;
|
||||
m[3][1] = v.y;
|
||||
m[3][2] = v.z;
|
||||
@@ -280,16 +270,14 @@ proc mat4_translate(v: Vec3) -> Mat4 {
|
||||
return m;
|
||||
}
|
||||
|
||||
proc mat4_rotate(v: Vec3, angle_radians: f32) -> Mat4 {
|
||||
var (
|
||||
c = cos(angle_radians);
|
||||
s = sin(angle_radians);
|
||||
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
||||
c := cos(angle_radians);
|
||||
s := sin(angle_radians);
|
||||
|
||||
a = norm(v);
|
||||
t = a * (1-c);
|
||||
a := norm(v);
|
||||
t := a * (1-c);
|
||||
|
||||
rot = mat4_identity();
|
||||
)
|
||||
rot := mat4_identity();
|
||||
|
||||
rot[0][0] = c + t.x*a.x;
|
||||
rot[0][1] = 0 + t.x*a.y + s*a.z;
|
||||
@@ -309,14 +297,14 @@ proc mat4_rotate(v: Vec3, angle_radians: f32) -> Mat4 {
|
||||
return rot;
|
||||
}
|
||||
|
||||
proc scale(m: Mat4, v: Vec3) -> Mat4 {
|
||||
scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
||||
m[0][0] *= v.x;
|
||||
m[1][1] *= v.y;
|
||||
m[2][2] *= v.z;
|
||||
return m;
|
||||
}
|
||||
|
||||
proc scale(m: Mat4, s: f32) -> Mat4 {
|
||||
scale :: proc(m: Mat4, s: f32) -> Mat4 {
|
||||
m[0][0] *= s;
|
||||
m[1][1] *= s;
|
||||
m[2][2] *= s;
|
||||
@@ -324,12 +312,10 @@ proc scale(m: Mat4, s: f32) -> Mat4 {
|
||||
}
|
||||
|
||||
|
||||
proc look_at(eye, centre, up: Vec3) -> Mat4 {
|
||||
var (
|
||||
f = norm(centre - eye);
|
||||
s = norm(cross(f, up));
|
||||
u = cross(s, f);
|
||||
)
|
||||
look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
||||
f := norm(centre - eye);
|
||||
s := norm(cross(f, up));
|
||||
u := cross(s, f);
|
||||
|
||||
return Mat4{
|
||||
{+s.x, +u.x, -f.x, 0},
|
||||
@@ -339,11 +325,10 @@ proc look_at(eye, centre, up: Vec3) -> Mat4 {
|
||||
};
|
||||
}
|
||||
|
||||
proc perspective(fovy, aspect, near, far: f32) -> Mat4 {
|
||||
var (
|
||||
m: Mat4;
|
||||
tan_half_fovy = tan(0.5 * fovy);
|
||||
)
|
||||
perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
||||
m: Mat4;
|
||||
tan_half_fovy := tan(0.5 * fovy);
|
||||
|
||||
m[0][0] = 1.0 / (aspect*tan_half_fovy);
|
||||
m[1][1] = 1.0 / (tan_half_fovy);
|
||||
m[2][2] = -(far + near) / (far - near);
|
||||
@@ -353,8 +338,8 @@ proc perspective(fovy, aspect, near, far: f32) -> Mat4 {
|
||||
}
|
||||
|
||||
|
||||
proc ortho3d(left, right, bottom, top, near, far: f32) -> Mat4 {
|
||||
var m = mat4_identity();
|
||||
ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
|
||||
m := mat4_identity();
|
||||
m[0][0] = +2.0 / (right - left);
|
||||
m[1][1] = +2.0 / (top - bottom);
|
||||
m[2][2] = -2.0 / (far - near);
|
||||
@@ -367,30 +352,28 @@ proc ortho3d(left, right, bottom, top, near, far: f32) -> Mat4 {
|
||||
|
||||
|
||||
|
||||
const (
|
||||
F32_DIG = 6;
|
||||
F32_EPSILON = 1.192092896e-07;
|
||||
F32_GUARD = 0;
|
||||
F32_MANT_DIG = 24;
|
||||
F32_MAX = 3.402823466e+38;
|
||||
F32_MAX_10_EXP = 38;
|
||||
F32_MAX_EXP = 128;
|
||||
F32_MIN = 1.175494351e-38;
|
||||
F32_MIN_10_EXP = -37;
|
||||
F32_MIN_EXP = -125;
|
||||
F32_NORMALIZE = 0;
|
||||
F32_RADIX = 2;
|
||||
F32_ROUNDS = 1;
|
||||
F32_DIG :: 6;
|
||||
F32_EPSILON :: 1.192092896e-07;
|
||||
F32_GUARD :: 0;
|
||||
F32_MANT_DIG :: 24;
|
||||
F32_MAX :: 3.402823466e+38;
|
||||
F32_MAX_10_EXP :: 38;
|
||||
F32_MAX_EXP :: 128;
|
||||
F32_MIN :: 1.175494351e-38;
|
||||
F32_MIN_10_EXP :: -37;
|
||||
F32_MIN_EXP :: -125;
|
||||
F32_NORMALIZE :: 0;
|
||||
F32_RADIX :: 2;
|
||||
F32_ROUNDS :: 1;
|
||||
|
||||
F64_DIG = 15; // # of decimal digits of precision
|
||||
F64_EPSILON = 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0
|
||||
F64_MANT_DIG = 53; // # of bits in mantissa
|
||||
F64_MAX = 1.7976931348623158e+308; // max value
|
||||
F64_MAX_10_EXP = 308; // max decimal exponent
|
||||
F64_MAX_EXP = 1024; // max binary exponent
|
||||
F64_MIN = 2.2250738585072014e-308; // min positive value
|
||||
F64_MIN_10_EXP = -307; // min decimal exponent
|
||||
F64_MIN_EXP = -1021; // min binary exponent
|
||||
F64_RADIX = 2; // exponent radix
|
||||
F64_ROUNDS = 1; // addition rounding: near
|
||||
)
|
||||
F64_DIG :: 15; // # of decimal digits of precision
|
||||
F64_EPSILON :: 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0
|
||||
F64_MANT_DIG :: 53; // # of bits in mantissa
|
||||
F64_MAX :: 1.7976931348623158e+308; // max value
|
||||
F64_MAX_10_EXP :: 308; // max decimal exponent
|
||||
F64_MAX_EXP :: 1024; // max binary exponent
|
||||
F64_MIN :: 2.2250738585072014e-308; // min positive value
|
||||
F64_MIN_10_EXP :: -307; // min decimal exponent
|
||||
F64_MIN_EXP :: -1021; // min binary exponent
|
||||
F64_RADIX :: 2; // exponent radix
|
||||
F64_ROUNDS :: 1; // addition rounding: near
|
||||
|
||||
+118
-112
@@ -1,78 +1,90 @@
|
||||
import (
|
||||
"fmt.odin";
|
||||
"os.odin";
|
||||
"raw.odin";
|
||||
)
|
||||
foreign __llvm_core {
|
||||
proc swap(b: u16) -> u16 #link_name "llvm.bswap.i16";
|
||||
proc swap(b: u32) -> u32 #link_name "llvm.bswap.i32";
|
||||
proc swap(b: u64) -> u64 #link_name "llvm.bswap.i64";
|
||||
swap :: proc(b: u16) -> u16 #link_name "llvm.bswap.i16" ---;
|
||||
swap :: proc(b: u32) -> u32 #link_name "llvm.bswap.i32" ---;
|
||||
swap :: proc(b: u64) -> u64 #link_name "llvm.bswap.i64" ---;
|
||||
}
|
||||
|
||||
proc set(data: rawptr, value: i32, len: int) -> rawptr {
|
||||
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #cc_contextless {
|
||||
return __mem_set(data, value, len);
|
||||
}
|
||||
proc zero(data: rawptr, len: int) -> rawptr {
|
||||
zero :: proc(data: rawptr, len: int) -> rawptr #cc_contextless {
|
||||
return __mem_zero(data, len);
|
||||
}
|
||||
proc copy(dst, src: rawptr, len: int) -> rawptr {
|
||||
copy :: proc(dst, src: rawptr, len: int) -> rawptr #cc_contextless {
|
||||
return __mem_copy(dst, src, len);
|
||||
}
|
||||
proc copy_non_overlapping(dst, src: rawptr, len: int) -> rawptr {
|
||||
copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #cc_contextless {
|
||||
return __mem_copy_non_overlapping(dst, src, len);
|
||||
}
|
||||
proc compare(a, b: []u8) -> int {
|
||||
compare :: proc(a, b: []u8) -> int #cc_contextless {
|
||||
return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
|
||||
}
|
||||
|
||||
|
||||
slice_ptr :: proc(ptr: ^$T, len: int) -> []T #cc_contextless {
|
||||
assert(len >= 0);
|
||||
slice := raw.Slice{data = ptr, len = len, cap = len};
|
||||
return (cast(^[]T)&slice)^;
|
||||
}
|
||||
slice_ptr :: proc(ptr: ^$T, len, cap: int) -> []T #cc_contextless {
|
||||
assert(0 <= len && len <= cap);
|
||||
slice := raw.Slice{data = ptr, len = len, cap = cap};
|
||||
return (cast(^[]T)&slice)^;
|
||||
}
|
||||
|
||||
proc kilobytes(x: int) -> int #inline { return (x) * 1024; }
|
||||
proc megabytes(x: int) -> int #inline { return kilobytes(x) * 1024; }
|
||||
proc gigabytes(x: int) -> int #inline { return megabytes(x) * 1024; }
|
||||
proc terabytes(x: int) -> int #inline { return gigabytes(x) * 1024; }
|
||||
slice_to_bytes :: proc(slice: []$T) -> []u8 #cc_contextless {
|
||||
s := cast(^raw.Slice)&slice;
|
||||
s.len *= size_of(T);
|
||||
s.cap *= size_of(T);
|
||||
return (cast(^[]u8)s)^;
|
||||
}
|
||||
|
||||
proc is_power_of_two(x: int) -> bool {
|
||||
if x <= 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
kilobytes :: proc(x: int) -> int #inline #cc_contextless { return (x) * 1024; }
|
||||
megabytes :: proc(x: int) -> int #inline #cc_contextless { return kilobytes(x) * 1024; }
|
||||
gigabytes :: proc(x: int) -> int #inline #cc_contextless { return megabytes(x) * 1024; }
|
||||
terabytes :: proc(x: int) -> int #inline #cc_contextless { return gigabytes(x) * 1024; }
|
||||
|
||||
is_power_of_two :: proc(x: int) -> bool {
|
||||
if x <= 0 do return false;
|
||||
return (x & (x-1)) == 0;
|
||||
}
|
||||
|
||||
proc align_forward(ptr: rawptr, align: int) -> rawptr {
|
||||
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
|
||||
assert(is_power_of_two(align));
|
||||
|
||||
var a = uint(align);
|
||||
var p = uint(ptr);
|
||||
var modulo = p & (a-1);
|
||||
if modulo != 0 {
|
||||
p += a - modulo;
|
||||
}
|
||||
a := uint(align);
|
||||
p := uint(ptr);
|
||||
modulo := p & (a-1);
|
||||
if modulo != 0 do p += a - modulo;
|
||||
return rawptr(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
type AllocationHeader struct {
|
||||
size: int,
|
||||
AllocationHeader :: struct {
|
||||
size: int;
|
||||
}
|
||||
|
||||
proc allocation_header_fill(header: ^AllocationHeader, data: rawptr, size: int) {
|
||||
allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) {
|
||||
header.size = size;
|
||||
var ptr = ^int(header+1);
|
||||
ptr := cast(^uint)(header+1);
|
||||
n := cast(^uint)data - ptr;
|
||||
|
||||
for var i = 0; rawptr(ptr) < data; i++ {
|
||||
(ptr+i)^ = -1;
|
||||
for i in 0..n {
|
||||
(ptr+i)^ = ~uint(0);
|
||||
}
|
||||
}
|
||||
proc allocation_header(data: rawptr) -> ^AllocationHeader {
|
||||
if data == nil {
|
||||
return nil;
|
||||
}
|
||||
var p = ^int(data);
|
||||
for (p-1)^ == -1 {
|
||||
p = (p-1);
|
||||
}
|
||||
return ^AllocationHeader(p-1);
|
||||
allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
||||
if data == nil do return nil;
|
||||
p := cast(^uint)data;
|
||||
for (p-1)^ == ~uint(0) do p = (p-1);
|
||||
return cast(^AllocationHeader)(p-1);
|
||||
}
|
||||
|
||||
|
||||
@@ -80,36 +92,36 @@ proc allocation_header(data: rawptr) -> ^AllocationHeader {
|
||||
|
||||
|
||||
// Custom allocators
|
||||
type (
|
||||
Arena struct {
|
||||
backing: Allocator,
|
||||
offset: int,
|
||||
memory: []u8,
|
||||
temp_count: int,
|
||||
}
|
||||
|
||||
ArenaTempMemory struct {
|
||||
arena: ^Arena,
|
||||
original_count: int,
|
||||
}
|
||||
)
|
||||
Arena :: struct {
|
||||
backing: Allocator;
|
||||
offset: int;
|
||||
memory: []u8;
|
||||
temp_count: int;
|
||||
}
|
||||
|
||||
ArenaTempMemory :: struct {
|
||||
arena: ^Arena;
|
||||
original_count: int;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
proc init_arena_from_memory(using a: ^Arena, data: []u8) {
|
||||
|
||||
init_arena_from_memory :: proc(using a: ^Arena, data: []u8) {
|
||||
backing = Allocator{};
|
||||
memory = data[0..<0];
|
||||
memory = data[..0];
|
||||
temp_count = 0;
|
||||
}
|
||||
|
||||
proc init_arena_from_context(using a: ^Arena, size: int) {
|
||||
init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
||||
backing = context.allocator;
|
||||
memory = make([]u8, size);
|
||||
temp_count = 0;
|
||||
}
|
||||
|
||||
proc free_arena(using a: ^Arena) {
|
||||
destroy_arena :: proc(using a: ^Arena) {
|
||||
if backing.procedure != nil {
|
||||
push_allocator backing {
|
||||
free(memory);
|
||||
@@ -119,31 +131,31 @@ proc free_arena(using a: ^Arena) {
|
||||
}
|
||||
}
|
||||
|
||||
proc arena_allocator(arena: ^Arena) -> Allocator {
|
||||
arena_allocator :: proc(arena: ^Arena) -> Allocator {
|
||||
return Allocator{
|
||||
procedure = arena_allocator_proc,
|
||||
data = arena,
|
||||
};
|
||||
}
|
||||
|
||||
proc arena_allocator_proc(allocator_data: rawptr, mode: AllocatorMode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||
using AllocatorMode;
|
||||
var arena = ^Arena(allocator_data);
|
||||
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||
using Allocator.Mode;
|
||||
arena := cast(^Arena)allocator_data;
|
||||
|
||||
match mode {
|
||||
case Alloc:
|
||||
var total_size = size + alignment;
|
||||
total_size := size + alignment;
|
||||
|
||||
if arena.offset + total_size > len(arena.memory) {
|
||||
fmt.fprintln(os.stderr, "Arena out of memory");
|
||||
return nil;
|
||||
}
|
||||
|
||||
#no_bounds_check var end = &arena.memory[arena.offset];
|
||||
#no_bounds_check end := &arena.memory[arena.offset];
|
||||
|
||||
var ptr = align_forward(end, alignment);
|
||||
ptr := align_forward(end, alignment);
|
||||
arena.offset += total_size;
|
||||
return zero(ptr, size);
|
||||
|
||||
@@ -161,19 +173,19 @@ proc arena_allocator_proc(allocator_data: rawptr, mode: AllocatorMode,
|
||||
return nil;
|
||||
}
|
||||
|
||||
proc begin_arena_temp_memory(a: ^Arena) -> ArenaTempMemory {
|
||||
var tmp: ArenaTempMemory;
|
||||
begin_arena_temp_memory :: proc(a: ^Arena) -> ArenaTempMemory {
|
||||
tmp: ArenaTempMemory;
|
||||
tmp.arena = a;
|
||||
tmp.original_count = len(a.memory);
|
||||
a.temp_count++;
|
||||
a.temp_count += 1;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
proc end_arena_temp_memory(using tmp: ArenaTempMemory) {
|
||||
end_arena_temp_memory :: proc(using tmp: ArenaTempMemory) {
|
||||
assert(len(arena.memory) >= original_count);
|
||||
assert(arena.temp_count > 0);
|
||||
arena.memory = arena.memory[0..<original_count];
|
||||
arena.temp_count--;
|
||||
arena.memory = arena.memory[..original_count];
|
||||
arena.temp_count -= 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -182,11 +194,9 @@ proc end_arena_temp_memory(using tmp: ArenaTempMemory) {
|
||||
|
||||
|
||||
|
||||
proc align_of_type_info(type_info: ^TypeInfo) -> int {
|
||||
proc prev_pow2(n: i64) -> i64 {
|
||||
if n <= 0 {
|
||||
return 0;
|
||||
}
|
||||
align_of_type_info :: proc(type_info: ^TypeInfo) -> int {
|
||||
prev_pow2 :: proc(n: i64) -> i64 {
|
||||
if n <= 0 do return 0;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
@@ -196,16 +206,18 @@ proc align_of_type_info(type_info: ^TypeInfo) -> int {
|
||||
return n - (n >> 1);
|
||||
}
|
||||
|
||||
const WORD_SIZE = size_of(int);
|
||||
const MAX_ALIGN = size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
|
||||
WORD_SIZE :: size_of(int);
|
||||
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
|
||||
using TypeInfo;
|
||||
match info in type_info {
|
||||
match info in type_info.variant {
|
||||
case Named:
|
||||
return align_of_type_info(info.base);
|
||||
case Integer:
|
||||
return info.size;
|
||||
return type_info.align;
|
||||
case Rune:
|
||||
return type_info.align;
|
||||
case Float:
|
||||
return info.size;
|
||||
return type_info.align;
|
||||
case String:
|
||||
return WORD_SIZE;
|
||||
case Boolean:
|
||||
@@ -223,18 +235,16 @@ proc align_of_type_info(type_info: ^TypeInfo) -> int {
|
||||
case Slice:
|
||||
return WORD_SIZE;
|
||||
case Vector:
|
||||
var size = size_of_type_info(info.elem);
|
||||
var count = int(max(prev_pow2(i64(info.count)), 1));
|
||||
var total = size * count;
|
||||
size := size_of_type_info(info.elem);
|
||||
count := int(max(prev_pow2(i64(info.count)), 1));
|
||||
total := size * count;
|
||||
return clamp(total, 1, MAX_ALIGN);
|
||||
case Tuple:
|
||||
return info.align;
|
||||
return type_info.align;
|
||||
case Struct:
|
||||
return info.align;
|
||||
return type_info.align;
|
||||
case Union:
|
||||
return info.align;
|
||||
case RawUnion:
|
||||
return info.align;
|
||||
return type_info.align;
|
||||
case Enum:
|
||||
return align_of_type_info(info.base);
|
||||
case Map:
|
||||
@@ -244,21 +254,23 @@ proc align_of_type_info(type_info: ^TypeInfo) -> int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
proc align_formula(size, align: int) -> int {
|
||||
var result = size + align-1;
|
||||
align_formula :: proc(size, align: int) -> int {
|
||||
result := size + align-1;
|
||||
return result - result%align;
|
||||
}
|
||||
|
||||
proc size_of_type_info(type_info: ^TypeInfo) -> int {
|
||||
const WORD_SIZE = size_of(int);
|
||||
size_of_type_info :: proc(type_info: ^TypeInfo) -> int {
|
||||
WORD_SIZE :: size_of(int);
|
||||
using TypeInfo;
|
||||
match info in type_info {
|
||||
match info in type_info.variant {
|
||||
case Named:
|
||||
return size_of_type_info(info.base);
|
||||
case Integer:
|
||||
return info.size;
|
||||
return type_info.size;
|
||||
case Rune:
|
||||
return type_info.size;
|
||||
case Float:
|
||||
return info.size;
|
||||
return type_info.size;
|
||||
case String:
|
||||
return 2*WORD_SIZE;
|
||||
case Boolean:
|
||||
@@ -270,33 +282,27 @@ proc size_of_type_info(type_info: ^TypeInfo) -> int {
|
||||
case Procedure:
|
||||
return WORD_SIZE;
|
||||
case Array:
|
||||
var count = info.count;
|
||||
if count == 0 {
|
||||
return 0;
|
||||
}
|
||||
var size = size_of_type_info(info.elem);
|
||||
var align = align_of_type_info(info.elem);
|
||||
var alignment = align_formula(size, align);
|
||||
count := info.count;
|
||||
if count == 0 do return 0;
|
||||
size := size_of_type_info(info.elem);
|
||||
align := align_of_type_info(info.elem);
|
||||
alignment := align_formula(size, align);
|
||||
return alignment*(count-1) + size;
|
||||
case DynamicArray:
|
||||
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
|
||||
case Slice:
|
||||
return 2*WORD_SIZE;
|
||||
case Vector:
|
||||
var count = info.count;
|
||||
if count == 0 {
|
||||
return 0;
|
||||
}
|
||||
var size = size_of_type_info(info.elem);
|
||||
var align = align_of_type_info(info.elem);
|
||||
var alignment = align_formula(size, align);
|
||||
count := info.count;
|
||||
if count == 0 do return 0;
|
||||
size := size_of_type_info(info.elem);
|
||||
align := align_of_type_info(info.elem);
|
||||
alignment := align_formula(size, align);
|
||||
return alignment*(count-1) + size;
|
||||
case Struct:
|
||||
return info.size;
|
||||
return type_info.size;
|
||||
case Union:
|
||||
return info.size;
|
||||
case RawUnion:
|
||||
return info.size;
|
||||
return type_info.size;
|
||||
case Enum:
|
||||
return size_of_type_info(info.base);
|
||||
case Map:
|
||||
|
||||
+37
-35
@@ -8,53 +8,55 @@ import (
|
||||
)
|
||||
import_load "opengl_constants.odin";
|
||||
|
||||
_ := compile_assert(ODIN_OS != "osx");
|
||||
|
||||
foreign lib {
|
||||
proc Clear (mask: u32) #link_name "glClear";
|
||||
proc ClearColor (r, g, b, a: f32) #link_name "glClearColor";
|
||||
proc Begin (mode: i32) #link_name "glBegin";
|
||||
proc End () #link_name "glEnd";
|
||||
proc Finish () #link_name "glFinish";
|
||||
proc BlendFunc (sfactor, dfactor: i32) #link_name "glBlendFunc";
|
||||
proc Enable (cap: i32) #link_name "glEnable";
|
||||
proc Disable (cap: i32) #link_name "glDisable";
|
||||
proc GenTextures (count: i32, result: ^u32) #link_name "glGenTextures";
|
||||
proc DeleteTextures(count: i32, result: ^u32) #link_name "glDeleteTextures";
|
||||
proc TexParameteri (target, pname, param: i32) #link_name "glTexParameteri";
|
||||
proc TexParameterf (target: i32, pname: i32, param: f32) #link_name "glTexParameterf";
|
||||
proc BindTexture (target: i32, texture: u32) #link_name "glBindTexture";
|
||||
proc LoadIdentity () #link_name "glLoadIdentity";
|
||||
proc Viewport (x, y, width, height: i32) #link_name "glViewport";
|
||||
proc Ortho (left, right, bottom, top, near, far: f64) #link_name "glOrtho";
|
||||
proc Color3f (r, g, b: f32) #link_name "glColor3f";
|
||||
proc Vertex3f (x, y, z: f32) #link_name "glVertex3f";
|
||||
proc GetError () -> i32 #link_name "glGetError";
|
||||
proc GetString (name: i32) -> ^u8 #link_name "glGetString";
|
||||
proc GetIntegerv (name: i32, v: ^i32) #link_name "glGetIntegerv";
|
||||
proc TexCoord2f (x, y: f32) #link_name "glTexCoord2f";
|
||||
proc TexImage2D (target, level, internal_format,
|
||||
width, height, border,
|
||||
format, type_: i32, pixels: rawptr) #link_name "glTexImage2D";
|
||||
Clear :: proc(mask: u32) #link_name "glClear" ---;
|
||||
ClearColor :: proc(r, g, b, a: f32) #link_name "glClearColor" ---;
|
||||
Begin :: proc(mode: i32) #link_name "glBegin" ---;
|
||||
End :: proc() #link_name "glEnd" ---;
|
||||
Finish :: proc() #link_name "glFinish" ---;
|
||||
BlendFunc :: proc(sfactor, dfactor: i32) #link_name "glBlendFunc" ---;
|
||||
Enable :: proc(cap: i32) #link_name "glEnable" ---;
|
||||
Disable :: proc(cap: i32) #link_name "glDisable" ---;
|
||||
GenTextures :: proc(count: i32, result: ^u32) #link_name "glGenTextures" ---;
|
||||
DeleteTextures :: proc(count: i32, result: ^u32) #link_name "glDeleteTextures"---;
|
||||
TexParameteri :: proc(target, pname, param: i32) #link_name "glTexParameteri" ---;
|
||||
TexParameterf :: proc(target: i32, pname: i32, param: f32) #link_name "glTexParameterf" ---;
|
||||
BindTexture :: proc(target: i32, texture: u32) #link_name "glBindTexture" ---;
|
||||
LoadIdentity :: proc() #link_name "glLoadIdentity" ---;
|
||||
Viewport :: proc(x, y, width, height: i32) #link_name "glViewport" ---;
|
||||
Ortho :: proc(left, right, bottom, top, near, far: f64) #link_name "glOrtho" ---;
|
||||
Color3f :: proc(r, g, b: f32) #link_name "glColor3f" ---;
|
||||
Vertex3f :: proc(x, y, z: f32) #link_name "glVertex3f" ---;
|
||||
GetError :: proc() -> i32 #link_name "glGetError" ---;
|
||||
GetString :: proc(name: i32) -> ^u8 #link_name "glGetString" ---;
|
||||
GetIntegerv :: proc(name: i32, v: ^i32) #link_name "glGetIntegerv" ---;
|
||||
TexCoord2f :: proc(x, y: f32) #link_name "glTexCoord2f" ---;
|
||||
TexImage2D :: proc(target, level, internal_format,
|
||||
width, height, border,
|
||||
format, type_: i32, pixels: rawptr) #link_name "glTexImage2D" ---;
|
||||
}
|
||||
|
||||
|
||||
proc _string_data(s: string) -> ^u8 #inline { return &s[0]; }
|
||||
_string_data :: proc(s: string) -> ^u8 #inline { return &s[0]; }
|
||||
|
||||
var _libgl = win32.load_library_a(_string_data("opengl32.dll\x00"));
|
||||
_libgl := win32.load_library_a(_string_data("opengl32.dll\x00"));
|
||||
|
||||
proc get_proc_address(name: string) -> rawptr {
|
||||
get_proc_address :: proc(name: string) -> rawptr {
|
||||
if name[len(name)-1] == 0 {
|
||||
name = name[0..<len(name)-1];
|
||||
name = name[..len(name)-1];
|
||||
}
|
||||
// NOTE(bill): null terminated
|
||||
assert((&name[0] + len(name))^ == 0);
|
||||
var res = wgl.get_proc_address(&name[0]);
|
||||
res := wgl.get_proc_address(&name[0]);
|
||||
if res == nil {
|
||||
res = win32.get_proc_address(_libgl, &name[0]);
|
||||
}
|
||||
return rawptr(res);
|
||||
}
|
||||
|
||||
var (
|
||||
// Procedures
|
||||
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
|
||||
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
|
||||
GenSamplers: proc(count: i32, buffers: ^u32) #cc_c;
|
||||
@@ -114,11 +116,11 @@ var (
|
||||
UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
|
||||
|
||||
GetUniformLocation: proc(program: u32, name: ^u8) -> i32 #cc_c;
|
||||
)
|
||||
|
||||
proc init() {
|
||||
proc set_proc_address(p: rawptr, name: string) #inline {
|
||||
var x = ^rawptr(p);
|
||||
|
||||
init :: proc() {
|
||||
set_proc_address :: proc(p: rawptr, name: string) #inline {
|
||||
x := cast(^rawptr)p;
|
||||
x^ = get_proc_address(name);
|
||||
}
|
||||
|
||||
|
||||
+1365
-1367
File diff suppressed because it is too large
Load Diff
+12
-12
@@ -4,46 +4,46 @@ import_load (
|
||||
"os_linux.odin" when ODIN_OS == "linux";
|
||||
)
|
||||
|
||||
proc write_string(fd: Handle, str: string) -> (int, Errno) {
|
||||
return write(fd, []u8(str));
|
||||
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
|
||||
return write(fd, cast([]u8)str);
|
||||
}
|
||||
|
||||
proc read_entire_file(name: string) -> ([]u8, bool) {
|
||||
var fd, err = open(name, O_RDONLY, 0);
|
||||
read_entire_file :: proc(name: string) -> (data: []u8, success: bool) {
|
||||
fd, err := open(name, O_RDONLY, 0);
|
||||
if err != 0 {
|
||||
return nil, false;
|
||||
}
|
||||
defer close(fd);
|
||||
|
||||
var length: i64;
|
||||
length: i64;
|
||||
if length, err = file_size(fd); err != 0 {
|
||||
return nil, false;
|
||||
}
|
||||
|
||||
if length == 0 {
|
||||
if length <= 0 {
|
||||
return nil, true;
|
||||
}
|
||||
|
||||
var data = make([]u8, length);
|
||||
data := make([]u8, int(length));
|
||||
if data == nil {
|
||||
return nil, false;
|
||||
}
|
||||
|
||||
var bytes_read, read_err = read(fd, data);
|
||||
bytes_read, read_err := read(fd, data);
|
||||
if read_err != 0 {
|
||||
free(data);
|
||||
return nil, false;
|
||||
}
|
||||
return data[0..<bytes_read], true;
|
||||
return data[0..bytes_read], true;
|
||||
}
|
||||
|
||||
proc write_entire_file(name: string, data: []u8) -> bool {
|
||||
var fd, err = open(name, O_WRONLY, 0);
|
||||
write_entire_file :: proc(name: string, data: []u8) -> (sucess: bool) {
|
||||
fd, err := open(name, O_WRONLY, 0);
|
||||
if err != 0 {
|
||||
return false;
|
||||
}
|
||||
defer close(fd);
|
||||
|
||||
var bytes_written, write_err = write(fd, data);
|
||||
bytes_written, write_err := write(fd, data);
|
||||
return write_err != 0;
|
||||
}
|
||||
|
||||
+151
-159
@@ -4,160 +4,152 @@ foreign_system_library (
|
||||
)
|
||||
import "strings.odin";
|
||||
|
||||
type (
|
||||
Handle i32;
|
||||
FileTime u64;
|
||||
Errno i32;
|
||||
)
|
||||
Handle :: i32;
|
||||
FileTime :: u64;
|
||||
Errno :: i32;
|
||||
|
||||
const (
|
||||
O_RDONLY = 0x00000;
|
||||
O_WRONLY = 0x00001;
|
||||
O_RDWR = 0x00002;
|
||||
O_CREAT = 0x00040;
|
||||
O_EXCL = 0x00080;
|
||||
O_NOCTTY = 0x00100;
|
||||
O_TRUNC = 0x00200;
|
||||
O_NONBLOCK = 0x00800;
|
||||
O_APPEND = 0x00400;
|
||||
O_SYNC = 0x01000;
|
||||
O_ASYNC = 0x02000;
|
||||
O_CLOEXEC = 0x80000;
|
||||
)
|
||||
|
||||
const (
|
||||
SEEK_SET = 0;
|
||||
SEEK_CUR = 1;
|
||||
SEEK_END = 2;
|
||||
SEEK_DATA = 3;
|
||||
SEEK_HOLE = 4;
|
||||
SEEK_MAX = SEEK_HOLE;
|
||||
)
|
||||
const (
|
||||
// NOTE(zangent): These are OS specific!
|
||||
// Do not mix these up!
|
||||
RTLD_LAZY = 0x001;
|
||||
RTLD_NOW = 0x002;
|
||||
RTLD_BINDING_MASK = 0x3;
|
||||
RTLD_GLOBAL = 0x100;
|
||||
)
|
||||
O_RDONLY :: 0x00000;
|
||||
O_WRONLY :: 0x00001;
|
||||
O_RDWR :: 0x00002;
|
||||
O_CREAT :: 0x00040;
|
||||
O_EXCL :: 0x00080;
|
||||
O_NOCTTY :: 0x00100;
|
||||
O_TRUNC :: 0x00200;
|
||||
O_NONBLOCK :: 0x00800;
|
||||
O_APPEND :: 0x00400;
|
||||
O_SYNC :: 0x01000;
|
||||
O_ASYNC :: 0x02000;
|
||||
O_CLOEXEC :: 0x80000;
|
||||
|
||||
|
||||
SEEK_SET :: 0;
|
||||
SEEK_CUR :: 1;
|
||||
SEEK_END :: 2;
|
||||
SEEK_DATA :: 3;
|
||||
SEEK_HOLE :: 4;
|
||||
SEEK_MAX :: SEEK_HOLE;
|
||||
|
||||
// NOTE(zangent): These are OS specific!
|
||||
// Do not mix these up!
|
||||
RTLD_LAZY :: 0x001;
|
||||
RTLD_NOW :: 0x002;
|
||||
RTLD_BINDING_MASK :: 0x3;
|
||||
RTLD_GLOBAL :: 0x100;
|
||||
|
||||
// "Argv" arguments converted to Odin strings
|
||||
var args = _alloc_command_line_arguments();
|
||||
args := _alloc_command_line_arguments();
|
||||
|
||||
type _FileTime struct #ordered {
|
||||
seconds: i64,
|
||||
nanoseconds: i32,
|
||||
reserved: i32,
|
||||
_FileTime :: struct #ordered {
|
||||
seconds: i64;
|
||||
nanoseconds: i32;
|
||||
reserved: i32;
|
||||
}
|
||||
|
||||
// Translated from
|
||||
// https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/+/jb-dev/sysroot/usr/include/bits/stat.h
|
||||
// Validity is not guaranteed.
|
||||
|
||||
type Stat struct #ordered {
|
||||
device_id: u64, // ID of device containing file
|
||||
serial: u64, // File serial number
|
||||
nlink: u32, // Number of hard links
|
||||
mode: u32, // Mode of the file
|
||||
uid: u32, // User ID of the file's owner
|
||||
gid: u32, // Group ID of the file's group
|
||||
_padding: i32, // 32 bits of padding
|
||||
rdev: u64, // Device ID, if device
|
||||
size: i64, // Size of the file, in bytes
|
||||
block_size: i64, // Optimal bllocksize for I/O
|
||||
blocks: i64, // Number of 512-byte blocks allocated
|
||||
Stat :: struct #ordered {
|
||||
device_id: u64; // ID of device containing file
|
||||
serial: u64; // File serial number
|
||||
nlink: u32; // Number of hard links
|
||||
mode: u32; // Mode of the file
|
||||
uid: u32; // User ID of the file's owner
|
||||
gid: u32; // Group ID of the file's group
|
||||
_padding: i32; // 32 bits of padding
|
||||
rdev: u64; // Device ID, if device
|
||||
size: i64; // Size of the file, in bytes
|
||||
block_size: i64; // Optimal bllocksize for I/O
|
||||
blocks: i64; // Number of 512-byte blocks allocated
|
||||
|
||||
last_access: _FileTime, // Time of last access
|
||||
modified: _FileTime, // Time of last modification
|
||||
status_change: _FileTime, // Time of last status change
|
||||
last_access: _FileTime; // Time of last access
|
||||
modified: _FileTime; // Time of last modification
|
||||
status_change: _FileTime; // Time of last status change
|
||||
|
||||
_reserve1,
|
||||
_reserve2,
|
||||
_reserve3: i64,
|
||||
serial_numbe: u64, // File serial number...? Maybe.
|
||||
_reserve4: i64,
|
||||
_reserve3: i64;
|
||||
serial_numbe: u64; // File serial number...? Maybe.
|
||||
_reserve4: i64;
|
||||
};
|
||||
|
||||
// File type
|
||||
const (
|
||||
S_IFMT = 0170000; // Type of file mask
|
||||
S_IFIFO = 0010000; // Named pipe (fifo)
|
||||
S_IFCHR = 0020000; // Character special
|
||||
S_IFDIR = 0040000; // Directory
|
||||
S_IFBLK = 0060000; // Block special
|
||||
S_IFREG = 0100000; // Regular
|
||||
S_IFLNK = 0120000; // Symbolic link
|
||||
S_IFSOCK = 0140000; // Socket
|
||||
S_IFMT :: 0170000; // Type of file mask
|
||||
S_IFIFO :: 0010000; // Named pipe (fifo)
|
||||
S_IFCHR :: 0020000; // Character special
|
||||
S_IFDIR :: 0040000; // Directory
|
||||
S_IFBLK :: 0060000; // Block special
|
||||
S_IFREG :: 0100000; // Regular
|
||||
S_IFLNK :: 0120000; // Symbolic link
|
||||
S_IFSOCK :: 0140000; // Socket
|
||||
|
||||
// File mode
|
||||
// Read, write, execute/search by owner
|
||||
S_IRWXU = 0000700; // RWX mask for owner
|
||||
S_IRUSR = 0000400; // R for owner
|
||||
S_IWUSR = 0000200; // W for owner
|
||||
S_IXUSR = 0000100; // X for owner
|
||||
// File mode
|
||||
// Read, write, execute/search by owner
|
||||
S_IRWXU :: 0000700; // RWX mask for owner
|
||||
S_IRUSR :: 0000400; // R for owner
|
||||
S_IWUSR :: 0000200; // W for owner
|
||||
S_IXUSR :: 0000100; // X for owner
|
||||
|
||||
// Read, write, execute/search by group
|
||||
S_IRWXG = 0000070; // RWX mask for group
|
||||
S_IRGRP = 0000040; // R for group
|
||||
S_IWGRP = 0000020; // W for group
|
||||
S_IXGRP = 0000010; // X for group
|
||||
S_IRWXG :: 0000070; // RWX mask for group
|
||||
S_IRGRP :: 0000040; // R for group
|
||||
S_IWGRP :: 0000020; // W for group
|
||||
S_IXGRP :: 0000010; // X for group
|
||||
|
||||
// Read, write, execute/search by others
|
||||
S_IRWXO = 0000007; // RWX mask for other
|
||||
S_IROTH = 0000004; // R for other
|
||||
S_IWOTH = 0000002; // W for other
|
||||
S_IXOTH = 0000001; // X for other
|
||||
S_IRWXO :: 0000007; // RWX mask for other
|
||||
S_IROTH :: 0000004; // R for other
|
||||
S_IWOTH :: 0000002; // W for other
|
||||
S_IXOTH :: 0000001; // X for other
|
||||
|
||||
S_ISUID = 0004000; // Set user id on execution
|
||||
S_ISGID = 0002000; // Set group id on execution
|
||||
S_ISVTX = 0001000; // Directory restrcted delete
|
||||
)
|
||||
S_ISUID :: 0004000; // Set user id on execution
|
||||
S_ISGID :: 0002000; // Set group id on execution
|
||||
S_ISVTX :: 0001000; // Directory restrcted delete
|
||||
|
||||
proc S_ISLNK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFLNK; }
|
||||
proc S_ISREG (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFREG; }
|
||||
proc S_ISDIR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFDIR; }
|
||||
proc S_ISCHR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFCHR; }
|
||||
proc S_ISBLK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFBLK; }
|
||||
proc S_ISFIFO(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFIFO; }
|
||||
proc S_ISSOCK(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFSOCK;}
|
||||
|
||||
const (
|
||||
R_OK = 4; // Test for read permission
|
||||
W_OK = 2; // Test for write permission
|
||||
X_OK = 1; // Test for execute permission
|
||||
F_OK = 0; // Test for file existance
|
||||
)
|
||||
S_ISLNK :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFLNK; }
|
||||
S_ISREG :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFREG; }
|
||||
S_ISDIR :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFDIR; }
|
||||
S_ISCHR :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFCHR; }
|
||||
S_ISBLK :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFBLK; }
|
||||
S_ISFIFO :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFIFO; }
|
||||
S_ISSOCK :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFSOCK;}
|
||||
|
||||
F_OK :: 0; // Test for file existance
|
||||
X_OK :: 1; // Test for execute permission
|
||||
W_OK :: 2; // Test for write permission
|
||||
R_OK :: 4; // Test for read permission
|
||||
|
||||
foreign libc {
|
||||
proc _unix_open (path: ^u8, mode: int) -> Handle #link_name "open";
|
||||
proc _unix_close (fd: Handle) -> i32 #link_name "close";
|
||||
proc _unix_read (fd: Handle, buf: rawptr, size: int) -> int #link_name "read";
|
||||
proc _unix_write (fd: Handle, buf: rawptr, size: int) -> int #link_name "write";
|
||||
proc _unix_seek (fd: Handle, offset: i64, whence: i32) -> i64 #link_name "lseek64";
|
||||
proc _unix_gettid() -> u64 #link_name "gettid";
|
||||
proc _unix_stat (path: ^u8, stat: ^Stat) -> i32 #link_name "stat";
|
||||
proc _unix_access(path: ^u8, mask: int) -> i32 #link_name "access";
|
||||
_unix_open :: proc(path: ^u8, mode: int) -> Handle #link_name "open" ---;
|
||||
_unix_close :: proc(fd: Handle) -> i32 #link_name "close" ---;
|
||||
_unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int #link_name "read" ---;
|
||||
_unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int #link_name "write" ---;
|
||||
_unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 #link_name "lseek64" ---;
|
||||
_unix_gettid :: proc() -> u64 #link_name "gettid" ---;
|
||||
_unix_stat :: proc(path: ^u8, stat: ^Stat) -> i32 #link_name "stat" ---;
|
||||
_unix_access :: proc(path: ^u8, mask: int) -> i32 #link_name "access" ---;
|
||||
|
||||
proc _unix_malloc (size: int) -> rawptr #link_name "malloc";
|
||||
proc _unix_free (ptr: rawptr) #link_name "free";
|
||||
proc _unix_realloc(ptr: rawptr, size: int) -> rawptr #link_name "realloc";
|
||||
proc _unix_getenv (^u8) -> ^u8 #link_name "getenv";
|
||||
_unix_malloc :: proc(size: int) -> rawptr #link_name "malloc" ---;
|
||||
_unix_free :: proc(ptr: rawptr) #link_name "free" ---;
|
||||
_unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #link_name "realloc" ---;
|
||||
_unix_getenv :: proc(^u8) -> ^u8 #link_name "getenv" ---;
|
||||
|
||||
proc _unix_exit(status: int) #link_name "exit";
|
||||
_unix_exit :: proc(status: int) #link_name "exit" ---;
|
||||
}
|
||||
foreign dl {
|
||||
proc _unix_dlopen (filename: ^u8, flags: int) -> rawptr #link_name "dlopen";
|
||||
proc _unix_dlsym (handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym";
|
||||
proc _unix_dlclose(handle: rawptr) -> int #link_name "dlclose";
|
||||
proc _unix_dlerror() -> ^u8 #link_name "dlerror";
|
||||
_unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #link_name "dlopen" ---;
|
||||
_unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym" ---;
|
||||
_unix_dlclose :: proc(handle: rawptr) -> int #link_name "dlclose" ---;
|
||||
_unix_dlerror :: proc() -> ^u8 #link_name "dlerror" ---;
|
||||
}
|
||||
|
||||
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
|
||||
proc open_simple(path: string, mode: int) -> (Handle, Errno) {
|
||||
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
|
||||
|
||||
var cstr = strings.new_c_string(path);
|
||||
var handle = _unix_open(cstr, mode);
|
||||
cstr := strings.new_c_string(path);
|
||||
handle := _unix_open(cstr, mode);
|
||||
free(cstr);
|
||||
if(handle == -1) {
|
||||
return 0, 1;
|
||||
@@ -165,78 +157,78 @@ proc open_simple(path: string, mode: int) -> (Handle, Errno) {
|
||||
return handle, 0;
|
||||
}
|
||||
// NOTE(zangent): This is here for compatability reasons. Should this be here?
|
||||
proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
|
||||
open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
|
||||
return open_simple(path, mode);
|
||||
}
|
||||
|
||||
proc close(fd: Handle) {
|
||||
close :: proc(fd: Handle) {
|
||||
_unix_close(fd);
|
||||
}
|
||||
|
||||
proc read(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
var sz = _unix_read(fd, &data[0], len(data));
|
||||
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
sz := _unix_read(fd, &data[0], len(data));
|
||||
return sz, 0;
|
||||
}
|
||||
|
||||
proc write(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
var sz = _unix_write(fd, &data[0], len(data));
|
||||
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
sz := _unix_write(fd, &data[0], len(data));
|
||||
return sz, 0;
|
||||
}
|
||||
|
||||
proc seek(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
var res = _unix_seek(fd, offset, i32(whence));
|
||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
res := _unix_seek(fd, offset, i32(whence));
|
||||
return res, 0;
|
||||
}
|
||||
|
||||
proc file_size(fd: Handle) -> (i64, Errno) {
|
||||
var prev, _ = seek(fd, 0, SEEK_CUR);
|
||||
var size, err = seek(fd, 0, SEEK_END);
|
||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
prev, _ := seek(fd, 0, SEEK_CUR);
|
||||
size, err := seek(fd, 0, SEEK_END);
|
||||
seek(fd, prev, SEEK_SET);
|
||||
return size, err;
|
||||
}
|
||||
|
||||
|
||||
// NOTE(bill): Uses startup to initialize it
|
||||
var (
|
||||
stdin: Handle = 0;
|
||||
stdout: Handle = 1;
|
||||
stderr: Handle = 2;
|
||||
)
|
||||
|
||||
stdin: Handle = 0;
|
||||
stdout: Handle = 1;
|
||||
stderr: Handle = 2;
|
||||
|
||||
/* TODO(zangent): Implement these!
|
||||
proc last_write_time(fd: Handle) -> FileTime {}
|
||||
proc last_write_time_by_name(name: string) -> FileTime {}
|
||||
last_write_time :: proc(fd: Handle) -> FileTime {}
|
||||
last_write_time_by_name :: proc(name: string) -> FileTime {}
|
||||
*/
|
||||
|
||||
proc stat(path: string) -> (Stat, int) #inline {
|
||||
var s: Stat;
|
||||
var cstr = strings.new_c_string(path);
|
||||
stat :: proc(path: string) -> (Stat, int) #inline {
|
||||
s: Stat;
|
||||
cstr := strings.new_c_string(path);
|
||||
defer free(cstr);
|
||||
var ret_int = _unix_stat(cstr, &s);
|
||||
ret_int := _unix_stat(cstr, &s);
|
||||
return s, int(ret_int);
|
||||
}
|
||||
|
||||
proc access(path: string, mask: int) -> bool #inline {
|
||||
var cstr = strings.new_c_string(path);
|
||||
access :: proc(path: string, mask: int) -> bool #inline {
|
||||
cstr := strings.new_c_string(path);
|
||||
defer free(cstr);
|
||||
return _unix_access(cstr, mask) == 0;
|
||||
}
|
||||
|
||||
proc heap_alloc(size: int) -> rawptr {
|
||||
heap_alloc :: proc(size: int) -> rawptr {
|
||||
assert(size > 0);
|
||||
return _unix_malloc(size);
|
||||
}
|
||||
|
||||
proc heap_resize(ptr: rawptr, new_size: int) -> rawptr {
|
||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||
return _unix_realloc(ptr, new_size);
|
||||
}
|
||||
|
||||
proc heap_free(ptr: rawptr) {
|
||||
heap_free :: proc(ptr: rawptr) {
|
||||
_unix_free(ptr);
|
||||
}
|
||||
|
||||
proc getenv(name: string) -> (string, bool) {
|
||||
var path_str = strings.new_c_string(name);
|
||||
var cstr: ^u8 = _unix_getenv(path_str);
|
||||
getenv :: proc(name: string) -> (string, bool) {
|
||||
path_str := strings.new_c_string(name);
|
||||
cstr: ^u8 = _unix_getenv(path_str);
|
||||
free(path_str);
|
||||
if(cstr == nil) {
|
||||
return "", false;
|
||||
@@ -244,38 +236,38 @@ proc getenv(name: string) -> (string, bool) {
|
||||
return strings.to_odin_string(cstr), true;
|
||||
}
|
||||
|
||||
proc exit(code: int) {
|
||||
exit :: proc(code: int) {
|
||||
_unix_exit(code);
|
||||
}
|
||||
|
||||
proc current_thread_id() -> int {
|
||||
current_thread_id :: proc() -> int {
|
||||
// return int(_unix_gettid());
|
||||
return 0;
|
||||
}
|
||||
|
||||
proc dlopen(filename: string, flags: int) -> rawptr #inline {
|
||||
var cstr = strings.new_c_string(filename);
|
||||
var handle = _unix_dlopen(cstr, flags);
|
||||
dlopen :: proc(filename: string, flags: int) -> rawptr #inline {
|
||||
cstr := strings.new_c_string(filename);
|
||||
handle := _unix_dlopen(cstr, flags);
|
||||
free(cstr);
|
||||
return handle;
|
||||
}
|
||||
proc dlsym(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
|
||||
dlsym :: proc(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
|
||||
assert(handle != nil);
|
||||
var cstr = strings.new_c_string(symbol);
|
||||
var proc_handle = _unix_dlsym(handle, cstr);
|
||||
cstr := strings.new_c_string(symbol);
|
||||
proc_handle := _unix_dlsym(handle, cstr);
|
||||
free(cstr);
|
||||
return proc_handle;
|
||||
}
|
||||
proc dlclose(handle: rawptr) -> bool #inline {
|
||||
dlclose :: proc(handle: rawptr) -> bool #inline {
|
||||
assert(handle != nil);
|
||||
return _unix_dlclose(handle) == 0;
|
||||
}
|
||||
proc dlerror() -> string {
|
||||
dlerror :: proc() -> string {
|
||||
return strings.to_odin_string(_unix_dlerror());
|
||||
}
|
||||
|
||||
|
||||
proc _alloc_command_line_arguments() -> []string {
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
// TODO(bill):
|
||||
return nil;
|
||||
}
|
||||
|
||||
+156
-187
@@ -1,68 +1,65 @@
|
||||
import win32 "sys/windows.odin";
|
||||
import "mem.odin";
|
||||
|
||||
type (
|
||||
Handle int;
|
||||
FileTime u64;
|
||||
)
|
||||
|
||||
const INVALID_HANDLE: Handle = -1;
|
||||
Handle :: int;
|
||||
FileTime :: u64;
|
||||
|
||||
|
||||
const (
|
||||
O_RDONLY = 0x00000;
|
||||
O_WRONLY = 0x00001;
|
||||
O_RDWR = 0x00002;
|
||||
O_CREAT = 0x00040;
|
||||
O_EXCL = 0x00080;
|
||||
O_NOCTTY = 0x00100;
|
||||
O_TRUNC = 0x00200;
|
||||
O_NONBLOCK = 0x00800;
|
||||
O_APPEND = 0x00400;
|
||||
O_SYNC = 0x01000;
|
||||
O_ASYNC = 0x02000;
|
||||
O_CLOEXEC = 0x80000;
|
||||
)
|
||||
INVALID_HANDLE: Handle : -1;
|
||||
|
||||
type Errno int;
|
||||
const (
|
||||
ERROR_NONE: Errno = 0;
|
||||
ERROR_FILE_NOT_FOUND = 2;
|
||||
ERROR_PATH_NOT_FOUND = 3;
|
||||
ERROR_ACCESS_DENIED = 5;
|
||||
ERROR_NO_MORE_FILES = 18;
|
||||
ERROR_HANDLE_EOF = 38;
|
||||
ERROR_NETNAME_DELETED = 64;
|
||||
ERROR_FILE_EXISTS = 80;
|
||||
ERROR_BROKEN_PIPE = 109;
|
||||
ERROR_BUFFER_OVERFLOW = 111;
|
||||
ERROR_INSUFFICIENT_BUFFER = 122;
|
||||
ERROR_MOD_NOT_FOUND = 126;
|
||||
ERROR_PROC_NOT_FOUND = 127;
|
||||
ERROR_DIR_NOT_EMPTY = 145;
|
||||
ERROR_ALREADY_EXISTS = 183;
|
||||
ERROR_ENVVAR_NOT_FOUND = 203;
|
||||
ERROR_MORE_DATA = 234;
|
||||
ERROR_OPERATION_ABORTED = 995;
|
||||
ERROR_IO_PENDING = 997;
|
||||
ERROR_NOT_FOUND = 1168;
|
||||
ERROR_PRIVILEGE_NOT_HELD = 1314;
|
||||
WSAEACCES = 10013;
|
||||
WSAECONNRESET = 10054;
|
||||
|
||||
// Windows reserves errors >= 1<<29 for application use
|
||||
ERROR_FILE_IS_PIPE = 1<<29 + 0;
|
||||
)
|
||||
|
||||
O_RDONLY :: 0x00000;
|
||||
O_WRONLY :: 0x00001;
|
||||
O_RDWR :: 0x00002;
|
||||
O_CREAT :: 0x00040;
|
||||
O_EXCL :: 0x00080;
|
||||
O_NOCTTY :: 0x00100;
|
||||
O_TRUNC :: 0x00200;
|
||||
O_NONBLOCK :: 0x00800;
|
||||
O_APPEND :: 0x00400;
|
||||
O_SYNC :: 0x01000;
|
||||
O_ASYNC :: 0x02000;
|
||||
O_CLOEXEC :: 0x80000;
|
||||
|
||||
Errno :: int;
|
||||
|
||||
ERROR_NONE: Errno : 0;
|
||||
ERROR_FILE_NOT_FOUND: Errno : 2;
|
||||
ERROR_PATH_NOT_FOUND: Errno : 3;
|
||||
ERROR_ACCESS_DENIED: Errno : 5;
|
||||
ERROR_NO_MORE_FILES: Errno : 18;
|
||||
ERROR_HANDLE_EOF: Errno : 38;
|
||||
ERROR_NETNAME_DELETED: Errno : 64;
|
||||
ERROR_FILE_EXISTS: Errno : 80;
|
||||
ERROR_BROKEN_PIPE: Errno : 109;
|
||||
ERROR_BUFFER_OVERFLOW: Errno : 111;
|
||||
ERROR_INSUFFICIENT_BUFFER: Errno : 122;
|
||||
ERROR_MOD_NOT_FOUND: Errno : 126;
|
||||
ERROR_PROC_NOT_FOUND: Errno : 127;
|
||||
ERROR_DIR_NOT_EMPTY: Errno : 145;
|
||||
ERROR_ALREADY_EXISTS: Errno : 183;
|
||||
ERROR_ENVVAR_NOT_FOUND: Errno : 203;
|
||||
ERROR_MORE_DATA: Errno : 234;
|
||||
ERROR_OPERATION_ABORTED: Errno : 995;
|
||||
ERROR_IO_PENDING: Errno : 997;
|
||||
ERROR_NOT_FOUND: Errno : 1168;
|
||||
ERROR_PRIVILEGE_NOT_HELD: Errno : 1314;
|
||||
WSAEACCES: Errno : 10013;
|
||||
WSAECONNRESET: Errno : 10054;
|
||||
|
||||
// Windows reserves errors >= 1<<29 for application use
|
||||
ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
|
||||
|
||||
|
||||
// "Argv" arguments converted to Odin strings
|
||||
var args = _alloc_command_line_arguments();
|
||||
args := _alloc_command_line_arguments();
|
||||
|
||||
|
||||
proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
|
||||
if len(path) == 0 {
|
||||
return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
|
||||
if len(path) == 0 do return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
|
||||
|
||||
var access: u32;
|
||||
access: u32;
|
||||
match mode & (O_RDONLY|O_WRONLY|O_RDWR) {
|
||||
case O_RDONLY: access = win32.FILE_GENERIC_READ;
|
||||
case O_WRONLY: access = win32.FILE_GENERIC_WRITE;
|
||||
@@ -77,14 +74,14 @@ proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno)
|
||||
access |= win32.FILE_APPEND_DATA;
|
||||
}
|
||||
|
||||
var share_mode = u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE);
|
||||
var sa: ^win32.Security_Attributes = nil;
|
||||
var sa_inherit = win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = 1};
|
||||
share_mode := u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE);
|
||||
sa: ^win32.SecurityAttributes = nil;
|
||||
sa_inherit := win32.SecurityAttributes{length = size_of(win32.SecurityAttributes), inherit_handle = 1};
|
||||
if mode&O_CLOEXEC == 0 {
|
||||
sa = &sa_inherit;
|
||||
}
|
||||
|
||||
var create_mode: u32;
|
||||
create_mode: u32;
|
||||
match {
|
||||
case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
|
||||
create_mode = win32.CREATE_NEW;
|
||||
@@ -98,102 +95,88 @@ proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno)
|
||||
create_mode = win32.OPEN_EXISTING;
|
||||
}
|
||||
|
||||
var buf: [300]u8;
|
||||
copy(buf[..], []u8(path));
|
||||
buf: [300]u8;
|
||||
copy(buf[..], cast([]u8)path);
|
||||
|
||||
var handle = Handle(win32.create_file_a(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
|
||||
if handle != INVALID_HANDLE {
|
||||
return handle, ERROR_NONE;
|
||||
}
|
||||
var err = win32.get_last_error();
|
||||
return INVALID_HANDLE, Errno(err);
|
||||
handle := Handle(win32.create_file_a(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
|
||||
if handle != INVALID_HANDLE do return handle, ERROR_NONE;
|
||||
|
||||
err := Errno(win32.get_last_error());
|
||||
return INVALID_HANDLE, err;
|
||||
}
|
||||
|
||||
proc close(fd: Handle) {
|
||||
close :: proc(fd: Handle) {
|
||||
win32.close_handle(win32.Handle(fd));
|
||||
}
|
||||
|
||||
|
||||
proc write(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
if len(data) == 0 {
|
||||
return 0, ERROR_NONE;
|
||||
}
|
||||
var single_write_length: i32;
|
||||
var total_write: i64;
|
||||
var length = i64(len(data));
|
||||
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
if len(data) == 0 do return 0, ERROR_NONE;
|
||||
|
||||
single_write_length: i32;
|
||||
total_write: i64;
|
||||
length := i64(len(data));
|
||||
|
||||
for total_write < length {
|
||||
var remaining = length - total_write;
|
||||
var to_read: i32;
|
||||
const MAX = 1<<31-1;
|
||||
if remaining <= MAX {
|
||||
to_read = i32(remaining);
|
||||
} else {
|
||||
to_read = MAX;
|
||||
}
|
||||
var e = win32.write_file(win32.Handle(fd), &data[total_write], to_read, &single_write_length, nil);
|
||||
remaining := length - total_write;
|
||||
MAX :: 1<<31-1;
|
||||
to_write: i32 = min(i32(remaining), MAX);
|
||||
|
||||
e := win32.write_file(win32.Handle(fd), &data[total_write], to_write, &single_write_length, nil);
|
||||
if single_write_length <= 0 || e == win32.FALSE {
|
||||
var err = win32.get_last_error();
|
||||
return int(total_write), Errno(e);
|
||||
err := Errno(win32.get_last_error());
|
||||
return int(total_write), err;
|
||||
}
|
||||
total_write += i64(single_write_length);
|
||||
}
|
||||
return int(total_write), ERROR_NONE;
|
||||
}
|
||||
|
||||
proc read(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
if len(data) == 0 {
|
||||
return 0, ERROR_NONE;
|
||||
}
|
||||
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
if len(data) == 0 do return 0, ERROR_NONE;
|
||||
|
||||
var single_read_length: i32;
|
||||
var total_read: i64;
|
||||
var length = i64(len(data));
|
||||
single_read_length: i32;
|
||||
total_read: i64;
|
||||
length := i64(len(data));
|
||||
|
||||
for total_read < length {
|
||||
var remaining = length - total_read;
|
||||
var to_read: u32;
|
||||
const MAX = 1<<32-1;
|
||||
if remaining <= MAX {
|
||||
to_read = u32(remaining);
|
||||
} else {
|
||||
to_read = MAX;
|
||||
}
|
||||
remaining := length - total_read;
|
||||
MAX :: 1<<32-1;
|
||||
to_read: u32 = min(u32(remaining), MAX);
|
||||
|
||||
var e = win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
|
||||
e := win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
|
||||
if single_read_length <= 0 || e == win32.FALSE {
|
||||
var err = win32.get_last_error();
|
||||
return int(total_read), Errno(e);
|
||||
err := Errno(win32.get_last_error());
|
||||
return int(total_read), err;
|
||||
}
|
||||
total_read += i64(single_read_length);
|
||||
}
|
||||
return int(total_read), ERROR_NONE;
|
||||
}
|
||||
|
||||
proc seek(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
var w: u32;
|
||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
w: u32;
|
||||
match whence {
|
||||
case 0: w = win32.FILE_BEGIN;
|
||||
case 1: w = win32.FILE_CURRENT;
|
||||
case 2: w = win32.FILE_END;
|
||||
}
|
||||
var hi = i32(offset>>32);
|
||||
var lo = i32(offset);
|
||||
var ft = win32.get_file_type(win32.Handle(fd));
|
||||
if ft == win32.FILE_TYPE_PIPE {
|
||||
return 0, ERROR_FILE_IS_PIPE;
|
||||
}
|
||||
var dw_ptr = win32.set_file_pointer(win32.Handle(fd), lo, &hi, w);
|
||||
hi := i32(offset>>32);
|
||||
lo := i32(offset);
|
||||
ft := win32.get_file_type(win32.Handle(fd));
|
||||
if ft == win32.FILE_TYPE_PIPE do return 0, ERROR_FILE_IS_PIPE;
|
||||
|
||||
dw_ptr := win32.set_file_pointer(win32.Handle(fd), lo, &hi, w);
|
||||
if dw_ptr == win32.INVALID_SET_FILE_POINTER {
|
||||
var err = win32.get_last_error();
|
||||
return 0, Errno(err);
|
||||
err := Errno(win32.get_last_error());
|
||||
return 0, err;
|
||||
}
|
||||
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
|
||||
}
|
||||
|
||||
proc file_size(fd: Handle) -> (i64, Errno) {
|
||||
var length: i64;
|
||||
var err: Errno;
|
||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
length: i64;
|
||||
err: Errno;
|
||||
if win32.get_file_size_ex(win32.Handle(fd), &length) == 0 {
|
||||
err = Errno(win32.get_last_error());
|
||||
}
|
||||
@@ -203,13 +186,13 @@ proc file_size(fd: Handle) -> (i64, Errno) {
|
||||
|
||||
|
||||
// NOTE(bill): Uses startup to initialize it
|
||||
var stdin = get_std_handle(win32.STD_INPUT_HANDLE);
|
||||
var stdout = get_std_handle(win32.STD_OUTPUT_HANDLE);
|
||||
var stderr = get_std_handle(win32.STD_ERROR_HANDLE);
|
||||
stdin := get_std_handle(win32.STD_INPUT_HANDLE);
|
||||
stdout := get_std_handle(win32.STD_OUTPUT_HANDLE);
|
||||
stderr := get_std_handle(win32.STD_ERROR_HANDLE);
|
||||
|
||||
|
||||
proc get_std_handle(h: int) -> Handle {
|
||||
var fd = win32.get_std_handle(i32(h));
|
||||
get_std_handle :: proc(h: int) -> Handle {
|
||||
fd := win32.get_std_handle(i32(h));
|
||||
win32.set_handle_information(fd, win32.HANDLE_FLAG_INHERIT, 0);
|
||||
return Handle(fd);
|
||||
}
|
||||
@@ -219,126 +202,112 @@ proc get_std_handle(h: int) -> Handle {
|
||||
|
||||
|
||||
|
||||
proc last_write_time(fd: Handle) -> FileTime {
|
||||
var file_info: win32.ByHandleFileInformation;
|
||||
last_write_time :: proc(fd: Handle) -> FileTime {
|
||||
file_info: win32.ByHandleFileInformation;
|
||||
win32.get_file_information_by_handle(win32.Handle(fd), &file_info);
|
||||
var lo = FileTime(file_info.last_write_time.lo);
|
||||
var hi = FileTime(file_info.last_write_time.hi);
|
||||
lo := FileTime(file_info.last_write_time.lo);
|
||||
hi := FileTime(file_info.last_write_time.hi);
|
||||
return lo | hi << 32;
|
||||
}
|
||||
|
||||
proc last_write_time_by_name(name: string) -> FileTime {
|
||||
var last_write_time: win32.Filetime;
|
||||
var data: win32.FileAttributeData;
|
||||
var buf: [1024]u8;
|
||||
last_write_time_by_name :: proc(name: string) -> FileTime {
|
||||
last_write_time: win32.Filetime;
|
||||
data: win32.FileAttributeData;
|
||||
buf: [1024]u8;
|
||||
|
||||
assert(len(buf) > len(name));
|
||||
|
||||
copy(buf[..], []u8(name));
|
||||
copy(buf[..], cast([]u8)name);
|
||||
|
||||
if win32.get_file_attributes_ex_a(&buf[0], win32.GetFileExInfoStandard, &data) != 0 {
|
||||
last_write_time = data.last_write_time;
|
||||
}
|
||||
|
||||
var l = FileTime(last_write_time.lo);
|
||||
var h = FileTime(last_write_time.hi);
|
||||
l := FileTime(last_write_time.lo);
|
||||
h := FileTime(last_write_time.hi);
|
||||
return l | h << 32;
|
||||
}
|
||||
|
||||
|
||||
|
||||
proc heap_alloc(size: int) -> rawptr {
|
||||
heap_alloc :: proc(size: int) -> rawptr {
|
||||
return win32.heap_alloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, size);
|
||||
}
|
||||
proc heap_resize(ptr: rawptr, new_size: int) -> rawptr {
|
||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||
if new_size == 0 {
|
||||
heap_free(ptr);
|
||||
return nil;
|
||||
}
|
||||
if ptr == nil {
|
||||
return heap_alloc(new_size);
|
||||
}
|
||||
if ptr == nil do return heap_alloc(new_size);
|
||||
|
||||
return win32.heap_realloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
|
||||
}
|
||||
proc heap_free(ptr: rawptr) {
|
||||
if ptr == nil {
|
||||
return;
|
||||
}
|
||||
heap_free :: proc(ptr: rawptr) {
|
||||
if ptr == nil do return;
|
||||
win32.heap_free(win32.get_process_heap(), 0, ptr);
|
||||
}
|
||||
|
||||
|
||||
proc exit(code: int) {
|
||||
exit :: proc(code: int) {
|
||||
win32.exit_process(u32(code));
|
||||
}
|
||||
|
||||
|
||||
|
||||
proc current_thread_id() -> int {
|
||||
current_thread_id :: proc() -> int {
|
||||
return int(win32.get_current_thread_id());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
proc _alloc_command_line_arguments() -> []string {
|
||||
proc alloc_ucs2_to_utf8(wstr: ^u16) -> string {
|
||||
var wstr_len = 0;
|
||||
for (wstr+wstr_len)^ != 0 {
|
||||
wstr_len++;
|
||||
}
|
||||
var len = 2*wstr_len-1;
|
||||
var buf = make([]u8, len+1);
|
||||
var str = slice_ptr(wstr, wstr_len+1);
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
alloc_ucs2_to_utf8 :: proc(wstr: ^u16) -> string {
|
||||
wstr_len := 0;
|
||||
for (wstr+wstr_len)^ != 0 do wstr_len += 1;
|
||||
|
||||
var i, j = 0, 0;
|
||||
len := 2*wstr_len-1;
|
||||
buf := make([]u8, len+1);
|
||||
str := mem.slice_ptr(wstr, wstr_len+1);
|
||||
|
||||
i, j := 0, 0;
|
||||
for str[j] != 0 {
|
||||
match {
|
||||
case str[j] < 0x80:
|
||||
if i+1 > len {
|
||||
return "";
|
||||
}
|
||||
buf[i] = u8(str[j]); i++;
|
||||
j++;
|
||||
if i+1 > len do return "";
|
||||
buf[i] = u8(str[j]); i += 1;
|
||||
j += 1;
|
||||
case str[j] < 0x800:
|
||||
if i+2 > len {
|
||||
return "";
|
||||
}
|
||||
buf[i] = u8(0xc0 + (str[j]>>6)); i++;
|
||||
buf[i] = u8(0x80 + (str[j]&0x3f)); i++;
|
||||
j++;
|
||||
if i+2 > len do return "";
|
||||
buf[i] = u8(0xc0 + (str[j]>>6)); i += 1;
|
||||
buf[i] = u8(0x80 + (str[j]&0x3f)); i += 1;
|
||||
j += 1;
|
||||
case 0xd800 <= str[j] && str[j] < 0xdc00:
|
||||
if i+4 > len {
|
||||
return "";
|
||||
}
|
||||
var c = rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000;
|
||||
buf[i] = u8(0xf0 + (c >> 18)); i++;
|
||||
buf[i] = u8(0x80 + ((c >> 12) & 0x3f)); i++;
|
||||
buf[i] = u8(0x80 + ((c >> 6) & 0x3f)); i++;
|
||||
buf[i] = u8(0x80 + ((c ) & 0x3f)); i++;
|
||||
if i+4 > len do return "";
|
||||
c := rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000;
|
||||
buf[i] = u8(0xf0 + (c >> 18)); i += 1;
|
||||
buf[i] = u8(0x80 + ((c >> 12) & 0x3f)); i += 1;
|
||||
buf[i] = u8(0x80 + ((c >> 6) & 0x3f)); i += 1;
|
||||
buf[i] = u8(0x80 + ((c ) & 0x3f)); i += 1;
|
||||
j += 2;
|
||||
case 0xdc00 <= str[j] && str[j] < 0xe000:
|
||||
return "";
|
||||
case:
|
||||
if i+3 > len {
|
||||
return "";
|
||||
}
|
||||
buf[i] = 0xe0 + u8 (str[j] >> 12); i++;
|
||||
buf[i] = 0x80 + u8((str[j] >> 6) & 0x3f); i++;
|
||||
buf[i] = 0x80 + u8((str[j] ) & 0x3f); i++;
|
||||
j++;
|
||||
if i+3 > len do return "";
|
||||
buf[i] = 0xe0 + u8 (str[j] >> 12); i += 1;
|
||||
buf[i] = 0x80 + u8((str[j] >> 6) & 0x3f); i += 1;
|
||||
buf[i] = 0x80 + u8((str[j] ) & 0x3f); i += 1;
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return string(buf[0..<i]);
|
||||
return string(buf[..i]);
|
||||
}
|
||||
|
||||
var arg_count: i32;
|
||||
var arg_list_ptr = win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count);
|
||||
var arg_list = make([]string, arg_count);
|
||||
for _, i in arg_list {
|
||||
arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^);
|
||||
}
|
||||
arg_count: i32;
|
||||
arg_list_ptr := win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count);
|
||||
arg_list := make([]string, int(arg_count));
|
||||
for _, i in arg_list do arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^);
|
||||
return arg_list;
|
||||
}
|
||||
|
||||
|
||||
+156
-165
@@ -5,160 +5,152 @@ foreign_system_library (
|
||||
|
||||
import "strings.odin";
|
||||
|
||||
type (
|
||||
Handle i32;
|
||||
FileTime u64;
|
||||
Errno int;
|
||||
Handle :: i32;
|
||||
FileTime :: u64;
|
||||
Errno :: int;
|
||||
|
||||
AddressSize int;
|
||||
)
|
||||
|
||||
const (
|
||||
O_RDONLY = 0x00000;
|
||||
O_WRONLY = 0x00001;
|
||||
O_RDWR = 0x00002;
|
||||
O_CREAT = 0x00040;
|
||||
O_EXCL = 0x00080;
|
||||
O_NOCTTY = 0x00100;
|
||||
O_TRUNC = 0x00200;
|
||||
O_NONBLOCK = 0x00800;
|
||||
O_APPEND = 0x00400;
|
||||
O_SYNC = 0x01000;
|
||||
O_ASYNC = 0x02000;
|
||||
O_CLOEXEC = 0x80000;
|
||||
)
|
||||
const (
|
||||
SEEK_SET = 0;
|
||||
SEEK_CUR = 1;
|
||||
SEEK_END = 2;
|
||||
SEEK_DATA = 3;
|
||||
SEEK_HOLE = 4;
|
||||
SEEK_MAX = SEEK_HOLE;
|
||||
)
|
||||
O_RDONLY :: 0x00000;
|
||||
O_WRONLY :: 0x00001;
|
||||
O_RDWR :: 0x00002;
|
||||
O_CREAT :: 0x00040;
|
||||
O_EXCL :: 0x00080;
|
||||
O_NOCTTY :: 0x00100;
|
||||
O_TRUNC :: 0x00200;
|
||||
O_NONBLOCK :: 0x00800;
|
||||
O_APPEND :: 0x00400;
|
||||
O_SYNC :: 0x01000;
|
||||
O_ASYNC :: 0x02000;
|
||||
O_CLOEXEC :: 0x80000;
|
||||
|
||||
const (
|
||||
// NOTE(zangent): These are OS specific!
|
||||
// Do not mix these up!
|
||||
RTLD_LAZY = 0x1;
|
||||
RTLD_NOW = 0x2;
|
||||
RTLD_LOCAL = 0x4;
|
||||
RTLD_GLOBAL = 0x8;
|
||||
RTLD_NODELETE = 0x80;
|
||||
RTLD_NOLOAD = 0x10;
|
||||
RTLD_FIRST = 0x100;
|
||||
)
|
||||
|
||||
var args: [dynamic]string;
|
||||
SEEK_SET :: 0;
|
||||
SEEK_CUR :: 1;
|
||||
SEEK_END :: 2;
|
||||
SEEK_DATA :: 3;
|
||||
SEEK_HOLE :: 4;
|
||||
SEEK_MAX :: SEEK_HOLE;
|
||||
|
||||
type _FileTime struct #ordered {
|
||||
seconds: i64,
|
||||
nanoseconds: i64
|
||||
|
||||
|
||||
// NOTE(zangent): These are OS specific!
|
||||
// Do not mix these up!
|
||||
RTLD_LAZY :: 0x1;
|
||||
RTLD_NOW :: 0x2;
|
||||
RTLD_LOCAL :: 0x4;
|
||||
RTLD_GLOBAL :: 0x8;
|
||||
RTLD_NODELETE :: 0x80;
|
||||
RTLD_NOLOAD :: 0x10;
|
||||
RTLD_FIRST :: 0x100;
|
||||
|
||||
|
||||
args: [dynamic]string;
|
||||
|
||||
_FileTime :: struct #ordered {
|
||||
seconds: i64;
|
||||
nanoseconds: i64;
|
||||
}
|
||||
|
||||
type Stat struct #ordered {
|
||||
device_id : i32, // ID of device containing file
|
||||
mode : u16, // Mode of the file
|
||||
nlink : u16, // Number of hard links
|
||||
serial : u64, // File serial number
|
||||
uid : u32, // User ID of the file's owner
|
||||
gid : u32, // Group ID of the file's group
|
||||
rdev : i32, // Device ID, if device
|
||||
Stat :: struct #ordered {
|
||||
device_id: i32; // ID of device containing file
|
||||
mode: u16; // Mode of the file
|
||||
nlink: u16; // Number of hard links
|
||||
serial: u64; // File serial number
|
||||
uid: u32; // User ID of the file's owner
|
||||
gid: u32; // Group ID of the file's group
|
||||
rdev: i32; // Device ID, if device
|
||||
|
||||
last_access : FileTime, // Time of last access
|
||||
modified : FileTime, // Time of last modification
|
||||
status_change : FileTime, // Time of last status change
|
||||
created : FileTime, // Time of creation
|
||||
last_access: FileTime; // Time of last access
|
||||
modified: FileTime; // Time of last modification
|
||||
status_change: FileTime; // Time of last status change
|
||||
created: FileTime; // Time of creation
|
||||
|
||||
size : i64, // Size of the file, in bytes
|
||||
blocks : i64, // Number of blocks allocated for the file
|
||||
block_size: i32, // Optimal blocksize for I/O
|
||||
flags : u32, // User-defined flags for the file
|
||||
gen_num : u32, // File generation number ...?
|
||||
_spare : i32, // RESERVED
|
||||
size: i64; // Size of the file, in bytes
|
||||
blocks: i64; // Number of blocks allocated for the file
|
||||
block_size: i32; // Optimal blocksize for I/O
|
||||
flags: u32; // User-defined flags for the file
|
||||
gen_num: u32; // File generation number ...?
|
||||
_spare: i32; // RESERVED
|
||||
_reserve1,
|
||||
_reserve2 : i64, // RESERVED
|
||||
_reserve2: i64; // RESERVED
|
||||
};
|
||||
|
||||
// File type
|
||||
const (
|
||||
S_IFMT = 0170000; // Type of file mask
|
||||
S_IFIFO = 0010000; // Named pipe (fifo)
|
||||
S_IFCHR = 0020000; // Character special
|
||||
S_IFDIR = 0040000; // Directory
|
||||
S_IFBLK = 0060000; // Block special
|
||||
S_IFREG = 0100000; // Regular
|
||||
S_IFLNK = 0120000; // Symbolic link
|
||||
S_IFSOCK = 0140000; // Socket
|
||||
S_IFMT :: 0170000; // Type of file mask
|
||||
S_IFIFO :: 0010000; // Named pipe (fifo)
|
||||
S_IFCHR :: 0020000; // Character special
|
||||
S_IFDIR :: 0040000; // Directory
|
||||
S_IFBLK :: 0060000; // Block special
|
||||
S_IFREG :: 0100000; // Regular
|
||||
S_IFLNK :: 0120000; // Symbolic link
|
||||
S_IFSOCK :: 0140000; // Socket
|
||||
|
||||
// File mode
|
||||
// Read, write, execute/search by owner
|
||||
S_IRWXU = 0000700; // RWX mask for owner
|
||||
S_IRUSR = 0000400; // R for owner
|
||||
S_IWUSR = 0000200; // W for owner
|
||||
S_IXUSR = 0000100; // X for owner
|
||||
// File mode
|
||||
// Read, write, execute/search by owner
|
||||
S_IRWXU :: 0000700; // RWX mask for owner
|
||||
S_IRUSR :: 0000400; // R for owner
|
||||
S_IWUSR :: 0000200; // W for owner
|
||||
S_IXUSR :: 0000100; // X for owner
|
||||
|
||||
// Read, write, execute/search by group
|
||||
S_IRWXG = 0000070; // RWX mask for group
|
||||
S_IRGRP = 0000040; // R for group
|
||||
S_IWGRP = 0000020; // W for group
|
||||
S_IXGRP = 0000010; // X for group
|
||||
// Read, write, execute/search by group
|
||||
S_IRWXG :: 0000070; // RWX mask for group
|
||||
S_IRGRP :: 0000040; // R for group
|
||||
S_IWGRP :: 0000020; // W for group
|
||||
S_IXGRP :: 0000010; // X for group
|
||||
|
||||
// Read, write, execute/search by others
|
||||
S_IRWXO = 0000007; // RWX mask for other
|
||||
S_IROTH = 0000004; // R for other
|
||||
S_IWOTH = 0000002; // W for other
|
||||
S_IXOTH = 0000001; // X for other
|
||||
// Read, write, execute/search by others
|
||||
S_IRWXO :: 0000007; // RWX mask for other
|
||||
S_IROTH :: 0000004; // R for other
|
||||
S_IWOTH :: 0000002; // W for other
|
||||
S_IXOTH :: 0000001; // X for other
|
||||
|
||||
S_ISUID = 0004000; // Set user id on execution
|
||||
S_ISGID = 0002000; // Set group id on execution
|
||||
S_ISVTX = 0001000; // Directory restrcted delete
|
||||
)
|
||||
S_ISUID :: 0004000; // Set user id on execution
|
||||
S_ISGID :: 0002000; // Set group id on execution
|
||||
S_ISVTX :: 0001000; // Directory restrcted delete
|
||||
|
||||
proc S_ISLNK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFLNK; }
|
||||
proc S_ISREG (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFREG; }
|
||||
proc S_ISDIR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFDIR; }
|
||||
proc S_ISCHR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFCHR; }
|
||||
proc S_ISBLK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFBLK; }
|
||||
proc S_ISFIFO(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFIFO; }
|
||||
proc S_ISSOCK(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFSOCK;}
|
||||
S_ISLNK :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFLNK;
|
||||
S_ISREG :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFREG;
|
||||
S_ISDIR :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFDIR;
|
||||
S_ISCHR :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFCHR;
|
||||
S_ISBLK :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFBLK;
|
||||
S_ISFIFO :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFIFO;
|
||||
S_ISSOCK :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFSOCK;
|
||||
|
||||
const (
|
||||
R_OK = 4; // Test for read permission
|
||||
W_OK = 2; // Test for write permission
|
||||
X_OK = 1; // Test for execute permission
|
||||
F_OK = 0; // Test for file existance
|
||||
)
|
||||
R_OK :: 4; // Test for read permission
|
||||
W_OK :: 2; // Test for write permission
|
||||
X_OK :: 1; // Test for execute permission
|
||||
F_OK :: 0; // Test for file existance
|
||||
|
||||
foreign libc {
|
||||
proc unix_open (path: ^u8, mode: int) -> Handle #link_name "open";
|
||||
proc unix_close (handle: Handle) #link_name "close";
|
||||
proc unix_read (handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "read";
|
||||
proc unix_write (handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "write";
|
||||
proc unix_lseek (fs: Handle, offset: AddressSize, whence: int) -> AddressSize #link_name "lseek";
|
||||
proc unix_gettid() -> u64 #link_name "gettid";
|
||||
proc unix_stat (path: ^u8, stat: ^Stat) -> int #link_name "stat";
|
||||
proc unix_access(path: ^u8, mask: int) -> int #link_name "access";
|
||||
unix_open :: proc(path: ^u8, mode: int) -> Handle #link_name "open" ---;
|
||||
unix_close :: proc(handle: Handle) #link_name "close" ---;
|
||||
unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "read" ---;
|
||||
unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "write" ---;
|
||||
unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int #link_name "lseek" ---;
|
||||
unix_gettid :: proc() -> u64 #link_name "gettid" ---;
|
||||
unix_stat :: proc(path: ^u8, stat: ^Stat) -> int #link_name "stat" ---;
|
||||
unix_access :: proc(path: ^u8, mask: int) -> int #link_name "access" ---;
|
||||
|
||||
proc unix_malloc (size: int) -> rawptr #link_name "malloc";
|
||||
proc unix_free (ptr: rawptr) #link_name "free";
|
||||
proc unix_realloc(ptr: rawptr, size: int) -> rawptr #link_name "realloc";
|
||||
proc unix_getenv (^u8) -> ^u8 #link_name "getenv";
|
||||
unix_malloc :: proc(size: int) -> rawptr #link_name "malloc" ---;
|
||||
unix_free :: proc(ptr: rawptr) #link_name "free" ---;
|
||||
unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #link_name "realloc" ---;
|
||||
unix_getenv :: proc(^u8) -> ^u8 #link_name "getenv" ---;
|
||||
|
||||
proc unix_exit(status: int) #link_name "exit";
|
||||
unix_exit :: proc(status: int) #link_name "exit" ---;
|
||||
}
|
||||
|
||||
foreign dl {
|
||||
proc unix_dlopen (filename: ^u8, flags: int) -> rawptr #link_name "dlopen";
|
||||
proc unix_dlsym (handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym";
|
||||
proc unix_dlclose(handle: rawptr) -> int #link_name "dlclose";
|
||||
proc unix_dlerror() -> ^u8 #link_name "dlerror";
|
||||
unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #link_name "dlopen" ---;
|
||||
unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym" ---;
|
||||
unix_dlclose :: proc(handle: rawptr) -> int #link_name "dlclose" ---;
|
||||
unix_dlerror :: proc() -> ^u8 #link_name "dlerror" ---;
|
||||
}
|
||||
|
||||
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
|
||||
proc open_simple(path: string, mode: int) -> (Handle, Errno) {
|
||||
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
|
||||
|
||||
var cstr = strings.new_c_string(path);
|
||||
var handle = unix_open(cstr, mode);
|
||||
cstr := strings.new_c_string(path);
|
||||
handle := unix_open(cstr, mode);
|
||||
free(cstr);
|
||||
if(handle == -1) {
|
||||
return 0, 1;
|
||||
@@ -167,92 +159,91 @@ proc open_simple(path: string, mode: int) -> (Handle, Errno) {
|
||||
}
|
||||
|
||||
// NOTE(zangent): This is here for compatability reasons. Should this be here?
|
||||
proc open(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
|
||||
open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
|
||||
return open_simple(path, mode);
|
||||
}
|
||||
|
||||
proc close(fd: Handle) {
|
||||
close :: proc(fd: Handle) {
|
||||
unix_close(fd);
|
||||
}
|
||||
|
||||
proc write(fd: Handle, data: []u8) -> (AddressSize, Errno) {
|
||||
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
assert(fd != -1);
|
||||
|
||||
var bytes_written = unix_write(fd, &data[0], len(data));
|
||||
bytes_written := unix_write(fd, &data[0], len(data));
|
||||
if(bytes_written == -1) {
|
||||
return 0, 1;
|
||||
}
|
||||
return bytes_written, 0;
|
||||
}
|
||||
|
||||
proc read(fd: Handle, data: []u8) -> (AddressSize, Errno) {
|
||||
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
assert(fd != -1);
|
||||
|
||||
var bytes_read = unix_read(fd, &data[0], len(data));
|
||||
bytes_read := unix_read(fd, &data[0], len(data));
|
||||
if(bytes_read == -1) {
|
||||
return 0, 1;
|
||||
}
|
||||
return bytes_read, 0;
|
||||
}
|
||||
|
||||
proc seek(fd: Handle, offset: AddressSize, whence: int) -> (AddressSize, Errno) {
|
||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
assert(fd != -1);
|
||||
|
||||
var final_offset = unix_lseek(fd, offset, whence);
|
||||
final_offset := i64(unix_lseek(fd, offset, whence));
|
||||
if(final_offset == -1) {
|
||||
return 0, 1;
|
||||
}
|
||||
return final_offset, 0;
|
||||
}
|
||||
|
||||
proc file_size(fd: Handle) -> (i64, Errno) {
|
||||
var prev, _ = seek(fd, 0, SEEK_CUR);
|
||||
var size, err = seek(fd, 0, SEEK_END);
|
||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
prev, _ := seek(fd, 0, SEEK_CUR);
|
||||
size, err := seek(fd, 0, SEEK_END);
|
||||
seek(fd, prev, SEEK_SET);
|
||||
return size, err;
|
||||
return i64(size), err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// NOTE(bill): Uses startup to initialize it
|
||||
var (
|
||||
stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE);
|
||||
stdout: Handle = 1; // get_std_handle(win32.STD_OUTPUT_HANDLE);
|
||||
stderr: Handle = 2; // get_std_handle(win32.STD_ERROR_HANDLE);
|
||||
)
|
||||
stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE);
|
||||
stdout: Handle = 1; // get_std_handle(win32.STD_OUTPUT_HANDLE);
|
||||
stderr: Handle = 2; // get_std_handle(win32.STD_ERROR_HANDLE);
|
||||
|
||||
/* TODO(zangent): Implement these!
|
||||
proc last_write_time(fd: Handle) -> FileTime {}
|
||||
proc last_write_time_by_name(name: string) -> FileTime {}
|
||||
last_write_time :: proc(fd: Handle) -> FileTime {}
|
||||
last_write_time_by_name :: proc(name: string) -> FileTime {}
|
||||
*/
|
||||
|
||||
proc stat(path: string) -> (Stat, bool) #inline {
|
||||
var s: Stat;
|
||||
var cstr = strings.new_c_string(path);
|
||||
stat :: proc(path: string) -> (Stat, bool) #inline {
|
||||
s: Stat;
|
||||
cstr := strings.new_c_string(path);
|
||||
defer free(cstr);
|
||||
var ret_int = unix_stat(cstr, &s);
|
||||
ret_int := unix_stat(cstr, &s);
|
||||
return s, ret_int==0;
|
||||
}
|
||||
|
||||
proc access(path: string, mask: int) -> bool #inline {
|
||||
var cstr = strings.new_c_string(path);
|
||||
access :: proc(path: string, mask: int) -> bool #inline {
|
||||
cstr := strings.new_c_string(path);
|
||||
defer free(cstr);
|
||||
return unix_access(cstr, mask) == 0;
|
||||
}
|
||||
|
||||
proc heap_alloc(size: int) -> rawptr #inline {
|
||||
heap_alloc :: proc(size: int) -> rawptr #inline {
|
||||
assert(size > 0);
|
||||
return unix_malloc(size);
|
||||
}
|
||||
proc heap_resize(ptr: rawptr, new_size: int) -> rawptr #inline {
|
||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr #inline {
|
||||
return unix_realloc(ptr, new_size);
|
||||
}
|
||||
proc heap_free(ptr: rawptr) #inline {
|
||||
heap_free :: proc(ptr: rawptr) #inline {
|
||||
unix_free(ptr);
|
||||
}
|
||||
|
||||
proc getenv(name: string) -> (string, bool) {
|
||||
var path_str = strings.new_c_string(name);
|
||||
var cstr: ^u8 = unix_getenv(path_str);
|
||||
getenv :: proc(name: string) -> (string, bool) {
|
||||
path_str := strings.new_c_string(name);
|
||||
cstr: ^u8 = unix_getenv(path_str);
|
||||
free(path_str);
|
||||
if(cstr == nil) {
|
||||
return "", false;
|
||||
@@ -260,33 +251,33 @@ proc getenv(name: string) -> (string, bool) {
|
||||
return strings.to_odin_string(cstr), true;
|
||||
}
|
||||
|
||||
proc exit(code: int) #inline {
|
||||
exit :: proc(code: int) #inline {
|
||||
unix_exit(code);
|
||||
}
|
||||
|
||||
|
||||
proc current_thread_id() -> int {
|
||||
current_thread_id :: proc() -> int {
|
||||
// return cast(int) unix_gettid();
|
||||
return 0;
|
||||
}
|
||||
|
||||
proc dlopen(filename: string, flags: int) -> rawptr #inline {
|
||||
var cstr = strings.new_c_string(filename);
|
||||
var handle = unix_dlopen(cstr, flags);
|
||||
dlopen :: proc(filename: string, flags: int) -> rawptr #inline {
|
||||
cstr := strings.new_c_string(filename);
|
||||
handle := unix_dlopen(cstr, flags);
|
||||
free(cstr);
|
||||
return handle;
|
||||
}
|
||||
proc dlsym(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
|
||||
dlsym :: proc(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
|
||||
assert(handle != nil);
|
||||
var cstr = strings.new_c_string(symbol);
|
||||
var proc_handle = unix_dlsym(handle, cstr);
|
||||
cstr := strings.new_c_string(symbol);
|
||||
proc_handle := unix_dlsym(handle, cstr);
|
||||
free(cstr);
|
||||
return proc_handle;
|
||||
}
|
||||
proc dlclose(handle: rawptr) -> bool #inline {
|
||||
dlclose :: proc(handle: rawptr) -> bool #inline {
|
||||
assert(handle != nil);
|
||||
return unix_dlclose(handle) == 0;
|
||||
}
|
||||
proc dlerror() -> string {
|
||||
dlerror :: proc() -> string {
|
||||
return strings.to_odin_string(unix_dlerror());
|
||||
}
|
||||
|
||||
+24
-25
@@ -1,29 +1,28 @@
|
||||
type (
|
||||
Any struct #ordered {
|
||||
data: rawptr,
|
||||
type_info: ^TypeInfo,
|
||||
};
|
||||
Any :: struct #ordered {
|
||||
data: rawptr;
|
||||
type_info: ^TypeInfo;
|
||||
};
|
||||
|
||||
String struct #ordered {
|
||||
data: ^u8,
|
||||
len: int,
|
||||
};
|
||||
String :: struct #ordered {
|
||||
data: ^u8;
|
||||
len: int;
|
||||
};
|
||||
|
||||
Slice struct #ordered {
|
||||
data: rawptr,
|
||||
len: int,
|
||||
cap: int,
|
||||
};
|
||||
Slice :: struct #ordered {
|
||||
data: rawptr;
|
||||
len: int;
|
||||
cap: int;
|
||||
};
|
||||
|
||||
DynamicArray struct #ordered {
|
||||
data: rawptr,
|
||||
len: int,
|
||||
cap: int,
|
||||
allocator: Allocator,
|
||||
};
|
||||
DynamicArray :: struct #ordered {
|
||||
data: rawptr;
|
||||
len: int;
|
||||
cap: int;
|
||||
allocator: Allocator;
|
||||
};
|
||||
|
||||
DynamicMap :: struct #ordered {
|
||||
hashes: [dynamic]int;
|
||||
entries: DynamicArray;
|
||||
};
|
||||
|
||||
DynamicMap struct #ordered {
|
||||
hashes: [dynamic]int,
|
||||
entries: DynamicArray,
|
||||
};
|
||||
)
|
||||
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
bubble_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
assert(f != nil);
|
||||
count := len(array);
|
||||
|
||||
init_j, last_j := 0, count-1;
|
||||
|
||||
for {
|
||||
init_swap, prev_swap := -1, -1;
|
||||
|
||||
for j in init_j..last_j {
|
||||
if f(array[j], array[j+1]) > 0 {
|
||||
array[j], array[j+1] = array[j+1], array[j];
|
||||
prev_swap = j;
|
||||
if init_swap == -1 do init_swap = j;
|
||||
}
|
||||
}
|
||||
|
||||
if prev_swap == -1 do return;
|
||||
|
||||
init_j = max(init_swap-1, 0);
|
||||
last_j = prev_swap;
|
||||
}
|
||||
}
|
||||
|
||||
bubble_sort :: proc(array: $A/[]$T) {
|
||||
count := len(array);
|
||||
|
||||
init_j, last_j := 0, count-1;
|
||||
|
||||
for {
|
||||
init_swap, prev_swap := -1, -1;
|
||||
|
||||
for j in init_j..last_j {
|
||||
if array[j] > array[j+1] {
|
||||
array[j], array[j+1] = array[j+1], array[j];
|
||||
prev_swap = j;
|
||||
if init_swap == -1 do init_swap = j;
|
||||
}
|
||||
}
|
||||
|
||||
if prev_swap == -1 do return;
|
||||
|
||||
init_j = max(init_swap-1, 0);
|
||||
last_j = prev_swap;
|
||||
}
|
||||
}
|
||||
|
||||
quick_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
assert(f != nil);
|
||||
a := array;
|
||||
n := len(a);
|
||||
if n < 2 do return;
|
||||
|
||||
p := a[n/2];
|
||||
i, j := 0, n-1;
|
||||
|
||||
loop: for {
|
||||
for f(a[i], p) < 0 do i += 1;
|
||||
for f(p, a[j]) < 0 do j -= 1;
|
||||
|
||||
if i >= j do break loop;
|
||||
|
||||
a[i], a[j] = a[j], a[i];
|
||||
i += 1;
|
||||
j -= 1;
|
||||
}
|
||||
|
||||
quick_sort(a[0..i], f);
|
||||
quick_sort(a[i..n], f);
|
||||
}
|
||||
|
||||
quick_sort :: proc(array: $A/[]$T) {
|
||||
a := array;
|
||||
n := len(a);
|
||||
if n < 2 do return;
|
||||
|
||||
p := a[n/2];
|
||||
i, j := 0, n-1;
|
||||
|
||||
loop: for {
|
||||
for a[i] < p do i += 1;
|
||||
for p < a[j] do j -= 1;
|
||||
|
||||
if i >= j do break loop;
|
||||
|
||||
a[i], a[j] = a[j], a[i];
|
||||
i += 1;
|
||||
j -= 1;
|
||||
}
|
||||
|
||||
quick_sort(a[0..i]);
|
||||
quick_sort(a[i..n]);
|
||||
}
|
||||
|
||||
_log2 :: proc(n: int) -> int {
|
||||
res := 0;
|
||||
for ; n != 0; n >>= 1 do res += 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
merge_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
merge_slices :: proc(arr1, arr2, out: A, f: proc(T, T) -> int) {
|
||||
N1, N2 := len(arr1), len(arr2);
|
||||
i, j := 0, 0;
|
||||
for k in 0..N1+N2 {
|
||||
if j == N2 || i < N1 && j < N2 && f(arr1[i], arr2[j]) < 0 {
|
||||
out[k] = arr1[i];
|
||||
i += 1;
|
||||
} else {
|
||||
out[k] = arr2[j];
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(f != nil);
|
||||
|
||||
arr1 := array;
|
||||
N := len(arr1);
|
||||
arr2 := make([]T, N);
|
||||
defer free(arr2);
|
||||
|
||||
a, b, m, M := N/2, N, 1, _log2(N);
|
||||
|
||||
for i in 0..M+1 {
|
||||
for j in 0..a {
|
||||
k := 2*j*m;
|
||||
merge_slices(arr1[k..k+m], arr1[k+m..k+m+m], arr2[k..], f);
|
||||
}
|
||||
if N-b > m {
|
||||
k := 2*a*m;
|
||||
merge_slices(arr1[k..k+m], arr1[k+m..k+m+(N-b)&(m-1)], arr2[k..], f);
|
||||
} else {
|
||||
copy(arr2[b..N], arr1[b..N]);
|
||||
}
|
||||
arr1, arr2 = arr2, arr1;
|
||||
m <<= 1;
|
||||
a >>= 1;
|
||||
b = a << uint(i) << 2;
|
||||
}
|
||||
|
||||
if M & 1 == 0 do copy(arr2, arr1);
|
||||
}
|
||||
|
||||
merge_sort :: proc(array: $A/[]$T) {
|
||||
merge_slices :: proc(arr1, arr2, out: A) {
|
||||
N1, N2 := len(arr1), len(arr2);
|
||||
i, j := 0, 0;
|
||||
for k in 0..N1+N2 {
|
||||
if j == N2 || i < N1 && j < N2 && arr1[i] < arr2[j] {
|
||||
out[k] = arr1[i];
|
||||
i += 1;
|
||||
} else {
|
||||
out[k] = arr2[j];
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arr1 := array;
|
||||
N := len(arr1);
|
||||
arr2 := make([]T, N);
|
||||
defer free(arr2);
|
||||
|
||||
a, b, m, M := N/2, N, 1, _log2(N);
|
||||
|
||||
for i in 0..M+1 {
|
||||
for j in 0..a {
|
||||
k := 2*j*m;
|
||||
merge_slices(arr1[k..k+m], arr1[k+m..k+m+m], arr2[k..]);
|
||||
}
|
||||
if N-b > m {
|
||||
k := 2*a*m;
|
||||
merge_slices(arr1[k..k+m], arr1[k+m..k+m+(N-b)&(m-1)], arr2[k..]);
|
||||
} else {
|
||||
copy(arr2[b..N], arr1[b..N]);
|
||||
}
|
||||
arr1, arr2 = arr2, arr1;
|
||||
m <<= 1;
|
||||
a >>= 1;
|
||||
b = a << uint(i) << 2;
|
||||
}
|
||||
|
||||
if M & 1 == 0 do copy(arr2, arr1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
compare_ints :: proc(a, b: int) -> int {
|
||||
match delta := a - b; {
|
||||
case delta < 0: return -1;
|
||||
case delta > 0: return +1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
compare_f32s :: proc(a, b: f32) -> int {
|
||||
match delta := a - b; {
|
||||
case delta < 0: return -1;
|
||||
case delta > 0: return +1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
compare_f64s :: proc(a, b: f64) -> int {
|
||||
match delta := a - b; {
|
||||
case delta < 0: return -1;
|
||||
case delta > 0: return +1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
compare_strings :: proc(a, b: string) -> int {
|
||||
return __string_cmp(a, b);
|
||||
}
|
||||
+150
-160
@@ -1,13 +1,13 @@
|
||||
import . "decimal.odin";
|
||||
|
||||
type IntFlag enum {
|
||||
IntFlag :: enum {
|
||||
Prefix = 1<<0,
|
||||
Plus = 1<<1,
|
||||
Space = 1<<2,
|
||||
}
|
||||
|
||||
|
||||
proc parse_bool(s: string) -> (result: bool, ok: bool) {
|
||||
parse_bool :: proc(s: string) -> (result: bool, ok: bool) {
|
||||
match s {
|
||||
case "1", "t", "T", "true", "TRUE", "True":
|
||||
return true, true;
|
||||
@@ -17,9 +17,9 @@ proc parse_bool(s: string) -> (result: bool, ok: bool) {
|
||||
return false, false;
|
||||
}
|
||||
|
||||
proc _digit_value(r: rune) -> int {
|
||||
var ri = int(r);
|
||||
var v: int = 16;
|
||||
_digit_value :: proc(r: rune) -> int {
|
||||
ri := int(r);
|
||||
v: int = 16;
|
||||
match r {
|
||||
case '0'..'9': v = ri-'0';
|
||||
case 'a'..'z': v = ri-'a'+10;
|
||||
@@ -28,8 +28,8 @@ proc _digit_value(r: rune) -> int {
|
||||
return v;
|
||||
}
|
||||
|
||||
proc parse_i128(s: string) -> i128 {
|
||||
var neg = false;
|
||||
parse_i128 :: proc(s: string) -> i128 {
|
||||
neg := false;
|
||||
if len(s) > 1 {
|
||||
match s[0] {
|
||||
case '-':
|
||||
@@ -41,7 +41,7 @@ proc parse_i128(s: string) -> i128 {
|
||||
}
|
||||
|
||||
|
||||
var base: i128 = 10;
|
||||
base: i128 = 10;
|
||||
if len(s) > 2 && s[0] == '0' {
|
||||
match s[1] {
|
||||
case 'b': base = 2; s = s[2..];
|
||||
@@ -53,13 +53,13 @@ proc parse_i128(s: string) -> i128 {
|
||||
}
|
||||
|
||||
|
||||
var value: i128;
|
||||
value: i128;
|
||||
for r in s {
|
||||
if r == '_' {
|
||||
continue;
|
||||
}
|
||||
|
||||
var v = i128(_digit_value(r));
|
||||
v := i128(_digit_value(r));
|
||||
if v >= base {
|
||||
break;
|
||||
}
|
||||
@@ -67,17 +67,18 @@ proc parse_i128(s: string) -> i128 {
|
||||
value += v;
|
||||
}
|
||||
|
||||
return neg ? -value : value;
|
||||
if neg do return -value;
|
||||
return value;
|
||||
}
|
||||
|
||||
proc parse_u128(s: string) -> u128 {
|
||||
var neg = false;
|
||||
parse_u128 :: proc(s: string) -> u128 {
|
||||
neg := false;
|
||||
if len(s) > 1 && s[0] == '+' {
|
||||
s = s[1..];
|
||||
}
|
||||
|
||||
|
||||
var base = u128(10);
|
||||
base := u128(10);
|
||||
if len(s) > 2 && s[0] == '0' {
|
||||
match s[1] {
|
||||
case 'b': base = 2; s = s[2..];
|
||||
@@ -89,93 +90,80 @@ proc parse_u128(s: string) -> u128 {
|
||||
}
|
||||
|
||||
|
||||
var value: u128;
|
||||
value: u128;
|
||||
for r in s {
|
||||
if r == '_' {
|
||||
continue;
|
||||
}
|
||||
|
||||
var v = u128(_digit_value(r));
|
||||
if v >= base {
|
||||
break;
|
||||
}
|
||||
if r == '_' do continue;
|
||||
v := u128(_digit_value(r));
|
||||
if v >= base do break;
|
||||
value *= base;
|
||||
value += u128(v);
|
||||
}
|
||||
|
||||
return neg ? -value : value;
|
||||
if neg do return -value;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
proc parse_int(s: string) -> int {
|
||||
parse_int :: proc(s: string) -> int {
|
||||
return int(parse_i128(s));
|
||||
}
|
||||
proc parse_uint(s: string, base: int) -> uint {
|
||||
parse_uint :: proc(s: string, base: int) -> uint {
|
||||
return uint(parse_u128(s));
|
||||
}
|
||||
|
||||
proc parse_f64(s: string) -> f64 {
|
||||
var i = 0;
|
||||
parse_f64 :: proc(s: string) -> f64 {
|
||||
i := 0;
|
||||
|
||||
var sign: f64 = 1;
|
||||
sign: f64 = 1;
|
||||
match s[i] {
|
||||
case '-': i++; sign = -1;
|
||||
case '+': i++;
|
||||
case '-': i += 1; sign = -1;
|
||||
case '+': i += 1;
|
||||
}
|
||||
|
||||
var value: f64 = 0;
|
||||
for ; i < len(s); i++ {
|
||||
var r = rune(s[i]);
|
||||
if r == '_' {
|
||||
continue;
|
||||
}
|
||||
var v = _digit_value(r);
|
||||
if v >= 10 {
|
||||
break;
|
||||
}
|
||||
value: f64 = 0;
|
||||
for ; i < len(s); i += 1 {
|
||||
r := rune(s[i]);
|
||||
if r == '_' do continue;
|
||||
|
||||
v := _digit_value(r);
|
||||
if v >= 10 do break;
|
||||
value *= 10;
|
||||
value += f64(v);
|
||||
}
|
||||
|
||||
if s[i] == '.' {
|
||||
var pow10: f64 = 10;
|
||||
i++;
|
||||
pow10: f64 = 10;
|
||||
i += 1;
|
||||
|
||||
for ; i < len(s); i++ {
|
||||
var r = rune(s[i]);
|
||||
if r == '_' {
|
||||
continue;
|
||||
}
|
||||
var v = _digit_value(r);
|
||||
if v >= 10 {
|
||||
break;
|
||||
}
|
||||
for ; i < len(s); i += 1 {
|
||||
r := rune(s[i]);
|
||||
if r == '_' do continue;
|
||||
|
||||
v := _digit_value(r);
|
||||
if v >= 10 do break;
|
||||
value += f64(v)/pow10;
|
||||
pow10 *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
var frac = false;
|
||||
var scale: f64 = 1;
|
||||
frac := false;
|
||||
scale: f64 = 1;
|
||||
|
||||
if s[i] == 'e' || s[i] == 'E' {
|
||||
i++;
|
||||
i += 1;
|
||||
|
||||
match s[i] {
|
||||
case '-': i++; frac = true;
|
||||
case '+': i++;
|
||||
case '-': i += 1; frac = true;
|
||||
case '+': i += 1;
|
||||
}
|
||||
|
||||
var exp: u32 = 0;
|
||||
for ; i < len(s); i++ {
|
||||
var r = rune(s[i]);
|
||||
if r == '_' {
|
||||
continue;
|
||||
}
|
||||
var d = u32(_digit_value(r));
|
||||
if d >= 10 {
|
||||
break;
|
||||
}
|
||||
exp: u32 = 0;
|
||||
for ; i < len(s); i += 1 {
|
||||
r := rune(s[i]);
|
||||
if r == '_' do continue;
|
||||
|
||||
d := u32(_digit_value(r));
|
||||
if d >= 10 do break;
|
||||
exp = exp * 10 + d;
|
||||
}
|
||||
if exp > 308 { exp = 308; }
|
||||
@@ -185,71 +173,75 @@ proc parse_f64(s: string) -> f64 {
|
||||
for exp > 0 { scale *= 10; exp -= 1; }
|
||||
}
|
||||
|
||||
return sign * (frac ? (value/scale) : (value*scale));
|
||||
if frac do return sign * (value/scale);
|
||||
return sign * (value*scale);
|
||||
}
|
||||
|
||||
|
||||
proc append_bool(buf: []u8, b: bool) -> string {
|
||||
var s = b ? "true" : "false";
|
||||
append(buf, ..[]u8(s));
|
||||
append_bool :: proc(buf: []u8, b: bool) -> string {
|
||||
if b {
|
||||
append(&buf, "true");
|
||||
} else {
|
||||
append(&buf, "false");
|
||||
}
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
proc append_uint(buf: []u8, u: u64, base: int) -> string {
|
||||
append_uint :: proc(buf: []u8, u: u64, base: int) -> string {
|
||||
return append_bits(buf, u128(u), base, false, 8*size_of(uint), digits, 0);
|
||||
}
|
||||
proc append_int(buf: []u8, i: i64, base: int) -> string {
|
||||
append_int :: proc(buf: []u8, i: i64, base: int) -> string {
|
||||
return append_bits(buf, u128(i), base, true, 8*size_of(int), digits, 0);
|
||||
}
|
||||
proc itoa(buf: []u8, i: int) -> string { return append_int(buf, i64(i), 10); }
|
||||
itoa :: proc(buf: []u8, i: int) -> string { return append_int(buf, i64(i), 10); }
|
||||
|
||||
proc append_float(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string {
|
||||
append_float :: proc(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string {
|
||||
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
type DecimalSlice struct {
|
||||
digits: []u8,
|
||||
count: int,
|
||||
decimal_point: int,
|
||||
neg: bool,
|
||||
DecimalSlice :: struct {
|
||||
digits: []u8;
|
||||
count: int;
|
||||
decimal_point: int;
|
||||
neg: bool;
|
||||
}
|
||||
|
||||
type Float_Info struct {
|
||||
mantbits: uint,
|
||||
expbits: uint,
|
||||
bias: int,
|
||||
FloatInfo :: struct {
|
||||
mantbits: uint;
|
||||
expbits: uint;
|
||||
bias: int;
|
||||
}
|
||||
|
||||
var (
|
||||
_f16_info = Float_Info{10, 5, -15};
|
||||
_f32_info = Float_Info{23, 8, -127};
|
||||
_f64_info = Float_Info{52, 11, -1023};
|
||||
)
|
||||
|
||||
proc generic_ftoa(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
|
||||
var bits: u64;
|
||||
var flt: ^Float_Info;
|
||||
_f16_info := FloatInfo{10, 5, -15};
|
||||
_f32_info := FloatInfo{23, 8, -127};
|
||||
_f64_info := FloatInfo{52, 11, -1023};
|
||||
|
||||
|
||||
generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
|
||||
bits: u64;
|
||||
flt: ^FloatInfo;
|
||||
match bit_size {
|
||||
case 32:
|
||||
bits = u64(transmute(u32, f32(val)));
|
||||
bits = u64(transmute(u32)f32(val));
|
||||
flt = &_f32_info;
|
||||
case 64:
|
||||
bits = transmute(u64, val);
|
||||
bits = transmute(u64)val;
|
||||
flt = &_f64_info;
|
||||
case:
|
||||
panic("strconv: invalid bit_size");
|
||||
}
|
||||
|
||||
var neg = bits>>(flt.expbits+flt.mantbits) != 0;
|
||||
var exp = int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
|
||||
var mant = bits & (u64(1) << flt.mantbits - 1);
|
||||
neg := bits>>(flt.expbits+flt.mantbits) != 0;
|
||||
exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
|
||||
mant := bits & (u64(1) << flt.mantbits - 1);
|
||||
|
||||
match exp {
|
||||
case 1<<flt.expbits - 1:
|
||||
var s: string;
|
||||
s: string;
|
||||
if mant != 0 {
|
||||
s = "NaN";
|
||||
} else if neg {
|
||||
@@ -257,11 +249,11 @@ proc generic_ftoa(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
|
||||
} else {
|
||||
s = "+Inf";
|
||||
}
|
||||
append(buf, ..[]u8(s));
|
||||
append(&buf, ...cast([]u8)s);
|
||||
return buf;
|
||||
|
||||
case 0: // denormalized
|
||||
exp++;
|
||||
exp += 1;
|
||||
|
||||
case:
|
||||
mant |= u64(1) << flt.mantbits;
|
||||
@@ -269,12 +261,12 @@ proc generic_ftoa(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
|
||||
|
||||
exp += flt.bias;
|
||||
|
||||
var d_: Decimal;
|
||||
var d = &d_;
|
||||
d_: Decimal;
|
||||
d := &d_;
|
||||
assign(d, mant);
|
||||
shift(d, exp - int(flt.mantbits));
|
||||
var digs: DecimalSlice;
|
||||
var shortest = prec < 0;
|
||||
digs: DecimalSlice;
|
||||
shortest := prec < 0;
|
||||
if shortest {
|
||||
round_shortest(d, mant, exp, flt);
|
||||
digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
|
||||
@@ -301,32 +293,32 @@ proc generic_ftoa(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
|
||||
|
||||
|
||||
|
||||
proc format_digits(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: u8) -> []u8 {
|
||||
format_digits :: proc(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: u8) -> []u8 {
|
||||
match fmt {
|
||||
case 'f', 'F':
|
||||
append(buf, neg ? '-' : '+');
|
||||
append(&buf, neg ? '-' : '+');
|
||||
|
||||
// integer, padded with zeros when needed
|
||||
if digs.decimal_point > 0 {
|
||||
var m = min(digs.count, digs.decimal_point);
|
||||
append(buf, ..digs.digits[0..<m]);
|
||||
for ; m < digs.decimal_point; m++ {
|
||||
append(buf, '0');
|
||||
m := min(digs.count, digs.decimal_point);
|
||||
append(&buf, ...digs.digits[..m]);
|
||||
for ; m < digs.decimal_point; m += 1 {
|
||||
append(&buf, '0');
|
||||
}
|
||||
} else {
|
||||
append(buf, '0');
|
||||
append(&buf, '0');
|
||||
}
|
||||
|
||||
|
||||
// fractional part
|
||||
if prec > 0 {
|
||||
append(buf, '.');
|
||||
for i in 0..<prec {
|
||||
var c: u8 = '0';
|
||||
if var j = digs.decimal_point + i; 0 <= j && j < digs.count {
|
||||
append(&buf, '.');
|
||||
for i in 0..prec {
|
||||
c: u8 = '0';
|
||||
if j := digs.decimal_point + i; 0 <= j && j < digs.count {
|
||||
c = digs.digits[j];
|
||||
}
|
||||
append(buf, c);
|
||||
append(&buf, c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,14 +333,12 @@ proc format_digits(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice, pre
|
||||
return buf; // TODO
|
||||
}
|
||||
|
||||
var c: [2]u8;
|
||||
c[0] = '%';
|
||||
c[1] = fmt;
|
||||
append(buf, ..c[..]);
|
||||
c := [2]u8{'%', fmt};
|
||||
append(&buf, ...c[..]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
|
||||
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^FloatInfo) {
|
||||
if mant == 0 { // If mantissa is zero, the number is zero
|
||||
d.count = 0;
|
||||
return;
|
||||
@@ -360,18 +350,18 @@ proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
|
||||
log(2) >~ 0.332
|
||||
332*(dp-nd) >= 100*(exp-mantbits)
|
||||
*/
|
||||
var minexp = flt.bias+1;
|
||||
minexp := flt.bias+1;
|
||||
if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - int(flt.mantbits)) {
|
||||
// Number is already its shortest
|
||||
return;
|
||||
}
|
||||
|
||||
var upper_: Decimal; var upper = &upper_;
|
||||
upper_: Decimal; upper := &upper_;
|
||||
assign(upper, 2*mant - 1);
|
||||
shift(upper, exp - int(flt.mantbits) - 1);
|
||||
|
||||
var mantlo: u64;
|
||||
var explo: int;
|
||||
mantlo: u64;
|
||||
explo: int;
|
||||
if mant > 1<<flt.mantbits || exp == minexp {
|
||||
mantlo = mant-1;
|
||||
explo = exp;
|
||||
@@ -379,25 +369,25 @@ proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
|
||||
mantlo = 2*mant - 1;
|
||||
explo = exp-1;
|
||||
}
|
||||
var lower_: Decimal; var lower = &lower_;
|
||||
lower_: Decimal; lower := &lower_;
|
||||
assign(lower, 2*mantlo + 1);
|
||||
shift(lower, explo - int(flt.mantbits) - 1);
|
||||
|
||||
var inclusive = mant%2 == 0;
|
||||
inclusive := mant%2 == 0;
|
||||
|
||||
for i in 0..<d.count {
|
||||
var l: u8 = '0'; // lower digit
|
||||
for i in 0..d.count {
|
||||
l: u8 = '0'; // lower digit
|
||||
if i < lower.count {
|
||||
l = lower.digits[i];
|
||||
}
|
||||
var m = d.digits[i]; // middle digit
|
||||
var u: u8 = '0'; // upper digit
|
||||
m := d.digits[i]; // middle digit
|
||||
u: u8 = '0'; // upper digit
|
||||
if i < upper.count {
|
||||
u = upper.digits[i];
|
||||
}
|
||||
|
||||
var ok_round_down = l != m || inclusive && i+1 == lower.count;
|
||||
var ok_round_up = m != u && (inclusive || m+1 < u || i+1 < upper.count);
|
||||
ok_round_down := l != m || inclusive && i+1 == lower.count;
|
||||
ok_round_up := m != u && (inclusive || m+1 < u || i+1 < upper.count);
|
||||
|
||||
if (ok_round_down && ok_round_up) {
|
||||
round(d, i+1);
|
||||
@@ -415,36 +405,36 @@ proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
|
||||
|
||||
}
|
||||
|
||||
const MAX_BASE = 32;
|
||||
var digits = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
MAX_BASE :: 32;
|
||||
digits := "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
|
||||
proc is_integer_negative(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
|
||||
var neg = false;
|
||||
is_integer_negative :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
|
||||
neg := false;
|
||||
if is_signed {
|
||||
match bit_size {
|
||||
case 8:
|
||||
var i = i8(u);
|
||||
i := i8(u);
|
||||
neg = i < 0;
|
||||
if neg { i = -i; }
|
||||
u = u128(i);
|
||||
case 16:
|
||||
var i = i16(u);
|
||||
i := i16(u);
|
||||
neg = i < 0;
|
||||
if neg { i = -i; }
|
||||
u = u128(i);
|
||||
case 32:
|
||||
var i = i32(u);
|
||||
i := i32(u);
|
||||
neg = i < 0;
|
||||
if neg { i = -i; }
|
||||
u = u128(i);
|
||||
case 64:
|
||||
var i = i64(u);
|
||||
i := i64(u);
|
||||
neg = i < 0;
|
||||
if neg { i = -i; }
|
||||
u = u128(i);
|
||||
case 128:
|
||||
var i = i128(u);
|
||||
i := i128(u);
|
||||
neg = i < 0;
|
||||
if neg { i = -i; }
|
||||
u = u128(i);
|
||||
@@ -455,46 +445,46 @@ proc is_integer_negative(u: u128, is_signed: bool, bit_size: int) -> (unsigned:
|
||||
return u, neg;
|
||||
}
|
||||
|
||||
proc append_bits(buf: []u8, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: IntFlag) -> string {
|
||||
append_bits :: proc(buf: []u8, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: IntFlag) -> string {
|
||||
if base < 2 || base > MAX_BASE {
|
||||
panic("strconv: illegal base passed to append_bits");
|
||||
}
|
||||
|
||||
var neg: bool;
|
||||
var a: [129]u8;
|
||||
var i = len(a);
|
||||
neg: bool;
|
||||
a: [129]u8;
|
||||
i := len(a);
|
||||
u, neg = is_integer_negative(u, is_signed, bit_size);
|
||||
var b = u128(base);
|
||||
b := u128(base);
|
||||
for u >= b {
|
||||
i--; a[i] = digits[uint(u % b)];
|
||||
i-=1; a[i] = digits[uint(u % b)];
|
||||
u /= b;
|
||||
}
|
||||
i--; a[i] = digits[uint(u % b)];
|
||||
i-=1; a[i] = digits[uint(u % b)];
|
||||
|
||||
if flags&IntFlag.Prefix != 0 {
|
||||
var ok = true;
|
||||
ok := true;
|
||||
match base {
|
||||
case 2: i--; a[i] = 'b';
|
||||
case 8: i--; a[i] = 'o';
|
||||
case 10: i--; a[i] = 'd';
|
||||
case 12: i--; a[i] = 'z';
|
||||
case 16: i--; a[i] = 'x';
|
||||
case 2: i-=1; a[i] = 'b';
|
||||
case 8: i-=1; a[i] = 'o';
|
||||
case 10: i-=1; a[i] = 'd';
|
||||
case 12: i-=1; a[i] = 'z';
|
||||
case 16: i-=1; a[i] = 'x';
|
||||
case: ok = false;
|
||||
}
|
||||
if ok {
|
||||
i--; a[i] = '0';
|
||||
i-=1; a[i] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if neg {
|
||||
i--; a[i] = '-';
|
||||
i-=1; a[i] = '-';
|
||||
} else if flags&IntFlag.Plus != 0 {
|
||||
i--; a[i] = '+';
|
||||
i-=1; a[i] = '+';
|
||||
} else if flags&IntFlag.Space != 0 {
|
||||
i--; a[i] = ' ';
|
||||
i-=1; a[i] = ' ';
|
||||
}
|
||||
|
||||
append(buf, ..a[i..]);
|
||||
append(&buf, ...a[i..]);
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
|
||||
+14
-13
@@ -1,21 +1,22 @@
|
||||
proc new_string(s: string) -> string {
|
||||
var c = make([]u8, len(s)+1);
|
||||
copy(c, []u8(s));
|
||||
import "mem.odin";
|
||||
|
||||
new_string :: proc(s: string) -> string {
|
||||
c := make([]u8, len(s)+1);
|
||||
copy(c, cast([]u8)s);
|
||||
c[len(s)] = 0;
|
||||
return string(c[0..<len(s)]);
|
||||
return string(c[..len(s)]);
|
||||
}
|
||||
|
||||
proc new_c_string(s: string) -> ^u8 {
|
||||
var c = make([]u8, len(s)+1);
|
||||
copy(c, []u8(s));
|
||||
new_c_string :: proc(s: string) -> ^u8 {
|
||||
c := make([]u8, len(s)+1);
|
||||
copy(c, cast([]u8)s);
|
||||
c[len(s)] = 0;
|
||||
return &c[0];
|
||||
}
|
||||
|
||||
proc to_odin_string(c: ^u8) -> string {
|
||||
var len = 0;
|
||||
for (c+len)^ != 0 {
|
||||
len++;
|
||||
}
|
||||
return string(slice_ptr(c, len));
|
||||
to_odin_string :: proc(c: ^u8) -> string {
|
||||
if c == nil do return "";
|
||||
len := 0;
|
||||
for (c+len)^ != 0 do len+=1;
|
||||
return string(mem.slice_ptr(c, len));
|
||||
}
|
||||
|
||||
+26
-26
@@ -3,67 +3,67 @@ import (
|
||||
"os.odin";
|
||||
)
|
||||
|
||||
type Semaphore struct {
|
||||
// _handle: win32.Handle,
|
||||
Semaphore :: struct {
|
||||
// _handle: win32.Handle;
|
||||
}
|
||||
|
||||
type Mutex struct {
|
||||
_semaphore: Semaphore,
|
||||
_counter: i32,
|
||||
_owner: i32,
|
||||
_recursion: i32,
|
||||
Mutex :: struct {
|
||||
_semaphore: Semaphore;
|
||||
_counter: i32;
|
||||
_owner: i32;
|
||||
_recursion: i32;
|
||||
}
|
||||
|
||||
proc current_thread_id() -> i32 {
|
||||
current_thread_id :: proc() -> i32 {
|
||||
return i32(os.current_thread_id());
|
||||
}
|
||||
|
||||
proc semaphore_init(s: ^Semaphore) {
|
||||
semaphore_init :: proc(s: ^Semaphore) {
|
||||
// s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
|
||||
}
|
||||
|
||||
proc semaphore_destroy(s: ^Semaphore) {
|
||||
semaphore_destroy :: proc(s: ^Semaphore) {
|
||||
// win32.CloseHandle(s._handle);
|
||||
}
|
||||
|
||||
proc semaphore_post(s: ^Semaphore, count: int) {
|
||||
semaphore_post :: proc(s: ^Semaphore, count: int) {
|
||||
// win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
|
||||
}
|
||||
|
||||
proc semaphore_release(s: ^Semaphore) #inline {
|
||||
semaphore_release :: proc(s: ^Semaphore) #inline {
|
||||
semaphore_post(s, 1);
|
||||
}
|
||||
|
||||
proc semaphore_wait(s: ^Semaphore) {
|
||||
semaphore_wait :: proc(s: ^Semaphore) {
|
||||
// win32.WaitForSingleObject(s._handle, win32.INFINITE);
|
||||
}
|
||||
|
||||
|
||||
proc mutex_init(m: ^Mutex) {
|
||||
mutex_init :: proc(m: ^Mutex) {
|
||||
atomics.store(&m._counter, 0);
|
||||
atomics.store(&m._owner, current_thread_id());
|
||||
semaphore_init(&m._semaphore);
|
||||
m._recursion = 0;
|
||||
}
|
||||
proc mutex_destroy(m: ^Mutex) {
|
||||
mutex_destroy :: proc(m: ^Mutex) {
|
||||
semaphore_destroy(&m._semaphore);
|
||||
}
|
||||
proc mutex_lock(m: ^Mutex) {
|
||||
var thread_id = current_thread_id();
|
||||
mutex_lock :: proc(m: ^Mutex) {
|
||||
thread_id := current_thread_id();
|
||||
if atomics.fetch_add(&m._counter, 1) > 0 {
|
||||
if thread_id != atomics.load(&m._owner) {
|
||||
semaphore_wait(&m._semaphore);
|
||||
}
|
||||
}
|
||||
atomics.store(&m._owner, thread_id);
|
||||
m._recursion++;
|
||||
m._recursion += 1;
|
||||
}
|
||||
proc mutex_try_lock(m: ^Mutex) -> bool {
|
||||
var thread_id = current_thread_id();
|
||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
thread_id := current_thread_id();
|
||||
if atomics.load(&m._owner) == thread_id {
|
||||
atomics.fetch_add(&m._counter, 1);
|
||||
} else {
|
||||
var expected: i32 = 0;
|
||||
expected: i32 = 0;
|
||||
if atomics.load(&m._counter) != 0 {
|
||||
return false;
|
||||
}
|
||||
@@ -72,15 +72,15 @@ proc mutex_try_lock(m: ^Mutex) -> bool {
|
||||
}
|
||||
atomics.store(&m._owner, thread_id);
|
||||
}
|
||||
m._recursion++;
|
||||
m._recursion += 1;
|
||||
return true;
|
||||
}
|
||||
proc mutex_unlock(m: ^Mutex) {
|
||||
var recursion: i32;
|
||||
var thread_id = current_thread_id();
|
||||
mutex_unlock :: proc(m: ^Mutex) {
|
||||
recursion: i32;
|
||||
thread_id := current_thread_id();
|
||||
assert(thread_id == atomics.load(&m._owner));
|
||||
|
||||
m._recursion--;
|
||||
m._recursion -= 1;
|
||||
recursion = m._recursion;
|
||||
if recursion == 0 {
|
||||
atomics.store(&m._owner, thread_id);
|
||||
|
||||
+53
-24
@@ -3,51 +3,80 @@ import (
|
||||
"atomics.odin";
|
||||
)
|
||||
|
||||
type Semaphore struct {
|
||||
_handle: win32.Handle,
|
||||
Semaphore :: struct {
|
||||
_handle: win32.Handle;
|
||||
}
|
||||
|
||||
type Mutex struct {
|
||||
_semaphore: Semaphore,
|
||||
_counter: i32,
|
||||
_owner: i32,
|
||||
_recursion: i32,
|
||||
/*
|
||||
Mutex :: struct {
|
||||
_semaphore: Semaphore;
|
||||
_counter: i32;
|
||||
_owner: i32;
|
||||
_recursion: i32;
|
||||
}
|
||||
*/
|
||||
|
||||
Mutex :: struct {
|
||||
_critical_section: win32.CriticalSection;
|
||||
}
|
||||
|
||||
proc current_thread_id() -> i32 {
|
||||
current_thread_id :: proc() -> i32 {
|
||||
return i32(win32.get_current_thread_id());
|
||||
}
|
||||
|
||||
proc semaphore_init(s: ^Semaphore) {
|
||||
semaphore_init :: proc(s: ^Semaphore) {
|
||||
s._handle = win32.create_semaphore_a(nil, 0, 1<<31-1, nil);
|
||||
}
|
||||
|
||||
proc semaphore_destroy(s: ^Semaphore) {
|
||||
semaphore_destroy :: proc(s: ^Semaphore) {
|
||||
win32.close_handle(s._handle);
|
||||
}
|
||||
|
||||
proc semaphore_post(s: ^Semaphore, count: int) {
|
||||
semaphore_post :: proc(s: ^Semaphore, count: int) {
|
||||
win32.release_semaphore(s._handle, i32(count), nil);
|
||||
}
|
||||
|
||||
proc semaphore_release(s: ^Semaphore) #inline { semaphore_post(s, 1); }
|
||||
semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
|
||||
|
||||
proc semaphore_wait(s: ^Semaphore) {
|
||||
semaphore_wait :: proc(s: ^Semaphore) {
|
||||
win32.wait_for_single_object(s._handle, win32.INFINITE);
|
||||
}
|
||||
|
||||
|
||||
proc mutex_init(m: ^Mutex) {
|
||||
mutex_init :: proc(m: ^Mutex, spin_count := 0) {
|
||||
win32.initialize_critical_section_and_spin_count(&m._critical_section, u32(spin_count));
|
||||
}
|
||||
|
||||
mutex_destroy :: proc(m: ^Mutex) {
|
||||
win32.delete_critical_section(&m._critical_section);
|
||||
}
|
||||
|
||||
mutex_lock :: proc(m: ^Mutex) {
|
||||
win32.enter_critical_section(&m._critical_section);
|
||||
}
|
||||
|
||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
return win32.try_enter_critical_section(&m._critical_section) != 0;
|
||||
}
|
||||
|
||||
mutex_unlock :: proc(m: ^Mutex) {
|
||||
win32.leave_critical_section(&m._critical_section);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
mutex_init :: proc(m: ^Mutex) {
|
||||
atomics.store(&m._counter, 0);
|
||||
atomics.store(&m._owner, current_thread_id());
|
||||
semaphore_init(&m._semaphore);
|
||||
m._recursion = 0;
|
||||
}
|
||||
proc mutex_destroy(m: ^Mutex) {
|
||||
mutex_destroy :: proc(m: ^Mutex) {
|
||||
semaphore_destroy(&m._semaphore);
|
||||
}
|
||||
proc mutex_lock(m: ^Mutex) {
|
||||
var thread_id = current_thread_id();
|
||||
mutex_lock :: proc(m: ^Mutex) {
|
||||
thread_id := current_thread_id();
|
||||
if atomics.fetch_add(&m._counter, 1) > 0 {
|
||||
if thread_id != atomics.load(&m._owner) {
|
||||
semaphore_wait(&m._semaphore);
|
||||
@@ -56,12 +85,12 @@ proc mutex_lock(m: ^Mutex) {
|
||||
atomics.store(&m._owner, thread_id);
|
||||
m._recursion++;
|
||||
}
|
||||
proc mutex_try_lock(m: ^Mutex) -> bool {
|
||||
var thread_id = current_thread_id();
|
||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
thread_id := current_thread_id();
|
||||
if atomics.load(&m._owner) == thread_id {
|
||||
atomics.fetch_add(&m._counter, 1);
|
||||
} else {
|
||||
var expected: i32 = 0;
|
||||
expected: i32 = 0;
|
||||
if atomics.load(&m._counter) != 0 {
|
||||
return false;
|
||||
}
|
||||
@@ -73,9 +102,9 @@ proc mutex_try_lock(m: ^Mutex) -> bool {
|
||||
m._recursion++;
|
||||
return true;
|
||||
}
|
||||
proc mutex_unlock(m: ^Mutex) {
|
||||
var recursion: i32;
|
||||
var thread_id = current_thread_id();
|
||||
mutex_unlock :: proc(m: ^Mutex) {
|
||||
recursion: i32;
|
||||
thread_id := current_thread_id();
|
||||
assert(thread_id == atomics.load(&m._owner));
|
||||
|
||||
m._recursion--;
|
||||
@@ -90,4 +119,4 @@ proc mutex_unlock(m: ^Mutex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
+66
-73
@@ -1,90 +1,83 @@
|
||||
foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
|
||||
import . "windows.odin";
|
||||
|
||||
const (
|
||||
CONTEXT_MAJOR_VERSION_ARB = 0x2091;
|
||||
CONTEXT_MINOR_VERSION_ARB = 0x2092;
|
||||
CONTEXT_FLAGS_ARB = 0x2094;
|
||||
CONTEXT_PROFILE_MASK_ARB = 0x9126;
|
||||
CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x0002;
|
||||
CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001;
|
||||
CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002;
|
||||
)
|
||||
|
||||
type (
|
||||
Hglrc Handle;
|
||||
ColorRef u32;
|
||||
CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
|
||||
CONTEXT_MINOR_VERSION_ARB :: 0x2092;
|
||||
CONTEXT_FLAGS_ARB :: 0x2094;
|
||||
CONTEXT_PROFILE_MASK_ARB :: 0x9126;
|
||||
CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002;
|
||||
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001;
|
||||
CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x00000002;
|
||||
|
||||
LayerPlaneDescriptor struct {
|
||||
size: u16,
|
||||
version: u16,
|
||||
flags: u32,
|
||||
pixel_type: u8,
|
||||
color_bits: u8,
|
||||
red_bits: u8,
|
||||
red_shift: u8,
|
||||
green_bits: u8,
|
||||
green_shift: u8,
|
||||
blue_bits: u8,
|
||||
blue_shift: u8,
|
||||
alpha_bits: u8,
|
||||
alpha_shift: u8,
|
||||
accum_bits: u8,
|
||||
accum_red_bits: u8,
|
||||
accum_green_bits: u8,
|
||||
accum_blue_bits: u8,
|
||||
accum_alpha_bits: u8,
|
||||
depth_bits: u8,
|
||||
stencil_bits: u8,
|
||||
aux_buffers: u8,
|
||||
layer_type: u8,
|
||||
reserved: u8,
|
||||
transparent: ColorRef,
|
||||
}
|
||||
Hglrc :: Handle;
|
||||
ColorRef :: u32;
|
||||
|
||||
PointFloat struct {
|
||||
x, y: f32,
|
||||
}
|
||||
LayerPlaneDescriptor :: struct {
|
||||
size: u16;
|
||||
version: u16;
|
||||
flags: u32;
|
||||
pixel_type: u8;
|
||||
color_bits: u8;
|
||||
red_bits: u8;
|
||||
red_shift: u8;
|
||||
green_bits: u8;
|
||||
green_shift: u8;
|
||||
blue_bits: u8;
|
||||
blue_shift: u8;
|
||||
alpha_bits: u8;
|
||||
alpha_shift: u8;
|
||||
accum_bits: u8;
|
||||
accum_red_bits: u8;
|
||||
accum_green_bits: u8;
|
||||
accum_blue_bits: u8;
|
||||
accum_alpha_bits: u8;
|
||||
depth_bits: u8;
|
||||
stencil_bits: u8;
|
||||
aux_buffers: u8;
|
||||
layer_type: u8;
|
||||
reserved: u8;
|
||||
transparent: ColorRef;
|
||||
}
|
||||
|
||||
Glyph_MetricsFloat struct {
|
||||
black_box_x: f32,
|
||||
black_box_y: f32,
|
||||
glyph_origin: PointFloat,
|
||||
cell_inc_x: f32,
|
||||
cell_inc_y: f32,
|
||||
}
|
||||
)
|
||||
PointFloat :: struct {x, y: f32};
|
||||
|
||||
type (
|
||||
CreateContextAttribsARBType proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
|
||||
ChoosePixelFormatARBType proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c;
|
||||
SwapIntervalEXTType proc(interval: i32) -> bool #cc_c;
|
||||
GetExtensionsStringARBType proc(Hdc) -> ^u8 #cc_c;
|
||||
)
|
||||
Glyph_MetricsFloat :: struct {
|
||||
black_box_x: f32;
|
||||
black_box_y: f32;
|
||||
glyph_origin: PointFloat;
|
||||
cell_inc_x: f32;
|
||||
cell_inc_y: f32;
|
||||
}
|
||||
|
||||
var (
|
||||
CreateContextAttribsARBType :: proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
|
||||
ChoosePixelFormatARBType :: proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c;
|
||||
SwapIntervalEXTType :: proc(interval: i32) -> bool #cc_c;
|
||||
GetExtensionsStringARBType :: proc(Hdc) -> ^u8 #cc_c;
|
||||
|
||||
// Procedures
|
||||
create_context_attribs_arb: CreateContextAttribsARBType;
|
||||
choose_pixel_format_arb: ChoosePixelFormatARBType;
|
||||
swap_interval_ext: SwapIntervalEXTType;
|
||||
get_extensions_string_arb: GetExtensionsStringARBType;
|
||||
)
|
||||
|
||||
|
||||
|
||||
foreign opengl32 {
|
||||
proc create_context (hdc: Hdc) -> Hglrc #link_name "wglCreateContext";
|
||||
proc make_current (hdc: Hdc, hglrc: Hglrc) -> Bool #link_name "wglMakeCurrent";
|
||||
proc get_proc_address (c_str: ^u8) -> Proc #link_name "wglGetProcAddress";
|
||||
proc delete_context (hglrc: Hglrc) -> Bool #link_name "wglDeleteContext";
|
||||
proc copy_context (src, dst: Hglrc, mask: u32) -> Bool #link_name "wglCopyContext";
|
||||
proc create_layer_context (hdc: Hdc, layer_plane: i32) -> Hglrc #link_name "wglCreateLayerContext";
|
||||
proc describe_layer_plane (hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^LayerPlaneDescriptor) -> Bool #link_name "wglDescribeLayerPlane";
|
||||
proc get_current_context () -> Hglrc #link_name "wglGetCurrentContext";
|
||||
proc get_current_dc () -> Hdc #link_name "wglGetCurrentDC";
|
||||
proc get_layer_palette_entries(hdc: Hdc, layer_plane, start, entries: i32, cr: ^ColorRef) -> i32 #link_name "wglGetLayerPaletteEntries";
|
||||
proc realize_layer_palette (hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool #link_name "wglRealizeLayerPalette";
|
||||
proc set_layer_palette_entries(hdc: Hdc, layer_plane, start, entries: i32, cr: ^ColorRef) -> i32 #link_name "wglSetLayerPaletteEntries";
|
||||
proc share_lists (hglrc1, hglrc2: Hglrc) -> Bool #link_name "wglShareLists";
|
||||
proc swap_layer_buffers (hdc: Hdc, planes: u32) -> Bool #link_name "wglSwapLayerBuffers";
|
||||
proc use_font_bitmaps (hdc: Hdc, first, count, list_base: u32) -> Bool #link_name "wglUseFontBitmaps";
|
||||
proc use_font_outlines (hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_MetricsFloat) -> Bool #link_name "wglUseFontOutlines";
|
||||
create_context :: proc(hdc: Hdc) -> Hglrc #link_name "wglCreateContext" ---;
|
||||
make_current :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool #link_name "wglMakeCurrent" ---;
|
||||
get_proc_address :: proc(c_str: ^u8) -> rawptr #link_name "wglGetProcAddress" ---;
|
||||
delete_context :: proc(hglrc: Hglrc) -> Bool #link_name "wglDeleteContext" ---;
|
||||
copy_context :: proc(src, dst: Hglrc, mask: u32) -> Bool #link_name "wglCopyContext" ---;
|
||||
create_layer_context :: proc(hdc: Hdc, layer_plane: i32) -> Hglrc #link_name "wglCreateLayerContext" ---;
|
||||
describe_layer_plane :: proc(hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^LayerPlaneDescriptor) -> Bool #link_name "wglDescribeLayerPlane" ---;
|
||||
get_current_context :: proc() -> Hglrc #link_name "wglGetCurrentContext" ---;
|
||||
get_current_dc :: proc() -> Hdc #link_name "wglGetCurrentDC" ---;
|
||||
get_layer_palette_entries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^ColorRef) -> i32 #link_name "wglGetLayerPaletteEntries" ---;
|
||||
realize_layer_palette :: proc(hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool #link_name "wglRealizeLayerPalette" ---;
|
||||
set_layer_palette_entries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^ColorRef) -> i32 #link_name "wglSetLayerPaletteEntries" ---;
|
||||
share_lists :: proc(hglrc1, hglrc2: Hglrc) -> Bool #link_name "wglShareLists" ---;
|
||||
swap_layer_buffers :: proc(hdc: Hdc, planes: u32) -> Bool #link_name "wglSwapLayerBuffers" ---;
|
||||
use_font_bitmaps :: proc(hdc: Hdc, first, count, list_base: u32) -> Bool #link_name "wglUseFontBitmaps" ---;
|
||||
use_font_outlines :: proc(hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_MetricsFloat) -> Bool #link_name "wglUseFontOutlines" ---;
|
||||
}
|
||||
|
||||
+409
-380
@@ -6,119 +6,115 @@ foreign_system_library (
|
||||
"shell32.lib" when ODIN_OS == "windows";
|
||||
)
|
||||
|
||||
type (
|
||||
Handle rawptr;
|
||||
Hwnd Handle;
|
||||
Hdc Handle;
|
||||
Hinstance Handle;
|
||||
Hicon Handle;
|
||||
Hcursor Handle;
|
||||
Hmenu Handle;
|
||||
Hbrush Handle;
|
||||
Hgdiobj Handle;
|
||||
Hmodule Handle;
|
||||
Hmonitor Handle;
|
||||
Wparam uint;
|
||||
Lparam int;
|
||||
Lresult int;
|
||||
WndProc proc(Hwnd, u32, Wparam, Lparam) -> Lresult #cc_c;
|
||||
)
|
||||
Handle :: rawptr;
|
||||
Hwnd :: Handle;
|
||||
Hdc :: Handle;
|
||||
Hinstance :: Handle;
|
||||
Hicon :: Handle;
|
||||
Hcursor :: Handle;
|
||||
Hmenu :: Handle;
|
||||
Hbrush :: Handle;
|
||||
Hgdiobj :: Handle;
|
||||
Hmodule :: Handle;
|
||||
Hmonitor :: Handle;
|
||||
Wparam :: uint;
|
||||
Lparam :: int;
|
||||
Lresult :: int;
|
||||
WndProc :: proc(Hwnd, u32, Wparam, Lparam) -> Lresult #cc_c;
|
||||
|
||||
type Bool i32;
|
||||
const (
|
||||
FALSE: Bool = 0;
|
||||
TRUE = 1;
|
||||
)
|
||||
Bool :: i32;
|
||||
FALSE: Bool : 0;
|
||||
TRUE: Bool : 1;
|
||||
|
||||
type Point struct #ordered {
|
||||
x, y: i32,
|
||||
Point :: struct #ordered {
|
||||
x, y: i32;
|
||||
}
|
||||
|
||||
type WndClassExA struct #ordered {
|
||||
size, style: u32,
|
||||
wnd_proc: WndProc,
|
||||
cls_extra, wnd_extra: i32,
|
||||
instance: Hinstance,
|
||||
icon: Hicon,
|
||||
cursor: Hcursor,
|
||||
background: Hbrush,
|
||||
menu_name, class_name: ^u8,
|
||||
sm: Hicon,
|
||||
WndClassExA :: struct #ordered {
|
||||
size, style: u32;
|
||||
wnd_proc: WndProc;
|
||||
cls_extra, wnd_extra: i32;
|
||||
instance: Hinstance;
|
||||
icon: Hicon;
|
||||
cursor: Hcursor;
|
||||
background: Hbrush;
|
||||
menu_name, class_name: ^u8;
|
||||
sm: Hicon;
|
||||
}
|
||||
|
||||
type Msg struct #ordered {
|
||||
hwnd: Hwnd,
|
||||
message: u32,
|
||||
wparam: Wparam,
|
||||
lparam: Lparam,
|
||||
time: u32,
|
||||
pt: Point,
|
||||
Msg :: struct #ordered {
|
||||
hwnd: Hwnd;
|
||||
message: u32;
|
||||
wparam: Wparam;
|
||||
lparam: Lparam;
|
||||
time: u32;
|
||||
pt: Point;
|
||||
}
|
||||
|
||||
type Rect struct #ordered {
|
||||
left: i32,
|
||||
top: i32,
|
||||
right: i32,
|
||||
bottom: i32,
|
||||
Rect :: struct #ordered {
|
||||
left: i32;
|
||||
top: i32;
|
||||
right: i32;
|
||||
bottom: i32;
|
||||
}
|
||||
|
||||
type Filetime struct #ordered {
|
||||
lo, hi: u32,
|
||||
Filetime :: struct #ordered {
|
||||
lo, hi: u32;
|
||||
}
|
||||
|
||||
type Systemtime struct #ordered {
|
||||
year, month: u16,
|
||||
day_of_week, day: u16,
|
||||
hour, minute, second, millisecond: u16,
|
||||
Systemtime :: struct #ordered {
|
||||
year, month: u16;
|
||||
day_of_week, day: u16;
|
||||
hour, minute, second, millisecond: u16;
|
||||
}
|
||||
|
||||
type ByHandleFileInformation struct #ordered {
|
||||
file_attributes: u32,
|
||||
ByHandleFileInformation :: struct #ordered {
|
||||
file_attributes: u32;
|
||||
creation_time,
|
||||
last_access_time,
|
||||
last_write_time: Filetime,
|
||||
last_write_time: Filetime;
|
||||
volume_serial_number,
|
||||
file_size_high,
|
||||
file_size_low,
|
||||
number_of_links,
|
||||
file_index_high,
|
||||
file_index_low: u32,
|
||||
file_index_low: u32;
|
||||
}
|
||||
|
||||
type FileAttributeData struct #ordered {
|
||||
file_attributes: u32,
|
||||
FileAttributeData :: struct #ordered {
|
||||
file_attributes: u32;
|
||||
creation_time,
|
||||
last_access_time,
|
||||
last_write_time: Filetime,
|
||||
last_write_time: Filetime;
|
||||
file_size_high,
|
||||
file_size_low: u32,
|
||||
file_size_low: u32;
|
||||
}
|
||||
|
||||
type FindData struct #ordered {
|
||||
file_attributes: u32,
|
||||
creation_time: Filetime,
|
||||
last_access_time: Filetime,
|
||||
last_write_time: Filetime,
|
||||
file_size_high: u32,
|
||||
file_size_low: u32,
|
||||
reserved0: u32,
|
||||
reserved1: u32,
|
||||
file_name: [MAX_PATH]u8,
|
||||
alternate_file_name: [14]u8,
|
||||
FindData :: struct #ordered {
|
||||
file_attributes: u32;
|
||||
creation_time: Filetime;
|
||||
last_access_time: Filetime;
|
||||
last_write_time: Filetime;
|
||||
file_size_high: u32;
|
||||
file_size_low: u32;
|
||||
reserved0: u32;
|
||||
reserved1: u32;
|
||||
file_name: [MAX_PATH]u8;
|
||||
alternate_file_name: [14]u8;
|
||||
}
|
||||
|
||||
type Security_Attributes struct #ordered {
|
||||
length: u32,
|
||||
security_descriptor: rawptr,
|
||||
inherit_handle: Bool,
|
||||
SecurityAttributes :: struct #ordered {
|
||||
length: u32;
|
||||
security_descriptor: rawptr;
|
||||
inherit_handle: Bool;
|
||||
}
|
||||
|
||||
|
||||
|
||||
type PixelFormatDescriptor struct #ordered {
|
||||
PixelFormatDescriptor :: struct #ordered {
|
||||
size,
|
||||
version,
|
||||
flags: u32,
|
||||
flags: u32;
|
||||
|
||||
pixel_type,
|
||||
color_bits,
|
||||
@@ -139,420 +135,453 @@ type PixelFormatDescriptor struct #ordered {
|
||||
stencil_bits,
|
||||
aux_buffers,
|
||||
layer_type,
|
||||
reserved: u8,
|
||||
reserved: u8;
|
||||
|
||||
layer_mask,
|
||||
visible_mask,
|
||||
damage_mask: u32,
|
||||
damage_mask: u32;
|
||||
}
|
||||
|
||||
CriticalSection :: struct #ordered {
|
||||
debug_info: ^CriticalSectionDebug;
|
||||
|
||||
lock_count: i32;
|
||||
recursion_count: i32;
|
||||
owning_thread: Handle;
|
||||
lock_semaphore: Handle;
|
||||
spin_count: ^u32;
|
||||
}
|
||||
|
||||
CriticalSectionDebug :: struct #ordered {
|
||||
typ: u16;
|
||||
creator_back_trace_index: u16;
|
||||
critical_section: ^CriticalSection;
|
||||
process_locks_list: ^ListEntry;
|
||||
entry_count: u32;
|
||||
contention_count: u32;
|
||||
flags: u32;
|
||||
creator_back_trace_index_high: u16;
|
||||
spare_word: u16;
|
||||
}
|
||||
|
||||
ListEntry :: struct #ordered {flink, blink: ^ListEntry};
|
||||
|
||||
|
||||
|
||||
type Proc proc() #cc_c;
|
||||
|
||||
const (
|
||||
MAPVK_VK_TO_VSC = 0;
|
||||
MAPVK_VSC_TO_VK = 1;
|
||||
MAPVK_VK_TO_CHAR = 2;
|
||||
MAPVK_VSC_TO_VK_EX = 3;
|
||||
)
|
||||
MAPVK_VK_TO_VSC :: 0;
|
||||
MAPVK_VSC_TO_VK :: 1;
|
||||
MAPVK_VK_TO_CHAR :: 2;
|
||||
MAPVK_VSC_TO_VK_EX :: 3;
|
||||
|
||||
|
||||
|
||||
const INVALID_HANDLE = Handle(~int(0));
|
||||
|
||||
INVALID_HANDLE :: Handle(~int(0));
|
||||
|
||||
CREATE_SUSPENDED :: 0x00000004;
|
||||
STACK_SIZE_PARAM_IS_A_RESERVATION :: 0x00010000;
|
||||
WAIT_ABANDONED :: 0x00000080;
|
||||
WAIT_OBJECT_0 :: 0;
|
||||
WAIT_TIMEOUT :: 0x00000102;
|
||||
WAIT_FAILED :: 0xffffffff;
|
||||
|
||||
CS_VREDRAW :: 0x0001;
|
||||
CS_HREDRAW :: 0x0002;
|
||||
CS_OWNDC :: 0x0020;
|
||||
CW_USEDEFAULT :: -0x80000000;
|
||||
|
||||
WS_OVERLAPPED :: 0;
|
||||
WS_MAXIMIZEBOX :: 0x00010000;
|
||||
WS_MINIMIZEBOX :: 0x00020000;
|
||||
WS_THICKFRAME :: 0x00040000;
|
||||
WS_SYSMENU :: 0x00080000;
|
||||
WS_BORDER :: 0x00800000;
|
||||
WS_CAPTION :: 0x00C00000;
|
||||
WS_VISIBLE :: 0x10000000;
|
||||
WS_POPUP :: 0x80000000;
|
||||
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
|
||||
WS_POPUPWINDOW :: WS_POPUP | WS_BORDER | WS_SYSMENU;
|
||||
|
||||
WM_DESTROY :: 0x0002;
|
||||
WM_SIZE :: 0x0005;
|
||||
WM_CLOSE :: 0x0010;
|
||||
WM_ACTIVATEAPP :: 0x001C;
|
||||
WM_QUIT :: 0x0012;
|
||||
WM_KEYDOWN :: 0x0100;
|
||||
WM_KEYUP :: 0x0101;
|
||||
WM_SIZING :: 0x0214;
|
||||
WM_SYSKEYDOWN :: 0x0104;
|
||||
WM_SYSKEYUP :: 0x0105;
|
||||
WM_WINDOWPOSCHANGED :: 0x0047;
|
||||
WM_SETCURSOR :: 0x0020;
|
||||
WM_CHAR :: 0x0102;
|
||||
WM_ACTIVATE :: 0x0006;
|
||||
WM_SETFOCUS :: 0x0007;
|
||||
WM_KILLFOCUS :: 0x0008;
|
||||
WM_USER :: 0x0400;
|
||||
|
||||
WM_MOUSEWHEEL :: 0x020A;
|
||||
WM_MOUSEMOVE :: 0x0200;
|
||||
WM_LBUTTONDOWN :: 0x0201;
|
||||
WM_LBUTTONUP :: 0x0202;
|
||||
WM_LBUTTONDBLCLK :: 0x0203;
|
||||
WM_RBUTTONDOWN :: 0x0204;
|
||||
WM_RBUTTONUP :: 0x0205;
|
||||
WM_RBUTTONDBLCLK :: 0x0206;
|
||||
WM_MBUTTONDOWN :: 0x0207;
|
||||
WM_MBUTTONUP :: 0x0208;
|
||||
WM_MBUTTONDBLCLK :: 0x0209;
|
||||
|
||||
PM_NOREMOVE :: 0x0000;
|
||||
PM_REMOVE :: 0x0001;
|
||||
PM_NOYIELD :: 0x0002;
|
||||
|
||||
BLACK_BRUSH :: 4;
|
||||
|
||||
SM_CXSCREEN :: 0;
|
||||
SM_CYSCREEN :: 1;
|
||||
|
||||
SW_SHOW :: 5;
|
||||
|
||||
COLOR_BACKGROUND :: Hbrush(int(1));
|
||||
|
||||
INVALID_SET_FILE_POINTER :: ~u32(0);
|
||||
HEAP_ZERO_MEMORY :: 0x00000008;
|
||||
INFINITE :: 0xffffffff;
|
||||
GWL_STYLE :: -16;
|
||||
Hwnd_TOP :: Hwnd(uint(0));
|
||||
|
||||
BI_RGB :: 0;
|
||||
DIB_RGB_COLORS :: 0x00;
|
||||
SRCCOPY: u32 : 0x00cc0020;
|
||||
|
||||
|
||||
const (
|
||||
CS_VREDRAW = 0x0001;
|
||||
CS_HREDRAW = 0x0002;
|
||||
CS_OWNDC = 0x0020;
|
||||
CW_USEDEFAULT = -0x80000000;
|
||||
MONITOR_DEFAULTTONULL :: 0x00000000;
|
||||
MONITOR_DEFAULTTOPRIMARY :: 0x00000001;
|
||||
MONITOR_DEFAULTTONEAREST :: 0x00000002;
|
||||
|
||||
WS_OVERLAPPED = 0;
|
||||
WS_MAXIMIZEBOX = 0x00010000;
|
||||
WS_MINIMIZEBOX = 0x00020000;
|
||||
WS_THICKFRAME = 0x00040000;
|
||||
WS_SYSMENU = 0x00080000;
|
||||
WS_BORDER = 0x00800000;
|
||||
WS_CAPTION = 0x00C00000;
|
||||
WS_VISIBLE = 0x10000000;
|
||||
WS_POPUP = 0x80000000;
|
||||
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
|
||||
WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU;
|
||||
|
||||
WM_DESTROY = 0x0002;
|
||||
WM_SIZE = 0x0005;
|
||||
WM_CLOSE = 0x0010;
|
||||
WM_ACTIVATEAPP = 0x001C;
|
||||
WM_QUIT = 0x0012;
|
||||
WM_KEYDOWN = 0x0100;
|
||||
WM_KEYUP = 0x0101;
|
||||
WM_SIZING = 0x0214;
|
||||
WM_SYSKEYDOWN = 0x0104;
|
||||
WM_SYSKEYUP = 0x0105;
|
||||
WM_WINDOWPOSCHANGED = 0x0047;
|
||||
WM_SETCURSOR = 0x0020;
|
||||
WM_CHAR = 0x0102;
|
||||
WM_ACTIVATE = 0x0006;
|
||||
WM_SETFOCUS = 0x0007;
|
||||
WM_KILLFOCUS = 0x0008;
|
||||
WM_USER = 0x0400;
|
||||
|
||||
WM_MOUSEWHEEL = 0x020A;
|
||||
WM_MOUSEMOVE = 0x0200;
|
||||
WM_LBUTTONDOWN = 0x0201;
|
||||
WM_LBUTTONUP = 0x0202;
|
||||
WM_LBUTTONDBLCLK = 0x0203;
|
||||
WM_RBUTTONDOWN = 0x0204;
|
||||
WM_RBUTTONUP = 0x0205;
|
||||
WM_RBUTTONDBLCLK = 0x0206;
|
||||
WM_MBUTTONDOWN = 0x0207;
|
||||
WM_MBUTTONUP = 0x0208;
|
||||
WM_MBUTTONDBLCLK = 0x0209;
|
||||
|
||||
PM_NOREMOVE = 0x0000;
|
||||
PM_REMOVE = 0x0001;
|
||||
PM_NOYIELD = 0x0002;
|
||||
|
||||
BLACK_BRUSH = 4;
|
||||
|
||||
SM_CXSCREEN = 0;
|
||||
SM_CYSCREEN = 1;
|
||||
|
||||
SW_SHOW = 5;
|
||||
)
|
||||
|
||||
const COLOR_BACKGROUND = Hbrush(int(1));
|
||||
|
||||
const INVALID_SET_FILE_POINTER = ~u32(0);
|
||||
const HEAP_ZERO_MEMORY = 0x00000008;
|
||||
const INFINITE = 0xffffffff;
|
||||
const GWL_STYLE = -16;
|
||||
const Hwnd_TOP = Hwnd(uint(0));
|
||||
|
||||
const BI_RGB = 0;
|
||||
const DIB_RGB_COLORS = 0x00;
|
||||
const SRCCOPY: u32 = 0x00cc0020;
|
||||
|
||||
const (
|
||||
MONITOR_DEFAULTTONULL = 0x00000000;
|
||||
MONITOR_DEFAULTTOPRIMARY = 0x00000001;
|
||||
MONITOR_DEFAULTTONEAREST = 0x00000002;
|
||||
)
|
||||
const (
|
||||
SWP_FRAMECHANGED = 0x0020;
|
||||
SWP_NOOWNERZORDER = 0x0200;
|
||||
SWP_NOZORDER = 0x0004;
|
||||
SWP_NOSIZE = 0x0001;
|
||||
SWP_NOMOVE = 0x0002;
|
||||
)
|
||||
SWP_FRAMECHANGED :: 0x0020;
|
||||
SWP_NOOWNERZORDER :: 0x0200;
|
||||
SWP_NOZORDER :: 0x0004;
|
||||
SWP_NOSIZE :: 0x0001;
|
||||
SWP_NOMOVE :: 0x0002;
|
||||
|
||||
|
||||
|
||||
|
||||
// Windows OpenGL
|
||||
const (
|
||||
PFD_TYPE_RGBA = 0;
|
||||
PFD_TYPE_COLORINDEX = 1;
|
||||
PFD_MAIN_PLANE = 0;
|
||||
PFD_OVERLAY_PLANE = 1;
|
||||
PFD_UNDERLAY_PLANE = -1;
|
||||
PFD_DOUBLEBUFFER = 1;
|
||||
PFD_STEREO = 2;
|
||||
PFD_DRAW_TO_WINDOW = 4;
|
||||
PFD_DRAW_TO_BITMAP = 8;
|
||||
PFD_SUPPORT_GDI = 16;
|
||||
PFD_SUPPORT_OPENGL = 32;
|
||||
PFD_GENERIC_FORMAT = 64;
|
||||
PFD_NEED_PALETTE = 128;
|
||||
PFD_NEED_SYSTEM_PALETTE = 0x00000100;
|
||||
PFD_SWAP_EXCHANGE = 0x00000200;
|
||||
PFD_SWAP_COPY = 0x00000400;
|
||||
PFD_SWAP_LAYER_BUFFERS = 0x00000800;
|
||||
PFD_GENERIC_ACCELERATED = 0x00001000;
|
||||
PFD_DEPTH_DONTCARE = 0x20000000;
|
||||
PFD_DOUBLEBUFFER_DONTCARE = 0x40000000;
|
||||
PFD_STEREO_DONTCARE = 0x80000000;
|
||||
)
|
||||
|
||||
PFD_TYPE_RGBA :: 0;
|
||||
PFD_TYPE_COLORINDEX :: 1;
|
||||
PFD_MAIN_PLANE :: 0;
|
||||
PFD_OVERLAY_PLANE :: 1;
|
||||
PFD_UNDERLAY_PLANE :: -1;
|
||||
PFD_DOUBLEBUFFER :: 1;
|
||||
PFD_STEREO :: 2;
|
||||
PFD_DRAW_TO_WINDOW :: 4;
|
||||
PFD_DRAW_TO_BITMAP :: 8;
|
||||
PFD_SUPPORT_GDI :: 16;
|
||||
PFD_SUPPORT_OPENGL :: 32;
|
||||
PFD_GENERIC_FORMAT :: 64;
|
||||
PFD_NEED_PALETTE :: 128;
|
||||
PFD_NEED_SYSTEM_PALETTE :: 0x00000100;
|
||||
PFD_SWAP_EXCHANGE :: 0x00000200;
|
||||
PFD_SWAP_COPY :: 0x00000400;
|
||||
PFD_SWAP_LAYER_BUFFERS :: 0x00000800;
|
||||
PFD_GENERIC_ACCELERATED :: 0x00001000;
|
||||
PFD_DEPTH_DONTCARE :: 0x20000000;
|
||||
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
|
||||
PFD_STEREO_DONTCARE :: 0x80000000;
|
||||
|
||||
GET_FILEEX_INFO_LEVELS :: i32;
|
||||
GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0;
|
||||
GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1;
|
||||
|
||||
type GET_FILEEX_INFO_LEVELS i32;
|
||||
const (
|
||||
GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS = 0;
|
||||
GetFileExMaxInfoLevel = 1;
|
||||
)
|
||||
|
||||
foreign kernel32 {
|
||||
proc get_last_error () -> i32 #cc_std #link_name "GetLastError";
|
||||
proc exit_process (exit_code: u32) #cc_std #link_name "ExitProcess";
|
||||
proc get_module_handle_a(module_name: ^u8) -> Hinstance #cc_std #link_name "GetModuleHandleA";
|
||||
proc sleep(ms: i32) -> i32 #cc_std #link_name "Sleep";
|
||||
proc query_performance_frequency(result: ^i64) -> i32 #cc_std #link_name "QueryPerformanceFrequency";
|
||||
proc query_performance_counter (result: ^i64) -> i32 #cc_std #link_name "QueryPerformanceCounter";
|
||||
proc output_debug_string_a(c_str: ^u8) #cc_std #link_name "OutputDebugStringA";
|
||||
get_last_error :: proc() -> i32 #cc_std #link_name "GetLastError" ---;
|
||||
exit_process :: proc(exit_code: u32) #cc_std #link_name "ExitProcess" ---;
|
||||
get_module_handle_a :: proc(module_name: ^u8) -> Hinstance #cc_std #link_name "GetModuleHandleA" ---;
|
||||
sleep :: proc(ms: i32) -> i32 #cc_std #link_name "Sleep" ---;
|
||||
query_performance_frequency :: proc(result: ^i64) -> i32 #cc_std #link_name "QueryPerformanceFrequency" ---;
|
||||
query_performance_counter :: proc(result: ^i64) -> i32 #cc_std #link_name "QueryPerformanceCounter" ---;
|
||||
output_debug_string_a :: proc(c_str: ^u8) #cc_std #link_name "OutputDebugStringA" ---;
|
||||
|
||||
proc get_command_line_a () -> ^u8 #cc_std #link_name "GetCommandLineA";
|
||||
proc get_command_line_w () -> ^u16 #cc_std #link_name "GetCommandLineW";
|
||||
proc get_system_metrics (index: i32) -> i32 #cc_std #link_name "GetSystemMetrics";
|
||||
proc get_current_thread_id () -> u32 #cc_std #link_name "GetCurrentThreadId";
|
||||
get_command_line_a :: proc() -> ^u8 #cc_std #link_name "GetCommandLineA" ---;
|
||||
get_command_line_w :: proc() -> ^u16 #cc_std #link_name "GetCommandLineW" ---;
|
||||
get_system_metrics :: proc(index: i32) -> i32 #cc_std #link_name "GetSystemMetrics" ---;
|
||||
get_current_thread_id :: proc() -> u32 #cc_std #link_name "GetCurrentThreadId" ---;
|
||||
|
||||
proc get_system_time_as_file_time(system_time_as_file_time: ^Filetime) #cc_std #link_name "GetSystemTimeAsFileTime";
|
||||
proc file_time_to_local_file_time(file_time: ^Filetime, local_file_time: ^Filetime) -> Bool #cc_std #link_name "FileTimeToLocalFileTime";
|
||||
proc file_time_to_system_time (file_time: ^Filetime, system_time: ^Systemtime) -> Bool #cc_std #link_name "FileTimeToSystemTime";
|
||||
proc system_time_to_file_time (system_time: ^Systemtime, file_time: ^Filetime) -> Bool #cc_std #link_name "SystemTimeToFileTime";
|
||||
get_system_time_as_file_time :: proc(system_time_as_file_time: ^Filetime) #cc_std #link_name "GetSystemTimeAsFileTime" ---;
|
||||
file_time_to_local_file_time :: proc(file_time: ^Filetime, local_file_time: ^Filetime) -> Bool #cc_std #link_name "FileTimeToLocalFileTime" ---;
|
||||
file_time_to_system_time :: proc(file_time: ^Filetime, system_time: ^Systemtime) -> Bool #cc_std #link_name "FileTimeToSystemTime" ---;
|
||||
system_time_to_file_time :: proc(system_time: ^Systemtime, file_time: ^Filetime) -> Bool #cc_std #link_name "SystemTimeToFileTime" ---;
|
||||
|
||||
proc close_handle (h: Handle) -> i32 #cc_std #link_name "CloseHandle";
|
||||
proc get_std_handle(h: i32) -> Handle #cc_std #link_name "GetStdHandle";
|
||||
proc create_file_a (filename: ^u8, desired_access, share_mode: u32,
|
||||
security: rawptr,
|
||||
creation, flags_and_attribs: u32, template_file: Handle) -> Handle #cc_std #link_name "CreateFileA";
|
||||
proc read_file (h: Handle, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> Bool #cc_std #link_name "ReadFile";
|
||||
proc write_file(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool #cc_std #link_name "WriteFile";
|
||||
close_handle :: proc(h: Handle) -> i32 #cc_std #link_name "CloseHandle" ---;
|
||||
get_std_handle :: proc(h: i32) -> Handle #cc_std #link_name "GetStdHandle" ---;
|
||||
create_file_a :: proc(filename: ^u8, desired_access, share_mode: u32,
|
||||
security: rawptr,
|
||||
creation, flags_and_attribs: u32, template_file: Handle) -> Handle #cc_std #link_name "CreateFileA" ---;
|
||||
read_file :: proc(h: Handle, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> Bool #cc_std #link_name "ReadFile" ---;
|
||||
write_file :: proc(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool #cc_std #link_name "WriteFile" ---;
|
||||
|
||||
proc get_file_size_ex (file_handle: Handle, file_size: ^i64) -> Bool #cc_std #link_name "GetFileSizeEx";
|
||||
proc get_file_attributes_a (filename: ^u8) -> u32 #cc_std #link_name "GetFileAttributesA";
|
||||
proc get_file_attributes_ex_a (filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool #cc_std #link_name "GetFileAttributesExA";
|
||||
proc get_file_information_by_handle(file_handle: Handle, file_info: ^ByHandleFileInformation) -> Bool #cc_std #link_name "GetFileInformationByHandle";
|
||||
get_file_size_ex :: proc(file_handle: Handle, file_size: ^i64) -> Bool #cc_std #link_name "GetFileSizeEx" ---;
|
||||
get_file_attributes_a :: proc(filename: ^u8) -> u32 #cc_std #link_name "GetFileAttributesA" ---;
|
||||
get_file_attributes_ex_a :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool #cc_std #link_name "GetFileAttributesExA" ---;
|
||||
get_file_information_by_handle :: proc(file_handle: Handle, file_info: ^ByHandleFileInformation) -> Bool #cc_std #link_name "GetFileInformationByHandle" ---;
|
||||
|
||||
proc get_file_type (file_handle: Handle) -> u32 #cc_std #link_name "GetFileType";
|
||||
proc set_file_pointer(file_handle: Handle, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #cc_std #link_name "SetFilePointer";
|
||||
get_file_type :: proc(file_handle: Handle) -> u32 #cc_std #link_name "GetFileType" ---;
|
||||
set_file_pointer :: proc(file_handle: Handle, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #cc_std #link_name "SetFilePointer" ---;
|
||||
|
||||
proc set_handle_information(obj: Handle, mask, flags: u32) -> Bool #cc_std #link_name "SetHandleInformation";
|
||||
set_handle_information :: proc(obj: Handle, mask, flags: u32) -> Bool #cc_std #link_name "SetHandleInformation" ---;
|
||||
|
||||
proc find_first_file_a(file_name : ^u8, data : ^FindData) -> Handle #cc_std #link_name "FindFirstFileA";
|
||||
proc find_next_file_a (file : Handle, data : ^FindData) -> Bool #cc_std #link_name "FindNextFileA";
|
||||
proc find_close (file : Handle) -> Bool #cc_std #link_name "FindClose";
|
||||
find_first_file_a :: proc(file_name : ^u8, data : ^FindData) -> Handle #cc_std #link_name "FindFirstFileA" ---;
|
||||
find_next_file_a :: proc(file : Handle, data : ^FindData) -> Bool #cc_std #link_name "FindNextFileA" ---;
|
||||
find_close :: proc(file : Handle) -> Bool #cc_std #link_name "FindClose" ---;
|
||||
|
||||
|
||||
proc heap_alloc (h: Handle, flags: u32, bytes: int) -> rawptr #cc_std #link_name "HeapAlloc";
|
||||
proc heap_realloc (h: Handle, flags: u32, memory: rawptr, bytes: int) -> rawptr #cc_std #link_name "HeapReAlloc";
|
||||
proc heap_free (h: Handle, flags: u32, memory: rawptr) -> Bool #cc_std #link_name "HeapFree";
|
||||
proc get_process_heap() -> Handle #cc_std #link_name "GetProcessHeap";
|
||||
heap_alloc :: proc(h: Handle, flags: u32, bytes: int) -> rawptr #cc_std #link_name "HeapAlloc" ---;
|
||||
heap_realloc :: proc(h: Handle, flags: u32, memory: rawptr, bytes: int) -> rawptr #cc_std #link_name "HeapReAlloc" ---;
|
||||
heap_free :: proc(h: Handle, flags: u32, memory: rawptr) -> Bool #cc_std #link_name "HeapFree" ---;
|
||||
get_process_heap :: proc() -> Handle #cc_std #link_name "GetProcessHeap" ---;
|
||||
|
||||
|
||||
proc create_semaphore_a (attributes: ^Security_Attributes, initial_count, maximum_count: i32, name: ^u8) -> Handle #cc_std #link_name "CreateSemaphoreA";
|
||||
proc release_semaphore (semaphore: Handle, release_count: i32, previous_count: ^i32) -> Bool #cc_std #link_name "ReleaseSemaphore";
|
||||
proc wait_for_single_object(handle: Handle, milliseconds: u32) -> u32 #cc_std #link_name "WaitForSingleObject";
|
||||
create_semaphore_a :: proc(attributes: ^SecurityAttributes, initial_count, maximum_count: i32, name: ^u8) -> Handle #cc_std #link_name "CreateSemaphoreA" ---;
|
||||
release_semaphore :: proc(semaphore: Handle, release_count: i32, previous_count: ^i32) -> Bool #cc_std #link_name "ReleaseSemaphore" ---;
|
||||
wait_for_single_object :: proc(handle: Handle, milliseconds: u32) -> u32 #cc_std #link_name "WaitForSingleObject" ---;
|
||||
|
||||
|
||||
proc interlocked_compare_exchange (dst: ^i32, exchange, comparand: i32) -> i32 #cc_std #link_name "InterlockedCompareExchange";
|
||||
proc interlocked_exchange (dst: ^i32, desired: i32) -> i32 #cc_std #link_name "InterlockedExchange";
|
||||
proc interlocked_exchange_add (dst: ^i32, desired: i32) -> i32 #cc_std #link_name "InterlockedExchangeAdd";
|
||||
proc interlocked_and (dst: ^i32, desired: i32) -> i32 #cc_std #link_name "InterlockedAnd";
|
||||
proc interlocked_or (dst: ^i32, desired: i32) -> i32 #cc_std #link_name "InterlockedOr";
|
||||
interlocked_compare_exchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #cc_c #link_name "InterlockedCompareExchange" ---;
|
||||
interlocked_exchange :: proc(dst: ^i32, desired: i32) -> i32 #cc_c #link_name "InterlockedExchange" ---;
|
||||
interlocked_exchange_add :: proc(dst: ^i32, desired: i32) -> i32 #cc_c #link_name "InterlockedExchangeAdd" ---;
|
||||
interlocked_and :: proc(dst: ^i32, desired: i32) -> i32 #cc_c #link_name "InterlockedAnd" ---;
|
||||
interlocked_or :: proc(dst: ^i32, desired: i32) -> i32 #cc_c #link_name "InterlockedOr" ---;
|
||||
|
||||
proc interlocked_compare_exchange64(dst: ^i64, exchange, comparand: i64) -> i64 #cc_std #link_name "InterlockedCompareExchange64";
|
||||
proc interlocked_exchange64 (dst: ^i64, desired: i64) -> i64 #cc_std #link_name "InterlockedExchange64";
|
||||
proc interlocked_exchange_add64 (dst: ^i64, desired: i64) -> i64 #cc_std #link_name "InterlockedExchangeAdd64";
|
||||
proc interlocked_and64 (dst: ^i64, desired: i64) -> i64 #cc_std #link_name "InterlockedAnd64";
|
||||
proc interlocked_or64 (dst: ^i64, desired: i64) -> i64 #cc_std #link_name "InterlockedOr64";
|
||||
interlocked_compare_exchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #cc_c #link_name "InterlockedCompareExchange64" ---;
|
||||
interlocked_exchange64 :: proc(dst: ^i64, desired: i64) -> i64 #cc_c #link_name "InterlockedExchange64" ---;
|
||||
interlocked_exchange_add64 :: proc(dst: ^i64, desired: i64) -> i64 #cc_c #link_name "InterlockedExchangeAdd64" ---;
|
||||
interlocked_and64 :: proc(dst: ^i64, desired: i64) -> i64 #cc_c #link_name "InterlockedAnd64" ---;
|
||||
interlocked_or64 :: proc(dst: ^i64, desired: i64) -> i64 #cc_c #link_name "InterlockedOr64" ---;
|
||||
|
||||
proc mm_pause () #cc_std #link_name "_mm_pause";
|
||||
proc read_write_barrier() #cc_std #link_name "ReadWriteBarrier";
|
||||
proc write_barrier () #cc_std #link_name "WriteBarrier";
|
||||
proc read_barrier () #cc_std #link_name "ReadBarrier";
|
||||
mm_pause :: proc() #cc_std #link_name "_mm_pause" ---;
|
||||
read_write_barrier :: proc() #cc_std #link_name "ReadWriteBarrier" ---;
|
||||
write_barrier :: proc() #cc_std #link_name "WriteBarrier" ---;
|
||||
read_barrier :: proc() #cc_std #link_name "ReadBarrier" ---;
|
||||
|
||||
create_thread :: proc(thread_attributes: ^SecurityAttributes, stack_size: int, start_routine: rawptr,
|
||||
parameter: rawptr, creation_flags: u32, thread_id: ^u32) -> Handle #cc_std #link_name "CreateThread" ---;
|
||||
resume_thread :: proc(thread: Handle) -> u32 #cc_std #link_name "ResumeThread" ---;
|
||||
get_thread_priority :: proc(thread: Handle) -> i32 #cc_std #link_name "GetThreadPriority" ---;
|
||||
set_thread_priority :: proc(thread: Handle, priority: i32) -> Bool #cc_std #link_name "SetThreadPriority" ---;
|
||||
get_exit_code_thread :: proc(thread: Handle, exit_code: ^u32) -> Bool #cc_std #link_name "GetExitCodeThread" ---;
|
||||
|
||||
proc load_library_a (c_str: ^u8) -> Hmodule #cc_std #link_name "LoadLibraryA";
|
||||
proc free_library (h: Hmodule) #cc_std #link_name "FreeLibrary";
|
||||
proc get_proc_address(h: Hmodule, c_str: ^u8) -> Proc #cc_std #link_name "GetProcAddress";
|
||||
initialize_critical_section :: proc(critical_section: ^CriticalSection) #cc_std #link_name "InitializeCriticalSection" ---;
|
||||
initialize_critical_section_and_spin_count :: proc(critical_section: ^CriticalSection, spin_count: u32) #cc_std #link_name "InitializeCriticalSectionAndSpinCount" ---;
|
||||
delete_critical_section :: proc(critical_section: ^CriticalSection) #cc_std #link_name "DeleteCriticalSection" ---;
|
||||
set_critical_section_spin_count :: proc(critical_section: ^CriticalSection, spin_count: u32) -> u32 #cc_std #link_name "SetCriticalSectionSpinCount" ---;
|
||||
try_enter_critical_section :: proc(critical_section: ^CriticalSection) -> Bool #cc_std #link_name "TryEnterCriticalSection" ---;
|
||||
enter_critical_section :: proc(critical_section: ^CriticalSection) #cc_std #link_name "EnterCriticalSection" ---;
|
||||
leave_critical_section :: proc(critical_section: ^CriticalSection) #cc_std #link_name "LeaveCriticalSection" ---;
|
||||
|
||||
create_event_a :: proc(event_attributes: ^SecurityAttributes, manual_reset, initial_state: Bool, name: ^u8) -> Handle #cc_std #link_name "CreateEventA" ---;
|
||||
|
||||
load_library_a :: proc(c_str: ^u8) -> Hmodule #cc_std #link_name "LoadLibraryA" ---;
|
||||
free_library :: proc(h: Hmodule) #cc_std #link_name "FreeLibrary" ---;
|
||||
get_proc_address :: proc(h: Hmodule, c_str: ^u8) -> rawptr #cc_std #link_name "GetProcAddress" ---;
|
||||
|
||||
}
|
||||
|
||||
foreign user32 {
|
||||
proc get_desktop_window () -> Hwnd #cc_std #link_name "GetDesktopWindow";
|
||||
proc show_cursor (show : Bool) #cc_std #link_name "ShowCursor";
|
||||
proc get_cursor_pos (p: ^Point) -> i32 #cc_std #link_name "GetCursorPos";
|
||||
proc screen_to_client (h: Hwnd, p: ^Point) -> i32 #cc_std #link_name "ScreenToClient";
|
||||
proc post_quit_message (exit_code: i32) #cc_std #link_name "PostQuitMessage";
|
||||
proc set_window_text_a (hwnd: Hwnd, c_string: ^u8) -> Bool #cc_std #link_name "SetWindowTextA";
|
||||
proc register_class_ex_a (wc: ^WndClassExA) -> i16 #cc_std #link_name "RegisterClassExA";
|
||||
get_desktop_window :: proc() -> Hwnd #cc_std #link_name "GetDesktopWindow" ---;
|
||||
show_cursor :: proc(show : Bool) #cc_std #link_name "ShowCursor" ---;
|
||||
get_cursor_pos :: proc(p: ^Point) -> i32 #cc_std #link_name "GetCursorPos" ---;
|
||||
screen_to_client :: proc(h: Hwnd, p: ^Point) -> i32 #cc_std #link_name "ScreenToClient" ---;
|
||||
post_quit_message :: proc(exit_code: i32) #cc_std #link_name "PostQuitMessage" ---;
|
||||
set_window_text_a :: proc(hwnd: Hwnd, c_string: ^u8) -> Bool #cc_std #link_name "SetWindowTextA" ---;
|
||||
register_class_ex_a :: proc(wc: ^WndClassExA) -> i16 #cc_std #link_name "RegisterClassExA" ---;
|
||||
|
||||
proc create_window_ex_a (ex_style: u32,
|
||||
class_name, title: ^u8,
|
||||
style: u32,
|
||||
x, y, w, h: i32,
|
||||
parent: Hwnd, menu: Hmenu, instance: Hinstance,
|
||||
param: rawptr) -> Hwnd #cc_std #link_name "CreateWindowExA";
|
||||
create_window_ex_a :: proc(ex_style: u32,
|
||||
class_name, title: ^u8,
|
||||
style: u32,
|
||||
x, y, w, h: i32,
|
||||
parent: Hwnd, menu: Hmenu, instance: Hinstance,
|
||||
param: rawptr) -> Hwnd #cc_std #link_name "CreateWindowExA" ---;
|
||||
|
||||
proc show_window (hwnd: Hwnd, cmd_show: i32) -> Bool #cc_std #link_name "ShowWindow";
|
||||
proc translate_message (msg: ^Msg) -> Bool #cc_std #link_name "TranslateMessage";
|
||||
proc dispatch_message_a (msg: ^Msg) -> Lresult #cc_std #link_name "DispatchMessageA";
|
||||
proc update_window (hwnd: Hwnd) -> Bool #cc_std #link_name "UpdateWindow";
|
||||
proc get_message_a (msg: ^Msg, hwnd: Hwnd, msg_filter_min, msg_filter_max : u32) -> Bool #cc_std #link_name "GetMessageA";
|
||||
proc peek_message_a (msg: ^Msg, hwnd: Hwnd,
|
||||
msg_filter_min, msg_filter_max, remove_msg: u32) -> Bool #cc_std #link_name "PeekMessageA";
|
||||
show_window :: proc(hwnd: Hwnd, cmd_show: i32) -> Bool #cc_std #link_name "ShowWindow" ---;
|
||||
translate_message :: proc(msg: ^Msg) -> Bool #cc_std #link_name "TranslateMessage" ---;
|
||||
dispatch_message_a :: proc(msg: ^Msg) -> Lresult #cc_std #link_name "DispatchMessageA" ---;
|
||||
update_window :: proc(hwnd: Hwnd) -> Bool #cc_std #link_name "UpdateWindow" ---;
|
||||
get_message_a :: proc(msg: ^Msg, hwnd: Hwnd, msg_filter_min, msg_filter_max : u32) -> Bool #cc_std #link_name "GetMessageA" ---;
|
||||
peek_message_a :: proc(msg: ^Msg, hwnd: Hwnd,
|
||||
msg_filter_min, msg_filter_max, remove_msg: u32) -> Bool #cc_std #link_name "PeekMessageA" ---;
|
||||
|
||||
|
||||
proc post_message (hwnd: Hwnd, msg, wparam, lparam : u32) -> Bool #cc_std #link_name "PostMessageA";
|
||||
post_message :: proc(hwnd: Hwnd, msg, wparam, lparam : u32) -> Bool #cc_std #link_name "PostMessageA" ---;
|
||||
|
||||
proc def_window_proc_a (hwnd: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Lresult #cc_std #link_name "DefWindowProcA";
|
||||
def_window_proc_a :: proc(hwnd: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Lresult #cc_std #link_name "DefWindowProcA" ---;
|
||||
|
||||
proc adjust_window_rect (rect: ^Rect, style: u32, menu: Bool) -> Bool #cc_std #link_name "AdjustWindowRect";
|
||||
proc get_active_window () -> Hwnd #cc_std #link_name "GetActiveWindow";
|
||||
adjust_window_rect :: proc(rect: ^Rect, style: u32, menu: Bool) -> Bool #cc_std #link_name "AdjustWindowRect" ---;
|
||||
get_active_window :: proc() -> Hwnd #cc_std #link_name "GetActiveWindow" ---;
|
||||
|
||||
proc destroy_window (wnd: Hwnd) -> Bool #cc_std #link_name "DestroyWindow";
|
||||
proc describe_pixel_format(dc: Hdc, pixel_format: i32, bytes : u32, pfd: ^PixelFormatDescriptor) -> i32 #cc_std #link_name "DescribePixelFormat";
|
||||
destroy_window :: proc(wnd: Hwnd) -> Bool #cc_std #link_name "DestroyWindow" ---;
|
||||
describe_pixel_format :: proc(dc: Hdc, pixel_format: i32, bytes : u32, pfd: ^PixelFormatDescriptor) -> i32 #cc_std #link_name "DescribePixelFormat" ---;
|
||||
|
||||
proc get_monitor_info_a (monitor: Hmonitor, mi: ^MonitorInfo) -> Bool #cc_std #link_name "GetMonitorInfoA";
|
||||
proc monitor_from_window (wnd: Hwnd, flags : u32) -> Hmonitor #cc_std #link_name "MonitorFromWindow";
|
||||
get_monitor_info_a :: proc(monitor: Hmonitor, mi: ^MonitorInfo) -> Bool #cc_std #link_name "GetMonitorInfoA" ---;
|
||||
monitor_from_window :: proc(wnd: Hwnd, flags : u32) -> Hmonitor #cc_std #link_name "MonitorFromWindow" ---;
|
||||
|
||||
proc set_window_pos (wnd: Hwnd, wndInsertAfter: Hwnd, x, y, width, height: i32, flags: u32) #cc_std #link_name "SetWindowPos";
|
||||
set_window_pos :: proc(wnd: Hwnd, wndInsertAfter: Hwnd, x, y, width, height: i32, flags: u32) #cc_std #link_name "SetWindowPos" ---;
|
||||
|
||||
proc get_window_placement (wnd: Hwnd, wndpl: ^WindowPlacement) -> Bool #cc_std #link_name "GetWindowPlacement";
|
||||
proc set_window_placement (wnd: Hwnd, wndpl: ^WindowPlacement) -> Bool #cc_std #link_name "SetWindowPlacement";
|
||||
proc get_window_rect (wnd: Hwnd, rect: ^Rect) -> Bool #cc_std #link_name "GetWindowRect";
|
||||
get_window_placement :: proc(wnd: Hwnd, wndpl: ^WindowPlacement) -> Bool #cc_std #link_name "GetWindowPlacement" ---;
|
||||
set_window_placement :: proc(wnd: Hwnd, wndpl: ^WindowPlacement) -> Bool #cc_std #link_name "SetWindowPlacement" ---;
|
||||
get_window_rect :: proc(wnd: Hwnd, rect: ^Rect) -> Bool #cc_std #link_name "GetWindowRect" ---;
|
||||
|
||||
proc get_window_long_ptr_a(wnd: Hwnd, index: i32) -> i64 #cc_std #link_name "GetWindowLongPtrA";
|
||||
proc set_window_long_ptr_a(wnd: Hwnd, index: i32, new: i64) -> i64 #cc_std #link_name "SetWindowLongPtrA";
|
||||
get_window_long_ptr_a :: proc(wnd: Hwnd, index: i32) -> i64 #cc_std #link_name "GetWindowLongPtrA" ---;
|
||||
set_window_long_ptr_a :: proc(wnd: Hwnd, index: i32, new: i64) -> i64 #cc_std #link_name "SetWindowLongPtrA" ---;
|
||||
|
||||
proc get_window_text (wnd: Hwnd, str: ^u8, maxCount: i32) -> i32 #cc_std #link_name "GetWindowText";
|
||||
get_window_text :: proc(wnd: Hwnd, str: ^u8, maxCount: i32) -> i32 #cc_std #link_name "GetWindowText" ---;
|
||||
|
||||
proc get_client_rect (hwnd: Hwnd, rect: ^Rect) -> Bool #cc_std #link_name "GetClientRect";
|
||||
get_client_rect :: proc(hwnd: Hwnd, rect: ^Rect) -> Bool #cc_std #link_name "GetClientRect" ---;
|
||||
|
||||
proc get_dc (h: Hwnd) -> Hdc #cc_std #link_name "GetDC";
|
||||
proc release_dc (wnd: Hwnd, hdc: Hdc) -> i32 #cc_std #link_name "ReleaseDC";
|
||||
get_dc :: proc(h: Hwnd) -> Hdc #cc_std #link_name "GetDC" ---;
|
||||
release_dc :: proc(wnd: Hwnd, hdc: Hdc) -> i32 #cc_std #link_name "ReleaseDC" ---;
|
||||
|
||||
proc map_virtual_key(scancode : u32, map_type : u32) -> u32 #cc_std #link_name "MapVirtualKeyA";
|
||||
map_virtual_key :: proc(scancode : u32, map_type : u32) -> u32 #cc_std #link_name "MapVirtualKeyA" ---;
|
||||
|
||||
proc get_key_state (v_key: i32) -> i16 #cc_std #link_name "GetKeyState";
|
||||
proc get_async_key_state(v_key: i32) -> i16 #cc_std #link_name "GetAsyncKeyState";
|
||||
get_key_state :: proc(v_key: i32) -> i16 #cc_std #link_name "GetKeyState" ---;
|
||||
get_async_key_state :: proc(v_key: i32) -> i16 #cc_std #link_name "GetAsyncKeyState" ---;
|
||||
}
|
||||
|
||||
foreign gdi32 {
|
||||
proc get_stock_object(fn_object: i32) -> Hgdiobj #cc_std #link_name "GetStockObject";
|
||||
get_stock_object :: proc(fn_object: i32) -> Hgdiobj #cc_std #link_name "GetStockObject" ---;
|
||||
|
||||
proc stretch_dibits( hdc: Hdc,
|
||||
stretch_dibits :: proc(hdc: Hdc,
|
||||
x_dst, y_dst, width_dst, height_dst: i32,
|
||||
x_src, y_src, width_src, header_src: i32,
|
||||
bits: rawptr, bits_info: ^BitmapInfo,
|
||||
usage: u32,
|
||||
rop: u32) -> i32 #cc_std #link_name "StretchDIBits";
|
||||
rop: u32) -> i32 #cc_std #link_name "StretchDIBits" ---;
|
||||
|
||||
proc set_pixel_format (hdc: Hdc, pixel_format: i32, pfd: ^PixelFormatDescriptor) -> Bool #cc_std #link_name "SetPixelFormat";
|
||||
proc choose_pixel_format(hdc: Hdc, pfd: ^PixelFormatDescriptor) -> i32 #cc_std #link_name "ChoosePixelFormat";
|
||||
proc swap_buffers (hdc: Hdc) -> Bool #cc_std #link_name "SwapBuffers";
|
||||
set_pixel_format :: proc(hdc: Hdc, pixel_format: i32, pfd: ^PixelFormatDescriptor) -> Bool #cc_std #link_name "SetPixelFormat" ---;
|
||||
choose_pixel_format :: proc(hdc: Hdc, pfd: ^PixelFormatDescriptor) -> i32 #cc_std #link_name "ChoosePixelFormat" ---;
|
||||
swap_buffers :: proc(hdc: Hdc) -> Bool #cc_std #link_name "SwapBuffers" ---;
|
||||
|
||||
}
|
||||
|
||||
foreign shell32 {
|
||||
proc command_line_to_argv_w(cmd_list: ^u16, num_args: ^i32) -> ^^u16 #cc_std #link_name "CommandLineToArgvW";
|
||||
command_line_to_argv_w :: proc(cmd_list: ^u16, num_args: ^i32) -> ^^u16 #cc_std #link_name "CommandLineToArgvW" ---;
|
||||
}
|
||||
|
||||
foreign winmm {
|
||||
proc time_get_time() -> u32 #cc_std #link_name "timeGetTime";
|
||||
time_get_time :: proc() -> u32 #cc_std #link_name "timeGetTime" ---;
|
||||
}
|
||||
|
||||
|
||||
|
||||
proc get_query_performance_frequency() -> i64 {
|
||||
var r: i64;
|
||||
get_query_performance_frequency :: proc() -> i64 {
|
||||
r: i64;
|
||||
query_performance_frequency(&r);
|
||||
return r;
|
||||
}
|
||||
|
||||
proc HIWORD(wParam: Wparam) -> u16 { return u16((u32(wParam) >> 16) & 0xffff); }
|
||||
proc HIWORD(lParam: Lparam) -> u16 { return u16((u32(lParam) >> 16) & 0xffff); }
|
||||
proc LOWORD(wParam: Wparam) -> u16 { return u16(wParam); }
|
||||
proc LOWORD(lParam: Lparam) -> u16 { return u16(lParam); }
|
||||
HIWORD :: proc(wParam: Wparam) -> u16 { return u16((u32(wParam) >> 16) & 0xffff); }
|
||||
HIWORD :: proc(lParam: Lparam) -> u16 { return u16((u32(lParam) >> 16) & 0xffff); }
|
||||
LOWORD :: proc(wParam: Wparam) -> u16 { return u16(wParam); }
|
||||
LOWORD :: proc(lParam: Lparam) -> u16 { return u16(lParam); }
|
||||
|
||||
proc is_key_down(key: KeyCode) -> bool #inline { return get_async_key_state(i32(key)) < 0; }
|
||||
is_key_down :: proc(key: KeyCode) -> bool #inline { return get_async_key_state(i32(key)) < 0; }
|
||||
|
||||
|
||||
|
||||
|
||||
const (
|
||||
MAX_PATH = 0x00000104;
|
||||
|
||||
HANDLE_FLAG_INHERIT = 1;
|
||||
HANDLE_FLAG_PROTECT_FROM_CLOSE = 2;
|
||||
MAX_PATH :: 0x00000104;
|
||||
|
||||
FILE_BEGIN = 0;
|
||||
FILE_CURRENT = 1;
|
||||
FILE_END = 2;
|
||||
HANDLE_FLAG_INHERIT :: 1;
|
||||
HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
|
||||
|
||||
FILE_SHARE_READ = 0x00000001;
|
||||
FILE_SHARE_WRITE = 0x00000002;
|
||||
FILE_SHARE_DELETE = 0x00000004;
|
||||
FILE_GENERIC_ALL = 0x10000000;
|
||||
FILE_GENERIC_EXECUTE = 0x20000000;
|
||||
FILE_GENERIC_WRITE = 0x40000000;
|
||||
FILE_GENERIC_READ = 0x80000000;
|
||||
FILE_BEGIN :: 0;
|
||||
FILE_CURRENT :: 1;
|
||||
FILE_END :: 2;
|
||||
|
||||
FILE_APPEND_DATA = 0x0004;
|
||||
FILE_SHARE_READ :: 0x00000001;
|
||||
FILE_SHARE_WRITE :: 0x00000002;
|
||||
FILE_SHARE_DELETE :: 0x00000004;
|
||||
FILE_GENERIC_ALL :: 0x10000000;
|
||||
FILE_GENERIC_EXECUTE :: 0x20000000;
|
||||
FILE_GENERIC_WRITE :: 0x40000000;
|
||||
FILE_GENERIC_READ :: 0x80000000;
|
||||
|
||||
STD_INPUT_HANDLE = -10;
|
||||
STD_OUTPUT_HANDLE = -11;
|
||||
STD_ERROR_HANDLE = -12;
|
||||
FILE_APPEND_DATA :: 0x0004;
|
||||
|
||||
CREATE_NEW = 1;
|
||||
CREATE_ALWAYS = 2;
|
||||
OPEN_EXISTING = 3;
|
||||
OPEN_ALWAYS = 4;
|
||||
TRUNCATE_EXISTING = 5;
|
||||
STD_INPUT_HANDLE :: -10;
|
||||
STD_OUTPUT_HANDLE :: -11;
|
||||
STD_ERROR_HANDLE :: -12;
|
||||
|
||||
INVALID_FILE_ATTRIBUTES = -1;
|
||||
CREATE_NEW :: 1;
|
||||
CREATE_ALWAYS :: 2;
|
||||
OPEN_EXISTING :: 3;
|
||||
OPEN_ALWAYS :: 4;
|
||||
TRUNCATE_EXISTING :: 5;
|
||||
|
||||
FILE_ATTRIBUTE_READONLY = 0x00000001;
|
||||
FILE_ATTRIBUTE_HIDDEN = 0x00000002;
|
||||
FILE_ATTRIBUTE_SYSTEM = 0x00000004;
|
||||
FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
|
||||
FILE_ATTRIBUTE_ARCHIVE = 0x00000020;
|
||||
FILE_ATTRIBUTE_DEVICE = 0x00000040;
|
||||
FILE_ATTRIBUTE_NORMAL = 0x00000080;
|
||||
FILE_ATTRIBUTE_TEMPORARY = 0x00000100;
|
||||
FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200;
|
||||
FILE_ATTRIBUTE_REPARSE_Point = 0x00000400;
|
||||
FILE_ATTRIBUTE_COMPRESSED = 0x00000800;
|
||||
FILE_ATTRIBUTE_OFFLINE = 0x00001000;
|
||||
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000;
|
||||
FILE_ATTRIBUTE_ENCRYPTED = 0x00004000;
|
||||
INVALID_FILE_ATTRIBUTES :: -1;
|
||||
|
||||
FILE_TYPE_DISK = 0x0001;
|
||||
FILE_TYPE_CHAR = 0x0002;
|
||||
FILE_TYPE_PIPE = 0x0003;
|
||||
)
|
||||
FILE_ATTRIBUTE_READONLY :: 0x00000001;
|
||||
FILE_ATTRIBUTE_HIDDEN :: 0x00000002;
|
||||
FILE_ATTRIBUTE_SYSTEM :: 0x00000004;
|
||||
FILE_ATTRIBUTE_DIRECTORY :: 0x00000010;
|
||||
FILE_ATTRIBUTE_ARCHIVE :: 0x00000020;
|
||||
FILE_ATTRIBUTE_DEVICE :: 0x00000040;
|
||||
FILE_ATTRIBUTE_NORMAL :: 0x00000080;
|
||||
FILE_ATTRIBUTE_TEMPORARY :: 0x00000100;
|
||||
FILE_ATTRIBUTE_SPARSE_FILE :: 0x00000200;
|
||||
FILE_ATTRIBUTE_REPARSE_Point :: 0x00000400;
|
||||
FILE_ATTRIBUTE_COMPRESSED :: 0x00000800;
|
||||
FILE_ATTRIBUTE_OFFLINE :: 0x00001000;
|
||||
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED :: 0x00002000;
|
||||
FILE_ATTRIBUTE_ENCRYPTED :: 0x00004000;
|
||||
|
||||
FILE_TYPE_DISK :: 0x0001;
|
||||
FILE_TYPE_CHAR :: 0x0002;
|
||||
FILE_TYPE_PIPE :: 0x0003;
|
||||
|
||||
|
||||
type MonitorInfo struct #ordered {
|
||||
size: u32,
|
||||
monitor: Rect,
|
||||
work: Rect,
|
||||
flags: u32,
|
||||
MonitorInfo :: struct #ordered {
|
||||
size: u32;
|
||||
monitor: Rect;
|
||||
work: Rect;
|
||||
flags: u32;
|
||||
}
|
||||
|
||||
type WindowPlacement struct #ordered {
|
||||
length: u32,
|
||||
flags: u32,
|
||||
show_cmd: u32,
|
||||
min_pos: Point,
|
||||
max_pos: Point,
|
||||
normal_pos: Rect,
|
||||
WindowPlacement :: struct #ordered {
|
||||
length: u32;
|
||||
flags: u32;
|
||||
show_cmd: u32;
|
||||
min_pos: Point;
|
||||
max_pos: Point;
|
||||
normal_pos: Rect;
|
||||
}
|
||||
|
||||
type BitmapInfoHeader struct #ordered {
|
||||
size: u32,
|
||||
width, height: i32,
|
||||
planes, bit_count: i16,
|
||||
compression: u32,
|
||||
size_image: u32,
|
||||
x_pels_per_meter: i32,
|
||||
y_pels_per_meter: i32,
|
||||
clr_used: u32,
|
||||
clr_important: u32,
|
||||
BitmapInfoHeader :: struct #ordered {
|
||||
size: u32;
|
||||
width, height: i32;
|
||||
planes, bit_count: i16;
|
||||
compression: u32;
|
||||
size_image: u32;
|
||||
x_pels_per_meter: i32;
|
||||
y_pels_per_meter: i32;
|
||||
clr_used: u32;
|
||||
clr_important: u32;
|
||||
}
|
||||
type BitmapInfo struct #ordered {
|
||||
using header: BitmapInfoHeader,
|
||||
colors: [1]RgbQuad,
|
||||
BitmapInfo :: struct #ordered {
|
||||
using header: BitmapInfoHeader;
|
||||
colors: [1]RgbQuad;
|
||||
}
|
||||
|
||||
|
||||
type RgbQuad struct #ordered { blue, green, red, reserved: u8 }
|
||||
RgbQuad :: struct #ordered { blue, green, red, reserved: u8 }
|
||||
|
||||
|
||||
type KeyCode enum i32 {
|
||||
KeyCode :: enum i32 {
|
||||
Lbutton = 0x01,
|
||||
Rbutton = 0x02,
|
||||
Cancel = 0x03,
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
_ :: compile_assert(ODIN_OS == "windows");
|
||||
|
||||
import win32 "sys/windows.odin";
|
||||
|
||||
Thread :: struct {
|
||||
using specific: OsSpecific;
|
||||
procedure: Proc;
|
||||
data: any;
|
||||
user_index: int;
|
||||
|
||||
init_context: Context;
|
||||
use_init_context: bool;
|
||||
|
||||
Proc :: #type proc(^Thread) -> int;
|
||||
OsSpecific :: struct {
|
||||
win32_thread: win32.Handle;
|
||||
win32_thread_id: u32;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
create :: proc(procedure: Thread.Proc) -> ^Thread {
|
||||
win32_thread_id: u32;
|
||||
|
||||
__windows_thread_entry_proc :: proc(data: rawptr) -> i32 #cc_c {
|
||||
if data == nil do return 0;
|
||||
|
||||
t := cast(^Thread)data;
|
||||
|
||||
c := context;
|
||||
if t.use_init_context {
|
||||
c = t.init_context;
|
||||
}
|
||||
|
||||
exit := 0;
|
||||
push_context c {
|
||||
exit = t.procedure(t);
|
||||
}
|
||||
|
||||
return cast(i32)exit;
|
||||
}
|
||||
|
||||
|
||||
win32_thread_proc := cast(rawptr)__windows_thread_entry_proc;
|
||||
thread := new(Thread);
|
||||
|
||||
win32_thread := win32.create_thread(nil, 0, win32_thread_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id);
|
||||
if win32_thread == nil {
|
||||
free(thread);
|
||||
return nil;
|
||||
}
|
||||
thread.procedure = procedure;
|
||||
thread.win32_thread = win32_thread;
|
||||
thread.win32_thread_id = win32_thread_id;
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
start :: proc(using thread: ^Thread) {
|
||||
win32.resume_thread(win32_thread);
|
||||
}
|
||||
|
||||
is_done :: proc(using thread: ^Thread) -> bool {
|
||||
res := win32.wait_for_single_object(win32_thread, 0);
|
||||
return res != win32.WAIT_TIMEOUT;
|
||||
}
|
||||
|
||||
join :: proc(using thread: ^Thread) {
|
||||
win32.wait_for_single_object(win32_thread, win32.INFINITE);
|
||||
win32.close_handle(win32_thread);
|
||||
win32_thread = win32.INVALID_HANDLE;
|
||||
}
|
||||
destroy :: proc(thread: ^Thread) {
|
||||
join(thread);
|
||||
free(thread);
|
||||
}
|
||||
+64
-59
@@ -1,98 +1,103 @@
|
||||
proc is_signed(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
match i in type_info_base(info) {
|
||||
is_signed :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
match i in type_info_base(info).variant {
|
||||
case TypeInfo.Integer: return i.signed;
|
||||
case TypeInfo.Float: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
proc is_integer(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Integer);
|
||||
is_integer :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Integer);
|
||||
return ok;
|
||||
}
|
||||
proc is_float(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Float);
|
||||
is_rune :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Rune);
|
||||
return ok;
|
||||
}
|
||||
proc is_complex(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Complex);
|
||||
is_float :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Float);
|
||||
return ok;
|
||||
}
|
||||
proc is_any(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Any);
|
||||
is_complex :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Complex);
|
||||
return ok;
|
||||
}
|
||||
proc is_string(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.String);
|
||||
is_any :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Any);
|
||||
return ok;
|
||||
}
|
||||
proc is_boolean(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Boolean);
|
||||
is_string :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.String);
|
||||
return ok;
|
||||
}
|
||||
proc is_pointer(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Pointer);
|
||||
is_boolean :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Boolean);
|
||||
return ok;
|
||||
}
|
||||
proc is_procedure(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Procedure);
|
||||
is_pointer :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Pointer);
|
||||
return ok;
|
||||
}
|
||||
proc is_array(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Array);
|
||||
is_procedure :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Procedure);
|
||||
return ok;
|
||||
}
|
||||
proc is_dynamic_array(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.DynamicArray);
|
||||
is_array :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Array);
|
||||
return ok;
|
||||
}
|
||||
proc is_dynamic_map(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Map);
|
||||
is_dynamic_array :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.DynamicArray);
|
||||
return ok;
|
||||
}
|
||||
proc is_slice(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Slice);
|
||||
is_dynamic_map :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Map);
|
||||
return ok;
|
||||
}
|
||||
proc is_vector(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Vector);
|
||||
is_slice :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Slice);
|
||||
return ok;
|
||||
}
|
||||
proc is_tuple(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Tuple);
|
||||
is_vector :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Vector);
|
||||
return ok;
|
||||
}
|
||||
proc is_struct(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Struct);
|
||||
is_tuple :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Tuple);
|
||||
return ok;
|
||||
}
|
||||
proc is_union(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Union);
|
||||
is_struct :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
s, ok := type_info_base(info).variant.(TypeInfo.Struct);
|
||||
return ok && !s.is_raw_union;
|
||||
}
|
||||
is_raw_union :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
s, ok := type_info_base(info).variant.(TypeInfo.Struct);
|
||||
return ok && s.is_raw_union;
|
||||
}
|
||||
is_union :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Union);
|
||||
return ok;
|
||||
}
|
||||
proc is_raw_union(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.RawUnion);
|
||||
return ok;
|
||||
}
|
||||
proc is_enum(info: ^TypeInfo) -> bool {
|
||||
if info == nil { return false; }
|
||||
var _, ok = type_info_base(info).(^TypeInfo.Enum);
|
||||
is_enum :: proc(info: ^TypeInfo) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(TypeInfo.Enum);
|
||||
return ok;
|
||||
}
|
||||
|
||||
+18
-23
@@ -1,18 +1,17 @@
|
||||
const (
|
||||
REPLACEMENT_CHAR = '\uFFFD';
|
||||
MAX_RUNE = '\U0010FFFF';
|
||||
REPLACEMENT_CHAR :: '\uFFFD';
|
||||
MAX_RUNE :: '\U0010FFFF';
|
||||
|
||||
_surr1 = 0xd800;
|
||||
_surr2 = 0xdc00;
|
||||
_surr3 = 0xe000;
|
||||
_surr_self = 0x10000;
|
||||
)
|
||||
_surr1 :: 0xd800;
|
||||
_surr2 :: 0xdc00;
|
||||
_surr3 :: 0xe000;
|
||||
_surr_self :: 0x10000;
|
||||
|
||||
proc is_surrogate(r: rune) -> bool {
|
||||
|
||||
is_surrogate :: proc(r: rune) -> bool {
|
||||
return _surr1 <= r && r < _surr3;
|
||||
}
|
||||
|
||||
proc decode_surrogate_pair(r1, r2: rune) -> rune {
|
||||
decode_surrogate_pair :: proc(r1, r2: rune) -> rune {
|
||||
if _surr1 <= r1 && r1 < _surr2 && _surr2 <= r2 && r2 < _surr3 {
|
||||
return (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self;
|
||||
}
|
||||
@@ -20,7 +19,7 @@ proc decode_surrogate_pair(r1, r2: rune) -> rune {
|
||||
}
|
||||
|
||||
|
||||
proc encode_surrogate_pair(r: rune) -> (r1, r2: rune) {
|
||||
encode_surrogate_pair :: proc(r: rune) -> (r1, r2: rune) {
|
||||
if r < _surr_self || r > MAX_RUNE {
|
||||
return REPLACEMENT_CHAR, REPLACEMENT_CHAR;
|
||||
}
|
||||
@@ -28,32 +27,28 @@ proc encode_surrogate_pair(r: rune) -> (r1, r2: rune) {
|
||||
return _surr1 + (r>>10)&0x3ff, _surr2 + r&0x3ff;
|
||||
}
|
||||
|
||||
proc encode(d: []u16, s: []rune) {
|
||||
var n = len(s);
|
||||
for r in s {
|
||||
if r >= _surr_self {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
encode :: proc(d: []u16, s: []rune) {
|
||||
n := len(s);
|
||||
for r in s do if r >= _surr_self do n += 1;
|
||||
|
||||
var max_n = min(len(d), n);
|
||||
max_n := min(len(d), n);
|
||||
n = 0;
|
||||
|
||||
for r in s {
|
||||
match r {
|
||||
case 0..<_surr1, _surr3..<_surr_self:
|
||||
case 0.._surr1, _surr3.._surr_self:
|
||||
d[n] = u16(r);
|
||||
n++;
|
||||
n += 1;
|
||||
|
||||
case _surr_self..MAX_RUNE:
|
||||
var r1, r2 = encode_surrogate_pair(r);
|
||||
r1, r2 := encode_surrogate_pair(r);
|
||||
d[n] = u16(r1);
|
||||
d[n+1] = u16(r2);
|
||||
n += 2;
|
||||
|
||||
case:
|
||||
d[n] = u16(REPLACEMENT_CHAR);
|
||||
n++;
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+102
-110
@@ -1,71 +1,67 @@
|
||||
const (
|
||||
RUNE_ERROR = '\ufffd';
|
||||
RUNE_SELF = 0x80;
|
||||
RUNE_BOM = 0xfeff;
|
||||
RUNE_EOF = ~rune(0);
|
||||
MAX_RUNE = '\U0010ffff';
|
||||
UTF_MAX = 4;
|
||||
RUNE_ERROR :: '\ufffd';
|
||||
RUNE_SELF :: 0x80;
|
||||
RUNE_BOM :: 0xfeff;
|
||||
RUNE_EOF :: ~rune(0);
|
||||
MAX_RUNE :: '\U0010ffff';
|
||||
UTF_MAX :: 4;
|
||||
|
||||
SURROGATE_MIN = 0xd800;
|
||||
SURROGATE_MAX = 0xdfff;
|
||||
SURROGATE_MIN :: 0xd800;
|
||||
SURROGATE_MAX :: 0xdfff;
|
||||
|
||||
T1 = 0b0000_0000;
|
||||
TX = 0b1000_0000;
|
||||
T2 = 0b1100_0000;
|
||||
T3 = 0b1110_0000;
|
||||
T4 = 0b1111_0000;
|
||||
T5 = 0b1111_1000;
|
||||
T1 :: 0b0000_0000;
|
||||
TX :: 0b1000_0000;
|
||||
T2 :: 0b1100_0000;
|
||||
T3 :: 0b1110_0000;
|
||||
T4 :: 0b1111_0000;
|
||||
T5 :: 0b1111_1000;
|
||||
|
||||
MASKX = 0b0011_1111;
|
||||
MASK2 = 0b0001_1111;
|
||||
MASK3 = 0b0000_1111;
|
||||
MASK4 = 0b0000_0111;
|
||||
MASKX :: 0b0011_1111;
|
||||
MASK2 :: 0b0001_1111;
|
||||
MASK3 :: 0b0000_1111;
|
||||
MASK4 :: 0b0000_0111;
|
||||
|
||||
RUNE1_MAX = 1<<7 - 1;
|
||||
RUNE2_MAX = 1<<11 - 1;
|
||||
RUNE3_MAX = 1<<16 - 1;
|
||||
RUNE1_MAX :: 1<<7 - 1;
|
||||
RUNE2_MAX :: 1<<11 - 1;
|
||||
RUNE3_MAX :: 1<<16 - 1;
|
||||
|
||||
// The default lowest and highest continuation byte.
|
||||
LOCB = 0b1000_0000;
|
||||
HICB = 0b1011_1111;
|
||||
)
|
||||
LOCB :: 0b1000_0000;
|
||||
HICB :: 0b1011_1111;
|
||||
|
||||
type AcceptRange struct { lo, hi: u8 }
|
||||
AcceptRange :: struct { lo, hi: u8 }
|
||||
|
||||
var (
|
||||
accept_ranges = [5]AcceptRange{
|
||||
{0x80, 0xbf},
|
||||
{0xa0, 0xbf},
|
||||
{0x80, 0x9f},
|
||||
{0x90, 0xbf},
|
||||
{0x80, 0x8f},
|
||||
};
|
||||
accept_ranges := [5]AcceptRange{
|
||||
{0x80, 0xbf},
|
||||
{0xa0, 0xbf},
|
||||
{0x80, 0x9f},
|
||||
{0x90, 0xbf},
|
||||
{0x80, 0x8f},
|
||||
};
|
||||
|
||||
accept_sizes = [256]u8{
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
|
||||
accept_sizes := [256]u8{
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
|
||||
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
|
||||
0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
|
||||
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
|
||||
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
|
||||
};
|
||||
)
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
|
||||
0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
|
||||
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
|
||||
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
|
||||
};
|
||||
|
||||
proc encode_rune(r: rune) -> ([4]u8, int) {
|
||||
var buf: [4]u8;
|
||||
var i = u32(r);
|
||||
const mask: u8 = 0x3f;
|
||||
encode_rune :: proc(r: rune) -> ([4]u8, int) {
|
||||
buf: [4]u8;
|
||||
i := u32(r);
|
||||
mask: u8 : 0x3f;
|
||||
if i <= 1<<7-1 {
|
||||
buf[0] = u8(r);
|
||||
return buf, 1;
|
||||
@@ -96,38 +92,38 @@ proc encode_rune(r: rune) -> ([4]u8, int) {
|
||||
return buf, 4;
|
||||
}
|
||||
|
||||
proc decode_rune(s: string) -> (rune, int) #inline { return decode_rune([]u8(s)); }
|
||||
proc decode_rune(s: []u8) -> (rune, int) {
|
||||
var n = len(s);
|
||||
decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune(cast([]u8)s); }
|
||||
decode_rune :: proc(s: []u8) -> (rune, int) {
|
||||
n := len(s);
|
||||
if n < 1 {
|
||||
return RUNE_ERROR, 0;
|
||||
}
|
||||
var s0 = s[0];
|
||||
var x = accept_sizes[s0];
|
||||
s0 := s[0];
|
||||
x := accept_sizes[s0];
|
||||
if x >= 0xF0 {
|
||||
var mask = rune(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
|
||||
mask := rune(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
|
||||
return rune(s[0])&~mask | RUNE_ERROR&mask, 1;
|
||||
}
|
||||
var sz = x & 7;
|
||||
var accept = accept_ranges[x>>4];
|
||||
sz := x & 7;
|
||||
accept := accept_ranges[x>>4];
|
||||
if n < int(sz) {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
var b1 = s[1];
|
||||
b1 := s[1];
|
||||
if b1 < accept.lo || accept.hi < b1 {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
if sz == 2 {
|
||||
return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2;
|
||||
}
|
||||
var b2 = s[2];
|
||||
b2 := s[2];
|
||||
if b2 < LOCB || HICB < b2 {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
if sz == 3 {
|
||||
return rune(s0&MASK3)<<12 | rune(b1&MASKX)<<6 | rune(b2&MASKX), 3;
|
||||
}
|
||||
var b3 = s[3];
|
||||
b3 := s[3];
|
||||
if b3 < LOCB || HICB < b3 {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
@@ -136,11 +132,11 @@ proc decode_rune(s: []u8) -> (rune, int) {
|
||||
|
||||
|
||||
|
||||
proc decode_last_rune(s: string) -> (rune, int) #inline { return decode_last_rune([]u8(s)); }
|
||||
proc decode_last_rune(s: []u8) -> (rune, int) {
|
||||
var r: rune;
|
||||
var size: int;
|
||||
var start, end, limit: int;
|
||||
decode_last_rune :: proc(s: string) -> (rune, int) #inline { return decode_last_rune(cast([]u8)s); }
|
||||
decode_last_rune :: proc(s: []u8) -> (rune, int) {
|
||||
r: rune;
|
||||
size: int;
|
||||
start, end, limit: int;
|
||||
|
||||
end = len(s);
|
||||
if end == 0 {
|
||||
@@ -155,16 +151,12 @@ proc decode_last_rune(s: []u8) -> (rune, int) {
|
||||
|
||||
limit = max(end - UTF_MAX, 0);
|
||||
|
||||
start--;
|
||||
for start >= limit {
|
||||
if rune_start(s[start]) {
|
||||
break;
|
||||
}
|
||||
start--;
|
||||
for start-=1; start >= limit; start-=1 {
|
||||
if rune_start(s[start]) do break;
|
||||
}
|
||||
|
||||
start = max(start, 0);
|
||||
r, size = decode_rune(s[start..<end]);
|
||||
r, size = decode_rune(s[start..end]);
|
||||
if start+size != end {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
@@ -175,7 +167,7 @@ proc decode_last_rune(s: []u8) -> (rune, int) {
|
||||
|
||||
|
||||
|
||||
proc valid_rune(r: rune) -> bool {
|
||||
valid_rune :: proc(r: rune) -> bool {
|
||||
if r < 0 {
|
||||
return false;
|
||||
} else if SURROGATE_MIN <= r && r <= SURROGATE_MAX {
|
||||
@@ -186,32 +178,32 @@ proc valid_rune(r: rune) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
proc valid_string(s: string) -> bool {
|
||||
var n = len(s);
|
||||
for var i = 0; i < n; {
|
||||
var si = s[i];
|
||||
valid_string :: proc(s: string) -> bool {
|
||||
n := len(s);
|
||||
for i := 0; i < n; {
|
||||
si := s[i];
|
||||
if si < RUNE_SELF { // ascii
|
||||
i++;
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
var x = accept_sizes[si];
|
||||
x := accept_sizes[si];
|
||||
if x == 0xf1 {
|
||||
return false;
|
||||
}
|
||||
var size = int(x & 7);
|
||||
size := int(x & 7);
|
||||
if i+size > n {
|
||||
return false;
|
||||
}
|
||||
var ar = accept_ranges[x>>4];
|
||||
if var b = s[i+1]; b < ar.lo || ar.hi < b {
|
||||
ar := accept_ranges[x>>4];
|
||||
if b := s[i+1]; b < ar.lo || ar.hi < b {
|
||||
return false;
|
||||
} else if size == 2 {
|
||||
// Okay
|
||||
} else if var b = s[i+2]; b < 0x80 || 0xbf < b {
|
||||
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
|
||||
return false;
|
||||
} else if size == 3 {
|
||||
// Okay
|
||||
} else if var b = s[i+3]; b < 0x80 || 0xbf < b {
|
||||
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
|
||||
return false;
|
||||
}
|
||||
i += size;
|
||||
@@ -219,40 +211,40 @@ proc valid_string(s: string) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
proc rune_start(b: u8) -> bool #inline { return b&0xc0 != 0x80; }
|
||||
rune_start :: proc(b: u8) -> bool #inline { return b&0xc0 != 0x80; }
|
||||
|
||||
proc rune_count(s: string) -> int #inline { return rune_count([]u8(s)); }
|
||||
proc rune_count(s: []u8) -> int {
|
||||
var count = 0;
|
||||
var n = len(s);
|
||||
rune_count :: proc(s: string) -> int #inline { return rune_count(cast([]u8)s); }
|
||||
rune_count :: proc(s: []u8) -> int {
|
||||
count := 0;
|
||||
n := len(s);
|
||||
|
||||
for var i = 0; i < n; {
|
||||
defer count++;
|
||||
var si = s[i];
|
||||
for i := 0; i < n; {
|
||||
defer count += 1;
|
||||
si := s[i];
|
||||
if si < RUNE_SELF { // ascii
|
||||
i++;
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
var x = accept_sizes[si];
|
||||
x := accept_sizes[si];
|
||||
if x == 0xf1 {
|
||||
i++;
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
var size = int(x & 7);
|
||||
size := int(x & 7);
|
||||
if i+size > n {
|
||||
i++;
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
var ar = accept_ranges[x>>4];
|
||||
if var b = s[i+1]; b < ar.lo || ar.hi < b {
|
||||
ar := accept_ranges[x>>4];
|
||||
if b := s[i+1]; b < ar.lo || ar.hi < b {
|
||||
size = 1;
|
||||
} else if size == 2 {
|
||||
// Okay
|
||||
} else if var b = s[i+2]; b < 0x80 || 0xbf < b {
|
||||
} else if b := s[i+2]; b < 0x80 || 0xbf < b {
|
||||
size = 1;
|
||||
} else if size == 3 {
|
||||
// Okay
|
||||
} else if var b = s[i+3]; b < 0x80 || 0xbf < b {
|
||||
} else if b := s[i+3]; b < 0x80 || 0xbf < b {
|
||||
size = 1;
|
||||
}
|
||||
i += size;
|
||||
@@ -261,7 +253,7 @@ proc rune_count(s: []u8) -> int {
|
||||
}
|
||||
|
||||
|
||||
proc rune_size(r: rune) -> int {
|
||||
rune_size :: proc(r: rune) -> int {
|
||||
match {
|
||||
case r < 0: return -1;
|
||||
case r <= 1<<7 - 1: return 1;
|
||||
|
||||
+11
-8
@@ -10,12 +10,16 @@ struct Array {
|
||||
isize capacity;
|
||||
|
||||
T &operator[](isize index) {
|
||||
GB_ASSERT_MSG(0 <= index && index < count, "Index out of bounds");
|
||||
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
||||
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||
#endif
|
||||
return data[index];
|
||||
}
|
||||
|
||||
T const &operator[](isize index) const {
|
||||
GB_ASSERT_MSG(0 <= index && index < count, "Index out of bounds");
|
||||
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
||||
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||
#endif
|
||||
return data[index];
|
||||
}
|
||||
};
|
||||
@@ -31,7 +35,6 @@ template <typename T> void array_reserve (Array<T> *array, isize capacit
|
||||
template <typename T> void array_resize (Array<T> *array, isize count);
|
||||
template <typename T> void array_set_capacity(Array<T> *array, isize capacity);
|
||||
|
||||
|
||||
template <typename T>
|
||||
void array_init(Array<T> *array, gbAllocator a, isize init_capacity) {
|
||||
array->allocator = a;
|
||||
@@ -61,7 +64,7 @@ Array<T> array_make(T *data, isize count, isize capacity) {
|
||||
|
||||
template <typename T>
|
||||
void array_free(Array<T> *array) {
|
||||
if (array->allocator.proc != NULL) {
|
||||
if (array->allocator.proc != nullptr) {
|
||||
gb_free(array->allocator, array->data);
|
||||
}
|
||||
array->count = 0;
|
||||
@@ -123,7 +126,7 @@ void array_set_capacity(Array<T> *array, isize capacity) {
|
||||
array_resize(array, capacity);
|
||||
}
|
||||
|
||||
T *new_data = NULL;
|
||||
T *new_data = nullptr;
|
||||
if (capacity > 0) {
|
||||
new_data = gb_alloc_array(array->allocator, T, capacity);
|
||||
gb_memmove(new_data, array->data, gb_size_of(T) * array->capacity);
|
||||
@@ -147,7 +150,7 @@ typedef Array(void) ArrayVoid;
|
||||
|
||||
#define array_init_reserve(x_, allocator_, init_capacity_) do { \
|
||||
void **e = cast(void **)&((x_)->e); \
|
||||
GB_ASSERT((x_) != NULL); \
|
||||
GB_ASSERT((x_) != nullptr); \
|
||||
(x_)->allocator = (allocator_); \
|
||||
(x_)->count = 0; \
|
||||
(x_)->capacity = (init_capacity_); \
|
||||
@@ -156,7 +159,7 @@ typedef Array(void) ArrayVoid;
|
||||
|
||||
#define array_init_count(x_, allocator_, init_count_) do { \
|
||||
void **e = cast(void **)&((x_)->e); \
|
||||
GB_ASSERT((x_) != NULL); \
|
||||
GB_ASSERT((x_) != nullptr); \
|
||||
(x_)->allocator = (allocator_); \
|
||||
(x_)->count = (init_count_); \
|
||||
(x_)->capacity = (init_count_); \
|
||||
@@ -203,7 +206,7 @@ typedef Array(void) ArrayVoid;
|
||||
|
||||
void array__set_capacity(void *ptr, isize capacity, isize element_size) {
|
||||
ArrayVoid *x = cast(ArrayVoid *)ptr;
|
||||
GB_ASSERT(ptr != NULL);
|
||||
GB_ASSERT(ptr != nullptr);
|
||||
|
||||
GB_ASSERT(element_size > 0);
|
||||
|
||||
|
||||
+41
-18
@@ -18,6 +18,11 @@ struct BuildContext {
|
||||
bool is_dll;
|
||||
bool generate_docs;
|
||||
i32 optimization_level;
|
||||
bool show_timings;
|
||||
bool keep_temp_files;
|
||||
|
||||
gbAffinity affinity;
|
||||
isize thread_count;
|
||||
};
|
||||
|
||||
|
||||
@@ -53,9 +58,9 @@ String odin_root_dir(void) {
|
||||
|
||||
len = 0;
|
||||
for (;;) {
|
||||
len = GetModuleFileNameW(NULL, &path_buf[0], path_buf.count);
|
||||
len = GetModuleFileNameW(nullptr, &path_buf[0], cast(int)path_buf.count);
|
||||
if (len == 0) {
|
||||
return make_string(NULL, 0);
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
if (len < path_buf.count) {
|
||||
break;
|
||||
@@ -64,12 +69,15 @@ String odin_root_dir(void) {
|
||||
}
|
||||
len += 1; // NOTE(bill): It needs an extra 1 for some reason
|
||||
|
||||
gb_mutex_lock(&string_buffer_mutex);
|
||||
defer (gb_mutex_unlock(&string_buffer_mutex));
|
||||
|
||||
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
|
||||
|
||||
GetModuleFileNameW(NULL, text, len);
|
||||
GetModuleFileNameW(nullptr, text, cast(int)len);
|
||||
path = string16_to_string(heap_allocator(), make_string16(text, len));
|
||||
|
||||
for (i = path.len-1; i >= 0; i--) {
|
||||
@@ -83,7 +91,6 @@ String odin_root_dir(void) {
|
||||
global_module_path = path;
|
||||
global_module_path_set = true;
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
|
||||
array_free(&path_buf);
|
||||
|
||||
@@ -119,8 +126,12 @@ String odin_root_dir(void) {
|
||||
}
|
||||
}
|
||||
|
||||
gb_mutex_lock(&string_buffer_mutex);
|
||||
defer (gb_mutex_unlock(&string_buffer_mutex));
|
||||
|
||||
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
|
||||
gb_memmove(text, &path_buf[0], len);
|
||||
|
||||
@@ -136,7 +147,6 @@ String odin_root_dir(void) {
|
||||
global_module_path = path;
|
||||
global_module_path_set = true;
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
|
||||
// array_free(&path_buf);
|
||||
|
||||
@@ -159,6 +169,7 @@ String odin_root_dir(void) {
|
||||
}
|
||||
|
||||
array_init_count(&path_buf, heap_allocator(), 300);
|
||||
defer (array_free(&path_buf));
|
||||
|
||||
len = 0;
|
||||
for (;;) {
|
||||
@@ -168,7 +179,7 @@ String odin_root_dir(void) {
|
||||
// path without checking this link. Sorry.
|
||||
len = readlink("/proc/self/exe", &path_buf[0], path_buf.count);
|
||||
if(len == 0) {
|
||||
return make_string(NULL, 0);
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
if (len < path_buf.count) {
|
||||
break;
|
||||
@@ -176,9 +187,14 @@ String odin_root_dir(void) {
|
||||
array_resize(&path_buf, 2*path_buf.count + 300);
|
||||
}
|
||||
|
||||
gb_mutex_lock(&string_buffer_mutex);
|
||||
defer (gb_mutex_unlock(&string_buffer_mutex));
|
||||
|
||||
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
|
||||
|
||||
gb_memmove(text, &path_buf[0], len);
|
||||
|
||||
path = make_string(text, len);
|
||||
@@ -193,10 +209,6 @@ String odin_root_dir(void) {
|
||||
global_module_path = path;
|
||||
global_module_path_set = true;
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
|
||||
array_free(&path_buf);
|
||||
|
||||
return path;
|
||||
}
|
||||
#endif
|
||||
@@ -204,14 +216,17 @@ String odin_root_dir(void) {
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
String path_to_fullpath(gbAllocator a, String s) {
|
||||
String result = {};
|
||||
gb_mutex_lock(&string_buffer_mutex);
|
||||
defer (gb_mutex_unlock(&string_buffer_mutex));
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
||||
String16 string16 = string_to_string16(string_buffer_allocator, s);
|
||||
String result = {0};
|
||||
|
||||
DWORD len = GetFullPathNameW(&string16[0], 0, NULL, NULL);
|
||||
DWORD len = GetFullPathNameW(&string16[0], 0, nullptr, nullptr);
|
||||
if (len != 0) {
|
||||
wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
|
||||
GetFullPathNameW(&string16[0], len, text, NULL);
|
||||
GetFullPathNameW(&string16[0], len, text, nullptr);
|
||||
text[len] = 0;
|
||||
result = string16_to_string(a, make_string16(text, len));
|
||||
}
|
||||
@@ -220,9 +235,11 @@ String path_to_fullpath(gbAllocator a, String s) {
|
||||
}
|
||||
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
|
||||
String path_to_fullpath(gbAllocator a, String s) {
|
||||
char *p = realpath(cast(char *)&s[0], 0);
|
||||
if(p == NULL) return make_string_c("");
|
||||
|
||||
char *p;
|
||||
gb_mutex_lock(&string_buffer_mutex);
|
||||
p = realpath(cast(char *)s.text, 0);
|
||||
gb_mutex_unlock(&string_buffer_mutex);
|
||||
if(p == nullptr) return make_string_c("");
|
||||
return make_string_c(p);
|
||||
}
|
||||
#else
|
||||
@@ -266,12 +283,18 @@ String get_fullpath_core(gbAllocator a, String path) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
String const ODIN_VERSION = str_lit("0.6.1a");
|
||||
|
||||
void init_build_context(void) {
|
||||
BuildContext *bc = &build_context;
|
||||
|
||||
gb_affinity_init(&bc->affinity);
|
||||
if (bc->thread_count == 0) {
|
||||
bc->thread_count = gb_max(bc->affinity.thread_count, 1);
|
||||
}
|
||||
|
||||
bc->ODIN_VENDOR = str_lit("odin");
|
||||
bc->ODIN_VERSION = str_lit("0.5.0");
|
||||
bc->ODIN_VERSION = ODIN_VERSION;
|
||||
bc->ODIN_ROOT = odin_root_dir();
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
|
||||
+226
-120
@@ -23,41 +23,58 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
}
|
||||
|
||||
|
||||
if (e->type == NULL) {
|
||||
if (operand->mode == Addressing_Overload) {
|
||||
if (e->type == nullptr) {
|
||||
error(operand->expr, "Cannot determine type from overloaded procedure `%.*s`", LIT(operand->overload_entities[0]->token.string));
|
||||
} else {
|
||||
check_assignment(c, operand, e->type, str_lit("variable assignment"));
|
||||
if (operand->mode != Addressing_Type) {
|
||||
return operand->type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e->type == nullptr) {
|
||||
e->type = t_invalid;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (e->type == NULL) {
|
||||
|
||||
|
||||
if (e->type == nullptr) {
|
||||
|
||||
// NOTE(bill): Use the type of the operand
|
||||
Type *t = operand->type;
|
||||
if (is_type_untyped(t)) {
|
||||
if (t == t_invalid || is_type_untyped_nil(t)) {
|
||||
error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
if (t == t_invalid || is_type_untyped_undef(t)) {
|
||||
error(e->token, "Invalid use of --- in %.*s", LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
t = default_type(t);
|
||||
}
|
||||
if (is_type_gen_proc(t)) {
|
||||
error(e->token, "Invalid use of a generic procedure in %.*s", LIT(context_name));
|
||||
if (is_type_polymorphic(t)) {
|
||||
gbString str = type_to_string(t);
|
||||
defer (gb_string_free(str));
|
||||
error(e->token, "Invalid use of a polymorphic type `%s` in %.*s", str, LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
} else if (is_type_empty_union(t)) {
|
||||
gbString str = type_to_string(t);
|
||||
defer (gb_string_free(str));
|
||||
error(e->token, "An empty union `%s` cannot be instantiated in %.*s", str, LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
return nullptr;
|
||||
}
|
||||
if (is_type_bit_field_value(t)) {
|
||||
t = default_bit_field_value_type(t);
|
||||
}
|
||||
if (is_type_variant(t)) {
|
||||
Type *st = base_type(t);
|
||||
GB_ASSERT(st->Record.variant_parent != NULL);
|
||||
t = st->Record.variant_parent;
|
||||
}
|
||||
GB_ASSERT(is_type_typed(t));
|
||||
e->type = t;
|
||||
}
|
||||
@@ -66,19 +83,20 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
|
||||
check_assignment(c, operand, e->type, context_name);
|
||||
if (operand->mode == Addressing_Invalid) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return e->type;
|
||||
}
|
||||
|
||||
void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNode *> inits, String context_name) {
|
||||
if ((lhs == NULL || lhs_count == 0) && inits.count == 0) {
|
||||
if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||
// an extra allocation
|
||||
@@ -100,16 +118,13 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNo
|
||||
if (rhs_count > 0 && lhs_count != rhs_count) {
|
||||
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
||||
}
|
||||
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
}
|
||||
|
||||
void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
||||
if (operand->mode == Addressing_Invalid ||
|
||||
operand->type == t_invalid ||
|
||||
e->type == t_invalid) {
|
||||
if (e->type == NULL) {
|
||||
if (e->type == nullptr) {
|
||||
e->type = t_invalid;
|
||||
}
|
||||
return;
|
||||
@@ -120,7 +135,7 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
||||
gbString str = expr_to_string(operand->expr);
|
||||
error(operand->expr, "`%s` is not a constant", str);
|
||||
gb_string_free(str);
|
||||
if (e->type == NULL) {
|
||||
if (e->type == nullptr) {
|
||||
e->type = t_invalid;
|
||||
}
|
||||
return;
|
||||
@@ -129,13 +144,13 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
error(operand->expr, "Invalid constant type: `%s`", type_str);
|
||||
gb_string_free(type_str);
|
||||
if (e->type == NULL) {
|
||||
if (e->type == nullptr) {
|
||||
e->type = t_invalid;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->type == NULL) { // NOTE(bill): type inference
|
||||
if (e->type == nullptr) { // NOTE(bill): type inference
|
||||
e->type = operand->type;
|
||||
}
|
||||
|
||||
@@ -150,11 +165,11 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
||||
}
|
||||
|
||||
void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
|
||||
GB_ASSERT(e->type == NULL);
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
String name = e->token.string;
|
||||
Type *named = make_type_named(c->allocator, name, NULL, e);
|
||||
Type *named = make_type_named(c->allocator, name, nullptr, e);
|
||||
named->Named.type_name = e;
|
||||
if (def != NULL && def->kind == Type_Named) {
|
||||
if (def != nullptr && def->kind == Type_Named) {
|
||||
def->Named.base = named;
|
||||
}
|
||||
e->type = named;
|
||||
@@ -169,7 +184,7 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
|
||||
}
|
||||
|
||||
void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, Type *named_type) {
|
||||
GB_ASSERT(e->type == NULL);
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
GB_ASSERT(e->kind == Entity_Constant);
|
||||
|
||||
if (e->flags & EntityFlag_Visited) {
|
||||
@@ -191,25 +206,92 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
}
|
||||
|
||||
Operand operand = {};
|
||||
if (init != NULL) {
|
||||
check_expr_or_type(c, &operand, init);
|
||||
}
|
||||
#if 0
|
||||
if (operand.mode == Addressing_Type) {
|
||||
e->kind = Entity_TypeName;
|
||||
|
||||
DeclInfo *d = c->context.decl;
|
||||
d->type_expr = d->init_expr;
|
||||
check_type_decl(c, e, d->type_expr, named_type);
|
||||
return;
|
||||
if (init != nullptr) {
|
||||
Entity *entity = nullptr;
|
||||
if (init->kind == AstNode_Ident) {
|
||||
entity = check_ident(c, &operand, init, nullptr, e->type, true);
|
||||
} else if (init->kind == AstNode_SelectorExpr) {
|
||||
entity = check_selector(c, &operand, init, e->type);
|
||||
} else {
|
||||
check_expr_or_type(c, &operand, init, e->type);
|
||||
}
|
||||
|
||||
switch (operand.mode) {
|
||||
case Addressing_Type: {
|
||||
e->kind = Entity_TypeName;
|
||||
|
||||
DeclInfo *d = c->context.decl;
|
||||
if (d->type_expr != nullptr) {
|
||||
error(e->token, "A type declaration cannot have an type parameter");
|
||||
}
|
||||
d->type_expr = d->init_expr;
|
||||
check_type_decl(c, e, d->type_expr, named_type);
|
||||
return;
|
||||
} break;
|
||||
|
||||
// NOTE(bill): Check to see if the expression it to be aliases
|
||||
#if 1
|
||||
case Addressing_Builtin:
|
||||
if (e->type != nullptr) {
|
||||
error(type_expr, "A constant alias of a built-in procedure may not have a type initializer");
|
||||
}
|
||||
e->kind = Entity_Builtin;
|
||||
e->Builtin.id = operand.builtin_id;
|
||||
e->type = t_invalid;
|
||||
return;
|
||||
|
||||
case Addressing_Overload:
|
||||
e->kind = Entity_Alias;
|
||||
e->Alias.base = operand.overload_entities[0];
|
||||
e->type = t_invalid;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
#if 1
|
||||
if (entity != nullptr) {
|
||||
switch (entity->kind) {
|
||||
case Entity_Alias:
|
||||
e->kind = Entity_Alias;
|
||||
e->type = entity->type;
|
||||
e->Alias.base = entity->Alias.base;
|
||||
return;
|
||||
case Entity_Procedure:
|
||||
e->kind = Entity_Alias;
|
||||
e->type = entity->type;
|
||||
e->Alias.base = entity;
|
||||
return;
|
||||
case Entity_ImportName:
|
||||
e->kind = Entity_ImportName;
|
||||
e->type = entity->type;
|
||||
e->ImportName.path = entity->ImportName.path;
|
||||
e->ImportName.name = entity->ImportName.path;
|
||||
e->ImportName.scope = entity->ImportName.scope;
|
||||
e->ImportName.used = false;
|
||||
return;
|
||||
case Entity_LibraryName:
|
||||
e->kind = Entity_LibraryName;
|
||||
e->type = entity->type;
|
||||
e->LibraryName.path = entity->LibraryName.path;
|
||||
e->LibraryName.name = entity->LibraryName.path;
|
||||
e->LibraryName.used = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (init != nullptr) {
|
||||
check_expr_or_type(c, &operand, init, e->type);
|
||||
}
|
||||
#endif
|
||||
|
||||
check_init_constant(c, e, &operand);
|
||||
|
||||
if (operand.mode == Addressing_Invalid ||
|
||||
base_type(operand.type) == t_invalid) {
|
||||
error(e->token, "Invalid declaration type");
|
||||
gbString str = expr_to_string(init);
|
||||
error(e->token, "Invalid declaration type `%s`", str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,14 +319,12 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||
if (is_type_integer(x) && is_type_integer(y)) {
|
||||
GB_ASSERT(x->kind == Type_Basic);
|
||||
GB_ASSERT(y->kind == Type_Basic);
|
||||
if (x->Basic.size == y->Basic.size) {
|
||||
continue;
|
||||
}
|
||||
i64 sx = type_size_of(heap_allocator(), x);
|
||||
i64 sy = type_size_of(heap_allocator(), y);
|
||||
if (sx == sy) continue;
|
||||
}
|
||||
|
||||
if (!are_types_identical(x, y)) {
|
||||
return false;
|
||||
}
|
||||
if (!are_types_identical(x, y)) return false;
|
||||
}
|
||||
for (isize i = 0; i < a->result_count; i++) {
|
||||
Type *x = base_type(a->results->Tuple.variables[i]->type);
|
||||
@@ -256,9 +336,9 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||
if (is_type_integer(x) && is_type_integer(y)) {
|
||||
GB_ASSERT(x->kind == Type_Basic);
|
||||
GB_ASSERT(y->kind == Type_Basic);
|
||||
if (x->Basic.size == y->Basic.size) {
|
||||
continue;
|
||||
}
|
||||
i64 sx = type_size_of(heap_allocator(), x);
|
||||
i64 sy = type_size_of(heap_allocator(), y);
|
||||
if (sx == sy) continue;
|
||||
}
|
||||
|
||||
if (!are_types_identical(x, y)) {
|
||||
@@ -270,8 +350,8 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||
}
|
||||
|
||||
void init_entity_foreign_library(Checker *c, Entity *e) {
|
||||
AstNode *ident = NULL;
|
||||
Entity **foreign_library = NULL;
|
||||
AstNode *ident = nullptr;
|
||||
Entity **foreign_library = nullptr;
|
||||
|
||||
switch (e->kind) {
|
||||
case Entity_Procedure:
|
||||
@@ -286,15 +366,15 @@ void init_entity_foreign_library(Checker *c, Entity *e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ident == NULL) {
|
||||
if (ident == nullptr) {
|
||||
error(e->token, "foreign entiies must declare which library they are from");
|
||||
} else if (ident->kind != AstNode_Ident) {
|
||||
error(ident, "foreign library names must be an identifier");
|
||||
} else {
|
||||
String name = ident->Ident.string;
|
||||
String name = ident->Ident.token.string;
|
||||
Entity *found = scope_lookup_entity(c->context.scope, name);
|
||||
if (found == NULL) {
|
||||
if (name == "_") {
|
||||
if (found == nullptr) {
|
||||
if (is_blank_ident(name)) {
|
||||
error(ident, "`_` cannot be used as a value type");
|
||||
} else {
|
||||
error(ident, "Undeclared name: %.*s", LIT(name));
|
||||
@@ -310,37 +390,44 @@ void init_entity_foreign_library(Checker *c, Entity *e) {
|
||||
}
|
||||
|
||||
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
GB_ASSERT(e->type == NULL);
|
||||
if (d->proc_decl->kind != AstNode_ProcDecl) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
if (d->proc_lit->kind != AstNode_ProcLit) {
|
||||
// TOOD(bill): Better error message
|
||||
error(d->proc_decl, "Expected a procedure to check");
|
||||
error(d->proc_lit, "Expected a procedure to check");
|
||||
return;
|
||||
}
|
||||
|
||||
Type *proc_type = e->type;
|
||||
if (d->gen_proc_type != NULL) {
|
||||
if (d->gen_proc_type != nullptr) {
|
||||
proc_type = d->gen_proc_type;
|
||||
} else {
|
||||
proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin);
|
||||
proc_type = make_type_proc(c->allocator, e->scope, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
|
||||
}
|
||||
e->type = proc_type;
|
||||
ast_node(pd, ProcDecl, d->proc_decl);
|
||||
ast_node(pl, ProcLit, d->proc_lit);
|
||||
|
||||
check_open_scope(c, pd->type);
|
||||
check_open_scope(c, pl->type);
|
||||
defer (check_close_scope(c));
|
||||
|
||||
check_procedure_type(c, proc_type, pd->type);
|
||||
|
||||
bool is_foreign = (pd->tags & ProcTag_foreign) != 0;
|
||||
bool is_link_name = (pd->tags & ProcTag_link_name) != 0;
|
||||
bool is_export = (pd->tags & ProcTag_export) != 0;
|
||||
bool is_inline = (pd->tags & ProcTag_inline) != 0;
|
||||
bool is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
|
||||
bool is_require_results = (pd->tags & ProcTag_require_results) != 0;
|
||||
|
||||
|
||||
auto prev_context = c->context;
|
||||
c->context.allow_polymorphic_types = true;
|
||||
check_procedure_type(c, proc_type, pl->type);
|
||||
c->context = prev_context;
|
||||
|
||||
TypeProc *pt = &proc_type->Proc;
|
||||
|
||||
bool is_foreign = (pl->tags & ProcTag_foreign) != 0;
|
||||
bool is_link_name = (pl->tags & ProcTag_link_name) != 0;
|
||||
bool is_export = (pl->tags & ProcTag_export) != 0;
|
||||
bool is_inline = (pl->tags & ProcTag_inline) != 0;
|
||||
bool is_no_inline = (pl->tags & ProcTag_no_inline) != 0;
|
||||
bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
|
||||
|
||||
|
||||
|
||||
if (d->scope->is_file && e->token.string == "main") {
|
||||
if (pt->param_count != 0 ||
|
||||
pt->result_count != 0) {
|
||||
@@ -348,51 +435,52 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
if (proc_type->Proc.calling_convention != ProcCC_Odin &&
|
||||
proc_type->Proc.calling_convention != ProcCC_Contextless) {
|
||||
if (pt->calling_convention != ProcCC_Odin &&
|
||||
pt->calling_convention != ProcCC_Contextless) {
|
||||
error(e->token, "Procedure `main` cannot have a custom calling convention");
|
||||
}
|
||||
proc_type->Proc.calling_convention = ProcCC_Contextless;
|
||||
pt->calling_convention = ProcCC_Contextless;
|
||||
}
|
||||
|
||||
if (is_inline && is_no_inline) {
|
||||
error(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
|
||||
error(pl->type, "You cannot apply both `inline` and `no_inline` to a procedure");
|
||||
}
|
||||
|
||||
if (is_foreign && is_export) {
|
||||
error(pd->type, "A foreign procedure cannot have an `export` tag");
|
||||
error(pl->type, "A foreign procedure cannot have an `export` tag");
|
||||
}
|
||||
|
||||
|
||||
if (pt->is_generic) {
|
||||
if (pd->body == NULL) {
|
||||
if (pt->is_polymorphic) {
|
||||
if (pl->body == nullptr) {
|
||||
error(e->token, "Polymorphic procedures must have a body");
|
||||
}
|
||||
|
||||
if (is_foreign) {
|
||||
error(e->token, "A foreign procedures cannot be a polymorphic");
|
||||
error(e->token, "A foreign procedure cannot be a polymorphic");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pd->body != NULL) {
|
||||
if (pl->body != nullptr) {
|
||||
if (is_foreign) {
|
||||
error(pd->body, "A foreign procedure cannot have a body");
|
||||
error(pl->body, "A foreign procedure cannot have a body");
|
||||
}
|
||||
if (proc_type->Proc.c_vararg) {
|
||||
error(pd->body, "A procedure with a `#c_vararg` field cannot have a body");
|
||||
error(pl->body, "A procedure with a `#c_vararg` field cannot have a body and must be foreign");
|
||||
}
|
||||
|
||||
d->scope = c->context.scope;
|
||||
|
||||
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
|
||||
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
|
||||
GB_ASSERT(pl->body->kind == AstNode_BlockStmt);
|
||||
if (!pt->is_polymorphic) {
|
||||
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pl->body, pl->tags);
|
||||
}
|
||||
} else if (!is_foreign) {
|
||||
error(e->token, "Only a foreign procedure cannot have a body");
|
||||
}
|
||||
|
||||
if (pt->result_count == 0 && is_require_results) {
|
||||
error(pd->type, "`#require_results` is not needed on a procedure with no results");
|
||||
error(pl->type, "`#require_results` is not needed on a procedure with no results");
|
||||
} else {
|
||||
pt->require_results = is_require_results;
|
||||
}
|
||||
@@ -401,8 +489,8 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
|
||||
if (is_foreign) {
|
||||
String name = e->token.string;
|
||||
if (pd->link_name.len > 0) {
|
||||
name = pd->link_name;
|
||||
if (pl->link_name.len > 0) {
|
||||
name = pl->link_name;
|
||||
}
|
||||
e->Procedure.is_foreign = true;
|
||||
e->Procedure.link_name = name;
|
||||
@@ -420,16 +508,16 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
Type *other_type = base_type(f->type);
|
||||
if (is_type_proc(this_type) && is_type_proc(other_type)) {
|
||||
if (!are_signatures_similar_enough(this_type, other_type)) {
|
||||
error(d->proc_decl,
|
||||
"Redeclaration of foreign procedure `%.*s` with different type signatures\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||
error(d->proc_lit,
|
||||
"Redeclaration of foreign procedure `%.*s` with different type signatures\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||
}
|
||||
} else if (!are_types_identical(this_type, other_type)) {
|
||||
error(d->proc_decl,
|
||||
"Foreign entity `%.*s` previously declared elsewhere with a different type\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||
error(d->proc_lit,
|
||||
"Foreign entity `%.*s` previously declared elsewhere with a different type\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||
}
|
||||
} else {
|
||||
map_set(fp, key, e);
|
||||
@@ -437,7 +525,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
} else {
|
||||
String name = e->token.string;
|
||||
if (is_link_name) {
|
||||
name = pd->link_name;
|
||||
name = pl->link_name;
|
||||
}
|
||||
|
||||
if (is_link_name || is_export) {
|
||||
@@ -451,10 +539,10 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
Entity *f = *found;
|
||||
TokenPos pos = f->token.pos;
|
||||
// TODO(bill): Better error message?
|
||||
error(d->proc_decl,
|
||||
"Non unique linking name for procedure `%.*s`\n"
|
||||
"\tother at %.*s(%td:%td)",
|
||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||
error(d->proc_lit,
|
||||
"Non unique linking name for procedure `%.*s`\n"
|
||||
"\tother at %.*s(%td:%td)",
|
||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||
} else {
|
||||
map_set(fp, key, e);
|
||||
}
|
||||
@@ -463,7 +551,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
|
||||
void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) {
|
||||
GB_ASSERT(e->type == NULL);
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
|
||||
if (e->flags & EntityFlag_Visited) {
|
||||
@@ -472,13 +560,28 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
}
|
||||
e->flags |= EntityFlag_Visited;
|
||||
|
||||
if (type_expr != NULL) {
|
||||
String context_name = str_lit("variable declaration");
|
||||
|
||||
if (type_expr != nullptr) {
|
||||
e->type = check_type(c, type_expr);
|
||||
}
|
||||
if (e->type != nullptr) {
|
||||
if (is_type_polymorphic(base_type(e->type))) {
|
||||
gbString str = type_to_string(e->type);
|
||||
defer (gb_string_free(str));
|
||||
error(e->token, "Invalid use of a polymorphic type `%s` in %.*s", str, LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
} else if (is_type_empty_union(e->type)) {
|
||||
gbString str = type_to_string(e->type);
|
||||
defer (gb_string_free(str));
|
||||
error(e->token, "An empty union `%s` cannot be instantiated in %.*s", str, LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (e->Variable.is_foreign) {
|
||||
if (init_expr != NULL) {
|
||||
if (init_expr != nullptr) {
|
||||
error(e->token, "A foreign variable declaration cannot have a default value");
|
||||
}
|
||||
init_entity_foreign_library(c, e);
|
||||
@@ -503,21 +606,21 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
}
|
||||
}
|
||||
|
||||
if (init_expr == NULL) {
|
||||
if (type_expr == NULL) {
|
||||
if (init_expr == nullptr) {
|
||||
if (type_expr == nullptr) {
|
||||
e->type = t_invalid;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (entities == NULL || entity_count == 1) {
|
||||
GB_ASSERT(entities == NULL || entities[0] == e);
|
||||
if (entities == nullptr || entity_count == 1) {
|
||||
GB_ASSERT(entities == nullptr || entities[0] == e);
|
||||
Operand operand = {};
|
||||
check_expr(c, &operand, init_expr);
|
||||
check_init_variable(c, e, &operand, str_lit("variable declaration"));
|
||||
check_init_variable(c, e, &operand, context_name);
|
||||
}
|
||||
|
||||
if (type_expr != NULL) {
|
||||
if (type_expr != nullptr) {
|
||||
for (isize i = 0; i < entity_count; i++) {
|
||||
entities[i]->type = e->type;
|
||||
}
|
||||
@@ -527,17 +630,17 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
Array<AstNode *> inits;
|
||||
array_init(&inits, c->allocator, 1);
|
||||
array_add(&inits, init_expr);
|
||||
check_init_variables(c, entities, entity_count, inits, str_lit("variable declaration"));
|
||||
check_init_variables(c, entities, entity_count, inits, context_name);
|
||||
}
|
||||
|
||||
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
if (e->type != NULL) {
|
||||
if (e->type != nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (d == NULL) {
|
||||
if (d == nullptr) {
|
||||
d = decl_info_of_entity(&c->info, e);
|
||||
if (d == NULL) {
|
||||
if (d == nullptr) {
|
||||
// TODO(bill): Err here?
|
||||
e->type = t_invalid;
|
||||
set_base_type(named_type, t_invalid);
|
||||
@@ -573,7 +676,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
|
||||
|
||||
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
|
||||
if (body == NULL) {
|
||||
if (body == nullptr) {
|
||||
return;
|
||||
}
|
||||
GB_ASSERT(body->kind == AstNode_BlockStmt);
|
||||
@@ -587,6 +690,8 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
}
|
||||
|
||||
CheckerContext old_context = c->context;
|
||||
defer (c->context = old_context);
|
||||
|
||||
c->context.scope = decl->scope;
|
||||
c->context.decl = decl;
|
||||
c->context.proc_name = proc_name;
|
||||
@@ -595,7 +700,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
GB_ASSERT(type->kind == Type_Proc);
|
||||
if (type->Proc.param_count > 0) {
|
||||
TypeTuple *params = &type->Proc.params->Tuple;
|
||||
for (isize i = 0; i < params->variable_count; i++) {
|
||||
for_array(i, params->variables) {
|
||||
Entity *e = params->variables[i];
|
||||
if (e->kind != Entity_Variable) {
|
||||
continue;
|
||||
@@ -606,23 +711,26 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
bool is_immutable = e->Variable.is_immutable;
|
||||
String name = e->token.string;
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||
Scope *scope = scope_of_node(&c->info, t->Record.node);
|
||||
GB_ASSERT(scope != NULL);
|
||||
if (t->kind == Type_Struct) {
|
||||
Scope *scope = t->Struct.scope;
|
||||
if (scope == nullptr) {
|
||||
scope = scope_of_node(&c->info, t->Struct.node);
|
||||
}
|
||||
GB_ASSERT(scope != nullptr);
|
||||
for_array(i, scope->elements.entries) {
|
||||
Entity *f = scope->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
uvar->Variable.is_immutable = is_immutable;
|
||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||
if (prev != NULL) {
|
||||
if (prev != nullptr) {
|
||||
error(e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error(e->token, "`using` can only be applied to variables of type struct or raw_union");
|
||||
error(e->token, "`using` can only be applied to variables of type struct");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -644,11 +752,9 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
}
|
||||
pop_procedure(c);
|
||||
|
||||
|
||||
check_scope_usage(c, c->context.scope);
|
||||
c->context = old_context;
|
||||
|
||||
if (decl->parent != NULL) {
|
||||
if (decl->parent != nullptr) {
|
||||
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
|
||||
for_array(i, decl->deps.entries) {
|
||||
HashKey key = decl->deps.entries[i].key;
|
||||
|
||||
+2623
-1143
File diff suppressed because it is too large
Load Diff
+270
-262
@@ -4,7 +4,7 @@ void check_stmt_list(Checker *c, Array<AstNode *> stmts, u32 flags) {
|
||||
}
|
||||
|
||||
if (flags&Stmt_CheckScopeDecls) {
|
||||
check_scope_decls(c, stmts, 1.2*stmts.count);
|
||||
check_scope_decls(c, stmts, cast(isize)(1.2*stmts.count));
|
||||
}
|
||||
|
||||
bool ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
|
||||
@@ -75,7 +75,7 @@ bool check_has_break(AstNode *stmt, bool implicit) {
|
||||
|
||||
case AstNode_IfStmt:
|
||||
if (check_has_break(stmt->IfStmt.body, implicit) ||
|
||||
(stmt->IfStmt.else_stmt != NULL && check_has_break(stmt->IfStmt.else_stmt, implicit))) {
|
||||
(stmt->IfStmt.else_stmt != nullptr && check_has_break(stmt->IfStmt.else_stmt, implicit))) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@@ -107,7 +107,7 @@ bool check_is_terminating(AstNode *node) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(is, IfStmt, node);
|
||||
if (is->else_stmt != NULL) {
|
||||
if (is->else_stmt != nullptr) {
|
||||
if (check_is_terminating(is->body) &&
|
||||
check_is_terminating(is->else_stmt)) {
|
||||
return true;
|
||||
@@ -116,7 +116,7 @@ bool check_is_terminating(AstNode *node) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(ws, WhenStmt, node);
|
||||
if (ws->else_stmt != NULL) {
|
||||
if (ws->else_stmt != nullptr) {
|
||||
if (check_is_terminating(ws->body) &&
|
||||
check_is_terminating(ws->else_stmt)) {
|
||||
return true;
|
||||
@@ -125,7 +125,7 @@ bool check_is_terminating(AstNode *node) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(fs, ForStmt, node);
|
||||
if (fs->cond == NULL && !check_has_break(fs->body, true)) {
|
||||
if (fs->cond == nullptr && !check_has_break(fs->body, true)) {
|
||||
return check_is_terminating(fs->body);
|
||||
}
|
||||
case_end;
|
||||
@@ -180,23 +180,22 @@ bool check_is_terminating(AstNode *node) {
|
||||
Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
||||
if (rhs->mode == Addressing_Invalid ||
|
||||
(rhs->type == t_invalid && rhs->mode != Addressing_Overload)) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AstNode *node = unparen_expr(lhs_node);
|
||||
|
||||
// NOTE(bill): Ignore assignments to `_`
|
||||
if (node->kind == AstNode_Ident &&
|
||||
node->Ident.string == "_") {
|
||||
add_entity_definition(&c->info, node, NULL);
|
||||
check_assignment(c, rhs, NULL, str_lit("assignment to `_` identifier"));
|
||||
if (is_blank_ident(node)) {
|
||||
add_entity_definition(&c->info, node, nullptr);
|
||||
check_assignment(c, rhs, nullptr, str_lit("assignment to `_` identifier"));
|
||||
if (rhs->mode == Addressing_Invalid) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return rhs->type;
|
||||
}
|
||||
|
||||
Entity *e = NULL;
|
||||
Entity *e = nullptr;
|
||||
bool used = false;
|
||||
Operand lhs = {Addressing_Invalid};
|
||||
|
||||
@@ -204,13 +203,13 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
||||
check_expr(c, &lhs, lhs_node);
|
||||
if (lhs.mode == Addressing_Invalid ||
|
||||
lhs.type == t_invalid) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (rhs->mode == Addressing_Overload) {
|
||||
isize overload_count = rhs->overload_count;
|
||||
Entity **procs = rhs->overload_entities;
|
||||
GB_ASSERT(procs != NULL && overload_count > 0);
|
||||
GB_ASSERT(procs != nullptr && overload_count > 0);
|
||||
|
||||
// NOTE(bill): These should be done
|
||||
for (isize i = 0; i < overload_count; i++) {
|
||||
@@ -228,32 +227,32 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
||||
}
|
||||
}
|
||||
|
||||
if (e != NULL) {
|
||||
if (e != nullptr) {
|
||||
// HACK TODO(bill): Should the entities be freed as it's technically a leak
|
||||
rhs->mode = Addressing_Value;
|
||||
rhs->type = e->type;
|
||||
rhs->overload_count = 0;
|
||||
rhs->overload_entities = NULL;
|
||||
rhs->overload_entities = nullptr;
|
||||
}
|
||||
} 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) {
|
||||
e = scope_lookup_entity(c->context.scope, i->token.string);
|
||||
if (e != nullptr && e->kind == Entity_Variable) {
|
||||
used = (e->flags & EntityFlag_Used) != 0; // TODO(bill): Make backup just in case
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (e != NULL && used) {
|
||||
if (e != nullptr && used) {
|
||||
e->flags |= EntityFlag_Used;
|
||||
}
|
||||
|
||||
Type *assignment_type = lhs.type;
|
||||
switch (lhs.mode) {
|
||||
case Addressing_Invalid:
|
||||
return NULL;
|
||||
return nullptr;
|
||||
|
||||
case Addressing_Variable: {
|
||||
if (is_type_bit_field_value(lhs.type)) {
|
||||
@@ -266,9 +265,9 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
||||
u128 u = *cast(u128 *)&i;
|
||||
u128 umax = U128_NEG_ONE;
|
||||
if (lhs_bits < 128) {
|
||||
umax = u128_sub(u128_shl(U128_ONE, lhs_bits), U128_ONE);
|
||||
umax = u128_sub(u128_shl(U128_ONE, cast(u32)lhs_bits), U128_ONE);
|
||||
}
|
||||
i128 imax = i128_shl(I128_ONE, lhs_bits-1ll);
|
||||
i128 imax = i128_shl(I128_ONE, cast(u32)lhs_bits-1);
|
||||
|
||||
bool ok = false;
|
||||
ok = !(u128_lt(u, U128_ZERO) || u128_gt(u, umax));
|
||||
@@ -286,7 +285,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
||||
error(rhs->expr, "Cannot assign `%s` to bit field `%s`", rhs_expr, lhs_expr);
|
||||
gb_string_free(rhs_expr);
|
||||
gb_string_free(lhs_expr);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -302,7 +301,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
||||
gbString str = expr_to_string(lhs.expr);
|
||||
error(lhs.expr, "Cannot assign to the value of a map `%s`", str);
|
||||
gb_string_free(str);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -316,9 +315,9 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
||||
check_expr(c, &op_c, se->expr);
|
||||
if (op_c.mode == Addressing_MapIndex) {
|
||||
gbString str = expr_to_string(lhs.expr);
|
||||
error(lhs.expr, "Cannot assign to record field `%s` in map", str);
|
||||
error(lhs.expr, "Cannot assign to struct field `%s` in map", str);
|
||||
gb_string_free(str);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,7 +333,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
||||
|
||||
check_assignment(c, rhs, assignment_type, str_lit("assignment"));
|
||||
if (rhs->mode == Addressing_Invalid) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return rhs->type;
|
||||
@@ -397,7 +396,7 @@ void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
|
||||
error(ws->cond, "Non-constant boolean `when` condition");
|
||||
return;
|
||||
}
|
||||
if (ws->body == NULL || ws->body->kind != AstNode_BlockStmt) {
|
||||
if (ws->body == nullptr || ws->body->kind != AstNode_BlockStmt) {
|
||||
error(ws->cond, "Invalid body for `when` statement");
|
||||
return;
|
||||
}
|
||||
@@ -420,7 +419,7 @@ void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
|
||||
}
|
||||
|
||||
void check_label(Checker *c, AstNode *label) {
|
||||
if (label == NULL) {
|
||||
if (label == nullptr) {
|
||||
return;
|
||||
}
|
||||
ast_node(l, Label, label);
|
||||
@@ -428,8 +427,8 @@ void check_label(Checker *c, AstNode *label) {
|
||||
error(l->name, "A label's name must be an identifier");
|
||||
return;
|
||||
}
|
||||
String name = l->name->Ident.string;
|
||||
if (name == "_") {
|
||||
String name = l->name->Ident.token.string;
|
||||
if (is_blank_ident(name)) {
|
||||
error(l->name, "A label's name cannot be a blank identifier");
|
||||
return;
|
||||
}
|
||||
@@ -439,7 +438,7 @@ void check_label(Checker *c, AstNode *label) {
|
||||
error(l->name, "A label is only allowed within a procedure");
|
||||
return;
|
||||
}
|
||||
GB_ASSERT(c->context.decl != NULL);
|
||||
GB_ASSERT(c->context.decl != nullptr);
|
||||
|
||||
bool ok = true;
|
||||
for_array(i, c->context.decl->labels) {
|
||||
@@ -451,7 +450,7 @@ void check_label(Checker *c, AstNode *label) {
|
||||
}
|
||||
}
|
||||
|
||||
Entity *e = make_entity_label(c->allocator, c->context.scope, l->name->Ident, t_invalid, label);
|
||||
Entity *e = make_entity_label(c->allocator, c->context.scope, l->name->Ident.token, t_invalid, label);
|
||||
add_entity(c, c->context.scope, l->name, e);
|
||||
e->parent_proc_decl = c->context.curr_proc_decl;
|
||||
|
||||
@@ -463,7 +462,7 @@ void check_label(Checker *c, AstNode *label) {
|
||||
|
||||
// Returns `true` for `continue`, `false` for `return`
|
||||
bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bool is_selector, Entity *e) {
|
||||
if (e == NULL) {
|
||||
if (e == nullptr) {
|
||||
error(us->token, "`using` applied to an unknown entity");
|
||||
return true;
|
||||
}
|
||||
@@ -473,13 +472,28 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
|
||||
switch (e->kind) {
|
||||
case Entity_TypeName: {
|
||||
Type *t = base_type(e->type);
|
||||
if (is_type_union(t)) {
|
||||
TokenPos pos = ast_node_token(expr).pos;
|
||||
for (isize i = 1; i < t->Record.variant_count; i++) {
|
||||
Entity *f = t->Record.variants[i];
|
||||
// gb_printf_err("%s\n", type_to_string(f->type));
|
||||
if (t->kind == Type_Struct) {
|
||||
Scope *s = t->Struct.scope;
|
||||
if (s != nullptr) {
|
||||
for_array(i, s->elements.entries) {
|
||||
Entity *f = s->elements.entries[i].value;
|
||||
if (f->kind != Entity_Variable) {
|
||||
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||
if (found != nullptr) {
|
||||
gbString expr_str = expr_to_string(expr);
|
||||
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
|
||||
gb_string_free(expr_str);
|
||||
return false;
|
||||
}
|
||||
f->using_parent = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (t->kind == Type_Enum) {
|
||||
for (isize i = 0; i < t->Enum.field_count; i++) {
|
||||
Entity *f = t->Enum.fields[i];
|
||||
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||
if (found != NULL) {
|
||||
if (found != nullptr) {
|
||||
gbString expr_str = expr_to_string(expr);
|
||||
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
|
||||
gb_string_free(expr_str);
|
||||
@@ -487,21 +501,8 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
|
||||
}
|
||||
f->using_parent = e;
|
||||
}
|
||||
} else if (is_type_enum(t)) {
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
Entity *f = t->Record.fields[i];
|
||||
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||
if (found != NULL) {
|
||||
gbString expr_str = expr_to_string(expr);
|
||||
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
|
||||
gb_string_free(expr_str);
|
||||
return false;
|
||||
}
|
||||
f->using_parent = e;
|
||||
}
|
||||
|
||||
} else {
|
||||
error(us->token, "`using` can be only applied to `union` or `enum` type entities");
|
||||
error(us->token, "`using` can be only applied to struct type entities");
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -510,7 +511,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
|
||||
for_array(i, scope->elements.entries) {
|
||||
Entity *decl = scope->elements.entries[i].value;
|
||||
Entity *found = scope_insert_entity(c->context.scope, decl);
|
||||
if (found != NULL) {
|
||||
if (found != nullptr) {
|
||||
gbString expr_str = expr_to_string(expr);
|
||||
error(us->token,
|
||||
"Namespace collision while `using` `%s` of: %.*s\n"
|
||||
@@ -530,7 +531,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (is_type_struct(t) || is_type_raw_union(t) || is_type_union(t)) {
|
||||
// TODO(bill): Make it work for unions too
|
||||
Scope *found = scope_of_node(&c->info, t->Record.node);
|
||||
Scope *found = scope_of_node(&c->info, t->Struct.node);
|
||||
for_array(i, found->elements.entries) {
|
||||
Entity *f = found->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
@@ -539,7 +540,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
|
||||
uvar->using_expr = expr;
|
||||
// }
|
||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||
if (prev != NULL) {
|
||||
if (prev != nullptr) {
|
||||
gbString expr_str = expr_to_string(expr);
|
||||
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string));
|
||||
gb_string_free(expr_str);
|
||||
@@ -590,7 +591,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
case_ast_node(es, ExprStmt, node)
|
||||
Operand operand = {Addressing_Invalid};
|
||||
ExprKind kind = check_expr_base(c, &operand, es->expr, NULL);
|
||||
ExprKind kind = check_expr_base(c, &operand, es->expr, nullptr);
|
||||
switch (operand.mode) {
|
||||
case Addressing_Type: {
|
||||
gbString str = type_to_string(operand.type);
|
||||
@@ -628,6 +629,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
check_stmt(c, ts->stmt, flags);
|
||||
case_end;
|
||||
|
||||
#if 0
|
||||
case_ast_node(s, IncDecStmt, node);
|
||||
TokenKind op = s->op.kind;
|
||||
switch (op) {
|
||||
@@ -670,6 +672,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
check_assignment_variable(c, &x, left);
|
||||
case_end;
|
||||
#endif
|
||||
|
||||
case_ast_node(as, AssignStmt, node);
|
||||
switch (as->op.kind) {
|
||||
@@ -683,6 +686,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||
// an extra allocation
|
||||
@@ -705,7 +709,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
error(as->lhs[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
||||
}
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
@@ -747,7 +750,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
case_ast_node(is, IfStmt, node);
|
||||
check_open_scope(c, node);
|
||||
|
||||
if (is->init != NULL) {
|
||||
if (is->init != nullptr) {
|
||||
check_stmt(c, is->init, 0);
|
||||
}
|
||||
|
||||
@@ -759,7 +762,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
check_stmt(c, is->body, mod_flags);
|
||||
|
||||
if (is->else_stmt != NULL) {
|
||||
if (is->else_stmt != nullptr) {
|
||||
switch (is->else_stmt->kind) {
|
||||
case AstNode_IfStmt:
|
||||
case AstNode_BlockStmt:
|
||||
@@ -814,7 +817,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
TypeProc *pt = &proc_type->Proc;
|
||||
isize result_count = 0;
|
||||
if (pt->results) {
|
||||
result_count = proc_type->Proc.results->Tuple.variable_count;
|
||||
result_count = proc_type->Proc.results->Tuple.variables.count;
|
||||
}
|
||||
|
||||
|
||||
@@ -862,7 +865,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
gb_string_free(expr_str);
|
||||
continue;
|
||||
}
|
||||
String name = fv->field->Ident.string;
|
||||
String name = fv->field->Ident.token.string;
|
||||
isize index = lookup_procedure_result(pt, name);
|
||||
if (index < 0) {
|
||||
error(arg, "No result named `%.*s` for this procedure type", LIT(name));
|
||||
@@ -882,7 +885,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
for (isize i = 0; i < result_count; i++) {
|
||||
if (!visited[i]) {
|
||||
Entity *e = pt->results->Tuple.variables[i];
|
||||
if (e->token.string == "_") {
|
||||
if (is_blank_ident(e->token)) {
|
||||
continue;
|
||||
}
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
@@ -931,17 +934,17 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
check_open_scope(c, node);
|
||||
check_label(c, fs->label); // TODO(bill): What should the label's "scope" be?
|
||||
|
||||
if (fs->init != NULL) {
|
||||
if (fs->init != nullptr) {
|
||||
check_stmt(c, fs->init, 0);
|
||||
}
|
||||
if (fs->cond != NULL) {
|
||||
if (fs->cond != nullptr) {
|
||||
Operand o = {Addressing_Invalid};
|
||||
check_expr(c, &o, fs->cond);
|
||||
if (o.mode != Addressing_Invalid && !is_type_boolean(o.type)) {
|
||||
error(fs->cond, "Non-boolean condition in `for` statement");
|
||||
}
|
||||
}
|
||||
if (fs->post != NULL) {
|
||||
if (fs->post != nullptr) {
|
||||
check_stmt(c, fs->post, 0);
|
||||
|
||||
if (fs->post->kind != AstNode_AssignStmt &&
|
||||
@@ -960,8 +963,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
check_open_scope(c, node);
|
||||
check_label(c, rs->label);
|
||||
|
||||
Type *val = NULL;
|
||||
Type *idx = NULL;
|
||||
Type *val = nullptr;
|
||||
Type *idx = nullptr;
|
||||
Entity *entities[2] = {};
|
||||
isize entity_count = 0;
|
||||
|
||||
@@ -1105,7 +1108,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
}
|
||||
|
||||
if (val == NULL) {
|
||||
if (val == nullptr) {
|
||||
gbString s = expr_to_string(operand.expr);
|
||||
gbString t = type_to_string(operand.type);
|
||||
error(operand.expr, "Cannot iterate over `%s` of type `%s`", s, t);
|
||||
@@ -1119,22 +1122,22 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
Type * rhs[2] = {val, idx};
|
||||
|
||||
for (isize i = 0; i < 2; i++) {
|
||||
if (lhs[i] == NULL) {
|
||||
if (lhs[i] == nullptr) {
|
||||
continue;
|
||||
}
|
||||
AstNode *name = lhs[i];
|
||||
Type * type = rhs[i];
|
||||
|
||||
Entity *entity = NULL;
|
||||
Entity *entity = nullptr;
|
||||
if (name->kind == AstNode_Ident) {
|
||||
Token token = name->Ident;
|
||||
Token token = name->Ident.token;
|
||||
String str = token.string;
|
||||
Entity *found = NULL;
|
||||
Entity *found = nullptr;
|
||||
|
||||
if (str != "_") {
|
||||
if (!is_blank_ident(str)) {
|
||||
found = current_scope_lookup_entity(c->context.scope, str);
|
||||
}
|
||||
if (found == NULL) {
|
||||
if (found == nullptr) {
|
||||
entity = make_entity_variable(c->allocator, c->context.scope, token, type, true);
|
||||
add_entity_definition(&c->info, name, entity);
|
||||
} else {
|
||||
@@ -1149,13 +1152,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
error(name, "A variable declaration must be an identifier");
|
||||
}
|
||||
|
||||
if (entity == NULL) {
|
||||
if (entity == nullptr) {
|
||||
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
|
||||
}
|
||||
|
||||
entities[entity_count++] = entity;
|
||||
|
||||
if (type == NULL) {
|
||||
if (type == nullptr) {
|
||||
entity->type = t_invalid;
|
||||
entity->flags |= EntityFlag_Used;
|
||||
}
|
||||
@@ -1177,12 +1180,12 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
check_open_scope(c, node);
|
||||
check_label(c, ms->label); // TODO(bill): What should the label's "scope" be?
|
||||
|
||||
if (ms->init != NULL) {
|
||||
if (ms->init != nullptr) {
|
||||
check_stmt(c, ms->init, 0);
|
||||
}
|
||||
if (ms->tag != NULL) {
|
||||
if (ms->tag != nullptr) {
|
||||
check_expr(c, &x, ms->tag);
|
||||
check_assignment(c, &x, NULL, str_lit("match expression"));
|
||||
check_assignment(c, &x, nullptr, str_lit("match expression"));
|
||||
} else {
|
||||
x.mode = Addressing_Constant;
|
||||
x.type = t_bool;
|
||||
@@ -1202,11 +1205,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
|
||||
// NOTE(bill): Check for multiple defaults
|
||||
AstNode *first_default = NULL;
|
||||
AstNode *first_default = nullptr;
|
||||
ast_node(bs, BlockStmt, ms->body);
|
||||
for_array(i, bs->stmts) {
|
||||
AstNode *stmt = bs->stmts[i];
|
||||
AstNode *default_stmt = NULL;
|
||||
AstNode *default_stmt = nullptr;
|
||||
if (stmt->kind == AstNode_CaseClause) {
|
||||
ast_node(cc, CaseClause, stmt);
|
||||
if (cc->list.count == 0) {
|
||||
@@ -1216,8 +1219,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
error(stmt, "Invalid AST - expected case clause");
|
||||
}
|
||||
|
||||
if (default_stmt != NULL) {
|
||||
if (first_default != NULL) {
|
||||
if (default_stmt != nullptr) {
|
||||
if (first_default != nullptr) {
|
||||
TokenPos pos = ast_node_token(first_default).pos;
|
||||
error(stmt,
|
||||
"multiple `default` clauses\n"
|
||||
@@ -1298,6 +1301,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
} else {
|
||||
Operand y = {};
|
||||
check_expr(c, &y, expr);
|
||||
|
||||
if (x.mode == Addressing_Invalid ||
|
||||
y.mode == Addressing_Invalid) {
|
||||
continue;
|
||||
@@ -1322,8 +1326,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
if (y.value.kind != ExactValue_Invalid) {
|
||||
HashKey key = hash_exact_value(y.value);
|
||||
TypeAndToken *found = map_get(&seen, key);
|
||||
if (found != NULL) {
|
||||
if (found != nullptr) {
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
isize count = multi_map_count(&seen, key);
|
||||
TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count);
|
||||
|
||||
@@ -1346,7 +1352,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
}
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
|
||||
if (continue_outer) {
|
||||
continue;
|
||||
@@ -1400,7 +1405,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
AstNode *rhs = as->rhs[0];
|
||||
|
||||
check_expr(c, &x, rhs);
|
||||
check_assignment(c, &x, NULL, str_lit("type match expression"));
|
||||
check_assignment(c, &x, nullptr, str_lit("type match expression"));
|
||||
match_type_kind = check_valid_type_match_type(x.type);
|
||||
if (check_valid_type_match_type(x.type) == MatchType_Invalid) {
|
||||
gbString str = type_to_string(x.type);
|
||||
@@ -1412,11 +1417,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
bool is_ptr = is_type_pointer(x.type);
|
||||
|
||||
// NOTE(bill): Check for multiple defaults
|
||||
AstNode *first_default = NULL;
|
||||
AstNode *first_default = nullptr;
|
||||
ast_node(bs, BlockStmt, ms->body);
|
||||
for_array(i, bs->stmts) {
|
||||
AstNode *stmt = bs->stmts[i];
|
||||
AstNode *default_stmt = NULL;
|
||||
AstNode *default_stmt = nullptr;
|
||||
if (stmt->kind == AstNode_CaseClause) {
|
||||
ast_node(cc, CaseClause, stmt);
|
||||
if (cc->list.count == 0) {
|
||||
@@ -1426,8 +1431,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
error(stmt, "Invalid AST - expected case clause");
|
||||
}
|
||||
|
||||
if (default_stmt != NULL) {
|
||||
if (first_default != NULL) {
|
||||
if (default_stmt != nullptr) {
|
||||
if (first_default != nullptr) {
|
||||
TokenPos pos = ast_node_token(first_default).pos;
|
||||
error(stmt,
|
||||
"Multiple `default` clauses\n"
|
||||
@@ -1459,19 +1464,19 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
// TODO(bill): Make robust
|
||||
Type *bt = base_type(type_deref(x.type));
|
||||
|
||||
Type *case_type = NULL;
|
||||
Type *case_type = nullptr;
|
||||
for_array(type_index, cc->list) {
|
||||
AstNode *type_expr = cc->list[type_index];
|
||||
if (type_expr != NULL) { // Otherwise it's a default expression
|
||||
if (type_expr != nullptr) { // Otherwise it's a default expression
|
||||
Operand y = {};
|
||||
check_expr_or_type(c, &y, type_expr);
|
||||
|
||||
if (match_type_kind == MatchType_Union) {
|
||||
GB_ASSERT(is_type_union(bt));
|
||||
bool tag_type_found = false;
|
||||
for (isize i = 0; i < bt->Record.variant_count; i++) {
|
||||
Entity *f = bt->Record.variants[i];
|
||||
if (are_types_identical(f->type, y.type)) {
|
||||
for_array(i, bt->Union.variants) {
|
||||
Type *vt = bt->Union.variants[i];
|
||||
if (are_types_identical(vt, y.type)) {
|
||||
tag_type_found = true;
|
||||
break;
|
||||
}
|
||||
@@ -1509,21 +1514,21 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
if (is_ptr &&
|
||||
!is_type_any(type_deref(x.type)) &&
|
||||
cc->list.count == 1 &&
|
||||
case_type != NULL) {
|
||||
case_type != nullptr) {
|
||||
case_type = make_type_pointer(c->allocator, case_type);
|
||||
}
|
||||
|
||||
if (cc->list.count > 1) {
|
||||
case_type = NULL;
|
||||
case_type = nullptr;
|
||||
}
|
||||
if (case_type == NULL) {
|
||||
if (case_type == nullptr) {
|
||||
case_type = x.type;
|
||||
}
|
||||
add_type_info_type(c, case_type);
|
||||
|
||||
check_open_scope(c, stmt);
|
||||
{
|
||||
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident, case_type, false);
|
||||
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident.token, case_type, false);
|
||||
tag_var->flags |= EntityFlag_Used;
|
||||
tag_var->flags |= EntityFlag_Value;
|
||||
add_entity(c, c->context.scope, lhs, tag_var);
|
||||
@@ -1573,16 +1578,16 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (bs->label != NULL) {
|
||||
if (bs->label != nullptr) {
|
||||
if (bs->label->kind != AstNode_Ident) {
|
||||
error(bs->label, "A branch statement's label name must be an identifier");
|
||||
return;
|
||||
}
|
||||
AstNode *ident = bs->label;
|
||||
String name = ident->Ident.string;
|
||||
String name = ident->Ident.token.string;
|
||||
Operand o = {};
|
||||
Entity *e = check_ident(c, &o, ident, NULL, NULL, false);
|
||||
if (e == NULL) {
|
||||
Entity *e = check_ident(c, &o, ident, nullptr, nullptr, false);
|
||||
if (e == nullptr) {
|
||||
error(ident, "Undeclared label name: %.*s", LIT(name));
|
||||
return;
|
||||
}
|
||||
@@ -1602,19 +1607,24 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
for_array(i, us->list) {
|
||||
AstNode *expr = unparen_expr(us->list[0]);
|
||||
Entity *e = NULL;
|
||||
Entity *e = nullptr;
|
||||
|
||||
bool is_selector = false;
|
||||
if (expr->kind == AstNode_Ident) {
|
||||
Operand o = {};
|
||||
e = check_ident(c, &o, expr, NULL, NULL, true);
|
||||
} else if (expr->kind == AstNode_SelectorExpr) {
|
||||
Operand o = {};
|
||||
e = check_selector(c, &o, expr, NULL);
|
||||
Operand o = {};
|
||||
switch (expr->kind) {
|
||||
case AstNode_Ident:
|
||||
e = check_ident(c, &o, expr, nullptr, nullptr, true);
|
||||
break;
|
||||
case AstNode_SelectorExpr:
|
||||
e = check_selector(c, &o, expr, nullptr);
|
||||
is_selector = true;
|
||||
} else if (expr->kind == AstNode_Implicit) {
|
||||
break;
|
||||
case AstNode_Implicit:
|
||||
error(us->token, "`using` applied to an implicit value");
|
||||
continue;
|
||||
default:
|
||||
error(us->token, "`using` can only be applied to an entity, got %.*s", LIT(ast_node_strings[expr->kind]));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!check_using_stmt_entity(c, us, expr, is_selector, e)) {
|
||||
@@ -1654,170 +1664,168 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
for_array(i, fb->decls) {
|
||||
AstNode *decl = fb->decls[i];
|
||||
if (decl->kind == AstNode_GenDecl) {
|
||||
switch (decl->GenDecl.token.kind) {
|
||||
case Token_var:
|
||||
check_stmt(c, decl, flags);
|
||||
break;
|
||||
}
|
||||
if (decl->kind == AstNode_ValueDecl && decl->ValueDecl.is_mutable) {
|
||||
check_stmt(c, decl, flags);
|
||||
}
|
||||
}
|
||||
|
||||
c->context = prev_context;
|
||||
case_end;
|
||||
|
||||
case_ast_node(vd, ValueDecl, node);
|
||||
if (!vd->is_mutable) {
|
||||
break;
|
||||
}
|
||||
Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count);
|
||||
isize entity_count = 0;
|
||||
|
||||
case_ast_node(gd, GenDecl, node);
|
||||
GB_ASSERT(!c->context.scope->is_file);
|
||||
for_array(i, gd->specs) {
|
||||
AstNode *spec = gd->specs[i];
|
||||
switch (gd->token.kind) {
|
||||
case Token_var: {
|
||||
ast_node(vd, ValueSpec, spec);
|
||||
if (vd->flags & VarDeclFlag_thread_local) {
|
||||
vd->flags &= ~VarDeclFlag_thread_local;
|
||||
error(node, "`thread_local` may only be applied to a variable declaration");
|
||||
}
|
||||
|
||||
Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count);
|
||||
isize entity_count = 0;
|
||||
|
||||
if (gd->flags & VarDeclFlag_thread_local) {
|
||||
gd->flags &= ~VarDeclFlag_thread_local;
|
||||
error(node, "`thread_local` may only be applied to a variable declaration");
|
||||
for_array(i, vd->names) {
|
||||
AstNode *name = vd->names[i];
|
||||
Entity *entity = nullptr;
|
||||
if (name->kind != AstNode_Ident) {
|
||||
error(name, "A variable declaration must be an identifier");
|
||||
} else {
|
||||
Token token = name->Ident.token;
|
||||
String str = token.string;
|
||||
Entity *found = nullptr;
|
||||
// NOTE(bill): Ignore assignments to `_`
|
||||
if (!is_blank_ident(str)) {
|
||||
found = current_scope_lookup_entity(c->context.scope, str);
|
||||
}
|
||||
if (found == nullptr) {
|
||||
entity = make_entity_variable(c->allocator, c->context.scope, token, nullptr, false);
|
||||
entity->identifier = name;
|
||||
|
||||
for_array(i, vd->names) {
|
||||
AstNode *name = vd->names[i];
|
||||
Entity *entity = NULL;
|
||||
if (name->kind != AstNode_Ident) {
|
||||
error(name, "A variable declaration must be an identifier");
|
||||
} else {
|
||||
Token token = name->Ident;
|
||||
String str = token.string;
|
||||
Entity *found = NULL;
|
||||
// NOTE(bill): Ignore assignments to `_`
|
||||
if (str != "_") {
|
||||
found = current_scope_lookup_entity(c->context.scope, str);
|
||||
}
|
||||
if (found == NULL) {
|
||||
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL, false);
|
||||
entity->identifier = name;
|
||||
AstNode *fl = c->context.curr_foreign_library;
|
||||
if (fl != nullptr) {
|
||||
GB_ASSERT(fl->kind == AstNode_Ident);
|
||||
entity->Variable.is_foreign = true;
|
||||
entity->Variable.foreign_library_ident = fl;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
if (entity == nullptr) {
|
||||
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
|
||||
}
|
||||
entity->parent_proc_decl = c->context.curr_proc_decl;
|
||||
entities[entity_count++] = entity;
|
||||
}
|
||||
|
||||
AstNode *fl = c->context.curr_foreign_library;
|
||||
if (fl != NULL) {
|
||||
GB_ASSERT(fl->kind == AstNode_Ident);
|
||||
entity->Variable.is_foreign = true;
|
||||
entity->Variable.foreign_library_ident = fl;
|
||||
Type *init_type = nullptr;
|
||||
if (vd->type != nullptr) {
|
||||
init_type = check_type(c, vd->type, nullptr);
|
||||
if (init_type == nullptr) {
|
||||
init_type = t_invalid;
|
||||
} else if (is_type_polymorphic(base_type(init_type))) {
|
||||
gbString str = type_to_string(init_type);
|
||||
error(vd->type, "Invalid use of a polymorphic type `%s` in variable declaration", str);
|
||||
gb_string_free(str);
|
||||
init_type = t_invalid;
|
||||
} else if (is_type_empty_union(init_type)) {
|
||||
gbString str = type_to_string(init_type);
|
||||
error(vd->type, "An empty union `%s` cannot be instantiated in variable declaration", str);
|
||||
gb_string_free(str);
|
||||
init_type = t_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
for (isize i = 0; i < entity_count; i++) {
|
||||
Entity *e = entities[i];
|
||||
GB_ASSERT(e != nullptr);
|
||||
if (e->flags & EntityFlag_Visited) {
|
||||
e->type = t_invalid;
|
||||
continue;
|
||||
}
|
||||
e->flags |= EntityFlag_Visited;
|
||||
|
||||
if (e->type == nullptr) {
|
||||
e->type = init_type;
|
||||
}
|
||||
}
|
||||
|
||||
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++) {
|
||||
Entity *e = entities[i];
|
||||
if (e->Variable.is_foreign) {
|
||||
if (vd->values.count > 0) {
|
||||
error(e->token, "A foreign variable declaration cannot have a default value");
|
||||
}
|
||||
init_entity_foreign_library(c, e);
|
||||
|
||||
String name = e->token.string;
|
||||
auto *fp = &c->info.foreigns;
|
||||
HashKey key = hash_string(name);
|
||||
Entity **found = map_get(fp, key);
|
||||
if (found) {
|
||||
Entity *f = *found;
|
||||
TokenPos pos = f->token.pos;
|
||||
Type *this_type = base_type(e->type);
|
||||
Type *other_type = base_type(f->type);
|
||||
if (!are_types_identical(this_type, other_type)) {
|
||||
error(e->token,
|
||||
"Foreign entity `%.*s` previously declared elsewhere with a different type\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||
}
|
||||
} else {
|
||||
map_set(fp, key, e);
|
||||
}
|
||||
}
|
||||
add_entity(c, c->context.scope, e->identifier, e);
|
||||
}
|
||||
|
||||
if ((vd->flags & VarDeclFlag_using) != 0) {
|
||||
Token token = ast_node_token(node);
|
||||
if (vd->type != nullptr && 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 == nullptr) {
|
||||
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 *scope = scope_of_node(&c->info, t->Struct.node);
|
||||
for_array(i, scope->elements.entries) {
|
||||
Entity *f = scope->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
uvar->Variable.is_immutable = is_immutable;
|
||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||
if (prev != nullptr) {
|
||||
error(token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
||||
return;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
if (entity == NULL) {
|
||||
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
|
||||
}
|
||||
entity->parent_proc_decl = c->context.curr_proc_decl;
|
||||
entities[entity_count++] = entity;
|
||||
} 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;
|
||||
}
|
||||
|
||||
Type *init_type = NULL;
|
||||
if (vd->type) {
|
||||
init_type = check_type(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 (isize i = 0; i < entity_count; i++) {
|
||||
Entity *e = entities[i];
|
||||
if (e->Variable.is_foreign) {
|
||||
if (vd->values.count > 0) {
|
||||
error(e->token, "A foreign variable declaration cannot have a default value");
|
||||
}
|
||||
init_entity_foreign_library(c, e);
|
||||
|
||||
String name = e->token.string;
|
||||
auto *fp = &c->info.foreigns;
|
||||
HashKey key = hash_string(name);
|
||||
Entity **found = map_get(fp, key);
|
||||
if (found) {
|
||||
Entity *f = *found;
|
||||
TokenPos pos = f->token.pos;
|
||||
Type *this_type = base_type(e->type);
|
||||
Type *other_type = base_type(f->type);
|
||||
if (!are_types_identical(this_type, other_type)) {
|
||||
error(e->token,
|
||||
"Foreign entity `%.*s` previously declared elsewhere with a different type\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||
}
|
||||
} else {
|
||||
map_set(fp, key, e);
|
||||
}
|
||||
}
|
||||
add_entity(c, c->context.scope, e->identifier, e);
|
||||
}
|
||||
|
||||
if ((gd->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 *scope = scope_of_node(&c->info, t->Record.node);
|
||||
for_array(i, scope->elements.entries) {
|
||||
Entity *f = scope->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
uvar->Variable.is_immutable = is_immutable;
|
||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||
if (prev != NULL) {
|
||||
error(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
case_end;
|
||||
|
||||
+449
-380
File diff suppressed because it is too large
Load Diff
+216
-64
@@ -12,9 +12,78 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
GB_ALLOCATOR_PROC(heap_allocator_proc);
|
||||
|
||||
gbAllocator heap_allocator(void) {
|
||||
return gb_heap_allocator();
|
||||
gbAllocator a;
|
||||
a.proc = heap_allocator_proc;
|
||||
a.data = NULL;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
||||
void *ptr = NULL;
|
||||
gb_unused(allocator_data);
|
||||
gb_unused(old_size);
|
||||
// TODO(bill): Throughly test!
|
||||
switch (type) {
|
||||
#if defined(GB_COMPILER_MSVC)
|
||||
case gbAllocation_Alloc:
|
||||
ptr = _aligned_malloc(size, alignment);
|
||||
if (flags & gbAllocatorFlag_ClearToZero)
|
||||
gb_zero_size(ptr, size);
|
||||
break;
|
||||
case gbAllocation_Free:
|
||||
_aligned_free(old_memory);
|
||||
break;
|
||||
case gbAllocation_Resize:
|
||||
ptr = _aligned_realloc(old_memory, size, alignment);
|
||||
break;
|
||||
|
||||
#elif defined(GB_SYSTEM_LINUX)
|
||||
// TODO(bill): *nix version that's decent
|
||||
case gbAllocation_Alloc: {
|
||||
ptr = aligned_alloc(alignment, size);
|
||||
// ptr = malloc(size+alignment);
|
||||
|
||||
if (flags & gbAllocatorFlag_ClearToZero) {
|
||||
gb_zero_size(ptr, size);
|
||||
}
|
||||
} break;
|
||||
|
||||
case gbAllocation_Free: {
|
||||
free(old_memory);
|
||||
} break;
|
||||
|
||||
case gbAllocation_Resize: {
|
||||
// ptr = realloc(old_memory, size);
|
||||
ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
|
||||
} break;
|
||||
#else
|
||||
// TODO(bill): *nix version that's decent
|
||||
case gbAllocation_Alloc: {
|
||||
posix_memalign(&ptr, alignment, size);
|
||||
|
||||
if (flags & gbAllocatorFlag_ClearToZero) {
|
||||
gb_zero_size(ptr, size);
|
||||
}
|
||||
} break;
|
||||
|
||||
case gbAllocation_Free: {
|
||||
free(old_memory);
|
||||
} break;
|
||||
|
||||
case gbAllocation_Resize: {
|
||||
ptr = gb_default_resize_align(heap_allocator(), old_memory, old_size, size, alignment);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
case gbAllocation_FreeAll:
|
||||
break;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#include "unicode.cpp"
|
||||
@@ -23,6 +92,9 @@ gbAllocator heap_allocator(void) {
|
||||
#include "integer128.cpp"
|
||||
#include "murmurhash3.cpp"
|
||||
|
||||
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
|
||||
|
||||
|
||||
u128 fnv128a(void const *data, isize len) {
|
||||
u128 o = u128_lo_hi(0x13bull, 0x1000000ull);
|
||||
u128 h = u128_lo_hi(0x62b821756295c58dull, 0x6c62272e07bb0142ull);
|
||||
@@ -52,93 +124,163 @@ gbAllocator scratch_allocator(void) {
|
||||
return gb_scratch_allocator(&scratch_memory);
|
||||
}
|
||||
|
||||
struct Pool {
|
||||
isize memblock_size;
|
||||
isize out_of_band_size;
|
||||
isize alignment;
|
||||
|
||||
struct DynamicArenaBlock {
|
||||
DynamicArenaBlock *prev;
|
||||
DynamicArenaBlock *next;
|
||||
u8 * start;
|
||||
isize count;
|
||||
isize capacity;
|
||||
Array<u8 *> unused_memblock;
|
||||
Array<u8 *> used_memblock;
|
||||
Array<u8 *> out_of_band_allocations;
|
||||
|
||||
gbVirtualMemory vm;
|
||||
u8 * current_memblock;
|
||||
u8 * current_pos;
|
||||
isize bytes_left;
|
||||
|
||||
gbAllocator block_allocator;
|
||||
};
|
||||
|
||||
struct DynamicArena {
|
||||
DynamicArenaBlock *start_block;
|
||||
DynamicArenaBlock *current_block;
|
||||
isize block_size;
|
||||
enum {
|
||||
POOL_BUCKET_SIZE_DEFAULT = 65536,
|
||||
POOL_OUT_OF_BAND_SIZE_DEFAULT = 6554,
|
||||
};
|
||||
|
||||
DynamicArenaBlock *add_dynamic_arena_block(DynamicArena *a) {
|
||||
GB_ASSERT(a != NULL);
|
||||
GB_ASSERT(a->block_size > 0);
|
||||
void pool_init(Pool *pool,
|
||||
isize memblock_size = POOL_BUCKET_SIZE_DEFAULT,
|
||||
isize out_of_band_size = POOL_OUT_OF_BAND_SIZE_DEFAULT,
|
||||
isize alignment = 8,
|
||||
gbAllocator block_allocator = heap_allocator(),
|
||||
gbAllocator array_allocator = heap_allocator()) {
|
||||
pool->memblock_size = memblock_size;
|
||||
pool->out_of_band_size = out_of_band_size;
|
||||
pool->alignment = alignment;
|
||||
pool->block_allocator = block_allocator;
|
||||
|
||||
gbVirtualMemory vm = gb_vm_alloc(NULL, a->block_size);
|
||||
DynamicArenaBlock *block = cast(DynamicArenaBlock *)vm.data;
|
||||
array_init(&pool->unused_memblock, array_allocator);
|
||||
array_init(&pool->used_memblock, array_allocator);
|
||||
array_init(&pool->out_of_band_allocations, array_allocator);
|
||||
}
|
||||
|
||||
u8 *start = cast(u8 *)gb_align_forward(cast(u8 *)(block + 1), GB_DEFAULT_MEMORY_ALIGNMENT);
|
||||
u8 *end = cast(u8 *)vm.data + vm.size;
|
||||
|
||||
block->vm = vm;
|
||||
block->start = start;
|
||||
block->count = 0;
|
||||
block->capacity = end-start;
|
||||
|
||||
if (a->current_block != NULL) {
|
||||
a->current_block->next = block;
|
||||
block->prev = a->current_block;
|
||||
void pool_free_all(Pool *p) {
|
||||
if (p->current_memblock != nullptr) {
|
||||
array_add(&p->unused_memblock, p->current_memblock);
|
||||
p->current_memblock = nullptr;
|
||||
}
|
||||
a->current_block = block;
|
||||
return block;
|
||||
|
||||
for_array(i, p->used_memblock) {
|
||||
array_add(&p->unused_memblock, p->used_memblock[i]);
|
||||
}
|
||||
array_clear(&p->unused_memblock);
|
||||
|
||||
for_array(i, p->out_of_band_allocations) {
|
||||
gb_free(p->block_allocator, p->out_of_band_allocations[i]);
|
||||
}
|
||||
array_clear(&p->out_of_band_allocations);
|
||||
}
|
||||
|
||||
void init_dynamic_arena(DynamicArena *a, isize block_size) {
|
||||
isize size = gb_size_of(DynamicArenaBlock) + block_size;
|
||||
size = cast(isize)gb_align_forward(cast(void *)cast(uintptr)size, GB_DEFAULT_MEMORY_ALIGNMENT);
|
||||
a->block_size = size;
|
||||
a->start_block = add_dynamic_arena_block(a);
|
||||
}
|
||||
void pool_destroy(Pool *p) {
|
||||
pool_free_all(p);
|
||||
|
||||
void destroy_dynamic_arena(DynamicArena *a) {
|
||||
DynamicArenaBlock *b = a->current_block;
|
||||
while (b != NULL) {
|
||||
gbVirtualMemory vm = b->vm;
|
||||
b = b->prev;
|
||||
gb_vm_free(b->vm);
|
||||
for_array(i, p->unused_memblock) {
|
||||
gb_free(p->block_allocator, p->unused_memblock[i]);
|
||||
}
|
||||
}
|
||||
|
||||
GB_ALLOCATOR_PROC(dynamic_arena_allocator_proc) {
|
||||
DynamicArena *a = cast(DynamicArena *)allocator_data;
|
||||
void *ptr = NULL;
|
||||
void pool_cycle_new_block(Pool *p) {
|
||||
GB_ASSERT_MSG(p->block_allocator.proc != nullptr,
|
||||
"You must call pool_init on a Pool before using it!");
|
||||
|
||||
if (p->current_memblock != nullptr) {
|
||||
array_add(&p->used_memblock, p->current_memblock);
|
||||
}
|
||||
|
||||
u8 *new_block = nullptr;
|
||||
|
||||
if (p->unused_memblock.count > 0) {
|
||||
new_block = array_pop(&p->unused_memblock);
|
||||
} else {
|
||||
GB_ASSERT(p->block_allocator.proc != nullptr);
|
||||
new_block = cast(u8 *)gb_alloc_align(p->block_allocator, p->memblock_size, p->alignment);
|
||||
}
|
||||
|
||||
p->bytes_left = p->memblock_size;
|
||||
p->current_memblock = new_block;
|
||||
p->current_memblock = new_block;
|
||||
}
|
||||
|
||||
void *pool_get(Pool *p,
|
||||
isize size, isize alignment = 0) {
|
||||
if (alignment <= 0) alignment = p->alignment;
|
||||
|
||||
isize extra = alignment - (size & alignment);
|
||||
size += extra;
|
||||
if (size >= p->out_of_band_size) {
|
||||
GB_ASSERT(p->block_allocator.proc != nullptr);
|
||||
u8 *memory = cast(u8 *)gb_alloc_align(p->block_allocator, p->memblock_size, alignment);
|
||||
if (memory != nullptr) {
|
||||
array_add(&p->out_of_band_allocations, memory);
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
if (p->bytes_left < size) {
|
||||
pool_cycle_new_block(p);
|
||||
if (p->current_memblock != nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
u8 *res = p->current_pos;
|
||||
p->current_pos += size;
|
||||
p->bytes_left -= size;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
gbAllocator pool_allocator(Pool *pool);
|
||||
|
||||
GB_ALLOCATOR_PROC(pool_allocator_procedure) {
|
||||
Pool *p = cast(Pool *)allocator_data;
|
||||
void *ptr = nullptr;
|
||||
|
||||
switch (type) {
|
||||
case gbAllocation_Alloc: {
|
||||
|
||||
} break;
|
||||
|
||||
case gbAllocation_Free: {
|
||||
} break;
|
||||
|
||||
case gbAllocation_Resize: {
|
||||
} break;
|
||||
|
||||
case gbAllocation_FreeAll:
|
||||
GB_PANIC("free_all is not supported by this allocator");
|
||||
case gbAllocation_Alloc:
|
||||
return pool_get(p, size, alignment);
|
||||
case gbAllocation_Free:
|
||||
// Does nothing
|
||||
break;
|
||||
case gbAllocation_FreeAll:
|
||||
pool_free_all(p);
|
||||
break;
|
||||
case gbAllocation_Resize:
|
||||
return gb_default_resize_align(pool_allocator(p), old_memory, old_size, size, alignment);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
gbAllocator dynamic_arena_allocator(DynamicArena *a) {
|
||||
gbAllocator allocator = {dynamic_arena_allocator_proc, a};
|
||||
gbAllocator pool_allocator(Pool *pool) {
|
||||
gbAllocator allocator;
|
||||
allocator.proc = pool_allocator_procedure;
|
||||
allocator.data = pool;
|
||||
return allocator;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
i32 next_pow2(i32 n) {
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
n--;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
i64 next_pow2(i64 n) {
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
@@ -154,6 +296,17 @@ i64 next_pow2(i64 n) {
|
||||
return n;
|
||||
}
|
||||
|
||||
i32 prev_pow2(i32 n) {
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
return n - (n >> 1);
|
||||
}
|
||||
i64 prev_pow2(i64 n) {
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
@@ -224,7 +377,6 @@ f64 gb_sqrt(f64 x) {
|
||||
|
||||
|
||||
|
||||
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
|
||||
|
||||
|
||||
// Doubly Linked Lists
|
||||
@@ -236,7 +388,7 @@ f64 gb_sqrt(f64 x) {
|
||||
} while (0)
|
||||
|
||||
#define DLIST_APPEND(root_element, curr_element, next_element) do { \
|
||||
if ((root_element) == NULL) { \
|
||||
if ((root_element) == nullptr) { \
|
||||
(root_element) = (curr_element) = (next_element); \
|
||||
} else { \
|
||||
DLIST_SET(curr_element, next_element); \
|
||||
@@ -250,7 +402,7 @@ f64 gb_sqrt(f64 x) {
|
||||
wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
|
||||
u32 i, j;
|
||||
|
||||
u32 len = string16_len(cmd_line);
|
||||
u32 len = cast(u32)string16_len(cmd_line);
|
||||
i = ((len+2)/2)*gb_size_of(void *) + gb_size_of(void *);
|
||||
|
||||
wchar_t **argv = cast(wchar_t **)GlobalAlloc(GMEM_FIXED, i + (len+2)*gb_size_of(wchar_t));
|
||||
@@ -302,7 +454,7 @@ wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
|
||||
i++;
|
||||
}
|
||||
_argv[j] = '\0';
|
||||
argv[argc] = NULL;
|
||||
argv[argc] = nullptr;
|
||||
|
||||
if (_argc) *_argc = argc;
|
||||
return argv;
|
||||
|
||||
+7
-13
@@ -10,7 +10,7 @@ String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
|
||||
len += 1; // for \n
|
||||
}
|
||||
if (len == 0) {
|
||||
return make_string(NULL, 0);
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
|
||||
u8 *text = gb_alloc_array(a, u8, len+1);
|
||||
@@ -32,6 +32,7 @@ String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
|
||||
return make_string(text, len);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void print_type_spec(AstNode *spec) {
|
||||
ast_node(ts, TypeSpec, spec);
|
||||
GB_ASSERT(ts->name->kind == AstNode_Ident);
|
||||
@@ -69,7 +70,7 @@ void print_proc_decl(AstNodeProcDecl *pd) {
|
||||
gbString params = expr_to_string(proc_type->params);
|
||||
defer (gb_string_free(params));
|
||||
gb_printf("proc %.*s(%s)", LIT(name), params);
|
||||
if (proc_type->results != NULL) {
|
||||
if (proc_type->results != nullptr) {
|
||||
ast_node(fl, FieldList, proc_type->results);
|
||||
isize count = fl->list.count;
|
||||
if (count > 0) {
|
||||
@@ -87,20 +88,13 @@ void print_proc_decl(AstNodeProcDecl *pd) {
|
||||
}
|
||||
gb_printf("\n\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
void print_declaration(AstNode *decl) {
|
||||
switch (decl->kind) {
|
||||
case_ast_node(gd, GenDecl, decl);
|
||||
for_array(spec_index, gd->specs) {
|
||||
AstNode *spec = gd->specs[spec_index];
|
||||
switch(gd->token.kind) {
|
||||
case Token_var:
|
||||
break;
|
||||
case Token_const:
|
||||
break;
|
||||
case Token_type:
|
||||
// print_type_spec(spec);
|
||||
break;
|
||||
case Token_import:
|
||||
case Token_import_load:
|
||||
break;
|
||||
@@ -111,9 +105,9 @@ void print_declaration(AstNode *decl) {
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(pd, ProcDecl, decl);
|
||||
print_proc_decl(pd);
|
||||
case_end;
|
||||
// case_ast_node(pd, ProcDecl, decl);
|
||||
// print_proc_decl(pd);
|
||||
// case_end;
|
||||
|
||||
case_ast_node(fb, ForeignBlockDecl, decl);
|
||||
// TODO(bill)
|
||||
|
||||
+20
-7
@@ -12,6 +12,7 @@ struct DeclInfo;
|
||||
ENTITY_KIND(TypeName) \
|
||||
ENTITY_KIND(Procedure) \
|
||||
ENTITY_KIND(Builtin) \
|
||||
ENTITY_KIND(Alias) \
|
||||
ENTITY_KIND(ImportName) \
|
||||
ENTITY_KIND(LibraryName) \
|
||||
ENTITY_KIND(Nil) \
|
||||
@@ -70,8 +71,8 @@ struct Entity {
|
||||
Token token;
|
||||
Scope * scope;
|
||||
Type * type;
|
||||
AstNode * identifier; // Can be NULL
|
||||
DeclInfo * parent_proc_decl; // NULL if in file/global scope
|
||||
AstNode * identifier; // Can be nullptr
|
||||
DeclInfo * parent_proc_decl; // nullptr if in file/global scope
|
||||
|
||||
// TODO(bill): Cleanup how `using` works for entities
|
||||
Entity * using_parent;
|
||||
@@ -86,15 +87,18 @@ struct Entity {
|
||||
i32 field_src_index;
|
||||
ExactValue default_value;
|
||||
bool default_is_nil;
|
||||
bool default_is_undef;
|
||||
bool default_is_location;
|
||||
bool is_immutable;
|
||||
bool is_thread_local;
|
||||
bool is_foreign;
|
||||
Entity * foreign_library;
|
||||
AstNode * foreign_library_ident;
|
||||
String link_name;
|
||||
} Variable;
|
||||
struct {
|
||||
bool is_type_alias;
|
||||
Type *type_parameter_specialization;
|
||||
} TypeName;
|
||||
struct {
|
||||
OverloadKind overload_kind;
|
||||
@@ -107,6 +111,9 @@ struct Entity {
|
||||
struct {
|
||||
i32 id;
|
||||
} Builtin;
|
||||
struct {
|
||||
Entity *base;
|
||||
} Alias;
|
||||
struct {
|
||||
String path;
|
||||
String name;
|
||||
@@ -126,7 +133,7 @@ struct Entity {
|
||||
};
|
||||
};
|
||||
|
||||
gb_global Entity *e_context = NULL;
|
||||
gb_global Entity *e_context = nullptr;
|
||||
|
||||
bool is_entity_kind_exported(EntityKind kind) {
|
||||
switch (kind) {
|
||||
@@ -141,7 +148,7 @@ bool is_entity_kind_exported(EntityKind kind) {
|
||||
|
||||
bool is_entity_exported(Entity *e) {
|
||||
// TODO(bill): Determine the actual exportation rules for imports of entities
|
||||
GB_ASSERT(e != NULL);
|
||||
GB_ASSERT(e != nullptr);
|
||||
if (!is_entity_kind_exported(e->kind)) {
|
||||
return false;
|
||||
}
|
||||
@@ -172,7 +179,7 @@ Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *typ
|
||||
}
|
||||
|
||||
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
|
||||
GB_ASSERT(parent != NULL);
|
||||
GB_ASSERT(parent != nullptr);
|
||||
token.pos = parent->token.pos;
|
||||
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
|
||||
entity->using_parent = parent;
|
||||
@@ -231,6 +238,12 @@ Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type, Entity *base) {
|
||||
Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type);
|
||||
entity->Alias.base = base;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||
String path, String name, Scope *import_scope) {
|
||||
Entity *entity = alloc_entity(a, Entity_ImportName, scope, token, type);
|
||||
@@ -254,7 +267,7 @@ Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type
|
||||
|
||||
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
|
||||
Token token = make_token_ident(name);
|
||||
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type);
|
||||
Entity *entity = alloc_entity(a, Entity_Nil, nullptr, token, type);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -269,6 +282,6 @@ Entity *make_entity_label(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||
|
||||
Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
|
||||
token.string = str_lit("_");
|
||||
return make_entity_variable(a, scope, token, NULL, false);
|
||||
return make_entity_variable(a, scope, token, nullptr, false);
|
||||
}
|
||||
|
||||
|
||||
+44
-17
@@ -5,6 +5,8 @@
|
||||
|
||||
struct AstNode;
|
||||
struct HashKey;
|
||||
struct Type;
|
||||
bool are_types_identical(Type *x, Type *y);
|
||||
|
||||
struct Complex128 {
|
||||
f64 real, imag;
|
||||
@@ -20,6 +22,7 @@ enum ExactValueKind {
|
||||
ExactValue_Complex,
|
||||
ExactValue_Pointer,
|
||||
ExactValue_Compound, // TODO(bill): Is this good enough?
|
||||
ExactValue_Type,
|
||||
|
||||
ExactValue_Count,
|
||||
};
|
||||
@@ -34,6 +37,7 @@ struct ExactValue {
|
||||
i64 value_pointer;
|
||||
Complex128 value_complex;
|
||||
AstNode * value_compound;
|
||||
Type * value_type;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -99,6 +103,12 @@ ExactValue exact_value_pointer(i64 ptr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_type(Type *type) {
|
||||
ExactValue result = {ExactValue_Type};
|
||||
result.value_type = type;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ExactValue exact_value_integer_from_string(String string) {
|
||||
return exact_value_u128(u128_from_string(string));
|
||||
@@ -494,19 +504,19 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
i128 b = y.value_integer;
|
||||
i128 c = I128_ZERO;
|
||||
switch (op) {
|
||||
case Token_Add: c = a + b; break;
|
||||
case Token_Sub: c = a - b; break;
|
||||
case Token_Mul: c = a * b; break;
|
||||
case Token_Add: c = a + b; break;
|
||||
case Token_Sub: c = a - b; break;
|
||||
case Token_Mul: c = a * b; break;
|
||||
case Token_Quo: return exact_value_float(fmod(i128_to_f64(a), i128_to_f64(b)));
|
||||
case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division
|
||||
case Token_Mod: c = a % b; break;
|
||||
case Token_ModMod: c = ((a % b) + b) % b; break;
|
||||
case Token_And: c = a & b; break;
|
||||
case Token_Or: c = a | b; break;
|
||||
case Token_Xor: c = a ^ b; break;
|
||||
case Token_AndNot: c = i128_and_not(a, b); break;
|
||||
case Token_Shl: c = a << i128_to_u64(b); break;
|
||||
case Token_Shr: c = a >> i128_to_u64(b); break;
|
||||
case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division
|
||||
case Token_Mod: c = a % b; break;
|
||||
case Token_ModMod: c = ((a % b) + b) % b; break;
|
||||
case Token_And: c = a & b; break;
|
||||
case Token_Or: c = a | b; break;
|
||||
case Token_Xor: c = a ^ b; break;
|
||||
case Token_AndNot: c = i128_and_not(a, b); break;
|
||||
case Token_Shl: c = a << cast(u32)i128_to_u64(b); break;
|
||||
case Token_Shr: c = a >> cast(u32)i128_to_u64(b); break;
|
||||
default: goto error;
|
||||
}
|
||||
|
||||
@@ -555,13 +565,23 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
}
|
||||
return exact_value_complex(real, imag);
|
||||
} break;
|
||||
|
||||
case ExactValue_String: {
|
||||
if (op != Token_Add) goto error;
|
||||
|
||||
// NOTE(bill): How do you minimize this over allocation?
|
||||
String sx = x.value_string;
|
||||
String sy = y.value_string;
|
||||
isize len = sx.len+sy.len;
|
||||
u8 *data = gb_alloc_array(heap_allocator(), u8, len);
|
||||
gb_memmove(data, sx.text, sx.len);
|
||||
gb_memmove(data+sx.len, sy.text, sy.len);
|
||||
return exact_value_string(make_string(data, len));
|
||||
} break;
|
||||
}
|
||||
|
||||
error:
|
||||
; // MSVC accepts this??? apparently you cannot declare variables immediately after labels...
|
||||
ExactValue error_value = {};
|
||||
// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
|
||||
return error_value;
|
||||
error:; // NOTE(bill): MSVC accepts this??? apparently you cannot declare variables immediately after labels...
|
||||
return empty_exact_value;
|
||||
}
|
||||
|
||||
gb_inline ExactValue exact_value_add(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Add, x, y); }
|
||||
@@ -639,6 +659,13 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
case Token_GtEq: return a >= b;
|
||||
}
|
||||
} break;
|
||||
|
||||
case ExactValue_Type:
|
||||
switch (op) {
|
||||
case Token_CmpEq: return are_types_identical(x.value_type, y.value_type);
|
||||
case Token_NotEq: return !are_types_identical(x.value_type, y.value_type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
GB_PANIC("Invalid comparison");
|
||||
|
||||
+108
-65
@@ -1,4 +1,4 @@
|
||||
/* gb.h - v0.28 - Ginger Bill's C Helper Library - public domain
|
||||
/* gb.h - v0.31 - Ginger Bill's C Helper Library - public domain
|
||||
- no warranty implied; use at your own risk
|
||||
|
||||
This is a single header file with a bunch of useful stuff
|
||||
@@ -58,6 +58,9 @@ TODOS
|
||||
- More date & time functions
|
||||
|
||||
VERSION HISTORY
|
||||
0.31 - Add gb_file_remove
|
||||
0.30 - Changes to gbThread (and gbMutex on Windows)
|
||||
0.29 - Add extras for gbString
|
||||
0.28 - Handle UCS2 correctly in Win32 part
|
||||
0.27 - OSX fixes and Linux gbAffinity
|
||||
0.26d - Minor changes to how gbFile works
|
||||
@@ -927,12 +930,12 @@ GB_DEF void gb_semaphore_wait (gbSemaphore *s);
|
||||
|
||||
|
||||
// Mutex
|
||||
// TODO(bill): Should this be replaced with a CRITICAL_SECTION on win32 or is the better?
|
||||
typedef struct gbMutex {
|
||||
gbSemaphore semaphore;
|
||||
gbAtomic32 counter;
|
||||
gbAtomic32 owner;
|
||||
i32 recursion;
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
CRITICAL_SECTION win32_critical_section;
|
||||
#else
|
||||
pthread_mutex_t pthread_mutex;
|
||||
#endif
|
||||
} gbMutex;
|
||||
|
||||
GB_DEF void gb_mutex_init (gbMutex *m);
|
||||
@@ -956,7 +959,7 @@ gb_mutex_init(&m);
|
||||
|
||||
|
||||
|
||||
#define GB_THREAD_PROC(name) void name(void *data)
|
||||
#define GB_THREAD_PROC(name) isize name(struct gbThread *thread)
|
||||
typedef GB_THREAD_PROC(gbThreadProc);
|
||||
|
||||
typedef struct gbThread {
|
||||
@@ -967,7 +970,9 @@ typedef struct gbThread {
|
||||
#endif
|
||||
|
||||
gbThreadProc *proc;
|
||||
void * data;
|
||||
void * user_data;
|
||||
isize user_index;
|
||||
isize return_value;
|
||||
|
||||
gbSemaphore semaphore;
|
||||
isize stack_size;
|
||||
@@ -975,7 +980,7 @@ typedef struct gbThread {
|
||||
} gbThread;
|
||||
|
||||
GB_DEF void gb_thread_init (gbThread *t);
|
||||
GB_DEF void gb_thread_destory (gbThread *t);
|
||||
GB_DEF void gb_thread_destroy (gbThread *t);
|
||||
GB_DEF void gb_thread_start (gbThread *t, gbThreadProc *proc, void *data);
|
||||
GB_DEF void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size);
|
||||
GB_DEF void gb_thread_join (gbThread *t);
|
||||
@@ -1521,6 +1526,8 @@ GB_DEF void gb_string_clear (gbString str);
|
||||
GB_DEF gbString gb_string_append (gbString str, gbString const other);
|
||||
GB_DEF gbString gb_string_append_length (gbString str, void const *other, isize num_bytes);
|
||||
GB_DEF gbString gb_string_appendc (gbString str, char const *other);
|
||||
GB_DEF gbString gb_string_append_rune (gbString str, Rune r);
|
||||
GB_DEF gbString gb_string_append_fmt (gbString str, char const *fmt, ...);
|
||||
GB_DEF gbString gb_string_set (gbString str, char const *cstr);
|
||||
GB_DEF gbString gb_string_make_space_for (gbString str, isize add_len);
|
||||
GB_DEF isize gb_string_allocation_size(gbString const str);
|
||||
@@ -2044,6 +2051,7 @@ GB_DEF b32 gb_file_exists (char const *filepath);
|
||||
GB_DEF gbFileTime gb_file_last_write_time(char const *filepath);
|
||||
GB_DEF b32 gb_file_copy (char const *existing_filename, char const *new_filename, b32 fail_if_exists);
|
||||
GB_DEF b32 gb_file_move (char const *existing_filename, char const *new_filename);
|
||||
GB_DEF b32 gb_file_remove (char const *filename);
|
||||
|
||||
|
||||
#ifndef GB_PATH_SEPARATOR
|
||||
@@ -4590,59 +4598,44 @@ gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); }
|
||||
#error
|
||||
#endif
|
||||
|
||||
// NOTE(bill): THIS IS FUCKING AWESOME THAT THIS "MUTEX" IS FAST AND RECURSIVE TOO!
|
||||
// NOTE(bill): WHO THE FUCK NEEDS A NORMAL MUTEX NOW?!?!?!?!
|
||||
gb_inline void gb_mutex_init(gbMutex *m) {
|
||||
gb_atomic32_store(&m->counter, 0);
|
||||
gb_atomic32_store(&m->owner, gb_thread_current_id());
|
||||
gb_semaphore_init(&m->semaphore);
|
||||
m->recursion = 0;
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
InitializeCriticalSection(&m->win32_critical_section);
|
||||
#else
|
||||
pthread_mutex_init(&m->pthread_mutex, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
gb_inline void gb_mutex_destroy(gbMutex *m) { gb_semaphore_destroy(&m->semaphore); }
|
||||
gb_inline void gb_mutex_destroy(gbMutex *m) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
DeleteCriticalSection(&m->win32_critical_section);
|
||||
#else
|
||||
pthread_mutex_destroy(&m->pthread_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
gb_inline void gb_mutex_lock(gbMutex *m) {
|
||||
i32 thread_id = cast(i32)gb_thread_current_id();
|
||||
if (gb_atomic32_fetch_add(&m->counter, 1) > 0) {
|
||||
if (thread_id != gb_atomic32_load(&m->owner))
|
||||
gb_semaphore_wait(&m->semaphore);
|
||||
}
|
||||
|
||||
gb_atomic32_store(&m->owner, thread_id);
|
||||
m->recursion++;
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
EnterCriticalSection(&m->win32_critical_section);
|
||||
#else
|
||||
pthread_mutex_lock(&m->pthread_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
gb_inline b32 gb_mutex_try_lock(gbMutex *m) {
|
||||
i32 thread_id = cast(i32)gb_thread_current_id();
|
||||
if (gb_atomic32_load(&m->owner) == thread_id) {
|
||||
gb_atomic32_fetch_add(&m->counter, 1);
|
||||
} else {
|
||||
i32 expected = 0;
|
||||
if (gb_atomic32_load(&m->counter) != 0)
|
||||
return false;
|
||||
if (!gb_atomic32_compare_exchange(&m->counter, expected, 1))
|
||||
return false;
|
||||
gb_atomic32_store(&m->owner, thread_id);
|
||||
}
|
||||
|
||||
m->recursion++;
|
||||
return true;
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
return TryEnterCriticalSection(&m->win32_critical_section) != 0;
|
||||
#else
|
||||
return pthread_mutex_trylock(&m->pthread_mutex) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
gb_inline void gb_mutex_unlock(gbMutex *m) {
|
||||
i32 recursion;
|
||||
i32 thread_id = cast(i32)gb_thread_current_id();
|
||||
|
||||
GB_ASSERT(thread_id == gb_atomic32_load(&m->owner));
|
||||
|
||||
recursion = --m->recursion;
|
||||
if (recursion == 0)
|
||||
gb_atomic32_store(&m->owner, thread_id);
|
||||
|
||||
if (gb_atomic32_fetch_add(&m->counter, -1) > 1) {
|
||||
if (recursion == 0)
|
||||
gb_semaphore_release(&m->semaphore);
|
||||
}
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
LeaveCriticalSection(&m->win32_critical_section);
|
||||
#else
|
||||
pthread_mutex_unlock(&m->pthread_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -4661,7 +4654,7 @@ void gb_thread_init(gbThread *t) {
|
||||
gb_semaphore_init(&t->semaphore);
|
||||
}
|
||||
|
||||
void gb_thread_destory(gbThread *t) {
|
||||
void gb_thread_destroy(gbThread *t) {
|
||||
if (t->is_running) gb_thread_join(t);
|
||||
gb_semaphore_destroy(&t->semaphore);
|
||||
}
|
||||
@@ -4669,22 +4662,32 @@ void gb_thread_destory(gbThread *t) {
|
||||
|
||||
gb_inline void gb__thread_run(gbThread *t) {
|
||||
gb_semaphore_release(&t->semaphore);
|
||||
t->proc(t->data);
|
||||
t->return_value = t->proc(t);
|
||||
}
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
gb_inline DWORD __stdcall gb__thread_proc(void *arg) { gb__thread_run(cast(gbThread *)arg); return 0; }
|
||||
gb_inline DWORD __stdcall gb__thread_proc(void *arg) {
|
||||
gbThread *t = cast(gbThread *)arg;
|
||||
gb__thread_run(t);
|
||||
t->is_running = false;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
gb_inline void * gb__thread_proc(void *arg) { gb__thread_run(cast(gbThread *)arg); return NULL; }
|
||||
gb_inline void * gb__thread_proc(void *arg) {
|
||||
gbThread *t = cast(gbThread *)arg;
|
||||
gb__thread_run(t);
|
||||
t->is_running = false;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
gb_inline void gb_thread_start(gbThread *t, gbThreadProc *proc, void *data) { gb_thread_start_with_stack(t, proc, data, 0); }
|
||||
gb_inline void gb_thread_start(gbThread *t, gbThreadProc *proc, void *user_data) { gb_thread_start_with_stack(t, proc, user_data, 0); }
|
||||
|
||||
gb_inline void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size) {
|
||||
gb_inline void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void *user_data, isize stack_size) {
|
||||
GB_ASSERT(!t->is_running);
|
||||
GB_ASSERT(proc != NULL);
|
||||
t->proc = proc;
|
||||
t->data = data;
|
||||
t->user_data = user_data;
|
||||
t->stack_size = stack_size;
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
@@ -4695,8 +4698,9 @@ gb_inline void gb_thread_start_with_stack(gbThread *t, gbThreadProc *proc, void
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
if (stack_size != 0)
|
||||
if (stack_size != 0) {
|
||||
pthread_attr_setstacksize(&attr, stack_size);
|
||||
}
|
||||
pthread_create(&t->posix_handle, &attr, gb__thread_proc, t);
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
@@ -5398,7 +5402,8 @@ gb_inline gbTempArenaMemory gb_temp_arena_memory_begin(gbArena *arena) {
|
||||
}
|
||||
|
||||
gb_inline void gb_temp_arena_memory_end(gbTempArenaMemory tmp) {
|
||||
GB_ASSERT(tmp.arena->total_allocated >= tmp.original_count);
|
||||
GB_ASSERT_MSG(tmp.arena->total_allocated >= tmp.original_count,
|
||||
"%td >= %td", tmp.arena->total_allocated, tmp.original_count);
|
||||
GB_ASSERT(tmp.arena->temp_count > 0);
|
||||
tmp.arena->total_allocated = tmp.original_count;
|
||||
tmp.arena->temp_count--;
|
||||
@@ -6573,6 +6578,26 @@ gb_inline gbString gb_string_appendc(gbString str, char const *other) {
|
||||
return gb_string_append_length(str, other, gb_strlen(other));
|
||||
}
|
||||
|
||||
gbString gb_string_append_rune(gbString str, Rune r) {
|
||||
if (r >= 0) {
|
||||
u8 buf[8] = {0};
|
||||
isize len = gb_utf8_encode_rune(buf, r);
|
||||
return gb_string_append_length(str, buf, len);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
gbString gb_string_append_fmt(gbString str, char const *fmt, ...) {
|
||||
isize res;
|
||||
char buf[4096] = {0};
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
res = gb_snprintf_va(str, gb_count_of(buf)-1, fmt, va);
|
||||
va_end(va);
|
||||
return gb_string_append_length(str, buf, res);
|
||||
}
|
||||
|
||||
|
||||
|
||||
gbString gb_string_set(gbString str, char const *cstr) {
|
||||
isize len = gb_strlen(cstr);
|
||||
@@ -7403,13 +7428,13 @@ u64 gb_murmur64_seed(void const *data_, isize len, u64 seed) {
|
||||
if (w_len_) *w_len_ = w_len;
|
||||
return NULL;
|
||||
}
|
||||
w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, len, NULL, 0);
|
||||
w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int)len, NULL, 0);
|
||||
if (w_len == 0) {
|
||||
if (w_len_) *w_len_ = w_len;
|
||||
return NULL;
|
||||
}
|
||||
w_text = gb_alloc_array(a, wchar_t, w_len+1);
|
||||
w_len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, len, w_text, w_len);
|
||||
w_len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, cast(int)len, w_text, cast(int)w_len);
|
||||
if (w_len1 == 0) {
|
||||
gb_free(a, w_text);
|
||||
if (w_len_) *w_len_ = 0;
|
||||
@@ -7908,6 +7933,19 @@ gb_inline b32 gb_file_move(char const *existing_filename, char const *new_filena
|
||||
return result;
|
||||
}
|
||||
|
||||
b32 gb_file_remove(char const *filename) {
|
||||
wchar_t *w_filename = NULL;
|
||||
gbAllocator a = gb_heap_allocator();
|
||||
b32 result = false;
|
||||
w_filename = gb__alloc_utf8_to_ucs2(a, filename, NULL);
|
||||
if (w_filename == NULL) {
|
||||
return false;
|
||||
}
|
||||
result = DeleteFileW(w_filename);
|
||||
gb_free(a, w_filename);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
@@ -7953,6 +7991,11 @@ gb_inline b32 gb_file_move(char const *existing_filename, char const *new_filena
|
||||
return false;
|
||||
}
|
||||
|
||||
b32 gb_file_remove(char const *filename) {
|
||||
return remove(filename) == 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -8057,17 +8100,17 @@ char *gb_path_get_full_name(gbAllocator a, char const *path) {
|
||||
return NULL;
|
||||
}
|
||||
w_fullpath = gb_alloc_array(gb_heap_allocator(), wchar_t, w_len+1);
|
||||
GetFullPathNameW(w_path, w_len, w_fullpath, NULL);
|
||||
GetFullPathNameW(w_path, cast(int)w_len, w_fullpath, NULL);
|
||||
w_fullpath[w_len] = 0;
|
||||
gb_free(gb_heap_allocator(), w_path);
|
||||
|
||||
new_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, w_len, NULL, 0, NULL, NULL);
|
||||
new_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int)w_len, NULL, 0, NULL, NULL);
|
||||
if (new_len == 0) {
|
||||
gb_free(gb_heap_allocator(), w_fullpath);
|
||||
return NULL;
|
||||
}
|
||||
new_path = gb_alloc_array(a, char, new_len+1);
|
||||
new_len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, w_len, new_path, new_len, NULL, NULL);
|
||||
new_len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, cast(int)w_len, new_path, cast(int)new_len, NULL, NULL);
|
||||
if (new_len1 == 0) {
|
||||
gb_free(gb_heap_allocator(), w_fullpath);
|
||||
gb_free(a, new_path);
|
||||
|
||||
+4
-4
@@ -520,7 +520,7 @@ u128 u128_quo(u128 a, u128 b) {
|
||||
}
|
||||
|
||||
u128 res = {0};
|
||||
u128_divide(a, b, &res, NULL);
|
||||
u128_divide(a, b, &res, nullptr);
|
||||
return res;
|
||||
}
|
||||
u128 u128_mod(u128 a, u128 b) {
|
||||
@@ -528,7 +528,7 @@ u128 u128_mod(u128 a, u128 b) {
|
||||
return u128_from_u64(a.lo%b.lo);
|
||||
}
|
||||
u128 res = {0};
|
||||
u128_divide(a, b, NULL, &res);
|
||||
u128_divide(a, b, nullptr, &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -716,11 +716,11 @@ void i128_divide(i128 a, i128 b, i128 *quo, i128 *rem) {
|
||||
|
||||
i128 i128_quo(i128 a, i128 b) {
|
||||
i128 res = {0};
|
||||
i128_divide(a, b, &res, NULL);
|
||||
i128_divide(a, b, &res, nullptr);
|
||||
return res;
|
||||
}
|
||||
i128 i128_mod(i128 a, i128 b) {
|
||||
i128 res = {0};
|
||||
i128_divide(a, b, NULL, &res);
|
||||
i128_divide(a, b, nullptr, &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
+1200
-1054
File diff suppressed because it is too large
Load Diff
+14
-14
@@ -39,7 +39,7 @@ void ir_opt_add_operands(Array<irValue *> *ops, irInstr *i) {
|
||||
array_add(ops, i->If.cond);
|
||||
break;
|
||||
case irInstr_Return:
|
||||
if (i->Return.value != NULL) {
|
||||
if (i->Return.value != nullptr) {
|
||||
array_add(ops, i->Return.value);
|
||||
}
|
||||
break;
|
||||
@@ -168,11 +168,11 @@ void ir_remove_dead_blocks(irProcedure *proc) {
|
||||
isize j = 0;
|
||||
for_array(i, proc->blocks) {
|
||||
irBlock *b = proc->blocks[i];
|
||||
if (b == NULL) {
|
||||
if (b == nullptr) {
|
||||
continue;
|
||||
}
|
||||
// NOTE(bill): Swap order
|
||||
b->index = j;
|
||||
b->index = cast(i32)j;
|
||||
proc->blocks[j++] = b;
|
||||
}
|
||||
proc->blocks.count = j;
|
||||
@@ -210,7 +210,7 @@ void ir_remove_unreachable_blocks(irProcedure *proc) {
|
||||
}
|
||||
// NOTE(bill): Mark as empty but don't actually free it
|
||||
// As it's been allocated with an arena
|
||||
proc->blocks[i] = NULL;
|
||||
proc->blocks[i] = nullptr;
|
||||
}
|
||||
}
|
||||
ir_remove_dead_blocks(proc);
|
||||
@@ -245,7 +245,7 @@ bool ir_opt_block_fusion(irProcedure *proc, irBlock *a) {
|
||||
ir_opt_block_replace_pred(b->succs[i], b, a);
|
||||
}
|
||||
|
||||
proc->blocks[b->index] = NULL;
|
||||
proc->blocks[b->index] = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ void ir_opt_blocks(irProcedure *proc) {
|
||||
changed = false;
|
||||
for_array(i, proc->blocks) {
|
||||
irBlock *b = proc->blocks[i];
|
||||
if (b == NULL) {
|
||||
if (b == nullptr) {
|
||||
continue;
|
||||
}
|
||||
GB_ASSERT_MSG(b->index == i, "%d, %td", b->index, i);
|
||||
@@ -286,11 +286,11 @@ void ir_opt_build_referrers(irProcedure *proc) {
|
||||
ir_opt_add_operands(&ops, &instr->Instr);
|
||||
for_array(k, ops) {
|
||||
irValue *op = ops[k];
|
||||
if (op == NULL) {
|
||||
if (op == nullptr) {
|
||||
continue;
|
||||
}
|
||||
Array<irValue *> *refs = ir_value_referrers(op);
|
||||
if (refs != NULL) {
|
||||
if (refs != nullptr) {
|
||||
array_add(refs, instr);
|
||||
}
|
||||
}
|
||||
@@ -325,10 +325,10 @@ i32 ir_lt_depth_first_search(irLTState *lt, irBlock *p, i32 i, irBlock **preorde
|
||||
preorder[i] = p;
|
||||
p->dom.pre = i++;
|
||||
lt->sdom[p->index] = p;
|
||||
ir_lt_link(lt, NULL, p);
|
||||
ir_lt_link(lt, nullptr, p);
|
||||
for_array(index, p->succs) {
|
||||
irBlock *q = p->succs[index];
|
||||
if (lt->sdom[q->index] == NULL) {
|
||||
if (lt->sdom[q->index] == nullptr) {
|
||||
lt->parent[q->index] = p;
|
||||
i = ir_lt_depth_first_search(lt, q, i, preorder);
|
||||
}
|
||||
@@ -339,7 +339,7 @@ i32 ir_lt_depth_first_search(irLTState *lt, irBlock *p, i32 i, irBlock **preorde
|
||||
irBlock *ir_lt_eval(irLTState *lt, irBlock *v) {
|
||||
irBlock *u = v;
|
||||
for (;
|
||||
lt->ancestor[v->index] != NULL;
|
||||
lt->ancestor[v->index] != nullptr;
|
||||
v = lt->ancestor[v->index]) {
|
||||
if (lt->sdom[v->index]->dom.pre < lt->sdom[u->index]->dom.pre) {
|
||||
u = v;
|
||||
@@ -373,7 +373,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
|
||||
|
||||
isize n = proc->blocks.count;
|
||||
i32 n = cast(i32)proc->blocks.count;
|
||||
irBlock **buf = gb_alloc_array(proc->module->tmp_allocator, irBlock *, 5*n);
|
||||
|
||||
irLTState lt = {0};
|
||||
@@ -432,7 +432,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
|
||||
for (isize i = 1; i < n; i++) {
|
||||
irBlock *w = preorder[i];
|
||||
if (w == root) {
|
||||
w->dom.idom = NULL;
|
||||
w->dom.idom = nullptr;
|
||||
} else {
|
||||
// Weird tree relationships here!
|
||||
|
||||
@@ -441,7 +441,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
|
||||
}
|
||||
|
||||
// Calculate children relation as inverse of idom
|
||||
if (w->dom.idom->dom.children.data == NULL) {
|
||||
if (w->dom.idom->dom.children.data == nullptr) {
|
||||
// TODO(bill): Is this good enough for memory allocations?
|
||||
array_init(&w->dom.idom->dom.children, heap_allocator());
|
||||
}
|
||||
|
||||
+576
-508
File diff suppressed because it is too large
Load Diff
+217
-102
@@ -1,5 +1,6 @@
|
||||
#define USE_CUSTOM_BACKEND 0
|
||||
// #define PRINT_TIMINGS
|
||||
#define USE_THREADED_PARSER 1
|
||||
// #define NO_ARRAY_BOUNDS_CHECK
|
||||
|
||||
#include "common.cpp"
|
||||
#include "timings.cpp"
|
||||
@@ -41,8 +42,8 @@ i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||
|
||||
cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1));
|
||||
|
||||
if (CreateProcessW(NULL, cmd.text,
|
||||
NULL, NULL, true, 0, NULL, NULL,
|
||||
if (CreateProcessW(nullptr, cmd.text,
|
||||
nullptr, nullptr, true, 0, nullptr, nullptr,
|
||||
&start_info, &pi)) {
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code);
|
||||
@@ -171,6 +172,9 @@ enum BuildFlagKind {
|
||||
BuildFlag_Invalid,
|
||||
|
||||
BuildFlag_OptimizationLevel,
|
||||
BuildFlag_ShowTimings,
|
||||
BuildFlag_ThreadCount,
|
||||
BuildFlag_KeepTempFiles,
|
||||
|
||||
BuildFlag_COUNT,
|
||||
};
|
||||
@@ -201,7 +205,11 @@ void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, Bu
|
||||
bool parse_build_flags(Array<String> args) {
|
||||
Array<BuildFlag> build_flags = {};
|
||||
array_init(&build_flags, heap_allocator(), BuildFlag_COUNT);
|
||||
add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer);
|
||||
add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer);
|
||||
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
|
||||
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
|
||||
|
||||
|
||||
Array<String> flag_args = args;
|
||||
flag_args.data += 3;
|
||||
@@ -214,105 +222,152 @@ bool parse_build_flags(Array<String> args) {
|
||||
String flag = flag_args[i];
|
||||
if (flag[0] != '-') {
|
||||
gb_printf_err("Invalid flag: %.*s\n", LIT(flag));
|
||||
} else {
|
||||
String name = substring(flag, 1, flag.len);
|
||||
isize end = 0;
|
||||
for (; end < name.len; end++) {
|
||||
if (name[end] == '=') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
name.len = end;
|
||||
String param = substring(flag, 2+end, flag.len);
|
||||
continue;
|
||||
}
|
||||
String name = substring(flag, 1, flag.len);
|
||||
isize end = 0;
|
||||
for (; end < name.len; end++) {
|
||||
if (name[end] == '=') break;
|
||||
}
|
||||
name = substring(name, 0, end);
|
||||
String param = {};
|
||||
if (end < flag.len-1) param = substring(flag, 2+end, flag.len);
|
||||
|
||||
bool found = false;
|
||||
for_array(build_flag_index, build_flags) {
|
||||
BuildFlag bf = build_flags[build_flag_index];
|
||||
if (bf.name == name) {
|
||||
found = true;
|
||||
if (set_flags[bf.kind]) {
|
||||
gb_printf_err("Previous flag set: `%.*s`\n", LIT(name));
|
||||
bool found = false;
|
||||
for_array(build_flag_index, build_flags) {
|
||||
BuildFlag bf = build_flags[build_flag_index];
|
||||
if (bf.name == name) {
|
||||
found = true;
|
||||
if (set_flags[bf.kind]) {
|
||||
gb_printf_err("Previous flag set: `%.*s`\n", LIT(name));
|
||||
bad_flags = true;
|
||||
} else {
|
||||
ExactValue value = {};
|
||||
bool ok = false;
|
||||
if (bf.param_kind == BuildFlagParam_None) {
|
||||
if (param.len == 0) {
|
||||
ok = true;
|
||||
} else {
|
||||
gb_printf_err("Flag `%.*s` was not expecting a parameter `%.*s`\n", LIT(name), LIT(param));
|
||||
bad_flags = true;
|
||||
}
|
||||
} else if (param.len == 0) {
|
||||
gb_printf_err("Flag missing for `%.*s`\n", LIT(name));
|
||||
bad_flags = true;
|
||||
} else {
|
||||
ExactValue value = {};
|
||||
bool ok = false;
|
||||
if (bf.param_kind == BuildFlagParam_None) {
|
||||
if (param.len == 0) {
|
||||
ok = true;
|
||||
ok = true;
|
||||
switch (bf.param_kind) {
|
||||
default: ok = false; break;
|
||||
case BuildFlagParam_Boolean: {
|
||||
if (param == "t") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "T") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "true") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "TRUE") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "1") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "f") {
|
||||
value = exact_value_bool(false);
|
||||
} else if (param == "F") {
|
||||
value = exact_value_bool(false);
|
||||
} else if (param == "false") {
|
||||
value = exact_value_bool(false);
|
||||
} else if (param == "FALSE") {
|
||||
value = exact_value_bool(false);
|
||||
} else if (param == "0") {
|
||||
value = exact_value_bool(false);
|
||||
} else {
|
||||
gb_printf_err("Flag `%.*s` was not expecting a parameter `%.*s`\n", LIT(name), LIT(param));
|
||||
bad_flags = true;
|
||||
gb_printf_err("Invalid flag parameter for `%.*s` = `%.*s`\n", LIT(name), LIT(param));
|
||||
}
|
||||
} else {
|
||||
if (param.len == 0) {
|
||||
gb_printf_err("Flag missing for `%.*s`\n", LIT(name));
|
||||
bad_flags = true;
|
||||
} else {
|
||||
ok = true;
|
||||
switch (bf.param_kind) {
|
||||
default: ok = false; break;
|
||||
case BuildFlagParam_Boolean: {
|
||||
if (param == "t") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "T") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "true") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "TRUE") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "1") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "f") {
|
||||
value = exact_value_bool(false);
|
||||
} else if (param == "F") {
|
||||
value = exact_value_bool(false);
|
||||
} else if (param == "false") {
|
||||
value = exact_value_bool(false);
|
||||
} else if (param == "FALSE") {
|
||||
value = exact_value_bool(false);
|
||||
} else if (param == "0") {
|
||||
value = exact_value_bool(false);
|
||||
} else {
|
||||
gb_printf_err("Invalid flag parameter for `%.*s` = `%.*s`\n", LIT(name), LIT(param));
|
||||
}
|
||||
} break;
|
||||
case BuildFlagParam_Integer:
|
||||
value = exact_value_integer_from_string(param);
|
||||
break;
|
||||
case BuildFlagParam_Float:
|
||||
value = exact_value_float_from_string(param);
|
||||
break;
|
||||
case BuildFlagParam_String:
|
||||
value = exact_value_string(param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
case BuildFlagParam_Integer:
|
||||
value = exact_value_integer_from_string(param);
|
||||
break;
|
||||
case BuildFlagParam_Float:
|
||||
value = exact_value_float_from_string(param);
|
||||
break;
|
||||
case BuildFlagParam_String:
|
||||
value = exact_value_string(param);
|
||||
break;
|
||||
}
|
||||
if (ok) {
|
||||
switch (bf.kind) {
|
||||
case BuildFlag_OptimizationLevel:
|
||||
if (value.kind == ExactValue_Integer) {
|
||||
build_context.optimization_level = cast(i32)i128_to_i64(value.value_integer);
|
||||
} else {
|
||||
gb_printf_err("%.*s expected an integer, got %.*s", LIT(name), LIT(param));
|
||||
bad_flags = true;
|
||||
ok = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
set_flags[bf.kind] = ok;
|
||||
}
|
||||
break;
|
||||
if (ok) {
|
||||
switch (bf.param_kind) {
|
||||
case BuildFlagParam_None:
|
||||
if (value.kind != ExactValue_Invalid) {
|
||||
gb_printf_err("%.*s expected no value, got %.*s", LIT(name), LIT(param));
|
||||
bad_flags = true;
|
||||
ok = false;
|
||||
}
|
||||
break;
|
||||
case BuildFlagParam_Boolean:
|
||||
if (value.kind != ExactValue_Bool) {
|
||||
gb_printf_err("%.*s expected a boolean, got %.*s", LIT(name), LIT(param));
|
||||
bad_flags = true;
|
||||
ok = false;
|
||||
}
|
||||
break;
|
||||
case BuildFlagParam_Integer:
|
||||
if (value.kind != ExactValue_Integer) {
|
||||
gb_printf_err("%.*s expected an integer, got %.*s", LIT(name), LIT(param));
|
||||
bad_flags = true;
|
||||
ok = false;
|
||||
}
|
||||
break;
|
||||
case BuildFlagParam_Float:
|
||||
if (value.kind != ExactValue_Float) {
|
||||
gb_printf_err("%.*s expected a floating pointer number, got %.*s", LIT(name), LIT(param));
|
||||
bad_flags = true;
|
||||
ok = false;
|
||||
}
|
||||
break;
|
||||
case BuildFlagParam_String:
|
||||
if (value.kind != ExactValue_String) {
|
||||
gb_printf_err("%.*s expected a string, got %.*s", LIT(name), LIT(param));
|
||||
bad_flags = true;
|
||||
ok = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ok) switch (bf.kind) {
|
||||
case BuildFlag_OptimizationLevel:
|
||||
GB_ASSERT(value.kind == ExactValue_Integer);
|
||||
build_context.optimization_level = cast(i32)i128_to_i64(value.value_integer);
|
||||
break;
|
||||
case BuildFlag_ShowTimings:
|
||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
||||
build_context.show_timings = true;
|
||||
break;
|
||||
case BuildFlag_ThreadCount: {
|
||||
GB_ASSERT(value.kind == ExactValue_Integer);
|
||||
isize count = cast(isize)i128_to_i64(value.value_integer);
|
||||
if (count <= 0) {
|
||||
gb_printf_err("%.*s expected a positive non-zero number, got %.*s", LIT(name), LIT(param));
|
||||
build_context.thread_count = 0;
|
||||
} else {
|
||||
build_context.thread_count = count;
|
||||
}
|
||||
} break;
|
||||
case BuildFlag_KeepTempFiles:
|
||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
||||
build_context.keep_temp_files = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
set_flags[bf.kind] = ok;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!found) {
|
||||
gb_printf_err("Unknown flag: `%.*s`\n", LIT(name));
|
||||
bad_flags = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
gb_printf_err("Unknown flag: `%.*s`\n", LIT(name));
|
||||
bad_flags = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +375,64 @@ bool parse_build_flags(Array<String> args) {
|
||||
}
|
||||
|
||||
|
||||
void show_timings(Checker *c, Timings *t) {
|
||||
Parser *p = c->parser;
|
||||
isize lines = p->total_line_count;
|
||||
isize tokens = p->total_token_count;
|
||||
isize files = p->files.count;
|
||||
{
|
||||
timings_print_all(t);
|
||||
gb_printf("\n");
|
||||
gb_printf("Total Lines - %td\n", lines);
|
||||
gb_printf("Total Tokens - %td\n", tokens);
|
||||
gb_printf("Total Files - %td\n", files);
|
||||
gb_printf("\n");
|
||||
}
|
||||
{
|
||||
TimeStamp ts = t->sections[0];
|
||||
GB_ASSERT(ts.label == "parse files");
|
||||
f64 parse_time = time_stamp_as_second(ts, t->freq);
|
||||
gb_printf("Parse pass\n");
|
||||
gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time);
|
||||
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
|
||||
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
|
||||
gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
|
||||
gb_printf("\n");
|
||||
}
|
||||
{
|
||||
f64 total_time = t->total_time_seconds;
|
||||
gb_printf("Total pass\n");
|
||||
gb_printf("LOC/s - %.3f\n", cast(f64)lines/total_time);
|
||||
gb_printf("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines);
|
||||
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/total_time);
|
||||
gb_printf("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens);
|
||||
gb_printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void remove_temp_files(String output_base) {
|
||||
if (build_context.keep_temp_files) return;
|
||||
|
||||
Array<u8> data = {};
|
||||
array_init_count(&data, heap_allocator(), output_base.len + 10);
|
||||
defer (array_free(&data));
|
||||
|
||||
isize n = output_base.len;
|
||||
gb_memcopy(data.data, output_base.text, n);
|
||||
#define EXT_REMOVE(s) do { \
|
||||
gb_memcopy(data.data+n, s, gb_size_of(s)); \
|
||||
gb_file_remove(cast(char *)data.data); \
|
||||
} while (0)
|
||||
EXT_REMOVE(".ll");
|
||||
EXT_REMOVE(".bc");
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
EXT_REMOVE(".obj");
|
||||
#else
|
||||
EXT_REMOVE(".o");
|
||||
#endif
|
||||
|
||||
#undef EXT_REMOVE
|
||||
}
|
||||
|
||||
int main(int arg_count, char **arg_ptr) {
|
||||
if (arg_count < 2) {
|
||||
@@ -375,7 +487,7 @@ int main(int arg_count, char **arg_ptr) {
|
||||
return 1;
|
||||
#endif
|
||||
} else if (args[1] == "version") {
|
||||
gb_printf("%s version %.*s\n", args[0], LIT(build_context.ODIN_VERSION));
|
||||
gb_printf("%.*s version %.*s\n", LIT(args[0]), LIT(ODIN_VERSION));
|
||||
return 0;
|
||||
} else {
|
||||
usage(args[0]);
|
||||
@@ -460,7 +572,7 @@ int main(int arg_count, char **arg_ptr) {
|
||||
|
||||
String output_name = ir_gen.output_name;
|
||||
String output_base = ir_gen.output_base;
|
||||
int base_name_len = output_base.len;
|
||||
int base_name_len = cast(int)output_base.len;
|
||||
|
||||
build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3);
|
||||
|
||||
@@ -556,10 +668,11 @@ int main(int arg_count, char **arg_ptr) {
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
#if defined(PRINT_TIMINGS)
|
||||
timings_print_all(&timings);
|
||||
#endif
|
||||
if (build_context.show_timings) {
|
||||
show_timings(&checker, &timings);
|
||||
}
|
||||
|
||||
remove_temp_files(output_base);
|
||||
|
||||
if (run_output) {
|
||||
system_exec_command_line_app("odin run", false, "%.*s.exe", LIT(output_base));
|
||||
@@ -662,9 +775,11 @@ int main(int arg_count, char **arg_ptr) {
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
#if defined(PRINT_TIMINGS)
|
||||
timings_print_all(&timings);
|
||||
#endif
|
||||
if (build_context.show_timings) {
|
||||
show_timings(&checker, &timings);
|
||||
}
|
||||
|
||||
remove_temp_files(output_base);
|
||||
|
||||
if (run_output) {
|
||||
system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base));
|
||||
|
||||
+6
-6
@@ -234,7 +234,7 @@ gb_inline T *map_get(Map<T> *h, HashKey key) {
|
||||
if (index >= 0) {
|
||||
return &h->entries[index].value;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -303,7 +303,7 @@ template <typename T>
|
||||
MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey key) {
|
||||
isize i = map__find(h, key).entry_index;
|
||||
if (i < 0) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return &h->entries[i];
|
||||
}
|
||||
@@ -317,14 +317,14 @@ MapEntry<T> *multi_map_find_next(Map<T> *h, MapEntry<T> *e) {
|
||||
}
|
||||
i = h->entries[i].next;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
isize multi_map_count(Map<T> *h, HashKey key) {
|
||||
isize count = 0;
|
||||
MapEntry<T> *e = multi_map_find_first(h, key);
|
||||
while (e != NULL) {
|
||||
while (e != nullptr) {
|
||||
count++;
|
||||
e = multi_map_find_next(h, e);
|
||||
}
|
||||
@@ -335,7 +335,7 @@ template <typename T>
|
||||
void multi_map_get_all(Map<T> *h, HashKey key, T *items) {
|
||||
isize i = 0;
|
||||
MapEntry<T> *e = multi_map_find_first(h, key);
|
||||
while (e != NULL) {
|
||||
while (e != nullptr) {
|
||||
items[i++] = e->value;
|
||||
e = multi_map_find_next(h, e);
|
||||
}
|
||||
@@ -374,7 +374,7 @@ void multi_map_remove(Map<T> *h, HashKey key, MapEntry<T> *e) {
|
||||
|
||||
template <typename T>
|
||||
void multi_map_remove_all(Map<T> *h, HashKey key) {
|
||||
while (map_get(h, key) != NULL) {
|
||||
while (map_get(h, key) != nullptr) {
|
||||
map_remove(h, key);
|
||||
}
|
||||
}
|
||||
|
||||
+1143
-759
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -6,7 +6,7 @@ gb_inline void print_indent(isize indent) {
|
||||
}
|
||||
|
||||
void print_ast(AstNode *node, isize indent) {
|
||||
if (node == NULL)
|
||||
if (node == nullptr)
|
||||
return;
|
||||
|
||||
switch (node->kind) {
|
||||
|
||||
+145
-151
@@ -206,7 +206,7 @@ ssaBlock *ssa_new_block(ssaProc *p, ssaBlockKind kind, char *name) {
|
||||
b->kind = kind;
|
||||
b->proc = p;
|
||||
p->scope_level = p->scope_level;
|
||||
if (name != NULL || name[0] != 0) {
|
||||
if (name != nullptr || name[0] != 0) {
|
||||
b->name = make_string_c(name);
|
||||
}
|
||||
|
||||
@@ -218,34 +218,34 @@ ssaBlock *ssa_new_block(ssaProc *p, ssaBlockKind kind, char *name) {
|
||||
}
|
||||
|
||||
void ssa_clear_block(ssaProc *p, ssaBlock *b) {
|
||||
GB_ASSERT(b->proc != NULL);
|
||||
GB_ASSERT(b->proc != nullptr);
|
||||
array_clear(&b->values);
|
||||
array_clear(&b->preds);
|
||||
array_clear(&b->succs);
|
||||
b->proc = NULL;
|
||||
b->proc = nullptr;
|
||||
b->kind = ssaBlock_Plain;
|
||||
}
|
||||
|
||||
|
||||
void ssa_start_block(ssaProc *p, ssaBlock *b) {
|
||||
GB_ASSERT(p->curr_block == NULL);
|
||||
GB_ASSERT(p->curr_block == nullptr);
|
||||
p->curr_block = b;
|
||||
}
|
||||
|
||||
ssaBlock *ssa_end_block(ssaProc *p) {
|
||||
ssaBlock *b = p->curr_block;
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
if (b == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
p->curr_block = NULL;
|
||||
p->curr_block = nullptr;
|
||||
return b;
|
||||
}
|
||||
|
||||
void ssa_add_edge_to(ssaBlock *b, ssaBlock *c) {
|
||||
if (b == NULL) {
|
||||
if (b == nullptr) {
|
||||
return;
|
||||
}
|
||||
GB_ASSERT(c != NULL);
|
||||
GB_ASSERT(c != nullptr);
|
||||
isize i = b->succs.count;
|
||||
isize j = b->preds.count;
|
||||
ssaEdge s = {c, j};
|
||||
@@ -255,11 +255,11 @@ void ssa_add_edge_to(ssaBlock *b, ssaBlock *c) {
|
||||
}
|
||||
|
||||
void ssa_set_control(ssaBlock *b, ssaValue *v) {
|
||||
if (b->control != NULL) {
|
||||
if (b->control != nullptr) {
|
||||
b->control->uses--;
|
||||
}
|
||||
b->control = v;
|
||||
if (v != NULL) {
|
||||
if (v != nullptr) {
|
||||
v->uses++;
|
||||
}
|
||||
}
|
||||
@@ -295,7 +295,7 @@ void ssa_add_arg(ssaValueArgs *va, ssaValue *arg) {
|
||||
|
||||
|
||||
ssaValue *ssa_new_value(ssaProc *p, ssaOp op, Type *t, ssaBlock *b) {
|
||||
GB_ASSERT(b != NULL);
|
||||
GB_ASSERT(b != nullptr);
|
||||
ssaValue *v = gb_alloc_item(p->allocator, ssaValue);
|
||||
v->id = p->value_id++;
|
||||
v->op = op;
|
||||
@@ -388,7 +388,7 @@ ssaValue *ssa_const_int(ssaProc *p, Type *t, i64 c) {
|
||||
case 64: return ssa_const_i64(p, t, cast(i64)c);
|
||||
}
|
||||
GB_PANIC("Unknown int size");
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -416,8 +416,8 @@ void ssa_reset(ssaValue *v, ssaOp op) {
|
||||
}
|
||||
|
||||
ssaValue *ssa_get_last_value(ssaBlock *b) {
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
if (b == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
isize len = b->values.count;
|
||||
if (len <= 0) {
|
||||
@@ -428,7 +428,7 @@ ssaValue *ssa_get_last_value(ssaBlock *b) {
|
||||
}
|
||||
|
||||
void ssa_emit_comment(ssaProc *p, String s) {
|
||||
// ssa_new_value0v(p, ssaOp_Comment, NULL, exact_value_string(s));
|
||||
// ssa_new_value0v(p, ssaOp_Comment, nullptr, exact_value_string(s));
|
||||
}
|
||||
|
||||
void ssa_build_defer_stmt(ssaProc *p, ssaDefer d) {
|
||||
@@ -463,7 +463,7 @@ void ssa_emit_defer_stmts(ssaProc *p, ssaDeferExitKind kind, ssaBlock *b) {
|
||||
} else if (kind == ssaDeferExit_Return) {
|
||||
ssa_build_defer_stmt(p, d);
|
||||
} else if (kind == ssaDeferExit_Branch) {
|
||||
GB_ASSERT(b != NULL);
|
||||
GB_ASSERT(b != nullptr);
|
||||
i32 lower_limit = b->scope_level+1;
|
||||
if (lower_limit < d.scope_level) {
|
||||
ssa_build_defer_stmt(p, d);
|
||||
@@ -534,7 +534,7 @@ bool ssa_is_op_const(ssaOp op) {
|
||||
bool ssa_is_blank_ident(AstNode *node) {
|
||||
if (node->kind == AstNode_Ident) {
|
||||
ast_node(i, Ident, node);
|
||||
return is_blank_ident(i->string);
|
||||
return is_blank_ident(i->token.string);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -542,7 +542,7 @@ bool ssa_is_blank_ident(AstNode *node) {
|
||||
|
||||
|
||||
ssaAddr ssa_addr(ssaValue *v) {
|
||||
if (v != NULL) {
|
||||
if (v != nullptr) {
|
||||
GB_ASSERT(is_type_pointer(v->type));
|
||||
}
|
||||
ssaAddr addr = {0};
|
||||
@@ -551,13 +551,13 @@ ssaAddr ssa_addr(ssaValue *v) {
|
||||
}
|
||||
|
||||
Type *ssa_addr_type(ssaAddr addr) {
|
||||
if (addr.addr == NULL) {
|
||||
return NULL;
|
||||
if (addr.addr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (addr.kind == ssaAddr_Map) {
|
||||
GB_PANIC("TODO: ssa_addr_type");
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Type *t = addr.addr->type;
|
||||
@@ -603,18 +603,18 @@ ssaAddr ssa_add_local_for_ident(ssaProc *p, AstNode *name) {
|
||||
return ssa_add_local(p, e, name);
|
||||
}
|
||||
|
||||
return ssa_addr(NULL);
|
||||
return ssa_addr(nullptr);
|
||||
}
|
||||
|
||||
ssaAddr ssa_add_local_generated(ssaProc *p, Type *t) {
|
||||
GB_ASSERT(t != NULL);
|
||||
GB_ASSERT(t != nullptr);
|
||||
|
||||
Scope *scope = NULL;
|
||||
Scope *scope = nullptr;
|
||||
if (p->curr_block) {
|
||||
// scope = p->curr_block->scope;
|
||||
}
|
||||
Entity *e = make_entity_variable(p->allocator, scope, empty_token, t, false);
|
||||
return ssa_add_local(p, e, NULL);
|
||||
return ssa_add_local(p, e, nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -639,24 +639,25 @@ bool can_ssa_type(Type *t) {
|
||||
case Type_Map:
|
||||
return false;
|
||||
case Type_Tuple:
|
||||
if (t->Tuple.variable_count > SSA_MAX_STRUCT_FIELD_COUNT) {
|
||||
if (t->Tuple.variables.count > SSA_MAX_STRUCT_FIELD_COUNT) {
|
||||
return false;
|
||||
}
|
||||
for (isize i = 0; i < t->Tuple.variable_count; i++) {
|
||||
for_array(i, t->Tuple.variables) {
|
||||
if (!can_ssa_type(t->Tuple.variables[i]->type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case Type_Record:
|
||||
if (t->Record.kind == TypeRecord_Union) {
|
||||
return false;
|
||||
} else if (t->Record.kind == TypeRecord_Struct) {
|
||||
if (t->Record.field_count > SSA_MAX_STRUCT_FIELD_COUNT) {
|
||||
case Type_Union:
|
||||
return false;
|
||||
|
||||
case Type_Struct:
|
||||
if (!t->Struct.is_raw_union) {
|
||||
if (t->Struct.fields.count > SSA_MAX_STRUCT_FIELD_COUNT) {
|
||||
return false;
|
||||
}
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
if (!can_ssa_type(t->Record.fields[i]->type)) {
|
||||
for_array(i, t->Struct.fields) {
|
||||
if (!can_ssa_type(t->Struct.fields[i]->type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -667,7 +668,7 @@ bool can_ssa_type(Type *t) {
|
||||
}
|
||||
|
||||
void ssa_addr_store(ssaProc *p, ssaAddr addr, ssaValue *value) {
|
||||
if (addr.addr == NULL) {
|
||||
if (addr.addr == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (addr.kind == ssaAddr_Map) {
|
||||
@@ -679,13 +680,13 @@ void ssa_addr_store(ssaProc *p, ssaAddr addr, ssaValue *value) {
|
||||
}
|
||||
|
||||
ssaValue *ssa_addr_load(ssaProc *p, ssaAddr addr) {
|
||||
if (addr.addr == NULL) {
|
||||
return NULL;
|
||||
if (addr.addr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (addr.kind == ssaAddr_Map) {
|
||||
GB_PANIC("here\n");
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Type *t = addr.addr->type;
|
||||
@@ -702,23 +703,23 @@ ssaValue *ssa_get_using_variable(ssaProc *p, Entity *e) {
|
||||
String name = e->token.string;
|
||||
Entity *parent = e->using_parent;
|
||||
Selection sel = lookup_field(p->allocator, parent->type, name, false);
|
||||
GB_ASSERT(sel.entity != NULL);
|
||||
GB_ASSERT(sel.entity != nullptr);
|
||||
ssaValue **pv = map_get(&p->module->values, hash_pointer(parent));
|
||||
ssaValue *v = NULL;
|
||||
if (pv != NULL) {
|
||||
ssaValue *v = nullptr;
|
||||
if (pv != nullptr) {
|
||||
v = *pv;
|
||||
} else {
|
||||
v = ssa_build_addr(p, e->using_expr).addr;
|
||||
}
|
||||
GB_ASSERT(v != NULL);
|
||||
GB_ASSERT(v != nullptr);
|
||||
GB_ASSERT(type_deref(v->type) == parent->type);
|
||||
return ssa_emit_deep_field_ptr_index(p, v, sel);
|
||||
}
|
||||
|
||||
ssaAddr ssa_build_addr_from_entity(ssaProc *p, Entity *e, AstNode *expr) {
|
||||
GB_ASSERT(e != NULL);
|
||||
GB_ASSERT(e != nullptr);
|
||||
|
||||
ssaValue *v = NULL;
|
||||
ssaValue *v = nullptr;
|
||||
ssaValue **found = map_get(&p->module->values, hash_pointer(e));
|
||||
if (found) {
|
||||
v = *found;
|
||||
@@ -727,7 +728,7 @@ ssaAddr ssa_build_addr_from_entity(ssaProc *p, Entity *e, AstNode *expr) {
|
||||
v = ssa_get_using_variable(p, e);
|
||||
}
|
||||
|
||||
if (v == NULL) {
|
||||
if (v == nullptr) {
|
||||
GB_PANIC("Unknown value: %.*s, entity: %p %.*s\n", LIT(e->token.string), e, LIT(entity_strings[e->kind]));
|
||||
}
|
||||
|
||||
@@ -773,11 +774,11 @@ ssaValue *ssa_emit_conv(ssaProc *p, ssaValue *v, Type *t) {
|
||||
|
||||
GB_PANIC("Invalid type conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t));
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
// NOTE(bill): Returns NULL if not possible
|
||||
// NOTE(bill): Returns nullptr if not possible
|
||||
ssaValue *ssa_address_from_load_or_generate_local(ssaProc *p, ssaValue *v) {
|
||||
if (v->op == ssaOp_Load) {
|
||||
return v->args[0];
|
||||
@@ -789,11 +790,11 @@ ssaValue *ssa_address_from_load_or_generate_local(ssaProc *p, ssaValue *v) {
|
||||
|
||||
|
||||
ssaValue *ssa_emit_array_index(ssaProc *p, ssaValue *v, ssaValue *index) {
|
||||
GB_ASSERT(v != NULL);
|
||||
GB_ASSERT(v != nullptr);
|
||||
GB_ASSERT(is_type_pointer(v->type));
|
||||
Type *t = base_type(type_deref(v->type));
|
||||
GB_ASSERT_MSG(is_type_array(t) || is_type_vector(t), "%s", type_to_string(t));
|
||||
Type *elem_ptr = NULL;
|
||||
Type *elem_ptr = nullptr;
|
||||
if (is_type_array(t)) {
|
||||
elem_ptr = make_type_pointer(p->allocator, t->Array.elem);
|
||||
} else if (is_type_vector(t)) {
|
||||
@@ -806,20 +807,14 @@ ssaValue *ssa_emit_array_index(ssaProc *p, ssaValue *v, ssaValue *index) {
|
||||
ssaValue *ssa_emit_ptr_index(ssaProc *p, ssaValue *s, i64 index) {
|
||||
gbAllocator a = p->allocator;
|
||||
Type *t = base_type(type_deref(s->type));
|
||||
Type *result_type = NULL;
|
||||
Type *result_type = nullptr;
|
||||
|
||||
if (is_type_struct(t)) {
|
||||
GB_ASSERT(t->Record.field_count > 0);
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
|
||||
result_type = make_type_pointer(a, t->Record.fields[index]->type);
|
||||
} else if (is_type_union(t)) {
|
||||
type_set_offsets(a, t);
|
||||
GB_ASSERT(t->Record.field_count > 0);
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
|
||||
result_type = make_type_pointer(a, t->Record.fields[index]->type);
|
||||
GB_ASSERT(t->Struct.fields.count > 0);
|
||||
result_type = make_type_pointer(a, t->Struct.fields[index]->type);
|
||||
} else if (is_type_tuple(t)) {
|
||||
GB_ASSERT(t->Tuple.variable_count > 0);
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
|
||||
GB_ASSERT(t->Tuple.variables.count > 0);
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Tuple.variables.count-1));
|
||||
result_type = make_type_pointer(a, t->Tuple.variables[index]->type);
|
||||
} else if (is_type_slice(t)) {
|
||||
switch (index) {
|
||||
@@ -844,17 +839,17 @@ ssaValue *ssa_emit_ptr_index(ssaProc *p, ssaValue *s, i64 index) {
|
||||
case 2: result_type = t_int_ptr; break;
|
||||
case 3: result_type = t_allocator_ptr; break;
|
||||
}
|
||||
} else if (is_type_dynamic_map(t)) {
|
||||
} else if (is_type_map(t)) {
|
||||
Type *gst = t->Map.generated_struct_type;
|
||||
switch (index) {
|
||||
case 0: result_type = make_type_pointer(a, gst->Record.fields[0]->type); break;
|
||||
case 1: result_type = make_type_pointer(a, gst->Record.fields[1]->type); break;
|
||||
case 0: result_type = make_type_pointer(a, gst->Struct.fields[0]->type); break;
|
||||
case 1: result_type = make_type_pointer(a, gst->Struct.fields[1]->type); break;
|
||||
}
|
||||
}else {
|
||||
GB_PANIC("TODO(bill): ssa_emit_ptr_index type: %s, %d", type_to_string(s->type), index);
|
||||
}
|
||||
|
||||
GB_ASSERT(result_type != NULL);
|
||||
GB_ASSERT(result_type != nullptr);
|
||||
|
||||
return ssa_new_value1i(p, ssaOp_PtrIndex, result_type, index, s);
|
||||
}
|
||||
@@ -869,20 +864,17 @@ ssaValue *ssa_emit_value_index(ssaProc *p, ssaValue *s, i64 index) {
|
||||
|
||||
gbAllocator a = p->allocator;
|
||||
Type *t = base_type(s->type);
|
||||
Type *result_type = NULL;
|
||||
Type *result_type = nullptr;
|
||||
|
||||
if (is_type_struct(t)) {
|
||||
GB_ASSERT(t->Record.field_count > 0);
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
|
||||
result_type = t->Record.fields[index]->type;
|
||||
GB_ASSERT(t->Struct.fields.count > 0);
|
||||
result_type = t->Struct.fields[index]->type;
|
||||
} else if (is_type_union(t)) {
|
||||
type_set_offsets(a, t);
|
||||
GB_ASSERT(t->Record.field_count > 0);
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
|
||||
result_type = t->Record.fields[index]->type;
|
||||
GB_ASSERT(t->Struct.fields.count > 0);
|
||||
result_type = t->Struct.fields[index]->type;
|
||||
} else if (is_type_tuple(t)) {
|
||||
GB_ASSERT(t->Tuple.variable_count > 0);
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
|
||||
GB_ASSERT(t->Tuple.variables.count > 0);
|
||||
result_type = t->Tuple.variables[index]->type;
|
||||
} else if (is_type_slice(t)) {
|
||||
switch (index) {
|
||||
@@ -907,17 +899,17 @@ ssaValue *ssa_emit_value_index(ssaProc *p, ssaValue *s, i64 index) {
|
||||
case 2: result_type = t_int; break;
|
||||
case 3: result_type = t_allocator; break;
|
||||
}
|
||||
} else if (is_type_dynamic_map(t)) {
|
||||
} else if (is_type_map(t)) {
|
||||
Type *gst = t->Map.generated_struct_type;
|
||||
switch (index) {
|
||||
case 0: result_type = gst->Record.fields[0]->type; break;
|
||||
case 1: result_type = gst->Record.fields[1]->type; break;
|
||||
case 0: result_type = gst->Struct.fields[0]->type; break;
|
||||
case 1: result_type = gst->Struct.fields[1]->type; break;
|
||||
}
|
||||
} else {
|
||||
GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(s->type), index);
|
||||
}
|
||||
|
||||
GB_ASSERT(result_type != NULL);
|
||||
GB_ASSERT(result_type != nullptr);
|
||||
|
||||
return ssa_new_value1i(p, ssaOp_ValueIndex, result_type, index, s);
|
||||
}
|
||||
@@ -937,10 +929,10 @@ ssaValue *ssa_emit_deep_field_ptr_index(ssaProc *p, ssaValue *e, Selection sel)
|
||||
|
||||
|
||||
if (is_type_raw_union(type)) {
|
||||
type = type->Record.fields[index]->type;
|
||||
type = type->Struct.fields[index]->type;
|
||||
e = ssa_emit_conv(p, e, make_type_pointer(p->allocator, type));
|
||||
} else if (type->kind == Type_Record) {
|
||||
type = type->Record.fields[index]->type;
|
||||
} else if (type->kind == Type_Struct) {
|
||||
type = type->Struct.fields[index]->type;
|
||||
e = ssa_emit_ptr_index(p, e, index);
|
||||
} else if (type->kind == Type_Tuple) {
|
||||
type = type->Tuple.variables[index]->type;
|
||||
@@ -1008,7 +1000,7 @@ ssaValue *ssa_emit_deep_field_value_index(ssaProc *p, ssaValue *e, Selection sel
|
||||
|
||||
if (is_type_raw_union(type)) {
|
||||
GB_PANIC("TODO(bill): IS THIS EVEN CORRECT?");
|
||||
type = type->Record.fields[index]->type;
|
||||
type = type->Struct.fields[index]->type;
|
||||
e = ssa_emit_conv(p, e, type);
|
||||
} else if (type->kind == Type_Map) {
|
||||
e = ssa_emit_value_index(p, e, 1);
|
||||
@@ -1048,13 +1040,13 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
|
||||
ssa_emit_comment(p, str_lit("SelectorExpr"));
|
||||
AstNode *sel = unparen_expr(se->selector);
|
||||
if (sel->kind == AstNode_Ident) {
|
||||
String selector = sel->Ident.string;
|
||||
String selector = sel->Ident.token.string;
|
||||
TypeAndValue tav = type_and_value_of_expr(p->module->info, se->expr);
|
||||
|
||||
if (tav.mode == Addressing_Invalid) {
|
||||
// NOTE(bill): Imports
|
||||
Entity *imp = entity_of_ident(p->module->info, se->expr);
|
||||
if (imp != NULL) {
|
||||
if (imp != nullptr) {
|
||||
GB_ASSERT(imp->kind == Entity_ImportName);
|
||||
}
|
||||
return ssa_build_addr(p, se->selector);
|
||||
@@ -1072,14 +1064,14 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
|
||||
// if (name == "names") {
|
||||
// ssaValue *ti_ptr = ir_type_info(p, type);
|
||||
|
||||
// ssaValue *names_ptr = NULL;
|
||||
// ssaValue *names_ptr = nullptr;
|
||||
|
||||
// if (is_type_enum(type)) {
|
||||
// ssaValue *enum_info = ssa_emit_conv(p, ti_ptr, t_type_info_enum_ptr);
|
||||
// names_ptr = ssa_emit_ptr_index(p, enum_info, 1);
|
||||
// } else if (type->kind == Type_Record) {
|
||||
// ssaValue *record_info = ssa_emit_conv(p, ti_ptr, t_type_info_record_ptr);
|
||||
// names_ptr = ssa_emit_ptr_index(p, record_info, 1);
|
||||
// } else if (type->kind == Type_Struct) {
|
||||
// ssaValue *struct_info = ssa_emit_conv(p, ti_ptr, t_type_info_struct_ptr);
|
||||
// names_ptr = ssa_emit_ptr_index(p, struct_info, 1);
|
||||
// }
|
||||
// return ssa_addr(names_ptr);
|
||||
// } else {
|
||||
@@ -1089,7 +1081,7 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
|
||||
}
|
||||
|
||||
Selection sel = lookup_field(p->allocator, type, selector, false);
|
||||
GB_ASSERT(sel.entity != NULL);
|
||||
GB_ASSERT(sel.entity != nullptr);
|
||||
|
||||
ssaValue *a = ssa_build_addr(p, se->expr).addr;
|
||||
a = ssa_emit_deep_field_ptr_index(p, a, sel);
|
||||
@@ -1101,7 +1093,7 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
|
||||
i64 index = i128_to_i64(val.value_integer);
|
||||
|
||||
Selection sel = lookup_field_from_index(p->allocator, type, index);
|
||||
GB_ASSERT(sel.entity != NULL);
|
||||
GB_ASSERT(sel.entity != nullptr);
|
||||
|
||||
ssaValue *a = ssa_build_addr(p, se->expr).addr;
|
||||
a = ssa_emit_deep_field_ptr_index(p, a, sel);
|
||||
@@ -1156,7 +1148,7 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
|
||||
LIT(token_pos.file), token_pos.line, token_pos.column);
|
||||
|
||||
|
||||
return ssa_addr(NULL);
|
||||
return ssa_addr(nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -1382,7 +1374,7 @@ ssaOp ssa_determine_op(TokenKind op, Type *t) {
|
||||
|
||||
|
||||
ssaValue *ssa_emit_comp(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y) {
|
||||
GB_ASSERT(x != NULL && y != NULL);
|
||||
GB_ASSERT(x != nullptr && y != nullptr);
|
||||
Type *a = core_type(x->type);
|
||||
Type *b = core_type(y->type);
|
||||
if (are_types_identical(a, b)) {
|
||||
@@ -1486,7 +1478,7 @@ ssaValue *ssa_emit_unary_arith(ssaProc *p, TokenKind op, ssaValue *x, Type *type
|
||||
GB_PANIC("unknown type for -x");
|
||||
} break;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
ssaValue *ssa_emit_arith(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y, Type *type) {
|
||||
if (is_type_vector(x->type)) {
|
||||
@@ -1537,11 +1529,11 @@ ssaValue *ssa_emit_arith(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y, Typ
|
||||
case Token_Or:
|
||||
case Token_Xor:
|
||||
case Token_AndNot:
|
||||
GB_ASSERT(x != NULL && y != NULL);
|
||||
GB_ASSERT(x != nullptr && y != nullptr);
|
||||
return ssa_new_value2(p, ssa_determine_op(op, x->type), type, x, y);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -1589,7 +1581,7 @@ ssaValue *ssa_emit_logical_binary_expr(ssaProc *p, AstNode *expr) {
|
||||
ssaBlock *rhs = ssa_new_block(p, ssaBlock_Plain, "logical.cmp.rhs");
|
||||
ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "logical.cmp.done");
|
||||
|
||||
GB_ASSERT(p->curr_block != NULL);
|
||||
GB_ASSERT(p->curr_block != nullptr);
|
||||
|
||||
Type *type = default_type(type_of_expr(p->module->info, expr));
|
||||
|
||||
@@ -1648,22 +1640,22 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
|
||||
|
||||
i64 s = 8*type_size_of(p->allocator, t);
|
||||
switch (s) {
|
||||
case 8: return ssa_const_i8 (p, tv.type, i128_to_i64(tv.value.value_integer));
|
||||
case 16: return ssa_const_i16(p, tv.type, i128_to_i64(tv.value.value_integer));
|
||||
case 32: return ssa_const_i32(p, tv.type, i128_to_i64(tv.value.value_integer));
|
||||
case 64: return ssa_const_i64(p, tv.type, i128_to_i64(tv.value.value_integer));
|
||||
case 8: return ssa_const_i8 (p, tv.type, cast (i8)i128_to_i64(tv.value.value_integer));
|
||||
case 16: return ssa_const_i16(p, tv.type, cast(i16)i128_to_i64(tv.value.value_integer));
|
||||
case 32: return ssa_const_i32(p, tv.type, cast(i32)i128_to_i64(tv.value.value_integer));
|
||||
case 64: return ssa_const_i64(p, tv.type, cast(i64)i128_to_i64(tv.value.value_integer));
|
||||
default: GB_PANIC("Unknown integer size");
|
||||
}
|
||||
} else if (is_type_float(t)) {
|
||||
GB_ASSERT(tv.value.kind == ExactValue_Float);
|
||||
i64 s = 8*type_size_of(p->allocator, t);
|
||||
switch (s) {
|
||||
case 32: return ssa_const_f32(p, tv.type, tv.value.value_float);
|
||||
case 64: return ssa_const_f64(p, tv.type, tv.value.value_float);
|
||||
case 32: return ssa_const_f32(p, tv.type, cast(f32)tv.value.value_float);
|
||||
case 64: return ssa_const_f64(p, tv.type, cast(f64)tv.value.value_float);
|
||||
default: GB_PANIC("Unknown float size");
|
||||
}
|
||||
}
|
||||
// IMPORTANT TODO(bill): Do constant record/array literals correctly
|
||||
// IMPORTANT TODO(bill): Do constant str/array literals correctly
|
||||
return ssa_const_nil(p, tv.type);
|
||||
}
|
||||
|
||||
@@ -1689,10 +1681,10 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
|
||||
GB_PANIC("TODO(bill): ssa_build_expr Entity_Builtin `%.*s`\n"
|
||||
"\t at %.*s(%td:%td)", LIT(builtin_procs[e->Builtin.id].name),
|
||||
LIT(token.pos.file), token.pos.line, token.pos.column);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
} else if (e->kind == Entity_Nil) {
|
||||
GB_PANIC("TODO(bill): nil");
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ssaValue **found = map_get(&p->module->values, hash_pointer(e));
|
||||
@@ -1737,7 +1729,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
|
||||
case Token_Shl:
|
||||
case Token_Shr: {
|
||||
GB_PANIC("TODO: shifts");
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
case Token_CmpEq:
|
||||
@@ -1772,29 +1764,29 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
|
||||
case_ast_node(te, TernaryExpr, expr);
|
||||
ssa_emit_comment(p, str_lit("TernaryExpr"));
|
||||
|
||||
ssaValue *yes = NULL;
|
||||
ssaValue *no = NULL;
|
||||
ssaValue *yes = nullptr;
|
||||
ssaValue *no = nullptr;
|
||||
|
||||
GB_ASSERT(te->y != NULL);
|
||||
GB_ASSERT(te->y != nullptr);
|
||||
ssaBlock *then = ssa_new_block(p, ssaBlock_Plain, "if.then");
|
||||
ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "if.done"); // NOTE(bill): Append later
|
||||
ssaBlock *else_ = ssa_new_block(p, ssaBlock_Plain, "if.else");
|
||||
|
||||
ssaBlock *v = NULL;
|
||||
ssaBlock *v = nullptr;
|
||||
|
||||
ssa_build_cond(p, te->cond, then, else_);
|
||||
ssa_start_block(p, then);
|
||||
|
||||
// ssa_open_scope(p);
|
||||
yes = ssa_build_expr(p, te->x);
|
||||
// ssa_close_scope(p, ssaDeferExit_Default, NULL);
|
||||
// ssa_close_scope(p, ssaDeferExit_Default, nullptr);
|
||||
|
||||
ssa_emit_jump(p, done);
|
||||
ssa_start_block(p, else_);
|
||||
|
||||
// ssa_open_scope(p);
|
||||
no = ssa_build_expr(p, te->y);
|
||||
// ssa_close_scope(p, ssaDeferExit_Default, NULL);
|
||||
// ssa_close_scope(p, ssaDeferExit_Default, nullptr);
|
||||
|
||||
ssa_emit_jump(p, done);
|
||||
ssa_start_block(p, done);
|
||||
@@ -1815,7 +1807,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
|
||||
|
||||
Type *type = type_of_expr(proc->module->info, expr);
|
||||
irValue *value = ir_value_procedure(proc->module->allocator,
|
||||
proc->module, NULL, type, pl->type, pl->body, name);
|
||||
proc->module, nullptr, type, pl->type, pl->body, name);
|
||||
|
||||
value->Proc.tags = pl->tags;
|
||||
value->Proc.parent = proc;
|
||||
@@ -1854,7 +1846,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
|
||||
|
||||
GB_PANIC("Unexpected expression: %.*s", LIT(ast_node_strings[expr->kind]));
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -1927,7 +1919,7 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) {
|
||||
p->module->stmt_state_flags = prev_stmt_state_flags;
|
||||
}
|
||||
void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
if (p->curr_block == NULL) {
|
||||
if (p->curr_block == nullptr) {
|
||||
ssaBlock *dead_block = ssa_new_block(p, ssaBlock_Plain, "");
|
||||
ssa_start_block(p, dead_block);
|
||||
}
|
||||
@@ -1939,7 +1931,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
case_ast_node(bs, BlockStmt, node);
|
||||
ssa_open_scope(p);
|
||||
ssa_build_stmt_list(p, bs->stmts);
|
||||
ssa_close_scope(p, ssaDeferExit_Default, NULL);
|
||||
ssa_close_scope(p, ssaDeferExit_Default, nullptr);
|
||||
case_end;
|
||||
|
||||
case_ast_node(us, UsingStmt, node);
|
||||
@@ -1955,6 +1947,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
ssa_build_when_stmt(p, ws);
|
||||
case_end;
|
||||
|
||||
#if 0
|
||||
case_ast_node(s, IncDecStmt, node);
|
||||
TokenKind op = Token_Add;
|
||||
if (s->op.kind == Token_Dec) {
|
||||
@@ -1964,6 +1957,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
Type *t = ssa_addr_type(addr);
|
||||
ssa_build_assign_op(p, addr, ssa_const_int(p, t, 1), op);
|
||||
case_end;
|
||||
#endif
|
||||
|
||||
case_ast_node(as, AssignStmt, node);
|
||||
ssa_emit_comment(p, str_lit("AssignStmt"));
|
||||
@@ -2012,7 +2006,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
Type *t = base_type(init->type);
|
||||
// TODO(bill): refactor for code reuse as this is repeated a bit
|
||||
if (t->kind == Type_Tuple) {
|
||||
for (isize i = 0; i < t->Tuple.variable_count; i++) {
|
||||
for_array(i, t->Tuple.variables) {
|
||||
Entity *e = t->Tuple.variables[i];
|
||||
ssaValue *v = ssa_emit_value_index(p, init, i);
|
||||
array_add(&inits, v);
|
||||
@@ -2064,7 +2058,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
|
||||
case_ast_node(is, IfStmt, node);
|
||||
ssa_emit_comment(p, str_lit("IfStmt"));
|
||||
if (is->init != NULL) {
|
||||
if (is->init != nullptr) {
|
||||
ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "if.init");
|
||||
ssa_emit_jump(p, init);
|
||||
ssa_start_block(p, init);
|
||||
@@ -2073,26 +2067,26 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
ssaBlock *then = ssa_new_block(p, ssaBlock_Plain, "if.then");
|
||||
ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "if.done");
|
||||
ssaBlock *else_ = done;
|
||||
if (is->else_stmt != NULL) {
|
||||
if (is->else_stmt != nullptr) {
|
||||
else_ = ssa_new_block(p, ssaBlock_Plain, "if.else");
|
||||
}
|
||||
ssaBlock *b = NULL;
|
||||
ssaBlock *b = nullptr;
|
||||
|
||||
ssa_build_cond(p, is->cond, then, else_);
|
||||
ssa_start_block(p, then);
|
||||
|
||||
ssa_open_scope(p);
|
||||
ssa_build_stmt(p, is->body);
|
||||
ssa_close_scope(p, ssaDeferExit_Default, NULL);
|
||||
ssa_close_scope(p, ssaDeferExit_Default, nullptr);
|
||||
|
||||
ssa_emit_jump(p, done);
|
||||
|
||||
if (is->else_stmt != NULL) {
|
||||
if (is->else_stmt != nullptr) {
|
||||
ssa_start_block(p, else_);
|
||||
|
||||
ssa_open_scope(p);
|
||||
ssa_build_stmt(p, is->else_stmt);
|
||||
ssa_close_scope(p, ssaDeferExit_Default, NULL);
|
||||
ssa_close_scope(p, ssaDeferExit_Default, nullptr);
|
||||
|
||||
ssa_emit_jump(p, done);
|
||||
}
|
||||
@@ -2103,7 +2097,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
|
||||
case_ast_node(fs, ForStmt, node);
|
||||
ssa_emit_comment(p, str_lit("ForStmt"));
|
||||
if (fs->init != NULL) {
|
||||
if (fs->init != nullptr) {
|
||||
ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "for.init");
|
||||
ssa_emit_jump(p, init);
|
||||
ssa_start_block(p, init);
|
||||
@@ -2113,11 +2107,11 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
ssaBlock *body = ssa_new_block(p, ssaBlock_Plain, "for.body");
|
||||
ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "for.done");
|
||||
ssaBlock *loop = body;
|
||||
if (fs->cond != NULL) {
|
||||
if (fs->cond != nullptr) {
|
||||
loop = ssa_new_block(p, ssaBlock_Plain, "for.loop");
|
||||
}
|
||||
ssaBlock *post = loop;
|
||||
if (fs->post != NULL) {
|
||||
if (fs->post != nullptr) {
|
||||
post = ssa_new_block(p, ssaBlock_Plain, "for.post");
|
||||
}
|
||||
|
||||
@@ -2129,15 +2123,15 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
ssa_start_block(p, body);
|
||||
}
|
||||
|
||||
ssa_push_target_list(p, done, post, NULL);
|
||||
ssa_push_target_list(p, done, post, nullptr);
|
||||
ssa_open_scope(p);
|
||||
ssa_build_stmt(p, fs->body);
|
||||
ssa_close_scope(p, ssaDeferExit_Default, NULL);
|
||||
ssa_close_scope(p, ssaDeferExit_Default, nullptr);
|
||||
ssa_pop_target_list(p);
|
||||
|
||||
ssa_emit_jump(p, post);
|
||||
|
||||
if (fs->post != NULL) {
|
||||
if (fs->post != nullptr) {
|
||||
ssa_start_block(p, post);
|
||||
ssa_build_stmt(p, fs->post);
|
||||
ssa_emit_jump(p, post);
|
||||
@@ -2159,25 +2153,25 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(bs, BranchStmt, node);
|
||||
ssaBlock *b = NULL;
|
||||
ssaBlock *b = nullptr;
|
||||
switch (bs->token.kind) {
|
||||
case Token_break:
|
||||
for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) {
|
||||
for (ssaTargetList *t = p->target_list; t != nullptr && b == nullptr; t = t->prev) {
|
||||
b = t->break_;
|
||||
}
|
||||
break;
|
||||
case Token_continue:
|
||||
for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) {
|
||||
for (ssaTargetList *t = p->target_list; t != nullptr && b == nullptr; t = t->prev) {
|
||||
b = t->continue_;
|
||||
}
|
||||
break;
|
||||
case Token_fallthrough:
|
||||
for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) {
|
||||
for (ssaTargetList *t = p->target_list; t != nullptr && b == nullptr; t = t->prev) {
|
||||
b = t->fallthrough_;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (b != NULL) {
|
||||
if (b != nullptr) {
|
||||
ssa_emit_defer_stmts(p, ssaDeferExit_Branch, b);
|
||||
}
|
||||
switch (bs->token.kind) {
|
||||
@@ -2198,7 +2192,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
}
|
||||
|
||||
void ssa_print_value(gbFile *f, ssaValue *v) {
|
||||
if (v == NULL) {
|
||||
if (v == nullptr) {
|
||||
gb_fprintf(f, "nil");
|
||||
}
|
||||
gb_fprintf(f, "v%d", v->id);
|
||||
@@ -2249,7 +2243,7 @@ void ssa_print_reg_value(gbFile *f, ssaValue *v) {
|
||||
gb_fprintf(f, " ");
|
||||
gb_fprintf(f, "v%d = %.*s", v->id, LIT(ssa_op_strings[v->op]));
|
||||
|
||||
if (v->type != NULL) {
|
||||
if (v->type != nullptr) {
|
||||
gbString type_str = type_to_string(default_type(v->type));
|
||||
gb_fprintf(f, " %s", type_str);
|
||||
gb_string_free(type_str);
|
||||
@@ -2313,7 +2307,7 @@ void ssa_print_proc(gbFile *f, ssaProc *p) {
|
||||
bool skip = false;
|
||||
for_array(k, v->args) {
|
||||
ssaValue *w = v->args[k];
|
||||
if (w != NULL && w->block == b && !printed[w->id]) {
|
||||
if (w != nullptr && w->block == b && !printed[w->id]) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
@@ -2377,13 +2371,13 @@ void ssa_build_proc(ssaModule *m, ssaProc *p) {
|
||||
p->module = m;
|
||||
m->proc = p;
|
||||
|
||||
if (p->decl_info->proc_decl == NULL ||
|
||||
p->decl_info->proc_decl->kind != AstNode_ProcDecl) {
|
||||
if (p->decl_info->proc_lit == nullptr ||
|
||||
p->decl_info->proc_lit->kind != AstNode_ProcLit) {
|
||||
return;
|
||||
}
|
||||
|
||||
ast_node(pl, ProcLit, p->decl_info->proc_decl);
|
||||
if (pl->body == NULL) {
|
||||
ast_node(pl, ProcLit, p->decl_info->proc_lit);
|
||||
if (pl->body == nullptr) {
|
||||
return;
|
||||
}
|
||||
p->entry = ssa_new_block(p, ssaBlock_Entry, "entry");
|
||||
@@ -2392,7 +2386,7 @@ void ssa_build_proc(ssaModule *m, ssaProc *p) {
|
||||
ssa_build_stmt(p, pl->body);
|
||||
|
||||
if (p->entity->type->Proc.result_count == 0) {
|
||||
ssa_emit_defer_stmts(p, ssaDeferExit_Return, NULL);
|
||||
ssa_emit_defer_stmts(p, ssaDeferExit_Return, nullptr);
|
||||
}
|
||||
|
||||
p->exit = ssa_new_block(p, ssaBlock_Exit, "exit");
|
||||
@@ -2429,7 +2423,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
||||
}
|
||||
|
||||
isize global_variable_max_count = 0;
|
||||
Entity *entry_point = NULL;
|
||||
Entity *entry_point = nullptr;
|
||||
bool has_dll_main = false;
|
||||
bool has_win_main = false;
|
||||
|
||||
@@ -2470,7 +2464,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (map_get(&m.min_dep_map, hash_pointer(e)) == NULL) {
|
||||
if (map_get(&m.min_dep_map, hash_pointer(e)) == nullptr) {
|
||||
// NOTE(bill): Nothing depends upon it so doesn't need to be built
|
||||
continue;
|
||||
}
|
||||
@@ -2495,14 +2489,14 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
||||
} break;
|
||||
|
||||
case Entity_Procedure: {
|
||||
ast_node(pd, ProcDecl, decl->proc_decl);
|
||||
ast_node(pl, ProcLit, decl->proc_lit);
|
||||
String original_name = name;
|
||||
AstNode *body = pd->body;
|
||||
AstNode *body = pl->body;
|
||||
if (e->Procedure.is_foreign) {
|
||||
name = e->token.string; // NOTE(bill): Don't use the mangled name
|
||||
}
|
||||
if (pd->link_name.len > 0) {
|
||||
name = pd->link_name;
|
||||
if (pl->link_name.len > 0) {
|
||||
name = pl->link_name;
|
||||
}
|
||||
|
||||
if (e == entry_point) {
|
||||
@@ -2511,11 +2505,11 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
||||
}
|
||||
|
||||
// ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
|
||||
// p->Proc.tags = pd->tags;
|
||||
// p->Proc.tags = pl->tags;
|
||||
|
||||
// ssa_module_add_value(m, e, p);
|
||||
// HashKey hash_name = hash_string(name);
|
||||
// if (map_get(&m.members, hash_name) == NULL) {
|
||||
// if (map_get(&m.members, hash_name) == nullptr) {
|
||||
// map_set(&m.members, hash_name, p);
|
||||
// }
|
||||
} break;
|
||||
@@ -2562,7 +2556,7 @@ String ssa_mangle_name(ssaModule *m, String path, Entity *e) {
|
||||
cast(char *)new_name, max_len,
|
||||
"%.*s-%u.%.*s",
|
||||
cast(int)base_len, base,
|
||||
file->id,
|
||||
cast(u32)file->id,
|
||||
LIT(name));
|
||||
if (is_overloaded) {
|
||||
char *str = cast(char *)new_name + new_name_len-1;
|
||||
|
||||
+44
-36
@@ -1,10 +1,12 @@
|
||||
gb_global gbArena string_buffer_arena = {};
|
||||
gb_global gbArena string_buffer_arena = {};
|
||||
gb_global gbAllocator string_buffer_allocator = {};
|
||||
gb_global gbMutex string_buffer_mutex = {};
|
||||
|
||||
void init_string_buffer_memory(void) {
|
||||
// NOTE(bill): This should be enough memory for file systems
|
||||
gb_arena_init_from_allocator(&string_buffer_arena, heap_allocator(), gb_megabytes(1));
|
||||
string_buffer_allocator = gb_arena_allocator(&string_buffer_arena);
|
||||
gb_mutex_init(&string_buffer_mutex);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +67,7 @@ gb_inline String16 make_string16(wchar_t *text, isize len) {
|
||||
}
|
||||
|
||||
isize string16_len(wchar_t *s) {
|
||||
if (s == NULL) {
|
||||
if (s == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
wchar_t *p = s;
|
||||
@@ -104,9 +106,8 @@ gb_inline bool str_eq_ignore_case(String a, String b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int string_compare(String x, String y) {
|
||||
if (!(x.len == y.len &&
|
||||
x.text == y.text)) {
|
||||
int string_compare(String const &x, String const &y) {
|
||||
if (x.len != y.len || x.text != y.text) {
|
||||
isize n, fast, offset, curr_block;
|
||||
isize *la, *lb;
|
||||
isize pos;
|
||||
@@ -148,26 +149,34 @@ GB_COMPARE_PROC(string_cmp_proc) {
|
||||
return string_compare(x, y);
|
||||
}
|
||||
|
||||
gb_inline bool str_eq(String a, String b) { return a.len == b.len ? gb_memcompare(a.text, b.text, a.len) == 0 : false; }
|
||||
gb_inline bool str_ne(String a, String b) { return !str_eq(a, b); }
|
||||
gb_inline bool str_lt(String a, String b) { return string_compare(a, b) < 0; }
|
||||
gb_inline bool str_gt(String a, String b) { return string_compare(a, b) > 0; }
|
||||
gb_inline bool str_le(String a, String b) { return string_compare(a, b) <= 0; }
|
||||
gb_inline bool str_ge(String a, String b) { return string_compare(a, b) >= 0; }
|
||||
gb_inline bool str_eq(String const &a, String const &b) {
|
||||
if (a.len != b.len) return false;
|
||||
for (isize i = 0; i < a.len; i++) {
|
||||
if (a.text[i] != b.text[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
gb_inline bool str_ne(String const &a, String const &b) { return !str_eq(a, b); }
|
||||
gb_inline bool str_lt(String const &a, String const &b) { return string_compare(a, b) < 0; }
|
||||
gb_inline bool str_gt(String const &a, String const &b) { return string_compare(a, b) > 0; }
|
||||
gb_inline bool str_le(String const &a, String const &b) { return string_compare(a, b) <= 0; }
|
||||
gb_inline bool str_ge(String const &a, String const &b) { return string_compare(a, b) >= 0; }
|
||||
|
||||
bool operator == (String a, String b) { return str_eq(a, b); }
|
||||
bool operator != (String a, String b) { return str_ne(a, b); }
|
||||
bool operator < (String a, String b) { return str_lt(a, b); }
|
||||
bool operator > (String a, String b) { return str_gt(a, b); }
|
||||
bool operator <= (String a, String b) { return str_le(a, b); }
|
||||
bool operator >= (String a, String b) { return str_ge(a, b); }
|
||||
gb_inline bool operator == (String const &a, String const &b) { return str_eq(a, b); }
|
||||
gb_inline bool operator != (String const &a, String const &b) { return str_ne(a, b); }
|
||||
gb_inline bool operator < (String const &a, String const &b) { return str_lt(a, b); }
|
||||
gb_inline bool operator > (String const &a, String const &b) { return str_gt(a, b); }
|
||||
gb_inline bool operator <= (String const &a, String const &b) { return str_le(a, b); }
|
||||
gb_inline bool operator >= (String const &a, String const &b) { return str_ge(a, b); }
|
||||
|
||||
template <isize N> bool operator == (String a, char const (&b)[N]) { return str_eq(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator != (String a, char const (&b)[N]) { return str_ne(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator < (String a, char const (&b)[N]) { return str_lt(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator > (String a, char const (&b)[N]) { return str_gt(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator <= (String a, char const (&b)[N]) { return str_le(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator >= (String a, char const (&b)[N]) { return str_ge(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator == (String const &a, char const (&b)[N]) { return str_eq(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator != (String const &a, char const (&b)[N]) { return str_ne(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator < (String const &a, char const (&b)[N]) { return str_lt(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator > (String const &a, char const (&b)[N]) { return str_gt(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator <= (String const &a, char const (&b)[N]) { return str_le(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator >= (String const &a, char const (&b)[N]) { return str_ge(a, make_string(cast(u8 *)b, N-1)); }
|
||||
|
||||
|
||||
|
||||
@@ -187,7 +196,6 @@ gb_inline bool str_has_prefix(String s, String prefix) {
|
||||
gb_inline isize string_extension_position(String str) {
|
||||
isize dot_pos = -1;
|
||||
isize i = str.len;
|
||||
bool seen_dot = false;
|
||||
while (i --> 0) {
|
||||
if (str[i] == GB_PATH_SEPARATOR)
|
||||
break;
|
||||
@@ -256,7 +264,7 @@ String filename_from_path(String s) {
|
||||
s.text += j+1;
|
||||
s.len = i-j-1;
|
||||
}
|
||||
return make_string(NULL, 0);
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -271,7 +279,7 @@ String filename_from_path(String s) {
|
||||
return MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, multibyte_input, input_length, output, output_size);
|
||||
}
|
||||
int convert_widechar_to_multibyte(wchar_t *widechar_input, int input_length, char *output, int output_size) {
|
||||
return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, NULL, NULL);
|
||||
return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, nullptr, nullptr);
|
||||
}
|
||||
#elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX)
|
||||
|
||||
@@ -305,20 +313,20 @@ String16 string_to_string16(gbAllocator a, String s) {
|
||||
wchar_t *text;
|
||||
|
||||
if (s.len < 1) {
|
||||
return make_string16(NULL, 0);
|
||||
return make_string16(nullptr, 0);
|
||||
}
|
||||
|
||||
len = convert_multibyte_to_widechar(cast(char *)s.text, s.len, NULL, 0);
|
||||
len = convert_multibyte_to_widechar(cast(char *)s.text, cast(int)s.len, nullptr, 0);
|
||||
if (len == 0) {
|
||||
return make_string16(NULL, 0);
|
||||
return make_string16(nullptr, 0);
|
||||
}
|
||||
|
||||
text = gb_alloc_array(a, wchar_t, len+1);
|
||||
|
||||
len1 = convert_multibyte_to_widechar(cast(char *)s.text, s.len, text, len);
|
||||
len1 = convert_multibyte_to_widechar(cast(char *)s.text, cast(int)s.len, text, cast(int)len);
|
||||
if (len1 == 0) {
|
||||
gb_free(a, text);
|
||||
return make_string16(NULL, 0);
|
||||
return make_string16(nullptr, 0);
|
||||
}
|
||||
text[len] = 0;
|
||||
|
||||
@@ -331,21 +339,21 @@ String string16_to_string(gbAllocator a, String16 s) {
|
||||
u8 *text;
|
||||
|
||||
if (s.len < 1) {
|
||||
return make_string(NULL, 0);
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
|
||||
len = convert_widechar_to_multibyte(s.text, s.len, NULL, 0);
|
||||
len = convert_widechar_to_multibyte(s.text, cast(int)s.len, nullptr, 0);
|
||||
if (len == 0) {
|
||||
return make_string(NULL, 0);
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
len += 1; // NOTE(bill): It needs an extra 1 for some reason
|
||||
|
||||
text = gb_alloc_array(a, u8, len+1);
|
||||
|
||||
len1 = convert_widechar_to_multibyte(s.text, s.len, cast(char *)text, len);
|
||||
len1 = convert_widechar_to_multibyte(s.text, cast(int)s.len, cast(char *)text, cast(int)len);
|
||||
if (len1 == 0) {
|
||||
gb_free(a, text);
|
||||
return make_string(NULL, 0);
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
text[len] = 0;
|
||||
|
||||
|
||||
+17
-6
@@ -8,6 +8,7 @@ struct Timings {
|
||||
TimeStamp total;
|
||||
Array<TimeStamp> sections;
|
||||
u64 freq;
|
||||
f64 total_time_seconds;
|
||||
};
|
||||
|
||||
|
||||
@@ -103,9 +104,13 @@ void timings_start_section(Timings *t, String label) {
|
||||
array_add(&t->sections, make_time_stamp(label));
|
||||
}
|
||||
|
||||
f64 time_stamp_as_ms(TimeStamp ts, u64 freq) {
|
||||
f64 time_stamp_as_second(TimeStamp ts, u64 freq) {
|
||||
GB_ASSERT_MSG(ts.finish >= ts.start, "time_stamp_as_ms - %.*s", LIT(ts.label));
|
||||
return 1000.0 * cast(f64)(ts.finish - ts.start) / cast(f64)freq;
|
||||
return cast(f64)(ts.finish - ts.start) / cast(f64)freq;
|
||||
}
|
||||
|
||||
f64 time_stamp_as_ms(TimeStamp ts, u64 freq) {
|
||||
return 1000.0*time_stamp_as_second(ts, freq);
|
||||
}
|
||||
|
||||
void timings_print_all(Timings *t) {
|
||||
@@ -123,16 +128,22 @@ void timings_print_all(Timings *t) {
|
||||
|
||||
GB_ASSERT(max_len <= gb_size_of(SPACES)-1);
|
||||
|
||||
gb_printf("%.*s%.*s - %.3f ms\n",
|
||||
t->total_time_seconds = time_stamp_as_second(t->total, t->freq);
|
||||
|
||||
f64 total_ms = time_stamp_as_ms(t->total, t->freq);
|
||||
|
||||
gb_printf("%.*s%.*s - % 9.3f ms - %6.2f%%\n",
|
||||
LIT(t->total.label),
|
||||
cast(int)(max_len-t->total.label.len), SPACES,
|
||||
time_stamp_as_ms(t->total, t->freq));
|
||||
total_ms,
|
||||
cast(f64)100.0);
|
||||
|
||||
for_array(i, t->sections) {
|
||||
TimeStamp ts = t->sections[i];
|
||||
gb_printf("%.*s%.*s - %.3f ms\n",
|
||||
f64 section_ms = time_stamp_as_ms(ts, t->freq);
|
||||
gb_printf("%.*s%.*s - % 9.3f ms - %6.2f%%\n",
|
||||
LIT(ts.label),
|
||||
cast(int)(max_len-ts.label.len), SPACES,
|
||||
time_stamp_as_ms(ts, t->freq));
|
||||
section_ms, 100*section_ms/total_ms);
|
||||
}
|
||||
}
|
||||
|
||||
+53
-37
@@ -37,26 +37,27 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
|
||||
TOKEN_KIND(Token_CmpOr, "||"), \
|
||||
\
|
||||
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
|
||||
TOKEN_KIND(Token_AddEq, "+="), \
|
||||
TOKEN_KIND(Token_SubEq, "-="), \
|
||||
TOKEN_KIND(Token_MulEq, "*="), \
|
||||
TOKEN_KIND(Token_QuoEq, "/="), \
|
||||
TOKEN_KIND(Token_ModEq, "%="), \
|
||||
TOKEN_KIND(Token_ModModEq, "%%="), \
|
||||
TOKEN_KIND(Token_AndEq, "&="), \
|
||||
TOKEN_KIND(Token_OrEq, "|="), \
|
||||
TOKEN_KIND(Token_XorEq, "~="), \
|
||||
TOKEN_KIND(Token_AndNotEq, "&~="), \
|
||||
TOKEN_KIND(Token_ShlEq, "<<="), \
|
||||
TOKEN_KIND(Token_ShrEq, ">>="), \
|
||||
TOKEN_KIND(Token_CmpAndEq, "&&="), \
|
||||
TOKEN_KIND(Token_CmpOrEq, "||="), \
|
||||
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
||||
TOKEN_KIND(Token_ArrowRight, "->"), \
|
||||
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
||||
TOKEN_KIND(Token_Inc, "++"), \
|
||||
TOKEN_KIND(Token_Dec, "--"), \
|
||||
TOKEN_KIND(Token_Undef, "---"), \
|
||||
TOKEN_KIND(Token_AddEq, "+="), \
|
||||
TOKEN_KIND(Token_SubEq, "-="), \
|
||||
TOKEN_KIND(Token_MulEq, "*="), \
|
||||
TOKEN_KIND(Token_QuoEq, "/="), \
|
||||
TOKEN_KIND(Token_ModEq, "%="), \
|
||||
TOKEN_KIND(Token_ModModEq, "%%="), \
|
||||
TOKEN_KIND(Token_AndEq, "&="), \
|
||||
TOKEN_KIND(Token_OrEq, "|="), \
|
||||
TOKEN_KIND(Token_XorEq, "~="), \
|
||||
TOKEN_KIND(Token_AndNotEq, "&~="), \
|
||||
TOKEN_KIND(Token_ShlEq, "<<="), \
|
||||
TOKEN_KIND(Token_ShrEq, ">>="), \
|
||||
TOKEN_KIND(Token_CmpAndEq, "&&="), \
|
||||
TOKEN_KIND(Token_CmpOrEq, "||="), \
|
||||
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
||||
TOKEN_KIND(Token_ArrowRight, "->"), \
|
||||
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
||||
TOKEN_KIND(Token_DoubleArrowRight, "=>"), \
|
||||
/* TOKEN_KIND(Token_Inc, "++"), */ \
|
||||
/* TOKEN_KIND(Token_Dec, "--"), */ \
|
||||
TOKEN_KIND(Token_Undef, "---"), \
|
||||
\
|
||||
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
|
||||
TOKEN_KIND(Token_CmpEq, "=="), \
|
||||
@@ -77,26 +78,25 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
|
||||
TOKEN_KIND(Token_Semicolon, ";"), \
|
||||
TOKEN_KIND(Token_Period, "."), \
|
||||
TOKEN_KIND(Token_Comma, ","), \
|
||||
TOKEN_KIND(Token_Ellipsis, ".."), \
|
||||
TOKEN_KIND(Token_HalfClosed, "..<"), \
|
||||
TOKEN_KIND(Token_Ellipsis, "..."), \
|
||||
TOKEN_KIND(Token_HalfClosed, ".."), \
|
||||
TOKEN_KIND(Token_BackSlash, "\\"), \
|
||||
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
|
||||
\
|
||||
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
TOKEN_KIND(Token_var, "var"), \
|
||||
TOKEN_KIND(Token_const, "const"), \
|
||||
TOKEN_KIND(Token_type, "type"), \
|
||||
TOKEN_KIND(Token_import, "import"), \
|
||||
TOKEN_KIND(Token_import_load, "import_load"), \
|
||||
TOKEN_KIND(Token_foreign, "foreign"), \
|
||||
TOKEN_KIND(Token_foreign_library, "foreign_library"), \
|
||||
TOKEN_KIND(Token_foreign_system_library, "foreign_system_library"), \
|
||||
TOKEN_KIND(Token_type, "type"), \
|
||||
TOKEN_KIND(Token_when, "when"), \
|
||||
TOKEN_KIND(Token_if, "if"), \
|
||||
TOKEN_KIND(Token_else, "else"), \
|
||||
TOKEN_KIND(Token_for, "for"), \
|
||||
TOKEN_KIND(Token_in, "in"), \
|
||||
TOKEN_KIND(Token_match, "match"), \
|
||||
TOKEN_KIND(Token_in, "in"), \
|
||||
TOKEN_KIND(Token_do, "do"), \
|
||||
TOKEN_KIND(Token_case, "case"), \
|
||||
TOKEN_KIND(Token_break, "break"), \
|
||||
TOKEN_KIND(Token_continue, "continue"), \
|
||||
@@ -107,21 +107,26 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
TOKEN_KIND(Token_macro, "macro"), \
|
||||
TOKEN_KIND(Token_struct, "struct"), \
|
||||
TOKEN_KIND(Token_union, "union"), \
|
||||
TOKEN_KIND(Token_raw_union, "raw_union"), \
|
||||
TOKEN_KIND(Token_enum, "enum"), \
|
||||
TOKEN_KIND(Token_bit_field, "bit_field"), \
|
||||
TOKEN_KIND(Token_vector, "vector"), \
|
||||
TOKEN_KIND(Token_map, "map"), \
|
||||
TOKEN_KIND(Token_static, "static"), \
|
||||
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
||||
TOKEN_KIND(Token_map, "map"), \
|
||||
TOKEN_KIND(Token_cast, "cast"), \
|
||||
TOKEN_KIND(Token_transmute, "transmute"), \
|
||||
TOKEN_KIND(Token_using, "using"), \
|
||||
TOKEN_KIND(Token_context, "context"), \
|
||||
TOKEN_KIND(Token_push_context, "push_context"), \
|
||||
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
|
||||
TOKEN_KIND(Token_size_of, "size_of"), \
|
||||
TOKEN_KIND(Token_align_of, "align_of"), \
|
||||
TOKEN_KIND(Token_offset_of, "offset_of"), \
|
||||
TOKEN_KIND(Token_type_of, "type_of"), \
|
||||
TOKEN_KIND(Token_type_info_of, "type_info_of"), \
|
||||
TOKEN_KIND(Token_asm, "asm"), \
|
||||
TOKEN_KIND(Token_yield, "yield"), \
|
||||
TOKEN_KIND(Token_await, "await"), \
|
||||
TOKEN_KIND(Token_atomic, "atomic"), \
|
||||
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
|
||||
TOKEN_KIND(Token_Count, "")
|
||||
|
||||
@@ -429,7 +434,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
|
||||
// TODO(bill): Memory map rather than copy contents
|
||||
gbFileContents fc = gb_file_read_contents(heap_allocator(), true, c_str);
|
||||
gb_zero_item(t);
|
||||
if (fc.data != NULL) {
|
||||
if (fc.data != nullptr) {
|
||||
t->start = cast(u8 *)fc.data;
|
||||
t->line = t->read_curr = t->curr = t->start;
|
||||
t->end = t->start + fc.size;
|
||||
@@ -464,7 +469,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
|
||||
}
|
||||
|
||||
gb_inline void destroy_tokenizer(Tokenizer *t) {
|
||||
if (t->start != NULL) {
|
||||
if (t->start != nullptr) {
|
||||
gb_free(heap_allocator(), t->start);
|
||||
}
|
||||
for_array(i, t->allocated_strings) {
|
||||
@@ -881,10 +886,10 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
token.kind = Token_Period; // Default
|
||||
if (t->curr_rune == '.') { // Could be an ellipsis
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_Ellipsis;
|
||||
if (t->curr_rune == '<') {
|
||||
token.kind = Token_HalfClosed;
|
||||
if (t->curr_rune == '.') {
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_HalfClosed;
|
||||
token.kind = Token_Ellipsis;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -912,10 +917,20 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
case '%': token.kind = token_kind_dub_eq(t, '%', Token_Mod, Token_ModEq, Token_ModMod, Token_ModModEq); break;
|
||||
|
||||
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
|
||||
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break;
|
||||
case '=':
|
||||
token.kind = Token_Eq;
|
||||
if (t->curr_rune == '>') {
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_DoubleArrowRight;
|
||||
} else if (t->curr_rune == '=') {
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_CmpEq;
|
||||
}
|
||||
break;
|
||||
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
|
||||
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
|
||||
case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
|
||||
// case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
|
||||
case '+': token.kind = token_kind_variant2(t, Token_Add, Token_AddEq); break;
|
||||
case '-':
|
||||
token.kind = Token_Sub;
|
||||
if (t->curr_rune == '=') {
|
||||
@@ -923,7 +938,7 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
token.kind = Token_SubEq;
|
||||
} else if (t->curr_rune == '-') {
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_Dec;
|
||||
token.kind = Token_Invalid;
|
||||
if (t->curr_rune == '-') {
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_Undef;
|
||||
@@ -970,6 +985,7 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
|
||||
case '<':
|
||||
if (t->curr_rune == '-') {
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_ArrowLeft;
|
||||
} else {
|
||||
token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
|
||||
|
||||
+601
-658
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user