Init new repository
This commit is contained in:
106
tests/any.txt
Normal file
106
tests/any.txt
Normal 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
4
tests/any2.txt
Normal 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
25
tests/arrays.txt
Normal 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
173
tests/assign.txt
Normal 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;
|
||||
}
|
||||
|
||||
18
tests/assign_void_proc.txt
Normal file
18
tests/assign_void_proc.txt
Normal 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'
|
||||
12
tests/break_inside_defer.txt
Normal file
12
tests/break_inside_defer.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
// #failed: resolve
|
||||
// #error: break inside of defer is illegal
|
||||
|
||||
main :: proc() {
|
||||
defer {
|
||||
{
|
||||
{
|
||||
for { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
tests/break_outside_loop.txt
Normal file
6
tests/break_outside_loop.txt
Normal 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
21
tests/build_if_note.txt
Normal 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
89
tests/builtins.txt
Normal 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
12
tests/builtins2.txt
Normal 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
21
tests/builtins3.txt
Normal 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;
|
||||
}
|
||||
13
tests/cannot_use_type_as_value.txt
Normal file
13
tests/cannot_use_type_as_value.txt
Normal 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;
|
||||
}
|
||||
4
tests/compilation/test_compile_header.cpp
Normal file
4
tests/compilation/test_compile_header.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "../../src/compiler/lib_compiler.h"
|
||||
|
||||
int main() {
|
||||
}
|
||||
40
tests/compilation/test_compile_packed.c
Normal file
40
tests/compilation/test_compile_packed.c
Normal 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;
|
||||
}
|
||||
40
tests/compilation/test_compile_packed_cpp.c
Normal file
40
tests/compilation/test_compile_packed_cpp.c
Normal 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;
|
||||
}
|
||||
5
tests/compilation/test_compile_with_core.c
Normal file
5
tests/compilation/test_compile_with_core.c
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "../../src/compiler/lib_compiler.c"
|
||||
#include "../../src/core/core.c"
|
||||
|
||||
int main() {
|
||||
}
|
||||
5
tests/compilation/test_compile_with_core_cpp.cpp
Normal file
5
tests/compilation/test_compile_with_core_cpp.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "../../src/compiler/lib_compiler.c"
|
||||
#include "../../src/core/core.c"
|
||||
|
||||
int main() {
|
||||
}
|
||||
11
tests/compo_cyclic_error.txt
Normal file
11
tests/compo_cyclic_error.txt
Normal 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
55
tests/compos.txt
Normal 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
4
tests/compos2.txt
Normal 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
48
tests/compos_resolve.txt
Normal 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
4
tests/const.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
// #dont_run
|
||||
A :: 123 + B + 23 + 123412512 + 123 + B;
|
||||
B :: 11;
|
||||
C :: A + B + A + B + 3251;
|
||||
37
tests/custom_untyped_string.txt
Normal file
37
tests/custom_untyped_string.txt
Normal 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) {}
|
||||
11
tests/defer_inside_defer.txt
Normal file
11
tests/defer_inside_defer.txt
Normal 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
21
tests/defer_order.txt
Normal 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);
|
||||
}
|
||||
7
tests/defer_with_return_inside.txt
Normal file
7
tests/defer_with_return_inside.txt
Normal 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
3
tests/division_by_0.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
// #failed: resolve
|
||||
// #error: division by 0
|
||||
a :: 10.0 / 0.0;
|
||||
36
tests/doc_comment.txt
Normal file
36
tests/doc_comment.txt
Normal 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
17
tests/doc_comments2.txt
Normal 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
8
tests/doc_comments3.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
// #failed: parse
|
||||
// #error: got unexpected token: package doc comment
|
||||
|
||||
/** file
|
||||
*/
|
||||
|
||||
/** package
|
||||
*/
|
||||
2
tests/duplicate_package_name/32asd/a.lc
Normal file
2
tests/duplicate_package_name/32asd/a.lc
Normal file
@@ -0,0 +1,2 @@
|
||||
b :: proc() {
|
||||
}
|
||||
6
tests/duplicate_package_name/main/main.lc
Normal file
6
tests/duplicate_package_name/main/main.lc
Normal file
@@ -0,0 +1,6 @@
|
||||
import "std_types";
|
||||
import "32asd";
|
||||
|
||||
main :: proc(): int {
|
||||
return 0;
|
||||
}
|
||||
2
tests/duplicate_package_name/std_types/a.lc
Normal file
2
tests/duplicate_package_name/std_types/a.lc
Normal file
@@ -0,0 +1,2 @@
|
||||
a :: proc() {
|
||||
}
|
||||
3
tests/duplicate_package_name/test.txt
Normal file
3
tests/duplicate_package_name/test.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
// #failed: package
|
||||
// #error: found 2 directories with the same name
|
||||
// #error: invalid package name, please change
|
||||
10
tests/error_call_proc_in_global_space.txt
Normal file
10
tests/error_call_proc_in_global_space.txt
Normal 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();
|
||||
9
tests/error_in_global_and_local.txt
Normal file
9
tests/error_in_global_and_local.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
// #failed: resolve
|
||||
// #error: undeclared identifier 'meme'
|
||||
A: meme;
|
||||
|
||||
main :: proc(): int {
|
||||
// #error: undeclared identifier 'asd'
|
||||
a: asd;
|
||||
return a;
|
||||
}
|
||||
37
tests/error_non_const_in_global_scope.txt
Normal file
37
tests/error_non_const_in_global_scope.txt
Normal 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()};
|
||||
|
||||
12
tests/error_on_shadowing.txt
Normal file
12
tests/error_on_shadowing.txt
Normal 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;
|
||||
}
|
||||
20
tests/error_pointer_arithmetic.txt
Normal file
20
tests/error_pointer_arithmetic.txt
Normal 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;
|
||||
}
|
||||
41
tests/error_proc_invalid_args.txt
Normal file
41
tests/error_proc_invalid_args.txt
Normal 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;
|
||||
}
|
||||
|
||||
8
tests/error_when_assigning_compo_to_global.txt
Normal file
8
tests/error_when_assigning_compo_to_global.txt
Normal 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
43
tests/errors.txt
Normal 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);
|
||||
13
tests/errors_proc_vargs.txt
Normal file
13
tests/errors_proc_vargs.txt
Normal 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;
|
||||
}
|
||||
7
tests/example_ui_and_hot_reloading/build.bat
Normal file
7
tests/example_ui_and_hot_reloading/build.bat
Normal 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
|
||||
|
||||
78
tests/example_ui_and_hot_reloading/dll/app_main.lc
Normal file
78
tests/example_ui_and_hot_reloading/dll/app_main.lc
Normal 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();
|
||||
}
|
||||
122
tests/example_ui_and_hot_reloading/dll/math.lc
Normal file
122
tests/example_ui_and_hot_reloading/dll/math.lc
Normal 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}; }
|
||||
3012
tests/example_ui_and_hot_reloading/dll/opengl.lc
Normal file
3012
tests/example_ui_and_hot_reloading/dll/opengl.lc
Normal file
File diff suppressed because it is too large
Load Diff
545
tests/example_ui_and_hot_reloading/dll/render_opengl.lc
Normal file
545
tests/example_ui_and_hot_reloading/dll/render_opengl.lc
Normal 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;
|
||||
}
|
||||
183
tests/example_ui_and_hot_reloading/dll/stb_truetype.lc
Normal file
183
tests/example_ui_and_hot_reloading/dll/stb_truetype.lc
Normal 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;
|
||||
342
tests/example_ui_and_hot_reloading/dll/ui.lc
Normal file
342
tests/example_ui_and_hot_reloading/dll/ui.lc
Normal 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;
|
||||
}
|
||||
89
tests/example_ui_and_hot_reloading/exe/exe_main.lc
Normal file
89
tests/example_ui_and_hot_reloading/exe/exe_main.lc
Normal 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;
|
||||
}
|
||||
557
tests/example_ui_and_hot_reloading/shared/core.lc
Normal file
557
tests/example_ui_and_hot_reloading/shared/core.lc
Normal 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);
|
||||
13
tests/example_ui_and_hot_reloading/shared/events.lc
Normal file
13
tests/example_ui_and_hot_reloading/shared/events.lc
Normal 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;
|
||||
}
|
||||
34
tests/example_ui_and_hot_reloading/shared/windows_types.lc
Normal file
34
tests/example_ui_and_hot_reloading/shared/windows_types.lc
Normal 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
37
tests/field_access.txt
Normal 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;
|
||||
}
|
||||
21
tests/field_pointer_offset.txt
Normal file
21
tests/field_pointer_offset.txt
Normal 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
17
tests/for.txt
Normal 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
12
tests/for2.txt
Normal 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
66
tests/fpointers.txt
Normal 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);
|
||||
}
|
||||
16
tests/implicit_compo_array_size.txt
Normal file
16
tests/implicit_compo_array_size.txt
Normal 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
9
tests/import_libc.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
// #failed: parse
|
||||
// #error: no package with name
|
||||
import "qweeeewewe";
|
||||
|
||||
main :: proc(): int {
|
||||
a := malloc(32);
|
||||
free(a);
|
||||
return 0;
|
||||
}
|
||||
12
tests/import_libc/main/main.lc
Normal file
12
tests/import_libc/main/main.lc
Normal 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
7
tests/import_libc2.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
import "libc";
|
||||
|
||||
main :: proc(): int {
|
||||
a: *int = malloc(sizeof(:int));
|
||||
defer free(a);
|
||||
return 0;
|
||||
}
|
||||
18
tests/invalid_note_name.txt
Normal file
18
tests/invalid_note_name.txt
Normal 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
40
tests/labeled_breaks.txt
Normal 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
92
tests/lack_return.txt
Normal 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
12
tests/large_values.txt
Normal 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
94
tests/literals.txt
Normal 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
46
tests/loops.txt
Normal 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
19
tests/lvalues.txt
Normal 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
5
tests/lvalues2.txt
Normal 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; }
|
||||
@@ -0,0 +1,6 @@
|
||||
a :: proc(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
a :: proc() {
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import "b";
|
||||
b :: proc() {
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
d :: proc(): int {
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,7 @@
|
||||
thing :: proc(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
not_thing :: proc(): int {
|
||||
return 0;
|
||||
}
|
||||
19
tests/multiple_errors_in_same_struct.txt
Normal file
19
tests/multiple_errors_in_same_struct.txt
Normal 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
16
tests/negate.txt
Normal 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
32
tests/nested_comments.txt
Normal 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;
|
||||
}
|
||||
9
tests/new_get_pointer.txt
Normal file
9
tests/new_get_pointer.txt
Normal 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
7
tests/nil.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
main :: proc(): int {
|
||||
a: *int;
|
||||
if a == nil {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
3028
tests/opengl_loader.txt
Normal file
3028
tests/opengl_loader.txt
Normal file
File diff suppressed because it is too large
Load Diff
129
tests/ops_on_basic_types_and_casts.txt
Normal file
129
tests/ops_on_basic_types_and_casts.txt
Normal 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
52
tests/packed_struct.txt
Normal 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;
|
||||
}
|
||||
22
tests/parse_decl_errors.txt
Normal file
22
tests/parse_decl_errors.txt
Normal 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
|
||||
8
tests/parse_decl_note.txt
Normal file
8
tests/parse_decl_note.txt
Normal 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
33
tests/pointers.txt
Normal 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
46
tests/raw_strings.txt
Normal 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;
|
||||
}
|
||||
10
tests/regression_const_assign_decls.txt
Normal file
10
tests/regression_const_assign_decls.txt
Normal 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;
|
||||
17
tests/regression_crash_on_decl_like_builtin.txt
Normal file
17
tests/regression_crash_on_decl_like_builtin.txt
Normal 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;
|
||||
}
|
||||
7
tests/regression_error_address_of_address.txt
Normal file
7
tests/regression_error_address_of_address.txt
Normal 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;
|
||||
}
|
||||
25
tests/regression_error_field_followed_by_invalid.txt
Normal file
25
tests/regression_error_field_followed_by_invalid.txt
Normal 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);
|
||||
}
|
||||
|
||||
20
tests/regression_error_handling_field_access.txt
Normal file
20
tests/regression_error_handling_field_access.txt
Normal 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;
|
||||
}
|
||||
26
tests/regression_error_handling_field_access2.txt
Normal file
26
tests/regression_error_handling_field_access2.txt
Normal 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;
|
||||
}
|
||||
18
tests/regression_incomplete_type.txt
Normal file
18
tests/regression_incomplete_type.txt
Normal 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;
|
||||
}
|
||||
12
tests/regression_note_after_if.txt
Normal file
12
tests/regression_note_after_if.txt
Normal 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;
|
||||
}
|
||||
10
tests/regression_return_null_pointer.txt
Normal file
10
tests/regression_return_null_pointer.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
A :: struct { i: int; }
|
||||
|
||||
thing :: proc(): *A {
|
||||
return nil;
|
||||
}
|
||||
|
||||
main :: proc(): int {
|
||||
result := :int(:ullong(thing()));
|
||||
return result;
|
||||
}
|
||||
6
tests/regression_same_named_agg_fields.txt
Normal file
6
tests/regression_same_named_agg_fields.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
// #failed: resolve
|
||||
// #error: duplicate field 'a' in aggregate type 'A'
|
||||
A :: struct {
|
||||
a: int;
|
||||
a: int;
|
||||
}
|
||||
4
tests/regression_same_named_proc_arguments.txt
Normal file
4
tests/regression_same_named_proc_arguments.txt
Normal 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
Reference in New Issue
Block a user