Init new repository

This commit is contained in:
Krzosa Karol
2024-04-13 15:29:53 +02:00
commit 5a2e3dcec4
335 changed files with 61571 additions and 0 deletions

106
tests/any.txt Normal file
View File

@@ -0,0 +1,106 @@
import "libc";
/**
* doc comment test
*
**/
print :: proc(v: Any) {
switch(v.type) {
case typeof(:int): {
val := :*int(v.data);
assert(*val == 4);
}
default: assert(0);
}
}
modify_any :: proc(v: Any) {
switch v.type {
case typeof(:int): {
val := :*int(v.data);
val[0] += 1;
}
case typeof(:*int): {
val := *:**int(v.data);
val[0] += 1;
}
default: assert(0);
}
}
any_vargs :: proc(fmt: *char, ...Any) {
va: va_list;
va_start(va, fmt);
for i := 0; fmt[i]; i += 1 {
if fmt[i] == '%' {
val := va_arg_any(va);
assert(val.type == typeof(:int) ||
val.type == typeof(:float) ||
val.type == typeof(:double)||
val.type == typeof(:*char) ||
val.type == typeof(:char) ||
val.type == typeof(:String));
}
}
va_end(va);
}
main :: proc(): int {
{
i: int;
modify_any(i);
assert(i == 0);
modify_any(&i);
assert(i == 1);
}
{
i: int = 4;
ii: *int = &i;
a: Any = {typeof(&i), &ii};
b: Any = &i;
c: Any = a;
assert(*:**int(a.data) == *:**int(b.data));
assert(a.type == b.type);
assert(a.data == c.data);
assert(a.type == c.type);
}
{
a: Any = 32;
b: Any = 33;
assert(*:*int(a.data) + 1 == *:*int(b.data));
}
{
c: Any = "thing";
d: Any = 32.5232;
e: Any = :float(32);
f: Any = :String("another_thing");
assert(c.type == typeof(:*char));
assert(d.type == typeof(:double));
assert(e.type == typeof(:float));
assert(f.type == typeof(:String));
}
{
a: String = "asd";
b: Any = a;
assert(:*String(b.data).len == 3);
}
{
any_vargs("% % %", "asd", 32, 32.042);
any_vargs("% % %", :String("asd"), :char(32), :float(32.042));
}
return 0;
}

4
tests/any2.txt Normal file
View File

@@ -0,0 +1,4 @@
// #failed: resolve
// #error: non constant global declarations are illegal
global: int = 4;
any_global: Any = global;

25
tests/arrays.txt Normal file
View File

@@ -0,0 +1,25 @@
import "libc";
p :: proc(a: [100]int @unused) {
}
vv: [10]int = {[5] = 4};
str := :[]*char{"A", "B", "CD"};
#static_assert(1 == 1);
main :: proc(): int {
v: [100]int = {1,2};
#static_assert(typeof(v) == typeof(:[100]int));
assert(v[0] == 1);
assert(v[1] == 2);
assert(vv[5] == 4);
assert(vv[6] == 0);
p(v); // disallow?
assert(str[0][0] == 'A');
p0: *int = &v[0];
p1 := &v[0];
#static_assert(typeof(p0) == typeof(p1));
return 0;
}

173
tests/assign.txt Normal file
View File

@@ -0,0 +1,173 @@
// #failed: resolve
// #expected_error_count: 41
E :: typedef int;
EA :: 0;
EB :: ^;
S :: struct {a: int;}
Ts :: typedef int;
@weak T :: typedef int;
main :: proc(): int {
{
a: int;
a = EB;
a /= 1;
a *= 1;
a %= 1;
a -= 1;
a += 1;
a &= 1;
a |= 1;
a <<= 1;
a >>= 1;
}
{
a: float;
a = 1;
a /= 1;
a *= 1;
a -= 1;
a += 1;
{a %= 1;}
{a &= 1;}
{a |= 1;}
{a <<= 1;}
{a >>= 1;}
}
{
a: E;
a = 1;
a /= 1;
a *= 1;
a %= 1;
a -= 1;
a += 1;
a &= 1;
a |= 1;
a <<= 1;
a >>= 1;
a = EB;
a /= EB;
a *= EB;
a %= EB;
a -= EB;
a += EB;
a &= EB;
a |= EB;
a <<= EB;
a >>= EB;
}
{
b: int;
a: *int;
a = &b;
{a /= &b;}
{a *= &b;}
{a %= &b;}
{a -= &b;}
{a += &b;}
{a &= &b;}
{a |= &b;}
{a <<= &b;}
{a >>= &b;}
}
{
a: S;
b: S;
a = b;
{a /= b;}
{a *= b;}
{a %= b;}
{a -= b;}
{a += b;}
{a &= b;}
{a |= b;}
{a <<= b;}
{a >>= b;}
}
{
a: Ts;
b: Ts;
a = 1;
a /= 1;
a *= 1;
a %= 1;
a -= 1;
a += 1;
a &= 1;
a |= 1;
a <<= 1;
a >>= 1;
a = b;
a /= b;
a *= b;
a %= b;
a -= b;
a += b;
a &= b;
a |= b;
a <<= b;
a >>= b;
}
{
a: T;
b: T;
a = 1;
a /= 1;
a *= 1;
a %= 1;
a -= 1;
a += 1;
a &= 1;
a |= 1;
a <<= 1;
a >>= 1;
a = b;
a /= b;
a *= b;
a %= b;
a -= b;
a += b;
a &= b;
a |= b;
a <<= b;
a >>= b;
}
{
a: String = "memes";
b: String = "memes";
a = "something_else";
a /= "something_else";
a *= "something_else";
a %= "something_else";
a -= "something_else";
a += "something_else";
a &= "something_else";
a |= "something_else";
a <<= "something_else";
a >>= "something_else";
a = b;
a /= b;
a *= b;
a %= b;
a -= b;
a += b;
a &= b;
a |= b;
a <<= b;
a >>= b;
}
return 0;
}

View File

@@ -0,0 +1,18 @@
// #failed: resolve
A :: proc() {}
B :: proc() {}
C :: proc() {}
D :: proc() {}
E :: proc() {}
main :: proc(): int {
a := A();
b := +B();
c := C() + D();
e := E() + 10;
return 0;
}
// #error: cannot assign void expression to a variable
// #error: invalid unary operation for type 'void'
// #error: cannot perform binary operation, types don't qualify for it, left: 'void' right: 'void'
// #error: cannot perform binary operation, types don't qualify for it, left: 'void' right: 'UntypedInt'

View File

@@ -0,0 +1,12 @@
// #failed: resolve
// #error: break inside of defer is illegal
main :: proc() {
defer {
{
{
for { break; }
}
}
}
}

View File

@@ -0,0 +1,6 @@
// #failed: resolve
// #error: break outside of a for loop is illegal
main :: proc() {
break;
}

21
tests/build_if_note.txt Normal file
View File

@@ -0,0 +1,21 @@
A :: proc() {
} @build_if(LC_OS == OS_LINUX)
A :: proc() {
} @build_if(LC_OS == OS_WINDOWS)
A :: proc() {
} @build_if(LC_OS == OS_MAC)
B :: proc() {
} @build_if(0)
B :: proc() {
}
main :: proc(): int {
A();
B();
return 0;
}

89
tests/builtins.txt Normal file
View File

@@ -0,0 +1,89 @@
import "libc";
main :: proc(): int {
a: int;
d: float;
assert(typeof(:int) == typeof(:int));
assert(typeof(:int) == typeof(a));
assert(typeof(:float) != typeof(:int));
assert(sizeof(:int) == sizeof(a));
assert(alignof(:int) == alignof(:int));
assert(sizeof(:int) != sizeof(:*int));
assert(typeof(:int) != typeof(:*int));
assert(alignof(:int) != alignof(:*int));
assert(typeof(:*int) == typeof(&a));
assert(sizeof(:*int) == sizeof(&a));
assert(sizeof(a) == sizeof(d));
arr: [30]int;
assert(lengthof(arr) == 30);
assert(sizeof(arr) == lengthof(arr) * sizeof(:int));
assert(typeof(arr) == typeof(:[30]int));
assert(typeof(:int) != typeof(:[30]int));
assert(typeof(arr[0]) == typeof(a));
assert(typeof(:double) != typeof(:int));
assert(typeof(:double) != typeof(:*double));
t := :[]ullong{
typeof(:char),
typeof(:uchar),
typeof(:short),
typeof(:ushort),
typeof(:bool),
typeof(:int),
typeof(:uint),
typeof(:long),
typeof(:ulong),
typeof(:llong),
typeof(:ullong),
typeof(:float),
typeof(:double),
typeof(:*char),
typeof(:*uchar),
typeof(:*short),
typeof(:*ushort),
typeof(:*bool),
typeof(:*int),
typeof(:*uint),
typeof(:*long),
typeof(:*ulong),
typeof(:*llong),
typeof(:*ullong),
typeof(:*float),
typeof(:*double),
typeof(:[1]char),
typeof(:[1]uchar),
typeof(:[1]short),
typeof(:[1]ushort),
typeof(:[1]bool),
typeof(:[1]int),
typeof(:[1]uint),
typeof(:[1]long),
typeof(:[1]ulong),
typeof(:[1]llong),
typeof(:[1]ullong),
typeof(:[1]float),
typeof(:[1]double),
typeof(:**char),
typeof(:**uchar),
typeof(:**short),
typeof(:**ushort),
typeof(:**bool),
typeof(:**int),
typeof(:**uint),
typeof(:**long),
typeof(:**ulong),
typeof(:**llong),
typeof(:**ullong),
typeof(:**float),
typeof(:**double),
};
for i := 0; i < lengthof(t); i += 1 {
for j := 0; j < lengthof(t); j += 1 {
if (i==j) continue;
assert(t[i] != t[j]);
}
}
return 0;
}

12
tests/builtins2.txt Normal file
View File

@@ -0,0 +1,12 @@
// #failed: resolve
// #expected_error_count: 6
main :: proc(): int {
sizeof(:int, a = 10);
sizeof(a = 10);
sizeof(10);
alignof(:int, a = 10);
alignof(a = 10);
alignof(10);
}

21
tests/builtins3.txt Normal file
View File

@@ -0,0 +1,21 @@
// #failed: resolve
A :: struct {
a: int;
b: int;
}
main :: proc(): int {
offsetof(:A, b);
// #error: first argument should be a type
offsetof(A, b);
// #error: expected 2 arguments to builtin procedure 'offsetof', got: 3
offsetof(:A, b, b);
// #error: named arguments in this builtin procedure are illegal
offsetof(a = :A, b);
return 0;
}

View File

@@ -0,0 +1,13 @@
// #failed: resolve
A :: struct { a: int; b: int; }
B :: typedef int;
main :: proc(): int {
// #error: cannot use type as value
a := :A;
// #error: cannot use type as value
b := :A.i;
// #error: declaration is type, unexpected inside expression
d := B;
return 0;
}

View File

@@ -0,0 +1,4 @@
#include "../../src/compiler/lib_compiler.h"
int main() {
}

View File

@@ -0,0 +1,40 @@
#define LIB_COMPILER_IMPLEMENTATION
#include "../../lib_compiler.h"
int main(int argc, char **argv) {
bool colored = LC_EnableTerminalColors();
LC_StringList dirs = {0};
LC_Arena arena = {0};
LC_String package = LC_MakeEmptyString();
for (int i = 1; i < argc; i += 1) {
LC_String arg = LC_MakeFromChar(argv[i]);
if (LC_StartsWith(arg, LC_Lit("dir="), LC_IgnoreCase)) {
LC_String dir = LC_Skip(arg, 4);
LC_AddNode(&arena, &dirs, dir);
} else {
package = arg;
}
}
if (package.len == 0) {
printf("package name not passed\n");
return 0;
}
LC_Lang *lang = LC_LangAlloc();
lang->use_colored_terminal_output = colored;
LC_LangBegin(lang);
LC_RegisterPackageDir(".");
for (LC_StringNode *it = dirs.first; it; it = it->next) {
LC_RegisterPackageDir(it->string.str);
}
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
LC_ASTRefList packages = LC_ResolvePackageByName(name);
if (lang->errors) return 1;
LC_String code = LC_GenerateUnityBuild(packages);
(void)code;
}

View File

@@ -0,0 +1,40 @@
#define LIB_COMPILER_IMPLEMENTATION
#include "../../lib_compiler.h"
int main(int argc, char **argv) {
bool colored = LC_EnableTerminalColors();
LC_StringList dirs = {0};
LC_Arena arena = {0};
LC_String package = LC_MakeEmptyString();
for (int i = 1; i < argc; i += 1) {
LC_String arg = LC_MakeFromChar(argv[i]);
if (LC_StartsWith(arg, LC_Lit("dir="), LC_IgnoreCase)) {
LC_String dir = LC_Skip(arg, 4);
LC_AddNode(&arena, &dirs, dir);
} else {
package = arg;
}
}
if (package.len == 0) {
printf("package name not passed\n");
return 0;
}
LC_Lang *lang = LC_LangAlloc();
lang->use_colored_terminal_output = colored;
LC_LangBegin(lang);
LC_RegisterPackageDir(".");
for (LC_StringNode *it = dirs.first; it; it = it->next) {
LC_RegisterPackageDir(it->string.str);
}
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
LC_ASTRefList packages = LC_ResolvePackageByName(name);
if (lang->errors) return 1;
LC_String code = LC_GenerateUnityBuild(packages);
(void)code;
}

View File

@@ -0,0 +1,5 @@
#include "../../src/compiler/lib_compiler.c"
#include "../../src/core/core.c"
int main() {
}

View File

@@ -0,0 +1,5 @@
#include "../../src/compiler/lib_compiler.c"
#include "../../src/core/core.c"
int main() {
}

View File

@@ -0,0 +1,11 @@
// #failed: resolve
// #error: cyclic dependency
A :: struct {
a: int;
b: int;
}
AA: A = {
a = 10,
b = AA.a,
};

55
tests/compos.txt Normal file
View File

@@ -0,0 +1,55 @@
import "libc";
Node :: struct {
i: int;
l: *Node;
r: *Node;
}
v: int;
thing :: proc(a:int @unused, b:int @unused, c:int @unused) {}
thingp :: proc(): *int {return &v;}
default_args :: proc(a: int = 10 @unused, b: int = 10 @unused): int {return 0;}
vargs_proc :: proc(a: int @unused, ...) {}
// v1 := default_args(v0, v0); // @todo: make error
// v0 := default_args(1,2);
main :: proc(): int {
node: Node = {
i = 1,
l = &:Node{
i = 2,
},
r = &:Node{
i = 3,
l = &:Node{
i = 4,
}
}
};
default_args();
default_args(a = 1);
default_args(b = 2);
default_args(1, 2);
default_args(a = 1, b = 2);
default_args(1, b = 2);
vargs_proc(1, 2, 3, 4);
vargs_proc(1);
assert(node.i == 1);
assert(node.l.i == 2);
assert(node.r.i == 3);
assert(node.r.l.i == 4);
:Node{2}.i = 2;
assert(:Node{2}.i == 2);
thing(1,2,3);
assert(thingp()[0] == 0);
thingp()[0] = 0;
*thingp() = 0;
return 0;
}

4
tests/compos2.txt Normal file
View File

@@ -0,0 +1,4 @@
// #failed: resolve
// #error: cannot assign, types require explicit cast, variable type: '[6]int' expression type: '[5]int'
d: [6]int = :[5]int{1, 2, 3, 4};

48
tests/compos_resolve.txt Normal file
View File

