Compare commits

..

97 Commits

Author SHA1 Message Date
Ginger Bill 49d337c830 v0.6.2; Use Ada_Case for types 2017-08-03 21:21:56 +01:00
Ginger Bill 294092979e Update build.bat 2017-08-01 21:38:06 +01:00
Ginger Bill c454ede184 v0.6.1a 2017-08-01 17:30:26 +01:00
Ginger Bill d854c5003c Fix minor errors for *nix 2017-08-01 17:28:49 +01:00
Ginger Bill 66d8776b83 v0.6.1 2017-08-01 15:18:37 +01:00
Ginger Bill ba6ecf35cf Disable threading on *nix for the time being 2017-08-01 15:09:43 +01:00
Ginger Bill 10cc9cf661 Add mutexes to string buffer allocator uses 2017-08-01 14:24:40 +01:00
Ginger Bill 2db971eedd Use pthread mutex 2017-08-01 13:49:12 +01:00
Ginger Bill 1775e80b41 HACK: Ignore Mutex check 2017-07-31 23:18:21 +01:00
Ginger Bill e4a93619db Update gb.h 2017-07-31 12:17:53 +01:00
Ginger Bill 4d14b3bcb4 Update remove_temp_files 2017-07-31 12:15:20 +01:00
Ginger Bill 9f4f5f9346 Add -keep-temp-files option 2017-07-31 12:06:04 +01:00
Ginger Bill 0fae31fb54 Extra type safety; Fix typos 2017-07-31 11:36:00 +01:00
Ginger Bill 8987a6630c v0.6.0 2017-07-30 22:26:22 +01:00
Ginger Bill 10ff8e0426 Fix ir for TypeInfo.Map 2017-07-30 20:17:25 +01:00
Ginger Bill a0ae02168a Update add_type_info_type to ignore polymorphic types 2017-07-30 20:13:23 +01:00
Ginger Bill a3c1ac2030 Speed up llvm ir printing; Use CRITICAL_SECTION for Mutex on windows 2017-07-30 19:47:37 +01:00
Ginger Bill 629b248f53 Parallelization of the Parser
~66% reduction (unoptimized build)
~30% reduction (optimized build)
2017-07-30 19:01:02 +01:00
Ginger Bill 62a72f0163 transmute(type)x; Minor code clean up 2017-07-30 14:52:42 +01:00
Ginger Bill 655931f0ea Minor Simplification of threading demo 2017-07-29 15:18:36 +01:00
Ginger Bill ca36fabfc0 Remove dead code for the "fixed" map idea 2017-07-29 14:43:42 +01:00
Ginger Bill 7bd62481ad Fix nil assignment to unions 2017-07-29 14:23:34 +01:00
Ginger Bill fbd27d7c45 Fix map internal type generation 2017-07-29 13:56:45 +01:00
Ginger Bill 3546391311 Merge branch 'master' of https://github.com/gingerBill/Odin 2017-07-29 13:01:28 +01:00
Ginger Bill 24c812115e Remove empty union check on array types; Fix overflowing error printing 2017-07-29 13:01:17 +01:00
gingerBill 28be0ad69b Fix IR print bug for empty structs; 2017-07-28 11:35:01 +01:00
gingerBill f0980c0a98 Fix import name exportation bug; Fix procedure type printing 2017-07-24 07:57:09 +01:00
Ginger Bill 1df4aa90ce Fix struct parameter bugs 2017-07-21 15:25:58 +01:00
Ginger Bill 6b3cf051f8 Fix math.odin, again 2017-07-21 12:39:05 +01:00
Ginger Bill 4ecd6e592b Fix missing semicolons in math.odin 2017-07-21 10:37:49 +01:00
Ginger Bill dbddec33c8 Internal changes; thread.odin for windows only 2017-07-20 23:57:56 +01:00
Ginger Bill 401a5955a4 Fix minor check on vector types 2017-07-20 19:55:54 +01:00
Ginger Bill 9a3b4167bb Fix polymorphic element types usage; Empty union as opaque type 2017-07-20 19:40:51 +01:00
Ginger Bill 13bc6eeea4 Make fields et al an Array rather than a raw pointer 2017-07-20 15:32:34 +01:00
Ginger Bill 2da18b6d33 Change internals from Record to Struct 2017-07-20 15:23:13 +01:00
Ginger Bill 6d37ed12d2 Update internals of a Union and Tuple 2017-07-20 15:17:04 +01:00
Ginger Bill eab23cd5b7 Fix parsing bug with procedure types in return values 2017-07-19 22:34:50 +01:00
Ginger Bill d233706a2d Fix minor parsing bug with procedure return types 2017-07-19 22:17:57 +01:00
Ginger Bill f1ab17ed4e type_info_of; enum_value_to_string and string_to_enum_value 2017-07-19 14:01:56 +01:00
Ginger Bill 6113164211 Change union layout to store type info rather than an integer; ternary expression for types with constant condition 2017-07-19 12:15:21 +01:00
Ginger Bill 4db462a703 Fix copy 2017-07-18 20:39:53 +01:00
Ginger Bill a22c6d6c0c Fix parsing error for compound literals 2017-07-18 19:57:30 +01:00
Ginger Bill 59fb7b020a Merge raw_union into struct as a memory layout tag #raw_union 2017-07-18 19:24:45 +01:00
Ginger Bill 65f079ebc4 Remove atomic, ++, and -- 2017-07-18 18:58:41 +01:00
Ginger Bill d16aa79492 General specialization for polymorphic parameters 2017-07-18 18:05:41 +01:00
Ginger Bill 5af0acc4af Disallow default struct values for any; new_clone 2017-07-18 16:02:01 +01:00
Ginger Bill a459364de3 Ignore missing default values for struct literals at the end 2017-07-18 15:32:34 +01:00
Ginger Bill 277ef1a68f Allow undefined --- as a struct field default value. 2017-07-18 15:09:24 +01:00
Ginger Bill 193c7c82c8 Default struct field values 2017-07-18 14:56:07 +01:00
Ginger Bill f7d8ba408c Fix some preload bugs. 2017-07-18 11:42:16 +01:00
Ginger Bill 9a8759efef Polymorphic type specialization for procedures 2017-07-17 15:08:36 +01:00
Ginger Bill 054948e701 Basic procedure type parameter specialization 2017-07-16 15:00:16 +01:00
Ginger Bill 1c5ddd65b4 Rudimentary support for parametric polymorphic types 2017-07-13 22:35:00 +01:00
Ginger Bill b8697fb4ed Change precedence order for types e.g. ^T(x) == ^(T(x)) 2017-07-13 16:20:07 +01:00
Ginger Bill 03570275c1 Fix issue #78 and have a better error message. 2017-07-13 11:35:01 +01:00
Ginger Bill b5587f1937 Fix aliasing of overloaded procedures from other scopes 2017-07-11 20:54:38 +01:00
Ginger Bill c4c6975f1b cast(Type)expr; Fix overloaded procedure determination on assignment 2017-07-11 14:40:27 +01:00
Ginger Bill 0be0fb2a57 Nested when statements within records 2017-07-10 23:47:22 +01:00
Ginger Bill 115e6e7f9e Update demo for both subtyping and union based Entity 2017-07-10 23:28:53 +01:00
Ginger Bill 3868a9a0f0 Clean up _preload.odin types 2017-07-10 23:15:41 +01:00
Ginger Bill ba5050ac7c Compiler Internal Changes: TypeRecord_Union -> Type_Union 2017-07-10 22:59:23 +01:00
Ginger Bill d936ca1ea0 Compiler internal change: TypeRecord_Enum -> Type_Enum 2017-07-10 22:42:58 +01:00
Ginger Bill fd8c4d58bb union type allow for any types and removes common fields 2017-07-10 22:32:21 +01:00
Ginger Bill ce4b7b8b7d Nested record declarations 2017-07-10 20:39:42 +01:00
Ginger Bill 069a47220e Make record semicolon syntax more consistent 2017-07-10 14:52:58 +01:00
Ginger Bill 66e4aaffc5 Use semicolons as field delimiters in records 2017-07-10 13:49:50 +01:00
Ginger Bill 81336b58cb "Fix" printing of embedded any to prevent recursion 2017-07-10 10:37:51 +01:00
Ginger Bill b201670f7a Fix _preload.odin; Add for in without parameters; Change sync.Mutex for windows 2017-07-08 23:13:57 +01:00
Ginger Bill 4b051a0d3b .. half closed range; ... open range; ... variadic syntax 2017-07-07 23:42:43 +01:00
Ginger Bill 45353465a6 Add sort.odin 2017-07-07 22:26:55 +01:00
Ginger Bill c63cb98019 Fix else do 2017-07-07 17:50:45 +01:00
Ginger Bill 773cf5ca08 Add -show-timings; Clean up polymorphic procedure code a bit 2017-07-07 15:26:49 +01:00
Ginger Bill 2db03cb4a5 Fix aprint* bug; NULL -> nullptr; Better error messages for overloaded functions 2017-07-06 22:43:55 +01:00
Ginger Bill eed873c6ec Add free for maps (a previous oversight) 2017-07-05 13:51:25 +01:00
Ginger Bill 3d2d461867 Replace many built-in procedures with user-level procedures 2017-07-04 23:52:00 +01:00
Ginger Bill 36392d658e Fix demo.odin 2017-07-04 22:43:38 +01:00
Ginger Bill 82696179e8 Merge branch 'master' of https://github.com/gingerBill/Odin 2017-07-04 22:42:41 +01:00
Ginger Bill 188bc28f6a Allow for overloading of polymorphic procedures 2017-07-04 22:42:25 +01:00
Ginger Bill 240da5c8e0 Allow aliasing of aliases 2017-07-04 16:06:08 +01:00
Ginger Bill 689a0c0b49 *_of as keyords; Allow constant aliasing for user/built-in procedures, import names, and library names 2017-07-04 11:23:48 +01:00
Ginger Bill bc16b290ba Disable polymorphic overloading in the global scope
TODO: Figure out why it does not work in the global scope
2017-07-02 22:08:39 +01:00
Ginger Bill 96d32680fe Allow overloading of polymorphic procedures 2017-07-02 10:45:22 +01:00
Ginger Bill d782b3d21d Fix do on for loops 2017-07-01 11:53:01 +01:00
Ginger Bill ed089b44b9 do keyword for inline statements instead of blocks 2017-07-01 11:38:44 +01:00
Ginger Bill 33f4af2e19 Fix demo 2017-06-29 21:01:07 +01:00
Ginger Bill 69f7382eec Implicit parametric polymorphic procedures 2017-06-29 20:56:18 +01:00
Ginger Bill 7e3293fc20 Fix odin version printing 2017-06-29 16:08:30 +01:00
Ginger Bill e4a8283327 Remove Type
What was I thinking?!
2017-06-29 15:48:07 +01:00
Ginger Bill 001baf4419 Add Type -- Runtime type for comparing types (similar to TypeInfo but simpler) 2017-06-29 15:13:41 +01:00
Ginger Bill d167290b28 Make AstNodeIdent a struct wrapping its Token 2017-06-29 12:11:50 +01:00
Ginger Bill f4879d4723 Update procedure names and extend demo.odin 2017-06-29 11:25:05 +01:00
Ginger Bill fd81c06c35 Remove var and const keywords; Fix default parameter syntax 2017-06-28 23:55:40 +01:00
Ginger Bill 94afcec757 :: style procedure declarations; remove old parsing code 2017-06-28 23:47:06 +01:00
Ginger Bill 4f28e9e1fb Remove type prefix declarations 2017-06-28 23:23:10 +01:00
Ginger Bill 0622509807 Disable var and const declarations 2017-06-28 23:17:20 +01:00
Ginger Bill 9ca2246bac Basic allowance for := and :: 2017-06-28 22:38:04 +01:00
Ginger Bill 647e2cafd7 Fix expand_to_tuple 2017-06-27 22:47:19 +01:00
56 changed files with 14012 additions and 10246 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2016 Ginger Bill. All rights reserved. Copyright (c) 2016-2017 Ginger Bill. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
+1 -2
View File
@@ -4,7 +4,7 @@
set exe_name=odin.exe set exe_name=odin.exe
:: Debug = 0, Release = 1 :: Debug = 0, Release = 1
set release_mode=0 set release_mode=1
set compiler_flags= -nologo -Oi -TP -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR- set compiler_flags= -nologo -Oi -TP -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
if %release_mode% EQU 0 ( rem Debug if %release_mode% EQU 0 ( rem Debug
@@ -38,7 +38,6 @@ if %release_mode% EQU 0 ( rem Debug
set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings% set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings%
set linker_settings=%libs% %linker_flags% set linker_settings=%libs% %linker_flags%
del *.pdb > NUL 2> NUL del *.pdb > NUL 2> NUL
del *.ilk > NUL 2> NUL del *.ilk > NUL 2> NUL
+593 -425
View File
File diff suppressed because it is too large Load Diff
+430
View File
@@ -0,0 +1,430 @@
import (
"fmt.odin";
"atomics.odin";
"bits.odin";
"decimal.odin";
"hash.odin";
"math.odin";
"mem.odin";
"opengl.odin";
"os.odin";
"raw.odin";
"strconv.odin";
"strings.odin";
"sync.odin";
"sort.odin";
"types.odin";
"utf8.odin";
"utf16.odin";
/*
*/
)
general_stuff :: proc() {
// Complex numbers
a := 3 + 4i;
b: complex64 = 3 + 4i;
c: complex128 = 3 + 4i;
d := complex(2, 3);
e := a / conj(a);
fmt.println("(3+4i)/(3-4i) =", e);
fmt.println(real(e), "+", imag(e), "i");
// C-style variadic procedures
foreign __llvm_core {
// The variadic part allows for extra type checking too which C does not provide
c_printf :: proc(fmt: ^u8, #c_vararg args: ...any) -> i32 #link_name "printf" ---;
}
str := "%d\n\x00";
// c_printf(&str[0], i32(789456123));
Foo :: struct {
x: int;
y: f32;
z: string;
}
foo := Foo{123, 0.513, "A string"};
x, y, z := expand_to_tuple(foo);
fmt.println(x, y, z);
compile_assert(type_of(x) == int);
compile_assert(type_of(y) == f32);
compile_assert(type_of(z) == string);
// By default, all variables are zeroed
// This can be overridden with the "uninitialized value"
// This is similar to `nil` but applied to everything
undef_int: int = ---;
// Context system is now implemented using Implicit Parameter Passing (IPP)
// The previous implementation was Thread Local Storage (TLS)
// IPP has the advantage that it works on systems without TLS and that you can
// link the context to the stack frame and thus look at previous contexts
//
// It does mean that a pointer is implicitly passed procedures with the default
// Odin calling convention (#cc_odin)
// This can be overridden with something like #cc_contextless or #cc_c if performance
// is worried about
}
foreign_blocks :: proc() {
// See sys/windows.odin
}
default_arguments :: proc() {
hello :: proc(a: int = 9, b: int = 9) do fmt.printf("a is %d; b is %d\n", a, b);
fmt.println("\nTesting default arguments:");
hello(1, 2);
hello(1);
hello();
}
named_arguments :: proc() {
Colour :: enum {
Red,
Orange,
Yellow,
Green,
Blue,
Octarine,
};
using Colour;
make_character :: proc(name, catch_phrase: string, favourite_colour, least_favourite_colour: Colour) {
fmt.println();
fmt.printf("My name is %v and I like %v. %v\n", name, favourite_colour, catch_phrase);
}
make_character("Frank", "¡Ay, caramba!", Blue, Green);
// As the procedures have more and more parameters, it is very easy
// to get many of the arguments in the wrong order especialy if the
// types are the same
make_character("¡Ay, caramba!", "Frank", Green, Blue);
// Named arguments help to disambiguate this problem
make_character(catch_phrase = "¡Ay, caramba!", name = "Frank",
least_favourite_colour = Green, favourite_colour = Blue);
// The named arguments can be specifed in any order.
make_character(favourite_colour = Octarine, catch_phrase = "U wot m8!",
least_favourite_colour = Green, name = "Dennis");
// NOTE: You cannot mix named arguments with normal values
/*
make_character("Dennis",
favourite_colour = Octarine, catch_phrase = "U wot m8!",
least_favourite_colour = Green);
*/
// Named arguments can also aid with default arguments
numerous_things :: proc(s: string, a := 1, b := 2, c := 3.14,
d := "The Best String!", e := false, f := 10.3/3.1, g := false) {
g_str := g ? "true" : "false";
fmt.printf("How many?! %s: %v\n", s, g_str);
}
numerous_things("First");
numerous_things(s = "Second", g = true);
// Default values can be placed anywhere, not just at the end like in other languages
weird :: proc(pre: string, mid: int = 0, post: string) {
fmt.println(pre, mid, post);
}
weird("How many things", 42, "huh?");
weird(pre = "Prefix", post = "Pat");
}
default_return_values :: proc() {
foo :: proc(x: int) -> (first: string = "Hellope", second := "world!") {
match x {
case 0: return;
case 1: return "Goodbye";
case 2: return "Goodbye", "cruel world...";
case 3: return second = "cruel world...", first = "Goodbye";
}
return second = "my old friend.";
}
fmt.printf("%s %s\n", foo(0));
fmt.printf("%s %s\n", foo(1));
fmt.printf("%s %s\n", foo(2));
fmt.printf("%s %s\n", foo(3));
fmt.printf("%s %s\n", foo(4));
fmt.println();
// A more "real" example
Error :: enum {
None,
WhyTheNumberThree,
TenIsTooBig,
};
Entity :: struct {
name: string;
id: u32;
}
some_thing :: proc(input: int) -> (result: ^Entity = nil, err := Error.None) {
match {
case input == 3: return err = Error.WhyTheNumberThree;
case input >= 10: return err = Error.TenIsTooBig;
}
e := new(Entity);
e.id = u32(input);
return result = e;
}
}
call_location :: proc() {
amazing :: proc(n: int, using loc := #caller_location) {
fmt.printf("%s(%d:%d) just asked to do something amazing.\n",
fully_pathed_filename, line, column);
fmt.printf("Normal -> %d\n", n);
fmt.printf("Amazing -> %d\n", n+1);
fmt.println();
}
loc := #location(main);
fmt.println("`main` is located at", loc);
fmt.println("This line is located at", #location());
fmt.println();
amazing(3);
amazing(4, #location(call_location));
// See _preload.odin for the implementations of `assert` and `panic`
}
explicit_parametric_polymorphic_procedures :: proc() {
// This is how `new` is actually implemented, see _preload.odin
alloc_type :: proc(T: type) -> ^T do return cast(^T)alloc(size_of(T), align_of(T));
int_ptr := alloc_type(int);
defer free(int_ptr);
int_ptr^ = 137;
fmt.println(int_ptr, int_ptr^);
// Named arguments work too!
another_ptr := alloc_type(T = f32);
defer free(another_ptr);
add :: proc(T: type, args: ...T) -> T {
res: T;
for arg in args do res += arg;
return res;
}
fmt.println("add =", add(int, 1, 2, 3, 4, 5, 6));
swap :: proc(T: type, a, b: ^T) {
tmp := a^;
a^ = b^;
b^ = tmp;
}
a, b: int = 3, 4;
fmt.println("Pre-swap:", a, b);
swap(int, &a, &b);
fmt.println("Post-swap:", a, b);
a, b = b, a; // Or use this syntax for this silly example case
Vector2 :: struct {x, y: f32;};
{
// A more complicated example using subtyping
// Something like this could be used in a game
Entity :: struct {
using position: Vector2;
flags: u64;
id: u64;
derived: any;
}
Rock :: struct {
using entity: Entity;
heavy: bool;
}
Door :: struct {
using entity: Entity;
open: bool;
}
Monster :: struct {
using entity: Entity;
is_robot: bool;
is_zombie: bool;
}
new_entity :: proc(T: type, x, y: f32) -> ^T {
result := new(T);
result.derived = result^;
result.x = x;
result.y = y;
return result;
}
entities: [dynamic]^Entity;
rock := new_entity(Rock, 3, 5);
// Named arguments work too!
door := new_entity(T = Door, x = 3, y = 6);
// And named arguments can be any order
monster := new_entity(
y = 1,
x = 2,
T = Monster,
);
append(&entities, rock, door, monster);
fmt.println("Subtyping");
for entity in entities {
match e in entity.derived {
case Rock: fmt.println("Rock", e.x, e.y);
case Door: fmt.println("Door", e.x, e.y);
case Monster: fmt.println("Monster", e.x, e.y);
}
}
}
{
Entity :: struct {
using position: Vector2;
flags: u64;
id: u64;
variant: union { Rock, Door, Monster };
}
Rock :: struct {
using entity: ^Entity;
heavy: bool;
}
Door :: struct {
using entity: ^Entity;
open: bool;
}
Monster :: struct {
using entity: ^Entity;
is_robot: bool;
is_zombie: bool;
}
new_entity :: proc(T: type, x, y: f32) -> ^T {
result := new(Entity);
result.variant = T{entity = result};
result.x = x;
result.y = y;
return cast(^T)&result.variant;
}
entities: [dynamic]^Entity;
rock := new_entity(Rock, 3, 5);
// Named arguments work too!
door := new_entity(T = Door, x = 3, y = 6);
// And named arguments can be any order
monster := new_entity(
y = 1,
x = 2,
T = Monster,
);
append(&entities, rock, door, monster);
fmt.println("Union");
for entity in entities {
match e in entity.variant {
case Rock: fmt.println("Rock", e.x, e.y);
case Door: fmt.println("Door", e.x, e.y);
case Monster: fmt.println("Monster", e.x, e.y);
}
}
}
}
implicit_polymorphic_assignment :: proc() {
yep :: proc(p: proc(x: int)) {
p(123);
}
frank :: proc(x: $T) do fmt.println("frank ->", x);
tim :: proc(x, y: $T) do fmt.println("tim ->", x, y);
yep(frank);
// yep(tim);
}
main :: proc() {
/*
foo :: proc(x: i64, y: f32) do fmt.println("#1", x, y);
foo :: proc(x: type, y: f32) do fmt.println("#2", type_info(x), y);
foo :: proc(x: type) do fmt.println("#3", type_info(x));
f :: foo;
f(y = 3785.1546, x = 123);
f(x = int, y = 897.513);
f(x = f32);
general_stuff();
foreign_blocks();
default_arguments();
named_arguments();
default_return_values();
call_location();
explicit_parametric_polymorphic_procedures();
implicit_polymorphic_assignment();
// Command line argument(s)!
// -opt=0,1,2,3
*/
/*
program := "+ + * - /";
accumulator := 0;
for token in program {
match token {
case '+': accumulator += 1;
case '-': accumulator -= 1;
case '*': accumulator *= 2;
case '/': accumulator /= 2;
case: // Ignore everything else
}
}
fmt.printf("The program \"%s\" calculates the value %d\n",
program, accumulator);
*/
}
+654 -425
View File
File diff suppressed because it is too large Load Diff
+48 -49
View File
@@ -1,88 +1,87 @@
#shared_global_scope; #shared_global_scope;
proc __multi3(a, b: u128) -> u128 #cc_c #link_name "__multi3" { __multi3 :: proc(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
const bits_in_dword_2 = size_of(i64) * 4; bits_in_dword_2 :: size_of(i64) * 4;
const lower_mask = u128(~u64(0) >> bits_in_dword_2); lower_mask :: u128(~u64(0) >> bits_in_dword_2);
when ODIN_ENDIAN == "bit" { TWords :: struct #raw_union {
type TWords raw_union { all: u128;
all: u128, using _: struct {
using _: struct {lo, hi: u64}, 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; r: TWords;
var t: u64; t: u64;
r.lo = u64(a & lower_mask) * u64(b & lower_mask); r.lo = u64(a & lower_mask) * u64(b & lower_mask);
t = r.lo >> bits_in_dword_2; t = r.lo >> bits_in_dword_2;
r.lo &= u64(lower_mask); 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.lo += u64(t & u64(lower_mask)) << bits_in_dword_2;
r.hi = t >> bits_in_dword_2; r.hi = t >> bits_in_dword_2;
t = r.lo >> bits_in_dword_2; t = r.lo >> bits_in_dword_2;
r.lo &= u64(lower_mask); 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.lo += u64(t & u64(lower_mask)) << bits_in_dword_2;
r.hi += t >> 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); r.hi += u64(a >> bits_in_dword_2) * u64(b >> bits_in_dword_2);
return r.all; return r.all;
} }
proc __u128_mod(a, b: u128) -> u128 #cc_c #link_name "__umodti3" { __u128_mod :: proc(a, b: u128) -> u128 #cc_c #link_name "__umodti3" {
var r: u128; r: u128;
__u128_quo_mod(a, b, &r); __u128_quo_mod(a, b, &r);
return 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); return __u128_quo_mod(a, b, nil);
} }
proc __i128_mod(a, b: i128) -> i128 #cc_c #link_name "__modti3" { __i128_mod :: proc(a, b: i128) -> i128 #cc_c #link_name "__modti3" {
var r: i128; r: i128;
__i128_quo_mod(a, b, &r); __i128_quo_mod(a, b, &r);
return 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); return __i128_quo_mod(a, b, nil);
} }
proc __i128_quo_mod(a, b: i128, rem: ^i128) -> (quo: i128) #cc_c #link_name "__divmodti4" { __i128_quo_mod :: proc(a, b: i128, rem: ^i128) -> (quo: i128) #cc_c #link_name "__divmodti4" {
var s: i128; s: i128;
s = b >> 127; s = b >> 127;
b = (b~s) - s; b = (b~s) - s;
s = a >> 127; s = a >> 127;
b = (a~s) - s; b = (a~s) - s;
var uquo: u128; uquo: u128;
var urem = __u128_quo_mod(transmute(u128, a), transmute(u128, b), &uquo); urem := __u128_quo_mod(transmute(u128)a, transmute(u128)b, &uquo);
var iquo = transmute(i128, uquo); iquo := transmute(i128)uquo;
var irem = transmute(i128, urem); irem := transmute(i128)urem;
iquo = (iquo~s) - s; iquo = (iquo~s) - s;
irem = (irem~s) - s; irem = (irem~s) - s;
if rem != nil { rem^ = irem; } if rem != nil do rem^ = irem;
return iquo; return iquo;
} }
proc __u128_quo_mod(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "__udivmodti4" { __u128_quo_mod :: proc(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "__udivmodti4" {
var alo, ahi = u64(a), u64(a>>64); alo, ahi := u64(a), u64(a>>64);
var blo, bhi = u64(b), u64(b>>64); blo, bhi := u64(b), u64(b>>64);
if b == 0 { if b == 0 {
if rem != nil { rem^ = 0; } if rem != nil do rem^ = 0;
return u128(alo/blo); 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 { for r >= d && (d>>127)&1 == 0 {
x <<= 1; x <<= 1;
@@ -98,15 +97,15 @@ proc __u128_quo_mod(a, b: u128, rem: ^u128) -> (quo: u128) #cc_c #link_name "__u
d >>= 1; d >>= 1;
} }
if rem != nil { rem^ = r; } if rem != nil do rem^ = r;
return q; 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 { when true {
// Source: https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/ // 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, was_infnan: FP32;
magic.u = (254-15) << 23; 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; 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 { when false {
// Source: https://gist.github.com/rygorous/2156668 // Source: https://gist.github.com/rygorous/2156668
const FP16 = raw_union {u: u16, f: f16}; FP16 :: struct #raw_union {u: u16, f: f16};
const FP32 = raw_union {u: u32, f: f32}; FP32 :: struct #raw_union {u: u32, f: f32};
f32infty, f16infty, magic: FP32; f32infty, f16infty, magic: FP32;
f32infty.u = 255<<23; f32infty.u = 255<<23;
f16infty.u = 31<<23; f16infty.u = 31<<23;
magic.u = 15<<23; magic.u = 15<<23;
const sign_mask = u32(0x80000000); sign_mask :: u32(0x80000000);
const round_mask = ~u32(0x0fff); round_mask :: ~u32(0x0fff);
f := transmute(FP32, f_); 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)); 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)); return f64(__f16_to_f32(f));
} }
*/ */
+33 -33
View File
@@ -2,99 +2,99 @@
// Inline vs external file? // Inline vs external file?
import win32 "sys/windows.odin" when ODIN_OS == "windows"; 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(); } yield_thread :: proc() { win32.mm_pause(); }
proc mfence () { win32.read_write_barrier(); } mfence :: proc() { win32.read_write_barrier(); }
proc sfence () { win32.write_barrier(); } sfence :: proc() { win32.write_barrier(); }
proc lfence () { win32.read_barrier(); } lfence :: proc() { win32.read_barrier(); }
proc load(a: ^i32) -> i32 { load :: proc(a: ^i32) -> i32 {
return a^; return a^;
} }
proc store(a: ^i32, value: i32) { store :: proc(a: ^i32, value: i32) {
a^ = value; 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); 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); 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); 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); 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); return win32.interlocked_or(a, operand);
} }
proc spin_lock(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
var old_value = compare_exchange(a, 1, 0); old_value := compare_exchange(a, 1, 0);
var counter = 0; counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) { for old_value != 0 && (time_out < 0 || counter < time_out) {
counter++; counter += 1;
yield_thread(); yield_thread();
old_value = compare_exchange(a, 1, 0); old_value = compare_exchange(a, 1, 0);
mfence(); mfence();
} }
return old_value == 0; return old_value == 0;
} }
proc spin_unlock(a: ^i32) { spin_unlock :: proc(a: ^i32) {
store(a, 0); store(a, 0);
mfence(); mfence();
} }
proc try_acquire_lock(a: ^i32) -> bool { try_acquire_lock :: proc(a: ^i32) -> bool {
yield_thread(); yield_thread();
var old_value = compare_exchange(a, 1, 0); old_value := compare_exchange(a, 1, 0);
mfence(); mfence();
return old_value == 0; return old_value == 0;
} }
proc load(a: ^i64) -> i64 { load :: proc(a: ^i64) -> i64 {
return a^; return a^;
} }
proc store(a: ^i64, value: i64) { store :: proc(a: ^i64, value: i64) {
a^ = value; 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); 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); 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); 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); 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); return win32.interlocked_or64(a, operand);
} }
proc spin_lock(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
var old_value = compare_exchange(a, 1, 0); old_value := compare_exchange(a, 1, 0);
var counter = 0; counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) { for old_value != 0 && (time_out < 0 || counter < time_out) {
counter++; counter += 1;
yield_thread(); yield_thread();
old_value = compare_exchange(a, 1, 0); old_value = compare_exchange(a, 1, 0);
mfence(); mfence();
} }
return old_value == 0; return old_value == 0;
} }
proc spin_unlock(a: ^i64) { spin_unlock :: proc(a: ^i64) {
store(a, 0); store(a, 0);
mfence(); mfence();
} }
proc try_acquire_lock(a: ^i64) -> bool { try_acquire_lock :: proc(a: ^i64) -> bool {
yield_thread(); yield_thread();
var old_value = compare_exchange(a, 1, 0); old_value := compare_exchange(a, 1, 0);
mfence(); mfence();
return old_value == 0; return old_value == 0;
} }
+222 -224
View File
@@ -1,287 +1,285 @@
const ( U8_MIN :: u8(0);
U8_MIN = u8(0); U16_MIN :: u16(0);
U16_MIN = u16(0); U32_MIN :: u32(0);
U32_MIN = u32(0); U64_MIN :: u64(0);
U64_MIN = u64(0); U128_MIN :: u128(0);
U128_MIN = u128(0);
I8_MIN = i8(-0x80); I8_MIN :: i8(-0x80);
I16_MIN = i16(-0x8000); I16_MIN :: i16(-0x8000);
I32_MIN = i32(-0x8000_0000); I32_MIN :: i32(-0x8000_0000);
I64_MIN = i64(-0x8000_0000_0000_0000); I64_MIN :: i64(-0x8000_0000_0000_0000);
I128_MIN = i128(-0x8000_0000_0000_0000_0000_0000_0000_0000); I128_MIN :: i128(-0x8000_0000_0000_0000_0000_0000_0000_0000);
U8_MAX = ~u8(0); U8_MAX :: ~u8(0);
U16_MAX = ~u16(0); U16_MAX :: ~u16(0);
U32_MAX = ~u32(0); U32_MAX :: ~u32(0);
U64_MAX = ~u64(0); U64_MAX :: ~u64(0);
U128_MAX = ~u128(0); U128_MAX :: ~u128(0);
I8_MAX = i8(0x7f); I8_MAX :: i8(0x7f);
I16_MAX = i16(0x7fff); I16_MAX :: i16(0x7fff);
I32_MAX = i32(0x7fff_ffff); I32_MAX :: i32(0x7fff_ffff);
I64_MAX = i64(0x7fff_ffff_ffff_ffff); I64_MAX :: i64(0x7fff_ffff_ffff_ffff);
I128_MAX = i128(0x7fff_ffff_ffff_ffff_ffff_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); } count_ones :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_ctpop :: proc(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); } count_ones :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_ctpop :: proc(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); } count_ones :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_ctpop :: proc(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); } count_ones :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_ctpop :: proc(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); } count_ones :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_ctpop :: proc(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); } count_ones :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_ctpop :: proc(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); } count_ones :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_ctpop :: proc(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); } count_ones :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_ctpop :: proc(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); } count_ones :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_ctpop :: proc(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); } count_ones :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_ctpop :: proc(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))); } } 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))); } }
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: 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); } count_zeros :: proc(i: u8) -> u8 { return 8 - count_ones(i); }
proc count_zeros(i: i8) -> i8 { return 8 - count_ones(i); } count_zeros :: proc(i: i8) -> i8 { return 8 - count_ones(i); }
proc count_zeros(i: u16) -> u16 { return 16 - count_ones(i); } count_zeros :: proc(i: u16) -> u16 { return 16 - count_ones(i); }
proc count_zeros(i: i16) -> i16 { return 16 - count_ones(i); } count_zeros :: proc(i: i16) -> i16 { return 16 - count_ones(i); }
proc count_zeros(i: u32) -> u32 { return 32 - count_ones(i); } count_zeros :: proc(i: u32) -> u32 { return 32 - count_ones(i); }
proc count_zeros(i: i32) -> i32 { return 32 - count_ones(i); } count_zeros :: proc(i: i32) -> i32 { return 32 - count_ones(i); }
proc count_zeros(i: u64) -> u64 { return 64 - count_ones(i); } count_zeros :: proc(i: u64) -> u64 { return 64 - count_ones(i); }
proc count_zeros(i: i64) -> i64 { return 64 - count_ones(i); } count_zeros :: proc(i: i64) -> i64 { return 64 - count_ones(i); }
proc count_zeros(i: u128) -> u128 { return 128 - count_ones(i); } count_zeros :: proc(i: u128) -> u128 { return 128 - count_ones(i); }
proc count_zeros(i: i128) -> i128 { return 128 - count_ones(i); } count_zeros :: proc(i: i128) -> i128 { return 128 - count_ones(i); }
proc count_zeros(i: uint) -> uint { return 8*size_of(uint) - count_ones(i); } count_zeros :: proc(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: 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)); } rotate_left :: proc(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)); } rotate_left :: proc(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)); } rotate_left :: proc(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)); } rotate_left :: proc(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)); } rotate_left :: proc(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)); } rotate_left :: proc(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)); } rotate_left :: proc(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)); } rotate_left :: proc(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)); } rotate_left :: proc(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)); } rotate_left :: proc(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)); } } 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)); } }
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: 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)); } rotate_right :: proc(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)); } rotate_right :: proc(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)); } rotate_right :: proc(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)); } rotate_right :: proc(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)); } rotate_right :: proc(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)); } rotate_right :: proc(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)); } rotate_right :: proc(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)); } rotate_right :: proc(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)); } rotate_right :: proc(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)); } rotate_right :: proc(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)); } } 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)); } }
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: 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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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))); } } 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))); } }
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: 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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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))); } } 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))); } }
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: 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); } reverse_bits :: proc(i: u8) -> u8 { foreign __llvm_core __llvm_bitreverse :: proc(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); } reverse_bits :: proc(i: i8) -> i8 { foreign __llvm_core __llvm_bitreverse :: proc(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); } reverse_bits :: proc(i: u16) -> u16 { foreign __llvm_core __llvm_bitreverse :: proc(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); } reverse_bits :: proc(i: i16) -> i16 { foreign __llvm_core __llvm_bitreverse :: proc(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); } reverse_bits :: proc(i: u32) -> u32 { foreign __llvm_core __llvm_bitreverse :: proc(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); } reverse_bits :: proc(i: i32) -> i32 { foreign __llvm_core __llvm_bitreverse :: proc(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); } reverse_bits :: proc(i: u64) -> u64 { foreign __llvm_core __llvm_bitreverse :: proc(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); } reverse_bits :: proc(i: i64) -> i64 { foreign __llvm_core __llvm_bitreverse :: proc(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); } reverse_bits :: proc(i: u128) -> u128 { foreign __llvm_core __llvm_bitreverse :: proc(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); } reverse_bits :: proc(i: i128) -> i128 { foreign __llvm_core __llvm_bitreverse :: proc(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))); } } 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))); } }
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: 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 { foreign __llvm_core {
proc byte_swap(u16) -> u16 #link_name "llvm.bswap.i16"; byte_swap :: proc(u16) -> u16 #link_name "llvm.bswap.i16" ---;
proc byte_swap(i16) -> i16 #link_name "llvm.bswap.i16"; byte_swap :: proc(i16) -> i16 #link_name "llvm.bswap.i16" ---;
proc byte_swap(u32) -> u32 #link_name "llvm.bswap.i32"; byte_swap :: proc(u32) -> u32 #link_name "llvm.bswap.i32" ---;
proc byte_swap(i32) -> i32 #link_name "llvm.bswap.i32"; byte_swap :: proc(i32) -> i32 #link_name "llvm.bswap.i32" ---;
proc byte_swap(u64) -> u64 #link_name "llvm.bswap.i64"; byte_swap :: proc(u64) -> u64 #link_name "llvm.bswap.i64" ---;
proc byte_swap(i64) -> i64 #link_name "llvm.bswap.i64"; byte_swap :: proc(i64) -> i64 #link_name "llvm.bswap.i64" ---;
proc byte_swap(u128) -> u128 #link_name "llvm.bswap.i128"; byte_swap :: proc(u128) -> u128 #link_name "llvm.bswap.i128" ---;
proc byte_swap(i128) -> i128 #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))); } } 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))); } }
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: 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; } from_be :: proc(i: u8) -> u8 { return i; }
proc from_be(i: i8) -> i8 { return i; } from_be :: proc(i: i8) -> i8 { return i; }
proc from_be(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } } from_be :: proc(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); } } from_be :: proc(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); } } from_be :: proc(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); } } from_be :: proc(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); } } from_be :: proc(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); } } from_be :: proc(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); } } from_be :: proc(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); } } from_be :: proc(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); } } from_be :: proc(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: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc from_le(i: u8) -> u8 { return i; } from_le :: proc(i: u8) -> u8 { return i; }
proc from_le(i: i8) -> i8 { return i; } from_le :: proc(i: i8) -> i8 { return i; }
proc from_le(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } } from_le :: proc(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); } } from_le :: proc(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); } } from_le :: proc(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); } } from_le :: proc(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); } } from_le :: proc(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); } } from_le :: proc(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); } } from_le :: proc(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); } } from_le :: proc(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); } } from_le :: proc(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: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
proc to_be(i: u8) -> u8 { return i; } to_be :: proc(i: u8) -> u8 { return i; }
proc to_be(i: i8) -> i8 { return i; } to_be :: proc(i: i8) -> i8 { return i; }
proc to_be(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } } to_be :: proc(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); } } to_be :: proc(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); } } to_be :: proc(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); } } to_be :: proc(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); } } to_be :: proc(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); } } to_be :: proc(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); } } to_be :: proc(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); } } to_be :: proc(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); } } to_be :: proc(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: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
proc to_le(i: u8) -> u8 { return i; } to_le :: proc(i: u8) -> u8 { return i; }
proc to_le(i: i8) -> i8 { return i; } to_le :: proc(i: i8) -> i8 { return i; }
proc to_le(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } } to_le :: proc(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); } } to_le :: proc(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); } } to_le :: proc(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); } } to_le :: proc(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); } } to_le :: proc(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); } } to_le :: proc(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); } } to_le :: proc(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); } } to_le :: proc(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); } } to_le :: proc(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: 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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
proc overflowing_add(lhs, rhs: uint) -> (uint, bool) { overflowing_add :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) { 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; return uint(x), ok;
} else { } else {
var x, ok = overflowing_add(u64(lhs), u64(rhs)); x, ok := overflowing_add(u64(lhs), u64(rhs));
return uint(x), ok; 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) { 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; return int(x), ok;
} else { } else {
var x, ok = overflowing_add(i64(lhs), i64(rhs)); x, ok := overflowing_add(i64(lhs), i64(rhs));
return int(x), ok; 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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
proc overflowing_sub(lhs, rhs: uint) -> (uint, bool) { overflowing_sub :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) { 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; return uint(x), ok;
} else { } else {
var x, ok = overflowing_sub(u64(lhs), u64(rhs)); x, ok := overflowing_sub(u64(lhs), u64(rhs));
return uint(x), ok; 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) { 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; return int(x), ok;
} else { } else {
var x, ok = overflowing_sub(i64(lhs), i64(rhs)); x, ok := overflowing_sub(i64(lhs), i64(rhs));
return int(x), ok; 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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
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); } 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); }
proc overflowing_mul(lhs, rhs: uint) -> (uint, bool) { overflowing_mul :: proc(lhs, rhs: uint) -> (uint, bool) {
when size_of(uint) == size_of(u32) { 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; return uint(x), ok;
} else { } else {
var x, ok = overflowing_mul(u64(lhs), u64(rhs)); x, ok := overflowing_mul(u64(lhs), u64(rhs));
return uint(x), ok; 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) { 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; return int(x), ok;
} else { } else {
var x, ok = overflowing_mul(i64(lhs), i64(rhs)); x, ok := overflowing_mul(i64(lhs), i64(rhs));
return int(x), ok; return int(x), ok;
} }
} }
proc is_power_of_two(i: u8) -> bool { return i > 0 && (i & (i-1)) == 0; } is_power_of_two :: proc(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; } is_power_of_two :: proc(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; } is_power_of_two :: proc(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; } is_power_of_two :: proc(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; } is_power_of_two :: proc(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; } is_power_of_two :: proc(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; } is_power_of_two :: proc(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; } is_power_of_two :: proc(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; } is_power_of_two :: proc(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; } is_power_of_two :: proc(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; } is_power_of_two :: proc(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: int) -> bool { return i > 0 && (i & (i-1)) == 0; }
+41
View File
@@ -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
View File
@@ -2,53 +2,53 @@
// Multiple precision decimal numbers // Multiple precision decimal numbers
// NOTE: This is only for floating point printing and nothing else // NOTE: This is only for floating point printing and nothing else
type Decimal struct { Decimal :: struct {
digits: [384]u8, // big-endian digits digits: [384]u8; // big-endian digits
count: int, count: int;
decimal_point: int, decimal_point: int;
neg, trunc: bool, neg, trunc: bool;
} }
proc decimal_to_string(buf: []u8, a: ^Decimal) -> string { decimal_to_string :: proc(buf: []u8, a: ^Decimal) -> string {
proc digit_zero(buf: []u8) -> int { digit_zero :: proc(buf: []u8) -> int {
for _, i in buf -> buf[i] = '0'; for _, i in buf do buf[i] = '0';
return len(buf); 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 // TODO(bill): make this work with a buffer that's not big enough
assert(len(buf) >= n); assert(len(buf) >= n);
buf = buf[0..<n]; buf = buf[0..n];
if a.count == 0 { if a.count == 0 {
buf[0] = '0'; buf[0] = '0';
return string(buf[0..<1]); return string(buf[0..1]);
} }
var w = 0; w := 0;
if a.decimal_point <= 0 { if a.decimal_point <= 0 {
buf[w] = '0'; w++; buf[w] = '0'; w+=1;
buf[w] = '.'; w++; buf[w] = '.'; w+=1;
w += digit_zero(buf[w ..< w-a.decimal_point]); w += digit_zero(buf[w .. w-a.decimal_point]);
w += copy(buf[w..], a.digits[0..<a.count]); w += copy(buf[w..], a.digits[0..a.count]);
} else if a.decimal_point < a.count { } else if a.decimal_point < a.count {
w += copy(buf[w..], a.digits[0..<a.decimal_point]); w += copy(buf[w..], a.digits[0..a.decimal_point]);
buf[w] = '.'; w++; buf[w] = '.'; w+=1;
w += copy(buf[w..], a.digits[a.decimal_point ..< a.count]); w += copy(buf[w..], a.digits[a.decimal_point .. a.count]);
} else { } else {
w += copy(buf[w..], a.digits[0..<a.count]); w += copy(buf[w..], a.digits[0..a.count]);
w += digit_zero(buf[w ..< w+a.decimal_point-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 // trim trailing zeros
proc trim(a: ^Decimal) { trim :: proc(a: ^Decimal) {
for a.count > 0 && a.digits[a.count-1] == '0' { for a.count > 0 && a.digits[a.count-1] == '0' {
a.count--; a.count -= 1;
} }
if a.count == 0 { if a.count == 0 {
a.decimal_point = 0; a.decimal_point = 0;
@@ -56,21 +56,21 @@ proc trim(a: ^Decimal) {
} }
proc assign(a: ^Decimal, i: u64) { assign :: proc(a: ^Decimal, i: u64) {
var buf: [32]u8; buf: [32]u8;
var n = 0; n := 0;
for i > 0 { for i > 0 {
var j = i/10; j := i/10;
i -= 10*j; i -= 10*j;
buf[n] = u8('0'+i); buf[n] = u8('0'+i);
n++; n+=1;
i = j; i = j;
} }
a.count = 0; a.count = 0;
for n--; n >= 0; n-- { for n -= 1; n >= 0; n -= 1 {
a.digits[a.count] = buf[n]; a.digits[a.count] = buf[n];
a.count++; a.count+=1;
} }
a.decimal_point = a.count; a.decimal_point = a.count;
trim(a); trim(a);
@@ -78,12 +78,12 @@ proc assign(a: ^Decimal, i: u64) {
proc shift_right(a: ^Decimal, k: uint) { shift_right :: proc(a: ^Decimal, k: uint) {
var r = 0; // read index r := 0; // read index
var w = 0; // write index w := 0; // write index
var n: uint; n: uint;
for ; n>>k == 0; r++ { for ; n>>k == 0; r+=1 {
if r >= a.count { if r >= a.count {
if n == 0 { if n == 0 {
// Just in case // Just in case
@@ -92,32 +92,32 @@ proc shift_right(a: ^Decimal, k: uint) {
} }
for n>>k == 0 { for n>>k == 0 {
n = n * 10; n = n * 10;
r++; r+=1;
} }
break; break;
} }
var c = uint(a.digits[r]); c := uint(a.digits[r]);
n = n*10 + c - '0'; n = n*10 + c - '0';
} }
a.decimal_point -= r-1; a.decimal_point -= r-1;
var mask: uint = (1<<k) - 1; mask: uint = (1<<k) - 1;
for ; r < a.count; r++ { for ; r < a.count; r+=1 {
var c = uint(a.digits[r]); c := uint(a.digits[r]);
var dig = n>>k; dig := n>>k;
n &= mask; n &= mask;
a.digits[w] = u8('0' + dig); a.digits[w] = u8('0' + dig);
w++; w+=1;
n = n*10 + c - '0'; n = n*10 + c - '0';
} }
for n > 0 { for n > 0 {
var dig = n>>k; dig := n>>k;
n &= mask; n &= mask;
if w < len(a.digits) { if w < len(a.digits) {
a.digits[w] = u8('0' + dig); a.digits[w] = u8('0' + dig);
w++; w+=1;
} else if dig > 0 { } else if dig > 0 {
a.trunc = true; a.trunc = true;
} }
@@ -129,18 +129,18 @@ proc shift_right(a: ^Decimal, k: uint) {
trim(a); trim(a);
} }
proc shift_left(a: ^Decimal, k: uint) { shift_left :: proc(a: ^Decimal, k: uint) {
var delta = int(k/4); delta := int(k/4);
var r = a.count; // read index r := a.count; // read index
var w = a.count+delta; // write index w := a.count+delta; // write index
var n: uint; n: uint;
for r--; r >= 0; r-- { for r -= 1; r >= 0; r -= 1 {
n += (uint(a.digits[r]) - '0') << k; n += (uint(a.digits[r]) - '0') << k;
var quo = n/10; quo := n/10;
var rem = n - 10*quo; rem := n - 10*quo;
w--; w -= 1;
if w < len(a.digits) { if w < len(a.digits) {
a.digits[w] = u8('0' + rem); a.digits[w] = u8('0' + rem);
} else if rem != 0 { } else if rem != 0 {
@@ -150,9 +150,9 @@ proc shift_left(a: ^Decimal, k: uint) {
} }
for n > 0 { for n > 0 {
var quo = n/10; quo := n/10;
var rem = n - 10*quo; rem := n - 10*quo;
w--; w -= 1;
if 0 <= w && w < len(a.digits) { if 0 <= w && w < len(a.digits) {
a.digits[w] = u8('0' + rem); a.digits[w] = u8('0' + rem);
} else if rem != 0 { } else if rem != 0 {
@@ -167,11 +167,9 @@ proc shift_left(a: ^Decimal, k: uint) {
trim(a); trim(a);
} }
proc shift(a: ^Decimal, k: int) { shift :: proc(a: ^Decimal, k: int) {
const ( uint_size :: 8*size_of(uint);
uint_size = 8*size_of(uint); max_shift :: uint_size-4;
max_shift = uint_size-4;
)
match { match {
case a.count == 0: 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 nd < 0 || nd >= a.count { return false ; }
if a.digits[nd] == '5' && nd+1 == a.count { 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 nd > 0 && (a.digits[nd-1]-'0')%2 != 0;
} }
return a.digits[nd] >= '5'; 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 nd < 0 || nd >= a.count { return; }
if can_round_up(a, nd) { if can_round_up(a, nd) {
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; } if nd < 0 || nd >= a.count { return; }
for var i = nd-1; i >= 0; i-- { for i := nd-1; i >= 0; i -= 1 {
if var c = a.digits[i]; c < '9' { if c := a.digits[i]; c < '9' {
a.digits[i]++; a.digits[i]+=1;
a.count = i+1; a.count = i+1;
return; return;
} }
@@ -226,10 +224,10 @@ proc round_up(a: ^Decimal, nd: int) {
// Number is just 9s // Number is just 9s
a.digits[0] = '1'; a.digits[0] = '1';
a.count = 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; } if nd < 0 || nd >= a.count { return; }
a.count = nd; a.count = nd;
trim(a); trim(a);
@@ -237,21 +235,21 @@ proc round_down(a: ^Decimal, nd: int) {
// Extract integer part, rounded appropriately. There are no guarantees about overflow. // 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 { if a.decimal_point > 20 {
return 0xffff_ffff_ffff_ffff; return 0xffff_ffff_ffff_ffff;
} }
var i: int; i: int = 0;
var n: u64 = 0; n: u64 = 0;
var m = min(a.decimal_point, a.count); m := min(a.decimal_point, a.count);
for i = 0; i < m; i++ { for ; i < m; i += 1 {
n = n*10 + u64(a.digits[i]-'0'); n = n*10 + u64(a.digits[i]-'0');
} }
for ; i < a.decimal_point; i++ { for ; i < a.decimal_point; i += 1 {
n *= 10; n *= 10;
} }
if can_round_up(a, a.decimal_point) { if can_round_up(a, a.decimal_point) {
n++; n+=1;
} }
return n; return n;
} }
+402 -391
View File
File diff suppressed because it is too large Load Diff
+46 -54
View File
@@ -1,65 +1,63 @@
proc crc32(data: []u8) -> u32 { import "mem.odin";
var result = ~u32(0);
crc32 :: proc(data: []u8) -> u32 {
result := ~u32(0);
for b in data { for b in data {
result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff]; result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff];
} }
return ~result; return ~result;
} }
proc crc64(data: []u8) -> u64 { crc64 :: proc(data: []u8) -> u64 {
var result = ~u64(0); result := ~u64(0);
for b in data { for b in data {
result = result>>8 ~ _crc64_table[(result ~ u64(b)) & 0xff]; result = result>>8 ~ _crc64_table[(result ~ u64(b)) & 0xff];
} }
return ~result; return ~result;
} }
proc fnv32(data: []u8) -> u32 { fnv32 :: proc(data: []u8) -> u32 {
var h: u32 = 0x811c9dc5; h: u32 = 0x811c9dc5;
for b in data { for b in data {
h = (h * 0x01000193) ~ u32(b); h = (h * 0x01000193) ~ u32(b);
} }
return h; return h;
} }
proc fnv64(data: []u8) -> u64 { fnv64 :: proc(data: []u8) -> u64 {
var h: u64 = 0xcbf29ce484222325; h: u64 = 0xcbf29ce484222325;
for b in data { for b in data {
h = (h * 0x100000001b3) ~ u64(b); h = (h * 0x100000001b3) ~ u64(b);
} }
return h; return h;
} }
proc fnv32a(data: []u8) -> u32 { fnv32a :: proc(data: []u8) -> u32 {
var h: u32 = 0x811c9dc5; h: u32 = 0x811c9dc5;
for b in data { for b in data {
h = (h ~ u32(b)) * 0x01000193; h = (h ~ u32(b)) * 0x01000193;
} }
return h; return h;
} }
proc fnv64a(data: []u8) -> u64 { fnv64a :: proc(data: []u8) -> u64 {
var h: u64 = 0xcbf29ce484222325; h: u64 = 0xcbf29ce484222325;
for b in data { for b in data {
h = (h ~ u64(b)) * 0x100000001b3; h = (h ~ u64(b)) * 0x100000001b3;
} }
return h; return h;
} }
proc murmur32(data: []u8) -> u32 { murmur32 :: proc(data: []u8) -> u32 {
const ( c1_32: u32 : 0xcc9e2d51;
c1_32: u32 = 0xcc9e2d51; c2_32: u32 : 0x1b873593;
c2_32: u32 = 0x1b873593;
)
var ( h1: u32 = 0;
h1: u32 = 0; nblocks := len(data)/4;
nblocks = len(data)/4; p := &data[0];
p = &data[0]; p1 := p + 4*nblocks;
p1 = p + 4*nblocks;
)
for ; p < p1; p += 4 { for ; p < p1; p += 4 {
var k1 = ^u32(p)^; k1 := (cast(^u32)p)^;
k1 *= c1_32; k1 *= c1_32;
k1 = (k1 << 15) | (k1 >> 17); k1 = (k1 << 15) | (k1 >> 17);
@@ -70,8 +68,8 @@ proc murmur32(data: []u8) -> u32 {
h1 = h1*5 + 0xe6546b64; h1 = h1*5 + 0xe6546b64;
} }
var tail = data[nblocks*4 ..]; tail := data[nblocks*4 ..];
var k1: u32; k1: u32;
match len(tail)&3 { match len(tail)&3 {
case 3: case 3:
k1 ~= u32(tail[2]) << 16; k1 ~= u32(tail[2]) << 16;
@@ -98,20 +96,18 @@ proc murmur32(data: []u8) -> u32 {
return h1; return h1;
} }
proc murmur64(data: []u8) -> u64 { murmur64 :: proc(data: []u8) -> u64 {
const SEED = 0x9747b28c; SEED :: 0x9747b28c;
when size_of(int) == 8 { when size_of(int) == 8 {
const ( m :: 0xc6a4a7935bd1e995;
m = 0xc6a4a7935bd1e995; r :: 47;
r = 47;
)
var h: u64 = SEED ~ (u64(len(data)) * m); h: u64 = SEED ~ (u64(len(data)) * m);
var data64 = slice_ptr(^u64(&data[0]), len(data)/size_of(u64)); data64 := mem.slice_ptr(cast(^u64)&data[0], len(data)/size_of(u64));
for _, i in data64 { for _, i in data64 {
var k = data64[i]; k := data64[i];
k *= m; k *= m;
k ~= k>>r; k ~= k>>r;
@@ -139,22 +135,18 @@ proc murmur64(data: []u8) -> u64 {
return h; return h;
} else { } else {
const ( m :: 0x5bd1e995;
m = 0x5bd1e995; r :: 24;
r = 24;
)
var ( h1 := u32(SEED) ~ u32(len(data));
h1 = u32(SEED) ~ u32(len(data)); h2 := u32(SEED) >> 32;
h2 = u32(SEED) >> 32; data32 := mem.slice_ptr(cast(^u32)&data[0], len(data)/size_of(u32));
data32 = slice_ptr(^u32(&data[0]), len(data)/size_of(u32)); len := len(data);
len = len(data); i := 0;
i = 0;
)
for len >= 8 { for len >= 8 {
var k1, k2: u32; k1, k2: u32;
k1 = data32[i]; i++; k1 = data32[i]; i += 1;
k1 *= m; k1 *= m;
k1 ~= k1>>r; k1 ~= k1>>r;
k1 *= m; k1 *= m;
@@ -162,7 +154,7 @@ proc murmur64(data: []u8) -> u64 {
h1 ~= k1; h1 ~= k1;
len -= 4; len -= 4;
k2 = data32[i]; i++; k2 = data32[i]; i += 1;
k2 *= m; k2 *= m;
k2 ~= k2>>r; k2 ~= k2>>r;
k2 *= m; k2 *= m;
@@ -172,8 +164,8 @@ proc murmur64(data: []u8) -> u64 {
} }
if len >= 4 { if len >= 4 {
var k1: u32; k1: u32;
k1 = data32[i]; i++; k1 = data32[i]; i += 1;
k1 *= m; k1 *= m;
k1 ~= k1>>r; k1 ~= k1>>r;
k1 *= m; k1 *= m;
@@ -183,7 +175,7 @@ proc murmur64(data: []u8) -> u64 {
} }
// TODO(bill): Fix this // 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 { match len {
case 3: case 3:
h2 ~= u32(data8[2]) << 16; 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, 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -276,7 +268,7 @@ var _crc32_table = [256]u32{
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
}; };
var _crc64_table = [256]u64{ _crc64_table := [256]u64{
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5, 0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a, 0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b, 0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
+163 -180
View File
@@ -1,97 +1,94 @@
const ( TAU :: 6.28318530717958647692528676655900576;
TAU = 6.28318530717958647692528676655900576; PI :: 3.14159265358979323846264338327950288;
PI = 3.14159265358979323846264338327950288; ONE_OVER_TAU :: 0.636619772367581343075535053490057448;
ONE_OVER_TAU = 0.636619772367581343075535053490057448; ONE_OVER_PI :: 0.159154943091895335768883763372514362;
ONE_OVER_PI = 0.159154943091895335768883763372514362;
E = 2.71828182845904523536; E :: 2.71828182845904523536;
SQRT_TWO = 1.41421356237309504880168872420969808; SQRT_TWO :: 1.41421356237309504880168872420969808;
SQRT_THREE = 1.73205080756887729352744634150587236; SQRT_THREE :: 1.73205080756887729352744634150587236;
SQRT_FIVE = 2.23606797749978969640917366873127623; SQRT_FIVE :: 2.23606797749978969640917366873127623;
LOG_TWO = 0.693147180559945309417232121458176568; LOG_TWO :: 0.693147180559945309417232121458176568;
LOG_TEN = 2.30258509299404568401799145468436421; LOG_TEN :: 2.30258509299404568401799145468436421;
EPSILON = 1.19209290e-7; EPSILON :: 1.19209290e-7;
τ = TAU; τ :: TAU;
π = PI; π :: PI;
)
type (
Vec2 [vector 2]f32;
Vec3 [vector 3]f32;
Vec4 [vector 4]f32;
// Column major Vec2 :: [vector 2]f32;
Mat2 [2][2]f32; Vec3 :: [vector 3]f32;
Mat3 [3][3]f32; Vec4 :: [vector 4]f32;
Mat4 [4][4]f32;
Complex complex64; // Column major
) Mat2 :: [2][2]f32;
Mat3 :: [3][3]f32;
Mat4 :: [4][4]f32;
Complex :: complex64;
foreign __llvm_core { foreign __llvm_core {
proc sqrt(x: f32) -> f32 #link_name "llvm.sqrt.f32"; sqrt :: proc(x: f32) -> f32 #link_name "llvm.sqrt.f32" ---;
proc sqrt(x: f64) -> f64 #link_name "llvm.sqrt.f64"; sqrt :: proc(x: f64) -> f64 #link_name "llvm.sqrt.f64" ---;
proc sin (θ: f32) -> f32 #link_name "llvm.sin.f32"; sin :: proc(θ: f32) -> f32 #link_name "llvm.sin.f32" ---;
proc sin (θ: f64) -> f64 #link_name "llvm.sin.f64"; sin :: proc(θ: f64) -> f64 #link_name "llvm.sin.f64" ---;
proc cos (θ: f32) -> f32 #link_name "llvm.cos.f32"; cos :: proc(θ: f32) -> f32 #link_name "llvm.cos.f32" ---;
proc cos (θ: f64) -> f64 #link_name "llvm.cos.f64"; cos :: proc(θ: f64) -> f64 #link_name "llvm.cos.f64" ---;
proc pow (x, power: f32) -> f32 #link_name "llvm.pow.f32"; pow :: proc(x, power: f32) -> f32 #link_name "llvm.pow.f32" ---;
proc pow (x, power: f64) -> f64 #link_name "llvm.pow.f64"; pow :: proc(x, power: f64) -> f64 #link_name "llvm.pow.f64" ---;
proc fmuladd(a, b, c: f32) -> f32 #link_name "llvm.fmuladd.f32"; fmuladd :: proc(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: f64) -> f64 #link_name "llvm.fmuladd.f64" ---;
} }
proc tan (θ: f32) -> f32 #inline { return sin(θ)/cos(θ); } tan :: proc(θ: f32) -> f32 #inline do return sin(θ)/cos(θ);
proc tan (θ: f64) -> f64 #inline { 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; } lerp :: proc(a, b, t: f32) -> (x: f32) do return a*(1-t) + b*t;
proc lerp (a, b, t: f64) -> (x: f64) { return a*(1-t) + b*t; } lerp :: proc(a, b, t: f64) -> (x: f64) do return a*(1-t) + b*t;
proc unlerp(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); } unlerp :: proc(a, b, x: f32) -> (t: f32) do return (x-a)/(b-a);
proc unlerp(a, b, x: f64) -> (t: f64) { 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; } sign :: proc(x: f32) -> f32 { if x >= 0 do return +1; return -1; }
proc sign(x: f64) -> f64 { return x >= 0 ? +1 : -1; } sign :: proc(x: f64) -> f64 { if x >= 0 do return +1; return -1; }
proc copy_sign(x, y: f32) -> f32 { copy_sign :: proc(x, y: f32) -> f32 {
var ix = transmute(u32, x); ix := transmute(u32)x;
var iy = transmute(u32, y); iy := transmute(u32)y;
ix &= 0x7fff_ffff; ix &= 0x7fff_ffff;
ix |= iy & 0x8000_0000; ix |= iy & 0x8000_0000;
return transmute(f32, ix); return transmute(f32)ix;
} }
proc copy_sign(x, y: f64) -> f64 { copy_sign :: proc(x, y: f64) -> f64 {
var ix = transmute(u64, x); ix := transmute(u64)x;
var iy = transmute(u64, y); iy := transmute(u64)y;
ix &= 0x7fff_ffff_ffff_ff; ix &= 0x7fff_ffff_ffff_ff;
ix |= iy & 0x8000_0000_0000_0000; 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); } round :: proc(x: f32) -> f32 { if x >= 0 do return floor(x + 0.5); return ceil(x - 0.5); }
proc round (x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : 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 floor :: proc(x: f32) -> f32 { if x >= 0 do return f32(i64(x)); return 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: 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 ceil :: proc(x: f32) -> f32 { if x < 0 do return f32(i64(x)); return 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: 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; } remainder :: proc(x, y: f32) -> f32 do return x - round(x/y) * y;
proc remainder(x, y: f64) -> f64 { 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 { mod :: proc(x, y: f32) -> f32 {
var result: f32; result: f32;
y = abs(y); y = abs(y);
result = remainder(abs(x), y); result = remainder(abs(x), y);
if sign(result) < 0 { if sign(result) < 0 {
@@ -99,8 +96,8 @@ proc mod(x, y: f32) -> f32 {
} }
return copy_sign(result, x); return copy_sign(result, x);
} }
proc mod(x, y: f64) -> f64 { mod :: proc(x, y: f64) -> f64 {
var result: f64; result: f64;
y = abs(y); y = abs(y);
result = remainder(abs(x), y); result = remainder(abs(x), y);
if sign(result) < 0 { if sign(result) < 0 {
@@ -110,57 +107,51 @@ proc mod(x, y: f64) -> f64 {
} }
proc to_radians(degrees: f32) -> f32 { return degrees * TAU / 360; } to_radians :: proc(degrees: f32) -> f32 do return degrees * TAU / 360;
proc to_degrees(radians: f32) -> f32 { return radians * 360 / TAU; } 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; } dot :: proc(a, b: $T/[vector 2]$E) -> E { 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; } dot :: proc(a, b: $T/[vector 3]$E) -> E { 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 4]$E) -> E { c := a*b; return c.x + c.y + c.z + c.w; }
proc cross(x, y: Vec3) -> Vec3 { cross :: proc(x, y: $T/[vector 3]$E) -> T {
var a = swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1); a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
var b = swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0); b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
return a - b; return T(a - b);
} }
proc mag(v: Vec2) -> f32 { return sqrt(dot(v, v)); } mag :: proc(v: $T/[vector 2]$E) -> E do return sqrt(dot(v, v));
proc mag(v: Vec3) -> f32 { return sqrt(dot(v, v)); } mag :: proc(v: $T/[vector 3]$E) -> E do return sqrt(dot(v, v));
proc mag(v: Vec4) -> f32 { 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); } norm :: proc(v: $T/[vector 2]$E) -> T do return v / mag(v);
proc norm(v: Vec3) -> Vec3 { return v / mag(v); } norm :: proc(v: $T/[vector 3]$E) -> T do return v / mag(v);
proc norm(v: Vec4) -> Vec4 { return v / mag(v); } norm :: proc(v: $T/[vector 4]$E) -> T do return v / mag(v);
proc norm0(v: Vec2) -> Vec2 { norm0 :: proc(v: $T/[vector 2]$E) -> T {
var m = mag(v); m := mag(v);
if m == 0 { if m == 0 do return 0;
return 0; return v/m;
}
return v / m;
} }
proc norm0(v: Vec3) -> Vec3 { norm0 :: proc(v: $T/[vector 3]$E) -> T {
var m = mag(v); m := mag(v);
if m == 0 { if m == 0 do return 0;
return 0; return v/m;
}
return v / m;
} }
proc norm0(v: Vec4) -> Vec4 { norm0 :: proc(v: $T/[vector 4]$E) -> T {
var m = mag(v); m := mag(v);
if m == 0 { if m == 0 do return 0;
return 0; return v/m;
}
return v / m;
} }
proc mat4_identity() -> Mat4 { mat4_identity :: proc() -> Mat4 {
return Mat4{ return Mat4{
{1, 0, 0, 0}, {1, 0, 0, 0},
{0, 1, 0, 0}, {0, 1, 0, 0},
@@ -169,19 +160,19 @@ proc mat4_identity() -> Mat4 {
}; };
} }
proc mat4_transpose(m: Mat4) -> Mat4 { mat4_transpose :: proc(m: Mat4) -> Mat4 {
for j in 0..<4 { for j in 0..4 {
for i in 0..<4 { for i in 0..4 {
m[i][j], m[j][i] = m[j][i], m[i][j]; m[i][j], m[j][i] = m[j][i], m[i][j];
} }
} }
return m; return m;
} }
proc mul(a, b: Mat4) -> Mat4 { mul :: proc(a, b: Mat4) -> Mat4 {
var c: Mat4; c: Mat4;
for j in 0..<4 { for j in 0..4 {
for i in 0..<4 { for i in 0..4 {
c[j][i] = a[0][i]*b[j][0] + c[j][i] = a[0][i]*b[j][0] +
a[1][i]*b[j][1] + a[1][i]*b[j][1] +
a[2][i]*b[j][2] + a[2][i]*b[j][2] +
@@ -191,7 +182,7 @@ proc mul(a, b: Mat4) -> Mat4 {
return c; return c;
} }
proc mul(m: Mat4, v: Vec4) -> Vec4 { mul :: proc(m: Mat4, v: Vec4) -> Vec4 {
return Vec4{ return Vec4{
m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w, m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w, m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
@@ -200,30 +191,29 @@ proc mul(m: Mat4, v: Vec4) -> Vec4 {
}; };
} }
proc inverse(m: Mat4) -> Mat4 { inverse :: proc(m: Mat4) -> Mat4 {
var o: 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][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); 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][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); 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][1] * o[0][1] +
m[0][2] * o[0][2] + m[0][2] * o[0][2] +
m[0][3] * o[0][3]); m[0][3] * o[0][3]);
@@ -271,8 +261,8 @@ proc inverse(m: Mat4) -> Mat4 {
} }
proc mat4_translate(v: Vec3) -> Mat4 { mat4_translate :: proc(v: Vec3) -> Mat4 {
var m = mat4_identity(); m := mat4_identity();
m[3][0] = v.x; m[3][0] = v.x;
m[3][1] = v.y; m[3][1] = v.y;
m[3][2] = v.z; m[3][2] = v.z;
@@ -280,16 +270,14 @@ proc mat4_translate(v: Vec3) -> Mat4 {
return m; return m;
} }
proc mat4_rotate(v: Vec3, angle_radians: f32) -> Mat4 { mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
var ( c := cos(angle_radians);
c = cos(angle_radians); s := sin(angle_radians);
s = sin(angle_radians);
a = norm(v); a := norm(v);
t = a * (1-c); t := a * (1-c);
rot = mat4_identity(); rot := mat4_identity();
)
rot[0][0] = c + t.x*a.x; rot[0][0] = c + t.x*a.x;
rot[0][1] = 0 + t.x*a.y + s*a.z; 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; return rot;
} }
proc scale(m: Mat4, v: Vec3) -> Mat4 { scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
m[0][0] *= v.x; m[0][0] *= v.x;
m[1][1] *= v.y; m[1][1] *= v.y;
m[2][2] *= v.z; m[2][2] *= v.z;
return m; return m;
} }
proc scale(m: Mat4, s: f32) -> Mat4 { scale :: proc(m: Mat4, s: f32) -> Mat4 {
m[0][0] *= s; m[0][0] *= s;
m[1][1] *= s; m[1][1] *= s;
m[2][2] *= s; m[2][2] *= s;
@@ -324,12 +312,10 @@ proc scale(m: Mat4, s: f32) -> Mat4 {
} }
proc look_at(eye, centre, up: Vec3) -> Mat4 { look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
var ( f := norm(centre - eye);
f = norm(centre - eye); s := norm(cross(f, up));
s = norm(cross(f, up)); u := cross(s, f);
u = cross(s, f);
)
return Mat4{ return Mat4{
{+s.x, +u.x, -f.x, 0}, {+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 { perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
var ( m: Mat4;
m: Mat4; tan_half_fovy := tan(0.5 * fovy);
tan_half_fovy = tan(0.5 * fovy);
)
m[0][0] = 1.0 / (aspect*tan_half_fovy); m[0][0] = 1.0 / (aspect*tan_half_fovy);
m[1][1] = 1.0 / (tan_half_fovy); m[1][1] = 1.0 / (tan_half_fovy);
m[2][2] = -(far + near) / (far - near); m[2][2] = -(far + near) / (far - near);
@@ -353,8 +338,8 @@ proc perspective(fovy, aspect, near, far: f32) -> Mat4 {
} }
proc ortho3d(left, right, bottom, top, near, far: f32) -> Mat4 { ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
var m = mat4_identity(); m := mat4_identity();
m[0][0] = +2.0 / (right - left); m[0][0] = +2.0 / (right - left);
m[1][1] = +2.0 / (top - bottom); m[1][1] = +2.0 / (top - bottom);
m[2][2] = -2.0 / (far - near); 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_DIG = 6; F32_EPSILON :: 1.192092896e-07;
F32_EPSILON = 1.192092896e-07; F32_GUARD :: 0;
F32_GUARD = 0; F32_MANT_DIG :: 24;
F32_MANT_DIG = 24; F32_MAX :: 3.402823466e+38;
F32_MAX = 3.402823466e+38; F32_MAX_10_EXP :: 38;
F32_MAX_10_EXP = 38; F32_MAX_EXP :: 128;
F32_MAX_EXP = 128; F32_MIN :: 1.175494351e-38;
F32_MIN = 1.175494351e-38; F32_MIN_10_EXP :: -37;
F32_MIN_10_EXP = -37; F32_MIN_EXP :: -125;
F32_MIN_EXP = -125; F32_NORMALIZE :: 0;
F32_NORMALIZE = 0; F32_RADIX :: 2;
F32_RADIX = 2; F32_ROUNDS :: 1;
F32_ROUNDS = 1;
F64_DIG = 15; // # of decimal digits of precision F64_DIG :: 15; // # of decimal digits of precision
F64_EPSILON = 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0 F64_EPSILON :: 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0
F64_MANT_DIG = 53; // # of bits in mantissa F64_MANT_DIG :: 53; // # of bits in mantissa
F64_MAX = 1.7976931348623158e+308; // max value F64_MAX :: 1.7976931348623158e+308; // max value
F64_MAX_10_EXP = 308; // max decimal exponent F64_MAX_10_EXP :: 308; // max decimal exponent
F64_MAX_EXP = 1024; // max binary exponent F64_MAX_EXP :: 1024; // max binary exponent
F64_MIN = 2.2250738585072014e-308; // min positive value F64_MIN :: 2.2250738585072014e-308; // min positive value
F64_MIN_10_EXP = -307; // min decimal exponent F64_MIN_10_EXP :: -307; // min decimal exponent
F64_MIN_EXP = -1021; // min binary exponent F64_MIN_EXP :: -1021; // min binary exponent
F64_RADIX = 2; // exponent radix F64_RADIX :: 2; // exponent radix
F64_ROUNDS = 1; // addition rounding: near F64_ROUNDS :: 1; // addition rounding: near
)
+122 -116
View File
@@ -1,78 +1,90 @@
import ( import (
"fmt.odin"; "fmt.odin";
"os.odin"; "os.odin";
"raw.odin";
) )
foreign __llvm_core { foreign __llvm_core {
proc swap(b: u16) -> u16 #link_name "llvm.bswap.i16"; swap :: proc(b: u16) -> u16 #link_name "llvm.bswap.i16" ---;
proc swap(b: u32) -> u32 #link_name "llvm.bswap.i32"; swap :: proc(b: u32) -> u32 #link_name "llvm.bswap.i32" ---;
proc swap(b: u64) -> u64 #link_name "llvm.bswap.i64"; 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); 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); 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); 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); 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))); 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; } slice_to_bytes :: proc(slice: []$T) -> []u8 #cc_contextless {
proc megabytes(x: int) -> int #inline { return kilobytes(x) * 1024; } s := cast(^raw.Slice)&slice;
proc gigabytes(x: int) -> int #inline { return megabytes(x) * 1024; } s.len *= size_of(T);
proc terabytes(x: int) -> int #inline { return gigabytes(x) * 1024; } s.cap *= size_of(T);
return (cast(^[]u8)s)^;
}
proc is_power_of_two(x: int) -> bool {
if x <= 0 { kilobytes :: proc(x: int) -> int #inline #cc_contextless { return (x) * 1024; }
return false; 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; 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)); assert(is_power_of_two(align));
var a = uint(align); a := uint(align);
var p = uint(ptr); p := uint(ptr);
var modulo = p & (a-1); modulo := p & (a-1);
if modulo != 0 { if modulo != 0 do p += a - modulo;
p += a - modulo;
}
return rawptr(p); return rawptr(p);
} }
type AllocationHeader struct { AllocationHeader :: struct {
size: int, 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; 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++ { for i in 0..n {
(ptr+i)^ = -1; (ptr+i)^ = ~uint(0);
} }
} }
proc allocation_header(data: rawptr) -> ^AllocationHeader { allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
if data == nil { if data == nil do return nil;
return nil; p := cast(^uint)data;
} for (p-1)^ == ~uint(0) do p = (p-1);
var p = ^int(data); return cast(^AllocationHeader)(p-1);
for (p-1)^ == -1 {
p = (p-1);
}
return ^AllocationHeader(p-1);
} }
@@ -80,36 +92,36 @@ proc allocation_header(data: rawptr) -> ^AllocationHeader {
// Custom allocators // Custom allocators
type (
Arena struct {
backing: Allocator,
offset: int,
memory: []u8,
temp_count: int,
}
ArenaTempMemory struct { Arena :: struct {
arena: ^Arena, backing: Allocator;
original_count: int, 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{}; backing = Allocator{};
memory = data[0..<0]; memory = data[..0];
temp_count = 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; backing = context.allocator;
memory = make([]u8, size); memory = make([]u8, size);
temp_count = 0; temp_count = 0;
} }
proc free_arena(using a: ^Arena) { destroy_arena :: proc(using a: ^Arena) {
if backing.procedure != nil { if backing.procedure != nil {
push_allocator backing { push_allocator backing {
free(memory); 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{ return Allocator{
procedure = arena_allocator_proc, procedure = arena_allocator_proc,
data = arena, data = arena,
}; };
} }
proc arena_allocator_proc(allocator_data: rawptr, mode: AllocatorMode, arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
size, alignment: int, size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr { old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
using AllocatorMode; using Allocator.Mode;
var arena = ^Arena(allocator_data); arena := cast(^Arena)allocator_data;
match mode { match mode {
case Alloc: case Alloc:
var total_size = size + alignment; total_size := size + alignment;
if arena.offset + total_size > len(arena.memory) { if arena.offset + total_size > len(arena.memory) {
fmt.fprintln(os.stderr, "Arena out of memory"); fmt.fprintln(os.stderr, "Arena out of memory");
return nil; 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; arena.offset += total_size;
return zero(ptr, size); return zero(ptr, size);
@@ -161,19 +173,19 @@ proc arena_allocator_proc(allocator_data: rawptr, mode: AllocatorMode,
return nil; return nil;
} }
proc begin_arena_temp_memory(a: ^Arena) -> ArenaTempMemory { begin_arena_temp_memory :: proc(a: ^Arena) -> ArenaTempMemory {
var tmp: ArenaTempMemory; tmp: ArenaTempMemory;
tmp.arena = a; tmp.arena = a;
tmp.original_count = len(a.memory); tmp.original_count = len(a.memory);
a.temp_count++; a.temp_count += 1;
return tmp; 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(len(arena.memory) >= original_count);
assert(arena.temp_count > 0); assert(arena.temp_count > 0);
arena.memory = arena.memory[0..<original_count]; arena.memory = arena.memory[..original_count];
arena.temp_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 { align_of_type_info :: proc(type_info: ^Type_Info) -> int {
proc prev_pow2(n: i64) -> i64 { prev_pow2 :: proc(n: i64) -> i64 {
if n <= 0 { if n <= 0 do return 0;
return 0;
}
n |= n >> 1; n |= n >> 1;
n |= n >> 2; n |= n >> 2;
n |= n >> 4; n |= n >> 4;
@@ -196,16 +206,18 @@ proc align_of_type_info(type_info: ^TypeInfo) -> int {
return n - (n >> 1); return n - (n >> 1);
} }
const WORD_SIZE = size_of(int); WORD_SIZE :: size_of(int);
const MAX_ALIGN = size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants? MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
using TypeInfo; using Type_Info;
match info in type_info { match info in type_info.variant {
case Named: case Named:
return align_of_type_info(info.base); return align_of_type_info(info.base);
case Integer: case Integer:
return info.size; return type_info.align;
case Rune:
return type_info.align;
case Float: case Float:
return info.size; return type_info.align;
case String: case String:
return WORD_SIZE; return WORD_SIZE;
case Boolean: case Boolean:
@@ -218,23 +230,21 @@ proc align_of_type_info(type_info: ^TypeInfo) -> int {
return WORD_SIZE; return WORD_SIZE;
case Array: case Array:
return align_of_type_info(info.elem); return align_of_type_info(info.elem);
case DynamicArray: case Dynamic_Array:
return WORD_SIZE; return WORD_SIZE;
case Slice: case Slice:
return WORD_SIZE; return WORD_SIZE;
case Vector: case Vector:
var size = size_of_type_info(info.elem); size := size_of_type_info(info.elem);
var count = int(max(prev_pow2(i64(info.count)), 1)); count := int(max(prev_pow2(i64(info.count)), 1));
var total = size * count; total := size * count;
return clamp(total, 1, MAX_ALIGN); return clamp(total, 1, MAX_ALIGN);
case Tuple: case Tuple:
return info.align; return type_info.align;
case Struct: case Struct:
return info.align; return type_info.align;
case Union: case Union:
return info.align; return type_info.align;
case RawUnion:
return info.align;
case Enum: case Enum:
return align_of_type_info(info.base); return align_of_type_info(info.base);
case Map: case Map:
@@ -244,21 +254,23 @@ proc align_of_type_info(type_info: ^TypeInfo) -> int {
return 0; return 0;
} }
proc align_formula(size, align: int) -> int { align_formula :: proc(size, align: int) -> int {
var result = size + align-1; result := size + align-1;
return result - result%align; return result - result%align;
} }
proc size_of_type_info(type_info: ^TypeInfo) -> int { size_of_type_info :: proc(type_info: ^Type_Info) -> int {
const WORD_SIZE = size_of(int); WORD_SIZE :: size_of(int);
using TypeInfo; using Type_Info;
match info in type_info { match info in type_info.variant {
case Named: case Named:
return size_of_type_info(info.base); return size_of_type_info(info.base);
case Integer: case Integer:
return info.size; return type_info.size;
case Rune:
return type_info.size;
case Float: case Float:
return info.size; return type_info.size;
case String: case String:
return 2*WORD_SIZE; return 2*WORD_SIZE;
case Boolean: case Boolean:
@@ -270,33 +282,27 @@ proc size_of_type_info(type_info: ^TypeInfo) -> int {
case Procedure: case Procedure:
return WORD_SIZE; return WORD_SIZE;
case Array: case Array:
var count = info.count; count := info.count;
if count == 0 { if count == 0 do return 0;
return 0; size := size_of_type_info(info.elem);
} align := align_of_type_info(info.elem);
var size = size_of_type_info(info.elem); alignment := align_formula(size, align);
var align = align_of_type_info(info.elem);
var alignment = align_formula(size, align);
return alignment*(count-1) + size; return alignment*(count-1) + size;
case DynamicArray: case Dynamic_Array:
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator); return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
case Slice: case Slice:
return 2*WORD_SIZE; return 2*WORD_SIZE;
case Vector: case Vector:
var count = info.count; count := info.count;
if count == 0 { if count == 0 do return 0;
return 0; size := size_of_type_info(info.elem);
} align := align_of_type_info(info.elem);
var size = size_of_type_info(info.elem); alignment := align_formula(size, align);
var align = align_of_type_info(info.elem);
var alignment = align_formula(size, align);
return alignment*(count-1) + size; return alignment*(count-1) + size;
case Struct: case Struct:
return info.size; return type_info.size;
case Union: case Union:
return info.size; return type_info.size;
case RawUnion:
return info.size;
case Enum: case Enum:
return size_of_type_info(info.base); return size_of_type_info(info.base);
case Map: case Map:
+37 -35
View File
@@ -8,53 +8,55 @@ import (
) )
import_load "opengl_constants.odin"; import_load "opengl_constants.odin";
_ := compile_assert(ODIN_OS != "osx");
foreign lib { foreign lib {
proc Clear (mask: u32) #link_name "glClear"; Clear :: proc(mask: u32) #link_name "glClear" ---;
proc ClearColor (r, g, b, a: f32) #link_name "glClearColor"; ClearColor :: proc(r, g, b, a: f32) #link_name "glClearColor" ---;
proc Begin (mode: i32) #link_name "glBegin"; Begin :: proc(mode: i32) #link_name "glBegin" ---;
proc End () #link_name "glEnd"; End :: proc() #link_name "glEnd" ---;
proc Finish () #link_name "glFinish"; Finish :: proc() #link_name "glFinish" ---;
proc BlendFunc (sfactor, dfactor: i32) #link_name "glBlendFunc"; BlendFunc :: proc(sfactor, dfactor: i32) #link_name "glBlendFunc" ---;
proc Enable (cap: i32) #link_name "glEnable"; Enable :: proc(cap: i32) #link_name "glEnable" ---;
proc Disable (cap: i32) #link_name "glDisable"; Disable :: proc(cap: i32) #link_name "glDisable" ---;
proc GenTextures (count: i32, result: ^u32) #link_name "glGenTextures"; GenTextures :: proc(count: i32, result: ^u32) #link_name "glGenTextures" ---;
proc DeleteTextures(count: i32, result: ^u32) #link_name "glDeleteTextures"; DeleteTextures :: proc(count: i32, result: ^u32) #link_name "glDeleteTextures"---;
proc TexParameteri (target, pname, param: i32) #link_name "glTexParameteri"; TexParameteri :: proc(target, pname, param: i32) #link_name "glTexParameteri" ---;
proc TexParameterf (target: i32, pname: i32, param: f32) #link_name "glTexParameterf"; TexParameterf :: proc(target: i32, pname: i32, param: f32) #link_name "glTexParameterf" ---;
proc BindTexture (target: i32, texture: u32) #link_name "glBindTexture"; BindTexture :: proc(target: i32, texture: u32) #link_name "glBindTexture" ---;
proc LoadIdentity () #link_name "glLoadIdentity"; LoadIdentity :: proc() #link_name "glLoadIdentity" ---;
proc Viewport (x, y, width, height: i32) #link_name "glViewport"; Viewport :: proc(x, y, width, height: i32) #link_name "glViewport" ---;
proc Ortho (left, right, bottom, top, near, far: f64) #link_name "glOrtho"; Ortho :: proc(left, right, bottom, top, near, far: f64) #link_name "glOrtho" ---;
proc Color3f (r, g, b: f32) #link_name "glColor3f"; Color3f :: proc(r, g, b: f32) #link_name "glColor3f" ---;
proc Vertex3f (x, y, z: f32) #link_name "glVertex3f"; Vertex3f :: proc(x, y, z: f32) #link_name "glVertex3f" ---;
proc GetError () -> i32 #link_name "glGetError"; GetError :: proc() -> i32 #link_name "glGetError" ---;
proc GetString (name: i32) -> ^u8 #link_name "glGetString"; GetString :: proc(name: i32) -> ^u8 #link_name "glGetString" ---;
proc GetIntegerv (name: i32, v: ^i32) #link_name "glGetIntegerv"; GetIntegerv :: proc(name: i32, v: ^i32) #link_name "glGetIntegerv" ---;
proc TexCoord2f (x, y: f32) #link_name "glTexCoord2f"; TexCoord2f :: proc(x, y: f32) #link_name "glTexCoord2f" ---;
proc TexImage2D (target, level, internal_format, TexImage2D :: proc(target, level, internal_format,
width, height, border, width, height, border,
format, type_: i32, pixels: rawptr) #link_name "glTexImage2D"; 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 { if name[len(name)-1] == 0 {
name = name[0..<len(name)-1]; name = name[..len(name)-1];
} }
// NOTE(bill): null terminated // NOTE(bill): null terminated
assert((&name[0] + len(name))^ == 0); assert((&name[0] + len(name))^ == 0);
var res = wgl.get_proc_address(&name[0]); res := wgl.get_proc_address(&name[0]);
if res == nil { if res == nil {
res = win32.get_proc_address(_libgl, &name[0]); res = win32.get_proc_address(_libgl, &name[0]);
} }
return rawptr(res); return rawptr(res);
} }
var ( // Procedures
GenBuffers: proc(count: i32, buffers: ^u32) #cc_c; GenBuffers: proc(count: i32, buffers: ^u32) #cc_c;
GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c; GenVertexArrays: proc(count: i32, buffers: ^u32) #cc_c;
GenSamplers: 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; UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c;
GetUniformLocation: proc(program: u32, name: ^u8) -> i32 #cc_c; GetUniformLocation: proc(program: u32, name: ^u8) -> i32 #cc_c;
)
proc init() {
proc set_proc_address(p: rawptr, name: string) #inline { init :: proc() {
var x = ^rawptr(p); set_proc_address :: proc(p: rawptr, name: string) #inline {
x := cast(^rawptr)p;
x^ = get_proc_address(name); x^ = get_proc_address(name);
} }
+1365 -1367
View File
File diff suppressed because it is too large Load Diff
+12 -12
View File
@@ -4,46 +4,46 @@ import_load (
"os_linux.odin" when ODIN_OS == "linux"; "os_linux.odin" when ODIN_OS == "linux";
) )
proc write_string(fd: Handle, str: string) -> (int, Errno) { write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
return write(fd, []u8(str)); return write(fd, cast([]u8)str);
} }
proc read_entire_file(name: string) -> ([]u8, bool) { read_entire_file :: proc(name: string) -> (data: []u8, success: bool) {
var fd, err = open(name, O_RDONLY, 0); fd, err := open(name, O_RDONLY, 0);
if err != 0 { if err != 0 {
return nil, false; return nil, false;
} }
defer close(fd); defer close(fd);
var length: i64; length: i64;
if length, err = file_size(fd); err != 0 { if length, err = file_size(fd); err != 0 {
return nil, false; return nil, false;
} }
if length == 0 { if length <= 0 {
return nil, true; return nil, true;
} }
var data = make([]u8, length); data := make([]u8, int(length));
if data == nil { if data == nil {
return nil, false; return nil, false;
} }
var bytes_read, read_err = read(fd, data); bytes_read, read_err := read(fd, data);
if read_err != 0 { if read_err != 0 {
free(data); free(data);
return nil, false; return nil, false;
} }
return data[0..<bytes_read], true; return data[0..bytes_read], true;
} }
proc write_entire_file(name: string, data: []u8) -> bool { write_entire_file :: proc(name: string, data: []u8) -> (sucess: bool) {
var fd, err = open(name, O_WRONLY, 0); fd, err := open(name, O_WRONLY, 0);
if err != 0 { if err != 0 {
return false; return false;
} }
defer close(fd); defer close(fd);
var bytes_written, write_err = write(fd, data); bytes_written, write_err := write(fd, data);
return write_err != 0; return write_err != 0;
} }
+151 -159
View File
@@ -4,160 +4,152 @@ foreign_system_library (
) )
import "strings.odin"; import "strings.odin";
type ( Handle :: i32;
Handle i32; File_Time :: u64;
FileTime u64; Errno :: i32;
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 ( O_RDONLY :: 0x00000;
SEEK_SET = 0; O_WRONLY :: 0x00001;
SEEK_CUR = 1; O_RDWR :: 0x00002;
SEEK_END = 2; O_CREAT :: 0x00040;
SEEK_DATA = 3; O_EXCL :: 0x00080;
SEEK_HOLE = 4; O_NOCTTY :: 0x00100;
SEEK_MAX = SEEK_HOLE; O_TRUNC :: 0x00200;
) O_NONBLOCK :: 0x00800;
const ( O_APPEND :: 0x00400;
// NOTE(zangent): These are OS specific! O_SYNC :: 0x01000;
// Do not mix these up! O_ASYNC :: 0x02000;
RTLD_LAZY = 0x001; O_CLOEXEC :: 0x80000;
RTLD_NOW = 0x002;
RTLD_BINDING_MASK = 0x3;
RTLD_GLOBAL = 0x100; 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 // "Argv" arguments converted to Odin strings
var args = _alloc_command_line_arguments(); args := _alloc_command_line_arguments();
type _FileTime struct #ordered { _File_Time :: struct #ordered {
seconds: i64, seconds: i64;
nanoseconds: i32, nanoseconds: i32;
reserved: i32, reserved: i32;
} }
// Translated from // 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 // 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. // Validity is not guaranteed.
type Stat struct #ordered { Stat :: struct #ordered {
device_id: u64, // ID of device containing file device_id: u64; // ID of device containing file
serial: u64, // File serial number serial: u64; // File serial number
nlink: u32, // Number of hard links nlink: u32; // Number of hard links
mode: u32, // Mode of the file mode: u32; // Mode of the file
uid: u32, // User ID of the file's owner uid: u32; // User ID of the file's owner
gid: u32, // Group ID of the file's group gid: u32; // Group ID of the file's group
_padding: i32, // 32 bits of padding _padding: i32; // 32 bits of padding
rdev: u64, // Device ID, if device rdev: u64; // Device ID, if device
size: i64, // Size of the file, in bytes size: i64; // Size of the file, in bytes
block_size: i64, // Optimal bllocksize for I/O block_size: i64; // Optimal bllocksize for I/O
blocks: i64, // Number of 512-byte blocks allocated blocks: i64; // Number of 512-byte blocks allocated
last_access: _FileTime, // Time of last access last_access: _File_Time; // Time of last access
modified: _FileTime, // Time of last modification modified: _File_Time; // Time of last modification
status_change: _FileTime, // Time of last status change status_change: _File_Time; // Time of last status change
_reserve1, _reserve1,
_reserve2, _reserve2,
_reserve3: i64, _reserve3: i64;
serial_numbe: u64, // File serial number...? Maybe. serial_numbe: u64; // File serial number...? Maybe.
_reserve4: i64, _reserve4: i64;
}; };
// File type // File type
const ( S_IFMT :: 0170000; // Type of file mask
S_IFMT = 0170000; // Type of file mask S_IFIFO :: 0010000; // Named pipe (fifo)
S_IFIFO = 0010000; // Named pipe (fifo) S_IFCHR :: 0020000; // Character special
S_IFCHR = 0020000; // Character special S_IFDIR :: 0040000; // Directory
S_IFDIR = 0040000; // Directory S_IFBLK :: 0060000; // Block special
S_IFBLK = 0060000; // Block special S_IFREG :: 0100000; // Regular
S_IFREG = 0100000; // Regular S_IFLNK :: 0120000; // Symbolic link
S_IFLNK = 0120000; // Symbolic link S_IFSOCK :: 0140000; // Socket
S_IFSOCK = 0140000; // Socket
// File mode // File mode
// Read, write, execute/search by owner // Read, write, execute/search by owner
S_IRWXU = 0000700; // RWX mask for owner S_IRWXU :: 0000700; // RWX mask for owner
S_IRUSR = 0000400; // R for owner S_IRUSR :: 0000400; // R for owner
S_IWUSR = 0000200; // W for owner S_IWUSR :: 0000200; // W for owner
S_IXUSR = 0000100; // X for owner S_IXUSR :: 0000100; // X for owner
// Read, write, execute/search by group // Read, write, execute/search by group
S_IRWXG = 0000070; // RWX mask for group S_IRWXG :: 0000070; // RWX mask for group
S_IRGRP = 0000040; // R for group S_IRGRP :: 0000040; // R for group
S_IWGRP = 0000020; // W for group S_IWGRP :: 0000020; // W for group
S_IXGRP = 0000010; // X for group S_IXGRP :: 0000010; // X for group
// Read, write, execute/search by others // Read, write, execute/search by others
S_IRWXO = 0000007; // RWX mask for other S_IRWXO :: 0000007; // RWX mask for other
S_IROTH = 0000004; // R for other S_IROTH :: 0000004; // R for other
S_IWOTH = 0000002; // W for other S_IWOTH :: 0000002; // W for other
S_IXOTH = 0000001; // X for other S_IXOTH :: 0000001; // X for other
S_ISUID = 0004000; // Set user id on execution S_ISUID :: 0004000; // Set user id on execution
S_ISGID = 0002000; // Set group id on execution S_ISGID :: 0002000; // Set group id on execution
S_ISVTX = 0001000; // Directory restrcted delete 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 ( S_ISLNK :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFLNK; }
R_OK = 4; // Test for read permission S_ISREG :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFREG; }
W_OK = 2; // Test for write permission S_ISDIR :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFDIR; }
X_OK = 1; // Test for execute permission S_ISCHR :: proc(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFCHR; }
F_OK = 0; // Test for file existance 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 { foreign libc {
proc _unix_open (path: ^u8, mode: int) -> Handle #link_name "open"; _unix_open :: proc(path: ^u8, mode: int) -> Handle #link_name "open" ---;
proc _unix_close (fd: Handle) -> i32 #link_name "close"; _unix_close :: proc(fd: Handle) -> i32 #link_name "close" ---;
proc _unix_read (fd: Handle, buf: rawptr, size: int) -> int #link_name "read"; _unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int #link_name "read" ---;
proc _unix_write (fd: Handle, buf: rawptr, size: int) -> int #link_name "write"; _unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int #link_name "write" ---;
proc _unix_seek (fd: Handle, offset: i64, whence: i32) -> i64 #link_name "lseek64"; _unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 #link_name "lseek64" ---;
proc _unix_gettid() -> u64 #link_name "gettid"; _unix_gettid :: proc() -> u64 #link_name "gettid" ---;
proc _unix_stat (path: ^u8, stat: ^Stat) -> i32 #link_name "stat"; _unix_stat :: proc(path: ^u8, stat: ^Stat) -> i32 #link_name "stat" ---;
proc _unix_access(path: ^u8, mask: int) -> i32 #link_name "access"; _unix_access :: proc(path: ^u8, mask: int) -> i32 #link_name "access" ---;
proc _unix_malloc (size: int) -> rawptr #link_name "malloc"; _unix_malloc :: proc(size: int) -> rawptr #link_name "malloc" ---;
proc _unix_free (ptr: rawptr) #link_name "free"; _unix_free :: proc(ptr: rawptr) #link_name "free" ---;
proc _unix_realloc(ptr: rawptr, size: int) -> rawptr #link_name "realloc"; _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #link_name "realloc" ---;
proc _unix_getenv (^u8) -> ^u8 #link_name "getenv"; _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 { foreign dl {
proc _unix_dlopen (filename: ^u8, flags: int) -> rawptr #link_name "dlopen"; _unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #link_name "dlopen" ---;
proc _unix_dlsym (handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym"; _unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym" ---;
proc _unix_dlclose(handle: rawptr) -> int #link_name "dlclose"; _unix_dlclose :: proc(handle: rawptr) -> int #link_name "dlclose" ---;
proc _unix_dlerror() -> ^u8 #link_name "dlerror"; _unix_dlerror :: proc() -> ^u8 #link_name "dlerror" ---;
} }
// TODO(zangent): Change this to just `open` when Bill fixes overloading. // 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); cstr := strings.new_c_string(path);
var handle = _unix_open(cstr, mode); handle := _unix_open(cstr, mode);
free(cstr); free(cstr);
if(handle == -1) { if(handle == -1) {
return 0, 1; return 0, 1;
@@ -165,78 +157,78 @@ proc open_simple(path: string, mode: int) -> (Handle, Errno) {
return handle, 0; return handle, 0;
} }
// NOTE(zangent): This is here for compatability reasons. Should this be here? // 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); return open_simple(path, mode);
} }
proc close(fd: Handle) { close :: proc(fd: Handle) {
_unix_close(fd); _unix_close(fd);
} }
proc read(fd: Handle, data: []u8) -> (int, Errno) { read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
var sz = _unix_read(fd, &data[0], len(data)); sz := _unix_read(fd, &data[0], len(data));
return sz, 0; return sz, 0;
} }
proc write(fd: Handle, data: []u8) -> (int, Errno) { write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
var sz = _unix_write(fd, &data[0], len(data)); sz := _unix_write(fd, &data[0], len(data));
return sz, 0; return sz, 0;
} }
proc seek(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
var res = _unix_seek(fd, offset, i32(whence)); res := _unix_seek(fd, offset, i32(whence));
return res, 0; return res, 0;
} }
proc file_size(fd: Handle) -> (i64, Errno) { file_size :: proc(fd: Handle) -> (i64, Errno) {
var prev, _ = seek(fd, 0, SEEK_CUR); prev, _ := seek(fd, 0, SEEK_CUR);
var size, err = seek(fd, 0, SEEK_END); size, err := seek(fd, 0, SEEK_END);
seek(fd, prev, SEEK_SET); seek(fd, prev, SEEK_SET);
return size, err; return size, err;
} }
// NOTE(bill): Uses startup to initialize it // NOTE(bill): Uses startup to initialize it
var (
stdin: Handle = 0; stdin: Handle = 0;
stdout: Handle = 1; stdout: Handle = 1;
stderr: Handle = 2; stderr: Handle = 2;
)
/* TODO(zangent): Implement these! /* TODO(zangent): Implement these!
proc last_write_time(fd: Handle) -> FileTime {} last_write_time :: proc(fd: Handle) -> File_Time {}
proc last_write_time_by_name(name: string) -> FileTime {} last_write_time_by_name :: proc(name: string) -> File_Time {}
*/ */
proc stat(path: string) -> (Stat, int) #inline { stat :: proc(path: string) -> (Stat, int) #inline {
var s: Stat; s: Stat;
var cstr = strings.new_c_string(path); cstr := strings.new_c_string(path);
defer free(cstr); defer free(cstr);
var ret_int = _unix_stat(cstr, &s); ret_int := _unix_stat(cstr, &s);
return s, int(ret_int); return s, int(ret_int);
} }
proc access(path: string, mask: int) -> bool #inline { access :: proc(path: string, mask: int) -> bool #inline {
var cstr = strings.new_c_string(path); cstr := strings.new_c_string(path);
defer free(cstr); defer free(cstr);
return _unix_access(cstr, mask) == 0; return _unix_access(cstr, mask) == 0;
} }
proc heap_alloc(size: int) -> rawptr { heap_alloc :: proc(size: int) -> rawptr {
assert(size > 0); assert(size > 0);
return _unix_malloc(size); 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); return _unix_realloc(ptr, new_size);
} }
proc heap_free(ptr: rawptr) { heap_free :: proc(ptr: rawptr) {
_unix_free(ptr); _unix_free(ptr);
} }
proc getenv(name: string) -> (string, bool) { getenv :: proc(name: string) -> (string, bool) {
var path_str = strings.new_c_string(name); path_str := strings.new_c_string(name);
var cstr: ^u8 = _unix_getenv(path_str); cstr: ^u8 = _unix_getenv(path_str);
free(path_str); free(path_str);
if(cstr == nil) { if(cstr == nil) {
return "", false; return "", false;
@@ -244,38 +236,38 @@ proc getenv(name: string) -> (string, bool) {
return strings.to_odin_string(cstr), true; return strings.to_odin_string(cstr), true;
} }
proc exit(code: int) { exit :: proc(code: int) {
_unix_exit(code); _unix_exit(code);
} }
proc current_thread_id() -> int { current_thread_id :: proc() -> int {
// return int(_unix_gettid()); // return int(_unix_gettid());
return 0; return 0;
} }
proc dlopen(filename: string, flags: int) -> rawptr #inline { dlopen :: proc(filename: string, flags: int) -> rawptr #inline {
var cstr = strings.new_c_string(filename); cstr := strings.new_c_string(filename);
var handle = _unix_dlopen(cstr, flags); handle := _unix_dlopen(cstr, flags);
free(cstr); free(cstr);
return handle; 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); assert(handle != nil);
var cstr = strings.new_c_string(symbol); cstr := strings.new_c_string(symbol);
var proc_handle = _unix_dlsym(handle, cstr); proc_handle := _unix_dlsym(handle, cstr);
free(cstr); free(cstr);
return proc_handle; return proc_handle;
} }
proc dlclose(handle: rawptr) -> bool #inline { dlclose :: proc(handle: rawptr) -> bool #inline {
assert(handle != nil); assert(handle != nil);
return _unix_dlclose(handle) == 0; return _unix_dlclose(handle) == 0;
} }
proc dlerror() -> string { dlerror :: proc() -> string {
return strings.to_odin_string(_unix_dlerror()); return strings.to_odin_string(_unix_dlerror());
} }
proc _alloc_command_line_arguments() -> []string { _alloc_command_line_arguments :: proc() -> []string {
// TODO(bill): // TODO(bill):
return nil; return nil;
} }
+156 -187
View File
@@ -1,68 +1,65 @@
import win32 "sys/windows.odin"; import win32 "sys/windows.odin";
import "mem.odin";
type ( Handle :: int;
Handle int; File_Time :: u64;
FileTime u64;
)
const INVALID_HANDLE: Handle = -1;
const ( INVALID_HANDLE: Handle : -1;
O_RDONLY = 0x00000;
O_WRONLY = 0x00001;
O_RDWR = 0x00002;
O_CREAT = 0x00040;
O_EXCL = 0x00080;
O_NOCTTY = 0x00100;
O_TRUNC = 0x00200;
O_NONBLOCK = 0x00800;
O_APPEND = 0x00400;
O_SYNC = 0x01000;
O_ASYNC = 0x02000;
O_CLOEXEC = 0x80000;
)
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 // "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) { open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
if len(path) == 0 { if len(path) == 0 do return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
}
var access: u32; access: u32;
match mode & (O_RDONLY|O_WRONLY|O_RDWR) { match mode & (O_RDONLY|O_WRONLY|O_RDWR) {
case O_RDONLY: access = win32.FILE_GENERIC_READ; case O_RDONLY: access = win32.FILE_GENERIC_READ;
case O_WRONLY: access = win32.FILE_GENERIC_WRITE; 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; access |= win32.FILE_APPEND_DATA;
} }
var share_mode = u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE); share_mode := u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE);
var sa: ^win32.Security_Attributes = nil; sa: ^win32.Security_Attributes = nil;
var sa_inherit = win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = 1}; sa_inherit := win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = 1};
if mode&O_CLOEXEC == 0 { if mode&O_CLOEXEC == 0 {
sa = &sa_inherit; sa = &sa_inherit;
} }
var create_mode: u32; create_mode: u32;
match { match {
case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL): case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
create_mode = win32.CREATE_NEW; 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; create_mode = win32.OPEN_EXISTING;
} }
var buf: [300]u8; buf: [300]u8;
copy(buf[..], []u8(path)); 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)); handle := Handle(win32.create_file_a(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
if handle != INVALID_HANDLE { if handle != INVALID_HANDLE do return handle, ERROR_NONE;
return handle, ERROR_NONE;
} err := Errno(win32.get_last_error());
var err = win32.get_last_error(); return INVALID_HANDLE, err;
return INVALID_HANDLE, Errno(err);
} }
proc close(fd: Handle) { close :: proc(fd: Handle) {
win32.close_handle(win32.Handle(fd)); win32.close_handle(win32.Handle(fd));
} }
proc write(fd: Handle, data: []u8) -> (int, Errno) { write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
if len(data) == 0 { if len(data) == 0 do return 0, ERROR_NONE;
return 0, ERROR_NONE;
} single_write_length: i32;
var single_write_length: i32; total_write: i64;
var total_write: i64; length := i64(len(data));
var length = i64(len(data));
for total_write < length { for total_write < length {
var remaining = length - total_write; remaining := length - total_write;
var to_read: i32; MAX :: 1<<31-1;
const MAX = 1<<31-1; to_write: i32 = min(i32(remaining), MAX);
if remaining <= MAX {
to_read = i32(remaining); e := win32.write_file(win32.Handle(fd), &data[total_write], to_write, &single_write_length, nil);
} else {
to_read = MAX;
}
var e = win32.write_file(win32.Handle(fd), &data[total_write], to_read, &single_write_length, nil);
if single_write_length <= 0 || e == win32.FALSE { if single_write_length <= 0 || e == win32.FALSE {
var err = win32.get_last_error(); err := Errno(win32.get_last_error());
return int(total_write), Errno(e); return int(total_write), err;
} }
total_write += i64(single_write_length); total_write += i64(single_write_length);
} }
return int(total_write), ERROR_NONE; return int(total_write), ERROR_NONE;
} }
proc read(fd: Handle, data: []u8) -> (int, Errno) { read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
if len(data) == 0 { if len(data) == 0 do return 0, ERROR_NONE;
return 0, ERROR_NONE;
}
var single_read_length: i32; single_read_length: i32;
var total_read: i64; total_read: i64;
var length = i64(len(data)); length := i64(len(data));
for total_read < length { for total_read < length {
var remaining = length - total_read; remaining := length - total_read;
var to_read: u32; MAX :: 1<<32-1;
const MAX = 1<<32-1; to_read: u32 = min(u32(remaining), MAX);
if remaining <= MAX {
to_read = u32(remaining);
} else {
to_read = MAX;
}
var e = win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil); e := win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
if single_read_length <= 0 || e == win32.FALSE { if single_read_length <= 0 || e == win32.FALSE {
var err = win32.get_last_error(); err := Errno(win32.get_last_error());
return int(total_read), Errno(e); return int(total_read), err;
} }
total_read += i64(single_read_length); total_read += i64(single_read_length);
} }
return int(total_read), ERROR_NONE; return int(total_read), ERROR_NONE;
} }
proc seek(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
var w: u32; w: u32;
match whence { match whence {
case 0: w = win32.FILE_BEGIN; case 0: w = win32.FILE_BEGIN;
case 1: w = win32.FILE_CURRENT; case 1: w = win32.FILE_CURRENT;
case 2: w = win32.FILE_END; case 2: w = win32.FILE_END;
} }
var hi = i32(offset>>32); hi := i32(offset>>32);
var lo = i32(offset); lo := i32(offset);
var ft = win32.get_file_type(win32.Handle(fd)); ft := win32.get_file_type(win32.Handle(fd));
if ft == win32.FILE_TYPE_PIPE { if ft == win32.FILE_TYPE_PIPE do return 0, ERROR_FILE_IS_PIPE;
return 0, ERROR_FILE_IS_PIPE;
} dw_ptr := win32.set_file_pointer(win32.Handle(fd), lo, &hi, w);
var dw_ptr = win32.set_file_pointer(win32.Handle(fd), lo, &hi, w);
if dw_ptr == win32.INVALID_SET_FILE_POINTER { if dw_ptr == win32.INVALID_SET_FILE_POINTER {
var err = win32.get_last_error(); err := Errno(win32.get_last_error());
return 0, Errno(err); return 0, err;
} }
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE; return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
} }
proc file_size(fd: Handle) -> (i64, Errno) { file_size :: proc(fd: Handle) -> (i64, Errno) {
var length: i64; length: i64;
var err: Errno; err: Errno;
if win32.get_file_size_ex(win32.Handle(fd), &length) == 0 { if win32.get_file_size_ex(win32.Handle(fd), &length) == 0 {
err = Errno(win32.get_last_error()); err = Errno(win32.get_last_error());
} }
@@ -203,13 +186,13 @@ proc file_size(fd: Handle) -> (i64, Errno) {
// NOTE(bill): Uses startup to initialize it // NOTE(bill): Uses startup to initialize it
var stdin = get_std_handle(win32.STD_INPUT_HANDLE); stdin := get_std_handle(win32.STD_INPUT_HANDLE);
var stdout = get_std_handle(win32.STD_OUTPUT_HANDLE); stdout := get_std_handle(win32.STD_OUTPUT_HANDLE);
var stderr = get_std_handle(win32.STD_ERROR_HANDLE); stderr := get_std_handle(win32.STD_ERROR_HANDLE);
proc get_std_handle(h: int) -> Handle { get_std_handle :: proc(h: int) -> Handle {
var fd = win32.get_std_handle(i32(h)); fd := win32.get_std_handle(i32(h));
win32.set_handle_information(fd, win32.HANDLE_FLAG_INHERIT, 0); win32.set_handle_information(fd, win32.HANDLE_FLAG_INHERIT, 0);
return Handle(fd); return Handle(fd);
} }
@@ -219,126 +202,112 @@ proc get_std_handle(h: int) -> Handle {
proc last_write_time(fd: Handle) -> FileTime { last_write_time :: proc(fd: Handle) -> File_Time {
var file_info: win32.ByHandleFileInformation; file_info: win32.By_Handle_File_Information;
win32.get_file_information_by_handle(win32.Handle(fd), &file_info); win32.get_file_information_by_handle(win32.Handle(fd), &file_info);
var lo = FileTime(file_info.last_write_time.lo); lo := File_Time(file_info.last_write_time.lo);
var hi = FileTime(file_info.last_write_time.hi); hi := File_Time(file_info.last_write_time.hi);
return lo | hi << 32; return lo | hi << 32;
} }
proc last_write_time_by_name(name: string) -> FileTime { last_write_time_by_name :: proc(name: string) -> File_Time {
var last_write_time: win32.Filetime; last_write_time: win32.Filetime;
var data: win32.FileAttributeData; data: win32.File_Attribute_Data;
var buf: [1024]u8; buf: [1024]u8;
assert(len(buf) > len(name)); 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 { if win32.get_file_attributes_ex_a(&buf[0], win32.GetFileExInfoStandard, &data) != 0 {
last_write_time = data.last_write_time; last_write_time = data.last_write_time;
} }
var l = FileTime(last_write_time.lo); l := File_Time(last_write_time.lo);
var h = FileTime(last_write_time.hi); h := File_Time(last_write_time.hi);
return l | h << 32; 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); 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 { if new_size == 0 {
heap_free(ptr); heap_free(ptr);
return nil; return nil;
} }
if ptr == nil { if ptr == nil do return heap_alloc(new_size);
return heap_alloc(new_size);
}
return win32.heap_realloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, ptr, new_size); return win32.heap_realloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
} }
proc heap_free(ptr: rawptr) { heap_free :: proc(ptr: rawptr) {
if ptr == nil { if ptr == nil do return;
return;
}
win32.heap_free(win32.get_process_heap(), 0, ptr); win32.heap_free(win32.get_process_heap(), 0, ptr);
} }
proc exit(code: int) { exit :: proc(code: int) {
win32.exit_process(u32(code)); win32.exit_process(u32(code));
} }
proc current_thread_id() -> int { current_thread_id :: proc() -> int {
return int(win32.get_current_thread_id()); return int(win32.get_current_thread_id());
} }
proc _alloc_command_line_arguments() -> []string { _alloc_command_line_arguments :: proc() -> []string {
proc alloc_ucs2_to_utf8(wstr: ^u16) -> string { alloc_ucs2_to_utf8 :: proc(wstr: ^u16) -> string {
var wstr_len = 0; wstr_len := 0;
for (wstr+wstr_len)^ != 0 { for (wstr+wstr_len)^ != 0 do wstr_len += 1;
wstr_len++;
}
var len = 2*wstr_len-1;
var buf = make([]u8, len+1);
var str = slice_ptr(wstr, wstr_len+1);
var i, j = 0, 0; 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 { for str[j] != 0 {
match { match {
case str[j] < 0x80: case str[j] < 0x80:
if i+1 > len { if i+1 > len do return "";
return ""; buf[i] = u8(str[j]); i += 1;
} j += 1;
buf[i] = u8(str[j]); i++;
j++;
case str[j] < 0x800: case str[j] < 0x800:
if i+2 > len { if i+2 > len do return "";
return ""; buf[i] = u8(0xc0 + (str[j]>>6)); i += 1;
} buf[i] = u8(0x80 + (str[j]&0x3f)); i += 1;
buf[i] = u8(0xc0 + (str[j]>>6)); i++; j += 1;
buf[i] = u8(0x80 + (str[j]&0x3f)); i++;
j++;
case 0xd800 <= str[j] && str[j] < 0xdc00: case 0xd800 <= str[j] && str[j] < 0xdc00:
if i+4 > len { if i+4 > len do return "";
return ""; c := rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000;
} buf[i] = u8(0xf0 + (c >> 18)); i += 1;
var c = rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000; buf[i] = u8(0x80 + ((c >> 12) & 0x3f)); i += 1;
buf[i] = u8(0xf0 + (c >> 18)); i++; buf[i] = u8(0x80 + ((c >> 6) & 0x3f)); i += 1;
buf[i] = u8(0x80 + ((c >> 12) & 0x3f)); i++; buf[i] = u8(0x80 + ((c ) & 0x3f)); i += 1;
buf[i] = u8(0x80 + ((c >> 6) & 0x3f)); i++;
buf[i] = u8(0x80 + ((c ) & 0x3f)); i++;
j += 2; j += 2;
case 0xdc00 <= str[j] && str[j] < 0xe000: case 0xdc00 <= str[j] && str[j] < 0xe000:
return ""; return "";
case: case:
if i+3 > len { if i+3 > len do return "";
return ""; buf[i] = 0xe0 + u8 (str[j] >> 12); i += 1;
} buf[i] = 0x80 + u8((str[j] >> 6) & 0x3f); i += 1;
buf[i] = 0xe0 + u8 (str[j] >> 12); i++; buf[i] = 0x80 + u8((str[j] ) & 0x3f); i += 1;
buf[i] = 0x80 + u8((str[j] >> 6) & 0x3f); i++; j += 1;
buf[i] = 0x80 + u8((str[j] ) & 0x3f); i++;
j++;
} }
} }
return string(buf[0..<i]); return string(buf[..i]);
} }
var arg_count: i32; arg_count: i32;
var arg_list_ptr = win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count); arg_list_ptr := win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count);
var arg_list = make([]string, arg_count); arg_list := make([]string, int(arg_count));
for _, i in arg_list { for _, i in arg_list do arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^);
arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^);
}
return arg_list; return arg_list;
} }
+156 -165
View File
@@ -5,160 +5,152 @@ foreign_system_library (
import "strings.odin"; import "strings.odin";
type ( Handle :: i32;
Handle i32; File_Time :: u64;
FileTime u64; Errno :: int;
Errno int;
AddressSize int;
)
const ( O_RDONLY :: 0x00000;
O_RDONLY = 0x00000; O_WRONLY :: 0x00001;
O_WRONLY = 0x00001; O_RDWR :: 0x00002;
O_RDWR = 0x00002; O_CREAT :: 0x00040;
O_CREAT = 0x00040; O_EXCL :: 0x00080;
O_EXCL = 0x00080; O_NOCTTY :: 0x00100;
O_NOCTTY = 0x00100; O_TRUNC :: 0x00200;
O_TRUNC = 0x00200; O_NONBLOCK :: 0x00800;
O_NONBLOCK = 0x00800; O_APPEND :: 0x00400;
O_APPEND = 0x00400; O_SYNC :: 0x01000;
O_SYNC = 0x01000; O_ASYNC :: 0x02000;
O_ASYNC = 0x02000; O_CLOEXEC :: 0x80000;
O_CLOEXEC = 0x80000;
)
const (
SEEK_SET = 0;
SEEK_CUR = 1;
SEEK_END = 2;
SEEK_DATA = 3;
SEEK_HOLE = 4;
SEEK_MAX = SEEK_HOLE;
)
const (
// NOTE(zangent): These are OS specific!
// Do not mix these up!
RTLD_LAZY = 0x1;
RTLD_NOW = 0x2;
RTLD_LOCAL = 0x4;
RTLD_GLOBAL = 0x8;
RTLD_NODELETE = 0x80;
RTLD_NOLOAD = 0x10;
RTLD_FIRST = 0x100;
)
var args: [dynamic]string; 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;
_File_Time :: struct #ordered {
seconds: i64;
nanoseconds: i64;
} }
type Stat struct #ordered { Stat :: struct #ordered {
device_id : i32, // ID of device containing file device_id: i32; // ID of device containing file
mode : u16, // Mode of the file mode: u16; // Mode of the file
nlink : u16, // Number of hard links nlink: u16; // Number of hard links
serial : u64, // File serial number serial: u64; // File serial number
uid : u32, // User ID of the file's owner uid: u32; // User ID of the file's owner
gid : u32, // Group ID of the file's group gid: u32; // Group ID of the file's group
rdev : i32, // Device ID, if device rdev: i32; // Device ID, if device
last_access : FileTime, // Time of last access last_access: File_Time; // Time of last access
modified : FileTime, // Time of last modification modified: File_Time; // Time of last modification
status_change : FileTime, // Time of last status change status_change: File_Time; // Time of last status change
created : FileTime, // Time of creation created: File_Time; // Time of creation
size : i64, // Size of the file, in bytes size: i64; // Size of the file, in bytes
blocks : i64, // Number of blocks allocated for the file blocks: i64; // Number of blocks allocated for the file
block_size: i32, // Optimal blocksize for I/O block_size: i32; // Optimal blocksize for I/O
flags : u32, // User-defined flags for the file flags: u32; // User-defined flags for the file
gen_num : u32, // File generation number ...? gen_num: u32; // File generation number ...?
_spare : i32, // RESERVED _spare: i32; // RESERVED
_reserve1, _reserve1,
_reserve2 : i64, // RESERVED _reserve2: i64; // RESERVED
}; };
// File type // File type
const ( S_IFMT :: 0170000; // Type of file mask
S_IFMT = 0170000; // Type of file mask S_IFIFO :: 0010000; // Named pipe (fifo)
S_IFIFO = 0010000; // Named pipe (fifo) S_IFCHR :: 0020000; // Character special
S_IFCHR = 0020000; // Character special S_IFDIR :: 0040000; // Directory
S_IFDIR = 0040000; // Directory S_IFBLK :: 0060000; // Block special
S_IFBLK = 0060000; // Block special S_IFREG :: 0100000; // Regular
S_IFREG = 0100000; // Regular S_IFLNK :: 0120000; // Symbolic link
S_IFLNK = 0120000; // Symbolic link S_IFSOCK :: 0140000; // Socket
S_IFSOCK = 0140000; // Socket
// File mode // File mode
// Read, write, execute/search by owner // Read, write, execute/search by owner
S_IRWXU = 0000700; // RWX mask for owner S_IRWXU :: 0000700; // RWX mask for owner
S_IRUSR = 0000400; // R for owner S_IRUSR :: 0000400; // R for owner
S_IWUSR = 0000200; // W for owner S_IWUSR :: 0000200; // W for owner
S_IXUSR = 0000100; // X for owner S_IXUSR :: 0000100; // X for owner
// Read, write, execute/search by group // Read, write, execute/search by group
S_IRWXG = 0000070; // RWX mask for group S_IRWXG :: 0000070; // RWX mask for group
S_IRGRP = 0000040; // R for group S_IRGRP :: 0000040; // R for group
S_IWGRP = 0000020; // W for group S_IWGRP :: 0000020; // W for group
S_IXGRP = 0000010; // X for group S_IXGRP :: 0000010; // X for group
// Read, write, execute/search by others // Read, write, execute/search by others
S_IRWXO = 0000007; // RWX mask for other S_IRWXO :: 0000007; // RWX mask for other
S_IROTH = 0000004; // R for other S_IROTH :: 0000004; // R for other
S_IWOTH = 0000002; // W for other S_IWOTH :: 0000002; // W for other
S_IXOTH = 0000001; // X for other S_IXOTH :: 0000001; // X for other
S_ISUID = 0004000; // Set user id on execution S_ISUID :: 0004000; // Set user id on execution
S_ISGID = 0002000; // Set group id on execution S_ISGID :: 0002000; // Set group id on execution
S_ISVTX = 0001000; // Directory restrcted delete S_ISVTX :: 0001000; // Directory restrcted delete
)
proc S_ISLNK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFLNK; } S_ISLNK :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFLNK;
proc S_ISREG (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFREG; } S_ISREG :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFREG;
proc S_ISDIR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFDIR; } S_ISDIR :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFDIR;
proc S_ISCHR (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFCHR; } S_ISCHR :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFCHR;
proc S_ISBLK (m: u32) -> bool #inline {return (m & S_IFMT) == S_IFBLK; } S_ISBLK :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFBLK;
proc S_ISFIFO(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFIFO; } S_ISFIFO :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFIFO;
proc S_ISSOCK(m: u32) -> bool #inline {return (m & S_IFMT) == S_IFSOCK;} S_ISSOCK :: proc(m: u32) -> bool #inline do return (m & S_IFMT) == S_IFSOCK;
const ( R_OK :: 4; // Test for read permission
R_OK = 4; // Test for read permission W_OK :: 2; // Test for write permission
W_OK = 2; // Test for write permission X_OK :: 1; // Test for execute permission
X_OK = 1; // Test for execute permission F_OK :: 0; // Test for file existance
F_OK = 0; // Test for file existance
)
foreign libc { foreign libc {
proc unix_open (path: ^u8, mode: int) -> Handle #link_name "open"; unix_open :: proc(path: ^u8, mode: int) -> Handle #link_name "open" ---;
proc unix_close (handle: Handle) #link_name "close"; unix_close :: proc(handle: Handle) #link_name "close" ---;
proc unix_read (handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "read"; unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "read" ---;
proc unix_write (handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "write"; unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "write" ---;
proc unix_lseek (fs: Handle, offset: AddressSize, whence: int) -> AddressSize #link_name "lseek"; unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int #link_name "lseek" ---;
proc unix_gettid() -> u64 #link_name "gettid"; unix_gettid :: proc() -> u64 #link_name "gettid" ---;
proc unix_stat (path: ^u8, stat: ^Stat) -> int #link_name "stat"; unix_stat :: proc(path: ^u8, stat: ^Stat) -> int #link_name "stat" ---;
proc unix_access(path: ^u8, mask: int) -> int #link_name "access"; unix_access :: proc(path: ^u8, mask: int) -> int #link_name "access" ---;
proc unix_malloc (size: int) -> rawptr #link_name "malloc"; unix_malloc :: proc(size: int) -> rawptr #link_name "malloc" ---;
proc unix_free (ptr: rawptr) #link_name "free"; unix_free :: proc(ptr: rawptr) #link_name "free" ---;
proc unix_realloc(ptr: rawptr, size: int) -> rawptr #link_name "realloc"; unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #link_name "realloc" ---;
proc unix_getenv (^u8) -> ^u8 #link_name "getenv"; 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 { foreign dl {
proc unix_dlopen (filename: ^u8, flags: int) -> rawptr #link_name "dlopen"; unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #link_name "dlopen" ---;
proc unix_dlsym (handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym"; unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #link_name "dlsym" ---;
proc unix_dlclose(handle: rawptr) -> int #link_name "dlclose"; unix_dlclose :: proc(handle: rawptr) -> int #link_name "dlclose" ---;
proc unix_dlerror() -> ^u8 #link_name "dlerror"; unix_dlerror :: proc() -> ^u8 #link_name "dlerror" ---;
} }
// TODO(zangent): Change this to just `open` when Bill fixes overloading. // 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); cstr := strings.new_c_string(path);
var handle = unix_open(cstr, mode); handle := unix_open(cstr, mode);
free(cstr); free(cstr);
if(handle == -1) { if(handle == -1) {
return 0, 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? // 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); return open_simple(path, mode);
} }
proc close(fd: Handle) { close :: proc(fd: Handle) {
unix_close(fd); unix_close(fd);
} }
proc write(fd: Handle, data: []u8) -> (AddressSize, Errno) { write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
assert(fd != -1); 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) { if(bytes_written == -1) {
return 0, 1; return 0, 1;
} }
return bytes_written, 0; return bytes_written, 0;
} }
proc read(fd: Handle, data: []u8) -> (AddressSize, Errno) { read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
assert(fd != -1); 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) { if(bytes_read == -1) {
return 0, 1; return 0, 1;
} }
return bytes_read, 0; 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); assert(fd != -1);
var final_offset = unix_lseek(fd, offset, whence); final_offset := i64(unix_lseek(fd, offset, whence));
if(final_offset == -1) { if(final_offset == -1) {
return 0, 1; return 0, 1;
} }
return final_offset, 0; return final_offset, 0;
} }
proc file_size(fd: Handle) -> (i64, Errno) { file_size :: proc(fd: Handle) -> (i64, Errno) {
var prev, _ = seek(fd, 0, SEEK_CUR); prev, _ := seek(fd, 0, SEEK_CUR);
var size, err = seek(fd, 0, SEEK_END); size, err := seek(fd, 0, SEEK_END);
seek(fd, prev, SEEK_SET); seek(fd, prev, SEEK_SET);
return size, err; return i64(size), err;
} }
// NOTE(bill): Uses startup to initialize it // NOTE(bill): Uses startup to initialize it
var ( stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE);
stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE); stdout: Handle = 1; // get_std_handle(win32.STD_OUTPUT_HANDLE);
stdout: Handle = 1; // get_std_handle(win32.STD_OUTPUT_HANDLE); stderr: Handle = 2; // get_std_handle(win32.STD_ERROR_HANDLE);
stderr: Handle = 2; // get_std_handle(win32.STD_ERROR_HANDLE);
)
/* TODO(zangent): Implement these! /* TODO(zangent): Implement these!
proc last_write_time(fd: Handle) -> FileTime {} last_write_time :: proc(fd: Handle) -> File_Time {}
proc last_write_time_by_name(name: string) -> FileTime {} last_write_time_by_name :: proc(name: string) -> File_Time {}
*/ */
proc stat(path: string) -> (Stat, bool) #inline { stat :: proc(path: string) -> (Stat, bool) #inline {
var s: Stat; s: Stat;
var cstr = strings.new_c_string(path); cstr := strings.new_c_string(path);
defer free(cstr); defer free(cstr);
var ret_int = unix_stat(cstr, &s); ret_int := unix_stat(cstr, &s);
return s, ret_int==0; return s, ret_int==0;
} }
proc access(path: string, mask: int) -> bool #inline { access :: proc(path: string, mask: int) -> bool #inline {
var cstr = strings.new_c_string(path); cstr := strings.new_c_string(path);
defer free(cstr); defer free(cstr);
return unix_access(cstr, mask) == 0; return unix_access(cstr, mask) == 0;
} }
proc heap_alloc(size: int) -> rawptr #inline { heap_alloc :: proc(size: int) -> rawptr #inline {
assert(size > 0); assert(size > 0);
return unix_malloc(size); 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); return unix_realloc(ptr, new_size);
} }
proc heap_free(ptr: rawptr) #inline { heap_free :: proc(ptr: rawptr) #inline {
unix_free(ptr); unix_free(ptr);
} }
proc getenv(name: string) -> (string, bool) { getenv :: proc(name: string) -> (string, bool) {
var path_str = strings.new_c_string(name); path_str := strings.new_c_string(name);
var cstr: ^u8 = unix_getenv(path_str); cstr: ^u8 = unix_getenv(path_str);
free(path_str); free(path_str);
if(cstr == nil) { if(cstr == nil) {
return "", false; return "", false;
@@ -260,33 +251,33 @@ proc getenv(name: string) -> (string, bool) {
return strings.to_odin_string(cstr), true; return strings.to_odin_string(cstr), true;
} }
proc exit(code: int) #inline { exit :: proc(code: int) #inline {
unix_exit(code); unix_exit(code);
} }
proc current_thread_id() -> int { current_thread_id :: proc() -> int {
// return cast(int) unix_gettid(); // return cast(int) unix_gettid();
return 0; return 0;
} }
proc dlopen(filename: string, flags: int) -> rawptr #inline { dlopen :: proc(filename: string, flags: int) -> rawptr #inline {
var cstr = strings.new_c_string(filename); cstr := strings.new_c_string(filename);
var handle = unix_dlopen(cstr, flags); handle := unix_dlopen(cstr, flags);
free(cstr); free(cstr);
return handle; 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); assert(handle != nil);
var cstr = strings.new_c_string(symbol); cstr := strings.new_c_string(symbol);
var proc_handle = unix_dlsym(handle, cstr); proc_handle := unix_dlsym(handle, cstr);
free(cstr); free(cstr);
return proc_handle; return proc_handle;
} }
proc dlclose(handle: rawptr) -> bool #inline { dlclose :: proc(handle: rawptr) -> bool #inline {
assert(handle != nil); assert(handle != nil);
return unix_dlclose(handle) == 0; return unix_dlclose(handle) == 0;
} }
proc dlerror() -> string { dlerror :: proc() -> string {
return strings.to_odin_string(unix_dlerror()); return strings.to_odin_string(unix_dlerror());
} }
+24 -25
View File
@@ -1,29 +1,28 @@
type ( Any :: struct #ordered {
Any struct #ordered { data: rawptr;
data: rawptr, type_info: ^Type_Info;
type_info: ^TypeInfo, };
};
String struct #ordered { String :: struct #ordered {
data: ^u8, data: ^u8;
len: int, len: int;
}; };
Slice struct #ordered { Slice :: struct #ordered {
data: rawptr, data: rawptr;
len: int, len: int;
cap: int, cap: int;
}; };
DynamicArray struct #ordered { Dynamic_Array :: struct #ordered {
data: rawptr, data: rawptr;
len: int, len: int;
cap: int, cap: int;
allocator: Allocator, allocator: Allocator;
}; };
Map :: struct #ordered {
hashes: [dynamic]int;
entries: Dynamic_Array;
};
DynamicMap struct #ordered {
hashes: [dynamic]int,
entries: DynamicArray,
};
)
+213
View File
@@ -0,0 +1,213 @@
bubble_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
assert(f != nil);
count := len(array);
init_j, last_j := 0, count-1;
for {
init_swap, prev_swap := -1, -1;
for j in init_j..last_j {
if f(array[j], array[j+1]) > 0 {
array[j], array[j+1] = array[j+1], array[j];
prev_swap = j;
if init_swap == -1 do init_swap = j;
}
}
if prev_swap == -1 do return;
init_j = max(init_swap-1, 0);
last_j = prev_swap;
}
}
bubble_sort :: proc(array: $A/[]$T) {
count := len(array);
init_j, last_j := 0, count-1;
for {
init_swap, prev_swap := -1, -1;
for j in init_j..last_j {
if array[j] > array[j+1] {
array[j], array[j+1] = array[j+1], array[j];
prev_swap = j;
if init_swap == -1 do init_swap = j;
}
}
if prev_swap == -1 do return;
init_j = max(init_swap-1, 0);
last_j = prev_swap;
}
}
quick_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
assert(f != nil);
a := array;
n := len(a);
if n < 2 do return;
p := a[n/2];
i, j := 0, n-1;
loop: for {
for f(a[i], p) < 0 do i += 1;
for f(p, a[j]) < 0 do j -= 1;
if i >= j do break loop;
a[i], a[j] = a[j], a[i];
i += 1;
j -= 1;
}
quick_sort(a[0..i], f);
quick_sort(a[i..n], f);
}
quick_sort :: proc(array: $A/[]$T) {
a := array;
n := len(a);
if n < 2 do return;
p := a[n/2];
i, j := 0, n-1;
loop: for {
for a[i] < p do i += 1;
for p < a[j] do j -= 1;
if i >= j do break loop;
a[i], a[j] = a[j], a[i];
i += 1;
j -= 1;
}
quick_sort(a[0..i]);
quick_sort(a[i..n]);
}
_log2 :: proc(n: int) -> int {
res := 0;
for ; n != 0; n >>= 1 do res += 1;
return res;
}
merge_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
merge_slices :: proc(arr1, arr2, out: A, f: proc(T, T) -> int) {
N1, N2 := len(arr1), len(arr2);
i, j := 0, 0;
for k in 0..N1+N2 {
if j == N2 || i < N1 && j < N2 && f(arr1[i], arr2[j]) < 0 {
out[k] = arr1[i];
i += 1;
} else {
out[k] = arr2[j];
j += 1;
}
}
}
assert(f != nil);
arr1 := array;
N := len(arr1);
arr2 := make([]T, N);
defer free(arr2);
a, b, m, M := N/2, N, 1, _log2(N);
for i in 0..M+1 {
for j in 0..a {
k := 2*j*m;
merge_slices(arr1[k..k+m], arr1[k+m..k+m+m], arr2[k..], f);
}
if N-b > m {
k := 2*a*m;
merge_slices(arr1[k..k+m], arr1[k+m..k+m+(N-b)&(m-1)], arr2[k..], f);
} else {
copy(arr2[b..N], arr1[b..N]);
}
arr1, arr2 = arr2, arr1;
m <<= 1;
a >>= 1;
b = a << uint(i) << 2;
}
if M & 1 == 0 do copy(arr2, arr1);
}
merge_sort :: proc(array: $A/[]$T) {
merge_slices :: proc(arr1, arr2, out: A) {
N1, N2 := len(arr1), len(arr2);
i, j := 0, 0;
for k in 0..N1+N2 {
if j == N2 || i < N1 && j < N2 && arr1[i] < arr2[j] {
out[k] = arr1[i];
i += 1;
} else {
out[k] = arr2[j];
j += 1;
}
}
}
arr1 := array;
N := len(arr1);
arr2 := make([]T, N);
defer free(arr2);
a, b, m, M := N/2, N, 1, _log2(N);
for i in 0..M+1 {
for j in 0..a {
k := 2*j*m;
merge_slices(arr1[k..k+m], arr1[k+m..k+m+m], arr2[k..]);
}
if N-b > m {
k := 2*a*m;
merge_slices(arr1[k..k+m], arr1[k+m..k+m+(N-b)&(m-1)], arr2[k..]);
} else {
copy(arr2[b..N], arr1[b..N]);
}
arr1, arr2 = arr2, arr1;
m <<= 1;
a >>= 1;
b = a << uint(i) << 2;
}
if M & 1 == 0 do copy(arr2, arr1);
}
compare_ints :: proc(a, b: int) -> int {
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);
}
+153 -163
View File
@@ -1,13 +1,13 @@
import . "decimal.odin"; import . "decimal.odin";
type IntFlag enum { Int_Flag :: enum {
Prefix = 1<<0, Prefix = 1<<0,
Plus = 1<<1, Plus = 1<<1,
Space = 1<<2, Space = 1<<2,
} }
proc parse_bool(s: string) -> (result: bool, ok: bool) { parse_bool :: proc(s: string) -> (result: bool, ok: bool) {
match s { match s {
case "1", "t", "T", "true", "TRUE", "True": case "1", "t", "T", "true", "TRUE", "True":
return true, true; return true, true;
@@ -17,9 +17,9 @@ proc parse_bool(s: string) -> (result: bool, ok: bool) {
return false, false; return false, false;
} }
proc _digit_value(r: rune) -> int { _digit_value :: proc(r: rune) -> int {
var ri = int(r); ri := int(r);
var v: int = 16; v: int = 16;
match r { match r {
case '0'..'9': v = ri-'0'; case '0'..'9': v = ri-'0';
case 'a'..'z': v = ri-'a'+10; case 'a'..'z': v = ri-'a'+10;
@@ -28,8 +28,8 @@ proc _digit_value(r: rune) -> int {
return v; return v;
} }
proc parse_i128(s: string) -> i128 { parse_i128 :: proc(s: string) -> i128 {
var neg = false; neg := false;
if len(s) > 1 { if len(s) > 1 {
match s[0] { match s[0] {
case '-': 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' { if len(s) > 2 && s[0] == '0' {
match s[1] { match s[1] {
case 'b': base = 2; s = s[2..]; 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 { for r in s {
if r == '_' { if r == '_' {
continue; continue;
} }
var v = i128(_digit_value(r)); v := i128(_digit_value(r));
if v >= base { if v >= base {
break; break;
} }
@@ -67,17 +67,18 @@ proc parse_i128(s: string) -> i128 {
value += v; value += v;
} }
return neg ? -value : value; if neg do return -value;
return value;
} }
proc parse_u128(s: string) -> u128 { parse_u128 :: proc(s: string) -> u128 {
var neg = false; neg := false;
if len(s) > 1 && s[0] == '+' { if len(s) > 1 && s[0] == '+' {
s = s[1..]; s = s[1..];
} }
var base = u128(10); base := u128(10);
if len(s) > 2 && s[0] == '0' { if len(s) > 2 && s[0] == '0' {
match s[1] { match s[1] {
case 'b': base = 2; s = s[2..]; 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 { for r in s {
if r == '_' { if r == '_' do continue;
continue; v := u128(_digit_value(r));
} if v >= base do break;
var v = u128(_digit_value(r));
if v >= base {
break;
}
value *= base; value *= base;
value += u128(v); 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)); 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)); return uint(parse_u128(s));
} }
proc parse_f64(s: string) -> f64 { parse_f64 :: proc(s: string) -> f64 {
var i = 0; i := 0;
var sign: f64 = 1; sign: f64 = 1;
match s[i] { match s[i] {
case '-': i++; sign = -1; case '-': i += 1; sign = -1;
case '+': i++; case '+': i += 1;
} }
var value: f64 = 0; value: f64 = 0;
for ; i < len(s); i++ { for ; i < len(s); i += 1 {
var r = rune(s[i]); r := rune(s[i]);
if r == '_' { if r == '_' do continue;
continue;
} v := _digit_value(r);
var v = _digit_value(r); if v >= 10 do break;
if v >= 10 {
break;
}
value *= 10; value *= 10;
value += f64(v); value += f64(v);
} }
if s[i] == '.' { if s[i] == '.' {
var pow10: f64 = 10; pow10: f64 = 10;
i++; i += 1;
for ; i < len(s); i++ { for ; i < len(s); i += 1 {
var r = rune(s[i]); r := rune(s[i]);
if r == '_' { if r == '_' do continue;
continue;
} v := _digit_value(r);
var v = _digit_value(r); if v >= 10 do break;
if v >= 10 {
break;
}
value += f64(v)/pow10; value += f64(v)/pow10;
pow10 *= 10; pow10 *= 10;
} }
} }
var frac = false; frac := false;
var scale: f64 = 1; scale: f64 = 1;
if s[i] == 'e' || s[i] == 'E' { if s[i] == 'e' || s[i] == 'E' {
i++; i += 1;
match s[i] { match s[i] {
case '-': i++; frac = true; case '-': i += 1; frac = true;
case '+': i++; case '+': i += 1;
} }
var exp: u32 = 0; exp: u32 = 0;
for ; i < len(s); i++ { for ; i < len(s); i += 1 {
var r = rune(s[i]); r := rune(s[i]);
if r == '_' { if r == '_' do continue;
continue;
} d := u32(_digit_value(r));
var d = u32(_digit_value(r)); if d >= 10 do break;
if d >= 10 {
break;
}
exp = exp * 10 + d; exp = exp * 10 + d;
} }
if exp > 308 { exp = 308; } if exp > 308 { exp = 308; }
@@ -185,71 +173,75 @@ proc parse_f64(s: string) -> f64 {
for exp > 0 { scale *= 10; exp -= 1; } 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 { append_bool :: proc(buf: []u8, b: bool) -> string {
var s = b ? "true" : "false"; if b {
append(buf, ..[]u8(s)); append(&buf, "true");
} else {
append(&buf, "false");
}
return string(buf); 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); 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); 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)); return string(generic_ftoa(buf, f, fmt, prec, bit_size));
} }
type DecimalSlice struct { DecimalSlice :: struct {
digits: []u8, digits: []u8;
count: int, count: int;
decimal_point: int, decimal_point: int;
neg: bool, neg: bool;
} }
type Float_Info struct { FloatInfo :: struct {
mantbits: uint, mantbits: uint;
expbits: uint, expbits: uint;
bias: int, 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 { _f16_info := FloatInfo{10, 5, -15};
var bits: u64; _f32_info := FloatInfo{23, 8, -127};
var flt: ^Float_Info; _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 { match bit_size {
case 32: case 32:
bits = u64(transmute(u32, f32(val))); bits = u64(transmute(u32)f32(val));
flt = &_f32_info; flt = &_f32_info;
case 64: case 64:
bits = transmute(u64, val); bits = transmute(u64)val;
flt = &_f64_info; flt = &_f64_info;
case: case:
panic("strconv: invalid bit_size"); panic("strconv: invalid bit_size");
} }
var neg = bits>>(flt.expbits+flt.mantbits) != 0; neg := bits>>(flt.expbits+flt.mantbits) != 0;
var exp = int(bits>>flt.mantbits) & (1<<flt.expbits - 1); exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
var mant = bits & (u64(1) << flt.mantbits - 1); mant := bits & (u64(1) << flt.mantbits - 1);
match exp { match exp {
case 1<<flt.expbits - 1: case 1<<flt.expbits - 1:
var s: string; s: string;
if mant != 0 { if mant != 0 {
s = "NaN"; s = "NaN";
} else if neg { } else if neg {
@@ -257,11 +249,11 @@ proc generic_ftoa(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
} else { } else {
s = "+Inf"; s = "+Inf";
} }
append(buf, ..[]u8(s)); append(&buf, ...cast([]u8)s);
return buf; return buf;
case 0: // denormalized case 0: // denormalized
exp++; exp += 1;
case: case:
mant |= u64(1) << flt.mantbits; 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; exp += flt.bias;
var d_: Decimal; d_: Decimal;
var d = &d_; d := &d_;
assign(d, mant); assign(d, mant);
shift(d, exp - int(flt.mantbits)); shift(d, exp - int(flt.mantbits));
var digs: DecimalSlice; digs: DecimalSlice;
var shortest = prec < 0; shortest := prec < 0;
if shortest { if shortest {
round_shortest(d, mant, exp, flt); round_shortest(d, mant, exp, flt);
digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point}; 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 { match fmt {
case 'f', 'F': case 'f', 'F':
append(buf, neg ? '-' : '+'); append(&buf, neg ? '-' : '+');
// integer, padded with zeros when needed // integer, padded with zeros when needed
if digs.decimal_point > 0 { if digs.decimal_point > 0 {
var m = min(digs.count, digs.decimal_point); m := min(digs.count, digs.decimal_point);
append(buf, ..digs.digits[0..<m]); append(&buf, ...digs.digits[..m]);
for ; m < digs.decimal_point; m++ { for ; m < digs.decimal_point; m += 1 {
append(buf, '0'); append(&buf, '0');
} }
} else { } else {
append(buf, '0'); append(&buf, '0');
} }
// fractional part // fractional part
if prec > 0 { if prec > 0 {
append(buf, '.'); append(&buf, '.');
for i in 0..<prec { for i in 0..prec {
var c: u8 = '0'; c: u8 = '0';
if var j = digs.decimal_point + i; 0 <= j && j < digs.count { if j := digs.decimal_point + i; 0 <= j && j < digs.count {
c = digs.digits[j]; 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 return buf; // TODO
} }
var c: [2]u8; c := [2]u8{'%', fmt};
c[0] = '%'; append(&buf, ...c[..]);
c[1] = fmt;
append(buf, ..c[..]);
return buf; 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 if mant == 0 { // If mantissa is zero, the number is zero
d.count = 0; d.count = 0;
return; return;
@@ -360,18 +350,18 @@ proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
log(2) >~ 0.332 log(2) >~ 0.332
332*(dp-nd) >= 100*(exp-mantbits) 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)) { if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - int(flt.mantbits)) {
// Number is already its shortest // Number is already its shortest
return; return;
} }
var upper_: Decimal; var upper = &upper_; upper_: Decimal; upper := &upper_;
assign(upper, 2*mant - 1); assign(upper, 2*mant - 1);
shift(upper, exp - int(flt.mantbits) - 1); shift(upper, exp - int(flt.mantbits) - 1);
var mantlo: u64; mantlo: u64;
var explo: int; explo: int;
if mant > 1<<flt.mantbits || exp == minexp { if mant > 1<<flt.mantbits || exp == minexp {
mantlo = mant-1; mantlo = mant-1;
explo = exp; explo = exp;
@@ -379,25 +369,25 @@ proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
mantlo = 2*mant - 1; mantlo = 2*mant - 1;
explo = exp-1; explo = exp-1;
} }
var lower_: Decimal; var lower = &lower_; lower_: Decimal; lower := &lower_;
assign(lower, 2*mantlo + 1); assign(lower, 2*mantlo + 1);
shift(lower, explo - int(flt.mantbits) - 1); shift(lower, explo - int(flt.mantbits) - 1);
var inclusive = mant%2 == 0; inclusive := mant%2 == 0;
for i in 0..<d.count { for i in 0..d.count {
var l: u8 = '0'; // lower digit l: u8 = '0'; // lower digit
if i < lower.count { if i < lower.count {
l = lower.digits[i]; l = lower.digits[i];
} }
var m = d.digits[i]; // middle digit m := d.digits[i]; // middle digit
var u: u8 = '0'; // upper digit u: u8 = '0'; // upper digit
if i < upper.count { if i < upper.count {
u = upper.digits[i]; u = upper.digits[i];
} }
var ok_round_down = l != m || inclusive && i+1 == lower.count; 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_up := m != u && (inclusive || m+1 < u || i+1 < upper.count);
if (ok_round_down && ok_round_up) { if (ok_round_down && ok_round_up) {
round(d, i+1); round(d, i+1);
@@ -415,36 +405,36 @@ proc round_shortest(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
} }
const MAX_BASE = 32; MAX_BASE :: 32;
var digits = "0123456789abcdefghijklmnopqrstuvwxyz"; digits := "0123456789abcdefghijklmnopqrstuvwxyz";
proc is_integer_negative(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) { is_integer_negative :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
var neg = false; neg := false;
if is_signed { if is_signed {
match bit_size { match bit_size {
case 8: case 8:
var i = i8(u); i := i8(u);
neg = i < 0; neg = i < 0;
if neg { i = -i; } if neg { i = -i; }
u = u128(i); u = u128(i);
case 16: case 16:
var i = i16(u); i := i16(u);
neg = i < 0; neg = i < 0;
if neg { i = -i; } if neg { i = -i; }
u = u128(i); u = u128(i);
case 32: case 32:
var i = i32(u); i := i32(u);
neg = i < 0; neg = i < 0;
if neg { i = -i; } if neg { i = -i; }
u = u128(i); u = u128(i);
case 64: case 64:
var i = i64(u); i := i64(u);
neg = i < 0; neg = i < 0;
if neg { i = -i; } if neg { i = -i; }
u = u128(i); u = u128(i);
case 128: case 128:
var i = i128(u); i := i128(u);
neg = i < 0; neg = i < 0;
if neg { i = -i; } if neg { i = -i; }
u = u128(i); u = u128(i);
@@ -455,46 +445,46 @@ proc is_integer_negative(u: u128, is_signed: bool, bit_size: int) -> (unsigned:
return u, neg; return u, neg;
} }
proc append_bits(buf: []u8, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: IntFlag) -> string { append_bits :: proc(buf: []u8, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> string {
if base < 2 || base > MAX_BASE { if base < 2 || base > MAX_BASE {
panic("strconv: illegal base passed to append_bits"); panic("strconv: illegal base passed to append_bits");
} }
var neg: bool; neg: bool;
var a: [129]u8; a: [129]u8;
var i = len(a); i := len(a);
u, neg = is_integer_negative(u, is_signed, bit_size); u, neg = is_integer_negative(u, is_signed, bit_size);
var b = u128(base); b := u128(base);
for u >= b { for u >= b {
i--; a[i] = digits[uint(u % b)]; i-=1; a[i] = digits[uint(u % b)];
u /= b; u /= b;
} }
i--; a[i] = digits[uint(u % b)]; i-=1; a[i] = digits[uint(u % b)];
if flags&IntFlag.Prefix != 0 { if flags&Int_Flag.Prefix != 0 {
var ok = true; ok := true;
match base { match base {
case 2: i--; a[i] = 'b'; case 2: i-=1; a[i] = 'b';
case 8: i--; a[i] = 'o'; case 8: i-=1; a[i] = 'o';
case 10: i--; a[i] = 'd'; case 10: i-=1; a[i] = 'd';
case 12: i--; a[i] = 'z'; case 12: i-=1; a[i] = 'z';
case 16: i--; a[i] = 'x'; case 16: i-=1; a[i] = 'x';
case: ok = false; case: ok = false;
} }
if ok { if ok {
i--; a[i] = '0'; i-=1; a[i] = '0';
} }
} }
if neg { if neg {
i--; a[i] = '-'; i-=1; a[i] = '-';
} else if flags&IntFlag.Plus != 0 { } else if flags&Int_Flag.Plus != 0 {
i--; a[i] = '+'; i-=1; a[i] = '+';
} else if flags&IntFlag.Space != 0 { } else if flags&Int_Flag.Space != 0 {
i--; a[i] = ' '; i-=1; a[i] = ' ';
} }
append(buf, ..a[i..]); append(&buf, ...a[i..]);
return string(buf); return string(buf);
} }
+14 -13
View File
@@ -1,21 +1,22 @@
proc new_string(s: string) -> string { import "mem.odin";
var c = make([]u8, len(s)+1);
copy(c, []u8(s)); new_string :: proc(s: string) -> string {
c := make([]u8, len(s)+1);
copy(c, cast([]u8)s);
c[len(s)] = 0; c[len(s)] = 0;
return string(c[0..<len(s)]); return string(c[..len(s)]);
} }
proc new_c_string(s: string) -> ^u8 { new_c_string :: proc(s: string) -> ^u8 {
var c = make([]u8, len(s)+1); c := make([]u8, len(s)+1);
copy(c, []u8(s)); copy(c, cast([]u8)s);
c[len(s)] = 0; c[len(s)] = 0;
return &c[0]; return &c[0];
} }
proc to_odin_string(c: ^u8) -> string { to_odin_string :: proc(c: ^u8) -> string {
var len = 0; if c == nil do return "";
for (c+len)^ != 0 { len := 0;
len++; for (c+len)^ != 0 do len+=1;
} return string(mem.slice_ptr(c, len));
return string(slice_ptr(c, len));
} }
+26 -26
View File
@@ -3,67 +3,67 @@ import (
"os.odin"; "os.odin";
) )
type Semaphore struct { Semaphore :: struct {
// _handle: win32.Handle, // _handle: win32.Handle;
} }
type Mutex struct { Mutex :: struct {
_semaphore: Semaphore, _semaphore: Semaphore;
_counter: i32, _counter: i32;
_owner: i32, _owner: i32;
_recursion: i32, _recursion: i32;
} }
proc current_thread_id() -> i32 { current_thread_id :: proc() -> i32 {
return i32(os.current_thread_id()); 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); // s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
} }
proc semaphore_destroy(s: ^Semaphore) { semaphore_destroy :: proc(s: ^Semaphore) {
// win32.CloseHandle(s._handle); // 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); // win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
} }
proc semaphore_release(s: ^Semaphore) #inline { semaphore_release :: proc(s: ^Semaphore) #inline {
semaphore_post(s, 1); semaphore_post(s, 1);
} }
proc semaphore_wait(s: ^Semaphore) { semaphore_wait :: proc(s: ^Semaphore) {
// win32.WaitForSingleObject(s._handle, win32.INFINITE); // win32.WaitForSingleObject(s._handle, win32.INFINITE);
} }
proc mutex_init(m: ^Mutex) { mutex_init :: proc(m: ^Mutex) {
atomics.store(&m._counter, 0); atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id()); atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore); semaphore_init(&m._semaphore);
m._recursion = 0; m._recursion = 0;
} }
proc mutex_destroy(m: ^Mutex) { mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(&m._semaphore); semaphore_destroy(&m._semaphore);
} }
proc mutex_lock(m: ^Mutex) { mutex_lock :: proc(m: ^Mutex) {
var thread_id = current_thread_id(); thread_id := current_thread_id();
if atomics.fetch_add(&m._counter, 1) > 0 { if atomics.fetch_add(&m._counter, 1) > 0 {
if thread_id != atomics.load(&m._owner) { if thread_id != atomics.load(&m._owner) {
semaphore_wait(&m._semaphore); semaphore_wait(&m._semaphore);
} }
} }
atomics.store(&m._owner, thread_id); atomics.store(&m._owner, thread_id);
m._recursion++; m._recursion += 1;
} }
proc mutex_try_lock(m: ^Mutex) -> bool { mutex_try_lock :: proc(m: ^Mutex) -> bool {
var thread_id = current_thread_id(); thread_id := current_thread_id();
if atomics.load(&m._owner) == thread_id { if atomics.load(&m._owner) == thread_id {
atomics.fetch_add(&m._counter, 1); atomics.fetch_add(&m._counter, 1);
} else { } else {
var expected: i32 = 0; expected: i32 = 0;
if atomics.load(&m._counter) != 0 { if atomics.load(&m._counter) != 0 {
return false; return false;
} }
@@ -72,15 +72,15 @@ proc mutex_try_lock(m: ^Mutex) -> bool {
} }
atomics.store(&m._owner, thread_id); atomics.store(&m._owner, thread_id);
} }
m._recursion++; m._recursion += 1;
return true; return true;
} }
proc mutex_unlock(m: ^Mutex) { mutex_unlock :: proc(m: ^Mutex) {
var recursion: i32; recursion: i32;
var thread_id = current_thread_id(); thread_id := current_thread_id();
assert(thread_id == atomics.load(&m._owner)); assert(thread_id == atomics.load(&m._owner));
m._recursion--; m._recursion -= 1;
recursion = m._recursion; recursion = m._recursion;
if recursion == 0 { if recursion == 0 {
atomics.store(&m._owner, thread_id); atomics.store(&m._owner, thread_id);
+53 -24
View File
@@ -3,51 +3,80 @@ import (
"atomics.odin"; "atomics.odin";
) )
type Semaphore struct { Semaphore :: struct {
_handle: win32.Handle, _handle: win32.Handle;
} }
type Mutex struct { /*
_semaphore: Semaphore, Mutex :: struct {
_counter: i32, _semaphore: Semaphore;
_owner: i32, _counter: i32;
_recursion: i32, _owner: i32;
_recursion: i32;
}
*/
Mutex :: struct {
_critical_section: win32.Critical_Section;
} }
proc current_thread_id() -> i32 { current_thread_id :: proc() -> i32 {
return i32(win32.get_current_thread_id()); 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); 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); 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); 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); 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._counter, 0);
atomics.store(&m._owner, current_thread_id()); atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore); semaphore_init(&m._semaphore);
m._recursion = 0; m._recursion = 0;
} }
proc mutex_destroy(m: ^Mutex) { mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(&m._semaphore); semaphore_destroy(&m._semaphore);
} }
proc mutex_lock(m: ^Mutex) { mutex_lock :: proc(m: ^Mutex) {
var thread_id = current_thread_id(); thread_id := current_thread_id();
if atomics.fetch_add(&m._counter, 1) > 0 { if atomics.fetch_add(&m._counter, 1) > 0 {
if thread_id != atomics.load(&m._owner) { if thread_id != atomics.load(&m._owner) {
semaphore_wait(&m._semaphore); semaphore_wait(&m._semaphore);
@@ -56,12 +85,12 @@ proc mutex_lock(m: ^Mutex) {
atomics.store(&m._owner, thread_id); atomics.store(&m._owner, thread_id);
m._recursion++; m._recursion++;
} }
proc mutex_try_lock(m: ^Mutex) -> bool { mutex_try_lock :: proc(m: ^Mutex) -> bool {
var thread_id = current_thread_id(); thread_id := current_thread_id();
if atomics.load(&m._owner) == thread_id { if atomics.load(&m._owner) == thread_id {
atomics.fetch_add(&m._counter, 1); atomics.fetch_add(&m._counter, 1);
} else { } else {
var expected: i32 = 0; expected: i32 = 0;
if atomics.load(&m._counter) != 0 { if atomics.load(&m._counter) != 0 {
return false; return false;
} }
@@ -73,9 +102,9 @@ proc mutex_try_lock(m: ^Mutex) -> bool {
m._recursion++; m._recursion++;
return true; return true;
} }
proc mutex_unlock(m: ^Mutex) { mutex_unlock :: proc(m: ^Mutex) {
var recursion: i32; recursion: i32;
var thread_id = current_thread_id(); thread_id := current_thread_id();
assert(thread_id == atomics.load(&m._owner)); assert(thread_id == atomics.load(&m._owner));
m._recursion--; m._recursion--;
@@ -90,4 +119,4 @@ proc mutex_unlock(m: ^Mutex) {
} }
} }
} }
*/
+70 -77
View File
@@ -1,90 +1,83 @@
foreign_system_library "opengl32.lib" when ODIN_OS == "windows"; foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
import . "windows.odin"; 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 ( CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
Hglrc Handle; CONTEXT_MINOR_VERSION_ARB :: 0x2092;
ColorRef u32; 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 { Hglrc :: Handle;
size: u16, Color_Ref :: u32;
version: u16,
flags: u32,
pixel_type: u8,
color_bits: u8,
red_bits: u8,
red_shift: u8,
green_bits: u8,
green_shift: u8,
blue_bits: u8,
blue_shift: u8,
alpha_bits: u8,
alpha_shift: u8,
accum_bits: u8,
accum_red_bits: u8,
accum_green_bits: u8,
accum_blue_bits: u8,
accum_alpha_bits: u8,
depth_bits: u8,
stencil_bits: u8,
aux_buffers: u8,
layer_type: u8,
reserved: u8,
transparent: ColorRef,
}
PointFloat struct { Layer_Plane_Descriptor :: struct {
x, y: f32, size: u16;
} version: u16;
flags: u32;
pixel_type: u8;
color_bits: u8;
red_bits: u8;
red_shift: u8;
green_bits: u8;
green_shift: u8;
blue_bits: u8;
blue_shift: u8;
alpha_bits: u8;
alpha_shift: u8;
accum_bits: u8;
accum_red_bits: u8;
accum_green_bits: u8;
accum_blue_bits: u8;
accum_alpha_bits: u8;
depth_bits: u8;
stencil_bits: u8;
aux_buffers: u8;
layer_type: u8;
reserved: u8;
transparent: Color_Ref;
}
Glyph_MetricsFloat struct { Point_Float :: struct {x, y: f32};
black_box_x: f32,
black_box_y: f32,
glyph_origin: PointFloat,
cell_inc_x: f32,
cell_inc_y: f32,
}
)
type ( Glyph_Metrics_Float :: struct {
CreateContextAttribsARBType proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc; black_box_x: f32;
ChoosePixelFormatARBType proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c; black_box_y: f32;
SwapIntervalEXTType proc(interval: i32) -> bool #cc_c; glyph_origin: Point_Float;
GetExtensionsStringARBType proc(Hdc) -> ^u8 #cc_c; cell_inc_x: f32;
) cell_inc_y: f32;
}
Create_Context_Attribs_ARB_Type :: #type proc(hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
Choose_Pixel_Format_ARB_Type :: #type proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c;
Swap_Interval_EXT_Type :: #type proc(interval: i32) -> bool #cc_c;
Get_Extensions_String_ARB_Type :: #type proc(Hdc) -> ^u8 #cc_c;
// Procedures
create_context_attribs_arb: Create_Context_Attribs_ARB_Type;
choose_pixel_format_arb: Choose_Pixel_Format_ARB_Type;
swap_interval_ext: Swap_Interval_EXT_Type;
get_extensions_string_arb: Get_Extensions_String_ARB_Type;
var (
create_context_attribs_arb: CreateContextAttribsARBType;
choose_pixel_format_arb: ChoosePixelFormatARBType;
swap_interval_ext: SwapIntervalEXTType;
get_extensions_string_arb: GetExtensionsStringARBType;
)
foreign opengl32 { foreign opengl32 {
proc create_context (hdc: Hdc) -> Hglrc #link_name "wglCreateContext"; create_context :: proc(hdc: Hdc) -> Hglrc #link_name "wglCreateContext" ---;
proc make_current (hdc: Hdc, hglrc: Hglrc) -> Bool #link_name "wglMakeCurrent"; make_current :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool #link_name "wglMakeCurrent" ---;
proc get_proc_address (c_str: ^u8) -> Proc #link_name "wglGetProcAddress"; get_proc_address :: proc(c_str: ^u8) -> rawptr #link_name "wglGetProcAddress" ---;
proc delete_context (hglrc: Hglrc) -> Bool #link_name "wglDeleteContext"; delete_context :: proc(hglrc: Hglrc) -> Bool #link_name "wglDeleteContext" ---;
proc copy_context (src, dst: Hglrc, mask: u32) -> Bool #link_name "wglCopyContext"; copy_context :: proc(src, dst: Hglrc, mask: u32) -> Bool #link_name "wglCopyContext" ---;
proc create_layer_context (hdc: Hdc, layer_plane: i32) -> Hglrc #link_name "wglCreateLayerContext"; create_layer_context :: proc(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"; describe_layer_plane :: proc(hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^Layer_Plane_Descriptor) -> Bool #link_name "wglDescribeLayerPlane" ---;
proc get_current_context () -> Hglrc #link_name "wglGetCurrentContext"; get_current_context :: proc() -> Hglrc #link_name "wglGetCurrentContext" ---;
proc get_current_dc () -> Hdc #link_name "wglGetCurrentDC"; get_current_dc :: proc() -> Hdc #link_name "wglGetCurrentDC" ---;
proc get_layer_palette_entries(hdc: Hdc, layer_plane, start, entries: i32, cr: ^ColorRef) -> i32 #link_name "wglGetLayerPaletteEntries"; get_layer_palette_entries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #link_name "wglGetLayerPaletteEntries" ---;
proc realize_layer_palette (hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool #link_name "wglRealizeLayerPalette"; realize_layer_palette :: proc(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"; set_layer_palette_entries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #link_name "wglSetLayerPaletteEntries" ---;
proc share_lists (hglrc1, hglrc2: Hglrc) -> Bool #link_name "wglShareLists"; share_lists :: proc(hglrc1, hglrc2: Hglrc) -> Bool #link_name "wglShareLists" ---;
proc swap_layer_buffers (hdc: Hdc, planes: u32) -> Bool #link_name "wglSwapLayerBuffers"; swap_layer_buffers :: proc(hdc: Hdc, planes: u32) -> Bool #link_name "wglSwapLayerBuffers" ---;
proc use_font_bitmaps (hdc: Hdc, first, count, list_base: u32) -> Bool #link_name "wglUseFontBitmaps"; use_font_bitmaps :: proc(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"; use_font_outlines :: proc(hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_Metrics_Float) -> Bool #link_name "wglUseFontOutlines" ---;
} }
+409 -380
View File
@@ -6,119 +6,115 @@ foreign_system_library (
"shell32.lib" when ODIN_OS == "windows"; "shell32.lib" when ODIN_OS == "windows";
) )
type ( Handle :: rawptr;
Handle rawptr; Hwnd :: Handle;
Hwnd Handle; Hdc :: Handle;
Hdc Handle; Hinstance :: Handle;
Hinstance Handle; Hicon :: Handle;
Hicon Handle; Hcursor :: Handle;
Hcursor Handle; Hmenu :: Handle;
Hmenu Handle; Hbrush :: Handle;
Hbrush Handle; Hgdiobj :: Handle;
Hgdiobj Handle; Hmodule :: Handle;
Hmodule Handle; Hmonitor :: Handle;
Hmonitor Handle; Wparam :: uint;
Wparam uint; Lparam :: int;
Lparam int; Lresult :: int;
Lresult int; Wnd_Proc :: proc(Hwnd, u32, Wparam, Lparam) -> Lresult #cc_c;
WndProc proc(Hwnd, u32, Wparam, Lparam) -> Lresult #cc_c;
)
type Bool i32; Bool :: i32;
const ( FALSE: Bool : 0;
FALSE: Bool = 0; TRUE: Bool : 1;
TRUE = 1;
)
type Point struct #ordered { Point :: struct #ordered {
x, y: i32, x, y: i32;
} }
type WndClassExA struct #ordered { Wnd_Class_Ex_A :: struct #ordered {
size, style: u32, size, style: u32;
wnd_proc: WndProc, wnd_proc: Wnd_Proc;
cls_extra, wnd_extra: i32, cls_extra, wnd_extra: i32;
instance: Hinstance, instance: Hinstance;
icon: Hicon, icon: Hicon;
cursor: Hcursor, cursor: Hcursor;
background: Hbrush, background: Hbrush;
menu_name, class_name: ^u8, menu_name, class_name: ^u8;
sm: Hicon, sm: Hicon;
} }
type Msg struct #ordered { Msg :: struct #ordered {
hwnd: Hwnd, hwnd: Hwnd;
message: u32, message: u32;
wparam: Wparam, wparam: Wparam;
lparam: Lparam, lparam: Lparam;
time: u32, time: u32;
pt: Point, pt: Point;
} }
type Rect struct #ordered { Rect :: struct #ordered {
left: i32, left: i32;
top: i32, top: i32;
right: i32, right: i32;
bottom: i32, bottom: i32;
} }
type Filetime struct #ordered { Filetime :: struct #ordered {
lo, hi: u32, lo, hi: u32;
} }
type Systemtime struct #ordered { Systemtime :: struct #ordered {
year, month: u16, year, month: u16;
day_of_week, day: u16, day_of_week, day: u16;
hour, minute, second, millisecond: u16, hour, minute, second, millisecond: u16;
} }
type ByHandleFileInformation struct #ordered { By_Handle_File_Information :: struct #ordered {
file_attributes: u32, file_attributes: u32;
creation_time, creation_time,
last_access_time, last_access_time,
last_write_time: Filetime, last_write_time: Filetime;
volume_serial_number, volume_serial_number,
file_size_high, file_size_high,
file_size_low, file_size_low,
number_of_links, number_of_links,
file_index_high, file_index_high,
file_index_low: u32, file_index_low: u32;
} }
type FileAttributeData struct #ordered { File_Attribute_Data :: struct #ordered {
file_attributes: u32, file_attributes: u32;
creation_time, creation_time,
last_access_time, last_access_time,
last_write_time: Filetime, last_write_time: Filetime;
file_size_high, file_size_high,
file_size_low: u32, file_size_low: u32;
} }
type FindData struct #ordered { Find_Data :: struct #ordered{
file_attributes: u32, file_attributes: u32;
creation_time: Filetime, creation_time: Filetime;
last_access_time: Filetime, last_access_time: Filetime;
last_write_time: Filetime, last_write_time: Filetime;
file_size_high: u32, file_size_high: u32;
file_size_low: u32, file_size_low: u32;
reserved0: u32, reserved0: u32;
reserved1: u32, reserved1: u32;
file_name: [MAX_PATH]u8, file_name: [MAX_PATH]u8;
alternate_file_name: [14]u8, alternate_file_name: [14]u8;
} }
type Security_Attributes struct #ordered { Security_Attributes :: struct #ordered {
length: u32, length: u32;
security_descriptor: rawptr, security_descriptor: rawptr;
inherit_handle: Bool, inherit_handle: Bool;
} }
type PixelFormatDescriptor struct #ordered { Pixel_Format_Descriptor :: struct #ordered {
size, size,
version, version,
flags: u32, flags: u32;
pixel_type, pixel_type,
color_bits, color_bits,
@@ -139,420 +135,453 @@ type PixelFormatDescriptor struct #ordered {
stencil_bits, stencil_bits,
aux_buffers, aux_buffers,
layer_type, layer_type,
reserved: u8, reserved: u8;
layer_mask, layer_mask,
visible_mask, visible_mask,
damage_mask: u32, damage_mask: u32;
} }
Critical_Section :: struct #ordered {
debug_info: ^Critical_Section_Debug;
lock_count: i32;
recursion_count: i32;
owning_thread: Handle;
lock_semaphore: Handle;
spin_count: ^u32;
}
Critical_Section_Debug :: struct #ordered {
typ: u16;
creator_back_trace_index: u16;
critical_section: ^Critical_Section;
process_locks_list: ^List_Entry;
entry_count: u32;
contention_count: u32;
flags: u32;
creator_back_trace_index_high: u16;
spare_word: u16;
}
List_Entry :: struct #ordered {flink, blink: ^List_Entry};
type Proc proc() #cc_c; MAPVK_VK_TO_VSC :: 0;
MAPVK_VSC_TO_VK :: 1;
const ( MAPVK_VK_TO_CHAR :: 2;
MAPVK_VK_TO_VSC = 0; MAPVK_VSC_TO_VK_EX :: 3;
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 ( MONITOR_DEFAULTTONULL :: 0x00000000;
CS_VREDRAW = 0x0001; MONITOR_DEFAULTTOPRIMARY :: 0x00000001;
CS_HREDRAW = 0x0002; MONITOR_DEFAULTTONEAREST :: 0x00000002;
CS_OWNDC = 0x0020;
CW_USEDEFAULT = -0x80000000;
WS_OVERLAPPED = 0; SWP_FRAMECHANGED :: 0x0020;
WS_MAXIMIZEBOX = 0x00010000; SWP_NOOWNERZORDER :: 0x0200;
WS_MINIMIZEBOX = 0x00020000; SWP_NOZORDER :: 0x0004;
WS_THICKFRAME = 0x00040000; SWP_NOSIZE :: 0x0001;
WS_SYSMENU = 0x00080000; SWP_NOMOVE :: 0x0002;
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;
)
// Windows OpenGL // 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 { foreign kernel32 {
proc get_last_error () -> i32 #cc_std #link_name "GetLastError"; get_last_error :: proc() -> i32 #cc_std #link_name "GetLastError" ---;
proc exit_process (exit_code: u32) #cc_std #link_name "ExitProcess"; exit_process :: proc(exit_code: u32) #cc_std #link_name "ExitProcess" ---;
proc get_module_handle_a(module_name: ^u8) -> Hinstance #cc_std #link_name "GetModuleHandleA"; get_module_handle_a :: proc(module_name: ^u8) -> Hinstance #cc_std #link_name "GetModuleHandleA" ---;
proc sleep(ms: i32) -> i32 #cc_std #link_name "Sleep"; sleep :: proc(ms: i32) -> i32 #cc_std #link_name "Sleep" ---;
proc query_performance_frequency(result: ^i64) -> i32 #cc_std #link_name "QueryPerformanceFrequency"; query_performance_frequency :: proc(result: ^i64) -> i32 #cc_std #link_name "QueryPerformanceFrequency" ---;
proc query_performance_counter (result: ^i64) -> i32 #cc_std #link_name "QueryPerformanceCounter"; query_performance_counter :: proc(result: ^i64) -> i32 #cc_std #link_name "QueryPerformanceCounter" ---;
proc output_debug_string_a(c_str: ^u8) #cc_std #link_name "OutputDebugStringA"; output_debug_string_a :: proc(c_str: ^u8) #cc_std #link_name "OutputDebugStringA" ---;
proc get_command_line_a () -> ^u8 #cc_std #link_name "GetCommandLineA"; get_command_line_a :: proc() -> ^u8 #cc_std #link_name "GetCommandLineA" ---;
proc get_command_line_w () -> ^u16 #cc_std #link_name "GetCommandLineW"; get_command_line_w :: proc() -> ^u16 #cc_std #link_name "GetCommandLineW" ---;
proc get_system_metrics (index: i32) -> i32 #cc_std #link_name "GetSystemMetrics"; get_system_metrics :: proc(index: i32) -> i32 #cc_std #link_name "GetSystemMetrics" ---;
proc get_current_thread_id () -> u32 #cc_std #link_name "GetCurrentThreadId"; 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"; get_system_time_as_file_time :: proc(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"; file_time_to_local_file_time :: proc(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"; file_time_to_system_time :: proc(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"; 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"; close_handle :: proc(h: Handle) -> i32 #cc_std #link_name "CloseHandle" ---;
proc get_std_handle(h: i32) -> Handle #cc_std #link_name "GetStdHandle"; get_std_handle :: proc(h: i32) -> Handle #cc_std #link_name "GetStdHandle" ---;
proc create_file_a (filename: ^u8, desired_access, share_mode: u32, create_file_a :: proc(filename: ^u8, desired_access, share_mode: u32,
security: rawptr, security: rawptr,
creation, flags_and_attribs: u32, template_file: Handle) -> Handle #cc_std #link_name "CreateFileA"; 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"; read_file :: proc(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"; 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"; get_file_size_ex :: proc(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"; get_file_attributes_a :: proc(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"; get_file_attributes_ex_a :: proc(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_information_by_handle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool #cc_std #link_name "GetFileInformationByHandle" ---;
proc get_file_type (file_handle: Handle) -> u32 #cc_std #link_name "GetFileType"; get_file_type :: proc(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"; 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"; find_first_file_a :: proc(file_name : ^u8, data : ^Find_Data) -> Handle #cc_std #link_name "FindFirstFileA" ---;
proc find_next_file_a (file : Handle, data : ^FindData) -> Bool #cc_std #link_name "FindNextFileA"; find_next_file_a :: proc(file : Handle, data : ^Find_Data) -> Bool #cc_std #link_name "FindNextFileA" ---;
proc find_close (file : Handle) -> Bool #cc_std #link_name "FindClose"; 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"; heap_alloc :: proc(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"; heap_realloc :: proc(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"; heap_free :: proc(h: Handle, flags: u32, memory: rawptr) -> Bool #cc_std #link_name "HeapFree" ---;
proc get_process_heap() -> Handle #cc_std #link_name "GetProcessHeap"; 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"; create_semaphore_a :: proc(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"; release_semaphore :: proc(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"; 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"; interlocked_compare_exchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #cc_c #link_name "InterlockedCompareExchange" ---;
proc interlocked_exchange (dst: ^i32, desired: i32) -> i32 #cc_std #link_name "InterlockedExchange"; interlocked_exchange :: proc(dst: ^i32, desired: i32) -> i32 #cc_c #link_name "InterlockedExchange" ---;
proc interlocked_exchange_add (dst: ^i32, desired: i32) -> i32 #cc_std #link_name "InterlockedExchangeAdd"; interlocked_exchange_add :: proc(dst: ^i32, desired: i32) -> i32 #cc_c #link_name "InterlockedExchangeAdd" ---;
proc interlocked_and (dst: ^i32, desired: i32) -> i32 #cc_std #link_name "InterlockedAnd"; interlocked_and :: proc(dst: ^i32, desired: i32) -> i32 #cc_c #link_name "InterlockedAnd" ---;
proc interlocked_or (dst: ^i32, desired: i32) -> i32 #cc_std #link_name "InterlockedOr"; 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"; interlocked_compare_exchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #cc_c #link_name "InterlockedCompareExchange64" ---;
proc interlocked_exchange64 (dst: ^i64, desired: i64) -> i64 #cc_std #link_name "InterlockedExchange64"; interlocked_exchange64 :: proc(dst: ^i64, desired: i64) -> i64 #cc_c #link_name "InterlockedExchange64" ---;
proc interlocked_exchange_add64 (dst: ^i64, desired: i64) -> i64 #cc_std #link_name "InterlockedExchangeAdd64"; interlocked_exchange_add64 :: proc(dst: ^i64, desired: i64) -> i64 #cc_c #link_name "InterlockedExchangeAdd64" ---;
proc interlocked_and64 (dst: ^i64, desired: i64) -> i64 #cc_std #link_name "InterlockedAnd64"; interlocked_and64 :: proc(dst: ^i64, desired: i64) -> i64 #cc_c #link_name "InterlockedAnd64" ---;
proc interlocked_or64 (dst: ^i64, desired: i64) -> i64 #cc_std #link_name "InterlockedOr64"; interlocked_or64 :: proc(dst: ^i64, desired: i64) -> i64 #cc_c #link_name "InterlockedOr64" ---;
proc mm_pause () #cc_std #link_name "_mm_pause"; mm_pause :: proc() #cc_std #link_name "_mm_pause" ---;
proc read_write_barrier() #cc_std #link_name "ReadWriteBarrier"; read_write_barrier :: proc() #cc_std #link_name "ReadWriteBarrier" ---;
proc write_barrier () #cc_std #link_name "WriteBarrier"; write_barrier :: proc() #cc_std #link_name "WriteBarrier" ---;
proc read_barrier () #cc_std #link_name "ReadBarrier"; read_barrier :: proc() #cc_std #link_name "ReadBarrier" ---;
create_thread :: proc(thread_attributes: ^Security_Attributes, 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"; initialize_critical_section :: proc(critical_section: ^Critical_Section) #cc_std #link_name "InitializeCriticalSection" ---;
proc free_library (h: Hmodule) #cc_std #link_name "FreeLibrary"; initialize_critical_section_and_spin_count :: proc(critical_section: ^Critical_Section, spin_count: u32) #cc_std #link_name "InitializeCriticalSectionAndSpinCount" ---;
proc get_proc_address(h: Hmodule, c_str: ^u8) -> Proc #cc_std #link_name "GetProcAddress"; delete_critical_section :: proc(critical_section: ^Critical_Section) #cc_std #link_name "DeleteCriticalSection" ---;
set_critical_section_spin_count :: proc(critical_section: ^Critical_Section, spin_count: u32) -> u32 #cc_std #link_name "SetCriticalSectionSpinCount" ---;
try_enter_critical_section :: proc(critical_section: ^Critical_Section) -> Bool #cc_std #link_name "TryEnterCriticalSection" ---;
enter_critical_section :: proc(critical_section: ^Critical_Section) #cc_std #link_name "EnterCriticalSection" ---;
leave_critical_section :: proc(critical_section: ^Critical_Section) #cc_std #link_name "LeaveCriticalSection" ---;
create_event_a :: proc(event_attributes: ^Security_Attributes, 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 { foreign user32 {
proc get_desktop_window () -> Hwnd #cc_std #link_name "GetDesktopWindow"; get_desktop_window :: proc() -> Hwnd #cc_std #link_name "GetDesktopWindow" ---;
proc show_cursor (show : Bool) #cc_std #link_name "ShowCursor"; show_cursor :: proc(show : Bool) #cc_std #link_name "ShowCursor" ---;
proc get_cursor_pos (p: ^Point) -> i32 #cc_std #link_name "GetCursorPos"; get_cursor_pos :: proc(p: ^Point) -> i32 #cc_std #link_name "GetCursorPos" ---;
proc screen_to_client (h: Hwnd, p: ^Point) -> i32 #cc_std #link_name "ScreenToClient"; screen_to_client :: proc(h: Hwnd, p: ^Point) -> i32 #cc_std #link_name "ScreenToClient" ---;
proc post_quit_message (exit_code: i32) #cc_std #link_name "PostQuitMessage"; post_quit_message :: proc(exit_code: i32) #cc_std #link_name "PostQuitMessage" ---;
proc set_window_text_a (hwnd: Hwnd, c_string: ^u8) -> Bool #cc_std #link_name "SetWindowTextA"; set_window_text_a :: proc(hwnd: Hwnd, c_string: ^u8) -> Bool #cc_std #link_name "SetWindowTextA" ---;
proc register_class_ex_a (wc: ^WndClassExA) -> i16 #cc_std #link_name "RegisterClassExA"; register_class_ex_a :: proc(wc: ^Wnd_Class_Ex_A) -> i16 #cc_std #link_name "RegisterClassExA" ---;
proc create_window_ex_a (ex_style: u32, create_window_ex_a :: proc(ex_style: u32,
class_name, title: ^u8, class_name, title: ^u8,
style: u32, style: u32,
x, y, w, h: i32, x, y, w, h: i32,
parent: Hwnd, menu: Hmenu, instance: Hinstance, parent: Hwnd, menu: Hmenu, instance: Hinstance,
param: rawptr) -> Hwnd #cc_std #link_name "CreateWindowExA"; param: rawptr) -> Hwnd #cc_std #link_name "CreateWindowExA" ---;
proc show_window (hwnd: Hwnd, cmd_show: i32) -> Bool #cc_std #link_name "ShowWindow"; show_window :: proc(hwnd: Hwnd, cmd_show: i32) -> Bool #cc_std #link_name "ShowWindow" ---;
proc translate_message (msg: ^Msg) -> Bool #cc_std #link_name "TranslateMessage"; translate_message :: proc(msg: ^Msg) -> Bool #cc_std #link_name "TranslateMessage" ---;
proc dispatch_message_a (msg: ^Msg) -> Lresult #cc_std #link_name "DispatchMessageA"; dispatch_message_a :: proc(msg: ^Msg) -> Lresult #cc_std #link_name "DispatchMessageA" ---;
proc update_window (hwnd: Hwnd) -> Bool #cc_std #link_name "UpdateWindow"; update_window :: proc(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"; get_message_a :: proc(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, peek_message_a :: proc(msg: ^Msg, hwnd: Hwnd,
msg_filter_min, msg_filter_max, remove_msg: u32) -> Bool #cc_std #link_name "PeekMessageA"; 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"; adjust_window_rect :: proc(rect: ^Rect, style: u32, menu: Bool) -> Bool #cc_std #link_name "AdjustWindowRect" ---;
proc get_active_window () -> Hwnd #cc_std #link_name "GetActiveWindow"; get_active_window :: proc() -> Hwnd #cc_std #link_name "GetActiveWindow" ---;
proc destroy_window (wnd: Hwnd) -> Bool #cc_std #link_name "DestroyWindow"; destroy_window :: proc(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"; describe_pixel_format :: proc(dc: Hdc, pixel_format: i32, bytes: u32, pfd: ^Pixel_Format_Descriptor) -> i32 #cc_std #link_name "DescribePixelFormat" ---;
proc get_monitor_info_a (monitor: Hmonitor, mi: ^MonitorInfo) -> Bool #cc_std #link_name "GetMonitorInfoA"; get_monitor_info_a :: proc(monitor: Hmonitor, mi: ^Monitor_Info) -> Bool #cc_std #link_name "GetMonitor_InfoA" ---;
proc monitor_from_window (wnd: Hwnd, flags : u32) -> Hmonitor #cc_std #link_name "MonitorFromWindow"; 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"; get_window_placement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool #cc_std #link_name "GetWindowPlacement" ---;
proc set_window_placement (wnd: Hwnd, wndpl: ^WindowPlacement) -> Bool #cc_std #link_name "SetWindowPlacement"; set_window_placement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool #cc_std #link_name "SetWindowPlacement" ---;
proc get_window_rect (wnd: Hwnd, rect: ^Rect) -> Bool #cc_std #link_name "GetWindowRect"; 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"; get_window_long_ptr_a :: proc(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"; 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"; get_dc :: proc(h: Hwnd) -> Hdc #cc_std #link_name "GetDC" ---;
proc release_dc (wnd: Hwnd, hdc: Hdc) -> i32 #cc_std #link_name "ReleaseDC"; 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"; get_key_state :: proc(v_key: i32) -> i16 #cc_std #link_name "GetKeyState" ---;
proc get_async_key_state(v_key: i32) -> i16 #cc_std #link_name "GetAsyncKeyState"; get_async_key_state :: proc(v_key: i32) -> i16 #cc_std #link_name "GetAsyncKeyState" ---;
} }
foreign gdi32 { 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_dst, y_dst, width_dst, height_dst: i32,
x_src, y_src, width_src, header_src: i32, x_src, y_src, width_src, header_src: i32,
bits: rawptr, bits_info: ^BitmapInfo, bits: rawptr, bits_info: ^BitmapInfo,
usage: u32, usage: u32,
rop: u32) -> i32 #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"; set_pixel_format :: proc(hdc: Hdc, pixel_format: i32, pfd: ^Pixel_Format_Descriptor) -> Bool #cc_std #link_name "SetPixelFormat" ---;
proc choose_pixel_format(hdc: Hdc, pfd: ^PixelFormatDescriptor) -> i32 #cc_std #link_name "ChoosePixelFormat"; choose_pixel_format :: proc(hdc: Hdc, pfd: ^Pixel_Format_Descriptor) -> i32 #cc_std #link_name "ChoosePixelFormat" ---;
proc swap_buffers (hdc: Hdc) -> Bool #cc_std #link_name "SwapBuffers"; swap_buffers :: proc(hdc: Hdc) -> Bool #cc_std #link_name "SwapBuffers" ---;
} }
foreign shell32 { 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 { 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 { get_query_performance_frequency :: proc() -> i64 {
var r: i64; r: i64;
query_performance_frequency(&r); query_performance_frequency(&r);
return r; return r;
} }
proc HIWORD(wParam: Wparam) -> u16 { return u16((u32(wParam) >> 16) & 0xffff); } HIWORD :: proc(wParam: Wparam) -> u16 { return u16((u32(wParam) >> 16) & 0xffff); }
proc HIWORD(lParam: Lparam) -> u16 { return u16((u32(lParam) >> 16) & 0xffff); } HIWORD :: proc(lParam: Lparam) -> u16 { return u16((u32(lParam) >> 16) & 0xffff); }
proc LOWORD(wParam: Wparam) -> u16 { return u16(wParam); } LOWORD :: proc(wParam: Wparam) -> u16 { return u16(wParam); }
proc LOWORD(lParam: Lparam) -> u16 { return u16(lParam); } 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: Key_Code) -> bool #inline { return get_async_key_state(i32(key)) < 0; }
const (
MAX_PATH = 0x00000104;
HANDLE_FLAG_INHERIT = 1; MAX_PATH :: 0x00000104;
HANDLE_FLAG_PROTECT_FROM_CLOSE = 2;
FILE_BEGIN = 0; HANDLE_FLAG_INHERIT :: 1;
FILE_CURRENT = 1; HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
FILE_END = 2;
FILE_SHARE_READ = 0x00000001; FILE_BEGIN :: 0;
FILE_SHARE_WRITE = 0x00000002; FILE_CURRENT :: 1;
FILE_SHARE_DELETE = 0x00000004; FILE_END :: 2;
FILE_GENERIC_ALL = 0x10000000;
FILE_GENERIC_EXECUTE = 0x20000000;
FILE_GENERIC_WRITE = 0x40000000;
FILE_GENERIC_READ = 0x80000000;
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; FILE_APPEND_DATA :: 0x0004;
STD_OUTPUT_HANDLE = -11;
STD_ERROR_HANDLE = -12;
CREATE_NEW = 1; STD_INPUT_HANDLE :: -10;
CREATE_ALWAYS = 2; STD_OUTPUT_HANDLE :: -11;
OPEN_EXISTING = 3; STD_ERROR_HANDLE :: -12;
OPEN_ALWAYS = 4;
TRUNCATE_EXISTING = 5;
INVALID_FILE_ATTRIBUTES = -1; CREATE_NEW :: 1;
CREATE_ALWAYS :: 2;
OPEN_EXISTING :: 3;
OPEN_ALWAYS :: 4;
TRUNCATE_EXISTING :: 5;
FILE_ATTRIBUTE_READONLY = 0x00000001; INVALID_FILE_ATTRIBUTES :: -1;
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_ATTRIBUTE_READONLY :: 0x00000001;
FILE_TYPE_CHAR = 0x0002; FILE_ATTRIBUTE_HIDDEN :: 0x00000002;
FILE_TYPE_PIPE = 0x0003; 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 { Monitor_Info :: struct #ordered {
size: u32, size: u32;
monitor: Rect, monitor: Rect;
work: Rect, work: Rect;
flags: u32, flags: u32;
} }
type WindowPlacement struct #ordered { Window_Placement :: struct #ordered {
length: u32, length: u32;
flags: u32, flags: u32;
show_cmd: u32, show_cmd: u32;
min_pos: Point, min_pos: Point;
max_pos: Point, max_pos: Point;
normal_pos: Rect, normal_pos: Rect;
} }
type BitmapInfoHeader struct #ordered { Bitmap_Info_Header :: struct #ordered {
size: u32, size: u32;
width, height: i32, width, height: i32;
planes, bit_count: i16, planes, bit_count: i16;
compression: u32, compression: u32;
size_image: u32, size_image: u32;
x_pels_per_meter: i32, x_pels_per_meter: i32;
y_pels_per_meter: i32, y_pels_per_meter: i32;
clr_used: u32, clr_used: u32;
clr_important: u32, clr_important: u32;
} }
type BitmapInfo struct #ordered { BitmapInfo :: struct #ordered {
using header: BitmapInfoHeader, using header: Bitmap_Info_Header;
colors: [1]RgbQuad, colors: [1]Rgb_Quad;
} }
type RgbQuad struct #ordered { blue, green, red, reserved: u8 } Rgb_Quad :: struct #ordered {blue, green, red, reserved: u8}
type KeyCode enum i32 { Key_Code :: enum i32 {
Lbutton = 0x01, Lbutton = 0x01,
Rbutton = 0x02, Rbutton = 0x02,
Cancel = 0x03, Cancel = 0x03,
+76
View File
@@ -0,0 +1,76 @@
_ :: compile_assert(ODIN_OS == "windows");
import win32 "sys/windows.odin";
Thread :: struct {
using specific: Os_Specific;
procedure: Proc;
data: any;
user_index: int;
init_context: Context;
use_init_context: bool;
Proc :: #type proc(^Thread) -> int;
Os_Specific :: 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);
}
+66 -61
View File
@@ -1,98 +1,103 @@
proc is_signed(info: ^TypeInfo) -> bool { is_signed :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
match i in type_info_base(info) { match i in type_info_base(info).variant {
case TypeInfo.Integer: return i.signed; case Type_Info.Integer: return i.signed;
case TypeInfo.Float: return true; case Type_Info.Float: return true;
} }
return false; return false;
} }
proc is_integer(info: ^TypeInfo) -> bool { is_integer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Integer); _, ok := type_info_base(info).variant.(Type_Info.Integer);
return ok; return ok;
} }
proc is_float(info: ^TypeInfo) -> bool { is_rune :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Float); _, ok := type_info_base(info).variant.(Type_Info.Rune);
return ok; return ok;
} }
proc is_complex(info: ^TypeInfo) -> bool { is_float :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Complex); _, ok := type_info_base(info).variant.(Type_Info.Float);
return ok; return ok;
} }
proc is_any(info: ^TypeInfo) -> bool { is_complex :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Any); _, ok := type_info_base(info).variant.(Type_Info.Complex);
return ok; return ok;
} }
proc is_string(info: ^TypeInfo) -> bool { is_any :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.String); _, ok := type_info_base(info).variant.(Type_Info.Any);
return ok; return ok;
} }
proc is_boolean(info: ^TypeInfo) -> bool { is_string :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Boolean); _, ok := type_info_base(info).variant.(Type_Info.String);
return ok; return ok;
} }
proc is_pointer(info: ^TypeInfo) -> bool { is_boolean :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Pointer); _, ok := type_info_base(info).variant.(Type_Info.Boolean);
return ok; return ok;
} }
proc is_procedure(info: ^TypeInfo) -> bool { is_pointer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Procedure); _, ok := type_info_base(info).variant.(Type_Info.Pointer);
return ok; return ok;
} }
proc is_array(info: ^TypeInfo) -> bool { is_procedure :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Array); _, ok := type_info_base(info).variant.(Type_Info.Procedure);
return ok; return ok;
} }
proc is_dynamic_array(info: ^TypeInfo) -> bool { is_array :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.DynamicArray); _, ok := type_info_base(info).variant.(Type_Info.Array);
return ok; return ok;
} }
proc is_dynamic_map(info: ^TypeInfo) -> bool { is_dynamic_array :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Map); _, ok := type_info_base(info).variant.(Type_Info.Dynamic_Array);
return ok; return ok;
} }
proc is_slice(info: ^TypeInfo) -> bool { is_dynamic_map :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Slice); _, ok := type_info_base(info).variant.(Type_Info.Map);
return ok; return ok;
} }
proc is_vector(info: ^TypeInfo) -> bool { is_slice :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Vector); _, ok := type_info_base(info).variant.(Type_Info.Slice);
return ok; return ok;
} }
proc is_tuple(info: ^TypeInfo) -> bool { is_vector :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Tuple); _, ok := type_info_base(info).variant.(Type_Info.Vector);
return ok; return ok;
} }
proc is_struct(info: ^TypeInfo) -> bool { is_tuple :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Struct); _, ok := type_info_base(info).variant.(Type_Info.Tuple);
return ok; return ok;
} }
proc is_union(info: ^TypeInfo) -> bool { is_struct :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.Union); s, ok := type_info_base(info).variant.(Type_Info.Struct);
return ok && !s.is_raw_union;
}
is_raw_union :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
s, ok := type_info_base(info).variant.(Type_Info.Struct);
return ok && s.is_raw_union;
}
is_union :: proc(info: ^Type_Info) -> bool {
if info == nil do return false;
_, ok := type_info_base(info).variant.(Type_Info.Union);
return ok; return ok;
} }
proc is_raw_union(info: ^TypeInfo) -> bool { is_enum :: proc(info: ^Type_Info) -> bool {
if info == nil { return false; } if info == nil do return false;
var _, ok = type_info_base(info).(^TypeInfo.RawUnion); _, ok := type_info_base(info).variant.(Type_Info.Enum);
return ok;
}
proc is_enum(info: ^TypeInfo) -> bool {
if info == nil { return false; }
var _, ok = type_info_base(info).(^TypeInfo.Enum);
return ok; return ok;
} }
+18 -23
View File
@@ -1,18 +1,17 @@
const ( REPLACEMENT_CHAR :: '\uFFFD';
REPLACEMENT_CHAR = '\uFFFD'; MAX_RUNE :: '\U0010FFFF';
MAX_RUNE = '\U0010FFFF';
_surr1 = 0xd800; _surr1 :: 0xd800;
_surr2 = 0xdc00; _surr2 :: 0xdc00;
_surr3 = 0xe000; _surr3 :: 0xe000;
_surr_self = 0x10000; _surr_self :: 0x10000;
)
proc is_surrogate(r: rune) -> bool {
is_surrogate :: proc(r: rune) -> bool {
return _surr1 <= r && r < _surr3; 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 { if _surr1 <= r1 && r1 < _surr2 && _surr2 <= r2 && r2 < _surr3 {
return (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self; 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 { if r < _surr_self || r > MAX_RUNE {
return REPLACEMENT_CHAR, REPLACEMENT_CHAR; 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; return _surr1 + (r>>10)&0x3ff, _surr2 + r&0x3ff;
} }
proc encode(d: []u16, s: []rune) { encode :: proc(d: []u16, s: []rune) {
var n = len(s); n := len(s);
for r in s { for r in s do if r >= _surr_self do n += 1;
if r >= _surr_self {
n++;
}
}
var max_n = min(len(d), n); max_n := min(len(d), n);
n = 0; n = 0;
for r in s { for r in s {
match r { match r {
case 0..<_surr1, _surr3..<_surr_self: case 0.._surr1, _surr3.._surr_self:
d[n] = u16(r); d[n] = u16(r);
n++; n += 1;
case _surr_self..MAX_RUNE: case _surr_self..MAX_RUNE:
var r1, r2 = encode_surrogate_pair(r); r1, r2 := encode_surrogate_pair(r);
d[n] = u16(r1); d[n] = u16(r1);
d[n+1] = u16(r2); d[n+1] = u16(r2);
n += 2; n += 2;
case: case:
d[n] = u16(REPLACEMENT_CHAR); d[n] = u16(REPLACEMENT_CHAR);
n++; n += 1;
} }
} }
} }
+102 -110
View File
@@ -1,71 +1,67 @@
const ( RUNE_ERROR :: '\ufffd';
RUNE_ERROR = '\ufffd'; RUNE_SELF :: 0x80;
RUNE_SELF = 0x80; RUNE_BOM :: 0xfeff;
RUNE_BOM = 0xfeff; RUNE_EOF :: ~rune(0);
RUNE_EOF = ~rune(0); MAX_RUNE :: '\U0010ffff';
MAX_RUNE = '\U0010ffff'; UTF_MAX :: 4;
UTF_MAX = 4;
SURROGATE_MIN = 0xd800; SURROGATE_MIN :: 0xd800;
SURROGATE_MAX = 0xdfff; SURROGATE_MAX :: 0xdfff;
T1 = 0b0000_0000; T1 :: 0b0000_0000;
TX = 0b1000_0000; TX :: 0b1000_0000;
T2 = 0b1100_0000; T2 :: 0b1100_0000;
T3 = 0b1110_0000; T3 :: 0b1110_0000;
T4 = 0b1111_0000; T4 :: 0b1111_0000;
T5 = 0b1111_1000; T5 :: 0b1111_1000;
MASKX = 0b0011_1111; MASKX :: 0b0011_1111;
MASK2 = 0b0001_1111; MASK2 :: 0b0001_1111;
MASK3 = 0b0000_1111; MASK3 :: 0b0000_1111;
MASK4 = 0b0000_0111; MASK4 :: 0b0000_0111;
RUNE1_MAX = 1<<7 - 1; RUNE1_MAX :: 1<<7 - 1;
RUNE2_MAX = 1<<11 - 1; RUNE2_MAX :: 1<<11 - 1;
RUNE3_MAX = 1<<16 - 1; RUNE3_MAX :: 1<<16 - 1;
// The default lowest and highest continuation byte. // The default lowest and highest continuation byte.
LOCB = 0b1000_0000; LOCB :: 0b1000_0000;
HICB = 0b1011_1111; HICB :: 0b1011_1111;
)
type AcceptRange struct { lo, hi: u8 } Accept_Range :: struct {lo, hi: u8};
var ( accept_ranges := [5]Accept_Range{
accept_ranges = [5]AcceptRange{ {0x80, 0xbf},
{0x80, 0xbf}, {0xa0, 0xbf},
{0xa0, 0xbf}, {0x80, 0x9f},
{0x80, 0x9f}, {0x90, 0xbf},
{0x90, 0xbf}, {0x80, 0x8f},
{0x80, 0x8f}, };
};
accept_sizes = [256]u8{ 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, // 0x00-0x0f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
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, // 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, // 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, // 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, // 0x60-0x6f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f 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, // 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, // 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, // 0xa0-0xaf
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf 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 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 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 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 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) { encode_rune :: proc(r: rune) -> ([4]u8, int) {
var buf: [4]u8; buf: [4]u8;
var i = u32(r); i := u32(r);
const mask: u8 = 0x3f; mask: u8 : 0x3f;
if i <= 1<<7-1 { if i <= 1<<7-1 {
buf[0] = u8(r); buf[0] = u8(r);
return buf, 1; return buf, 1;
@@ -96,38 +92,38 @@ proc encode_rune(r: rune) -> ([4]u8, int) {
return buf, 4; return buf, 4;
} }
proc decode_rune(s: string) -> (rune, int) #inline { return decode_rune([]u8(s)); } decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune(cast([]u8)s); }
proc decode_rune(s: []u8) -> (rune, int) { decode_rune :: proc(s: []u8) -> (rune, int) {
var n = len(s); n := len(s);
if n < 1 { if n < 1 {
return RUNE_ERROR, 0; return RUNE_ERROR, 0;
} }
var s0 = s[0]; s0 := s[0];
var x = accept_sizes[s0]; x := accept_sizes[s0];
if x >= 0xF0 { 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; return rune(s[0])&~mask | RUNE_ERROR&mask, 1;
} }
var sz = x & 7; sz := x & 7;
var accept = accept_ranges[x>>4]; accept := accept_ranges[x>>4];
if n < int(sz) { if n < int(sz) {
return RUNE_ERROR, 1; return RUNE_ERROR, 1;
} }
var b1 = s[1]; b1 := s[1];
if b1 < accept.lo || accept.hi < b1 { if b1 < accept.lo || accept.hi < b1 {
return RUNE_ERROR, 1; return RUNE_ERROR, 1;
} }
if sz == 2 { if sz == 2 {
return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2; return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2;
} }
var b2 = s[2]; b2 := s[2];
if b2 < LOCB || HICB < b2 { if b2 < LOCB || HICB < b2 {
return RUNE_ERROR, 1; return RUNE_ERROR, 1;
} }
if sz == 3 { if sz == 3 {
return rune(s0&MASK3)<<12 | rune(b1&MASKX)<<6 | rune(b2&MASKX), 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 { if b3 < LOCB || HICB < b3 {
return RUNE_ERROR, 1; 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)); } decode_last_rune :: proc(s: string) -> (rune, int) #inline { return decode_last_rune(cast([]u8)s); }
proc decode_last_rune(s: []u8) -> (rune, int) { decode_last_rune :: proc(s: []u8) -> (rune, int) {
var r: rune; r: rune;
var size: int; size: int;
var start, end, limit: int; start, end, limit: int;
end = len(s); end = len(s);
if end == 0 { if end == 0 {
@@ -155,16 +151,12 @@ proc decode_last_rune(s: []u8) -> (rune, int) {
limit = max(end - UTF_MAX, 0); limit = max(end - UTF_MAX, 0);
start--; for start-=1; start >= limit; start-=1 {
for start >= limit { if rune_start(s[start]) do break;
if rune_start(s[start]) {
break;
}
start--;
} }
start = max(start, 0); start = max(start, 0);
r, size = decode_rune(s[start..<end]); r, size = decode_rune(s[start..end]);
if start+size != end { if start+size != end {
return RUNE_ERROR, 1; 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 { if r < 0 {
return false; return false;
} else if SURROGATE_MIN <= r && r <= SURROGATE_MAX { } else if SURROGATE_MIN <= r && r <= SURROGATE_MAX {
@@ -186,32 +178,32 @@ proc valid_rune(r: rune) -> bool {
return true; return true;
} }
proc valid_string(s: string) -> bool { valid_string :: proc(s: string) -> bool {
var n = len(s); n := len(s);
for var i = 0; i < n; { for i := 0; i < n; {
var si = s[i]; si := s[i];
if si < RUNE_SELF { // ascii if si < RUNE_SELF { // ascii
i++; i += 1;
continue; continue;
} }
var x = accept_sizes[si]; x := accept_sizes[si];
if x == 0xf1 { if x == 0xf1 {
return false; return false;
} }
var size = int(x & 7); size := int(x & 7);
if i+size > n { if i+size > n {
return false; return false;
} }
var ar = accept_ranges[x>>4]; ar := accept_ranges[x>>4];
if var b = s[i+1]; b < ar.lo || ar.hi < b { if b := s[i+1]; b < ar.lo || ar.hi < b {
return false; return false;
} else if size == 2 { } else if size == 2 {
// Okay // Okay
} else if var b = s[i+2]; b < 0x80 || 0xbf < b { } else if b := s[i+2]; b < 0x80 || 0xbf < b {
return false; return false;
} else if size == 3 { } else if size == 3 {
// Okay // Okay
} else if var b = s[i+3]; b < 0x80 || 0xbf < b { } else if b := s[i+3]; b < 0x80 || 0xbf < b {
return false; return false;
} }
i += size; i += size;
@@ -219,40 +211,40 @@ proc valid_string(s: string) -> bool {
return true; 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)); } rune_count :: proc(s: string) -> int #inline { return rune_count(cast([]u8)s); }
proc rune_count(s: []u8) -> int { rune_count :: proc(s: []u8) -> int {
var count = 0; count := 0;
var n = len(s); n := len(s);
for var i = 0; i < n; { for i := 0; i < n; {
defer count++; defer count += 1;
var si = s[i]; si := s[i];
if si < RUNE_SELF { // ascii if si < RUNE_SELF { // ascii
i++; i += 1;
continue; continue;
} }
var x = accept_sizes[si]; x := accept_sizes[si];
if x == 0xf1 { if x == 0xf1 {
i++; i += 1;
continue; continue;
} }
var size = int(x & 7); size := int(x & 7);
if i+size > n { if i+size > n {
i++; i += 1;
continue; continue;
} }
var ar = accept_ranges[x>>4]; ar := accept_ranges[x>>4];
if var b = s[i+1]; b < ar.lo || ar.hi < b { if b := s[i+1]; b < ar.lo || ar.hi < b {
size = 1; size = 1;
} else if size == 2 { } else if size == 2 {
// Okay // Okay
} else if var b = s[i+2]; b < 0x80 || 0xbf < b { } else if b := s[i+2]; b < 0x80 || 0xbf < b {
size = 1; size = 1;
} else if size == 3 { } else if size == 3 {
// Okay // Okay
} else if var b = s[i+3]; b < 0x80 || 0xbf < b { } else if b := s[i+3]; b < 0x80 || 0xbf < b {
size = 1; size = 1;
} }
i += size; 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 { match {
case r < 0: return -1; case r < 0: return -1;
case r <= 1<<7 - 1: return 1; case r <= 1<<7 - 1: return 1;
+11 -8
View File
@@ -10,12 +10,16 @@ struct Array {
isize capacity; isize capacity;
T &operator[](isize index) { 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]; return data[index];
} }
T const &operator[](isize index) const { 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]; 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_resize (Array<T> *array, isize count);
template <typename T> void array_set_capacity(Array<T> *array, isize capacity); template <typename T> void array_set_capacity(Array<T> *array, isize capacity);
template <typename T> template <typename T>
void array_init(Array<T> *array, gbAllocator a, isize init_capacity) { void array_init(Array<T> *array, gbAllocator a, isize init_capacity) {
array->allocator = a; array->allocator = a;
@@ -61,7 +64,7 @@ Array<T> array_make(T *data, isize count, isize capacity) {
template <typename T> template <typename T>
void array_free(Array<T> *array) { void array_free(Array<T> *array) {
if (array->allocator.proc != NULL) { if (array->allocator.proc != nullptr) {
gb_free(array->allocator, array->data); gb_free(array->allocator, array->data);
} }
array->count = 0; array->count = 0;
@@ -123,7 +126,7 @@ void array_set_capacity(Array<T> *array, isize capacity) {
array_resize(array, capacity); array_resize(array, capacity);
} }
T *new_data = NULL; T *new_data = nullptr;
if (capacity > 0) { if (capacity > 0) {
new_data = gb_alloc_array(array->allocator, T, capacity); new_data = gb_alloc_array(array->allocator, T, capacity);
gb_memmove(new_data, array->data, gb_size_of(T) * array->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 { \ #define array_init_reserve(x_, allocator_, init_capacity_) do { \
void **e = cast(void **)&((x_)->e); \ void **e = cast(void **)&((x_)->e); \
GB_ASSERT((x_) != NULL); \ GB_ASSERT((x_) != nullptr); \
(x_)->allocator = (allocator_); \ (x_)->allocator = (allocator_); \
(x_)->count = 0; \ (x_)->count = 0; \
(x_)->capacity = (init_capacity_); \ (x_)->capacity = (init_capacity_); \
@@ -156,7 +159,7 @@ typedef Array(void) ArrayVoid;
#define array_init_count(x_, allocator_, init_count_) do { \ #define array_init_count(x_, allocator_, init_count_) do { \
void **e = cast(void **)&((x_)->e); \ void **e = cast(void **)&((x_)->e); \
GB_ASSERT((x_) != NULL); \ GB_ASSERT((x_) != nullptr); \
(x_)->allocator = (allocator_); \ (x_)->allocator = (allocator_); \
(x_)->count = (init_count_); \ (x_)->count = (init_count_); \
(x_)->capacity = (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) { void array__set_capacity(void *ptr, isize capacity, isize element_size) {
ArrayVoid *x = cast(ArrayVoid *)ptr; ArrayVoid *x = cast(ArrayVoid *)ptr;
GB_ASSERT(ptr != NULL); GB_ASSERT(ptr != nullptr);
GB_ASSERT(element_size > 0); GB_ASSERT(element_size > 0);
+41 -18
View File
@@ -18,6 +18,11 @@ struct BuildContext {
bool is_dll; bool is_dll;
bool generate_docs; bool generate_docs;
i32 optimization_level; 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; len = 0;
for (;;) { for (;;) {
len = GetModuleFileNameW(NULL, &path_buf[0], path_buf.count); len = GetModuleFileNameW(nullptr, &path_buf[0], cast(int)path_buf.count);
if (len == 0) { if (len == 0) {
return make_string(NULL, 0); return make_string(nullptr, 0);
} }
if (len < path_buf.count) { if (len < path_buf.count) {
break; break;
@@ -64,12 +69,15 @@ String odin_root_dir(void) {
} }
len += 1; // NOTE(bill): It needs an extra 1 for some reason 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); 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); 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)); path = string16_to_string(heap_allocator(), make_string16(text, len));
for (i = path.len-1; i >= 0; i--) { for (i = path.len-1; i >= 0; i--) {
@@ -83,7 +91,6 @@ String odin_root_dir(void) {
global_module_path = path; global_module_path = path;
global_module_path_set = true; global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
array_free(&path_buf); 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); 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); text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
gb_memmove(text, &path_buf[0], len); gb_memmove(text, &path_buf[0], len);
@@ -136,7 +147,6 @@ String odin_root_dir(void) {
global_module_path = path; global_module_path = path;
global_module_path_set = true; global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
// array_free(&path_buf); // array_free(&path_buf);
@@ -159,6 +169,7 @@ String odin_root_dir(void) {
} }
array_init_count(&path_buf, heap_allocator(), 300); array_init_count(&path_buf, heap_allocator(), 300);
defer (array_free(&path_buf));
len = 0; len = 0;
for (;;) { for (;;) {
@@ -168,7 +179,7 @@ String odin_root_dir(void) {
// path without checking this link. Sorry. // path without checking this link. Sorry.
len = readlink("/proc/self/exe", &path_buf[0], path_buf.count); len = readlink("/proc/self/exe", &path_buf[0], path_buf.count);
if(len == 0) { if(len == 0) {
return make_string(NULL, 0); return make_string(nullptr, 0);
} }
if (len < path_buf.count) { if (len < path_buf.count) {
break; break;
@@ -176,9 +187,14 @@ String odin_root_dir(void) {
array_resize(&path_buf, 2*path_buf.count + 300); 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); 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); text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
gb_memmove(text, &path_buf[0], len); gb_memmove(text, &path_buf[0], len);
path = make_string(text, len); path = make_string(text, len);
@@ -193,10 +209,6 @@ String odin_root_dir(void) {
global_module_path = path; global_module_path = path;
global_module_path_set = true; global_module_path_set = true;
gb_temp_arena_memory_end(tmp);
array_free(&path_buf);
return path; return path;
} }
#endif #endif
@@ -204,14 +216,17 @@ String odin_root_dir(void) {
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
String path_to_fullpath(gbAllocator a, String s) { 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); gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
String16 string16 = string_to_string16(string_buffer_allocator, s); 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) { if (len != 0) {
wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1); 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; text[len] = 0;
result = string16_to_string(a, make_string16(text, len)); 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) #elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
String path_to_fullpath(gbAllocator a, String s) { String path_to_fullpath(gbAllocator a, String s) {
char *p = realpath(cast(char *)&s[0], 0); char *p;
if(p == NULL) return make_string_c(""); 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); return make_string_c(p);
} }
#else #else
@@ -266,12 +283,18 @@ String get_fullpath_core(gbAllocator a, String path) {
} }
String const ODIN_VERSION = str_lit("0.6.2");
void init_build_context(void) { void init_build_context(void) {
BuildContext *bc = &build_context; 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_VENDOR = str_lit("odin");
bc->ODIN_VERSION = str_lit("0.5.0"); bc->ODIN_VERSION = ODIN_VERSION;
bc->ODIN_ROOT = odin_root_dir(); bc->ODIN_ROOT = odin_root_dir();
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
+226 -120
View File
@@ -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; e->type = t_invalid;
} }
return NULL; return nullptr;
} }
if (e->type == NULL) {
if (e->type == nullptr) {
// NOTE(bill): Use the type of the operand // NOTE(bill): Use the type of the operand
Type *t = operand->type; Type *t = operand->type;
if (is_type_untyped(t)) { if (is_type_untyped(t)) {
if (t == t_invalid || is_type_untyped_nil(t)) { if (t == t_invalid || is_type_untyped_nil(t)) {
error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name)); error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name));
e->type = t_invalid; e->type = t_invalid;
return NULL; return nullptr;
} }
if (t == t_invalid || is_type_untyped_undef(t)) { if (t == t_invalid || is_type_untyped_undef(t)) {
error(e->token, "Invalid use of --- in %.*s", LIT(context_name)); error(e->token, "Invalid use of --- in %.*s", LIT(context_name));
e->type = t_invalid; e->type = t_invalid;
return NULL; return nullptr;
} }
t = default_type(t); t = default_type(t);
} }
if (is_type_gen_proc(t)) { if (is_type_polymorphic(t)) {
error(e->token, "Invalid use of a generic procedure in %.*s", LIT(context_name)); 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; 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)) { if (is_type_bit_field_value(t)) {
t = default_bit_field_value_type(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)); GB_ASSERT(is_type_typed(t));
e->type = 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); check_assignment(c, operand, e->type, context_name);
if (operand->mode == Addressing_Invalid) { if (operand->mode == Addressing_Invalid) {
return NULL; return nullptr;
} }
return e->type; return e->type;
} }
void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNode *> inits, String context_name) { void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNode *> inits, String context_name) {
if ((lhs == NULL || lhs_count == 0) && inits.count == 0) { if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) {
return; return;
} }
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); 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 // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation // 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) { if (rhs_count > 0 && lhs_count != rhs_count) {
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
} }
gb_temp_arena_memory_end(tmp);
} }
void check_init_constant(Checker *c, Entity *e, Operand *operand) { void check_init_constant(Checker *c, Entity *e, Operand *operand) {
if (operand->mode == Addressing_Invalid || if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid || operand->type == t_invalid ||
e->type == t_invalid) { e->type == t_invalid) {
if (e->type == NULL) { if (e->type == nullptr) {
e->type = t_invalid; e->type = t_invalid;
} }
return; return;
@@ -120,7 +135,7 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
gbString str = expr_to_string(operand->expr); gbString str = expr_to_string(operand->expr);
error(operand->expr, "`%s` is not a constant", str); error(operand->expr, "`%s` is not a constant", str);
gb_string_free(str); gb_string_free(str);
if (e->type == NULL) { if (e->type == nullptr) {
e->type = t_invalid; e->type = t_invalid;
} }
return; return;
@@ -129,13 +144,13 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
gbString type_str = type_to_string(operand->type); gbString type_str = type_to_string(operand->type);
error(operand->expr, "Invalid constant type: `%s`", type_str); error(operand->expr, "Invalid constant type: `%s`", type_str);
gb_string_free(type_str); gb_string_free(type_str);
if (e->type == NULL) { if (e->type == nullptr) {
e->type = t_invalid; e->type = t_invalid;
} }
return; return;
} }
if (e->type == NULL) { // NOTE(bill): type inference if (e->type == nullptr) { // NOTE(bill): type inference
e->type = operand->type; 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) { 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; 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; named->Named.type_name = e;
if (def != NULL && def->kind == Type_Named) { if (def != nullptr && def->kind == Type_Named) {
def->Named.base = named; def->Named.base = named;
} }
e->type = 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) { 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); GB_ASSERT(e->kind == Entity_Constant);
if (e->flags & EntityFlag_Visited) { if (e->flags & EntityFlag_Visited) {
@@ -191,25 +206,92 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
} }
Operand operand = {}; 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; if (init != nullptr) {
d->type_expr = d->init_expr; Entity *entity = nullptr;
check_type_decl(c, e, d->type_expr, named_type); if (init->kind == AstNode_Ident) {
return; 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); check_init_constant(c, e, &operand);
if (operand.mode == Addressing_Invalid || if (operand.mode == Addressing_Invalid ||
base_type(operand.type) == t_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)) { if (is_type_integer(x) && is_type_integer(y)) {
GB_ASSERT(x->kind == Type_Basic); GB_ASSERT(x->kind == Type_Basic);
GB_ASSERT(y->kind == Type_Basic); GB_ASSERT(y->kind == Type_Basic);
if (x->Basic.size == y->Basic.size) { i64 sx = type_size_of(heap_allocator(), x);
continue; i64 sy = type_size_of(heap_allocator(), y);
} if (sx == sy) continue;
} }
if (!are_types_identical(x, y)) { if (!are_types_identical(x, y)) return false;
return false;
}
} }
for (isize i = 0; i < a->result_count; i++) { for (isize i = 0; i < a->result_count; i++) {
Type *x = base_type(a->results->Tuple.variables[i]->type); 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)) { if (is_type_integer(x) && is_type_integer(y)) {
GB_ASSERT(x->kind == Type_Basic); GB_ASSERT(x->kind == Type_Basic);
GB_ASSERT(y->kind == Type_Basic); GB_ASSERT(y->kind == Type_Basic);
if (x->Basic.size == y->Basic.size) { i64 sx = type_size_of(heap_allocator(), x);
continue; i64 sy = type_size_of(heap_allocator(), y);
} if (sx == sy) continue;
} }
if (!are_types_identical(x, y)) { 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) { void init_entity_foreign_library(Checker *c, Entity *e) {
AstNode *ident = NULL; AstNode *ident = nullptr;
Entity **foreign_library = NULL; Entity **foreign_library = nullptr;
switch (e->kind) { switch (e->kind) {
case Entity_Procedure: case Entity_Procedure:
@@ -286,15 +366,15 @@ void init_entity_foreign_library(Checker *c, Entity *e) {
return; return;
} }
if (ident == NULL) { if (ident == nullptr) {
error(e->token, "foreign entiies must declare which library they are from"); error(e->token, "foreign entiies must declare which library they are from");
} else if (ident->kind != AstNode_Ident) { } else if (ident->kind != AstNode_Ident) {
error(ident, "foreign library names must be an identifier"); error(ident, "foreign library names must be an identifier");
} else { } else {
String name = ident->Ident.string; String name = ident->Ident.token.string;
Entity *found = scope_lookup_entity(c->context.scope, name); Entity *found = scope_lookup_entity(c->context.scope, name);
if (found == NULL) { if (found == nullptr) {
if (name == "_") { if (is_blank_ident(name)) {
error(ident, "`_` cannot be used as a value type"); error(ident, "`_` cannot be used as a value type");
} else { } else {
error(ident, "Undeclared name: %.*s", LIT(name)); 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) { void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
GB_ASSERT(e->type == NULL); GB_ASSERT(e->type == nullptr);
if (d->proc_decl->kind != AstNode_ProcDecl) { if (d->proc_lit->kind != AstNode_ProcLit) {
// TOOD(bill): Better error message // TOOD(bill): Better error message
error(d->proc_decl, "Expected a procedure to check"); error(d->proc_lit, "Expected a procedure to check");
return; return;
} }
Type *proc_type = e->type; Type *proc_type = e->type;
if (d->gen_proc_type != NULL) { if (d->gen_proc_type != nullptr) {
proc_type = d->gen_proc_type; proc_type = d->gen_proc_type;
} else { } 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; 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)); 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; 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 (d->scope->is_file && e->token.string == "main") {
if (pt->param_count != 0 || if (pt->param_count != 0 ||
pt->result_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); error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
gb_string_free(str); gb_string_free(str);
} }
if (proc_type->Proc.calling_convention != ProcCC_Odin && if (pt->calling_convention != ProcCC_Odin &&
proc_type->Proc.calling_convention != ProcCC_Contextless) { pt->calling_convention != ProcCC_Contextless) {
error(e->token, "Procedure `main` cannot have a custom calling convention"); 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) { 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) { 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_polymorphic) {
if (pt->is_generic) { if (pl->body == nullptr) {
if (pd->body == NULL) {
error(e->token, "Polymorphic procedures must have a body"); error(e->token, "Polymorphic procedures must have a body");
} }
if (is_foreign) { if (is_foreign) {
error(e->token, "A foreign procedures cannot be a polymorphic"); error(e->token, "A foreign procedure cannot be a polymorphic");
return; return;
} }
} }
if (pd->body != NULL) { if (pl->body != nullptr) {
if (is_foreign) { 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) { 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; d->scope = c->context.scope;
GB_ASSERT(pd->body->kind == AstNode_BlockStmt); GB_ASSERT(pl->body->kind == AstNode_BlockStmt);
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags); 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) { } else if (!is_foreign) {
error(e->token, "Only a foreign procedure cannot have a body"); error(e->token, "Only a foreign procedure cannot have a body");
} }
if (pt->result_count == 0 && is_require_results) { 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 { } else {
pt->require_results = is_require_results; pt->require_results = is_require_results;
} }
@@ -401,8 +489,8 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
if (is_foreign) { if (is_foreign) {
String name = e->token.string; String name = e->token.string;
if (pd->link_name.len > 0) { if (pl->link_name.len > 0) {
name = pd->link_name; name = pl->link_name;
} }
e->Procedure.is_foreign = true; e->Procedure.is_foreign = true;
e->Procedure.link_name = name; 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); Type *other_type = base_type(f->type);
if (is_type_proc(this_type) && is_type_proc(other_type)) { if (is_type_proc(this_type) && is_type_proc(other_type)) {
if (!are_signatures_similar_enough(this_type, other_type)) { if (!are_signatures_similar_enough(this_type, other_type)) {
error(d->proc_decl, error(d->proc_lit,
"Redeclaration of foreign procedure `%.*s` with different type signatures\n" "Redeclaration of foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)", "\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column); LIT(name), LIT(pos.file), pos.line, pos.column);
} }
} else if (!are_types_identical(this_type, other_type)) { } else if (!are_types_identical(this_type, other_type)) {
error(d->proc_decl, error(d->proc_lit,
"Foreign entity `%.*s` previously declared elsewhere with a different type\n" "Foreign entity `%.*s` previously declared elsewhere with a different type\n"
"\tat %.*s(%td:%td)", "\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column); LIT(name), LIT(pos.file), pos.line, pos.column);
} }
} else { } else {
map_set(fp, key, e); map_set(fp, key, e);
@@ -437,7 +525,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
} else { } else {
String name = e->token.string; String name = e->token.string;
if (is_link_name) { if (is_link_name) {
name = pd->link_name; name = pl->link_name;
} }
if (is_link_name || is_export) { if (is_link_name || is_export) {
@@ -451,10 +539,10 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
Entity *f = *found; Entity *f = *found;
TokenPos pos = f->token.pos; TokenPos pos = f->token.pos;
// TODO(bill): Better error message? // TODO(bill): Better error message?
error(d->proc_decl, error(d->proc_lit,
"Non unique linking name for procedure `%.*s`\n" "Non unique linking name for procedure `%.*s`\n"
"\tother at %.*s(%td:%td)", "\tother at %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column); LIT(name), LIT(pos.file), pos.line, pos.column);
} else { } else {
map_set(fp, key, e); 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) { 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); GB_ASSERT(e->kind == Entity_Variable);
if (e->flags & EntityFlag_Visited) { 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; 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); 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 (e->Variable.is_foreign) {
if (init_expr != NULL) { if (init_expr != nullptr) {
error(e->token, "A foreign variable declaration cannot have a default value"); error(e->token, "A foreign variable declaration cannot have a default value");
} }
init_entity_foreign_library(c, e); 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 (init_expr == nullptr) {
if (type_expr == NULL) { if (type_expr == nullptr) {
e->type = t_invalid; e->type = t_invalid;
} }
return; return;
} }
if (entities == NULL || entity_count == 1) { if (entities == nullptr || entity_count == 1) {
GB_ASSERT(entities == NULL || entities[0] == e); GB_ASSERT(entities == nullptr || entities[0] == e);
Operand operand = {}; Operand operand = {};
check_expr(c, &operand, init_expr); 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++) { for (isize i = 0; i < entity_count; i++) {
entities[i]->type = e->type; 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<AstNode *> inits;
array_init(&inits, c->allocator, 1); array_init(&inits, c->allocator, 1);
array_add(&inits, init_expr); 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) { void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
if (e->type != NULL) { if (e->type != nullptr) {
return; return;
} }
if (d == NULL) { if (d == nullptr) {
d = decl_info_of_entity(&c->info, e); d = decl_info_of_entity(&c->info, e);
if (d == NULL) { if (d == nullptr) {
// TODO(bill): Err here? // TODO(bill): Err here?
e->type = t_invalid; e->type = t_invalid;
set_base_type(named_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) { void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
if (body == NULL) { if (body == nullptr) {
return; return;
} }
GB_ASSERT(body->kind == AstNode_BlockStmt); 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; CheckerContext old_context = c->context;
defer (c->context = old_context);
c->context.scope = decl->scope; c->context.scope = decl->scope;
c->context.decl = decl; c->context.decl = decl;
c->context.proc_name = proc_name; 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); GB_ASSERT(type->kind == Type_Proc);
if (type->Proc.param_count > 0) { if (type->Proc.param_count > 0) {
TypeTuple *params = &type->Proc.params->Tuple; 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]; Entity *e = params->variables[i];
if (e->kind != Entity_Variable) { if (e->kind != Entity_Variable) {
continue; 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; bool is_immutable = e->Variable.is_immutable;
String name = e->token.string; String name = e->token.string;
Type *t = base_type(type_deref(e->type)); Type *t = base_type(type_deref(e->type));
if (is_type_struct(t) || is_type_raw_union(t)) { if (t->kind == Type_Struct) {
Scope *scope = scope_of_node(&c->info, t->Record.node); Scope *scope = t->Struct.scope;
GB_ASSERT(scope != NULL); if (scope == nullptr) {
scope = scope_of_node(&c->info, t->Struct.node);
}
GB_ASSERT(scope != nullptr);
for_array(i, scope->elements.entries) { for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[i].value; Entity *f = scope->elements.entries[i].value;
if (f->kind == Entity_Variable) { if (f->kind == Entity_Variable) {
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type); Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
uvar->Variable.is_immutable = is_immutable; uvar->Variable.is_immutable = is_immutable;
Entity *prev = scope_insert_entity(c->context.scope, uvar); Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != NULL) { if (prev != nullptr) {
error(e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string)); error(e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
break; break;
} }
} }
} }
} else { } 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; break;
} }
} }
@@ -644,11 +752,9 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
} }
pop_procedure(c); pop_procedure(c);
check_scope_usage(c, c->context.scope); 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) // NOTE(bill): Add the dependencies from the procedure literal (lambda)
for_array(i, decl->deps.entries) { for_array(i, decl->deps.entries) {
HashKey key = decl->deps.entries[i].key; HashKey key = decl->deps.entries[i].key;
+2626 -1144
View File
File diff suppressed because it is too large Load Diff
+270 -262
View File
@@ -4,7 +4,7 @@ void check_stmt_list(Checker *c, Array<AstNode *> stmts, u32 flags) {
} }
if (flags&Stmt_CheckScopeDecls) { 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; bool ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
@@ -75,7 +75,7 @@ bool check_has_break(AstNode *stmt, bool implicit) {
case AstNode_IfStmt: case AstNode_IfStmt:
if (check_has_break(stmt->IfStmt.body, implicit) || 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; return true;
} }
break; break;
@@ -107,7 +107,7 @@ bool check_is_terminating(AstNode *node) {
case_end; case_end;
case_ast_node(is, IfStmt, node); case_ast_node(is, IfStmt, node);
if (is->else_stmt != NULL) { if (is->else_stmt != nullptr) {
if (check_is_terminating(is->body) && if (check_is_terminating(is->body) &&
check_is_terminating(is->else_stmt)) { check_is_terminating(is->else_stmt)) {
return true; return true;
@@ -116,7 +116,7 @@ bool check_is_terminating(AstNode *node) {
case_end; case_end;
case_ast_node(ws, WhenStmt, node); case_ast_node(ws, WhenStmt, node);
if (ws->else_stmt != NULL) { if (ws->else_stmt != nullptr) {
if (check_is_terminating(ws->body) && if (check_is_terminating(ws->body) &&
check_is_terminating(ws->else_stmt)) { check_is_terminating(ws->else_stmt)) {
return true; return true;
@@ -125,7 +125,7 @@ bool check_is_terminating(AstNode *node) {
case_end; case_end;
case_ast_node(fs, ForStmt, node); 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); return check_is_terminating(fs->body);
} }
case_end; case_end;
@@ -180,23 +180,22 @@ bool check_is_terminating(AstNode *node) {
Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
if (rhs->mode == Addressing_Invalid || if (rhs->mode == Addressing_Invalid ||
(rhs->type == t_invalid && rhs->mode != Addressing_Overload)) { (rhs->type == t_invalid && rhs->mode != Addressing_Overload)) {
return NULL; return nullptr;
} }
AstNode *node = unparen_expr(lhs_node); AstNode *node = unparen_expr(lhs_node);
// NOTE(bill): Ignore assignments to `_` // NOTE(bill): Ignore assignments to `_`
if (node->kind == AstNode_Ident && if (is_blank_ident(node)) {
node->Ident.string == "_") { add_entity_definition(&c->info, node, nullptr);
add_entity_definition(&c->info, node, NULL); check_assignment(c, rhs, nullptr, str_lit("assignment to `_` identifier"));
check_assignment(c, rhs, NULL, str_lit("assignment to `_` identifier"));
if (rhs->mode == Addressing_Invalid) { if (rhs->mode == Addressing_Invalid) {
return NULL; return nullptr;
} }
return rhs->type; return rhs->type;
} }
Entity *e = NULL; Entity *e = nullptr;
bool used = false; bool used = false;
Operand lhs = {Addressing_Invalid}; 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); check_expr(c, &lhs, lhs_node);
if (lhs.mode == Addressing_Invalid || if (lhs.mode == Addressing_Invalid ||
lhs.type == t_invalid) { lhs.type == t_invalid) {
return NULL; return nullptr;
} }
if (rhs->mode == Addressing_Overload) { if (rhs->mode == Addressing_Overload) {
isize overload_count = rhs->overload_count; isize overload_count = rhs->overload_count;
Entity **procs = rhs->overload_entities; 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 // NOTE(bill): These should be done
for (isize i = 0; i < overload_count; i++) { 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 // HACK TODO(bill): Should the entities be freed as it's technically a leak
rhs->mode = Addressing_Value; rhs->mode = Addressing_Value;
rhs->type = e->type; rhs->type = e->type;
rhs->overload_count = 0; rhs->overload_count = 0;
rhs->overload_entities = NULL; rhs->overload_entities = nullptr;
} }
} else { } else {
if (node->kind == AstNode_Ident) { if (node->kind == AstNode_Ident) {
ast_node(i, Ident, node); ast_node(i, Ident, node);
e = scope_lookup_entity(c->context.scope, i->string); e = scope_lookup_entity(c->context.scope, i->token.string);
if (e != NULL && e->kind == Entity_Variable) { if (e != nullptr && e->kind == Entity_Variable) {
used = (e->flags & EntityFlag_Used) != 0; // TODO(bill): Make backup just in case 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; e->flags |= EntityFlag_Used;
} }
Type *assignment_type = lhs.type; Type *assignment_type = lhs.type;
switch (lhs.mode) { switch (lhs.mode) {
case Addressing_Invalid: case Addressing_Invalid:
return NULL; return nullptr;
case Addressing_Variable: { case Addressing_Variable: {
if (is_type_bit_field_value(lhs.type)) { 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 u = *cast(u128 *)&i;
u128 umax = U128_NEG_ONE; u128 umax = U128_NEG_ONE;
if (lhs_bits < 128) { 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; bool ok = false;
ok = !(u128_lt(u, U128_ZERO) || u128_gt(u, umax)); 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); error(rhs->expr, "Cannot assign `%s` to bit field `%s`", rhs_expr, lhs_expr);
gb_string_free(rhs_expr); gb_string_free(rhs_expr);
gb_string_free(lhs_expr); gb_string_free(lhs_expr);
return NULL; return nullptr;
} }
break; break;
} }
@@ -302,7 +301,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
gbString str = expr_to_string(lhs.expr); gbString str = expr_to_string(lhs.expr);
error(lhs.expr, "Cannot assign to the value of a map `%s`", str); error(lhs.expr, "Cannot assign to the value of a map `%s`", str);
gb_string_free(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); check_expr(c, &op_c, se->expr);
if (op_c.mode == Addressing_MapIndex) { if (op_c.mode == Addressing_MapIndex) {
gbString str = expr_to_string(lhs.expr); 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); 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")); check_assignment(c, rhs, assignment_type, str_lit("assignment"));
if (rhs->mode == Addressing_Invalid) { if (rhs->mode == Addressing_Invalid) {
return NULL; return nullptr;
} }
return rhs->type; 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"); error(ws->cond, "Non-constant boolean `when` condition");
return; 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"); error(ws->cond, "Invalid body for `when` statement");
return; return;
} }
@@ -420,7 +419,7 @@ void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
} }
void check_label(Checker *c, AstNode *label) { void check_label(Checker *c, AstNode *label) {
if (label == NULL) { if (label == nullptr) {
return; return;
} }
ast_node(l, Label, label); 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"); error(l->name, "A label's name must be an identifier");
return; return;
} }
String name = l->name->Ident.string; String name = l->name->Ident.token.string;
if (name == "_") { if (is_blank_ident(name)) {
error(l->name, "A label's name cannot be a blank identifier"); error(l->name, "A label's name cannot be a blank identifier");
return; return;
} }
@@ -439,7 +438,7 @@ void check_label(Checker *c, AstNode *label) {
error(l->name, "A label is only allowed within a procedure"); error(l->name, "A label is only allowed within a procedure");
return; return;
} }
GB_ASSERT(c->context.decl != NULL); GB_ASSERT(c->context.decl != nullptr);
bool ok = true; bool ok = true;
for_array(i, c->context.decl->labels) { 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); add_entity(c, c->context.scope, l->name, e);
e->parent_proc_decl = c->context.curr_proc_decl; 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` // Returns `true` for `continue`, `false` for `return`
bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bool is_selector, Entity *e) { 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"); error(us->token, "`using` applied to an unknown entity");
return true; return true;
} }
@@ -473,13 +472,28 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
switch (e->kind) { switch (e->kind) {
case Entity_TypeName: { case Entity_TypeName: {
Type *t = base_type(e->type); Type *t = base_type(e->type);
if (is_type_union(t)) { if (t->kind == Type_Struct) {
TokenPos pos = ast_node_token(expr).pos; Scope *s = t->Struct.scope;
for (isize i = 1; i < t->Record.variant_count; i++) { if (s != nullptr) {
Entity *f = t->Record.variants[i]; for_array(i, s->elements.entries) {
// gb_printf_err("%s\n", type_to_string(f->type)); 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); Entity *found = scope_insert_entity(c->context.scope, f);
if (found != NULL) { if (found != nullptr) {
gbString expr_str = expr_to_string(expr); gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
gb_string_free(expr_str); 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; 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 { } 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; } break;
@@ -510,7 +511,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
for_array(i, scope->elements.entries) { for_array(i, scope->elements.entries) {
Entity *decl = scope->elements.entries[i].value; Entity *decl = scope->elements.entries[i].value;
Entity *found = scope_insert_entity(c->context.scope, decl); Entity *found = scope_insert_entity(c->context.scope, decl);
if (found != NULL) { if (found != nullptr) {
gbString expr_str = expr_to_string(expr); gbString expr_str = expr_to_string(expr);
error(us->token, error(us->token,
"Namespace collision while `using` `%s` of: %.*s\n" "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)); Type *t = base_type(type_deref(e->type));
if (is_type_struct(t) || is_type_raw_union(t) || is_type_union(t)) { if (is_type_struct(t) || is_type_raw_union(t) || is_type_union(t)) {
// TODO(bill): Make it work for unions too // 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) { for_array(i, found->elements.entries) {
Entity *f = found->elements.entries[i].value; Entity *f = found->elements.entries[i].value;
if (f->kind == Entity_Variable) { 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; uvar->using_expr = expr;
// } // }
Entity *prev = scope_insert_entity(c->context.scope, uvar); Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != NULL) { if (prev != nullptr) {
gbString expr_str = expr_to_string(expr); gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string)); error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string));
gb_string_free(expr_str); 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) case_ast_node(es, ExprStmt, node)
Operand operand = {Addressing_Invalid}; 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) { switch (operand.mode) {
case Addressing_Type: { case Addressing_Type: {
gbString str = type_to_string(operand.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); check_stmt(c, ts->stmt, flags);
case_end; case_end;
#if 0
case_ast_node(s, IncDecStmt, node); case_ast_node(s, IncDecStmt, node);
TokenKind op = s->op.kind; TokenKind op = s->op.kind;
switch (op) { switch (op) {
@@ -670,6 +672,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} }
check_assignment_variable(c, &x, left); check_assignment_variable(c, &x, left);
case_end; case_end;
#endif
case_ast_node(as, AssignStmt, node); case_ast_node(as, AssignStmt, node);
switch (as->op.kind) { 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); 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 // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation // 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); error(as->lhs[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
} }
gb_temp_arena_memory_end(tmp);
} break; } break;
default: { default: {
@@ -747,7 +750,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_ast_node(is, IfStmt, node); case_ast_node(is, IfStmt, node);
check_open_scope(c, node); check_open_scope(c, node);
if (is->init != NULL) { if (is->init != nullptr) {
check_stmt(c, is->init, 0); 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); check_stmt(c, is->body, mod_flags);
if (is->else_stmt != NULL) { if (is->else_stmt != nullptr) {
switch (is->else_stmt->kind) { switch (is->else_stmt->kind) {
case AstNode_IfStmt: case AstNode_IfStmt:
case AstNode_BlockStmt: case AstNode_BlockStmt:
@@ -814,7 +817,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
TypeProc *pt = &proc_type->Proc; TypeProc *pt = &proc_type->Proc;
isize result_count = 0; isize result_count = 0;
if (pt->results) { 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); gb_string_free(expr_str);
continue; continue;
} }
String name = fv->field->Ident.string; String name = fv->field->Ident.token.string;
isize index = lookup_procedure_result(pt, name); isize index = lookup_procedure_result(pt, name);
if (index < 0) { if (index < 0) {
error(arg, "No result named `%.*s` for this procedure type", LIT(name)); 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++) { for (isize i = 0; i < result_count; i++) {
if (!visited[i]) { if (!visited[i]) {
Entity *e = pt->results->Tuple.variables[i]; Entity *e = pt->results->Tuple.variables[i];
if (e->token.string == "_") { if (is_blank_ident(e->token)) {
continue; continue;
} }
GB_ASSERT(e->kind == Entity_Variable); 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_open_scope(c, node);
check_label(c, fs->label); // TODO(bill): What should the label's "scope" be? 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); check_stmt(c, fs->init, 0);
} }
if (fs->cond != NULL) { if (fs->cond != nullptr) {
Operand o = {Addressing_Invalid}; Operand o = {Addressing_Invalid};
check_expr(c, &o, fs->cond); check_expr(c, &o, fs->cond);
if (o.mode != Addressing_Invalid && !is_type_boolean(o.type)) { if (o.mode != Addressing_Invalid && !is_type_boolean(o.type)) {
error(fs->cond, "Non-boolean condition in `for` statement"); error(fs->cond, "Non-boolean condition in `for` statement");
} }
} }
if (fs->post != NULL) { if (fs->post != nullptr) {
check_stmt(c, fs->post, 0); check_stmt(c, fs->post, 0);
if (fs->post->kind != AstNode_AssignStmt && 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_open_scope(c, node);
check_label(c, rs->label); check_label(c, rs->label);
Type *val = NULL; Type *val = nullptr;
Type *idx = NULL; Type *idx = nullptr;
Entity *entities[2] = {}; Entity *entities[2] = {};
isize entity_count = 0; 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 s = expr_to_string(operand.expr);
gbString t = type_to_string(operand.type); gbString t = type_to_string(operand.type);
error(operand.expr, "Cannot iterate over `%s` of type `%s`", s, t); 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}; Type * rhs[2] = {val, idx};
for (isize i = 0; i < 2; i++) { for (isize i = 0; i < 2; i++) {
if (lhs[i] == NULL) { if (lhs[i] == nullptr) {
continue; continue;
} }
AstNode *name = lhs[i]; AstNode *name = lhs[i];
Type * type = rhs[i]; Type * type = rhs[i];
Entity *entity = NULL; Entity *entity = nullptr;
if (name->kind == AstNode_Ident) { if (name->kind == AstNode_Ident) {
Token token = name->Ident; Token token = name->Ident.token;
String str = token.string; 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); 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); entity = make_entity_variable(c->allocator, c->context.scope, token, type, true);
add_entity_definition(&c->info, name, entity); add_entity_definition(&c->info, name, entity);
} else { } else {
@@ -1149,13 +1152,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
error(name, "A variable declaration must be an identifier"); 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)); entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
} }
entities[entity_count++] = entity; entities[entity_count++] = entity;
if (type == NULL) { if (type == nullptr) {
entity->type = t_invalid; entity->type = t_invalid;
entity->flags |= EntityFlag_Used; entity->flags |= EntityFlag_Used;
} }
@@ -1177,12 +1180,12 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
check_open_scope(c, node); check_open_scope(c, node);
check_label(c, ms->label); // TODO(bill): What should the label's "scope" be? 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); check_stmt(c, ms->init, 0);
} }
if (ms->tag != NULL) { if (ms->tag != nullptr) {
check_expr(c, &x, ms->tag); 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 { } else {
x.mode = Addressing_Constant; x.mode = Addressing_Constant;
x.type = t_bool; x.type = t_bool;
@@ -1202,11 +1205,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
// NOTE(bill): Check for multiple defaults // NOTE(bill): Check for multiple defaults
AstNode *first_default = NULL; AstNode *first_default = nullptr;
ast_node(bs, BlockStmt, ms->body); ast_node(bs, BlockStmt, ms->body);
for_array(i, bs->stmts) { for_array(i, bs->stmts) {
AstNode *stmt = bs->stmts[i]; AstNode *stmt = bs->stmts[i];
AstNode *default_stmt = NULL; AstNode *default_stmt = nullptr;
if (stmt->kind == AstNode_CaseClause) { if (stmt->kind == AstNode_CaseClause) {
ast_node(cc, CaseClause, stmt); ast_node(cc, CaseClause, stmt);
if (cc->list.count == 0) { 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"); error(stmt, "Invalid AST - expected case clause");
} }
if (default_stmt != NULL) { if (default_stmt != nullptr) {
if (first_default != NULL) { if (first_default != nullptr) {
TokenPos pos = ast_node_token(first_default).pos; TokenPos pos = ast_node_token(first_default).pos;
error(stmt, error(stmt,
"multiple `default` clauses\n" "multiple `default` clauses\n"
@@ -1298,6 +1301,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} else { } else {
Operand y = {}; Operand y = {};
check_expr(c, &y, expr); check_expr(c, &y, expr);
if (x.mode == Addressing_Invalid || if (x.mode == Addressing_Invalid ||
y.mode == Addressing_Invalid) { y.mode == Addressing_Invalid) {
continue; continue;
@@ -1322,8 +1326,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (y.value.kind != ExactValue_Invalid) { if (y.value.kind != ExactValue_Invalid) {
HashKey key = hash_exact_value(y.value); HashKey key = hash_exact_value(y.value);
TypeAndToken *found = map_get(&seen, key); TypeAndToken *found = map_get(&seen, key);
if (found != NULL) { if (found != nullptr) {
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
defer (gb_temp_arena_memory_end(tmp));
isize count = multi_map_count(&seen, key); isize count = multi_map_count(&seen, key);
TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count); 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) { if (continue_outer) {
continue; continue;
@@ -1400,7 +1405,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
AstNode *rhs = as->rhs[0]; AstNode *rhs = as->rhs[0];
check_expr(c, &x, rhs); 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); match_type_kind = check_valid_type_match_type(x.type);
if (check_valid_type_match_type(x.type) == MatchType_Invalid) { if (check_valid_type_match_type(x.type) == MatchType_Invalid) {
gbString str = type_to_string(x.type); 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); bool is_ptr = is_type_pointer(x.type);
// NOTE(bill): Check for multiple defaults // NOTE(bill): Check for multiple defaults
AstNode *first_default = NULL; AstNode *first_default = nullptr;
ast_node(bs, BlockStmt, ms->body); ast_node(bs, BlockStmt, ms->body);
for_array(i, bs->stmts) { for_array(i, bs->stmts) {
AstNode *stmt = bs->stmts[i]; AstNode *stmt = bs->stmts[i];
AstNode *default_stmt = NULL; AstNode *default_stmt = nullptr;
if (stmt->kind == AstNode_CaseClause) { if (stmt->kind == AstNode_CaseClause) {
ast_node(cc, CaseClause, stmt); ast_node(cc, CaseClause, stmt);
if (cc->list.count == 0) { 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"); error(stmt, "Invalid AST - expected case clause");
} }
if (default_stmt != NULL) { if (default_stmt != nullptr) {
if (first_default != NULL) { if (first_default != nullptr) {
TokenPos pos = ast_node_token(first_default).pos; TokenPos pos = ast_node_token(first_default).pos;
error(stmt, error(stmt,
"Multiple `default` clauses\n" "Multiple `default` clauses\n"
@@ -1459,19 +1464,19 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
// TODO(bill): Make robust // TODO(bill): Make robust
Type *bt = base_type(type_deref(x.type)); Type *bt = base_type(type_deref(x.type));
Type *case_type = NULL; Type *case_type = nullptr;
for_array(type_index, cc->list) { for_array(type_index, cc->list) {
AstNode *type_expr = cc->list[type_index]; 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 = {}; Operand y = {};
check_expr_or_type(c, &y, type_expr); check_expr_or_type(c, &y, type_expr);
if (match_type_kind == MatchType_Union) { if (match_type_kind == MatchType_Union) {
GB_ASSERT(is_type_union(bt)); GB_ASSERT(is_type_union(bt));
bool tag_type_found = false; bool tag_type_found = false;
for (isize i = 0; i < bt->Record.variant_count; i++) { for_array(i, bt->Union.variants) {
Entity *f = bt->Record.variants[i]; Type *vt = bt->Union.variants[i];
if (are_types_identical(f->type, y.type)) { if (are_types_identical(vt, y.type)) {
tag_type_found = true; tag_type_found = true;
break; break;
} }
@@ -1509,21 +1514,21 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (is_ptr && if (is_ptr &&
!is_type_any(type_deref(x.type)) && !is_type_any(type_deref(x.type)) &&
cc->list.count == 1 && cc->list.count == 1 &&
case_type != NULL) { case_type != nullptr) {
case_type = make_type_pointer(c->allocator, case_type); case_type = make_type_pointer(c->allocator, case_type);
} }
if (cc->list.count > 1) { if (cc->list.count > 1) {
case_type = NULL; case_type = nullptr;
} }
if (case_type == NULL) { if (case_type == nullptr) {
case_type = x.type; case_type = x.type;
} }
add_type_info_type(c, case_type); add_type_info_type(c, case_type);
check_open_scope(c, stmt); 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_Used;
tag_var->flags |= EntityFlag_Value; tag_var->flags |= EntityFlag_Value;
add_entity(c, c->context.scope, lhs, tag_var); add_entity(c, c->context.scope, lhs, tag_var);
@@ -1573,16 +1578,16 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
break; break;
} }
if (bs->label != NULL) { if (bs->label != nullptr) {
if (bs->label->kind != AstNode_Ident) { if (bs->label->kind != AstNode_Ident) {
error(bs->label, "A branch statement's label name must be an identifier"); error(bs->label, "A branch statement's label name must be an identifier");
return; return;
} }
AstNode *ident = bs->label; AstNode *ident = bs->label;
String name = ident->Ident.string; String name = ident->Ident.token.string;
Operand o = {}; Operand o = {};
Entity *e = check_ident(c, &o, ident, NULL, NULL, false); Entity *e = check_ident(c, &o, ident, nullptr, nullptr, false);
if (e == NULL) { if (e == nullptr) {
error(ident, "Undeclared label name: %.*s", LIT(name)); error(ident, "Undeclared label name: %.*s", LIT(name));
return; return;
} }
@@ -1602,19 +1607,24 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} }
for_array(i, us->list) { for_array(i, us->list) {
AstNode *expr = unparen_expr(us->list[0]); AstNode *expr = unparen_expr(us->list[0]);
Entity *e = NULL; Entity *e = nullptr;
bool is_selector = false; bool is_selector = false;
if (expr->kind == AstNode_Ident) { Operand o = {};
Operand o = {}; switch (expr->kind) {
e = check_ident(c, &o, expr, NULL, NULL, true); case AstNode_Ident:
} else if (expr->kind == AstNode_SelectorExpr) { e = check_ident(c, &o, expr, nullptr, nullptr, true);
Operand o = {}; break;
e = check_selector(c, &o, expr, NULL); case AstNode_SelectorExpr:
e = check_selector(c, &o, expr, nullptr);
is_selector = true; is_selector = true;
} else if (expr->kind == AstNode_Implicit) { break;
case AstNode_Implicit:
error(us->token, "`using` applied to an implicit value"); error(us->token, "`using` applied to an implicit value");
continue; 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)) { 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) { for_array(i, fb->decls) {
AstNode *decl = fb->decls[i]; AstNode *decl = fb->decls[i];
if (decl->kind == AstNode_GenDecl) { if (decl->kind == AstNode_ValueDecl && decl->ValueDecl.is_mutable) {
switch (decl->GenDecl.token.kind) { check_stmt(c, decl, flags);
case Token_var:
check_stmt(c, decl, flags);
break;
}
} }
} }
c->context = prev_context; c->context = prev_context;
case_end; 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); if (vd->flags & VarDeclFlag_thread_local) {
GB_ASSERT(!c->context.scope->is_file); vd->flags &= ~VarDeclFlag_thread_local;
for_array(i, gd->specs) { error(node, "`thread_local` may only be applied to a variable declaration");
AstNode *spec = gd->specs[i]; }
switch (gd->token.kind) {
case Token_var: {
ast_node(vd, ValueSpec, spec);
Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count); for_array(i, vd->names) {
isize entity_count = 0; AstNode *name = vd->names[i];
Entity *entity = nullptr;
if (gd->flags & VarDeclFlag_thread_local) { if (name->kind != AstNode_Ident) {
gd->flags &= ~VarDeclFlag_thread_local; error(name, "A variable declaration must be an identifier");
error(node, "`thread_local` may only be applied to a variable declaration"); } 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 *fl = c->context.curr_foreign_library;
AstNode *name = vd->names[i]; if (fl != nullptr) {
Entity *entity = NULL; GB_ASSERT(fl->kind == AstNode_Ident);
if (name->kind != AstNode_Ident) { entity->Variable.is_foreign = true;
error(name, "A variable declaration must be an identifier"); entity->Variable.foreign_library_ident = fl;
} else { }
Token token = name->Ident; } else {
String str = token.string; TokenPos pos = found->token.pos;
Entity *found = NULL; error(token,
// NOTE(bill): Ignore assignments to `_` "Redeclaration of `%.*s` in this scope\n"
if (str != "_") { "\tat %.*s(%td:%td)",
found = current_scope_lookup_entity(c->context.scope, str); LIT(str), LIT(pos.file), pos.line, pos.column);
} entity = found;
if (found == NULL) { }
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL, false); }
entity->identifier = name; 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; Type *init_type = nullptr;
if (fl != NULL) { if (vd->type != nullptr) {
GB_ASSERT(fl->kind == AstNode_Ident); init_type = check_type(c, vd->type, nullptr);
entity->Variable.is_foreign = true; if (init_type == nullptr) {
entity->Variable.foreign_library_ident = fl; 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) { } else {
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name)); // NOTE(bill): skip the rest to remove extra errors
} error(token, "`using` can only be applied to variables of type struct or raw_union");
entity->parent_proc_decl = c->context.curr_proc_decl; return;
entities[entity_count++] = entity;
} }
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; case_end;
+454 -385
View File
File diff suppressed because it is too large Load Diff
+216 -64
View File
@@ -12,9 +12,78 @@
#include <math.h> #include <math.h>
GB_ALLOCATOR_PROC(heap_allocator_proc);
gbAllocator heap_allocator(void) { 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" #include "unicode.cpp"
@@ -23,6 +92,9 @@ gbAllocator heap_allocator(void) {
#include "integer128.cpp" #include "integer128.cpp"
#include "murmurhash3.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 fnv128a(void const *data, isize len) {
u128 o = u128_lo_hi(0x13bull, 0x1000000ull); u128 o = u128_lo_hi(0x13bull, 0x1000000ull);
u128 h = u128_lo_hi(0x62b821756295c58dull, 0x6c62272e07bb0142ull); u128 h = u128_lo_hi(0x62b821756295c58dull, 0x6c62272e07bb0142ull);
@@ -52,93 +124,163 @@ gbAllocator scratch_allocator(void) {
return gb_scratch_allocator(&scratch_memory); return gb_scratch_allocator(&scratch_memory);
} }
struct Pool {
isize memblock_size;
isize out_of_band_size;
isize alignment;
struct DynamicArenaBlock { Array<u8 *> unused_memblock;
DynamicArenaBlock *prev; Array<u8 *> used_memblock;
DynamicArenaBlock *next; Array<u8 *> out_of_band_allocations;
u8 * start;
isize count;
isize capacity;
gbVirtualMemory vm; u8 * current_memblock;
u8 * current_pos;
isize bytes_left;
gbAllocator block_allocator;
}; };
struct DynamicArena { enum {
DynamicArenaBlock *start_block; POOL_BUCKET_SIZE_DEFAULT = 65536,
DynamicArenaBlock *current_block; POOL_OUT_OF_BAND_SIZE_DEFAULT = 6554,
isize block_size;
}; };
DynamicArenaBlock *add_dynamic_arena_block(DynamicArena *a) { void pool_init(Pool *pool,
GB_ASSERT(a != NULL); isize memblock_size = POOL_BUCKET_SIZE_DEFAULT,
GB_ASSERT(a->block_size > 0); 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); array_init(&pool->unused_memblock, array_allocator);
DynamicArenaBlock *block = cast(DynamicArenaBlock *)vm.data; 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); void pool_free_all(Pool *p) {
u8 *end = cast(u8 *)vm.data + vm.size; if (p->current_memblock != nullptr) {
array_add(&p->unused_memblock, p->current_memblock);
block->vm = vm; p->current_memblock = nullptr;
block->start = start;
block->count = 0;
block->capacity = end-start;
if (a->current_block != NULL) {
a->current_block->next = block;
block->prev = a->current_block;
} }
a->current_block = block;
return block; 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) { void pool_destroy(Pool *p) {
isize size = gb_size_of(DynamicArenaBlock) + block_size; pool_free_all(p);
size = cast(isize)gb_align_forward(cast(void *)cast(uintptr)size, GB_DEFAULT_MEMORY_ALIGNMENT);
a->block_size = size;
a->start_block = add_dynamic_arena_block(a);
}
void destroy_dynamic_arena(DynamicArena *a) { for_array(i, p->unused_memblock) {
DynamicArenaBlock *b = a->current_block; gb_free(p->block_allocator, p->unused_memblock[i]);
while (b != NULL) {
gbVirtualMemory vm = b->vm;
b = b->prev;
gb_vm_free(b->vm);
} }
} }
GB_ALLOCATOR_PROC(dynamic_arena_allocator_proc) { void pool_cycle_new_block(Pool *p) {
DynamicArena *a = cast(DynamicArena *)allocator_data; GB_ASSERT_MSG(p->block_allocator.proc != nullptr,
void *ptr = NULL; "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) { switch (type) {
case gbAllocation_Alloc: { case gbAllocation_Alloc:
return pool_get(p, size, alignment);
} break; case gbAllocation_Free:
// Does nothing
case gbAllocation_Free: {
} break;
case gbAllocation_Resize: {
} break;
case gbAllocation_FreeAll:
GB_PANIC("free_all is not supported by this allocator");
break; 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; return ptr;
} }
gbAllocator dynamic_arena_allocator(DynamicArena *a) { gbAllocator pool_allocator(Pool *pool) {
gbAllocator allocator = {dynamic_arena_allocator_proc, a}; gbAllocator allocator;
allocator.proc = pool_allocator_procedure;
allocator.data = pool;
return allocator; 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) { i64 next_pow2(i64 n) {
if (n <= 0) { if (n <= 0) {
return 0; return 0;
@@ -154,6 +296,17 @@ i64 next_pow2(i64 n) {
return 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) { i64 prev_pow2(i64 n) {
if (n <= 0) { if (n <= 0) {
return 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 // Doubly Linked Lists
@@ -236,7 +388,7 @@ f64 gb_sqrt(f64 x) {
} while (0) } while (0)
#define DLIST_APPEND(root_element, curr_element, next_element) do { \ #define DLIST_APPEND(root_element, curr_element, next_element) do { \
if ((root_element) == NULL) { \ if ((root_element) == nullptr) { \
(root_element) = (curr_element) = (next_element); \ (root_element) = (curr_element) = (next_element); \
} else { \ } else { \
DLIST_SET(curr_element, next_element); \ 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) { wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
u32 i, j; 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 *); i = ((len+2)/2)*gb_size_of(void *) + gb_size_of(void *);
wchar_t **argv = cast(wchar_t **)GlobalAlloc(GMEM_FIXED, i + (len+2)*gb_size_of(wchar_t)); wchar_t **argv = cast(wchar_t **)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++; i++;
} }
_argv[j] = '\0'; _argv[j] = '\0';
argv[argc] = NULL; argv[argc] = nullptr;
if (_argc) *_argc = argc; if (_argc) *_argc = argc;
return argv; return argv;
+7 -13
View File
@@ -10,7 +10,7 @@ String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
len += 1; // for \n len += 1; // for \n
} }
if (len == 0) { if (len == 0) {
return make_string(NULL, 0); return make_string(nullptr, 0);
} }
u8 *text = gb_alloc_array(a, u8, len+1); 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); return make_string(text, len);
} }
#if 0
void print_type_spec(AstNode *spec) { void print_type_spec(AstNode *spec) {
ast_node(ts, TypeSpec, spec); ast_node(ts, TypeSpec, spec);
GB_ASSERT(ts->name->kind == AstNode_Ident); 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); gbString params = expr_to_string(proc_type->params);
defer (gb_string_free(params)); defer (gb_string_free(params));
gb_printf("proc %.*s(%s)", LIT(name), 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); ast_node(fl, FieldList, proc_type->results);
isize count = fl->list.count; isize count = fl->list.count;
if (count > 0) { if (count > 0) {
@@ -87,20 +88,13 @@ void print_proc_decl(AstNodeProcDecl *pd) {
} }
gb_printf("\n\n"); gb_printf("\n\n");
} }
#endif
void print_declaration(AstNode *decl) { void print_declaration(AstNode *decl) {
switch (decl->kind) { switch (decl->kind) {
case_ast_node(gd, GenDecl, decl); case_ast_node(gd, GenDecl, decl);
for_array(spec_index, gd->specs) { for_array(spec_index, gd->specs) {
AstNode *spec = gd->specs[spec_index]; AstNode *spec = gd->specs[spec_index];
switch(gd->token.kind) { 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:
case Token_import_load: case Token_import_load:
break; break;
@@ -111,9 +105,9 @@ void print_declaration(AstNode *decl) {
} }
case_end; case_end;
case_ast_node(pd, ProcDecl, decl); // case_ast_node(pd, ProcDecl, decl);
print_proc_decl(pd); // print_proc_decl(pd);
case_end; // case_end;
case_ast_node(fb, ForeignBlockDecl, decl); case_ast_node(fb, ForeignBlockDecl, decl);
// TODO(bill) // TODO(bill)
+20 -7
View File
@@ -12,6 +12,7 @@ struct DeclInfo;
ENTITY_KIND(TypeName) \ ENTITY_KIND(TypeName) \
ENTITY_KIND(Procedure) \ ENTITY_KIND(Procedure) \
ENTITY_KIND(Builtin) \ ENTITY_KIND(Builtin) \
ENTITY_KIND(Alias) \
ENTITY_KIND(ImportName) \ ENTITY_KIND(ImportName) \
ENTITY_KIND(LibraryName) \ ENTITY_KIND(LibraryName) \
ENTITY_KIND(Nil) \ ENTITY_KIND(Nil) \
@@ -70,8 +71,8 @@ struct Entity {
Token token; Token token;
Scope * scope; Scope * scope;
Type * type; Type * type;
AstNode * identifier; // Can be NULL AstNode * identifier; // Can be nullptr
DeclInfo * parent_proc_decl; // NULL if in file/global scope DeclInfo * parent_proc_decl; // nullptr if in file/global scope
// TODO(bill): Cleanup how `using` works for entities // TODO(bill): Cleanup how `using` works for entities
Entity * using_parent; Entity * using_parent;
@@ -86,15 +87,18 @@ struct Entity {
i32 field_src_index; i32 field_src_index;
ExactValue default_value; ExactValue default_value;
bool default_is_nil; bool default_is_nil;
bool default_is_undef;
bool default_is_location; bool default_is_location;
bool is_immutable; bool is_immutable;
bool is_thread_local; bool is_thread_local;
bool is_foreign; bool is_foreign;
Entity * foreign_library; Entity * foreign_library;
AstNode * foreign_library_ident; AstNode * foreign_library_ident;
String link_name;
} Variable; } Variable;
struct { struct {
bool is_type_alias; bool is_type_alias;
Type *type_parameter_specialization;
} TypeName; } TypeName;
struct { struct {
OverloadKind overload_kind; OverloadKind overload_kind;
@@ -107,6 +111,9 @@ struct Entity {
struct { struct {
i32 id; i32 id;
} Builtin; } Builtin;
struct {
Entity *base;
} Alias;
struct { struct {
String path; String path;
String name; 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) { bool is_entity_kind_exported(EntityKind kind) {
switch (kind) { switch (kind) {
@@ -141,7 +148,7 @@ bool is_entity_kind_exported(EntityKind kind) {
bool is_entity_exported(Entity *e) { bool is_entity_exported(Entity *e) {
// TODO(bill): Determine the actual exportation rules for imports of entities // 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)) { if (!is_entity_kind_exported(e->kind)) {
return false; 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) { 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; token.pos = parent->token.pos;
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type); Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
entity->using_parent = parent; entity->using_parent = parent;
@@ -231,6 +238,12 @@ Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type
return entity; 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, Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *type,
String path, String name, Scope *import_scope) { String path, String name, Scope *import_scope) {
Entity *entity = alloc_entity(a, Entity_ImportName, scope, token, type); 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) { Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
Token token = make_token_ident(name); Token token = make_token_ident(name);
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type); Entity *entity = alloc_entity(a, Entity_Nil, nullptr, token, type);
return entity; 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) { Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
token.string = str_lit("_"); token.string = str_lit("_");
return make_entity_variable(a, scope, token, NULL, false); return make_entity_variable(a, scope, token, nullptr, false);
} }
+44 -17
View File
@@ -5,6 +5,8 @@
struct AstNode; struct AstNode;
struct HashKey; struct HashKey;
struct Type;
bool are_types_identical(Type *x, Type *y);
struct Complex128 { struct Complex128 {
f64 real, imag; f64 real, imag;
@@ -20,6 +22,7 @@ enum ExactValueKind {
ExactValue_Complex, ExactValue_Complex,
ExactValue_Pointer, ExactValue_Pointer,
ExactValue_Compound, // TODO(bill): Is this good enough? ExactValue_Compound, // TODO(bill): Is this good enough?
ExactValue_Type,
ExactValue_Count, ExactValue_Count,
}; };
@@ -34,6 +37,7 @@ struct ExactValue {
i64 value_pointer; i64 value_pointer;
Complex128 value_complex; Complex128 value_complex;
AstNode * value_compound; AstNode * value_compound;
Type * value_type;
}; };
}; };
@@ -99,6 +103,12 @@ ExactValue exact_value_pointer(i64 ptr) {
return result; 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) { ExactValue exact_value_integer_from_string(String string) {
return exact_value_u128(u128_from_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 b = y.value_integer;
i128 c = I128_ZERO; i128 c = I128_ZERO;
switch (op) { switch (op) {
case Token_Add: c = a + b; break; case Token_Add: c = a + b; break;
case Token_Sub: c = a - b; break; case Token_Sub: c = a - b; break;
case Token_Mul: 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_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_QuoEq: c = a / b; break; // NOTE(bill): Integer division
case Token_Mod: c = a % b; break; case Token_Mod: c = a % b; break;
case Token_ModMod: c = ((a % b) + b) % b; break; case Token_ModMod: c = ((a % b) + b) % b; break;
case Token_And: c = a & b; break; case Token_And: c = a & b; break;
case Token_Or: c = a | b; break; case Token_Or: c = a | b; break;
case Token_Xor: c = a ^ b; break; case Token_Xor: c = a ^ b; break;
case Token_AndNot: c = i128_and_not(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_Shl: c = a << cast(u32)i128_to_u64(b); break;
case Token_Shr: c = a >> i128_to_u64(b); break; case Token_Shr: c = a >> cast(u32)i128_to_u64(b); break;
default: goto error; default: goto error;
} }
@@ -555,13 +565,23 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
} }
return exact_value_complex(real, imag); return exact_value_complex(real, imag);
} break; } 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: error:; // NOTE(bill): MSVC accepts this??? apparently you cannot declare variables immediately after labels...
; // MSVC accepts this??? apparently you cannot declare variables immediately after labels... return empty_exact_value;
ExactValue error_value = {};
// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
return error_value;
} }
gb_inline ExactValue exact_value_add(ExactValue x, ExactValue y) { return exact_binary_operator_value(Token_Add, x, y); } gb_inline ExactValue exact_value_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; case Token_GtEq: return a >= b;
} }
} break; } break;
case ExactValue_Type:
switch (op) {
case Token_CmpEq: return are_types_identical(x.value_type, y.value_type);
case Token_NotEq: return !are_types_identical(x.value_type, y.value_type);
}
break;
} }
GB_PANIC("Invalid comparison"); GB_PANIC("Invalid comparison");
+108 -65
View File
@@ -1,4 +1,4 @@
/* gb.h - v0.28 - Ginger Bill's C Helper Library - public domain /* gb.h - v0.31 - Ginger Bill's C Helper Library - public domain
- no warranty implied; use at your own risk - no warranty implied; use at your own risk
This is a single header file with a bunch of useful stuff This is a single header file with a bunch of useful stuff
@@ -58,6 +58,9 @@ TODOS
- More date & time functions - More date & time functions
VERSION HISTORY 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.28 - Handle UCS2 correctly in Win32 part
0.27 - OSX fixes and Linux gbAffinity 0.27 - OSX fixes and Linux gbAffinity
0.26d - Minor changes to how gbFile works 0.26d - Minor changes to how gbFile works
@@ -927,12 +930,12 @@ GB_DEF void gb_semaphore_wait (gbSemaphore *s);
// Mutex // Mutex
// TODO(bill): Should this be replaced with a CRITICAL_SECTION on win32 or is the better?
typedef struct gbMutex { typedef struct gbMutex {
gbSemaphore semaphore; #if defined(GB_SYSTEM_WINDOWS)
gbAtomic32 counter; CRITICAL_SECTION win32_critical_section;
gbAtomic32 owner; #else
i32 recursion; pthread_mutex_t pthread_mutex;
#endif
} gbMutex; } gbMutex;
GB_DEF void gb_mutex_init (gbMutex *m); 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 GB_THREAD_PROC(gbThreadProc);
typedef struct gbThread { typedef struct gbThread {
@@ -967,7 +970,9 @@ typedef struct gbThread {
#endif #endif
gbThreadProc *proc; gbThreadProc *proc;
void * data; void * user_data;
isize user_index;
isize return_value;
gbSemaphore semaphore; gbSemaphore semaphore;
isize stack_size; isize stack_size;
@@ -975,7 +980,7 @@ typedef struct gbThread {
} gbThread; } gbThread;
GB_DEF void gb_thread_init (gbThread *t); 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 (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_start_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize stack_size);
GB_DEF void gb_thread_join (gbThread *t); 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 (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_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_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_set (gbString str, char const *cstr);
GB_DEF gbString gb_string_make_space_for (gbString str, isize add_len); GB_DEF gbString gb_string_make_space_for (gbString str, isize add_len);
GB_DEF isize gb_string_allocation_size(gbString const str); 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 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_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_move (char const *existing_filename, char const *new_filename);
GB_DEF b32 gb_file_remove (char const *filename);
#ifndef GB_PATH_SEPARATOR #ifndef GB_PATH_SEPARATOR
@@ -4590,59 +4598,44 @@ gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); }
#error #error
#endif #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_inline void gb_mutex_init(gbMutex *m) {
gb_atomic32_store(&m->counter, 0); #if defined(GB_SYSTEM_WINDOWS)
gb_atomic32_store(&m->owner, gb_thread_current_id()); InitializeCriticalSection(&m->win32_critical_section);
gb_semaphore_init(&m->semaphore); #else
m->recursion = 0; 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) { gb_inline void gb_mutex_lock(gbMutex *m) {
i32 thread_id = cast(i32)gb_thread_current_id(); #if defined(GB_SYSTEM_WINDOWS)
if (gb_atomic32_fetch_add(&m->counter, 1) > 0) { EnterCriticalSection(&m->win32_critical_section);
if (thread_id != gb_atomic32_load(&m->owner)) #else
gb_semaphore_wait(&m->semaphore); pthread_mutex_lock(&m->pthread_mutex);
} #endif
gb_atomic32_store(&m->owner, thread_id);
m->recursion++;
} }
gb_inline b32 gb_mutex_try_lock(gbMutex *m) { gb_inline b32 gb_mutex_try_lock(gbMutex *m) {
i32 thread_id = cast(i32)gb_thread_current_id(); #if defined(GB_SYSTEM_WINDOWS)
if (gb_atomic32_load(&m->owner) == thread_id) { return TryEnterCriticalSection(&m->win32_critical_section) != 0;
gb_atomic32_fetch_add(&m->counter, 1); #else
} else { return pthread_mutex_trylock(&m->pthread_mutex) == 0;
i32 expected = 0; #endif
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;
} }
gb_inline void gb_mutex_unlock(gbMutex *m) { gb_inline void gb_mutex_unlock(gbMutex *m) {
i32 recursion; #if defined(GB_SYSTEM_WINDOWS)
i32 thread_id = cast(i32)gb_thread_current_id(); LeaveCriticalSection(&m->win32_critical_section);
#else
GB_ASSERT(thread_id == gb_atomic32_load(&m->owner)); pthread_mutex_unlock(&m->pthread_mutex);
#endif
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);
}
} }
@@ -4661,7 +4654,7 @@ void gb_thread_init(gbThread *t) {
gb_semaphore_init(&t->semaphore); 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); if (t->is_running) gb_thread_join(t);
gb_semaphore_destroy(&t->semaphore); gb_semaphore_destroy(&t->semaphore);
} }
@@ -4669,22 +4662,32 @@ void gb_thread_destory(gbThread *t) {
gb_inline void gb__thread_run(gbThread *t) { gb_inline void gb__thread_run(gbThread *t) {
gb_semaphore_release(&t->semaphore); gb_semaphore_release(&t->semaphore);
t->proc(t->data); t->return_value = t->proc(t);
} }
#if defined(GB_SYSTEM_WINDOWS) #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 #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 #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(!t->is_running);
GB_ASSERT(proc != NULL); GB_ASSERT(proc != NULL);
t->proc = proc; t->proc = proc;
t->data = data; t->user_data = user_data;
t->stack_size = stack_size; t->stack_size = stack_size;
#if defined(GB_SYSTEM_WINDOWS) #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_t attr;
pthread_attr_init(&attr); pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (stack_size != 0) if (stack_size != 0) {
pthread_attr_setstacksize(&attr, stack_size); pthread_attr_setstacksize(&attr, stack_size);
}
pthread_create(&t->posix_handle, &attr, gb__thread_proc, t); pthread_create(&t->posix_handle, &attr, gb__thread_proc, t);
pthread_attr_destroy(&attr); 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_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); GB_ASSERT(tmp.arena->temp_count > 0);
tmp.arena->total_allocated = tmp.original_count; tmp.arena->total_allocated = tmp.original_count;
tmp.arena->temp_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)); 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) { gbString gb_string_set(gbString str, char const *cstr) {
isize len = gb_strlen(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; if (w_len_) *w_len_ = w_len;
return NULL; 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 == 0) {
if (w_len_) *w_len_ = w_len; if (w_len_) *w_len_ = w_len;
return NULL; return NULL;
} }
w_text = gb_alloc_array(a, wchar_t, w_len+1); 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) { if (w_len1 == 0) {
gb_free(a, w_text); gb_free(a, w_text);
if (w_len_) *w_len_ = 0; 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; 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 #else
@@ -7953,6 +7991,11 @@ gb_inline b32 gb_file_move(char const *existing_filename, char const *new_filena
return false; return false;
} }
b32 gb_file_remove(char const *filename) {
return remove(filename) == 0;
}
#endif #endif
@@ -8057,17 +8100,17 @@ char *gb_path_get_full_name(gbAllocator a, char const *path) {
return NULL; return NULL;
} }
w_fullpath = gb_alloc_array(gb_heap_allocator(), wchar_t, w_len+1); 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; w_fullpath[w_len] = 0;
gb_free(gb_heap_allocator(), w_path); 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) { if (new_len == 0) {
gb_free(gb_heap_allocator(), w_fullpath); gb_free(gb_heap_allocator(), w_fullpath);
return NULL; return NULL;
} }
new_path = gb_alloc_array(a, char, new_len+1); 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) { if (new_len1 == 0) {
gb_free(gb_heap_allocator(), w_fullpath); gb_free(gb_heap_allocator(), w_fullpath);
gb_free(a, new_path); gb_free(a, new_path);
+4 -4
View File
@@ -520,7 +520,7 @@ u128 u128_quo(u128 a, u128 b) {
} }
u128 res = {0}; u128 res = {0};
u128_divide(a, b, &res, NULL); u128_divide(a, b, &res, nullptr);
return res; return res;
} }
u128 u128_mod(u128 a, u128 b) { 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); return u128_from_u64(a.lo%b.lo);
} }
u128 res = {0}; u128 res = {0};
u128_divide(a, b, NULL, &res); u128_divide(a, b, nullptr, &res);
return 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 i128_quo(i128 a, i128 b) {
i128 res = {0}; i128 res = {0};
i128_divide(a, b, &res, NULL); i128_divide(a, b, &res, nullptr);
return res; return res;
} }
i128 i128_mod(i128 a, i128 b) { i128 i128_mod(i128 a, i128 b) {
i128 res = {0}; i128 res = {0};
i128_divide(a, b, NULL, &res); i128_divide(a, b, nullptr, &res);
return res; return res;
} }
+1200 -1054
View File
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -39,7 +39,7 @@ void ir_opt_add_operands(Array<irValue *> *ops, irInstr *i) {
array_add(ops, i->If.cond); array_add(ops, i->If.cond);
break; break;
case irInstr_Return: case irInstr_Return:
if (i->Return.value != NULL) { if (i->Return.value != nullptr) {
array_add(ops, i->Return.value); array_add(ops, i->Return.value);
} }
break; break;
@@ -168,11 +168,11 @@ void ir_remove_dead_blocks(irProcedure *proc) {
isize j = 0; isize j = 0;
for_array(i, proc->blocks) { for_array(i, proc->blocks) {
irBlock *b = proc->blocks[i]; irBlock *b = proc->blocks[i];
if (b == NULL) { if (b == nullptr) {
continue; continue;
} }
// NOTE(bill): Swap order // NOTE(bill): Swap order
b->index = j; b->index = cast(i32)j;
proc->blocks[j++] = b; proc->blocks[j++] = b;
} }
proc->blocks.count = j; 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 // NOTE(bill): Mark as empty but don't actually free it
// As it's been allocated with an arena // As it's been allocated with an arena
proc->blocks[i] = NULL; proc->blocks[i] = nullptr;
} }
} }
ir_remove_dead_blocks(proc); 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); ir_opt_block_replace_pred(b->succs[i], b, a);
} }
proc->blocks[b->index] = NULL; proc->blocks[b->index] = nullptr;
return true; return true;
} }
@@ -258,7 +258,7 @@ void ir_opt_blocks(irProcedure *proc) {
changed = false; changed = false;
for_array(i, proc->blocks) { for_array(i, proc->blocks) {
irBlock *b = proc->blocks[i]; irBlock *b = proc->blocks[i];
if (b == NULL) { if (b == nullptr) {
continue; continue;
} }
GB_ASSERT_MSG(b->index == i, "%d, %td", b->index, i); 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); ir_opt_add_operands(&ops, &instr->Instr);
for_array(k, ops) { for_array(k, ops) {
irValue *op = ops[k]; irValue *op = ops[k];
if (op == NULL) { if (op == nullptr) {
continue; continue;
} }
Array<irValue *> *refs = ir_value_referrers(op); Array<irValue *> *refs = ir_value_referrers(op);
if (refs != NULL) { if (refs != nullptr) {
array_add(refs, instr); 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; preorder[i] = p;
p->dom.pre = i++; p->dom.pre = i++;
lt->sdom[p->index] = p; lt->sdom[p->index] = p;
ir_lt_link(lt, NULL, p); ir_lt_link(lt, nullptr, p);
for_array(index, p->succs) { for_array(index, p->succs) {
irBlock *q = p->succs[index]; irBlock *q = p->succs[index];
if (lt->sdom[q->index] == NULL) { if (lt->sdom[q->index] == nullptr) {
lt->parent[q->index] = p; lt->parent[q->index] = p;
i = ir_lt_depth_first_search(lt, q, i, preorder); 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 *ir_lt_eval(irLTState *lt, irBlock *v) {
irBlock *u = v; irBlock *u = v;
for (; for (;
lt->ancestor[v->index] != NULL; lt->ancestor[v->index] != nullptr;
v = lt->ancestor[v->index]) { v = lt->ancestor[v->index]) {
if (lt->sdom[v->index]->dom.pre < lt->sdom[u->index]->dom.pre) { if (lt->sdom[v->index]->dom.pre < lt->sdom[u->index]->dom.pre) {
u = v; 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); 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); irBlock **buf = gb_alloc_array(proc->module->tmp_allocator, irBlock *, 5*n);
irLTState lt = {0}; irLTState lt = {0};
@@ -432,7 +432,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
for (isize i = 1; i < n; i++) { for (isize i = 1; i < n; i++) {
irBlock *w = preorder[i]; irBlock *w = preorder[i];
if (w == root) { if (w == root) {
w->dom.idom = NULL; w->dom.idom = nullptr;
} else { } else {
// Weird tree relationships here! // Weird tree relationships here!
@@ -441,7 +441,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
} }
// Calculate children relation as inverse of idom // 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? // TODO(bill): Is this good enough for memory allocations?
array_init(&w->dom.idom->dom.children, heap_allocator()); array_init(&w->dom.idom->dom.children, heap_allocator());
} }
+609 -510
View File
File diff suppressed because it is too large Load Diff
+219 -102
View File
@@ -1,5 +1,8 @@
#define USE_CUSTOM_BACKEND 0 #define USE_CUSTOM_BACKEND 0
// #define PRINT_TIMINGS // #define NO_ARRAY_BOUNDS_CHECK
#if !defined(USE_THREADED_PARSER)
#define USE_THREADED_PARSER 0
#endif
#include "common.cpp" #include "common.cpp"
#include "timings.cpp" #include "timings.cpp"
@@ -41,8 +44,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)); cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1));
if (CreateProcessW(NULL, cmd.text, if (CreateProcessW(nullptr, cmd.text,
NULL, NULL, true, 0, NULL, NULL, nullptr, nullptr, true, 0, nullptr, nullptr,
&start_info, &pi)) { &start_info, &pi)) {
WaitForSingleObject(pi.hProcess, INFINITE); WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code); GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code);
@@ -171,6 +174,9 @@ enum BuildFlagKind {
BuildFlag_Invalid, BuildFlag_Invalid,
BuildFlag_OptimizationLevel, BuildFlag_OptimizationLevel,
BuildFlag_ShowTimings,
BuildFlag_ThreadCount,
BuildFlag_KeepTempFiles,
BuildFlag_COUNT, BuildFlag_COUNT,
}; };
@@ -201,7 +207,11 @@ void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, Bu
bool parse_build_flags(Array<String> args) { bool parse_build_flags(Array<String> args) {
Array<BuildFlag> build_flags = {}; Array<BuildFlag> build_flags = {};
array_init(&build_flags, heap_allocator(), BuildFlag_COUNT); 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; Array<String> flag_args = args;
flag_args.data += 3; flag_args.data += 3;
@@ -214,105 +224,152 @@ bool parse_build_flags(Array<String> args) {
String flag = flag_args[i]; String flag = flag_args[i];
if (flag[0] != '-') { if (flag[0] != '-') {
gb_printf_err("Invalid flag: %.*s\n", LIT(flag)); gb_printf_err("Invalid flag: %.*s\n", LIT(flag));
} else { continue;
String name = substring(flag, 1, flag.len); }
isize end = 0; String name = substring(flag, 1, flag.len);
for (; end < name.len; end++) { isize end = 0;
if (name[end] == '=') { for (; end < name.len; end++) {
break; if (name[end] == '=') break;
} }
} name = substring(name, 0, end);
name.len = end; String param = {};
String param = substring(flag, 2+end, flag.len); if (end < flag.len-1) param = substring(flag, 2+end, flag.len);
bool found = false; bool found = false;
for_array(build_flag_index, build_flags) { for_array(build_flag_index, build_flags) {
BuildFlag bf = build_flags[build_flag_index]; BuildFlag bf = build_flags[build_flag_index];
if (bf.name == name) { if (bf.name == name) {
found = true; found = true;
if (set_flags[bf.kind]) { if (set_flags[bf.kind]) {
gb_printf_err("Previous flag set: `%.*s`\n", LIT(name)); 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; bad_flags = true;
} else { } else {
ExactValue value = {}; ok = true;
bool ok = false; switch (bf.param_kind) {
if (bf.param_kind == BuildFlagParam_None) { default: ok = false; break;
if (param.len == 0) { case BuildFlagParam_Boolean: {
ok = true; 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 { } else {
gb_printf_err("Flag `%.*s` was not expecting a parameter `%.*s`\n", LIT(name), LIT(param)); gb_printf_err("Invalid flag parameter for `%.*s` = `%.*s`\n", LIT(name), LIT(param));
bad_flags = true;
} }
} else { } break;
if (param.len == 0) { case BuildFlagParam_Integer:
gb_printf_err("Flag missing for `%.*s`\n", LIT(name)); value = exact_value_integer_from_string(param);
bad_flags = true; break;
} else { case BuildFlagParam_Float:
ok = true; value = exact_value_float_from_string(param);
switch (bf.param_kind) { break;
default: ok = false; break; case BuildFlagParam_String:
case BuildFlagParam_Boolean: { value = exact_value_string(param);
if (param == "t") { break;
value = exact_value_bool(true);
} else if (param == "T") {
value = exact_value_bool(true);
} else if (param == "true") {
value = exact_value_bool(true);
} else if (param == "TRUE") {
value = exact_value_bool(true);
} else if (param == "1") {
value = exact_value_bool(true);
} else if (param == "f") {
value = exact_value_bool(false);
} else if (param == "F") {
value = exact_value_bool(false);
} else if (param == "false") {
value = exact_value_bool(false);
} else if (param == "FALSE") {
value = exact_value_bool(false);
} else if (param == "0") {
value = exact_value_bool(false);
} else {
gb_printf_err("Invalid flag parameter for `%.*s` = `%.*s`\n", LIT(name), LIT(param));
}
} break;
case BuildFlagParam_Integer:
value = exact_value_integer_from_string(param);
break;
case BuildFlagParam_Float:
value = exact_value_float_from_string(param);
break;
case BuildFlagParam_String:
value = exact_value_string(param);
break;
}
}
} }
if (ok) {
switch (bf.kind) {
case BuildFlag_OptimizationLevel:
if (value.kind == ExactValue_Integer) {
build_context.optimization_level = cast(i32)i128_to_i64(value.value_integer);
} else {
gb_printf_err("%.*s expected an integer, got %.*s", LIT(name), LIT(param));
bad_flags = true;
ok = false;
}
break;
}
}
set_flags[bf.kind] = ok;
} }
break; if (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)); if (!found) {
bad_flags = true; gb_printf_err("Unknown flag: `%.*s`\n", LIT(name));
} bad_flags = true;
} }
} }
@@ -320,7 +377,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) { int main(int arg_count, char **arg_ptr) {
if (arg_count < 2) { if (arg_count < 2) {
@@ -375,7 +489,7 @@ int main(int arg_count, char **arg_ptr) {
return 1; return 1;
#endif #endif
} else if (args[1] == "version") { } 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; return 0;
} else { } else {
usage(args[0]); usage(args[0]);
@@ -460,7 +574,7 @@ int main(int arg_count, char **arg_ptr) {
String output_name = ir_gen.output_name; String output_name = ir_gen.output_name;
String output_base = ir_gen.output_base; 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); build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3);
@@ -556,10 +670,11 @@ int main(int arg_count, char **arg_ptr) {
return exit_code; return exit_code;
} }
#if defined(PRINT_TIMINGS) if (build_context.show_timings) {
timings_print_all(&timings); show_timings(&checker, &timings);
#endif }
remove_temp_files(output_base);
if (run_output) { if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s.exe", LIT(output_base)); system_exec_command_line_app("odin run", false, "%.*s.exe", LIT(output_base));
@@ -662,9 +777,11 @@ int main(int arg_count, char **arg_ptr) {
return exit_code; return exit_code;
} }
#if defined(PRINT_TIMINGS) if (build_context.show_timings) {
timings_print_all(&timings); show_timings(&checker, &timings);
#endif }
remove_temp_files(output_base);
if (run_output) { if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base)); system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base));
+6 -6
View File
@@ -234,7 +234,7 @@ gb_inline T *map_get(Map<T> *h, HashKey key) {
if (index >= 0) { if (index >= 0) {
return &h->entries[index].value; return &h->entries[index].value;
} }
return NULL; return nullptr;
} }
template <typename T> template <typename T>
@@ -303,7 +303,7 @@ template <typename T>
MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey key) { MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey key) {
isize i = map__find(h, key).entry_index; isize i = map__find(h, key).entry_index;
if (i < 0) { if (i < 0) {
return NULL; return nullptr;
} }
return &h->entries[i]; 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; i = h->entries[i].next;
} }
return NULL; return nullptr;
} }
template <typename T> template <typename T>
isize multi_map_count(Map<T> *h, HashKey key) { isize multi_map_count(Map<T> *h, HashKey key) {
isize count = 0; isize count = 0;
MapEntry<T> *e = multi_map_find_first(h, key); MapEntry<T> *e = multi_map_find_first(h, key);
while (e != NULL) { while (e != nullptr) {
count++; count++;
e = multi_map_find_next(h, e); 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) { void multi_map_get_all(Map<T> *h, HashKey key, T *items) {
isize i = 0; isize i = 0;
MapEntry<T> *e = multi_map_find_first(h, key); MapEntry<T> *e = multi_map_find_first(h, key);
while (e != NULL) { while (e != nullptr) {
items[i++] = e->value; items[i++] = e->value;
e = multi_map_find_next(h, e); 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> template <typename T>
void multi_map_remove_all(Map<T> *h, HashKey key) { 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); map_remove(h, key);
} }
} }
+1143 -759
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -6,7 +6,7 @@ gb_inline void print_indent(isize indent) {
} }
void print_ast(AstNode *node, isize indent) { void print_ast(AstNode *node, isize indent) {
if (node == NULL) if (node == nullptr)
return; return;
switch (node->kind) { switch (node->kind) {
+145 -151
View File
@@ -206,7 +206,7 @@ ssaBlock *ssa_new_block(ssaProc *p, ssaBlockKind kind, char *name) {
b->kind = kind; b->kind = kind;
b->proc = p; b->proc = p;
p->scope_level = p->scope_level; p->scope_level = p->scope_level;
if (name != NULL || name[0] != 0) { if (name != nullptr || name[0] != 0) {
b->name = make_string_c(name); 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) { 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->values);
array_clear(&b->preds); array_clear(&b->preds);
array_clear(&b->succs); array_clear(&b->succs);
b->proc = NULL; b->proc = nullptr;
b->kind = ssaBlock_Plain; b->kind = ssaBlock_Plain;
} }
void ssa_start_block(ssaProc *p, ssaBlock *b) { void ssa_start_block(ssaProc *p, ssaBlock *b) {
GB_ASSERT(p->curr_block == NULL); GB_ASSERT(p->curr_block == nullptr);
p->curr_block = b; p->curr_block = b;
} }
ssaBlock *ssa_end_block(ssaProc *p) { ssaBlock *ssa_end_block(ssaProc *p) {
ssaBlock *b = p->curr_block; ssaBlock *b = p->curr_block;
if (b == NULL) { if (b == nullptr) {
return NULL; return nullptr;
} }
p->curr_block = NULL; p->curr_block = nullptr;
return b; return b;
} }
void ssa_add_edge_to(ssaBlock *b, ssaBlock *c) { void ssa_add_edge_to(ssaBlock *b, ssaBlock *c) {
if (b == NULL) { if (b == nullptr) {
return; return;
} }
GB_ASSERT(c != NULL); GB_ASSERT(c != nullptr);
isize i = b->succs.count; isize i = b->succs.count;
isize j = b->preds.count; isize j = b->preds.count;
ssaEdge s = {c, j}; 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) { void ssa_set_control(ssaBlock *b, ssaValue *v) {
if (b->control != NULL) { if (b->control != nullptr) {
b->control->uses--; b->control->uses--;
} }
b->control = v; b->control = v;
if (v != NULL) { if (v != nullptr) {
v->uses++; 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) { 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); ssaValue *v = gb_alloc_item(p->allocator, ssaValue);
v->id = p->value_id++; v->id = p->value_id++;
v->op = op; 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); case 64: return ssa_const_i64(p, t, cast(i64)c);
} }
GB_PANIC("Unknown int size"); 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) { ssaValue *ssa_get_last_value(ssaBlock *b) {
if (b == NULL) { if (b == nullptr) {
return NULL; return nullptr;
} }
isize len = b->values.count; isize len = b->values.count;
if (len <= 0) { if (len <= 0) {
@@ -428,7 +428,7 @@ ssaValue *ssa_get_last_value(ssaBlock *b) {
} }
void ssa_emit_comment(ssaProc *p, String s) { 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) { 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) { } else if (kind == ssaDeferExit_Return) {
ssa_build_defer_stmt(p, d); ssa_build_defer_stmt(p, d);
} else if (kind == ssaDeferExit_Branch) { } else if (kind == ssaDeferExit_Branch) {
GB_ASSERT(b != NULL); GB_ASSERT(b != nullptr);
i32 lower_limit = b->scope_level+1; i32 lower_limit = b->scope_level+1;
if (lower_limit < d.scope_level) { if (lower_limit < d.scope_level) {
ssa_build_defer_stmt(p, d); ssa_build_defer_stmt(p, d);
@@ -534,7 +534,7 @@ bool ssa_is_op_const(ssaOp op) {
bool ssa_is_blank_ident(AstNode *node) { bool ssa_is_blank_ident(AstNode *node) {
if (node->kind == AstNode_Ident) { if (node->kind == AstNode_Ident) {
ast_node(i, Ident, node); ast_node(i, Ident, node);
return is_blank_ident(i->string); return is_blank_ident(i->token.string);
} }
return false; return false;
} }
@@ -542,7 +542,7 @@ bool ssa_is_blank_ident(AstNode *node) {
ssaAddr ssa_addr(ssaValue *v) { ssaAddr ssa_addr(ssaValue *v) {
if (v != NULL) { if (v != nullptr) {
GB_ASSERT(is_type_pointer(v->type)); GB_ASSERT(is_type_pointer(v->type));
} }
ssaAddr addr = {0}; ssaAddr addr = {0};
@@ -551,13 +551,13 @@ ssaAddr ssa_addr(ssaValue *v) {
} }
Type *ssa_addr_type(ssaAddr addr) { Type *ssa_addr_type(ssaAddr addr) {
if (addr.addr == NULL) { if (addr.addr == nullptr) {
return NULL; return nullptr;
} }
if (addr.kind == ssaAddr_Map) { if (addr.kind == ssaAddr_Map) {
GB_PANIC("TODO: ssa_addr_type"); GB_PANIC("TODO: ssa_addr_type");
return NULL; return nullptr;
} }
Type *t = addr.addr->type; 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_add_local(p, e, name);
} }
return ssa_addr(NULL); return ssa_addr(nullptr);
} }
ssaAddr ssa_add_local_generated(ssaProc *p, Type *t) { 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) { if (p->curr_block) {
// scope = p->curr_block->scope; // scope = p->curr_block->scope;
} }
Entity *e = make_entity_variable(p->allocator, scope, empty_token, t, false); 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: case Type_Map:
return false; return false;
case Type_Tuple: 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; 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)) { if (!can_ssa_type(t->Tuple.variables[i]->type)) {
return false; return false;
} }
} }
return true; return true;
case Type_Record: case Type_Union:
if (t->Record.kind == TypeRecord_Union) { return false;
return false;
} else if (t->Record.kind == TypeRecord_Struct) { case Type_Struct:
if (t->Record.field_count > SSA_MAX_STRUCT_FIELD_COUNT) { if (!t->Struct.is_raw_union) {
if (t->Struct.fields.count > SSA_MAX_STRUCT_FIELD_COUNT) {
return false; return false;
} }
for (isize i = 0; i < t->Record.field_count; i++) { for_array(i, t->Struct.fields) {
if (!can_ssa_type(t->Record.fields[i]->type)) { if (!can_ssa_type(t->Struct.fields[i]->type)) {
return false; return false;
} }
} }
@@ -667,7 +668,7 @@ bool can_ssa_type(Type *t) {
} }
void ssa_addr_store(ssaProc *p, ssaAddr addr, ssaValue *value) { void ssa_addr_store(ssaProc *p, ssaAddr addr, ssaValue *value) {
if (addr.addr == NULL) { if (addr.addr == nullptr) {
return; return;
} }
if (addr.kind == ssaAddr_Map) { 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) { ssaValue *ssa_addr_load(ssaProc *p, ssaAddr addr) {
if (addr.addr == NULL) { if (addr.addr == nullptr) {
return NULL; return nullptr;
} }
if (addr.kind == ssaAddr_Map) { if (addr.kind == ssaAddr_Map) {
GB_PANIC("here\n"); GB_PANIC("here\n");
return NULL; return nullptr;
} }
Type *t = addr.addr->type; Type *t = addr.addr->type;
@@ -702,23 +703,23 @@ ssaValue *ssa_get_using_variable(ssaProc *p, Entity *e) {
String name = e->token.string; String name = e->token.string;
Entity *parent = e->using_parent; Entity *parent = e->using_parent;
Selection sel = lookup_field(p->allocator, parent->type, name, false); 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 **pv = map_get(&p->module->values, hash_pointer(parent));
ssaValue *v = NULL; ssaValue *v = nullptr;
if (pv != NULL) { if (pv != nullptr) {
v = *pv; v = *pv;
} else { } else {
v = ssa_build_addr(p, e->using_expr).addr; 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); GB_ASSERT(type_deref(v->type) == parent->type);
return ssa_emit_deep_field_ptr_index(p, v, sel); return ssa_emit_deep_field_ptr_index(p, v, sel);
} }
ssaAddr ssa_build_addr_from_entity(ssaProc *p, Entity *e, AstNode *expr) { 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)); ssaValue **found = map_get(&p->module->values, hash_pointer(e));
if (found) { if (found) {
v = *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); 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])); 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)); 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) { ssaValue *ssa_address_from_load_or_generate_local(ssaProc *p, ssaValue *v) {
if (v->op == ssaOp_Load) { if (v->op == ssaOp_Load) {
return v->args[0]; 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) { 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)); GB_ASSERT(is_type_pointer(v->type));
Type *t = base_type(type_deref(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)); 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)) { if (is_type_array(t)) {
elem_ptr = make_type_pointer(p->allocator, t->Array.elem); elem_ptr = make_type_pointer(p->allocator, t->Array.elem);
} else if (is_type_vector(t)) { } 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) { ssaValue *ssa_emit_ptr_index(ssaProc *p, ssaValue *s, i64 index) {
gbAllocator a = p->allocator; gbAllocator a = p->allocator;
Type *t = base_type(type_deref(s->type)); Type *t = base_type(type_deref(s->type));
Type *result_type = NULL; Type *result_type = nullptr;
if (is_type_struct(t)) { if (is_type_struct(t)) {
GB_ASSERT(t->Record.field_count > 0); GB_ASSERT(t->Struct.fields.count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); result_type = make_type_pointer(a, t->Struct.fields[index]->type);
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);
} else if (is_type_tuple(t)) { } else if (is_type_tuple(t)) {
GB_ASSERT(t->Tuple.variable_count > 0); GB_ASSERT(t->Tuple.variables.count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1)); GB_ASSERT(gb_is_between(index, 0, t->Tuple.variables.count-1));
result_type = make_type_pointer(a, t->Tuple.variables[index]->type); result_type = make_type_pointer(a, t->Tuple.variables[index]->type);
} else if (is_type_slice(t)) { } else if (is_type_slice(t)) {
switch (index) { 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 2: result_type = t_int_ptr; break;
case 3: result_type = t_allocator_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; Type *gst = t->Map.generated_struct_type;
switch (index) { switch (index) {
case 0: result_type = make_type_pointer(a, gst->Record.fields[0]->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->Record.fields[1]->type); break; case 1: result_type = make_type_pointer(a, gst->Struct.fields[1]->type); break;
} }
}else { }else {
GB_PANIC("TODO(bill): ssa_emit_ptr_index type: %s, %d", type_to_string(s->type), index); 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); 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; gbAllocator a = p->allocator;
Type *t = base_type(s->type); Type *t = base_type(s->type);
Type *result_type = NULL; Type *result_type = nullptr;
if (is_type_struct(t)) { if (is_type_struct(t)) {
GB_ASSERT(t->Record.field_count > 0); GB_ASSERT(t->Struct.fields.count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); result_type = t->Struct.fields[index]->type;
result_type = t->Record.fields[index]->type;
} else if (is_type_union(t)) { } else if (is_type_union(t)) {
type_set_offsets(a, t); type_set_offsets(a, t);
GB_ASSERT(t->Record.field_count > 0); GB_ASSERT(t->Struct.fields.count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); result_type = t->Struct.fields[index]->type;
result_type = t->Record.fields[index]->type;
} else if (is_type_tuple(t)) { } else if (is_type_tuple(t)) {
GB_ASSERT(t->Tuple.variable_count > 0); GB_ASSERT(t->Tuple.variables.count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
result_type = t->Tuple.variables[index]->type; result_type = t->Tuple.variables[index]->type;
} else if (is_type_slice(t)) { } else if (is_type_slice(t)) {
switch (index) { 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 2: result_type = t_int; break;
case 3: result_type = t_allocator; 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; Type *gst = t->Map.generated_struct_type;
switch (index) { switch (index) {
case 0: result_type = gst->Record.fields[0]->type; break; case 0: result_type = gst->Struct.fields[0]->type; break;
case 1: result_type = gst->Record.fields[1]->type; break; case 1: result_type = gst->Struct.fields[1]->type; break;
} }
} else { } else {
GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(s->type), index); 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); 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)) { 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)); e = ssa_emit_conv(p, e, make_type_pointer(p->allocator, type));
} else if (type->kind == Type_Record) { } else if (type->kind == Type_Struct) {
type = type->Record.fields[index]->type; type = type->Struct.fields[index]->type;
e = ssa_emit_ptr_index(p, e, index); e = ssa_emit_ptr_index(p, e, index);
} else if (type->kind == Type_Tuple) { } else if (type->kind == Type_Tuple) {
type = type->Tuple.variables[index]->type; 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)) { if (is_type_raw_union(type)) {
GB_PANIC("TODO(bill): IS THIS EVEN CORRECT?"); 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); e = ssa_emit_conv(p, e, type);
} else if (type->kind == Type_Map) { } else if (type->kind == Type_Map) {
e = ssa_emit_value_index(p, e, 1); 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")); ssa_emit_comment(p, str_lit("SelectorExpr"));
AstNode *sel = unparen_expr(se->selector); AstNode *sel = unparen_expr(se->selector);
if (sel->kind == AstNode_Ident) { 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); TypeAndValue tav = type_and_value_of_expr(p->module->info, se->expr);
if (tav.mode == Addressing_Invalid) { if (tav.mode == Addressing_Invalid) {
// NOTE(bill): Imports // NOTE(bill): Imports
Entity *imp = entity_of_ident(p->module->info, se->expr); Entity *imp = entity_of_ident(p->module->info, se->expr);
if (imp != NULL) { if (imp != nullptr) {
GB_ASSERT(imp->kind == Entity_ImportName); GB_ASSERT(imp->kind == Entity_ImportName);
} }
return ssa_build_addr(p, se->selector); return ssa_build_addr(p, se->selector);
@@ -1072,14 +1064,14 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
// if (name == "names") { // if (name == "names") {
// ssaValue *ti_ptr = ir_type_info(p, type); // ssaValue *ti_ptr = ir_type_info(p, type);
// ssaValue *names_ptr = NULL; // ssaValue *names_ptr = nullptr;
// if (is_type_enum(type)) { // if (is_type_enum(type)) {
// ssaValue *enum_info = ssa_emit_conv(p, ti_ptr, t_type_info_enum_ptr); // ssaValue *enum_info = ssa_emit_conv(p, ti_ptr, t_type_info_enum_ptr);
// names_ptr = ssa_emit_ptr_index(p, enum_info, 1); // names_ptr = ssa_emit_ptr_index(p, enum_info, 1);
// } else if (type->kind == Type_Record) { // } else if (type->kind == Type_Struct) {
// ssaValue *record_info = ssa_emit_conv(p, ti_ptr, t_type_info_record_ptr); // ssaValue *struct_info = ssa_emit_conv(p, ti_ptr, t_type_info_struct_ptr);
// names_ptr = ssa_emit_ptr_index(p, record_info, 1); // names_ptr = ssa_emit_ptr_index(p, struct_info, 1);
// } // }
// return ssa_addr(names_ptr); // return ssa_addr(names_ptr);
// } else { // } else {
@@ -1089,7 +1081,7 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
} }
Selection sel = lookup_field(p->allocator, type, selector, false); 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; ssaValue *a = ssa_build_addr(p, se->expr).addr;
a = ssa_emit_deep_field_ptr_index(p, a, sel); 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); i64 index = i128_to_i64(val.value_integer);
Selection sel = lookup_field_from_index(p->allocator, type, index); 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; ssaValue *a = ssa_build_addr(p, se->expr).addr;
a = ssa_emit_deep_field_ptr_index(p, a, sel); 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); 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) { 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 *a = core_type(x->type);
Type *b = core_type(y->type); Type *b = core_type(y->type);
if (are_types_identical(a, b)) { 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"); GB_PANIC("unknown type for -x");
} break; } break;
} }
return NULL; return nullptr;
} }
ssaValue *ssa_emit_arith(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y, Type *type) { ssaValue *ssa_emit_arith(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y, Type *type) {
if (is_type_vector(x->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_Or:
case Token_Xor: case Token_Xor:
case Token_AndNot: 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 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 *rhs = ssa_new_block(p, ssaBlock_Plain, "logical.cmp.rhs");
ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "logical.cmp.done"); 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)); 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); i64 s = 8*type_size_of(p->allocator, t);
switch (s) { switch (s) {
case 8: return ssa_const_i8 (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, 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, 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, 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"); default: GB_PANIC("Unknown integer size");
} }
} else if (is_type_float(t)) { } else if (is_type_float(t)) {
GB_ASSERT(tv.value.kind == ExactValue_Float); GB_ASSERT(tv.value.kind == ExactValue_Float);
i64 s = 8*type_size_of(p->allocator, t); i64 s = 8*type_size_of(p->allocator, t);
switch (s) { switch (s) {
case 32: return ssa_const_f32(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, 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"); 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); 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" GB_PANIC("TODO(bill): ssa_build_expr Entity_Builtin `%.*s`\n"
"\t at %.*s(%td:%td)", LIT(builtin_procs[e->Builtin.id].name), "\t at %.*s(%td:%td)", LIT(builtin_procs[e->Builtin.id].name),
LIT(token.pos.file), token.pos.line, token.pos.column); LIT(token.pos.file), token.pos.line, token.pos.column);
return NULL; return nullptr;
} else if (e->kind == Entity_Nil) { } else if (e->kind == Entity_Nil) {
GB_PANIC("TODO(bill): nil"); GB_PANIC("TODO(bill): nil");
return NULL; return nullptr;
} }
ssaValue **found = map_get(&p->module->values, hash_pointer(e)); 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_Shl:
case Token_Shr: { case Token_Shr: {
GB_PANIC("TODO: shifts"); GB_PANIC("TODO: shifts");
return NULL; return nullptr;
} }
case Token_CmpEq: case Token_CmpEq:
@@ -1772,29 +1764,29 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
case_ast_node(te, TernaryExpr, expr); case_ast_node(te, TernaryExpr, expr);
ssa_emit_comment(p, str_lit("TernaryExpr")); ssa_emit_comment(p, str_lit("TernaryExpr"));
ssaValue *yes = NULL; ssaValue *yes = nullptr;
ssaValue *no = NULL; ssaValue *no = nullptr;
GB_ASSERT(te->y != NULL); GB_ASSERT(te->y != nullptr);
ssaBlock *then = ssa_new_block(p, ssaBlock_Plain, "if.then"); 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 *done = ssa_new_block(p, ssaBlock_Plain, "if.done"); // NOTE(bill): Append later
ssaBlock *else_ = ssa_new_block(p, ssaBlock_Plain, "if.else"); 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_build_cond(p, te->cond, then, else_);
ssa_start_block(p, then); ssa_start_block(p, then);
// ssa_open_scope(p); // ssa_open_scope(p);
yes = ssa_build_expr(p, te->x); 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_emit_jump(p, done);
ssa_start_block(p, else_); ssa_start_block(p, else_);
// ssa_open_scope(p); // ssa_open_scope(p);
no = ssa_build_expr(p, te->y); 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_emit_jump(p, done);
ssa_start_block(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); Type *type = type_of_expr(proc->module->info, expr);
irValue *value = ir_value_procedure(proc->module->allocator, 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.tags = pl->tags;
value->Proc.parent = proc; 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])); 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; p->module->stmt_state_flags = prev_stmt_state_flags;
} }
void ssa_build_stmt_internal(ssaProc *p, AstNode *node) { 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, ""); ssaBlock *dead_block = ssa_new_block(p, ssaBlock_Plain, "");
ssa_start_block(p, dead_block); 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); case_ast_node(bs, BlockStmt, node);
ssa_open_scope(p); ssa_open_scope(p);
ssa_build_stmt_list(p, bs->stmts); ssa_build_stmt_list(p, bs->stmts);
ssa_close_scope(p, ssaDeferExit_Default, NULL); ssa_close_scope(p, ssaDeferExit_Default, nullptr);
case_end; case_end;
case_ast_node(us, UsingStmt, node); 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); ssa_build_when_stmt(p, ws);
case_end; case_end;
#if 0
case_ast_node(s, IncDecStmt, node); case_ast_node(s, IncDecStmt, node);
TokenKind op = Token_Add; TokenKind op = Token_Add;
if (s->op.kind == Token_Dec) { 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); Type *t = ssa_addr_type(addr);
ssa_build_assign_op(p, addr, ssa_const_int(p, t, 1), op); ssa_build_assign_op(p, addr, ssa_const_int(p, t, 1), op);
case_end; case_end;
#endif
case_ast_node(as, AssignStmt, node); case_ast_node(as, AssignStmt, node);
ssa_emit_comment(p, str_lit("AssignStmt")); 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); Type *t = base_type(init->type);
// TODO(bill): refactor for code reuse as this is repeated a bit // TODO(bill): refactor for code reuse as this is repeated a bit
if (t->kind == Type_Tuple) { 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]; Entity *e = t->Tuple.variables[i];
ssaValue *v = ssa_emit_value_index(p, init, i); ssaValue *v = ssa_emit_value_index(p, init, i);
array_add(&inits, v); array_add(&inits, v);
@@ -2064,7 +2058,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
case_ast_node(is, IfStmt, node); case_ast_node(is, IfStmt, node);
ssa_emit_comment(p, str_lit("IfStmt")); 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"); ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "if.init");
ssa_emit_jump(p, init); ssa_emit_jump(p, init);
ssa_start_block(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 *then = ssa_new_block(p, ssaBlock_Plain, "if.then");
ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "if.done"); ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "if.done");
ssaBlock *else_ = done; ssaBlock *else_ = done;
if (is->else_stmt != NULL) { if (is->else_stmt != nullptr) {
else_ = ssa_new_block(p, ssaBlock_Plain, "if.else"); else_ = ssa_new_block(p, ssaBlock_Plain, "if.else");
} }
ssaBlock *b = NULL; ssaBlock *b = nullptr;
ssa_build_cond(p, is->cond, then, else_); ssa_build_cond(p, is->cond, then, else_);
ssa_start_block(p, then); ssa_start_block(p, then);
ssa_open_scope(p); ssa_open_scope(p);
ssa_build_stmt(p, is->body); 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); ssa_emit_jump(p, done);
if (is->else_stmt != NULL) { if (is->else_stmt != nullptr) {
ssa_start_block(p, else_); ssa_start_block(p, else_);
ssa_open_scope(p); ssa_open_scope(p);
ssa_build_stmt(p, is->else_stmt); 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); ssa_emit_jump(p, done);
} }
@@ -2103,7 +2097,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
case_ast_node(fs, ForStmt, node); case_ast_node(fs, ForStmt, node);
ssa_emit_comment(p, str_lit("ForStmt")); 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"); ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "for.init");
ssa_emit_jump(p, init); ssa_emit_jump(p, init);
ssa_start_block(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 *body = ssa_new_block(p, ssaBlock_Plain, "for.body");
ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "for.done"); ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "for.done");
ssaBlock *loop = body; ssaBlock *loop = body;
if (fs->cond != NULL) { if (fs->cond != nullptr) {
loop = ssa_new_block(p, ssaBlock_Plain, "for.loop"); loop = ssa_new_block(p, ssaBlock_Plain, "for.loop");
} }
ssaBlock *post = loop; ssaBlock *post = loop;
if (fs->post != NULL) { if (fs->post != nullptr) {
post = ssa_new_block(p, ssaBlock_Plain, "for.post"); 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_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_open_scope(p);
ssa_build_stmt(p, fs->body); 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_pop_target_list(p);
ssa_emit_jump(p, post); ssa_emit_jump(p, post);
if (fs->post != NULL) { if (fs->post != nullptr) {
ssa_start_block(p, post); ssa_start_block(p, post);
ssa_build_stmt(p, fs->post); ssa_build_stmt(p, fs->post);
ssa_emit_jump(p, post); ssa_emit_jump(p, post);
@@ -2159,25 +2153,25 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
case_end; case_end;
case_ast_node(bs, BranchStmt, node); case_ast_node(bs, BranchStmt, node);
ssaBlock *b = NULL; ssaBlock *b = nullptr;
switch (bs->token.kind) { switch (bs->token.kind) {
case Token_break: 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_; b = t->break_;
} }
break; break;
case Token_continue: 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_; b = t->continue_;
} }
break; break;
case Token_fallthrough: 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_; b = t->fallthrough_;
} }
break; break;
} }
if (b != NULL) { if (b != nullptr) {
ssa_emit_defer_stmts(p, ssaDeferExit_Branch, b); ssa_emit_defer_stmts(p, ssaDeferExit_Branch, b);
} }
switch (bs->token.kind) { 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) { void ssa_print_value(gbFile *f, ssaValue *v) {
if (v == NULL) { if (v == nullptr) {
gb_fprintf(f, "nil"); gb_fprintf(f, "nil");
} }
gb_fprintf(f, "v%d", v->id); 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, " ");
gb_fprintf(f, "v%d = %.*s", v->id, LIT(ssa_op_strings[v->op])); 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)); gbString type_str = type_to_string(default_type(v->type));
gb_fprintf(f, " %s", type_str); gb_fprintf(f, " %s", type_str);
gb_string_free(type_str); gb_string_free(type_str);
@@ -2313,7 +2307,7 @@ void ssa_print_proc(gbFile *f, ssaProc *p) {
bool skip = false; bool skip = false;
for_array(k, v->args) { for_array(k, v->args) {
ssaValue *w = v->args[k]; 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; skip = true;
break; break;
} }
@@ -2377,13 +2371,13 @@ void ssa_build_proc(ssaModule *m, ssaProc *p) {
p->module = m; p->module = m;
m->proc = p; m->proc = p;
if (p->decl_info->proc_decl == NULL || if (p->decl_info->proc_lit == nullptr ||
p->decl_info->proc_decl->kind != AstNode_ProcDecl) { p->decl_info->proc_lit->kind != AstNode_ProcLit) {
return; return;
} }
ast_node(pl, ProcLit, p->decl_info->proc_decl); ast_node(pl, ProcLit, p->decl_info->proc_lit);
if (pl->body == NULL) { if (pl->body == nullptr) {
return; return;
} }
p->entry = ssa_new_block(p, ssaBlock_Entry, "entry"); 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); ssa_build_stmt(p, pl->body);
if (p->entity->type->Proc.result_count == 0) { 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"); 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; isize global_variable_max_count = 0;
Entity *entry_point = NULL; Entity *entry_point = nullptr;
bool has_dll_main = false; bool has_dll_main = false;
bool has_win_main = false; bool has_win_main = false;
@@ -2470,7 +2464,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
continue; 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 // NOTE(bill): Nothing depends upon it so doesn't need to be built
continue; continue;
} }
@@ -2495,14 +2489,14 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
} break; } break;
case Entity_Procedure: { case Entity_Procedure: {
ast_node(pd, ProcDecl, decl->proc_decl); ast_node(pl, ProcLit, decl->proc_lit);
String original_name = name; String original_name = name;
AstNode *body = pd->body; AstNode *body = pl->body;
if (e->Procedure.is_foreign) { if (e->Procedure.is_foreign) {
name = e->token.string; // NOTE(bill): Don't use the mangled name name = e->token.string; // NOTE(bill): Don't use the mangled name
} }
if (pd->link_name.len > 0) { if (pl->link_name.len > 0) {
name = pd->link_name; name = pl->link_name;
} }
if (e == entry_point) { 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); // 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); // ssa_module_add_value(m, e, p);
// HashKey hash_name = hash_string(name); // 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); // map_set(&m.members, hash_name, p);
// } // }
} break; } break;
@@ -2562,7 +2556,7 @@ String ssa_mangle_name(ssaModule *m, String path, Entity *e) {
cast(char *)new_name, max_len, cast(char *)new_name, max_len,
"%.*s-%u.%.*s", "%.*s-%u.%.*s",
cast(int)base_len, base, cast(int)base_len, base,
file->id, cast(u32)file->id,
LIT(name)); LIT(name));
if (is_overloaded) { if (is_overloaded) {
char *str = cast(char *)new_name + new_name_len-1; char *str = cast(char *)new_name + new_name_len-1;
+44 -36
View File
@@ -1,10 +1,12 @@
gb_global gbArena string_buffer_arena = {}; gb_global gbArena string_buffer_arena = {};
gb_global gbAllocator string_buffer_allocator = {}; gb_global gbAllocator string_buffer_allocator = {};
gb_global gbMutex string_buffer_mutex = {};
void init_string_buffer_memory(void) { void init_string_buffer_memory(void) {
// NOTE(bill): This should be enough memory for file systems // NOTE(bill): This should be enough memory for file systems
gb_arena_init_from_allocator(&string_buffer_arena, heap_allocator(), gb_megabytes(1)); gb_arena_init_from_allocator(&string_buffer_arena, heap_allocator(), gb_megabytes(1));
string_buffer_allocator = gb_arena_allocator(&string_buffer_arena); 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) { isize string16_len(wchar_t *s) {
if (s == NULL) { if (s == nullptr) {
return 0; return 0;
} }
wchar_t *p = s; wchar_t *p = s;
@@ -104,9 +106,8 @@ gb_inline bool str_eq_ignore_case(String a, String b) {
return false; return false;
} }
int string_compare(String x, String y) { int string_compare(String const &x, String const &y) {
if (!(x.len == y.len && if (x.len != y.len || x.text != y.text) {
x.text == y.text)) {
isize n, fast, offset, curr_block; isize n, fast, offset, curr_block;
isize *la, *lb; isize *la, *lb;
isize pos; isize pos;
@@ -148,26 +149,34 @@ GB_COMPARE_PROC(string_cmp_proc) {
return string_compare(x, y); 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_eq(String const &a, String const &b) {
gb_inline bool str_ne(String a, String b) { return !str_eq(a, b); } if (a.len != b.len) return false;
gb_inline bool str_lt(String a, String b) { return string_compare(a, b) < 0; } for (isize i = 0; i < a.len; i++) {
gb_inline bool str_gt(String a, String b) { return string_compare(a, b) > 0; } if (a.text[i] != b.text[i]) {
gb_inline bool str_le(String a, String b) { return string_compare(a, b) <= 0; } return false;
gb_inline bool str_ge(String a, String b) { return string_compare(a, b) >= 0; } }
}
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); } gb_inline bool operator == (String const &a, String const &b) { return str_eq(a, b); }
bool operator != (String a, String b) { return str_ne(a, b); } gb_inline bool operator != (String const &a, String const &b) { return str_ne(a, b); }
bool operator < (String a, String b) { return str_lt(a, b); } gb_inline bool operator < (String const &a, String const &b) { return str_lt(a, b); }
bool operator > (String a, String b) { return str_gt(a, b); } gb_inline bool operator > (String const &a, String const &b) { return str_gt(a, b); }
bool operator <= (String a, String b) { return str_le(a, b); } gb_inline bool operator <= (String const &a, String const &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_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 const &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 const &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 const &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 const &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 const &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_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) { gb_inline isize string_extension_position(String str) {
isize dot_pos = -1; isize dot_pos = -1;
isize i = str.len; isize i = str.len;
bool seen_dot = false;
while (i --> 0) { while (i --> 0) {
if (str[i] == GB_PATH_SEPARATOR) if (str[i] == GB_PATH_SEPARATOR)
break; break;
@@ -256,7 +264,7 @@ String filename_from_path(String s) {
s.text += j+1; s.text += j+1;
s.len = i-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); 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) { 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) #elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX)
@@ -305,20 +313,20 @@ String16 string_to_string16(gbAllocator a, String s) {
wchar_t *text; wchar_t *text;
if (s.len < 1) { 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) { if (len == 0) {
return make_string16(NULL, 0); return make_string16(nullptr, 0);
} }
text = gb_alloc_array(a, wchar_t, len+1); 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) { if (len1 == 0) {
gb_free(a, text); gb_free(a, text);
return make_string16(NULL, 0); return make_string16(nullptr, 0);
} }
text[len] = 0; text[len] = 0;
@@ -331,21 +339,21 @@ String string16_to_string(gbAllocator a, String16 s) {
u8 *text; u8 *text;
if (s.len < 1) { 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) { 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 len += 1; // NOTE(bill): It needs an extra 1 for some reason
text = gb_alloc_array(a, u8, len+1); 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) { if (len1 == 0) {
gb_free(a, text); gb_free(a, text);
return make_string(NULL, 0); return make_string(nullptr, 0);
} }
text[len] = 0; text[len] = 0;
+17 -6
View File
@@ -8,6 +8,7 @@ struct Timings {
TimeStamp total; TimeStamp total;
Array<TimeStamp> sections; Array<TimeStamp> sections;
u64 freq; 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)); 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)); 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) { 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_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), LIT(t->total.label),
cast(int)(max_len-t->total.label.len), SPACES, 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) { for_array(i, t->sections) {
TimeStamp ts = t->sections[i]; 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), LIT(ts.label),
cast(int)(max_len-ts.label.len), SPACES, cast(int)(max_len-ts.label.len), SPACES,
time_stamp_as_ms(ts, t->freq)); section_ms, 100*section_ms/total_ms);
} }
} }
+53 -37
View File
@@ -37,26 +37,27 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
TOKEN_KIND(Token_CmpOr, "||"), \ TOKEN_KIND(Token_CmpOr, "||"), \
\ \
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
TOKEN_KIND(Token_AddEq, "+="), \ TOKEN_KIND(Token_AddEq, "+="), \
TOKEN_KIND(Token_SubEq, "-="), \ TOKEN_KIND(Token_SubEq, "-="), \
TOKEN_KIND(Token_MulEq, "*="), \ TOKEN_KIND(Token_MulEq, "*="), \
TOKEN_KIND(Token_QuoEq, "/="), \ TOKEN_KIND(Token_QuoEq, "/="), \
TOKEN_KIND(Token_ModEq, "%="), \ TOKEN_KIND(Token_ModEq, "%="), \
TOKEN_KIND(Token_ModModEq, "%%="), \ TOKEN_KIND(Token_ModModEq, "%%="), \
TOKEN_KIND(Token_AndEq, "&="), \ TOKEN_KIND(Token_AndEq, "&="), \
TOKEN_KIND(Token_OrEq, "|="), \ TOKEN_KIND(Token_OrEq, "|="), \
TOKEN_KIND(Token_XorEq, "~="), \ TOKEN_KIND(Token_XorEq, "~="), \
TOKEN_KIND(Token_AndNotEq, "&~="), \ TOKEN_KIND(Token_AndNotEq, "&~="), \
TOKEN_KIND(Token_ShlEq, "<<="), \ TOKEN_KIND(Token_ShlEq, "<<="), \
TOKEN_KIND(Token_ShrEq, ">>="), \ TOKEN_KIND(Token_ShrEq, ">>="), \
TOKEN_KIND(Token_CmpAndEq, "&&="), \ TOKEN_KIND(Token_CmpAndEq, "&&="), \
TOKEN_KIND(Token_CmpOrEq, "||="), \ TOKEN_KIND(Token_CmpOrEq, "||="), \
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \ TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
TOKEN_KIND(Token_ArrowRight, "->"), \ TOKEN_KIND(Token_ArrowRight, "->"), \
TOKEN_KIND(Token_ArrowLeft, "<-"), \ TOKEN_KIND(Token_ArrowLeft, "<-"), \
TOKEN_KIND(Token_Inc, "++"), \ TOKEN_KIND(Token_DoubleArrowRight, "=>"), \
TOKEN_KIND(Token_Dec, "--"), \ /* TOKEN_KIND(Token_Inc, "++"), */ \
TOKEN_KIND(Token_Undef, "---"), \ /* TOKEN_KIND(Token_Dec, "--"), */ \
TOKEN_KIND(Token_Undef, "---"), \
\ \
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \ TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
TOKEN_KIND(Token_CmpEq, "=="), \ TOKEN_KIND(Token_CmpEq, "=="), \
@@ -77,26 +78,25 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
TOKEN_KIND(Token_Semicolon, ";"), \ TOKEN_KIND(Token_Semicolon, ";"), \
TOKEN_KIND(Token_Period, "."), \ TOKEN_KIND(Token_Period, "."), \
TOKEN_KIND(Token_Comma, ","), \ TOKEN_KIND(Token_Comma, ","), \
TOKEN_KIND(Token_Ellipsis, ".."), \ TOKEN_KIND(Token_Ellipsis, "..."), \
TOKEN_KIND(Token_HalfClosed, "..<"), \ TOKEN_KIND(Token_HalfClosed, ".."), \
TOKEN_KIND(Token_BackSlash, "\\"), \ TOKEN_KIND(Token_BackSlash, "\\"), \
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
\ \
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ 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, "import"), \
TOKEN_KIND(Token_import_load, "import_load"), \ TOKEN_KIND(Token_import_load, "import_load"), \
TOKEN_KIND(Token_foreign, "foreign"), \ TOKEN_KIND(Token_foreign, "foreign"), \
TOKEN_KIND(Token_foreign_library, "foreign_library"), \ TOKEN_KIND(Token_foreign_library, "foreign_library"), \
TOKEN_KIND(Token_foreign_system_library, "foreign_system_library"), \ TOKEN_KIND(Token_foreign_system_library, "foreign_system_library"), \
TOKEN_KIND(Token_type, "type"), \
TOKEN_KIND(Token_when, "when"), \ TOKEN_KIND(Token_when, "when"), \
TOKEN_KIND(Token_if, "if"), \ TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_else, "else"), \ TOKEN_KIND(Token_else, "else"), \
TOKEN_KIND(Token_for, "for"), \ TOKEN_KIND(Token_for, "for"), \
TOKEN_KIND(Token_in, "in"), \
TOKEN_KIND(Token_match, "match"), \ TOKEN_KIND(Token_match, "match"), \
TOKEN_KIND(Token_in, "in"), \
TOKEN_KIND(Token_do, "do"), \
TOKEN_KIND(Token_case, "case"), \ TOKEN_KIND(Token_case, "case"), \
TOKEN_KIND(Token_break, "break"), \ TOKEN_KIND(Token_break, "break"), \
TOKEN_KIND(Token_continue, "continue"), \ TOKEN_KIND(Token_continue, "continue"), \
@@ -107,21 +107,26 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_macro, "macro"), \ TOKEN_KIND(Token_macro, "macro"), \
TOKEN_KIND(Token_struct, "struct"), \ TOKEN_KIND(Token_struct, "struct"), \
TOKEN_KIND(Token_union, "union"), \ TOKEN_KIND(Token_union, "union"), \
TOKEN_KIND(Token_raw_union, "raw_union"), \
TOKEN_KIND(Token_enum, "enum"), \ TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_bit_field, "bit_field"), \ TOKEN_KIND(Token_bit_field, "bit_field"), \
TOKEN_KIND(Token_vector, "vector"), \ TOKEN_KIND(Token_vector, "vector"), \
TOKEN_KIND(Token_map, "map"), \
TOKEN_KIND(Token_static, "static"), \ TOKEN_KIND(Token_static, "static"), \
TOKEN_KIND(Token_dynamic, "dynamic"), \ 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_using, "using"), \
TOKEN_KIND(Token_context, "context"), \ TOKEN_KIND(Token_context, "context"), \
TOKEN_KIND(Token_push_context, "push_context"), \ TOKEN_KIND(Token_push_context, "push_context"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \ 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_asm, "asm"), \
TOKEN_KIND(Token_yield, "yield"), \ TOKEN_KIND(Token_yield, "yield"), \
TOKEN_KIND(Token_await, "await"), \ TOKEN_KIND(Token_await, "await"), \
TOKEN_KIND(Token_atomic, "atomic"), \
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \ TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
TOKEN_KIND(Token_Count, "") TOKEN_KIND(Token_Count, "")
@@ -429,7 +434,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
// TODO(bill): Memory map rather than copy contents // TODO(bill): Memory map rather than copy contents
gbFileContents fc = gb_file_read_contents(heap_allocator(), true, c_str); gbFileContents fc = gb_file_read_contents(heap_allocator(), true, c_str);
gb_zero_item(t); gb_zero_item(t);
if (fc.data != NULL) { if (fc.data != nullptr) {
t->start = cast(u8 *)fc.data; t->start = cast(u8 *)fc.data;
t->line = t->read_curr = t->curr = t->start; t->line = t->read_curr = t->curr = t->start;
t->end = t->start + fc.size; t->end = t->start + fc.size;
@@ -464,7 +469,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
} }
gb_inline void destroy_tokenizer(Tokenizer *t) { gb_inline void destroy_tokenizer(Tokenizer *t) {
if (t->start != NULL) { if (t->start != nullptr) {
gb_free(heap_allocator(), t->start); gb_free(heap_allocator(), t->start);
} }
for_array(i, t->allocated_strings) { for_array(i, t->allocated_strings) {
@@ -881,10 +886,10 @@ Token tokenizer_get_token(Tokenizer *t) {
token.kind = Token_Period; // Default token.kind = Token_Period; // Default
if (t->curr_rune == '.') { // Could be an ellipsis if (t->curr_rune == '.') { // Could be an ellipsis
advance_to_next_rune(t); advance_to_next_rune(t);
token.kind = Token_Ellipsis; token.kind = Token_HalfClosed;
if (t->curr_rune == '<') { if (t->curr_rune == '.') {
advance_to_next_rune(t); advance_to_next_rune(t);
token.kind = Token_HalfClosed; token.kind = Token_Ellipsis;
} }
} }
break; 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_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_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_Xor, Token_XorEq); break;
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); 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 '-': case '-':
token.kind = Token_Sub; token.kind = Token_Sub;
if (t->curr_rune == '=') { if (t->curr_rune == '=') {
@@ -923,7 +938,7 @@ Token tokenizer_get_token(Tokenizer *t) {
token.kind = Token_SubEq; token.kind = Token_SubEq;
} else if (t->curr_rune == '-') { } else if (t->curr_rune == '-') {
advance_to_next_rune(t); advance_to_next_rune(t);
token.kind = Token_Dec; token.kind = Token_Invalid;
if (t->curr_rune == '-') { if (t->curr_rune == '-') {
advance_to_next_rune(t); advance_to_next_rune(t);
token.kind = Token_Undef; token.kind = Token_Undef;
@@ -970,6 +985,7 @@ Token tokenizer_get_token(Tokenizer *t) {
case '<': case '<':
if (t->curr_rune == '-') { if (t->curr_rune == '-') {
advance_to_next_rune(t);
token.kind = Token_ArrowLeft; token.kind = Token_ArrowLeft;
} else { } else {
token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq); token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
+601 -658
View File
File diff suppressed because it is too large Load Diff