Examples
Learn GX by example. Each snippet is a complete, runnable program.
Basics
Hello World 01_hello_world.gx
// 01_hello_world.ec - The simplest EC program
// Build: ec examples/01_hello_world.ec -o build/01_hello_world.exe
fn main() {
var a:i32 = 100;
var b:i32 = 200;
var name:str = "Afan";
print("Hello, GXers!! {a} : {b} : {name}\n");
}
Variables 02_variables.gx
// 02_variables.ec - Variable declarations, types, and string interpolation
// Build: ec examples/02_variables.ec -o build/02_variables.exe
fn main() {
// Type inference with var
var a = 10;
var b = 3.14;
var name = "GX";
// Explicit types
var x:i32 = 100;
var y:f32 = 2.718;
var big:i64 = 9999999999;
var precise:f64 = 3.14159265358979;
// String interpolation
print("a={a}\n");
print("b={b}\n");
print("name={name}\n");
print("x={x} y={y}\n");
print("big={big}\n");
print("precise={precise}\n");
print("i32 as string: " + x.str() + "\n");
print("f64 as string: " + precise.str() + "\n");
// Assignment
x = x + 1;
print("x after +1: {x}\n");
}
Print And Strings 03_print_and_strings.gx
// 03_print_and_strings.ec - Print, string concatenation, interpolation, UTF-8
// Build: ec examples/03_print_and_strings.ec -o build/03_print_and_strings.exe
fn main() {
do_some()
do_some1()
// Basic print
print("Hello GXers!\n");
var s:str = "Family";
// String concatenation with +
var greeting = "Hello" + ", " + "GX {s}!!! \n";
print(greeting)
// String interpolation with {expr}
var x:i32 = 42;
var f:f32 = 3.14;
print("int={x} float={f}\n");
// .str() converts any type to string
var v = vec3{1.0, 2.0, 3.0};
print("vec3={v}\n");
print("vec3 via concat: " + v.str() + "\n");
// UTF-8 strings
var utf = "Hello UTF-8: cafe\n";
print(utf);
// Escape sequences
print("Tab:\there\n");
print("Quote: \"hello\"\n");
// String + number auto-converts
print("result=" + (10 + 20).str() + "\n");
}
Data Types
Control Flow 04_control_flow.gx
// 04_control_flow.ec - If/elif/else, while loops, for-range, for-each, collect
// Build: ec examples/04_control_flow.ec -o build/04_control_flow.exe
fn main() {
// --- If / elif / else ---
var score:i32 = 75;
var x:i32 = 10;
print("Helloo\n");
if (score >= 90) {
print("Grade: A\n");
} elif (score >= 80) {
print("Grade: B\n");
} elif (score >= 70) {
print("Grade: C\n");
} else {
print("Grade: F\n");
}
// --- While loop ---
var count:i32 = 0;
while (count < 5) {
print("count={count}\n");
count = count + 1;
}
// --- For-range (inclusive) ---
print("\nFor-range 1 to 5:\n");
for (i = 1:5) {
print(" i={i}\n");
}
// --- For-each over array ---
print("\nFor-each:\n");
var arr:i32[5] = {10, 20, 30, 40, 50};
for (var x in arr) {
print(" x={x}\n");
}
// --- For-each with where filter ---
print("\nFiltered (even only):\n");
var nums:i32[8] = {1, 2, 3, 4, 5, 6, 7, 8};
for (var n in nums) where (n % 2 == 0) {
print(" even={n}\n");
}
// --- Collect: build array from loop ---
var evens = for (n in nums) where (n % 2 == 0) collect n;
print("\nCollected evens ({evens.len()}):");
for (i = 0:3) {
print(" {evens.at(i)}");
}
print("\n");
// Collect with transform
var doubled = for (n in nums) where (n <= 4) collect n * 10;
print("Doubled small ({doubled.len()}):");
for (i = 0:3) {
print(" {doubled.at(i)}");
}
print("\n");
evens.free();
doubled.free();
}
Arrays 05_arrays.gx
// 05_arrays.ec - Fixed-size arrays: declaration, init, iteration
// Build: ec examples/05_arrays.ec -o build/05_arrays.exe
fn main() {
// Fixed-size array with initializer
var scores:i32[5] = {95, 82, 74, 88, 91};
var win:[]i32 = scores[0:3];
print("Winners:\n");
for (var s in win) {
print(" win {s}\n");
}
// Array with inferred size
var colors:f32[3] = {1.0, 0.0, 0.0};
print("\nRGB: {colors[0]}, {colors[1]}, {colors[2]}\n");
// Modify by index
scores[0] = 100;
print("\nUpdated first score: {scores[0]}\n");
// Iterate with range
print("\nAll scores after update:\n");
for (i = 0:4) {
print(" scores[{i}] = {scores[i]}\n");
}
}
Dynamic Arrays 06_dynamic_arrays.gx
// 06_dynamic_arrays.ec - array<T> dynamic container: init, push, sort, remove, for-each
// Build: ec examples/06_dynamic_arrays.ec -o build/06_dynamic_arrays.exe
fn main() {
// --- Static array for-each ---
print("Static array\n");
var week_days:str[7] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
for (item:str in week_days) {
print("Day: {item}\n");
}
// --- Dynamic array with initializer syntax ---
print("\nDynamic array (initializer syntax)\n");
var darr:array<str> = {"Afan", "Sanela", "Ajdin"};
defer darr.free();
// For-each works on dynamic arrays
for (var item in darr) {
print(" item: {item}\n");
}
// Multiple iterations work fine
print("\nSecond iteration with index:\n");
var cnt = 0;
for (var item in darr) {
print(" [{cnt}] {item}\n");
cnt = cnt + 1;
}
// Index-based loop also works
print("\nIndex-based loop:\n");
for (j = 0:darr.len()-1) {
print(" {darr.at(j)}\n");
}
// --- Dynamic array without initializer (auto-init) ---
var a:array<i32>;
defer a.free();
// Push elements
a.push(30);
a.push(10);
a.push(50);
a.push(20);
a.push(40);
print("\nAfter push: len={a.len()} cap={a.cap()}\n");
// Access elements
print("a[0]={a.at(0)} a[1]={a.at(1)} a[2]={a.at(2)}\n");
// For-each over i32 dynamic array
print("\nFor-each over i32 array:\n");
for (var n in a) {
print(" {n}\n");
}
// Sort
a.sort();
print("\nAfter sort:\n");
for (var n in a) {
print(" {n}\n");
}
// Remove (swap with last - O(1))
a.remove_swap(0);
print("\nAfter remove_swap(0): len={a.len()}\n");
for (var n in a) {
print(" {n}\n");
}
// Clear
a.clear();
print("\nAfter clear: len={a.len()}\n");
// --- Collect: create dynamic array from loop ---
var data:i32[6] = {5, 12, 3, 18, 7, 20};
var big = for (x in data) where (x >= 10) collect x;
print("\nCollected (>= 10): ");
for (var n in big) {
print("{n} ");
}
print("(len={big.len()})\n");
big.free();
print("\nDone.\n");
}
Structs 07_structs.gx
// 07_structs.ec - Structs, field access, extension methods
// Build: ec examples/07_structs.ec -o build/07_structs.exe
struct Player {
id:i32
name:str
score:f32
}
ex Player {
fn greet() {
print("Player {name} (id={id}) score={score}\n");
}
fn add_score(points:f32) {
score = score + points;
}
}
struct Vec2i {
x:i32
y:i32
}
ex Vec2i {
fn to_str:str() {
return "({x}, {y})";
}
}
fn main() {
// Create with initializer
var p = Player{1, "Alice", 0.0};
p.greet();
// Modify via extension method
p.add_score(100.5);
p.add_score(50.0);
p.greet();
// Direct field access
p.name = "Bob";
print("Renamed to: {p.name}\n");
// Custom struct with str conversion
var pos = Vec2i{10, 20};
print("Position: " + pos.to_str() + "\n");
}
Enums 08_enums.gx
// 08_enums.ec - Enums: declaration, comparison, branching
// Build: ec examples/08_enums.ec -o build/08_enums.exe
enum Direction {
North
South
East
West
}
enum Color {
Red = 0
Green = 1
Blue = 2
}
fn main() {
// Declare enum variables
var dir:Direction = East;
// Compare enum values
if (dir == North) {
print("Heading North\n");
} elif (dir == East) {
print("Heading East\n");
} elif (dir == South) {
print("Heading South\n");
} else {
print("Heading West\n");
}
// Enum to string (shows integer value)
print("East = {dir}\n");
// Another enum
var c:Color = Blue;
print("Blue = {c}\n");
}
Functions & Control
Vec Mat Math 09_vec_mat_math.gx
// 09_vec_mat_math.ec - Built-in vector and matrix types
// Build: ec examples/09_vec_mat_math.ec -o build/09_vec_mat_math.exe
fn main() {
// --- Vectors ---
var a = vec3{1.0, 2.0, 3.0};
var b = vec3{4.0, 5.0, 6.0};
// Vector addition
var c = a + b;
print("a + b = {c}\n");
// Scalar multiply
var d = a * 2.0;
print("a * 2 = {d}\n");
// Negate
var e = -a;
var len = 32;
for (i=0:len) {
print("i = {i}\n");
}
print("-a = {e}\n");
// Field access
print("a.x={a.x} a.y={a.y} a.z={a.z}\n");
// --- vec2 and vec4 ---
var v2 = vec2{10.0, 20.0};
print("vec2: {v2}\n");
var v4 = vec4{1.0, 0.0, 0.0, 1.0};
print("vec4: {v4}\n");
// --- Swizzle ---
var sw1 = a.xy;
print("a.xy = {sw1}\n");
var sw2 = a.zyx;
print("a.zyx = {sw2}\n");
var sw3 = v4.wz;
print("v4.wz = {sw3}\n");
var sw4 = v2.yx;
print("v2.yx = {sw4}\n");
// Repeat components
var sw5 = a.xx;
print("a.xx = {sw5}\n");
// --- Matrix ---
var M = mat4{
vec4{1,0,0,0},
vec4{0,1,0,0},
vec4{0,0,1,0},
vec4{0,0,0,1},
};
print("Identity: {M}\n");
}
Functions 10_functions.gx
// 10_functions.ec - Functions, return types, recursion
// Build: ec examples/10_functions.ec -o build/10_functions.exe
fn add:i32(a:i32, b:i32) {
return a + b;
}
fn larger:i32(a:i32, b:i32) {
if (a > b) {
return a;
}
return b;
}
fn factorial:i32(n:i32) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
fn greet(name:str) {
print("Hello, {name}!\n");
}
fn main() {
// Basic function calls
var sum = add(10, 20);
print("add(10, 20) = {sum}\n");
var m = larger(42, 17);
print("larger(42, 17) = {m}\n");
// Recursion
for (i = 1:8) {
print("{i}! = {factorial(i)}\n");
}
// Void function
greet("EC");
}
Bool 11_bool.gx
// 11_bool.ec - Boolean literals: true and false
// Build: ec examples/11_bool.ec -o build/11_bool.exe
fn main() {
var a:bool = true;
var b:bool = false;
print("a = {a}\n");
print("b = {b}\n");
if (a) {
print("a is true\n");
}
if (!b) {
print("b is false\n");
}
// Boolean logic
var c = a && b;
var d = a || b;
print("true && false = {c}\n");
print("true || false = {d}\n");
// Comparison produces bool
var x = 5;
var gt = x > 3;
print("5 > 3 = {gt}\n");
// Use in conditions directly
var done = false;
var count = 0;
while (!done) {
count = count + 1;
if (count == 3) {
done = true;
}
}
print("counted to {count}\n");
}
Input 12_input.gx
// Example: input() built-in function
// Reads a line from stdin, with an optional prompt string.
fn main() {
var name:str = input("What is your name? ");
print("Hello, {name}!\n");
var color:str = input("Favorite color? ");
print("{name} likes {color}\n");
// input() with no prompt
print("Type something: ");
var line:str = input();
print("You said: {line}\n");
}
Bitwise 13_bitwise.gx
// 13_bitwise.ec - Bitwise operators and hex literals
// Build: ec examples/13_bitwise.ec -o build/13_bitwise.exe
fn main() {
// --- Hex literals ---
var a:i32 = 0xFF;
var b:i32 = 0x0F;
var c:i32 = 0x0A;
print("Hex literals: a=0xFF={a}, b=0x0F={b}\n");
// --- Bitwise AND ---
var and_result:i32 = a & b & c;
print("\nBitwise AND: 0xFF & 0x0F = {and_result}\n");
// --- Bitwise OR ---
var or_result:i32 = 0xF0 | 0x0F;
print("Bitwise OR: 0xF0 | 0x0F = {or_result}\n");
// --- Bitwise XOR ---
var xor_result:i32 = 0xFF ^ 0x0F;
print("Bitwise XOR: 0xFF ^ 0x0F = {xor_result}\n");
// --- Bitwise NOT ---
var not_result:i32 = ~0;
print("Bitwise NOT: ~0 = {not_result}\n");
// --- Left shift ---
var lshift:i32 = 1 << 4;
print("Left shift: 1 << 4 = {lshift}\n");
// --- Right shift ---
var rshift:i32 = 256 >> 3;
print("Right shift: 256 >> 3 = {rshift}\n");
// --- Flags pattern ---
print("\n--- Flags pattern ---\n");
var FLAG_READ:u32 = 1 << 0;
var FLAG_WRITE:u32 = 1 << 1;
var FLAG_EXEC:u32 = 1 << 2;
var perms:u32 = FLAG_READ | FLAG_EXEC;
print("Permissions: {perms}\n");
print("Has READ: {perms & FLAG_READ}\n");
print("Has WRITE: {perms & FLAG_WRITE}\n");
print("Has EXEC: {perms & FLAG_EXEC}\n");
// Add write permission
perms = perms | FLAG_WRITE;
print("\nAfter adding WRITE: {perms}\n");
print("Has WRITE: {perms & FLAG_WRITE}\n");
// Remove exec permission (AND with inverted flag)
perms = perms & ~FLAG_EXEC;
print("\nAfter removing EXEC: {perms}\n");
print("Has EXEC: {perms & FLAG_EXEC}\n");
// Toggle read with XOR
perms = perms ^ FLAG_READ;
print("\nAfter toggling READ: {perms}\n");
print("Has READ: {perms & FLAG_READ}\n");
// --- Byte extraction ---
print("\n--- Byte extraction ---\n");
var val:i32 = 0xABCD;
var low:i32 = val & 0xFF;
var high:i32 = (val >> 8) & 0xFF;
print("0xABCD low byte: {low}\n");
print("0xABCD high byte: {high}\n");
// --- Bit counting (popcount) ---
print("\n--- Bit counting ---\n");
var num:i32 = 0xFF;
var count:i32 = 0;
var tmp:i32 = num;
for (i = 0:31) {
if (tmp & 1) {
count = count + 1;
}
tmp = tmp >> 1;
}
print("Bits set in 0xFF: {count}\n");
// --- Power of two check ---
print("\n--- Power of two check ---\n");
var vals:i32[6] = {1, 2, 3, 4, 16, 255};
for (var v in vals) {
var is_pow2:i32 = 0;
if (v & (v - 1)) {
is_pow2 = 0;
} else {
is_pow2 = 1;
}
print("{v} is power of 2: {is_pow2}\n");
}
print("\nDone.\n");
}
Advanced Features
Break Continue 21_break_continue.gx
// Break and Continue example
fn main() {
// Break: exit loop early
print("Break test: ");
for (i = 0:20) {
if (i > 4) {
break;
}
print("{i} ");
}
print("\n");
// Continue: skip even numbers
print("Continue test: ");
for (i = 0:10) {
if (i % 2 == 0) {
continue;
}
print("{i} ");
}
print("\n");
var a:i32 = 10;
a++;
a--;
++a;
--a;
print("a={a}\n");
// Break in while loop
print("While break: ");
var n:i32 = 0;
while (n < 100) {
if (n > 5) {
break;
}
print("{n} ");
n = n + 1;
}
print("\n");
// Continue in while loop
print("While continue: ");
var m:i32 = 0;
while (m < 10) {
m = m + 1;
if (m % 3 == 0) {
continue;
}
print("{m} ");
}
print("\n");
} Match 21_match.gx
// 21_match.ec - Match statement: clean multi-way branching
// Build: ec examples/21_match.ec -o build/21_match.exe
// Test 1: Match on integer with single values
fn test_int() {
var x:i32 = 2;
match (x) {
1: print("one\n")
2: print("two\n")
3: print("three\n")
default: print("other\n")
}
}
// Test 2: Match with comma-separated patterns
fn test_comma() {
var code:i32 = 5;
match (code) {
1, 2, 3: print("low\n")
4, 5, 6: print("mid\n")
7, 8, 9: print("high\n")
default: print("out of range\n")
}
}
// Test 3: Match with range
fn test_range() {
var score:i32 = 85;
match (score) {
0..59: print("F\n")
60..69: print("D\n")
70..79: print("C\n")
80..89: print("B\n")
90..100: print("A\n")
default: print("invalid\n")
}
}
// Test 4: Match on enum
enum Color { Red Green Blue }
fn test_enum() {
var c:Color = Green;
match (c) {
Red: print("red\n")
Green: print("green\n")
Blue: print("blue\n")
}
}
// Test 5: Match with block body
fn test_block() {
var n:i32 = 3;
match (n) {
1: {
print("one ");
print("(single)\n");
}
2, 3: {
print("two or three ");
print("(group)\n");
}
default: print("other\n")
}
}
fn main() {
print("--- int match ---\n");
test_int();
print("--- comma match ---\n");
test_comma();
print("--- range match ---\n");
test_range();
print("--- enum match ---\n");
test_enum();
print("--- block match ---\n");
test_block();
}
Func Ptr 22_func_ptr.gx
// Function pointer validation test
fn add:i32(a:i32, b:i32) {
return a + b;
}
fn negate:i32(x:i32) {
return 0 - x;
}
fn apply:i32(f:fn(i32):i32, val:i32) {
return f(val);
}
fn main() {
// Valid: assign function matching signature
var op:fn(i32, i32):i32 = add;
print("add(3,4) = {op(3, 4)}\n");
// Valid: pass function pointer as argument
var result:i32 = apply(negate, 42);
print("negate(42) = {result}\n");
// Call through function pointer
var f:fn(i32):i32 = negate;
print("f(10) = {f(10)}\n");
}
Increment 23_increment.gx
// Increment and Decrement operators
fn main() {
// Postfix
var a:i32 = 5;
a++;
print("a++ => {a}\n");
var b:i32 = 10;
b--;
print("b-- => {b}\n");
var h1:i32 = b<11?10:20;
print("h={h1}\n");
// Prefix
var c:i32 = 0;
++c;
++c;
++c;
c++;
--c;
c--;
print("++c x3 => {c}\n");
// Prefix vs postfix in expressions
var e:i32 = 5;
var f:i32 = e++;
print("postfix: e={e}, f={f}\n");
var g:i32 = 5;
var h:i32 = ++g;
print("prefix: g={g}, h={h}\n");
} Union 24_union.gx
// Example 24: Union Types
// Unions allow multiple fields to share the same memory — only one is valid at a time.
// Use cases: type punning, variant storage, memory-efficient tagged unions.
// --- Basic union: type punning ---
union IntFloat {
i: i32
f: f32
}
// --- Tagged union pattern: manual tag + union ---
enum ValueKind {
IntVal
FloatVal
StrVal
}
union ValueData {
i: i32
f: f32
s: str
}
union Actor {
id:i32
name:str
}
struct Value {
kind: ValueKind
data: ValueData
}
fn print_value(v: Value) {
match (v.kind) {
IntVal: print("int: {v.data.i}\n")
FloatVal: print("float: {v.data.f}\n")
StrVal: print("str: {v.data.s}\n")
}
}
// --- Color as packed bytes ---
union Color {
rgba: u32
bytes: u8[4]
}
fn main() {
// Type punning: reinterpret i32 bits as f32
var pun: IntFloat;
pun.i = 1065353216; // IEEE 754 for 1.0f
print("int bits: {pun.i}\n");
print("as float: {pun.f}\n");
// Tagged union: variant storage
var v1: Value;
v1.kind = IntVal;
v1.data.i = 42;
print_value(v1);
var v2: Value;
v2.kind = FloatVal;
v2.data.f = 3.14;
print_value(v2);
var v3: Value;
v3.kind = StrVal;
v3.data.s = "hello";
print_value(v3);
// Packed color: write as u32, read bytes
var c: Color;
c.rgba = 0xFF8040FF;
print("color rgba: {c.rgba}\n");
}
Fat Str 25_fat_str.gx
// Example 25: Fat Strings (ec_str)
// str is now { ptr, len } — O(1) length, proper comparison, safe iteration.
fn main() {
// Basic str with .len and .cstr
var s: str = "hello";
print("s = {s}\n");
print("s.len = {s.len}\n");
// String comparison (uses ec_str_eq, not pointer comparison!)
var a: str = "hello";
var b: str = "hello";
var c: str = "world";
if (a == b) {
print("a == b: true (correct!)\n");
}
if (a != c) {
print("a != c: true (correct!)\n");
}
// String concatenation
var greeting: str = "Hello, " + "EC!";
print("greeting = {greeting}\n");
print("greeting.len = {greeting.len}\n");
// String interpolation
var x: i32 = 42;
var msg: str = "The answer is {x}";
print("{msg}\n");
// Empty string
var empty: str = "";
print("empty.len = {empty.len}\n");
// Escape sequences — sizeof handles them correctly
var newline: str = "a\nb";
print("newline.len = {newline.len}\n");
print("\nAll fat string tests passed!\n");
}
Sort 25_sort.gx
// 25_sort.ec - Sort on all container types: fixed array, slice, array<T>
// Build: ec examples/25_sort.ec -o build/25_sort.exe
fn print_arr(label: str, s: []i32) {
print("{label}: ");
for (var x in s) {
print("{x} ");
}
print("\n");
}
fn main() {
// === Fixed array sort ===
var fixed:i32[6] = {42, 7, 99, 3, 55, 1};
print_arr("before fixed", fixed);
fixed.sort();
print_arr("after fixed", fixed);
// === Slice sort ===
var data:i32[8] = {80, 20, 60, 10, 90, 40, 70, 30};
var sl:[]i32 = data[2:6];
print_arr("before slice", sl);
sl.sort();
print_arr("after slice", sl);
print_arr("full data ", data);
// === Dynamic array sort ===
var dyn:array<i32>;
dyn.init();
dyn.push(33);
dyn.push(11);
dyn.push(77);
dyn.push(22);
dyn.push(55);
// print via slice
var ds:[]i32 = dyn;
print_arr("before dyn ", ds);
dyn.sort();
var ds2:[]i32 = dyn;
print_arr("after dyn ", ds2);
dyn.free();
} Sizeof 26_sizeof.gx
// sizeof expression examples
struct Point {
x: f32
y: f32
}
struct Color {
r: u8
g: u8
b: u8
a: u8
}
fn main() {
// sizeof with built-in types
print("sizeof(i8) = {sizeof(i8)}\n");
print("sizeof(i16) = {sizeof(i16)}\n");
print("sizeof(i32) = {sizeof(i32)}\n");
print("sizeof(i64) = {sizeof(i64)}\n");
print("sizeof(f32) = {sizeof(f32)}\n");
print("sizeof(f64) = {sizeof(f64)}\n");
print("sizeof(bool) = {sizeof(bool)}\n");
// sizeof with user-defined structs (via expression)
var p:Point = Point{1.0, 2.0};
print("sizeof(Point) = {sizeof(p)}\n");
var c:Color = Color{255, 128, 0, 255};
print("sizeof(Color) = {sizeof(c)}\n");
// sizeof with vec types
print("sizeof(vec2) = {sizeof(vec2)}\n");
print("sizeof(vec3) = {sizeof(vec3)}\n");
print("sizeof(vec4) = {sizeof(vec4)}\n");
// sizeof in expressions
var arr_size:i64 = 10 * sizeof(i32);
print("10 * sizeof(i32) = {arr_size}\n");
} Slice 26_slice.gx
// Example 26: Slices and Safe Arrays
// Arrays automatically have .len and work like slices.
fn sum:i32(data: []i32) {
var total: i32 = 0;
for (var x in data) {
total += x;
}
return total;
}
fn print_slice(data: []i32) {
print("[");
for (var x in data) {
print("{x} ");
}
print("]\n");
}
fn main() {
var arr: i32[5] = {10, 20, 30, 40, 50};
// Arrays have .len — compile-time constant, no struct needed
print("arr.len = {arr.len}\n");
// Arrays implicitly convert to slices at function boundaries
print("sum(arr) = {sum(arr)}\n");
print("arr = ");
print_slice(arr);
// Subslicing works directly on arrays
var mid: []i32 = arr[1:4];
print("arr[1:4] = ");
print_slice(mid);
print("mid.len = {mid.len}\n");
// Slices work the same way
var s: []i32 = arr;
print("s[0] = {s[0]}\n");
print("s.len = {s.len}\n");
// Subslice of subslice
var inner: []i32 = mid[0:2];
print("inner = ");
print_slice(inner);
print("\nAll tests passed!\n");
}
Bounds Check 27_bounds_check.gx
// Example 27: Bounds Checking
// Out-of-bounds access panics in debug mode (default).
// Use -O1 or higher to disable checks for release builds.
fn main() {
// Fixed array bounds check
var arr: i32[3] = {10, 20, 30};
print("arr[0] = {arr[0]}\n");
print("arr[2] = {arr[2]}\n");
print("arr.len = {arr.len}\n");
// Slice bounds check
var s: []i32 = arr;
print("s[0] = {s[0]}\n");
print("s[2] = {s[2]}\n");
// This will PANIC:
print("About to access s[10]...\n");
print("s[10] = {s[10]}\n");
print("This should never print!\n");
}
Const 28_const.gx
// Example 28: Const declarations and constant folding
// Global constants (no type annotation - inferred)
const PI = 3.14159265358979;
const TAU = PI * 2.0;
const SCREEN_WIDTH = 1920;
const SCREEN_HEIGHT = 1080;
const ASPECT_RATIO = 16.0 / 9.0;
// Global constants with type annotation
const MAX_ENTITIES:i32 = 1024;
const BUFFER_SIZE:i64 = MAX_ENTITIES * 64;
// Const expressions with bitwise ops
const FLAG_READ = 1;
const FLAG_WRITE = 2;
const FLAG_EXEC = 4;
const FLAG_ALL = FLAG_READ | FLAG_WRITE | FLAG_EXEC;
// Boolean consts
const DEBUG_MODE = false;
const IS_WIDE = SCREEN_WIDTH > 1000;
fn main() {
print("=== Const Declarations ===");
// Using global consts
print("PI = {PI}");
print("TAU = {TAU}");
print("Screen: {SCREEN_WIDTH}x{SCREEN_HEIGHT}");
print("Aspect ratio: {ASPECT_RATIO}");
print("Max entities: {MAX_ENTITIES}");
print("Buffer size: {BUFFER_SIZE}");
print("");
print("=== Const Folding ===");
// Const folding: these should be computed at compile time
const AREA = SCREEN_WIDTH * SCREEN_HEIGHT;
print("Screen area: {AREA}");
const HALF_PI = PI / 2.0;
print("PI/2 = {HALF_PI}");
// Bitwise const
print("FLAG_ALL = {FLAG_ALL}");
// Boolean const
print("Debug mode: {DEBUG_MODE}");
print("Is wide: {IS_WIDE}");
print("");
print("=== Const in Expressions ===");
// Const used in regular expressions
var x = SCREEN_WIDTH / 2;
var y = SCREEN_HEIGHT / 2;
print("Center: ({x}, {y})");
// Const in loop bounds
const LOOP_COUNT = 5;
for (i=0:LOOP_COUNT) {
print(" i = {i}");
}
print("");
print("=== Negative and Unary ===");
const NEG_ONE = -1;
const NOT_FLAG = ~FLAG_READ;
print("NEG_ONE = {NEG_ONE}");
print("~FLAG_READ = {NOT_FLAG}");
print("Done!");
}
Compile-Time
Comptime If 29_comptime_if.gx
// Example 29: Compile-time conditional compilation (#if)
// Platform detection with @os
#if (@os == "windows") {
const PLATFORM = "Windows";
}
#else {
const PLATFORM = "Other";
}
fn main() {
print("Platform: {PLATFORM}");
// Statement-level #if with @os
#if (@os == "windows") {
print("Running on Windows");
}
#else {
print("Running on non-Windows");
}
// #if with user const
const ENABLE_FEATURE = true;
#if (ENABLE_FEATURE) {
print("Feature enabled");
}
// @debug check (false unless --debug flag)
#if (@debug) {
print("Debug mode ON");
}
#else {
print("Debug mode OFF");
}
// @opt level check
#if (@opt > 0) {
print("Optimized build");
}
#else {
print("Unoptimized build");
}
print("Done!");
}
Comptime Fn 30_comptime_fn.gx
// Example 30: Compile-time functions (#fn)
// Align a size up to the given alignment
#fn align_up:i32(size:i32, align:i32) {
return (size + align - 1) & ~(align - 1);
}
// Create a bitmask with N bits set
#fn make_bitmask:i32(bits:i32) {
if (bits <= 0) { return 0; }
if (bits >= 32) { return -1; }
return (1 << bits) - 1;
}
// Compile-time fibonacci
#fn fib:i32(n:i32) {
if (n <= 1) { return n; }
return fib(n - 1) + fib(n - 2);
}
// Compile-time max
#fn max:i32(a:i32, b:i32) {
if (a > b) { return a; }
return b;
}
// Compile-time power
#fn pow:i32(base:i32, exp:i32) {
var result:i32 = 1;
var i:i32 = 0;
while (i < exp) {
result = result * base;
i = i + 1;
}
return result;
}
// All evaluated at compile time — no runtime computation!
const BUF_SIZE = align_up(100, 64);
const CHANNEL_MASK = make_bitmask(8);
const PIXEL_MASK = make_bitmask(24);
const FIB_10 = fib(10);
const MAX_DIM = max(1920, 1080);
const TWO_TO_10 = pow(2, 10);
const COMBINED = align_up(FIB_10, 16);
fn main() {
print("=== Compile-Time Functions (#fn) ===");
print("align_up(100, 64) = {BUF_SIZE}");
print("make_bitmask(8) = {CHANNEL_MASK}");
print("make_bitmask(24) = {PIXEL_MASK}");
print("fib(10) = {FIB_10}");
print("max(1920, 1080) = {MAX_DIM}");
print("pow(2, 10) = {TWO_TO_10}");
print("align_up(fib(10), 16) = {COMBINED}");
print("Done!");
}
Comptime For 31_comptime_for.gx
// Example 31: Compile-time loop unrolling with #for
// #for unrolls the loop at compile time, substituting the iteration
// variable with literal integer values. No runtime loop overhead.
fn main() {
// Basic #for — unrolls to 5 print calls
print("=== Compile-Time Loop Unrolling (#for) ===");
#for (i=0:5) {
print("iteration {i}");
}
// #for with expressions using the loop variable
var sum:i32 = 0;
#for (i=1:6) {
sum += i * i;
}
print("sum of squares 1..5 = {sum}");
// Nested #for — generates 3x3 = 9 iterations
#for (row=0:3) {
#for (col=0:3) {
var val:i32 = row * 3 + col;
print(" ({row},{col}) = {val}");
}
}
// #for with const bounds
const N = 4;
#for (i=0:N) {
print("channel {i}");
}
print("Done!");
}
Struct Comptime 32_struct_comptime.gx
// Example 32: Struct and Enum level comptime expansion (Phase 5)
// Struct with conditional fields based on platform
struct PlatformInfo {
name: str
#if (@os == "windows") {
handle: i64
registry_key: str
} #else {
fd: i32
path: str
}
version: i32
}
// Struct with generated fields via #for
struct Pixel {
#for (i=0:4) {
channel_i: f32
}
}
// Enum with conditional members
enum LogLevel {
Error
Warning
Info
#if (@debug) {
Debug
Trace
}
}
fn main() {
print("=== Struct/Enum Comptime Expansion (Phase 5) ===");
// PlatformInfo has platform-specific fields
var info: PlatformInfo;
info.name = "test";
info.version = 1;
info.handle = 42;
info.registry_key = "HKLM";
print("name = {info.name}");
print("version = {info.version.str()}");
print("handle = {info.handle.str()}");
print("registry_key = {info.registry_key}");
// Pixel has channel_0 through channel_3 (generated by #for)
var px: Pixel;
px.channel_0 = 1.0;
px.channel_1 = 0.5;
px.channel_2 = 0.25;
px.channel_3 = 1.0;
print("pixel = ({px.channel_0.str()}, {px.channel_1.str()}, {px.channel_2.str()}, {px.channel_3.str()})");
// LogLevel enum — Debug/Trace only exist in debug builds
var level: LogLevel = Error;
print("log level = {level.str()}");
print("Done!");
}
Reflection 33_reflection.gx
// Example 33: Compile-time reflection (Phase 6)
struct Point {
x: f32
y: f32
z: f32
}
struct Node {
value: i32
next: *Node
}
enum Color { Red Green Blue }
fn main() {
print("=== Compile-Time Reflection (Phase 6) ===\n");
// --- Struct field reflection ---
print("Point has {@fields(Point)} fields:\n");
#for (i=0:@fields(Point)) {
print(" {@field(Point, i)}: {@field_type(Point, i)}\n");
}
// --- Field detail intrinsics ---
print("Node has {@fields(Node)} fields:");
#for (i=0:@fields(Node)) {
print(" {@field(Node, i)}: ptr={@field_is_ptr(Node, i)}\n");
}
// --- Enum member reflection ---
print("Color has {@members(Color)} members:\n");
#for (i=0:@members(Color)) {
print(" {@member(Color, i)}");
}
// --- Type meta ---
print("@type_kind(Point) = {@type_kind(Point)}\n");
print("@type_kind(Color) = {@type_kind(Color)}\n");
print("@type_name(Point) = {@type_name(Point)}\n");
// Note: Function reflection (@params, @param, @return_type) works
// but requires multi-file module setup (single-file function
// declarations have a pre-existing resolver limitation)
print("Done!");
}
Build Directives 34_build_directives.gx
// Example 34: Build directives (Phase 7)
// @link, @cflags, @ldflags make .ec files self-contained.
// Build directives — these inject linker/compiler flags without CLI args
@link("ucrtbase")
// Platform-conditional linking via #if
#if (@os == "windows") {
@link("kernel32")
}
fn main() {
print("=== Build Directives (Phase 7) ===");
print("@link and @cflags are collected from source");
print("No CLI flags needed for linking!");
print("Done!");
}
Templates 35_templates.gx
// Example 35: Compile-time templates (Phase 8)
// #type T declares a type parameter — monomorphized at compile time.
#type T
struct Pair {
first: T
second: T
}
fn main() {
print("=== Compile-Time Templates (Phase 8) ===");
// Pair<i32> — generates struct Pair_i32 { int32_t first; int32_t second; }
var pi: Pair<i32>;
pi.first = 10;
pi.second = 20;
print("Pair<i32>: ({pi.first.str()}, {pi.second.str()})");
// Pair<i64> — generates struct Pair_i64 { int64_t first; int64_t second; }
var pl: Pair<i64>;
pl.first = 100;
pl.second = 200;
print("Pair<i64>: ({pl.first.str()}, {pl.second.str()})");
var pf: Pair<f32>;
pf.first = 100.32;
pf.second = 200.32;
print("Pair<f32>: ({pf.first.str()}, {pf.second.str()})");
var ps: Pair<str>;
ps.first = "Afan";
ps.second = "Olovcic";
print("Pair<f32>: ({ps.first.str()}, {ps.second.str()})");
{
var ps:Pair< str >;
ps.first = "Sanela";
ps.second = "Gluhovic";
print("Pair<f32>: ({ps.first.str()}, {ps.second.str()})");
}
print("Done!");
}
Standard Library
Pointers 36_pointers.gx
// Example 36: Pointer arithmetic
fn main() {
print("=== Pointer Arithmetic ===");
// Basic dereference
var x:i32 = 42;
var p:*i32 = &x;
print("*p = {(*p).str()}");
*p = 99;
print("after *p=99: x = {x.str()}#\n");
// Pointer arithmetic: take address, add offset
var a:i32 = 10;
var b:i32 = 20;
var c:i32 = 30;
a+=10;
a++;
a+=0xFF;
var pa:*i32 = &a;
// Test pointer + int type
var pb:*i32 = pa + 1;
print("pa+1 deref = {(*pb).str()}");
// Pointer difference
var diff:i64 = pb - pa;
print("pb - pa = {diff.str()}");
// Pointer indexing
print("pa[0] = {pa[0].str()}");
print("Done!");
}
Main Args 37_main_args.gx
// Example 37: Main with string arguments
// Usage: gx 37_main_args.gx -o args.exe && args.exe hello world
fn main(args: str[]) {
print("Got {args.len} arguments:\n");
for (var arg in args) {
print(" - {arg}\n");
}
}
Par For 37_par_for.gx
// Example 37: Parallel For (par for)
// Uses OpenMP under the hood — requires -O1+ (clang/gcc) for actual parallelism
// With TCC (default), runs sequentially (graceful degradation)
fn main() {
var data:i32[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Parallel for-range: each iteration is independent
par for (i = 0:9) {
data[i] = data[i] * 2;
print("{data[i]}\n");
}
// Print results
/*for (i = 0:9) {
print("{data[i]}\n");
}*/
}
Strings 38_strings.gx
// 38_strings.gx — String method tests
fn main() {
var s = " Hello, World! "
// ── trim ─────────────────────────────────
var trimmed = s.trim()
var trim_l = s.trim_left()
var trim_r = s.trim_right()
print("trim: '" + trimmed + "'\n")
print("trim_left: '" + trim_l + "'\n")
print("trim_right: '" + trim_r + "'\n")
var hw = s.trim()
// ── find / contains ──────────────────────
var needle1 = "World"
var needle2 = "xyz"
var needle3 = "l"
print("find World: {hw.find(needle1)}\n")
print("find xyz: {hw.find(needle2)}\n")
print("find_last l: {hw.find_last(needle3)}\n")
print("contains Hello: {hw.contains(needle1)}\n")
print("contains xyz: {hw.contains(needle2)}\n")
// ── starts_with / ends_with ──────────────
var prefix = "Hello"
var suffix = "!"
print("starts_with Hello: {hw.starts_with(prefix)}\n")
print("ends_with !: {hw.ends_with(suffix)}\n")
// ── sub ──────────────────────────────────
var sub1 = hw.sub(0, 5)
var sub2 = hw.sub(7)
print("sub(0,5): '" + sub1 + "'\n")
print("sub(7): '" + sub2 + "'\n")
// ── upper / lower ────────────────────────
var up = hw.upper()
var lo = hw.lower()
print("upper: '" + up + "'\n")
print("lower: '" + lo + "'\n")
// ── replace ──────────────────────────────
var old_s = "World"
var new_s = "GX"
var rep = hw.replace(old_s, new_s)
print("replace: '" + rep + "'\n")
// ── count ────────────────────────────────
var cnt = hw.count(needle3)
print("count l: {cnt}\n")
// ── repeat ───────────────────────────────
var dash_str = "-"
var dash = dash_str.repeat(20)
print(dash + "\n")
// ── split ────────────────────────────────
var csv = "one,two,three,four"
var delim = ","
var parts = csv.split(delim)
print("split count: {parts.len}\n")
for (var p in parts) {
print(" part: '" + p + "'\n")
}
// ── chaining ─────────────────────────────
var input_str = " HELLO world "
var hello = "hello"
var hi = "hi"
var result = input_str.trim().lower().replace(hello, hi)
print("chained: '" + result + "'\n")
// ── string interpolation to var ──────────
var name = "GX"
var greeting:str = "Hello {name}!"
print(greeting + "\n")
}
Io 39_io.gx
// 39_io.gx - Test the io module
import io.io
import io.file
import io.fs
import io.path
fn main() {
// --- Console I/O ---
println("=== Console I/O ===")
println("Hello from println!")
eprintln("This goes to stderr")
// --- Path utilities ---
println("\n=== Path Utilities ===")
var p = "src/frontend/parser/parser.cpp"
print(" path: ") println(p)
print(" dirname: ") println(dirname(p))
print(" basename: ") println(basename(p))
print(" extension: ") println(extension(p))
print(" stem: ") println(stem(p))
var win = "C:\\Users\\test\\file.txt"
print(" win path: ") println(win)
print(" dirname: ") println(dirname(win))
print(" basename: ") println(basename(win))
print(" is_absolute('/usr/bin'): ")
if (is_absolute("/usr/bin")) { println("true") } else { println("false") }
print(" is_absolute('C:\\foo'): ")
if (is_absolute("C:\\foo")) { println("true") } else { println("false") }
print(" is_absolute('relative'): ")
if (is_absolute("relative")) { println("true") } else { println("false") }
print(" join('foo','bar'): ") println(join("foo", "bar"))
print(" join('foo/','bar'): ") println(join("foo/", "bar"))
// --- Filesystem ---
println("\n=== Filesystem ===")
print(" exists('examples/39_io.gx'): ")
if (exists("examples/39_io.gx")) { println("true") } else { println("false") }
print(" is_file('examples/39_io.gx'): ")
if (is_file("examples/39_io.gx")) { println("true") } else { println("false") }
print(" is_dir('examples'): ")
if (is_dir("examples")) { println("true") } else { println("false") }
print(" is_file('nonexistent'): ")
if (is_file("nonexistent")) { println("true") } else { println("false") }
var sz = file_size("examples/39_io.gx")
print(" file_size: ") print("{sz}") println(" bytes")
// --- File I/O ---
println("\n=== File I/O ===")
// Write a test file
var ok = write_all("_test_io.txt", "Hello from GX io module!\nLine 2\n")
print(" write_all: ") if (ok) { println("ok") } else { println("failed") }
// Read it back
var content = read_all("_test_io.txt")
print(" read_all: ") print(content)
// Append to it
ok = append_all("_test_io.txt", "Line 3 appended\n")
print(" append: ") if (ok) { println("ok") } else { println("failed") }
// Read again
content = read_all("_test_io.txt")
print(" after append:\n") print(content)
// Low-level file API
var f = file_open("_test_io.txt", "r")
if (f != 0) {
var pos = file_tell(f)
print(" tell at start: ") println("{pos}")
file_close(f)
}
// Clean up test file
ok = remove_file("_test_io.txt")
print(" remove: ") if (ok) { println("ok") } else { println("failed") }
print(" exists after remove: ")
if (exists("_test_io.txt")) { println("true") } else { println("false") }
// make_dir / remove_dir
ok = make_dir("_test_dir")
print("\n make_dir: ") if (ok) { println("ok") } else { println("failed") }
print(" is_dir: ") if (is_dir("_test_dir")) { println("true") } else { println("false") }
ok = remove_dir("_test_dir")
print(" remove_dir:") if (ok) { println("ok") } else { println("failed") }
println("\n=== Done ===")
}
Random 40_random.gx
// 40_random.gx - Test random and noise modules
import random.random
import random.noise
fn main() {
// --- Random numbers ---
print("=== Random (default seed) ===\n")
print(" rand_int(100): ") print("{rand_int(100)}") print("\n")
print(" rand_int(100): ") print("{rand_int(100)}") print("\n")
print(" rand_range(10,20): ") print("{rand_range(10, 20)}") print("\n")
print(" rand_f32(): ") print("{rand_f32()}") print("\n")
print(" rand_bool(): ")
if (rand_bool()) { print("true\n") } else { print("false\n") }
// --- Seeded (deterministic) ---
print("\n=== Seeded (42) ===\n")
seed(42)
print(" rand_int(100): ") print("{rand_int(100)}") print("\n")
print(" rand_int(100): ") print("{rand_int(100)}") print("\n")
// Same seed = same sequence
print("\n=== Seeded (42) again ===\n")
seed(42)
print(" rand_int(100): ") print("{rand_int(100)}") print("\n")
print(" rand_int(100): ") print("{rand_int(100)}") print("\n")
// --- Float range ---
print("\n=== Float range ===\n")
seed(123)
var i:i32 = 0
while (i < 5) {
var v:f32 = rand_f32_range(-1.0, 1.0)
print(" rand_f32_range(-1,1): ") print("{v}") print("\n")
i = i + 1
}
// --- Simplex noise ---
print("\n=== Simplex Noise ===\n")
print(" simplex1(0.5): ") print("{simplex1(0.5)}") print("\n")
print(" simplex1(1.0): ") print("{simplex1(1.0)}") print("\n")
print(" simplex1(1.5): ") print("{simplex1(1.5)}") print("\n")
print(" simplex2(0.5, 0.5): ") print("{simplex2(0.5, 0.5)}") print("\n")
print(" simplex2(1.0, 2.0): ") print("{simplex2(1.0, 2.0)}") print("\n")
print(" simplex3(0.5, 0.5, 0.5): ") print("{simplex3(0.5, 0.5, 0.5)}") print("\n")
print(" simplex4(1,2,3,4): ") print("{simplex4(1.0, 2.0, 3.0, 4.0)}") print("\n")
// --- fBm ---
print("\n=== Fractal Brownian Motion ===\n")
print(" fbm2(0.5, 0.5, 4, 2.0, 0.5): ") print("{fbm2(0.5, 0.5, 4, 2.0, 0.5)}") print("\n")
print(" fbm3(1, 2, 3, 6, 2.0, 0.5): ") print("{fbm3(1.0, 2.0, 3.0, 6, 2.0, 0.5)}") print("\n")
// --- 2D noise map (ASCII) ---
print("\n=== 2D Noise Map (10x5) ===\n")
var y:i32 = 0
while (y < 5) {
var x:i32 = 0
while (x < 20) {
var n:f32 = simplex2(x * 0.2, y * 0.2)
if (n > 0.3) { print("#") }
else if (n > 0.0) { print("+") }
else if (n > -0.3) { print(".") }
else { print(" ") }
x = x + 1
}
print("\n")
y = y + 1
}
print("\n=== Done ===\n")
}
Out Params 41_out_params.gx
// Example 41: Out Parameters & Const-by-Default Pointers
//
// GX pointer parameters are read-only (const) by default.
// Use 'out' to mark parameters that the function will modify.
// GX functions cannot return pointers — use 'out' params instead.
struct Point {
x: f32
y: f32
}
struct Result {
value: f32
ok: bool
}
// 'out' pointer param: function CAN modify what the pointer points to
fn init_point(out p: *Point, x: f32, y: f32) {
p.x = x
p.y = y
}
fn scale_point(out p: *Point, factor: f32) {
p.x = p.x * factor
p.y = p.y * factor
}
// No 'out': pointer is read-only (const Point* in C)
fn print_point(p: *Point) {
print("({p.x.str()}, {p.y.str()})\n")
// p.x = 99.0 ← compile error: Cannot write through read-only pointer
}
// out value param: multi-return pattern
// 'out result:f32' becomes 'float*' in C
fn divide:bool(a: f32, b: f32, out result: f32) {
if (b == 0.0) { return false }
*result = a / b
return true
}
// out struct param: fill a result struct
fn compute(a: f32, b: f32, out r: *Result) {
if (b == 0.0) {
r.ok = false
r.value = 0.0
} else {
r.ok = true
r.value = a / b
}
}
fn main() {
// === Out pointer param: init and modify ===
var pt = Point{0.0, 0.0}
init_point(&pt, 3.0, 4.0)
print("After init: ")
print_point(&pt)
scale_point(&pt, 2.0)
print("After scale: ")
print_point(&pt)
// === Out value param (multi-return) ===
var result: f32 = 0.0
if (divide(10.0, 3.0, &result)) {
print("10 / 3 = {result.str()}\n")
}
if (!divide(5.0, 0.0, &result)) {
print("Division by zero caught!\n")
}
// === Out struct param ===
var r = Result{0.0, false}
compute(10.0, 4.0, &r)
if (r.ok) {
print("10 / 4 = {r.value.str()}\n")
}
}
Typedef 42_typedef.gx
// Example 42: Type Aliases
//
// `type NewName:ExistingType` creates a type alias.
// The alias is interchangeable with the original type.
// Emits a C `typedef` — zero runtime cost.
// Alias to built-in types
type byte:u8
type size:u64
type real:f32
// Alias to pointer type
type cstring:*c_char
struct Point {
x: real
y: real
}
type Vec2D:Point
fn distance:real(a: *Vec2D, b: *Vec2D) {
var dx:real = b.x - a.x
var dy:real = b.y - a.y
return dx * dx + dy * dy
}
fn main() {
var b:byte = 255
var s:size = 1024
var r:real = 3.14
print("byte: {b.str()}\n")
print("size: {s.str()}\n")
print("real: {r.str()}\n")
var p1 = Vec2D{1.0, 2.0}
var p2 = Vec2D{4.0, 6.0}
var d = distance(&p1, &p2)
print("distance^2: {d.str()}\n")
} Microaudio 44_microaudio.gx
// Example 44: Microaudio
//
// Minimal audio playback using the microaudio module.
// Loads and plays WAV files.
//
// Run: gx examples/44_microaudio.gx -I modules -o build/audio_test.exe
import microaudio.audio
fn main() {
audio_init()
defer audio_shutdown()
// Load a WAV file (place a .wav file next to the executable)
var snd = audio_load("test.wav")
if (snd < 0) {
print("Could not load test.wav\n")
print("Place a WAV file named test.wav in the working directory.\n")
return
}
print("Sound loaded (id={snd.str()})\n")
// Set volume to 80%
audio_set_volume(snd, 0.8)
// Play the sound
audio_play(snd)
print("Playing... press Enter to stop.\n")
input()
audio_stop(snd)
audio_free(snd)
print("Done.\n")
}
Json 45_json.gx
// 45_json.gx - JSON module example
// Demonstrates parsing, querying, building, and serializing JSON
import json
fn main() {
// ---- Parsing JSON ----
var text = "{\"name\": \"Alice\", \"age\": 30, \"scores\": [95, 87, 92], \"active\": true}"
var doc = json.gx_json_parse(text.cstr, text.len, 0)
if (doc == 0) {
print("Failed to parse JSON\n")
return
}
defer json.gx_json_free(doc)
var r = json.gx_json_root(doc)
// ---- Reading values ----
var name = json.gx_json_get_str(json.gx_json_obj_get(r, "name"))
var age = json.gx_json_get_int(json.gx_json_obj_get(r, "age"))
var active = json.gx_json_get_bool(json.gx_json_obj_get(r, "active"))
print("Name: {name}\n")
print("Age: {age}\n")
print("Active: {active}\n")
// ---- Array access ----
var scores = json.gx_json_obj_get(r, "scores")
print("Scores:\n")
// Array access by index
var s0 = json.gx_json_get_int(json.gx_json_arr_get(scores, 0))
var s1 = json.gx_json_get_int(json.gx_json_arr_get(scores, 1))
var s2 = json.gx_json_get_int(json.gx_json_arr_get(scores, 2))
print(" [0] = {s0}\n")
print(" [1] = {s1}\n")
print(" [2] = {s2}\n")
// ---- Type inspection ----
var name_type = json.gx_json_type_desc(json.gx_json_obj_get(r, "name"))
var age_type = json.gx_json_type_desc(json.gx_json_obj_get(r, "age"))
var scores_type = json.gx_json_type_desc(scores)
print("Type of name: {name_type}\n")
print("Type of age: {age_type}\n")
print("Type of scores: {scores_type}\n")
// ---- Serialize back (pretty) ----
var pretty = json.gx_json_write(doc, json.WRITE_PRETTY)
print("\nPretty printed:\n{pretty}\n")
// ---- Build JSON from scratch ----
print("--- Building JSON ---\n")
var mdoc = json.gx_json_new_doc()
defer json.gx_json_mut_free(mdoc)
var obj = json.gx_json_new_obj(mdoc)
json.gx_json_set_root(mdoc, obj)
json.gx_json_obj_add_str(mdoc, obj, "language", "GX")
json.gx_json_obj_add_int(mdoc, obj, "version", 2)
json.gx_json_obj_add_bool(mdoc, obj, "fast", true)
json.gx_json_obj_add_float(mdoc, obj, "pi", 3.14159)
// Nested array
var arr = json.gx_json_obj_add_arr(mdoc, obj, "features")
json.gx_json_arr_add_str(mdoc, arr, "transpiles to C")
json.gx_json_arr_add_str(mdoc, arr, "zero-cost abstractions")
json.gx_json_arr_add_str(mdoc, arr, "yyjson powered")
// Nested object
var meta = json.gx_json_obj_add_obj(mdoc, obj, "meta")
json.gx_json_obj_add_str(mdoc, meta, "author", "GX Team")
json.gx_json_obj_add_int(mdoc, meta, "year", 2026)
var result = json.gx_json_mut_write(mdoc, json.WRITE_PRETTY)
print("{result}\n")
}
Time 46_time.gx
// 46_time.gx - Time module example
// Demonstrates clock, date/time, formatting, benchmarking, and sleep
import time
fn main() {
// ---- Current date and time ----
var now = time.gx_time_unix()
var y = time.gx_time_year(now)
var mo = time.gx_time_month(now)
var d = time.gx_time_day(now)
var h = time.gx_time_hour(now)
var mi = time.gx_time_minute(now)
var s = time.gx_time_second(now)
print("Current local time: {y}-{mo}-{d} {h}:{mi}:{s}\n")
// UTC equivalent
var uy = time.gx_time_utc_year(now)
var umo = time.gx_time_utc_month(now)
var ud = time.gx_time_utc_day(now)
var uh = time.gx_time_utc_hour(now)
print("Current UTC time: {uy}-{umo}-{ud} {uh}:{mi}:{s}\n")
// ---- Formatting ----
var formatted = time.gx_time_format(now, "%Y-%m-%d %H:%M:%S")
print("Formatted (local): {formatted}\n")
var formatted_utc = time.gx_time_format_utc(now, "%Y-%m-%d %H:%M:%S")
print("Formatted (UTC): {formatted_utc}\n")
// Day of week
var wd = time.gx_time_weekday(now)
var day_name = time.gx_time_format(now, "%A")
print("Weekday: {wd} ({day_name})\n")
// ---- Benchmarking ----
print("\n--- Benchmark ---\n")
var t0 = time.gx_time_now_ns()
// Do some work
var sum = 0
for (i = 0 : 999999) {
sum = sum + i
}
var t1 = time.gx_time_now_ns()
var ms = time.gx_time_elapsed_ms(t0, t1)
var us = time.gx_time_elapsed_us(t0, t1)
print("Sum of 0..999999 = {sum}\n")
print("Elapsed: {ms} ms ({us} us)\n")
// ---- Sleep ----
print("\n--- Sleep test ---\n")
var s0 = time.gx_time_now_ns()
time.gx_time_sleep_ms(100)
var s1 = time.gx_time_now_ns()
var slept = time.gx_time_elapsed_ms(s0, s1)
print("Slept ~100ms, measured: {slept} ms\n")
// ---- Build timestamp ----
var epoch = time.gx_time_make(2026, 1, 1, 0, 0, 0)
var new_year = time.gx_time_format(epoch, "%Y-%m-%d %H:%M:%S (%A)")
print("\nNew Year 2026: {new_year}\n")
}
Xml 47_xml.gx
// 47_xml.gx - XML parsing, navigation, and building example
// Build: gx 47_xml.gx -I modules -o build/47_xml.exe
import xml
fn main() {
// ---- Parse XML from string ----
var data = "<library name='City Library'><book id='1'><title>The Rust Programming Language</title><author>Steve Klabnik</author><year>2019</year></book><book id='2'><title>The C Programming Language</title><author>Kernighan and Ritchie</author><year>1978</year></book><book id='3'><title>Structure and Interpretation</title><author>Abelson and Sussman</author><year>1996</year></book></library>"
var doc = xml.gx_xml_parse(data.cstr, data.len)
if (xml.gx_xml_has_error(doc)) {
print("Parse error: {xml.gx_xml_error(doc)}\n")
xml.gx_xml_free(doc)
return
}
// Root element
print("Root tag: {xml.gx_xml_name(doc)}\n")
var lib_name = xml.gx_xml_attr(doc, "name")
print("Library: {lib_name}\n")
var num_books = xml.gx_xml_child_count(doc, "book")
print("Book count: {num_books}\n\n")
// Iterate children with same tag name
var book = xml.gx_xml_child(doc, "book")
while (book != 0) {
var id = xml.gx_xml_attr(book, "id")
var title = xml.gx_xml_txt(xml.gx_xml_child(book, "title"))
var author = xml.gx_xml_txt(xml.gx_xml_child(book, "author"))
var year = xml.gx_xml_txt(xml.gx_xml_child(book, "year"))
print("Book {id}: {title} by {author} ({year})\n")
book = xml.gx_xml_next(book)
}
// ---- Build XML from scratch ----
print("\n--- Building XML ---\n")
var root = xml.gx_xml_new("config")
xml.gx_xml_set_attr(root, "version", "1.0")
var window = xml.gx_xml_add_child(root, "window")
xml.gx_xml_set_attr(window, "width", "1280")
xml.gx_xml_set_attr(window, "height", "720")
xml.gx_xml_set_txt(window, "Main Window")
var gfx = xml.gx_xml_add_child(root, "graphics")
xml.gx_xml_set_attr(gfx, "backend", "opengl")
var res = xml.gx_xml_add_child(gfx, "resolution")
xml.gx_xml_set_txt(res, "1920x1080")
var aa = xml.gx_xml_add_child(gfx, "antialiasing")
xml.gx_xml_set_txt(aa, "4x MSAA")
// Serialize to string
var xml_str = xml.gx_xml_to_str(root)
print("{xml_str}\n")
xml.gx_xml_free_str(xml_str)
xml.gx_xml_free(root)
xml.gx_xml_free(doc)
}
Test Math test_math.gx
// test_math.ec - Verify vec and mat math modules compile and produce correct results
import math.scalar
import math.vec
import math.mat
fn main() {
// --- scalar tests ---
print("=== Scalar ===\n");
var s:f32 = sinf(PI() / 2.0);
print("sin(PI/2) = {s}\n");
var c:f32 = cosf(0.0);
print("cos(0) = {c}\n");
var sq:f32 = sqrtf(9.0);
print("sqrt(9) = {sq}\n");
var sw_pos:vec3 = {1,2,3};
sw_pos.xy += 10;
print("sw_pos after .xy += 10: {sw_pos}\n");
var cl:f32 = clamp_f(5.0, 0.0, 1.0);
print("clamp(5, 0, 1) = {cl}\n");
var lr:f32 = lerp_f(0.0, 10.0, 0.25);
print("lerp(0, 10, 0.25) = {lr}\n");
var rad:f32 = radians(180.0);
print("radians(180) = {rad}\n");
// --- vec3 tests ---
print("\n=== Vec3 ===\n");
var a:vec3;
a.x = 3.0;
a.y = 0.0;
a.z = 4.0;
var len:f32 = length_v3(a);
print("length(3,0,4) = {len}\n");
var n:vec3 = normalize_v3(a);
print("normalize(3,0,4) = {n}\n");
var b:vec3;
b.x = 1.0;
b.y = 2.0;
b.z = 3.0;
var d:f32 = distance_v3(a, b);
print("distance = {d}\n");
var mid:vec3 = lerp_v3(a, b, 0.5);
print("lerp(a, b, 0.5) = {mid}\n");
// --- vec2 tests ---
print("\n=== Vec2 ===\n");
var v2:vec2;
v2.x = 3.0;
v2.y = 4.0;
var len2:f32 = length_v2(v2);
print("length(3,4) = {len2}\n");
var n2:vec2 = normalize_v2(v2);
print("normalize(3,4) = {n2}\n");
// --- mat4 tests ---
print("\n=== Mat4 ===\n");
var id:mat4 = identity_mat4();
print("identity = {id}\n");
// Test translation
var pos:vec3;
pos.x = 10.0;
pos.y = 20.0;
pos.z = 30.0;
var tm:mat4 = translation(pos);
var tc:vec4 = tm.col[3];
print("translation(10,20,30) col3 = {tc}\n");
// Test mul_m4 (identity * translation = translation)
var result:mat4 = mul_m4(id, tm);
var rc:vec4 = result.col[3];
print("I * T col3 = {rc}\n");
// Test mul_m4v4
var v:vec4;
v.x = 1.0;
v.y = 0.0;
v.z = 0.0;
v.w = 1.0;
var tv:vec4 = mul_m4v4(tm, v);
print("T * (1,0,0,1) = {tv}\n");
// Test perspective
var proj:mat4 = perspective(radians(60.0), 1.333, 0.1, 100.0);
var p00:f32 = proj.col[0].x;
print("perspective[0][0] = {p00}\n");
// Test look_at
var eye:vec3;
eye.x = 0.0;
eye.y = 0.0;
eye.z = 5.0;
var target:vec3;
target.x = 0.0;
target.y = 0.0;
target.z = 0.0;
var up:vec3;
up.x = 0.0;
up.y = 1.0;
up.z = 0.0;
var view:mat4 = look_at(eye, target, up);
var vc:vec4 = view.col[3];
print("look_at col3 = {vc}\n");
print("\nAll math tests done.\n");
}