@@ -0,0 +1,48 @@
// #failed: resolve
Vals :: struct {a:int;b:int;}
vv0: Vals = {1, 2};
vv1: Vals = {1};
vv2: Vals = {a = 1};
vv3: Vals = {a = 1, b = 2};
vv4: Vals = {};
v0 := :Vals {1, 2};
v1 := :Vals {1};
v2 := :Vals {a = 1};
v3 := :Vals {a = 1, b = 2};
v4 := :Vals {};
// #error: too many struct initializers, expected less then 2 got instead 3
e0 := :Vals {1, 2, 3};
// #error: too many struct initializers, expected less then 2 got instead 3
e1 := :Vals {a = 1, b = 2, c = 3};
// #error: no matching declaration with name 'c' in type 'Vals'
e2 := :Vals {c = 3};
// #error: mixing named and positional arguments is illegal
e3 := :Vals {a = 2, 2};
// #error: mixing named and positional arguments is illegal
e4 := :Vals {b = 2, 2};
// #error: mixing named and positional arguments is illegal
e5 := :Vals {c = 2, 2};
Node :: struct {
l: *Node;
r: *Node;
i: int;
}
// #error: cannot assign, can assign only const integer equal to 0, variable type: '*Node' expression type: 'UntypedInt'
n0: Node = {i = 10, l = &:Node{1, 2, 3}}; // this is legal, do we do something about this?
a: int;
// #error: cannot assign, types require explicit cast, variable type: '*Node' expression type: '*int'
ne0: Node = {i = 10, l = &:Node{&a}};
// #error: too many struct initializers, expected less then 3 got instead 4
ne1: Node = {i = 10, l = &:Node{1, 2, 3, 4}};
// #error: no matching declaration with name 'c' in type 'Node'
ne2: Node = {i = 10, l = &:Node{c = 2}};
// #error: mixing named and positional arguments is illegal
ne3: Node = {i = 10, l = &:Node{l = 0, r = 0, 2}};

4
tests/const.txt Normal file
View File

@@ -0,0 +1,4 @@
// #dont_run
A :: 123 + B + 23 + 123412512 + 123 + B;
B :: 11;
C :: A + B + A + B + 3251;

View File

@@ -0,0 +1,37 @@
import "libc";
S :: struct { s: String; }
main :: proc(): int {
using_const: String = "Something";
str := using_const.str;
len := using_const.len;
assert(str[0] == 'S');
assert(typeof(str) == typeof(:*char));
assert(typeof(len) == typeof(:int));
cast_string := :String("Something");
assert(typeof(cast_string) == typeof(:String));
assert(cast_string.str[0] == 'S');
assert(cast_string.len == 9);
new_line: String = "\n";
assert(new_line.len == 1);
assert(*new_line.str == '\n');
ss: S = { "Thing" }; @unused
ss2: S = { {str = "asd", len = 3} }; @unused
proc_call("Memes");
constant :: "string";
from_constant: String = constant; @unused
return 0;
}
global_string: String = "Something";
global_s: S = { "Thing" };
proc_call :: proc(s: String @unused) {}

View File

@@ -0,0 +1,11 @@
// #failed: resolve
// #error: defer inside of defer is illegal
main :: proc(): int {
i := 0;
defer {
defer i += 1;
i += 1;
}
return 0;
}

21
tests/defer_order.txt Normal file
View File

@@ -0,0 +1,21 @@
i := 0;
a: [4]int;
test :: proc() {
defer {a[i] = 1; i += 1;}
defer {a[i] = 2; i += 1;}
defer {a[i] = 3; i += 1;}
defer {a[i] = 4; i += 1;}
}
main :: proc(): int {
test();
i1 := a[0] == 4;
i2 := a[1] == 3;
i3 := a[2] == 2;
i4 := a[3] == 1;
result := i1 + i2 + i3 + i4;
result -= 4;
return :int(result);
}

View File

@@ -0,0 +1,7 @@
// #failed: resolve
// #error: returning from defer block is illegal
main :: proc(): int {
defer return 0;
return 0;
}

3
tests/division_by_0.txt Normal file
View File

@@ -0,0 +1,3 @@
// #failed: resolve
// #error: division by 0
a :: 10.0 / 0.0;

36
tests/doc_comment.txt Normal file
View File

@@ -0,0 +1,36 @@
// #failed: parse
// #error: got unexpected token: doc comment
// #error: got unexpected token: doc comment
/**
* doc comment test
*
**/
A :: proc() {
}
/**
* doc comment test
*
**/
/**
* doc comment test
*
**/
B :: proc() {
}
/**
* doc comment test
*
**/
/**
* doc comment test
*
**/
C :: proc() {
}

17
tests/doc_comments2.txt Normal file
View File

@@ -0,0 +1,17 @@
/** package
* package doc comment
*/
/** file
* file doc comment
*/
/**
* normal doc comment
*/
something :: proc() {
}
main :: proc(): int {
return 0;
}

8
tests/doc_comments3.txt Normal file
View File

@@ -0,0 +1,8 @@
// #failed: parse
// #error: got unexpected token: package doc comment
/** file
*/
/** package
*/

View File

@@ -0,0 +1,2 @@
b :: proc() {
}

View File

@@ -0,0 +1,6 @@
import "std_types";
import "32asd";
main :: proc(): int {
return 0;
}

View File

@@ -0,0 +1,2 @@
a :: proc() {
}

View File

@@ -0,0 +1,3 @@
// #failed: package
// #error: found 2 directories with the same name
// #error: invalid package name, please change

View File

@@ -0,0 +1,10 @@
// #failed: resolve
// #error: non constant global declarations are illegal
// #error: expected an untyped constant
thing :: proc(): int {
return 0;
}
variable := thing();
constant :: thing();

View File

@@ -0,0 +1,9 @@
// #failed: resolve
// #error: undeclared identifier 'meme'
A: meme;
main :: proc(): int {
// #error: undeclared identifier 'asd'
a: asd;
return a;
}

View File

@@ -0,0 +1,37 @@
// #failed: resolve
BUILTIN_sizeof := sizeof(:int);
BUILTIN_alignof := sizeof(:int);
BUILTIN_typedef := typeof(F);
BUILTIN_offsetof := offsetof(:STRUCT, a);
A: int;
B: *int = &A;
PROC :: proc(): int {return 10;}
ARR: [4]int = {1,2,3,4};
// #error: non constant global declarations are illegal
ARR_PROC_VAL := :[]int{PROC(),2,3,4};
// #error: non constant global declarations are illegal
ARR_VAL := ARR[0];
// #error: non constant global declarations are illegal
C := *B;
// #error: non constant global declarations are illegal
D := B[0];
//// #error: non constant global declarations are illegal
//E := B^[0];
// #error: non constant global declarations are illegal
VAR := PROC();
// #error: cannot assign, can assign only const integer equal to 0, variable type: '*int' expression type: 'UntypedInt'
F: *int = 1 - 1;
// #error: cannot assign, can assign only const integer equal to 0, variable type: '*int' expression type: 'UntypedInt'
G: *int = -(1-1);
STRUCT :: struct { a: int; b: int; }
STRUCT_VAL: STRUCT = { 1, 2 };
GG := STRUCT_VAL.a;
// #error: non constant global declarations are illegal
STRUCT_VAL_PROC: STRUCT = {PROC()};

View File

@@ -0,0 +1,12 @@
// #failed: resolve
main :: proc(): int {
// #error: there are 2 decls with the same name 'a'
// #error: a
a: int;
{
a: int;
}
return 1;
}

View File

@@ -0,0 +1,20 @@
// #failed: resolve
// #error: invalid binary operation for type '*int'
// #error: invalid binary operation for type '*int'
// #error: invalid binary operation for type '*int'
// #error: invalid binary operation for type '*int'
// #error: indexing with non integer value of type '*int'
main :: proc(): int {
a: *int;
b: *int;
val: int;
c := a - b;
d := a - 4;
e := a * 2;
f := a + val;
g := &a[b];
return 0;
}

View File

@@ -0,0 +1,41 @@
// #failed: resolve
// #error: unknown argument to a procedure call, couldn't match it with any of the declared arguments
// #error: unknown argument to a procedure call, couldn't match it with any of the declared arguments
// #error: unknown argument to a procedure call, couldn't match it with any of the declared arguments
// #error: mixing named and positional arguments is illegal
// #error: mixing named and positional arguments is illegal
// #error: invalid argument count passed in to procedure call
// #error: invalid argument count passed in to procedure call
// #error: invalid argument count passed in to procedure call
// #error: invalid argument count passed in to procedure call
// #error: unknown argument to a procedure call, couldn't match it with any of the declared arguments
// #error: cannot assign void expression to a variable
default_args :: proc(a: int = 10, b: int = 10): int {
return a + b;
}
no_default :: proc(a: int @unused, b: int @unused) {
}
main :: proc(): int {
def0 := default_args(1,2,3);
def1 := default_args(c = 10);
def2 := default_args(1, a = 1, b = 2);
def3 := default_args(a = 1, 2);
def4 := default_args(b = 1, 2);
no_default();
no_default(1);
no_default(a = 1);
no_default(b = 1);
no_default(a = 2, c = 1);
assign_void := no_default(1, 2);
return 0;
}

View File

@@ -0,0 +1,8 @@
a: [2]int;
main :: proc(): int {
a = {[1] = 2};
a = {1, 2};
return a[1] - 2;
}

43
tests/errors.txt Normal file
View File

@@ -0,0 +1,43 @@
// #failed: resolve
// #error: declaration is type, unexpected inside expression
i0 := typeof(int);
// #error: declaration is type, unexpected inside expression
i1 := sizeof(double);
p0: *int;
// #error: non constant global declarations are illegal
p1: int = p0[0];
// #error: invalid binary operation for type '*int'
p2 := p0 + 1;
Tint :: typedef int;
t0: int;
t1: Tint;
// #error: cannot perform binary operation, types are incompatible, left: 'Tint' right: 'int'
t2 := t1 + t0;
// #error: #static_assert cant be used as variable initializer
AssertInitializer: int = #static_assert(1 == 1);
// #error: cannot assign, can assign only const integer equal to 0, variable type: '*int' expression type: 'UntypedInt'
pi0: *int = 1;
pi1: *int = nil;
// #error: cannot assign, can assign only const integer equal to 0, variable type: '*int' expression type: 'UntypedInt'
pi2: *int = 1-1;
_pi3: *char;
// #error: cannot assign, types require explicit cast, variable type: '*int' expression type: '*char'
pi3: *int = _pi3;
_pi4: char;
// #error: cannot assign, types require explicit cast, variable type: '*int' expression type: '*char'
pi4: *int = &_pi4;
// #error: cannot create a variable of type void
pi5: void = 0;
// #error: cannot create a variable of type void
pi6: void;
// #error: cannot cast, types are incompatible, left: 'void' right: 'UntypedInt'
pi7 := :void(0);

View File

@@ -0,0 +1,13 @@
// #failed: resolve
// #error: calling procedure with invalid argument count, expected at least 1 args, got 0
// #error: variadic procedures cannot have named arguments
var_proc :: proc(a: int, ...): int {
return a;
}
main :: proc(): int {
var_proc();
var_proc(a = 1);
return 0;
}

View File

@@ -0,0 +1,7 @@
@echo off
mkdir build
cd build
clang unity_exe.c -o platform.exe -g -O0 -I"../.."
clang unity_dll.c -o game.dll -O0 -shared -g -I"../.." -Wl,-export:APP_Update

View File

@@ -0,0 +1,78 @@
import "shared";
IO_Assertf :: proc(b: bool, s: *char, ...); @foreign
IO_Assert :: proc(b: bool); @foreign
IO_InvalidCodepath :: proc(); @foreign
S8_Lit :: proc(s: *char): S8_String; @foreign
IO_FatalErrorf :: proc(msg: *char, ...); @foreign
IO_FatalError :: proc(msg: *char); @foreign
HashBytes :: proc(data: *void, data_size: u64): u64; @foreign
// @todo: hmm ?
SLL_QUEUE_ADD :: proc(first: *void, last: *void, data: *void); @foreign
Mu: *MU_Context;
Gs: *GameState;
Perm: *MA_Arena;
Temp: *MA_Arena;
R: *R_Render;
GameState :: struct {
render: R_Render;
}
activated: bool;
APP_Update :: proc(event: LibraryEvent, mu: *MU_Context, dll_context: *DLL_Context) {
Mu = mu;
Perm = &dll_context.perm;
Temp = dll_context.temp;
Gs = dll_context.context;
if event == Init {
dll_context.context = MA_PushSize(Perm, :usize(sizeof(:GameState)));
Gs = dll_context.context;
R_Init(&Gs.render);
return;
}
if event == Reload {
R_Reload();
return;
}
if event == Unload {
return;
}
UI_Begin();
Ui.cut = UI_Cut_Top;
UI_PushLayout({});
{
Ui.cut = UI_Cut_Left;
if (UI_Checkbox(&activated, "File")) {
}
UI_Button("Edit");
Ui.cut = UI_Cut_Right;
UI_Button("Memes");
Ui.s.cut_size.x += 100000;
UI_Fill();
UI_PopLayout();
UI_PopStyle();
}
UI_End();
R_Text2D({
pos = {100, 100},
text = S8_Lit("Testing memes"),
color = R_ColorWhite,
do_draw = true,
scale = 1.0,
});
R_Rect2D(R2P_SizeF(200, 200, 100, 100), R.atlas.white_texture_bounding_box, R_ColorWhite);
R_EndFrame();
}

View File

@@ -0,0 +1,122 @@
V2 :: struct { x: f32; y: f32; }
V3 :: struct { x: f32; y: f32; z: f32; }
V4 :: struct { x: f32; y: f32; z: f32; w: f32; }
R2P :: struct { min: V2; max: V2; }
V2I :: struct { x: i32; y: i32; }
V3I :: struct { x: i32; y: i32; z: i32; }
V4I :: struct { x: i32; y: i32; z: i32; w: i32; }
R2P_SizeF :: proc(px: f32, py: f32, sx: f32, sy: f32): R2P {
result: R2P = {{px, py}, {px + sx, py + sy}};
return result;
}
R2P_Size :: proc(pos: V2, size: V2): R2P {
result := :R2P{{pos.x, pos.y}, {pos.x + size.x, pos.y + size.y}};
return result;
}
R2P_GetSize :: proc(r: R2P): V2 {
result := :V2{r.max.x - r.min.x, r.max.y - r.min.y};
return result;
}
V2_Mul :: proc(a: V2, b: V2): V2 {
result := :V2{a.x * b.x, a.y * b.y};
return result;
}
V2_MulF :: proc(a: V2, b: f32): V2 {
result := :V2{a.x * b, a.y * b};
return result;
}
V2_FromV2I :: proc(a: V2I): V2 {
result := :V2{:f32(a.x), :f32(a.y)};
return result;
}
I32_Max :: proc(a: i32, b: i32): i32 {
if a > b return a;
return b;
}
I32_Min :: proc(a: i32, b: i32): i32 {
if a > b return b;
return a;
}
F32_Max :: proc(a: f32, b: f32): f32 {
if a > b return a;
return b;
}
F32_Min :: proc(a: f32, b: f32): f32 {
if a > b return b;
return a;
}
F32_Clamp :: proc(val: f32, min: f32, max: f32): f32 {
if (val > max) return max;
if (val < min) return min;
return val;
}
R2P_CutLeft :: proc(r: *R2P, value: float): R2P {
minx := r.min.x;
r.min.x = F32_Min(r.max.x, r.min.x + value);
return :R2P{
{ minx, r.min.y},
{r.min.x, r.max.y}
};
}
R2P_CutRight :: proc(r: *R2P, value: f32): R2P {
maxx := r.max.x;
r.max.x = F32_Max(r.max.x - value, r.min.x);
return :R2P{
{r.max.x, r.min.y},
{ maxx, r.max.y}
};
}
R2P_CutTop :: proc(r: *R2P, value: f32): R2P { // Y is up
maxy := r.max.y;
r.max.y = F32_Max(r.min.y, r.max.y - value);
return :R2P{
{r.min.x, r.max.y},
{r.max.x, maxy}
};
}
R2P_CutBottom :: proc(r: *R2P, value: f32): R2P { // Y is up
miny := r.min.y;
r.min.y = F32_Min(r.min.y + value, r.max.y);
return :R2P{
{r.min.x, miny},
{r.max.x, r.min.y}
};
}
R2P_Shrink :: proc(r: R2P, size: f32): R2P {
return :R2P{
:V2{r.min.x + size, r.min.y + size},
:V2{r.max.x - size, r.max.y - size}
};
}
R2P_CollidesV2 :: proc(rect: R2P , point: V2): bool {
result := point.x > rect.min.x && point.x < rect.max.x && point.y > rect.min.y && point.y < rect.max.y;
return result;
}
R2P_CollidesR2P :: proc(a: R2P, b: R2P): bool {
result := a.min.x < b.max.x && a.max.x > b.min.x && a.min.y < b.max.y && a.max.y > b.min.y;
return result;
}
V2_Add :: proc(a: V2, b: V2): V2 { return {a.x + b.x, a.y + b.y}; }
V2_Sub :: proc(a: V2, b: V2): V2 { return {a.x - b.x, a.y - b.y}; }
V2_DivF :: proc(a: V2, b: f32): V2 { return {a.x / b, a.y / b}; }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,545 @@
R_CommandBufferSize :: 1024 * 1024;
R_Atlas :: struct {
bitmap : *u32;
sizei : V2I;
size : V2;
inverse_size : V2;
cursor : V2I;
biggest_height : i32;
white_texture_bounding_box : R2P;
texture_id : u32;
padding : V2I;
}
R_FontGlyph :: struct {
size : V2;
offset : V2;
x_advance : f32;
left_side_bearing : f32;
atlas_bounding_box : R2P;
}
R_Font :: struct {
atlas : *R_Atlas;
glyphs : [96]R_FontGlyph;
glyph_count : i32;
first_char : i32;
last_char : i32;
// This is for oversampling
// 0.5 = we draw the font as 2 times smaller then it is.
// Should lead to better quality result.
scaling_transform : f32;
// scaling transform is applied to these
size : f32;
ascent : f32;
descent : f32;
line_gap : f32;
// scaling factor not applied, not sure if these will be useful
scale : f32;
em_scale : f32;
white_texture_bounding_box : R2P;
}
R_Vertex2D :: struct {
pos : V2;
tex : V2;
color: V4;
}
R_CommandKind :: typedef int;
R_CommandKind_Null :: 0;
R_CommandKind_Triangle :: ^;
R_CommandKind_Triangle2D :: ^;
R_Command :: struct {
kind: R_CommandKind;
next: *R_Command;
out : *R_Vertex2D; // user write
data: *R_Vertex2D;
count: i32;
max_count: i32;
}
R_Shader :: struct {
pipeline: u32;
fragment: u32;
vertex : u32;
}
R_Render :: struct {
first_command2d: *R_Command;
last_command2d : *R_Command;
total_vertex_count: u64;
vbo: u32;
vao: u32;
shader2d: R_Shader;
atlas: R_Atlas;
font_medium: R_Font;
font: *R_Font;
}
R_Text2DDesc :: struct {
pos: V2;
text: S8_String;
color: V4;
scale: f32;
do_draw: bool;
rects_arena: *MA_Arena;
}
R_StringMeasure :: struct {
first_rect: *R_RectNode;
last_rect : *R_RectNode;
rect: R2P;
}
R_RectNode :: struct {
next: *R_RectNode;
rect: R2P;
utf8_codepoint_byte_size: i32;
}
R_PackType :: typedef int;
R_PackType_MonoColorFont :: 0;
R_PackType_RGBABitmap :: ^;
R_CreateAtlas :: proc(arena: *MA_Arena, size: V2I, padding: V2I): R_Atlas {
result: R_Atlas;
result.padding = padding;
result.sizei = size;
result.size = V2_FromV2I(size);
result.inverse_size.x = 1.0 / result.size.x;
result.inverse_size.y = 1.0 / result.size.y;
result.bitmap = MA_PushSize(arena, :usize(:i32(sizeof(:u32)) * size.x * size.y));
// Add a whitebox first for rectangle rendering
for y: i32 = 0; y < 16; y += 1 {
for x: i32 = 0; x < 16; x += 1 {
dst := &result.bitmap[x + y * result.sizei.x];
*dst = 0xffffffff;
}
}
// Skipping some pixels to avoid linear interpolation on edges
result.white_texture_bounding_box = :R2P{
{2.0 * result.inverse_size.x, 2.0 / result.size.y},
{14.0 * result.inverse_size.x, 14.0 / result.size.y},
};
result.cursor.x += 16 + padding.x;
result.biggest_height += 16 + padding.y;
return result;
}
R_PackBitmapInvertY :: proc(atlas: *R_Atlas, pack_type: R_PackType, bitmap: *u8, width: i32, height: i32): R2P {
// Packing into a texture atlas
// @Inefficient The algorithm is a simplest thing I had in mind, first we advance
// through the atlas in X packing consecutive glyphs. After we get to the end of the row
// we advance to the next row by the Y size of the biggest packed glyph. If we get to the
// end of atlas and fail to pack everything the app panics.
if (atlas.cursor.x + width > atlas.sizei.x) {
if (atlas.cursor.y + height < atlas.sizei.y) {
atlas.cursor.x = 0;
atlas.cursor.y += atlas.biggest_height + atlas.padding.y;
}
else {
IO_FatalErrorf("Error while packing a font into atlas. Atlas size for this font scale is a bit too small");
}
}
// Write the bitmap with inverted Y
src := bitmap;
// @todo: ambigious syntax, expression parsing doesn't stop at '{', error in wrong place
// for y := atlas.cursor.y + height - 1; y >= atlas.cursor.y; y++ {
for y := atlas.cursor.y + height - 1; y >= atlas.cursor.y; y -= 1 {
for x := atlas.cursor.x; x < atlas.cursor.x + width; x += 1 {
if (pack_type == R_PackType_RGBABitmap) {
atlas.bitmap[x + y * atlas.sizei.x] = *:*u32(src);
src = &src[4];
continue;
}
if (pack_type == R_PackType_MonoColorFont) {
dst := :*u8(&atlas.bitmap[x + y * atlas.sizei.x]);
dst[0] = 0xFF;
dst[1] = 0xFF;
dst[2] = 0xFF;
dst[3] = *src;
src = &src[1];
continue;
}
IO_InvalidCodepath();
}
}
size := :V2{:f32(width) * atlas.inverse_size.x, :f32(height) * atlas.inverse_size.y};
cursor := V2_FromV2I(atlas.cursor);
pos := V2_Mul(cursor, atlas.inverse_size);
result := R2P_Size(pos, size);
atlas.cursor.x += width + atlas.padding.x;
atlas.biggest_height = I32_Max(atlas.biggest_height, height);
return result;
}
Font_Create :: proc(atlas: *R_Atlas, size: f32, path: S8_String, oversampling: f32): R_Font {
scratch := MA_GetScratch();
font_file := OS_ReadFile(scratch.arena, path);
result: R_Font;
result.scaling_transform = 1.0 / oversampling;
result.size = oversampling * size;
result.first_char = ' ';
result.last_char = '~';
stb_font: stbtt_fontinfo;
if (font_file.len) {
success := stbtt_InitFont(&stb_font, :*uchar(font_file.str), 0);
if (success) {
ascent: int;
descent: int;
gap: int;
stbtt_GetFontVMetrics(&stb_font, &ascent, &descent, &gap);
result.scale = stbtt_ScaleForPixelHeight(&stb_font, result.size);
result.em_scale = stbtt_ScaleForMappingEmToPixels(&stb_font, result.size);
result.ascent = :f32(ascent) * result.scale;
result.descent = :f32(descent) * result.scale;
result.line_gap = :f32(gap) * result.scale;
result.white_texture_bounding_box = atlas.white_texture_bounding_box;
for ascii_symbol := result.first_char; ascii_symbol <= result.last_char; ascii_symbol+=1 {
width: int;
height: int;
xoff: int;
yoff: int;
bitmap := :*u8(stbtt_GetCodepointBitmap(&stb_font, 0, result.scale, :int(ascii_symbol), &width, &height, &xoff, &yoff));
x_advance: int;
left_side_bearing: int;
stbtt_GetCodepointHMetrics(&stb_font, :int(ascii_symbol), &x_advance, &left_side_bearing);
g := &result.glyphs[result.glyph_count];
result.glyph_count += 1;
g.atlas_bounding_box = R_PackBitmapInvertY(atlas, R_PackType_MonoColorFont, bitmap, :i32(width), :i32(height));
g.size = :V2{:f32(width), :f32(height)};
// Offset y needs to be inverted cause bitmap has inverted Y
g.offset = :V2{:f32(xoff), -(g.size.y + :f32(yoff))};
g.x_advance = :f32(x_advance) * result.scale;
g.left_side_bearing = :f32(left_side_bearing) * result.scale;
// Apply scaling transform
g.offset = V2_MulF(g.offset, result.scaling_transform);
g.x_advance = g.x_advance * result.scaling_transform;
g.left_side_bearing = g.left_side_bearing * result.scaling_transform;
g.size = V2_MulF(g.size, result.scaling_transform);
stbtt_FreeBitmap(:*uchar(bitmap), nil);
}
result.ascent *= result.scaling_transform;
result.descent *= result.scaling_transform;
result.size *= result.scaling_transform;
result.line_gap *= result.scaling_transform;
}
}
MA_EndTemp(scratch);
return result;
}
Font_GetGlyph :: proc(font: *R_Font, codepoint: i32): *R_FontGlyph {
is_in_range := codepoint >= font.first_char && codepoint <= font.last_char;
if (is_in_range) {
index := codepoint - font.first_char;
return &font.glyphs[index];
}
else {
index := '?' - font.first_char;
return &font.glyphs[index];
}
}
GL_DebugCallback :: proc(source: GLenum @unused, type: GLenum @unused, id: GLuint @unused, severity: GLenum, length: GLsizei @unused, message: *GLchar, user: *void @unused) {
IO_Printf("%s\n", message);
if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM) {
IO_FatalErrorf("%s", message);
}
}
GL_SetProcAddress :: proc(p: *void, name: *char) {
pp := :**void(p);
*pp = Mu.gl_get_proc_address(name);
}
GL_LoadProcs :: proc() {
load_up_to(4, 5, :*void(GL_SetProcAddress));
glDebugMessageCallback(:*void(GL_DebugCallback), nil);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
}
R_Reload :: proc() {
GL_LoadProcs();
}
R_Init :: proc(render: *R_Render) {
R = render;
GL_LoadProcs();
atlas := R_CreateAtlas(Temp, :V2I{1024, 1024}, :V2I{4, 4});
R.font_medium = Font_Create(&atlas, 32, S8_Lit("C:/windows/fonts/Calibri.ttf"), 1.0);
{
glCreateTextures(GL_TEXTURE_2D, 1, &atlas.texture_id);
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureStorage2D(atlas.texture_id, 1, GL_RGBA8, :i32(atlas.sizei.x), :i32(atlas.sizei.y));
glTextureSubImage2D(atlas.texture_id, 0, 0, 0, :i32(atlas.sizei.x), :i32(atlas.sizei.y), GL_RGBA, GL_UNSIGNED_BYTE, atlas.bitmap);
}
R.atlas = atlas;
R.font_medium.atlas = &R.atlas;
R.font = &R.font_medium;
glCreateBuffers(1, &R.vbo);
glNamedBufferStorage(R.vbo, R_CommandBufferSize, nil, GL_DYNAMIC_STORAGE_BIT);
{
glCreateVertexArrays(1, &R.vao);
vbuf_index: u32 = 0;
glVertexArrayVertexBuffer(R.vao, vbuf_index, R.vbo, 0, :i32(sizeof(:R_Vertex2D)));
a_pos: u32 = 0;
pos_offset: u32 = #`offsetof(R_Vertex2D, pos)`;
glVertexArrayAttribFormat(R.vao, a_pos, 2, GL_FLOAT, GL_FALSE, pos_offset);
glVertexArrayAttribBinding(R.vao, a_pos, vbuf_index);
glEnableVertexArrayAttrib(R.vao, a_pos);
a_tex: u32 = 1;
tex_offset: u32 = #`offsetof(R_Vertex2D, tex)`;
glVertexArrayAttribFormat(R.vao, a_tex, 2, GL_FLOAT, GL_FALSE, tex_offset);
glVertexArrayAttribBinding(R.vao, a_tex, vbuf_index);
glEnableVertexArrayAttrib(R.vao, a_tex);
a_color: u32 = 2;
color_offset: u32 = #`offsetof(R_Vertex2D, color)`; // @todo
glVertexArrayAttribFormat(R.vao, a_color, 4, GL_FLOAT, GL_FALSE, color_offset);
glVertexArrayAttribBinding(R.vao, a_color, vbuf_index);
glEnableVertexArrayAttrib(R.vao, a_color);
}
vshader := `#version 450 core
layout(location=0) uniform vec2 U_InvHalfScreenSize;
layout(location=0) in vec2 IN_Pos;
layout(location=1) in vec2 IN_Tex;
layout(location=2) in vec4 IN_Color;
out gl_PerVertex { vec4 gl_Position; }; // required because of ARB_separate_shader_objects
out vec2 OUT_UV;
out vec4 OUT_Color;
void main() {
vec2 pos = IN_Pos * U_InvHalfScreenSize;
pos -= vec2(1, 1);
gl_Position = vec4(pos, 0, 1);
OUT_UV = IN_Tex;
OUT_Color = IN_Color;
}
`;
fshader := `#version 450 core
in vec2 IN_UV;
in vec4 IN_Color;
layout (binding=0) uniform sampler2D S_Texture;
layout (location=0) out vec4 OUT_Color;
void main() {
vec4 c = IN_Color;
vec4 texture_color = texture(S_Texture, IN_UV);
OUT_Color = c * texture_color;
}
`;
R.shader2d = R_CreateShader(vshader, fshader);
}
R_CreateShader :: proc(glsl_vshader: *char, glsl_fshader: *char): R_Shader {
result: R_Shader;
result.vertex = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vshader);
result.fragment = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fshader);
linked: i32;
glGetProgramiv(result.vertex, GL_LINK_STATUS, &linked);
if (!linked) {
message: [1024]char;
glGetProgramInfoLog(result.vertex, :i32(sizeof(message)), nil, :*u8(&message[0]));
IO_FatalErrorf("[GL] Failed to create vertex shader! %s", message);
}
glGetProgramiv(result.fragment, GL_LINK_STATUS, &linked);
if (!linked) {
message: [1024]char;
glGetProgramInfoLog(result.fragment, :i32(sizeof(message)), nil, :*u8(&message[0]));
IO_FatalErrorf("[GL] Failed to create fragment shader! %s", message);
}
glGenProgramPipelines(1, &result.pipeline);
glUseProgramStages(result.pipeline, GL_VERTEX_SHADER_BIT, result.vertex);
glUseProgramStages(result.pipeline, GL_FRAGMENT_SHADER_BIT, result.fragment);
return result;
}
R_GetCommand :: proc(kind: R_CommandKind, vcount_to_add: i32): *R_Command {
make_new := R.last_command2d == 0 ||
R.last_command2d.kind != kind ||
R.last_command2d.count + vcount_to_add > R.last_command2d.max_count;
if make_new {
sizeof_r_command: usize = #`sizeof(R_Command)`;
c: *R_Command = MA_PushSize(Temp, sizeof_r_command);
c.kind = kind;
c.data = MA_PushSizeNonZeroed(Temp, R_CommandBufferSize);
if (kind == R_CommandKind_Triangle2D) {
c.max_count = R_CommandBufferSize / :i32(sizeof(:R_Vertex2D));
SLL_QUEUE_ADD(R.first_command2d, R.last_command2d, c);
}
else IO_InvalidCodepath();
}
c := R.last_command2d;
c.out = &c.data[c.count];
c.count += vcount_to_add;
R.total_vertex_count += :u64(vcount_to_add);
return c;
}
R_Rect2D :: proc(rect: R2P, tex: R2P, color: V4) {
c := R_GetCommand(R_CommandKind_Triangle2D, 6);
c.out[0].pos = :V2{rect.min.x, rect.max.y};
c.out[0].tex = :V2{tex.min.x, tex.max.y};
c.out[0].color = color;
c.out[1].pos = :V2{rect.max.x, rect.max.y};
c.out[1].tex = :V2{tex.max.x, tex.max.y};
c.out[1].color = color;
c.out[2].pos = :V2{rect.min.x, rect.min.y};
c.out[2].tex = :V2{tex.min.x, tex.min.y};
c.out[2].color = color;
c.out[3].pos = :V2{rect.min.x, rect.min.y};
c.out[3].tex = :V2{tex.min.x, tex.min.y};
c.out[3].color = color;
c.out[4].pos = :V2{rect.max.x, rect.max.y};
c.out[4].tex = :V2{tex.max.x, tex.max.y};
c.out[4].color = color;
c.out[5].pos = :V2{rect.max.x, rect.min.y};
c.out[5].tex = :V2{tex.max.x, tex.min.y};
c.out[5].color = color;
}
R_Text2D :: proc(params: R_Text2DDesc): R_StringMeasure {
result: R_StringMeasure;
original_pos := params.pos;
max_pos := params.pos;
pos := params.pos;
scale := params.scale;
for iter := UTF8_IterateEx(params.text.str, :int(params.text.len)); iter.item /*;UTF8_Advance(&iter)@todo*/ {
it: u32 = iter.item;
if it == '\n' {
pos.x = original_pos.x;
pos.y -= R.font.size * scale;
if (pos.x > max_pos.x) max_pos.x = pos.x;
if (pos.y < max_pos.y) max_pos.y = pos.y; // @warning: min position y actually
continue;
}
g: *R_FontGlyph = Font_GetGlyph(R.font, :i32(it));
sym_pos := pos;
pos.x += g.x_advance * scale;
if (pos.x > max_pos.x) max_pos.x = pos.x;
if (pos.y < max_pos.y) max_pos.y = pos.y; // @warning: min position y actually
sym_pos.x += g.offset.x * scale;
sym_pos.y += g.offset.y * scale;
minp: V2 = {sym_pos.x, sym_pos.y};
rect: R2P = R2P_Size(minp, V2_MulF(g.size, scale));
if (params.do_draw) {
R_Rect2D(rect, g.atlas_bounding_box, params.color);
}
if (params.rects_arena) {
node: *R_RectNode = MA_PushSize(params.rects_arena, :usize(sizeof(:R_RectNode)));
node.rect = rect;
node.utf8_codepoint_byte_size = :i32(iter.utf8_codepoint_byte_size);
SLL_QUEUE_ADD(result.first_rect, result.last_rect, node);
}
UTF8_Advance(&iter); // @todo
}
result.rect = {
{original_pos.x, max_pos.y + R.font.descent * scale}, /* @warning: min position y actually */
{max_pos.x, original_pos.y + R.font.ascent * scale},
};
return result;
}
R_GetTextSize :: proc(text: S8_String): f32 {
m := R_Text2D({text = text, scale = 1.0});
size := R2P_GetSize(m.rect).x;
return size;
}
R_ColorWhite: V4 = {1,1,1,1};
R_ColorBlack: V4 = {0,0,0,1};
R_DrawText :: proc(text: S8_String, pos: V2, color: V4): R_StringMeasure {
result := R_Text2D({text = text, color = color, pos = pos, do_draw = true, scale = 1.0});
return result;
}
R_EndFrame :: proc() {
ws := :V2{:f32(Mu.window.size.x), :f32(Mu.window.size.y)};
wsi := :V2I{:i32(Mu.window.size.x), :i32(Mu.window.size.y)};
x: f32 = 1 / (ws.x / 2);
y: f32 = 1 / (ws.y / 2);
glViewport(0, 0, wsi.x, wsi.y);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
// Default draw using the font texture
{
glBindProgramPipeline(R.shader2d.pipeline);
glProgramUniform2f(R.shader2d.vertex, 0, x, y);
for it := R.first_command2d; it; it = it.next {
if (it.kind == R_CommandKind_Triangle2D) {
glNamedBufferSubData(R.vbo, 0, :int(it.count) * :int(sizeof(:R_Vertex2D)), it.data);
glBindVertexArray(R.vao);
s_texture: u32 = 0; // texture unit that sampler2D will use in GLSL code
glBindTextureUnit(s_texture, R.font.atlas.texture_id);
glDrawArrays(GL_TRIANGLES, 0, it.count);
continue;
}
IO_InvalidCodepath();
}
}
R.first_command2d = nil;
R.last_command2d = nil;
R.total_vertex_count = 0;
}

View File

@@ -0,0 +1,183 @@
#`#include "vendor/stb_truetype.c"`;
@foreign stbrp_rect :: struct {f: int;}
@foreign
stbtt__buf :: struct {
data: *uchar;
cursor: int;
size: int;
}
@foreign
stbtt_bakedchar :: struct {
x0: ushort;
y0: ushort;
x1: ushort;
y1: ushort;
xoff: float;
yoff: float;
xadvance: float;
}
@foreign stbtt_BakeFontBitmap :: proc(data: *uchar, offset: int, pixel_height: float, pixels: *uchar, pw: int, ph: int, first_char: int, num_chars: int, chardata: *stbtt_bakedchar): int;
@foreign
stbtt_aligned_quad :: struct {
x0: float;
y0: float;
s0: float;
t0: float;
x1: float;
y1: float;
s1: float;
t1: float;
}
@foreign stbtt_GetBakedQuad :: proc(chardata: *stbtt_bakedchar, pw: int, ph: int, char_index: int, xpos: *float, ypos: *float, q: *stbtt_aligned_quad, opengl_fillrule: int);
@foreign stbtt_GetScaledFontVMetrics :: proc(fontdata: *uchar, index: int, size: float, ascent: *float, descent: *float, lineGap: *float);
@foreign
stbtt_packedchar :: struct {
x0: ushort;
y0: ushort;
x1: ushort;
y1: ushort;
xoff: float;
yoff: float;
xadvance: float;
xoff2: float;
yoff2: float;
}
@foreign stbtt_PackBegin :: proc(spc: *stbtt_pack_context, pixels: *uchar, width: int, height: int, stride_in_bytes: int, padding: int, alloc_context: *void): int;
@foreign stbtt_PackEnd :: proc(spc: *stbtt_pack_context);
@foreign stbtt_PackFontRange :: proc(spc: *stbtt_pack_context, fontdata: *uchar, font_index: int, font_size: float, first_unicode_char_in_range: int, num_chars_in_range: int, chardata_for_range: *stbtt_packedchar): int;
@foreign
stbtt_pack_range :: struct {
font_size: float;
first_unicode_codepoint_in_range: int;
array_of_unicode_codepoints: *int;
num_chars: int;
chardata_for_range: *stbtt_packedchar;
h_oversample: uchar;
v_oversample: uchar;
}
@foreign stbtt_PackFontRanges :: proc(spc: *stbtt_pack_context, fontdata: *uchar, font_index: int, ranges: *stbtt_pack_range, num_ranges: int): int;
@foreign stbtt_PackSetOversampling :: proc(spc: *stbtt_pack_context, h_oversample: uint, v_oversample: uint);
@foreign stbtt_PackSetSkipMissingCodepoints :: proc(spc: *stbtt_pack_context, skip: int);
@foreign stbtt_GetPackedQuad :: proc(chardata: *stbtt_packedchar, pw: int, ph: int, char_index: int, xpos: *float, ypos: *float, q: *stbtt_aligned_quad, align_to_integer: int);
@foreign stbtt_PackFontRangesGatherRects :: proc(spc: *stbtt_pack_context, info: *stbtt_fontinfo, ranges: *stbtt_pack_range, num_ranges: int, rects: *stbrp_rect): int;
@foreign stbtt_PackFontRangesPackRects :: proc(spc: *stbtt_pack_context, rects: *stbrp_rect, num_rects: int);
@foreign stbtt_PackFontRangesRenderIntoRects :: proc(spc: *stbtt_pack_context, info: *stbtt_fontinfo, ranges: *stbtt_pack_range, num_ranges: int, rects: *stbrp_rect): int;
@foreign
stbtt_pack_context :: struct {
user_allocator_context: *void;
pack_info: *void;
width: int;
height: int;
stride_in_bytes: int;
padding: int;
skip_missing: int;
h_oversample: uint;
v_oversample: uint;
pixels: *uchar;
nodes: *void;
}
@foreign stbtt_GetNumberOfFonts :: proc(data: *uchar): int;
@foreign stbtt_GetFontOffsetForIndex :: proc(data: *uchar, index: int): int;
@foreign
stbtt_fontinfo :: struct {
userdata: *void;
data: *uchar;
fontstart: int;
numGlyphs: int;
loca: int;
head: int;
glyf: int;
hhea: int;
hmtx: int;
kern: int;
gpos: int;
svg: int;
index_map: int;
indexToLocFormat: int;
cff: stbtt__buf;
charstrings: stbtt__buf;
gsubrs: stbtt__buf;
subrs: stbtt__buf;
fontdicts: stbtt__buf;
fdselect: stbtt__buf;
}
@foreign stbtt_InitFont :: proc(info: *stbtt_fontinfo, data: *uchar, offset: int): int;
@foreign stbtt_FindGlyphIndex :: proc(info: *stbtt_fontinfo, unicode_codepoint: int): int;
@foreign stbtt_ScaleForPixelHeight :: proc(info: *stbtt_fontinfo, pixels: float): float;
@foreign stbtt_ScaleForMappingEmToPixels :: proc(info: *stbtt_fontinfo, pixels: float): float;
@foreign stbtt_GetFontVMetrics :: proc(info: *stbtt_fontinfo, ascent: *int, descent: *int, lineGap: *int);
@foreign stbtt_GetFontVMetricsOS2 :: proc(info: *stbtt_fontinfo, typoAscent: *int, typoDescent: *int, typoLineGap: *int): int;
@foreign stbtt_GetFontBoundingBox :: proc(info: *stbtt_fontinfo, x0: *int, y0: *int, x1: *int, y1: *int);
@foreign stbtt_GetCodepointHMetrics :: proc(info: *stbtt_fontinfo, codepoint: int, advanceWidth: *int, leftSideBearing: *int);
@foreign stbtt_GetCodepointKernAdvance :: proc(info: *stbtt_fontinfo, ch1: int, ch2: int): int;
@foreign stbtt_GetCodepointBox :: proc(info: *stbtt_fontinfo, codepoint: int, x0: *int, y0: *int, x1: *int, y1: *int): int;
@foreign stbtt_GetGlyphHMetrics :: proc(info: *stbtt_fontinfo, glyph_index: int, advanceWidth: *int, leftSideBearing: *int);
@foreign stbtt_GetGlyphKernAdvance :: proc(info: *stbtt_fontinfo, glyph1: int, glyph2: int): int;
@foreign stbtt_GetGlyphBox :: proc(info: *stbtt_fontinfo, glyph_index: int, x0: *int, y0: *int, x1: *int, y1: *int): int;
@foreign
stbtt_kerningentry :: struct {
glyph1: int;
glyph2: int;
advance: int;
}
@foreign stbtt_GetKerningTableLength :: proc(info: *stbtt_fontinfo): int;
@foreign stbtt_GetKerningTable :: proc(info: *stbtt_fontinfo, table: *stbtt_kerningentry, table_length: int): int;
@foreign
stbtt_vertex :: struct {
x: short;
y: short;
cx: short;
cy: short;
cx1: short;
cy1: short;
type: uchar;
padding: uchar;
}
@foreign stbtt_IsGlyphEmpty :: proc(info: *stbtt_fontinfo, glyph_index: int): int;
@foreign stbtt_GetCodepointShape :: proc(info: *stbtt_fontinfo, unicode_codepoint: int, vertices: **stbtt_vertex): int;
@foreign stbtt_GetGlyphShape :: proc(info: *stbtt_fontinfo, glyph_index: int, vertices: **stbtt_vertex): int;
@foreign stbtt_FreeShape :: proc(info: *stbtt_fontinfo, vertices: *stbtt_vertex);
@foreign stbtt_FindSVGDoc :: proc(info: *stbtt_fontinfo, gl: int): *uchar;
@foreign stbtt_GetCodepointSVG :: proc(info: *stbtt_fontinfo, unicode_codepoint: int, svg: **char): int;
@foreign stbtt_GetGlyphSVG :: proc(info: *stbtt_fontinfo, gl: int, svg: **char): int;
@foreign stbtt_FreeBitmap :: proc(bitmap: *uchar, userdata: *void);
@foreign stbtt_GetCodepointBitmap :: proc(info: *stbtt_fontinfo, scale_x: float, scale_y: float, codepoint: int, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
@foreign stbtt_GetCodepointBitmapSubpixel :: proc(info: *stbtt_fontinfo, scale_x: float, scale_y: float, shift_x: float, shift_y: float, codepoint: int, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
@foreign stbtt_MakeCodepointBitmap :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, codepoint: int);
@foreign stbtt_MakeCodepointBitmapSubpixel :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, codepoint: int);
@foreign stbtt_MakeCodepointBitmapSubpixelPrefilter :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, oversample_x: int, oversample_y: int, sub_x: *float, sub_y: *float, codepoint: int);
@foreign stbtt_GetCodepointBitmapBox :: proc(font: *stbtt_fontinfo, codepoint: int, scale_x: float, scale_y: float, ix0: *int, iy0: *int, ix1: *int, iy1: *int);
@foreign stbtt_GetCodepointBitmapBoxSubpixel :: proc(font: *stbtt_fontinfo, codepoint: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, ix0: *int, iy0: *int, ix1: *int, iy1: *int);
@foreign stbtt_GetGlyphBitmap :: proc(info: *stbtt_fontinfo, scale_x: float, scale_y: float, glyph: int, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
@foreign stbtt_GetGlyphBitmapSubpixel :: proc(info: *stbtt_fontinfo, scale_x: float, scale_y: float, shift_x: float, shift_y: float, glyph: int, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
@foreign stbtt_MakeGlyphBitmap :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, glyph: int);
@foreign stbtt_MakeGlyphBitmapSubpixel :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, glyph: int);
@foreign stbtt_MakeGlyphBitmapSubpixelPrefilter :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, oversample_x: int, oversample_y: int, sub_x: *float, sub_y: *float, glyph: int);
@foreign stbtt_GetGlyphBitmapBox :: proc(font: *stbtt_fontinfo, glyph: int, scale_x: float, scale_y: float, ix0: *int, iy0: *int, ix1: *int, iy1: *int);
@foreign stbtt_GetGlyphBitmapBoxSubpixel :: proc(font: *stbtt_fontinfo, glyph: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, ix0: *int, iy0: *int, ix1: *int, iy1: *int);
@foreign
stbtt__bitmap :: struct {
w: int;
h: int;
stride: int;
pixels: *uchar;
}
@foreign stbtt_Rasterize :: proc(result: *stbtt__bitmap, flatness_in_pixels: float, vertices: *stbtt_vertex, num_verts: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, x_off: int, y_off: int, invert: int, userdata: *void);
@foreign stbtt_FreeSDF :: proc(bitmap: *uchar, userdata: *void);
@foreign stbtt_GetGlyphSDF :: proc(info: *stbtt_fontinfo, scale: float, glyph: int, padding: int, onedge_value: uchar, pixel_dist_scale: float, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
@foreign stbtt_GetCodepointSDF :: proc(info: *stbtt_fontinfo, scale: float, codepoint: int, padding: int, onedge_value: uchar, pixel_dist_scale: float, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
@foreign stbtt_FindMatchingFont :: proc(fontdata: *uchar, name: *char, flags: int): int;
@foreign stbtt_CompareUTF8toUTF16_bigendian :: proc(s1: *char, len1: int, s2: *char, len2: int): int;
@foreign stbtt_GetFontNameString :: proc(font: *stbtt_fontinfo, length: *int, platformID: int, encodingID: int, languageID: int, nameID: int): *char;

View File

@@ -0,0 +1,342 @@
Ui: UI_State;
UI_TextAlign :: typedef int;
UI_TextAlign_Center :: 0;
UI_TextAlign_CenterLeft :: ^;
UI_Layout :: struct {
rect: R2P;
}
UI_Widget :: struct {
next: *UI_Widget;
id: u64;
last_touched_frame_index: u64;
}
UI_Cut :: typedef int;
UI_Cut_Left :: 0;
UI_Cut_Right :: ^;
UI_Cut_Top :: ^;
UI_Cut_Bottom :: ^;
UI_Style :: struct {
cut_size: V2;
text_align: UI_TextAlign;
scroll: V2;
absolute: bool;
absolute_rect: R2P;
button_background_color: V4;
hot_button_background_color: V4;
interacting_with_button_background_color: V4;
active_button_background_color: V4;
text_color: V4;
button_border_color: V4;
checked_checkbox_button_background_color: V4;
draw_text_shadow: bool;
}
UI_BaseButtonDesc :: struct {
text: S8_String;
draw_text: bool;
draw_border: bool;
draw_background: bool;
use_checked_checkbox_button_background_colors: bool;
}
UI_Result :: struct {
pressed: bool;
interacting_with: bool;
hot: bool;
drag: V2;
}
UI_LayoutStack :: struct {
data: [256]UI_Layout;
len : i32;
}
UI_State :: struct {
cut: UI_Cut;
s: UI_Style; // current style
base_style: UI_Style;
// @todo: add stack id concept
cached_widgets: LC_Map; // @todo: add removing widgets at end of frame
layouts: UI_LayoutStack;
font: *R_Font;
hot: u64;
interacting_with: u64;
id: u64;
inside_begin_end_pair: bool;
// next cut output
text_width: f32;
text_size: V2;
}
UI_AddLayout :: proc(s: *UI_LayoutStack, layout: UI_Layout) {
if s.len + 1 > lengthof(s.data) {
IO_FatalErrorf("layout stack overflow reached max item count: %d", lengthof(s.data));
}
s.data[s.len] = layout;
s.len += 1;
}
UI_GetLastLayout :: proc(s: *UI_LayoutStack): *UI_Layout {
if (s.len == 0) IO_FatalErrorf("error, trying to get last layout but there are none");
return &s.data[s.len - 1];
}
UI_Begin :: proc() {
IO_Assert(Ui.inside_begin_end_pair == false);
Ui.inside_begin_end_pair = true;
IO_Assert(Ui.layouts.len == 0 || Ui.layouts.len == 1);
Ui.layouts.len = 0;
UI_AddLayout(&Ui.layouts, {R2P_SizeF(0, 0, :f32(Mu.window.size.x), :f32(Mu.window.size.y))});
UI_SetStyle();
}
UI_SetStyle :: proc() {
Ui.font = R.font;
Ui.base_style = {
cut_size = :V2{-1, Ui.font.size + 4},
button_background_color = :V4{0, 0, 0, 1.0},
text_color = :V4{1, 1, 1, 1},
button_border_color = :V4{1, 1, 1, 1},
checked_checkbox_button_background_color = :V4{0.5, 0.5, 0.5, 1.0},
hot_button_background_color = :V4{0.5, 0, 0, 1},
interacting_with_button_background_color = :V4{1.0, 0, 0, 1},
active_button_background_color = :V4{1, 0, 0, 1},
};
Ui.s = Ui.base_style;
}
UI_End :: proc() {
IO_Assert(Ui.inside_begin_end_pair);
Ui.inside_begin_end_pair = false;
if (Mu.window.mouse.left.unpress) {
Ui.interacting_with = NULL;
}
Ui.hot = NULL;
}
R_DrawBorder :: proc(r: R2P, color: V4) {
r = R2P_Shrink(r, 1);
R_Rect2D(R2P_CutLeft(&r, 1), R.atlas.white_texture_bounding_box, color);
R_Rect2D(R2P_CutRight(&r, 1), R.atlas.white_texture_bounding_box, color);
R_Rect2D(R2P_CutTop(&r, 1), R.atlas.white_texture_bounding_box, color);
R_Rect2D(R2P_CutBottom(&r, 1), R.atlas.white_texture_bounding_box, color);
}
UI_GetNextRect :: proc(text: S8_String): R2P {
if (Ui.s.absolute) return Ui.s.absolute_rect;
l := UI_GetLastLayout(&Ui.layouts);
cut := Ui.s.cut_size;
font := Ui.font;
if (text.len) {
Ui.text_width = R_GetTextSize(text);
Ui.text_size = :V2{Ui.text_width, font.ascent};
}
if (cut.x < 0) {
cut.x = Ui.text_width + 32;
if (cut.x < 0) {
cut.x = 32;
}
}
if (cut.y < 0) {
cut.y = font.ascent;
}
if (Ui.cut == UI_Cut_Top || Ui.cut == UI_Cut_Bottom) {
scroll_y := F32_Clamp(Ui.s.scroll.y, -cut.y, cut.y);
cut.y -= scroll_y;
Ui.s.scroll.y -= scroll_y;
}
if (Ui.cut == UI_Cut_Left || Ui.cut == UI_Cut_Right) {
scrollx := F32_Clamp(Ui.s.scroll.x, -cut.x, cut.x);
cut.x -= scrollx;
Ui.s.scroll.x -= scrollx;
}
if (Ui.cut == UI_Cut_Left) {
return R2P_CutLeft(&l.rect, cut.x);
}
if (Ui.cut == UI_Cut_Right) {
return R2P_CutRight(&l.rect, cut.x);
}
if (Ui.cut == UI_Cut_Top) {
return R2P_CutTop(&l.rect, cut.y);
}
if (Ui.cut == UI_Cut_Bottom) {
return R2P_CutBottom(&l.rect, cut.y);
}
IO_InvalidCodepath();
return :R2P{};
}
UI_GetWidget :: proc(text: S8_String): *UI_Widget {
if (Ui.cached_widgets.allocator.p == NULL) {
Ui.cached_widgets.allocator = Perm.allocator;
}
hash := HashBytes(text.str, :u64(text.len));
widget: *UI_Widget = LC_MapGetU64(&Ui.cached_widgets, hash);
if (!widget) {
widget = MA_PushSize(Perm, :usize(sizeof(:UI_Widget)));
widget.id = hash;
LC_MapInsertU64(&Ui.cached_widgets, hash, widget);
}
IO_Assert(widget.id == hash);
widget.last_touched_frame_index = :u64(Mu.frame);
return widget;
}
UI_BaseButton :: proc(desc: UI_BaseButtonDesc): UI_Result {
result: UI_Result;
rect := UI_GetNextRect(desc.text);
mouse_pos: V2 = {:f32(Mu.window.mouse.pos.x), :f32(Mu.window.mouse.pos.y)};
delta_mouse_pos: V2 = {:f32(Mu.window.mouse.delta_pos.x), :f32(Mu.window.mouse.delta_pos.y)};
if (rect.min.x == rect.max.x || rect.min.y == rect.max.y) {
return result;
}
widget := UI_GetWidget(desc.text);
if (R2P_CollidesV2(rect, mouse_pos)) {
Ui.hot = widget.id;
}
if (Ui.hot == widget.id) {
result.hot = true;
if (Mu.window.mouse.left.press) {
Ui.interacting_with = widget.id;
}
}
if (Ui.interacting_with == widget.id) {
result.interacting_with = true;
result.drag = delta_mouse_pos;
if (Ui.hot == widget.id && Mu.window.mouse.left.unpress) {
result.pressed = true;
}
}
text_pos := rect.min;
rect_size := R2P_GetSize(rect);
centered_text_pos := V2_Add(text_pos, V2_DivF(V2_Sub(rect_size, Ui.text_size), 2.0));
if (Ui.s.text_align == UI_TextAlign_Center) {
text_pos = centered_text_pos;
}
if (Ui.s.text_align == UI_TextAlign_CenterLeft) {
text_pos.y = centered_text_pos.y;
text_pos.x += 4;
}
button_background_color: V4 = Ui.s.button_background_color;
text_color: V4 = Ui.s.text_color;
button_border_color: V4 = Ui.s.button_border_color;
if (desc.use_checked_checkbox_button_background_colors) {
button_background_color = Ui.s.checked_checkbox_button_background_color;
}
if (Ui.hot == widget.id) {
button_background_color = Ui.s.hot_button_background_color;
}
if (Ui.interacting_with == widget.id) {
button_background_color = Ui.s.interacting_with_button_background_color;
}
if (result.pressed) {
button_background_color = Ui.s.active_button_background_color;
}
if (desc.draw_background) {
R_Rect2D(rect, R.atlas.white_texture_bounding_box, button_background_color);
}
if (desc.draw_border) {
R_DrawBorder(rect, button_border_color);
}
if (desc.draw_text) {
if (Ui.s.draw_text_shadow) {
R_Text2D({
text = desc.text,
color = R_ColorWhite,
pos = :V2{text_pos.x + 2, text_pos.y - 2},
do_draw = true,
scale = 1.0,
});
}
R_DrawText(desc.text, text_pos, text_color);
}
return result;
}
UI_Button :: proc(str: *char): bool {
result := UI_BaseButton({
text = S8_MakeFromChar(str),
draw_text = true,
draw_border = true,
draw_background = true,
});
return result.pressed;
}
UI_Checkbox :: proc(val: *bool, str: *char): bool {
result: UI_Result = UI_BaseButton({
text = S8_MakeFromChar(str),
draw_text = true,
draw_border = true,
draw_background = true,
use_checked_checkbox_button_background_colors = *val,
});
if (result.pressed) {
*val = !*val;
}
return *val;
}
UI_Fill :: proc() {
rect := UI_GetNextRect(S8_MakeEmpty());
R_Rect2D(rect, R.atlas.white_texture_bounding_box, Ui.s.button_background_color);
R_DrawBorder(rect, Ui.s.button_border_color);
}
UI_PopStyle :: proc() {
Ui.s = Ui.base_style;
}
UI_PopLayout :: proc() {
if Ui.layouts.len == 0 {
IO_FatalError("tryign to pop a layout but layout stack is empty");
}
Ui.layouts.len -= 1;
}
UI_PushLayout :: proc(rect_override: R2P): R2P {
rect: R2P;
if (rect_override.min.x != 0 || rect_override.min.y != 0 || rect_override.max.x != 0 || rect_override.max.y != 0) {
rect = rect_override;
}
else {
rect = UI_GetNextRect(S8_MakeEmpty());
}
UI_AddLayout(&Ui.layouts, {rect});
return rect;
}

View File

@@ -0,0 +1,89 @@
import "shared";
Mu: *MU_Context;
TempArena: MA_Arena;
Temp := &TempArena;
@foreign RandomSeed :: struct { a: u64; }
@foreign GetRandomU64 :: proc(state: *RandomSeed): u64;
LibraryHotLoad :: struct {
reload_count: int;
user_context: DLL_Context;
library: LIB_Library;
update_proc: LibraryUpdate;
last_write_time: i64;
seed: RandomSeed;
init_happened_on_this_frame: bool;
}
ReloadUpdate :: proc(lib: *LibraryHotLoad) {
new_write_time := OS_GetFileModTime(S8_MakeFromChar("game.dll"));
if new_write_time == -1 || new_write_time == lib.last_write_time {
return;
}
if lib.update_proc {
lib.update_proc(Unload, Mu, &lib.user_context);
lib.update_proc = nil;
}
if (lib.seed.a == 0) lib.seed.a = 13;
random_value := GetRandomU64(&lib.seed);
out_filename_dll := S8_Format(Temp, "temp_%u.dll", random_value);
out_filename_pdb := S8_Format(Temp, "temp_%u.pdb", random_value);
OS_CopyFile(S8_MakeFromChar("game.dll"), out_filename_dll, true);
OS_CopyFile(S8_MakeFromChar("game.pdb"), out_filename_pdb, true);
library := LIB_LoadLibrary(out_filename_dll.str);
if !library {
IO_Printf("Failed to load library %Q\n", out_filename_dll);
return;
}
update_proc: LibraryUpdate = LIB_LoadSymbol(library, "APP_Update");
if !library {
IO_Printf("Failed to load library %Q\n", out_filename_dll);
return;
}
lib.library = library;
lib.update_proc = update_proc;
lib.last_write_time = new_write_time;
if lib.reload_count == 0 {
lib.update_proc(Init, Mu, &lib.user_context);
lib.init_happened_on_this_frame = true;
}
else {
lib.update_proc(Reload, Mu, &lib.user_context);
}
lib.reload_count += 1;
}
CallUpdate :: proc(lib: *LibraryHotLoad) {
ReloadUpdate(lib);
if lib.update_proc && !lib.init_happened_on_this_frame {
lib.update_proc(Update, Mu, &lib.user_context);
}
lib.init_happened_on_this_frame = false;
}
main :: proc(): int {
Mu = MU_Start({
enable_opengl = true,
window = {
size = {1280, 720}
},
delta_time = 0.0166666
});
lib: LibraryHotLoad = {user_context = {temp = Temp}};
for MU_Update(Mu) {
CallUpdate(&lib);
if (Mu.window.key[MU_KEY_ESCAPE].down) {
MU_Quit(Mu);
}
}
return 0;
}

View File

@@ -0,0 +1,557 @@
#`
#include "core/core.c"
#include "core/map.c"
`;
@foreign
UTF32_Result :: struct {
out_str: u32;
advance: int;
error: int;
}
@foreign
UTF8_Result :: struct {
out_str: [4]u8;
len: int;
error: int;
}
@foreign
UTF16_Result :: struct {
out_str: [2]u16;
len: int;
error: int;
}
@foreign
UTF8_Iter :: struct {
str: *char;
len: int;
utf8_codepoint_byte_size: int;
i: int;
item: u32;
}
@foreign UTF_ConvertUTF16ToUTF32 :: proc(c: *u16, max_advance: int): UTF32_Result;
@foreign UTF_ConvertUTF32ToUTF8 :: proc(codepoint: u32): UTF8_Result;
@foreign UTF_ConvertUTF8ToUTF32 :: proc(c: *char, max_advance: int): UTF32_Result;
@foreign UTF_ConvertUTF32ToUTF16 :: proc(codepoint: u32): UTF16_Result;
@foreign UTF_CreateCharFromWidechar :: proc(buffer: *char, buffer_size: i64, in: *wchar_t, inlen: i64): i64;
@foreign UTF_CreateWidecharFromChar :: proc(buffer: *wchar_t, buffer_size: i64, in: *char, inlen: i64): i64;
@foreign UTF8_Advance :: proc(iter: *UTF8_Iter);
@foreign UTF8_IterateEx :: proc(str: *char, len: int): UTF8_Iter;
@foreign UTF8_Iterate :: proc(str: *char): UTF8_Iter;
@foreign UTF_CreateStringFromWidechar :: proc(arena: *MA_Arena, wstr: *wchar_t, wsize: i64): S8_String;
@foreign
IO_ErrorResult :: typedef int;
IO_ErrorResult_Continue :: 0;
IO_ErrorResult_Break :: ^;
IO_ErrorResult_Exit :: ^;
@foreign IO_Printf :: proc(msg: *char, ...);
@foreign IO_Print :: proc(msg: *char);
@foreign IO_OutputMessage :: proc(str: *char, len: int);
@foreign IO_OutputError :: proc(str: *char, len: int): IO_ErrorResult;
@foreign IO_Exit :: proc(error_code: int);
@foreign IO_IsDebuggerPresent :: proc(): bool;
@foreign
M_AllocatorOp :: typedef int;
M_AllocatorOp_Allocate :: 0;
M_AllocatorOp_Deallocate :: ^;
@foreign M_AllocatorProc :: typedef proc(a: *void, b: M_AllocatorOp, c: *void, d: usize): *void;
@foreign
M_Allocator :: struct {
obj: *void;
p: proc(a: *void, b: M_AllocatorOp, c: *void, d: usize): *void;
}
@foreign M_AllocNonZeroed :: proc(allocator: M_Allocator, size: usize): *void;
@foreign M_Alloc :: proc(allocator: M_Allocator, size: usize): *void;
@foreign M_AllocCopy :: proc(allocator: M_Allocator, p: *void, size: usize): *void;
@foreign M_Dealloc :: proc(allocator: M_Allocator, p: *void);
@foreign MA_AllocatorProc :: proc(allocator: M_Allocator, kind: M_AllocatorOp, p: *void, size: usize): *void;
@foreign M_GetSystemAllocator :: proc(): M_Allocator;
@foreign
MV_Memory :: struct {
commit: usize;
reserve: usize;
data: *u8;
}
@foreign
MA_Arena :: struct {
allocator: M_Allocator;
memory: MV_Memory;
alignment: int;
saved_alignment: int;
len: usize;
packed_array_element_size: usize;
packed_array_begin: usize;
}
@foreign
MA_Temp :: struct {
arena: *MA_Arena;
pos: usize;
}
@foreign MA_MemoryZero :: proc(p: *void, size: usize);
@foreign MA_MemoryCopy :: proc(dst: *void, src: *void, size: usize);
@foreign MA_GetAlignOffset :: proc(size: usize, align: usize): usize;
@foreign MA_AlignUp :: proc(size: usize, align: usize): usize;
@foreign MA_AlignDown :: proc(size: usize, align: usize): usize;
@foreign MA_DeallocateStub :: proc(arena: *MA_Arena, p: *void);
@foreign MA_PopToPos :: proc(arena: *MA_Arena, pos: usize);
@foreign MA_PopSize :: proc(arena: *MA_Arena, size: usize): *void;
@foreign MA_DeallocateArena :: proc(arena: *MA_Arena);
@foreign MA_Reset :: proc(arena: *MA_Arena);
@foreign MA__BeginPackedArray :: proc(arena: *MA_Arena, element_size: usize): *void;
@foreign MA_EndPackedArray :: proc(arena: *MA_Arena): int;
@foreign MA_SetAlignment :: proc(arena: *MA_Arena, alignment: int);
@foreign MA_GetTop :: proc(a: *MA_Arena): *u8;
@foreign MA_PushSizeNonZeroed :: proc(a: *MA_Arena, size: usize): *void;
@foreign MA_PushSize :: proc(arena: *MA_Arena, size: usize): *void;
@foreign MA_Init :: proc(a: *MA_Arena, reserve: usize);
@foreign MA_Create :: proc(): MA_Arena;
@foreign MA_InitFromBuffer :: proc(arena: *MA_Arena, buffer: *void, size: usize);
@foreign MA_MakeFromBuffer :: proc(buffer: *void, size: usize): MA_Arena;
@foreign MA_PushStringCopy :: proc(arena: *MA_Arena, p: *char, size: usize): *char;
@foreign MA_PushCopy :: proc(arena: *MA_Arena, p: *void, size: usize): *void;
@foreign MA_IsPointerInside :: proc(arena: *MA_Arena, p: *void): bool;
@foreign MA_PushArena :: proc(arena: *MA_Arena, size: usize): MA_Arena;
@foreign MA_BeginTemp :: proc(arena: *MA_Arena): MA_Temp;
@foreign MA_EndTemp :: proc(checkpoint: MA_Temp);
@foreign MA_GetScratchEx :: proc(conflicts: **MA_Arena, conflict_count: int): MA_Temp;
@foreign MA_GetScratch :: proc(): MA_Temp;
@foreign MA_GetScratch1 :: proc(conflict: *MA_Arena): MA_Temp;
@foreign MV_Reserve :: proc(size: usize): MV_Memory;
@foreign MV_Commit :: proc(m: *MV_Memory, commit: usize): bool;
@foreign MV_Deallocate :: proc(m: *MV_Memory);
@foreign MV_DecommitPos :: proc(m: *MV_Memory, pos: usize): bool;
@foreign
S8_String :: struct {
str: *char;
len: i64;
}
@foreign
S8_Node :: struct {
next: *S8_Node;
string: S8_String;
}
@foreign
S8_List :: struct {
node_count: i64;
char_count: i64;
first: *S8_Node;
last: *S8_Node;
}
@foreign S8_AreEqual :: proc(a: S8_String, b: S8_String, ignore_case: uint): bool;
@foreign S8_EndsWith :: proc(a: S8_String, end: S8_String, ignore_case: uint): bool;
@foreign S8_StartsWith :: proc(a: S8_String, start: S8_String, ignore_case: uint): bool;
@foreign S8_Make :: proc(str: *char, len: i64): S8_String;
@foreign S8_Copy :: proc(allocator: *MA_Arena, string: S8_String): S8_String;
@foreign S8_NormalizePath :: proc(s: S8_String);
@foreign S8_Chop :: proc(string: S8_String, len: i64): S8_String;
@foreign S8_Skip :: proc(string: S8_String, len: i64): S8_String;
@foreign S8_GetPostfix :: proc(string: S8_String, len: i64): S8_String;
@foreign S8_GetPrefix :: proc(string: S8_String, len: i64): S8_String;
@foreign S8_Slice :: proc(string: S8_String, first_index: i64, one_past_last_index: i64): S8_String;
@foreign S8_Trim :: proc(string: S8_String): S8_String;
@foreign S8_TrimEnd :: proc(string: S8_String): S8_String;
@foreign S8_ToLowerCase :: proc(allocator: *MA_Arena, s: S8_String): S8_String;
@foreign S8_ToUpperCase :: proc(allocator: *MA_Arena, s: S8_String): S8_String;
@foreign S8_Find :: proc(string: S8_String, find: S8_String, flags: uint, index_out: *i64): bool;
@foreign S8_Split :: proc(allocator: *MA_Arena, string: S8_String, find: S8_String, flags: uint): S8_List;
@foreign S8_MergeWithSeparator :: proc(allocator: *MA_Arena, list: S8_List, separator: S8_String): S8_String;
@foreign S8_Merge :: proc(allocator: *MA_Arena, list: S8_List): S8_String;
@foreign S8_ReplaceAll :: proc(allocator: *MA_Arena, string: S8_String, replace: S8_String, with: S8_String, flags: uint): S8_String;
@foreign S8_FindAll :: proc(allocator: *MA_Arena, string: S8_String, find: S8_String, flags: uint): S8_List;
@foreign S8_ChopLastSlash :: proc(s: S8_String): S8_String;
@foreign S8_ChopLastPeriod :: proc(s: S8_String): S8_String;
@foreign S8_SkipToLastSlash :: proc(s: S8_String): S8_String;
@foreign S8_SkipToLastPeriod :: proc(s: S8_String): S8_String;
@foreign S8_Length :: proc(string: *char): i64;
@foreign S8_WideLength :: proc(string: *wchar_t): i64;
@foreign S8_MakeFromChar :: proc(string: *char): S8_String;
@foreign S8_MakeEmpty :: proc(): S8_String;
@foreign S8_MakeEmptyList :: proc(): S8_List;
@foreign S8_FormatV :: proc(allocator: *MA_Arena, str: *char, args1: va_list): S8_String;
@foreign S8_Format :: proc(allocator: *MA_Arena, str: *char, ...): S8_String;
@foreign S8_CreateNode :: proc(allocator: *MA_Arena, string: S8_String): *S8_Node;
@foreign S8_ReplaceNodeString :: proc(list: *S8_List, node: *S8_Node, new_string: S8_String);
@foreign S8_AddExistingNode :: proc(list: *S8_List, node: *S8_Node);
@foreign S8_AddArray :: proc(allocator: *MA_Arena, list: *S8_List, array: **char, count: int);
@foreign S8_AddArrayWithPrefix :: proc(allocator: *MA_Arena, list: *S8_List, prefix: *char, array: **char, count: int);
@foreign S8_MakeList :: proc(allocator: *MA_Arena, a: S8_String): S8_List;
@foreign S8_CopyList :: proc(allocator: *MA_Arena, a: S8_List): S8_List;
@foreign S8_ConcatLists :: proc(allocator: *MA_Arena, a: S8_List, b: S8_List): S8_List;
@foreign S8_AddNode :: proc(allocator: *MA_Arena, list: *S8_List, string: S8_String): *S8_Node;
@foreign S8_AddF :: proc(allocator: *MA_Arena, list: *S8_List, str: *char, ...): S8_String;
@foreign
MU__Float2 :: struct {
x: float;
y: float;
}
@foreign
MU__Int2 :: struct {
x: int;
y: int;
}
@foreign MU_glGetProcAddress :: typedef proc(a: *char): *void;
@foreign
MU_Window_Params :: struct {
size: MU__Int2;
pos: MU__Int2;
title: *char;
enable_canvas: bool;
resizable: bool;
borderless: bool;
fps_cursor: bool;
}
@foreign
MU_Params :: struct {
memory: *void;
cap: usize;
enable_opengl: bool;
opengl_major: int;
opengl_minor: int;
delta_time: double;
window: MU_Window_Params;
sound_callback: proc(a: *MU_Context, b: *u16, c: u32): void;
}
@foreign
MU_Key_State :: struct {
down: bool;
press: bool;
unpress: bool;
raw_press: bool;
}
@foreign
MU_Key :: typedef int;
MU_KEY_INVALID :: 0;
MU_KEY_ESCAPE :: ^;
MU_KEY_ENTER :: ^;
MU_KEY_TAB :: ^;
MU_KEY_BACKSPACE :: ^;
MU_KEY_INSERT :: ^;
MU_KEY_DELETE :: ^;
MU_KEY_RIGHT :: ^;
MU_KEY_LEFT :: ^;
MU_KEY_DOWN :: ^;
MU_KEY_UP :: ^;
MU_KEY_PAGE_UP :: ^;
MU_KEY_PAGE_DOWN :: ^;
MU_KEY_HOME :: ^;
MU_KEY_END :: ^;
MU_KEY_F1 :: ^;
MU_KEY_F2 :: ^;
MU_KEY_F3 :: ^;
MU_KEY_F4 :: ^;
MU_KEY_F5 :: ^;
MU_KEY_F6 :: ^;
MU_KEY_F7 :: ^;
MU_KEY_F8 :: ^;
MU_KEY_F9 :: ^;
MU_KEY_F10 :: ^;
MU_KEY_F11 :: ^;
MU_KEY_F12 :: ^;
MU_KEY_SPACE :: 32;
MU_KEY_APOSTROPHE :: 39;
MU_KEY_PLUS :: 43;
MU_KEY_COMMA :: 44;
MU_KEY_MINUS :: 45;
MU_KEY_PERIOD :: 46;
MU_KEY_SLASH :: 47;
MU_KEY_0 :: 48;
MU_KEY_1 :: 49;
MU_KEY_2 :: 50;
MU_KEY_3 :: 51;
MU_KEY_4 :: 52;
MU_KEY_5 :: 53;
MU_KEY_6 :: 54;
MU_KEY_7 :: 55;
MU_KEY_8 :: 56;
MU_KEY_9 :: 57;
MU_KEY_SEMICOLON :: 59;
MU_KEY_EQUAL :: 61;
MU_KEY_A :: 65;
MU_KEY_B :: 66;
MU_KEY_C :: 67;
MU_KEY_D :: 68;
MU_KEY_E :: 69;
MU_KEY_F :: 70;
MU_KEY_G :: 71;
MU_KEY_H :: 72;
MU_KEY_I :: 73;
MU_KEY_J :: 74;
MU_KEY_K :: 75;
MU_KEY_L :: 76;
MU_KEY_M :: 77;
MU_KEY_N :: 78;
MU_KEY_O :: 79;
MU_KEY_P :: 80;
MU_KEY_Q :: 81;
MU_KEY_R :: 82;
MU_KEY_S :: 83;
MU_KEY_T :: 84;
MU_KEY_U :: 85;
MU_KEY_V :: 86;
MU_KEY_W :: 87;
MU_KEY_X :: 88;
MU_KEY_Y :: 89;
MU_KEY_Z :: 90;
MU_KEY_LEFT_BRACKET :: 91;
MU_KEY_BACKSLASH :: 92;
MU_KEY_RIGHT_BRACKET :: 93;
MU_KEY_GRAVE_ACCENT :: 96;
MU_KEY_F13 :: ^;
MU_KEY_F14 :: ^;
MU_KEY_F15 :: ^;
MU_KEY_F16 :: ^;
MU_KEY_F17 :: ^;
MU_KEY_F18 :: ^;
MU_KEY_F19 :: ^;
MU_KEY_F20 :: ^;
MU_KEY_F21 :: ^;
MU_KEY_F22 :: ^;
MU_KEY_F23 :: ^;
MU_KEY_F24 :: ^;
MU_KEY_KP_0 :: ^;
MU_KEY_KP_1 :: ^;
MU_KEY_KP_2 :: ^;
MU_KEY_KP_3 :: ^;
MU_KEY_KP_4 :: ^;
MU_KEY_KP_5 :: ^;
MU_KEY_KP_6 :: ^;
MU_KEY_KP_7 :: ^;
MU_KEY_KP_8 :: ^;
MU_KEY_KP_9 :: ^;
MU_KEY_KP_DECIMAL :: ^;
MU_KEY_KP_DIVIDE :: ^;
MU_KEY_KP_MULTIPLY :: ^;
MU_KEY_KP_SUBTRACT :: ^;
MU_KEY_KP_ADD :: ^;
MU_KEY_KP_ENTER :: ^;
MU_KEY_LEFT_SHIFT :: ^;
MU_KEY_LEFT_CONTROL :: ^;
MU_KEY_LEFT_ALT :: ^;
MU_KEY_LEFT_SUPER :: ^;
MU_KEY_RIGHT_SHIFT :: ^;
MU_KEY_RIGHT_CONTROL :: ^;
MU_KEY_RIGHT_ALT :: ^;
MU_KEY_RIGHT_SUPER :: ^;
MU_KEY_CAPS_LOCK :: ^;
MU_KEY_SCROLL_LOCK :: ^;
MU_KEY_NUM_LOCK :: ^;
MU_KEY_PRINT_SCREEN :: ^;
MU_KEY_PAUSE :: ^;
MU_KEY_SHIFT :: ^;
MU_KEY_CONTROL :: ^;
MU_KEY_COUNT :: ^;
@foreign
MU_Mouse_State :: struct {
pos: MU__Int2;
posf: MU__Float2;
delta_pos: MU__Int2;
delta_pos_normalized: MU__Float2;
left: MU_Key_State;
middle: MU_Key_State;
right: MU_Key_State;
delta_wheel: float;
}
@foreign
MU_DroppedFile :: struct {
next: *MU_DroppedFile;
filename: *char;
filename_size: int;
}
@foreign
MU_Arena :: struct {
memory: *char;
len: usize;
cap: usize;
}
@foreign
MU_Window :: struct {
size: MU__Int2;
sizef: MU__Float2;
pos: MU__Int2;
posf: MU__Float2;
dpi_scale: float;
is_fullscreen: bool;
is_fps_mode: bool;
is_focused: bool;
change_cursor_on_mouse_hold: bool;
processed_events_this_frame: u64;
should_render: bool;
first_dropped_file: *MU_DroppedFile;
canvas: *u32;
canvas_enabled: bool;
mouse: MU_Mouse_State;
key: [140]MU_Key_State;
user_text32: [32]u32;
user_text32_count: int;
user_text8: [32]char;
user_text8_count: int;
next: *MU_Window;
handle: *void;
platform: *void;
}
@foreign
MU_Time :: struct {
app_start: double;
frame_start: double;
update: double;
update_total: double;
delta: double;
deltaf: float;
total: double;
totalf: float;
}
@foreign
MU_Sound :: struct {
initialized: bool;
samples_per_second: uint;
number_of_channels: uint;
bytes_per_sample: uint;
callback: proc(a: *MU_Context, b: *u16, c: u32): void;
}
@foreign
MU_Context :: struct {
quit: bool;
sound: MU_Sound;
time: MU_Time;
first_frame: bool;
_MU_Update_count: int;
frame: usize;
consecutive_missed_frames: usize;
total_missed_frames: usize;
primary_monitor_size: MU__Int2;
opengl_initialized: bool;
opengl_major: int;
opengl_minor: int;
gl_get_proc_address: proc(a: *char): *void;
params: MU_Params;
window: *MU_Window;
all_windows: *MU_Window;
perm_arena: MU_Arena;
frame_arena: MU_Arena;
platform: *void;
}
@foreign MU_Quit :: proc(mu: *MU_Context);
@foreign MU_DefaultSoundCallback :: proc(mu: *MU_Context, buffer: *u16, samples_to_fill: u32);
@foreign MU_GetTime :: proc(): double;
@foreign MU_ToggleFPSMode :: proc(window: *MU_Window);
@foreign MU_DisableFPSMode :: proc(window: *MU_Window);
@foreign MU_EnableFPSMode :: proc(window: *MU_Window);
@foreign MU_ToggleFullscreen :: proc(window: *MU_Window);
@foreign MU_Init :: proc(mu: *MU_Context, params: MU_Params, len: usize);
@foreign MU_AddWindow :: proc(mu: *MU_Context, params: MU_Window_Params): *MU_Window;
@foreign MU_InitWindow :: proc(mu: *MU_Context, window: *MU_Window, params: MU_Window_Params);
@foreign MU_Start :: proc(params: MU_Params): *MU_Context;
@foreign MU_Update :: proc(mu: *MU_Context): bool;
@foreign LIB_Library :: typedef *void;
@foreign LIB_LoadLibrary :: proc(str: *char): LIB_Library;
@foreign LIB_LoadSymbol :: proc(lib: LIB_Library, symbol: *char): *void;
@foreign LIB_UnloadLibrary :: proc(lib: LIB_Library): bool;
@foreign
CTX_Context :: struct {
heap: M_Allocator;
temp_alloc: M_Allocator;
perm_alloc: M_Allocator;
temp: *MA_Arena;
perm: *MA_Arena;
temporary_arena: MA_Arena;
pernament_arena: MA_Arena;
user_context: *void;
}
@foreign CTX_Init :: proc();
@foreign
OS_Result :: typedef int;
OS_SUCCESS :: 0;
OS_ALREADY_EXISTS :: ^;
OS_PATH_NOT_FOUND :: ^;
OS_FAILURE :: ^;
@foreign
OS_Date :: struct {
year: u32;
month: u32;
day: u32;
hour: u32;
minute: u32;
second: u32;
milliseconds: u32;
}
@foreign OS_IsAbsolute :: proc(path: S8_String): bool;
@foreign OS_GetExePath :: proc(arena: *MA_Arena): S8_String;
@foreign OS_GetExeDir :: proc(arena: *MA_Arena): S8_String;
@foreign OS_GetWorkingDir :: proc(arena: *MA_Arena): S8_String;
@foreign OS_SetWorkingDir :: proc(path: S8_String);
@foreign OS_GetAbsolutePath :: proc(arena: *MA_Arena, relative: S8_String): S8_String;
@foreign OS_FileExists :: proc(path: S8_String): bool;
@foreign OS_IsDir :: proc(path: S8_String): bool;
@foreign OS_IsFile :: proc(path: S8_String): bool;
@foreign OS_GetTime :: proc(): double;
@foreign OS_ListDir :: proc(arena: *MA_Arena, path: S8_String, flags: uint): S8_List;
@foreign OS_MakeDir :: proc(path: S8_String): OS_Result;
@foreign OS_CopyFile :: proc(from: S8_String, to: S8_String, overwrite: bool): OS_Result;
@foreign OS_DeleteFile :: proc(path: S8_String): OS_Result;
@foreign OS_DeleteDir :: proc(path: S8_String, flags: uint): OS_Result;
@foreign OS_AppendFile :: proc(path: S8_String, string: S8_String): OS_Result;
@foreign OS_WriteFile :: proc(path: S8_String, string: S8_String): OS_Result;
@foreign OS_ReadFile :: proc(arena: *MA_Arena, path: S8_String): S8_String;
@foreign OS_SystemF :: proc(string: *char, ...): int;
@foreign OS_GetFileModTime :: proc(file: S8_String): i64;
@foreign OS_GetDate :: proc(): OS_Date;
@foreign S8_SplitOnRegex :: proc(arena: *MA_Arena, string: S8_String, regex: S8_String, flags: uint): S8_List;
@foreign OS_ListDirRegex :: proc(arena: *MA_Arena, path: S8_String, flags: uint, regex: *char): S8_List;
@foreign OS_ListDirRegexAsString :: proc(arena: *MA_Arena, path: S8_String, flags: uint, regex: *char): S8_String;
@foreign OS_ExpandIncludesList :: proc(arena: *MA_Arena, out: *S8_List, filepath: S8_String): bool;
@foreign OS_ExpandIncludes :: proc(arena: *MA_Arena, filepath: S8_String): S8_String;
@foreign
LC_MapEntry :: struct {
key: u64;
value: u64;
}
@foreign
LC_Map :: struct {
allocator: M_Allocator;
entries: *LC_MapEntry;
cap: int;
len: int;
}
@foreign LC_MapReserve :: proc(map: *LC_Map, size: int);
@foreign LC_GetMapEntryEx :: proc(map: *LC_Map, key: u64): *LC_MapEntry;
@foreign LC_InsertMapEntry :: proc(map: *LC_Map, key: u64, value: u64): *LC_MapEntry;
@foreign LC_GetMapEntry :: proc(map: *LC_Map, key: u64): *LC_MapEntry;
@foreign LC_MapInsert :: proc(map: *LC_Map, keystr: S8_String, value: *void);
@foreign LC_MapGet :: proc(map: *LC_Map, keystr: S8_String): *void;
@foreign LC_MapInsertU64 :: proc(map: *LC_Map, keystr: u64, value: *void);
@foreign LC_MapGetU64 :: proc(map: *LC_Map, keystr: u64): *void;
@foreign LC_MapGetP :: proc(map: *LC_Map, key: *void): *void;
@foreign LC_MapInsertP :: proc(map: *LC_Map, key: *void, value: *void);
@foreign Map_Insert2P :: proc(map: *LC_Map, key: *void, value: *void);

View File

@@ -0,0 +1,13 @@
LibraryUpdate :: typedef proc(event: LibraryEvent, mu: *MU_Context, context: *DLL_Context);
LibraryEvent :: typedef int;
Init :: 0;
Reload :: ^;
Unload :: ^;
Update :: ^;
DLL_Context :: struct {
temp: *MA_Arena;
perm: MA_Arena;
context: *void;
}

View File

@@ -0,0 +1,34 @@
#`#include <stdint.h>`;
@foreign(int8_t) i8 :: typedef char;
@foreign(int16_t) i16 :: typedef short;
@foreign(int32_t) i32 :: typedef int;
@foreign(int64_t) i64 :: typedef llong;
@foreign(uint8_t) u8 :: typedef uchar;
@foreign(uint16_t) u16 :: typedef ushort;
@foreign(uint32_t) u32 :: typedef uint;
@foreign(uint64_t) u64 :: typedef ullong;
@foreign(size_t) usize :: typedef u64;
@foreign(intptr_t) isize :: typedef i64;
@foreign(intptr_t) intptr :: typedef i64;
@foreign(uintptr_t) uintptr :: typedef u64;
@weak @foreign f32 :: typedef float;
@weak @foreign f64 :: typedef double;
@foreign wchar_t :: typedef u16;
@foreign va_list :: typedef u64;
NULL :: 0;
@foreign UINT64_MAX: u64;
@foreign UINT32_MAX: u32;
@foreign UINT16_MAX: u16;
@foreign UINT8_MAX: u8;
@foreign INT64_MAX: i64;
@foreign INT32_MAX: i32;
@foreign INT16_MAX: i16;
@foreign INT8_MAX: i8;

37
tests/field_access.txt Normal file
View File

@@ -0,0 +1,37 @@
import "libc";
T :: struct {
a: int;
t2: T2;
}
T2 :: struct {
b: int;
}
T3 :: struct {
om: T;
}
main :: proc(): int {
t: T;
a := t.a; @unused
b := (t).a; @unused
i0 := :T{10}.a;
i1 := :T{}.t2.b;
i2 := :T{t2={1}}.t2;
assert(i0 == 10);
assert(i1 == 0);
assert(i2.b == 1);
assert(t.t2.b == 0);
i3: T3;
i3.om.a = 10;
i3.om.t2.b = 10;
return 0;
}

View File

@@ -0,0 +1,21 @@
import "libc";
Some_Struct :: struct {
i: *int;
}
main :: proc(): int {
i: [4]int = {1, 2, 3, 4};
s: Some_Struct = {i = addptr(i, 1)};
assert(s.i[0] == 2);
assert(s.i[-1] == 1);
assert(s.i[1] == 3);
assert(addptr(s.i, 1)[0] == 3);
assert(*addptr(s.i, -1) == 1);
assert(addptr(s.i, -1)[0] == 1);
return 0;
}

17
tests/for.txt Normal file
View File

@@ -0,0 +1,17 @@
main :: proc(): int {
for i := 0; i < 4 {
i += 1;
}
i := 0;
for i < 4; i += 1 {
//
}
i = 0;
for i < 4 {
i += 1;
}
return 0;
}

12
tests/for2.txt Normal file
View File

@@ -0,0 +1,12 @@
A :: struct {
a: int;
}
main :: proc(): int {
result := 2;
for &:A{1} {result -= 1; break;}
for "asd" {result -= 1; break;}
return result;
}

66
tests/fpointers.txt Normal file
View File

@@ -0,0 +1,66 @@
ValidProc :: proc(): int {return 1;}
ProcPointer: proc(): int = ValidProc;
ProcT :: typedef proc(): int; @weak
ProcP: ProcT;
main :: proc(): int {
ProcPointer = ValidProc;
ProcPointer = nil;
ProcP = ValidProc;
ProcP = nil;
v: *void;
ProcP = v;
ProcPointer = v;
ProcP = nil;
ProcPointer = ValidProc;
value := ProcPointer(); @unused
ProcP = ValidProc;
ProcP();
v = ProcPointer;
ProcP = ProcPointer;
vv := :*void(ProcPointer);
pv := :ProcT(vv); @unused
pv2 := :proc(): int(vv); @unused
a: *int;
b := :ProcT(a); @unused
c := &ProcP; @unused
return 0;
}
FP :: typedef proc(i: int = 10);
Thing :: struct {
fp: FP;
fp2: proc(i: int);
}
glob0: FP;
glob1: proc(j: int);
Another :: proc() {
thing: Thing;
thing.fp();
thing.fp2(10);
var0: FP;
var1: proc(j: int);
var0();
var1(j = 10);
glob0();
glob1(j = 10);
}

View File

@@ -0,0 +1,16 @@
import c "libc";
a: []int = {1, 2, 3, 4, 5};
b: [6]int = {1, 2, 3, 4};
main :: proc(): int {
local_a: []int = {1, 2, 3, 4, 5};
local_b: [6]int = {1, 2, 3, 4};
c.assert(lengthof(a) == 5);
c.assert(lengthof(b) == 6);
c.assert(lengthof(local_a) == 5);
c.assert(lengthof(local_b) == 6);
return 0;
}

9
tests/import_libc.txt Normal file
View File

@@ -0,0 +1,9 @@
// #failed: parse
// #error: no package with name
import "qweeeewewe";
main :: proc(): int {
a := malloc(32);
free(a);
return 0;
}

View File

@@ -0,0 +1,12 @@
import "libc";
main :: proc(): int {
a := malloc(32);
free(a);
s := sin(32.0); @unused
result := ceil(0.7);
result -= 1;
return :int(result);
}

7
tests/import_libc2.txt Normal file
View File

@@ -0,0 +1,7 @@
import "libc";
main :: proc(): int {
a: *int = malloc(sizeof(:int));
defer free(a);
return 0;
}

View File

@@ -0,0 +1,18 @@
// #failed: parse
// #error: unregistered note name: 'something'
// #error: unregistered note name: 'other'
// #error: unregistered note name: 'another'
// #error: unregistered note name: 'and_other'
// #error: unregistered note name: 'andd'
#something;
@other
A :: proc() {
}
#another;
@and_other
@andd
B :: proc() {
}

40
tests/labeled_breaks.txt Normal file
View File

@@ -0,0 +1,40 @@
import "libc";
v: int;
p :: proc() {
for {
defer v += 1;
for {
defer v += 1;
{ defer v += 1; return; }
}
}
}
main :: proc(): int {
i := 0;
out: for {
defer i += 1;
in: for {
defer i += 1;
break out;
}
}
assert(i == 2);
i = 0;
out1: for {
defer { i += 1; }
in1: for {
defer i += 1;
if (i < 2) continue out1;
if (i > 2) break in1;
}
break;
}
assert(i == 5);
p();
assert(v == 3);
return 0;
}

92
tests/lack_return.txt Normal file
View File

@@ -0,0 +1,92 @@
// #failed: resolve
// #error: you can get through this procedure without hitting a return stmt
a :: proc(): int {
val := 10;
{
if (val == 1) {
return 0;
} else if val == 2 {
val = 5;
} else {
val = 4;
}
}
}
// #error: you can get through this procedure without hitting a return stmt
b :: proc(): int {
val := 10;
{
if val == 10 {
if val == 10 {
return 0;
}
} else if val == 5 {
return 20;
} else {
return 0;
}
}
}
// regression, error in return and we don't want to report the lack of return by accident
// #error: cannot assign void
c :: proc(): int {
for {
return;
}
}
// #error: cannot assign void
d :: proc(): int {
val := 4;
if val {
return;
}
}
// #error: you can get through this procedure without hitting a return stmt
e :: proc(): int {
val := false;
for {
if val {
return 10;
}
}
if val {
}
else {
return 10;
}
}
f :: proc(): int {
switch 4 {
case 1: return 0;
default: return 0;
}
}
// #error: you can get through this procedure without hitting a return stmt
g :: proc(): int {
val := 4;
switch val {
case 1: return 0;
case 2: return 0;
case 3: return 0;
}
}
h :: proc(): int {
val := 4;
switch val {
case 1: return 0;
case 2: return 0;
case 3: return 0;
default: return 0;
}
}

12
tests/large_values.txt Normal file
View File

@@ -0,0 +1,12 @@
import "libc";
VAL :: -9223372036854775800;
AFTER_VAL :: ^;
main :: proc(): int {
#static_assert(VAL == -9223372036854775800);
const_value: llong = -9223372036854775800;
enum_value: llong = VAL;
assert(const_value == enum_value);
assert(AFTER_VAL == const_value + 1);
return 0;
}

94
tests/literals.txt Normal file
View File

@@ -0,0 +1,94 @@
import "libc";
main :: proc(argc: int @unused, argv: **char @unused): int {
{
i: int;
j0 := &i; @unused
j1 := :ullong(&i); @unused
}
{
b := 0 && 1; @unused
}
{
d := 20.0 + 40;
assert(d == 60.0);
e: float = 20; @unused
c: float = 10 + 20;
assert(c == :float(30));
assert(d == :double(60.0));
assert(:int(d) == :int(60.0));
assert(:int(d) == 60);
assert(:uint(-1) > 1000000);
f: float;
assert(f == 0.0);
assert(:double(f) == 0);
}
{
c := !1;
assert(typeof(c) == typeof(:bool));
}
{
a: int = 10;
b: double = 10;
assert(:int(b) == a);
assert(:double(a) == b);
assert(a == 10*true);
assert(a != 0);
}
{
assert(10.0 == 10);
assert(10.0 != 9.0);
assert(10.0 != 9);
}
{
assert(:uint(1) == 1);
assert(:uint(-1) != 1);
c: uchar = :uchar(-1);
assert(c == 255);
a: ushort = :ushort(-1);
assert(a == :ushort(-1));
assert(:uint(a) != :uint(-1));
assert(:int(a) != :int(-1));
assert(:uint(:ushort(-1)) != :uint(-1));
assert(:ullong(:uchar(-1)) != :ullong(-1));
}
{
a := :[]uchar{:uchar(-1), :uchar(-2), :uchar(-3)};
first := 255;
for i: uchar = 0; i < lengthof(a); i += 1 {
assert(:uchar(first) - i == a[i]);
}
assert(typeof(a[0]) == typeof(:uchar));
}
{
b: double = 10;
a := 10.0 == b;
assert(typeof(a) == typeof(:bool));
}
{
a: bool = true;
b := false;
assert(typeof(a) == typeof(b));
}
{
a :: 1 << 63;
U64MAX :: 0xffffffffffffffff;
assert(U64MAX == :ullong(-1));
assert(a == :ullong(1) << 63);
}
return 0;
}

46
tests/loops.txt Normal file
View File

@@ -0,0 +1,46 @@
import "libc";
main :: proc(): int {
i := 0;
for {
if (i == 2) break;
i += 1;
}
assert(i == 2);
for i = 0; i < 2; i += 1 {
}
assert(i == 2);
for ;i < 4; i += 1 {}
assert(i == 4);
for i < 5 {
i += 1;
}
assert(i == 5);
for ;;i += 1 {
if (i == 8) break;
}
assert(i == 8);
for i = 0; i < 3 {
i += 1;
}
for i = 4 {
assert(i == 4);
break;
}
assert(i == 4);
for j := 4 {
assert(j == 4);
break;
}
return 0;
}

19
tests/lvalues.txt Normal file
View File

@@ -0,0 +1,19 @@
import "libc";
main :: proc(): int {
i4: llong = 4;
p := &i4;
assert(*p == i4);
*p -= 1;
*&i4 -= 1;
assert(*&i4 == 2);
pp := &p;
**pp += 2;
assert(i4 == 4);
assert(**pp == 4);
return 0;
}

5
tests/lvalues2.txt Normal file
View File

@@ -0,0 +1,5 @@
// #failed: resolve
// #error: assigning value to a temporal object (lvalue)
f0 :: proc() { (1+1) = 2; }
// #error: assigning value to a temporal object (lvalue)
f1 :: proc() { 1+1 = 2; }

View File

@@ -0,0 +1,6 @@
a :: proc(): int {
return 0;
}
a :: proc() {
}

View File

@@ -0,0 +1,3 @@
import "b";
b :: proc() {
}

View File

@@ -0,0 +1,2 @@
d :: proc(): int {
}

View File

@@ -0,0 +1,13 @@
import "a";
import "b";
import "working";
import "d_not_working";
a :: proc(): int {
return 0;
}
should_not_report_undeclared_n :: proc(): int {
result := b();
return result;
}

View File

@@ -0,0 +1,7 @@
Idea behind this test is that we want to make sure all imports are looked into regardless of errors.
// #failed: package
// #error: there are 2 decls
// #error: there are 2 decls
// #error: circular import
// #error: you can get through this procedure without

View File

@@ -0,0 +1,7 @@
thing :: proc(): int {
return 0;
}
not_thing :: proc(): int {
return 0;
}

View File

@@ -0,0 +1,19 @@
// #failed: resolve
// #error: undeclared identifier 'asd'
// #error: undeclared identifier 'qwe'
// #error: undeclared identifier 'asd'
// #error: undeclared identifier 'totk'
A :: struct {
a: asd;
b: qwe;
c: asd;
d: totk;
}
// #error: duplicate field 'O'
B :: struct {
O: int;
O: int;
}

16
tests/negate.txt Normal file
View File

@@ -0,0 +1,16 @@
import "libc";
#static_assert(~4 | (1 << 37) == -5);
main :: proc(): int {
{a: llong = ~1;
b := ~:llong(1);
assert(a == b);}
{a: ullong = ~1;
b := ~:ullong(1);
assert(a == b);}
return 0;
}

32
tests/nested_comments.txt Normal file
View File

@@ -0,0 +1,32 @@
/* Nesting 0
/* Nesting 1
*/
/* Nesting 1
/* Nesting 2
*/
*/
*/
main :: proc(): int {
/* Nesting 0
/* Nesting 1
*/
/* Nesting 1
/* Nesting 2
/* Nesting 3 */
/* Nesting 3 */
/* Nesting 3 */
*/
*/
*/
return 0;
}

View File

@@ -0,0 +1,9 @@
main :: proc(): int {
i: int;
a: [32]int;
b := addptr(a, 4); @unused
val := i ^ i; @unused
return i;
}

7
tests/nil.txt Normal file
View File

@@ -0,0 +1,7 @@
main :: proc(): int {
a: *int;
if a == nil {
return 0;
}
return 1;
}

3028
tests/opengl_loader.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,129 @@
// #failed: resolve
// #error: invalid binary operation for type 'float'
// #error: invalid binary operation for type 'float'
// #error: invalid binary operation for type 'float'
// #error: invalid binary operation for type 'float'
// #error: invalid binary operation for type 'float'
// #error: invalid binary operation for type 'double'
// #error: invalid binary operation for type 'double'
// #error: invalid binary operation for type 'double'
// #error: invalid binary operation for type 'double'
// #error: invalid binary operation for type 'double'
char1184605005 := :char(451)+:char(200);
char1543628619 := :char(451)-:char(200);
char2426623557 := :char(451)*:char(200);
char1926046121 := :char(451)/:char(200);
char3015104713 := :char(451)%:char(200);
char4094601016 := :char(451)>>:char(200);
char3594810486 := :char(451)<<:char(200);
char4661534 := :char(451)|:char(200);
char4128516316 := :char(451)&:char(200);
uchar418625421 := :uchar(451)+:uchar(200);
uchar1301943202 := :uchar(451)-:uchar(200);
uchar133926661 := :uchar(451)*:uchar(200);
uchar306256219 := :uchar(451)/:uchar(200);
uchar2048152242 := :uchar(451)%:uchar(200);
uchar2693568151 := :uchar(451)>>:uchar(200);
uchar1859046010 := :uchar(451)<<:uchar(200);
uchar271747438 := :uchar(451)|:uchar(200);
uchar2456123388 := :uchar(451)&:uchar(200);
short1892008467 := :short(451)+:short(200);
short397978967 := :short(451)-:short(200);
short3347868109 := :short(451)*:short(200);
short1385996894 := :short(451)/:short(200);
short295729027 := :short(451)%:short(200);
short4097226668 := :short(451)>>:short(200);
short3909136835 := :short(451)<<:short(200);
short3691421792 := :short(451)|:short(200);
short1750775072 := :short(451)&:short(200);
ushort2551662666 := :ushort(451)+:ushort(200);
ushort424162394 := :ushort(451)-:ushort(200);
ushort446231218 := :ushort(451)*:ushort(200);
ushort694759383 := :ushort(451)/:ushort(200);
ushort289787800 := :ushort(451)%:ushort(200);
ushort2817106439 := :ushort(451)>>:ushort(200);
ushort2340950147 := :ushort(451)<<:ushort(200);
ushort1213153378 := :ushort(451)|:ushort(200);
ushort2747762274 := :ushort(451)&:ushort(200);
bool2725368302 := :bool(451)+:bool(200);
bool4108749261 := :bool(451)-:bool(200);
bool3030947742 := :bool(451)*:bool(200);
bool2306203953 := :bool(451)/:bool(200);
bool3072857278 := :bool(451)%:bool(200);
bool3371870999 := :bool(451)>>:bool(200);
bool2007071617 := :bool(451)<<:bool(200);
bool3624728886 := :bool(451)|:bool(200);
bool2301390148 := :bool(451)&:bool(200);
int3652314270 := :int(451)+:int(200);
int88498391 := :int(451)-:int(200);
int828520918 := :int(451)*:int(200);
int3506325541 := :int(451)/:int(200);
int3107620494 := :int(451)%:int(200);
int3023998979 := :int(451)>>:int(200);
int1597279715 := :int(451)<<:int(200);
int4049992760 := :int(451)|:int(200);
int4026481088 := :int(451)&:int(200);
uint3551573939 := :uint(451)+:uint(200);
uint2297715228 := :uint(451)-:uint(200);
uint2027992488 := :uint(451)*:uint(200);
uint4212072131 := :uint(451)/:uint(200);
uint2351180318 := :uint(451)%:uint(200);
uint820061642 := :uint(451)>>:uint(200);
uint3195196673 := :uint(451)<<:uint(200);
uint2563592427 := :uint(451)|:uint(200);
uint2241958026 := :uint(451)&:uint(200);
long914993451 := :long(451)+:long(200);
long3082782857 := :long(451)-:long(200);
long1033106904 := :long(451)*:long(200);
long3821577267 := :long(451)/:long(200);
long2849045448 := :long(451)%:long(200);
long3183126591 := :long(451)>>:long(200);
long3862049455 := :long(451)<<:long(200);
long3375570186 := :long(451)|:long(200);
long2762439088 := :long(451)&:long(200);
ulong1669356355 := :ulong(451)+:ulong(200);
ulong2958289717 := :ulong(451)-:ulong(200);
ulong837362083 := :ulong(451)*:ulong(200);
ulong3417766688 := :ulong(451)/:ulong(200);
ulong3734930923 := :ulong(451)%:ulong(200);
ulong3430916640 := :ulong(451)>>:ulong(200);
ulong3263419748 := :ulong(451)<<:ulong(200);
ulong4106423246 := :ulong(451)|:ulong(200);
ulong2418261593 := :ulong(451)&:ulong(200);
llong2532134757 := :llong(451)+:llong(200);
llong4027182267 := :llong(451)-:llong(200);
llong2738991522 := :llong(451)*:llong(200);
llong584915521 := :llong(451)/:llong(200);
llong539575637 := :llong(451)%:llong(200);
llong1269621407 := :llong(451)>>:llong(200);
llong3781491866 := :llong(451)<<:llong(200);
llong4056699875 := :llong(451)|:llong(200);
llong3763295108 := :llong(451)&:llong(200);
ullong3899501603 := :ullong(451)+:ullong(200);
ullong4163116987 := :ullong(451)-:ullong(200);
ullong900520260 := :ullong(451)*:ullong(200);
ullong2083869174 := :ullong(451)/:ullong(200);
ullong1864796312 := :ullong(451)%:ullong(200);
ullong2757485449 := :ullong(451)>>:ullong(200);
ullong461805070 := :ullong(451)<<:ullong(200);
ullong1569839266 := :ullong(451)|:ullong(200);
ullong1735299987 := :ullong(451)&:ullong(200);
float1386138228 := :float(451)+:float(200);
float2298997472 := :float(451)-:float(200);
float1658412341 := :float(451)*:float(200);
float410190543 := :float(451)/:float(200);
float1517791460 := :float(451)%:float(200);
float3613392565 := :float(451)>>:float(200);
float214453256 := :float(451)<<:float(200);
float1348722320 := :float(451)|:float(200);
float1203551533 := :float(451)&:float(200);
double2979475223 := :double(451)+:double(200);
double667886729 := :double(451)-:double(200);
double3956848768 := :double(451)*:double(200);
double550709745 := :double(451)/:double(200);
double1846357701 := :double(451)%:double(200);
double1374823896 := :double(451)>>:double(200);
double1816508307 := :double(451)<<:double(200);
double3749361724 := :double(451)|:double(200);
double2314584652 := :double(451)&:double(200);

52
tests/packed_struct.txt Normal file
View File

@@ -0,0 +1,52 @@
import "libc";
A :: struct {
a: short;
b: char;
c: int;
d: char;
e: llong;
f: uchar;
} @packed
B :: struct {
a: A;
b: A;
}
C :: struct {
a: llong;
b: A;
c: A;
}
D :: struct {
a: A;
b: int;
c: char;
} @packed
#static_assert(sizeof(:A) == 17);
#static_assert(alignof(:A) == 1);
#static_assert(sizeof(:B) == 34);
#static_assert(alignof(:B) == 1);
#static_assert(sizeof(:C) == 48);
#static_assert(alignof(:C) == 8);
#static_assert(sizeof(:D) == 22);
#static_assert(alignof(:D) == 1);
main :: proc(): int {
assert(sizeof(:A) == 17);
assert(alignof(:A) == 1);
assert(sizeof(:B) == 34);
assert(alignof(:B) == 1);
assert(sizeof(:C) == 48);
assert(alignof(:C) == 8);
return 0;
}

View File

@@ -0,0 +1,22 @@
ASDF;
Something :: proc() {
}
^Memes;
Some_Struct :: struct {
i: int;
}
Another_One
// #failed: parse
// #error: got unexpected token
// #error: got unexpected token
// #error: got unexpected token

View File

@@ -0,0 +1,8 @@
// #failed: resolve
// #expected_error_count: 4
m :: proc(); @api
m :: proc(); @api
m :: proc(); @api
@api
@api

33
tests/pointers.txt Normal file
View File

@@ -0,0 +1,33 @@
import "libc";
main :: proc(): int {
{
arr: [100]int = {1, 2 ,3 ,4};
p0 := addptr(arr, 1);
assert(*p0 == 2);
p1 := addptr(p0, 1);
assert(p1[0] == 3);
}
{
i: *int = :*int(1);
if i {
i = nil;
assert(i == 0);
}
}
{
token_count :: 20;
tokens: [token_count]int;
x: *int = addptr(tokens, 0);
t: *int = addptr(tokens, 4);
r1 := x && (t >= &tokens[0] && t < &tokens[token_count]);
r2 := x && (t >= addptr(tokens, 0) && t < addptr(tokens, token_count));
assert(r1 == true);
assert(r2 == true);
}
return 0;
}

46
tests/raw_strings.txt Normal file
View File

@@ -0,0 +1,46 @@
import "libc";
A :: `THING
THING`;
B: String = `THING
THING`;
main :: proc(): int {
a :: `
Something
Other thing
Another thing
`;
b := `
Something
Other thing
Another thing
`; @unused
c: String = `
Something
Other thing
Another thing
`;
d := a; @unused
e := A; @unused
has_new_lines: bool;
for i := 0; i < c.len; i += 1 {
if c.str[i] == '\n' {
has_new_lines = true;
}
assert(c.str[i] != 0);
}
assert(has_new_lines);
lena := lengthof(A); @unused
assert(lengthof(A) == 11 || lengthof(A) == 12); // either CRLF or LF
assert(B.len == 11 || B.len == 12);
return 0;
}

View File

@@ -0,0 +1,10 @@
// #failed: resolve
PROC :: proc() {}
CONST :: 40;
STRUCT :: struct { a: int; }
// #error: declaration is type, unexpected inside expression
A :: STRUCT;
// #error: expected an untyped constant
C :: PROC;
D :: CONST;

View File

@@ -0,0 +1,17 @@
// #failed: resolve
// #expected_error_count: 6
OS_WINDOWS :: 10;
String :: struct {
a: int;
}
int :: struct {
i: long;
}
// This should be OK
UntypedFloat :: struct {
a: float;
}

View File

@@ -0,0 +1,7 @@
// #failed: resolve
// #error: trying to access address of a temporal object
main :: proc(): int {
a := 0;
app := &(&(a));
return 0;
}

View File

@@ -0,0 +1,25 @@
// #failed: parse
S :: struct { i: int; }
A :: struct { i: int; }
main :: proc(): int {
s: S;
// #error: expected identifier got instead integer literal
a := s.32;
// #error: expected identifier got instead string literal
b := s."asd";
// #error: expected identifier got instead open paren
d := s.("asd");
val := 32;
// #error: expected identifier got instead open paren
e := s.(24 + val);
// #error: expected identifier got instead open paren
f := s.(24 + 24);
}

View File

@@ -0,0 +1,20 @@
// #failed: resolve
Some_Struct :: struct {
item: int;
another_item: int;
}
main :: proc() {
{
some_struct: Some_Struct;
// #error: undeclared identifier 'i'
i := some_struct.i;
}
@unused im: int; // int should be declared
@unused thing: Some_Struct;
// #error: undeclared identifier 'undeclared'
another_undeclared: undeclared;
}

View File

@@ -0,0 +1,26 @@
// #failed: resolve
Some_Struct :: struct {
item: int;
another_item: int;
}
main :: proc() {
ss: Some_Struct;
if ss.item {
{
// #error: undeclared identifier 'i'
a := ss.i;
// #error: undeclared identifier 'b'
ss.item = b - a;
}
}
@unused thing: Some_Struct;
// #error: undeclared identifier 'undeclared'
undeclared;
another_thing: Some_Struct;
// #error: very likely a bug, expression statement
another_thing;
}

View File

@@ -0,0 +1,18 @@
// #dont_run
#static_assert(sizeof(:A) == 8);
A :: struct {
a: int;
b: int;
}
#static_assert(offsetof(:B, a) == 0);
B :: struct {
a: int;
b: int;
}
#static_assert(alignof(:C) != 0);
C :: struct {
a: int;
b: int;
}

View File

@@ -0,0 +1,12 @@
main :: proc(): int {
a := true;
if a {
a = false;
}
thing := 10; @unused
// I had an error once because note got eaten by else clause parse
// I have reversed that but if I decided that else if / else could be
// tagged then this test is meant to catch that
return 0;
}

View File

@@ -0,0 +1,10 @@
A :: struct { i: int; }
thing :: proc(): *A {
return nil;
}
main :: proc(): int {
result := :int(:ullong(thing()));
return result;
}

View File

@@ -0,0 +1,6 @@
// #failed: resolve
// #error: duplicate field 'a' in aggregate type 'A'
A :: struct {
a: int;
a: int;
}

View File

@@ -0,0 +1,4 @@
// #failed: resolve
// #error: duplicate proc argument 'a'
A :: proc(a: int, a: int) {
}

Some files were not shown because too many files have changed in this diff Show More