test: group examples into per-category folders
Move examples/*.sx and their expected/ snapshots into per-category subfolders (examples/<category>/...). Folder = leading filename token, with ffi-objc/ffi-jni kept whole; filenames are unchanged. The corpus runner and LSP sweep now discover each category's expected/ dir, while issues/ stays flat. Example 1058's repo-root-relative companion import is made file-relative. Path strings embedded in 164 snapshots were regenerated (path-only changes). Test-layout docs in CLAUDE.md updated.
This commit is contained in:
5
examples/basic/0010-basic-basic.sx
Normal file
5
examples/basic/0010-basic-basic.sx
Normal file
@@ -0,0 +1,5 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
main :: () -> i32 {
|
||||
if false then 40 else 42
|
||||
}
|
||||
4
examples/basic/0011-basic-stdout.sx
Normal file
4
examples/basic/0011-basic-stdout.sx
Normal file
@@ -0,0 +1,4 @@
|
||||
#import "modules/std.sx";
|
||||
main :: () {
|
||||
print("Hello\n");
|
||||
}
|
||||
21
examples/basic/0012-basic-shadow.sx
Normal file
21
examples/basic/0012-basic-shadow.sx
Normal file
@@ -0,0 +1,21 @@
|
||||
#import "modules/std.sx";
|
||||
main :: () -> i32 {
|
||||
x := 42;
|
||||
{
|
||||
print("scope opened\n");
|
||||
defer print("scope closed\n");
|
||||
|
||||
// define a inner variable x shadowing the one define in the outer scope(s)
|
||||
x:= 6;
|
||||
print("scoped x: {}\n", x); //expect 6
|
||||
}
|
||||
print("main x: {}\n", x); //expect 42
|
||||
0
|
||||
}
|
||||
|
||||
// ** stdout **
|
||||
// scope opened
|
||||
// scoped x: 6
|
||||
// scope closed
|
||||
// main x: 42
|
||||
//
|
||||
11
examples/basic/0013-basic-defer.sx
Normal file
11
examples/basic/0013-basic-defer.sx
Normal file
@@ -0,0 +1,11 @@
|
||||
#import "modules/std.sx";
|
||||
main :: () -> i32 {
|
||||
defer print("still here\n");
|
||||
return 42;
|
||||
}
|
||||
|
||||
// ** exit code **
|
||||
// 42
|
||||
// ** stdout **
|
||||
// still here
|
||||
//
|
||||
9
examples/basic/0014-basic-code.sx
Normal file
9
examples/basic/0014-basic-code.sx
Normal file
@@ -0,0 +1,9 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
generate::() -> string {
|
||||
return "print(\"hello from the other side\n\");";
|
||||
}
|
||||
|
||||
main :: () {
|
||||
#insert generate();
|
||||
}
|
||||
15
examples/basic/0015-basic-demo.sx
Normal file
15
examples/basic/0015-basic-demo.sx
Normal file
@@ -0,0 +1,15 @@
|
||||
std :: #import "modules/std.sx";
|
||||
|
||||
vec3 :: (x:f32, y:f32, z:f32) -> std.Vector(3, f32) {
|
||||
.[x,y,z]
|
||||
}
|
||||
|
||||
main :: () {
|
||||
v1 := vec3(1,0,0);
|
||||
v2 := vec3(0,0,1);
|
||||
s := 0.5;
|
||||
|
||||
sum := (v1 - v2);// math.cross(v1, v2);
|
||||
|
||||
std.print("{}\n", sum);
|
||||
}
|
||||
50
examples/basic/0016-basic-while.sx
Normal file
50
examples/basic/0016-basic-while.sx
Normal file
@@ -0,0 +1,50 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
sumOf10 :: () -> i32 {
|
||||
i:= 1;
|
||||
s:=0;
|
||||
while i <= 10 {
|
||||
s+=i;
|
||||
i+=1;
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
someSum :: #run sumOf10();
|
||||
|
||||
main :: () {
|
||||
// Basic while loop: count to 5
|
||||
i := 0;
|
||||
while i < 5 {
|
||||
i += 1;
|
||||
}
|
||||
print("count: {}\n", i);
|
||||
|
||||
// While with break
|
||||
x := 1;
|
||||
while x < 100 {
|
||||
if x == 12 {
|
||||
break;
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
print("break at: {}\n", x);
|
||||
|
||||
// While with continue: sum odd numbers 1-9
|
||||
sum := 0;
|
||||
j := 0;
|
||||
while j < 10 {
|
||||
j += 1;
|
||||
// Skip even numbers
|
||||
if j == 2 { continue; }
|
||||
if j == 4 { continue; }
|
||||
if j == 6 { continue; }
|
||||
if j == 8 { continue; }
|
||||
if j == 10 { continue; }
|
||||
sum += j;
|
||||
}
|
||||
print("sum of odd 1-9: {}\n", sum);
|
||||
|
||||
print("sum {}", someSum);
|
||||
|
||||
}
|
||||
18
examples/basic/0017-basic-conditions.sx
Normal file
18
examples/basic/0017-basic-conditions.sx
Normal file
@@ -0,0 +1,18 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
main :: () {
|
||||
x:= 32;
|
||||
y:= 40;
|
||||
|
||||
if 0 <= x <= 100 and 0 <= y <= 100 {
|
||||
print("contained");
|
||||
}
|
||||
|
||||
if 1000 > x > -100 and 0 <= y <= 100 {
|
||||
print("contained");
|
||||
}
|
||||
|
||||
if 1000 > x >= -100 and 0 <= y <= 100 {
|
||||
print("contained");
|
||||
}
|
||||
}
|
||||
35
examples/basic/0018-basic-quicksort.sx
Normal file
35
examples/basic/0018-basic-quicksort.sx
Normal file
@@ -0,0 +1,35 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
quick_sort :: (items: []$T) {
|
||||
partition :: (items: []T, lo: i64, hi: i64) -> i64 {
|
||||
pivot := items[hi];
|
||||
i := lo - 1;
|
||||
j := lo;
|
||||
while j < hi {
|
||||
if items[j] < pivot {
|
||||
i += 1;
|
||||
items[i], items[j] = items[j], items[i];
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
i += 1;
|
||||
items[i], items[hi] = items[hi], items[i];
|
||||
i
|
||||
}
|
||||
|
||||
sort :: (items: []T, lo: i64, hi: i64) {
|
||||
if lo < hi {
|
||||
pi := partition(items, lo, hi);
|
||||
sort(items, lo, pi - 1);
|
||||
sort(items, pi + 1, hi);
|
||||
}
|
||||
}
|
||||
|
||||
sort(items, 0, items.len - 1);
|
||||
}
|
||||
|
||||
main :: () {
|
||||
arr : []i64 = .[333, 2, 3, 5, 2, 2, 3, 4, 5, 6, 6, 1];
|
||||
quick_sort(arr);
|
||||
print("{}\n", arr);
|
||||
}
|
||||
295
examples/basic/0019-basic-dot-shorthand.sx
Normal file
295
examples/basic/0019-basic-dot-shorthand.sx
Normal file
@@ -0,0 +1,295 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
// ============================================================
|
||||
// Dot-shorthand tests: .identifier(args) unification
|
||||
// Tests both tagged enum backward compat and struct static methods
|
||||
// ============================================================
|
||||
|
||||
// --- Type declarations ---
|
||||
|
||||
Color :: enum { red; green; blue; }
|
||||
|
||||
Shape :: enum {
|
||||
circle: f32;
|
||||
rect: struct { w, h: f32; };
|
||||
none;
|
||||
}
|
||||
|
||||
Vec2 :: struct {
|
||||
x: f32;
|
||||
y: f32;
|
||||
|
||||
create :: (x: f32, y: f32) -> Vec2 { Vec2.{ x = x, y = y } }
|
||||
zero :: () -> Vec2 { Vec2.{ x = 0.0, y = 0.0 } }
|
||||
unit_x :: () -> Vec2 { Vec2.{ x = 1.0, y = 0.0 } }
|
||||
add :: (a: Vec2, b: Vec2) -> Vec2 { Vec2.{ x = a.x + b.x, y = a.y + b.y } }
|
||||
scale :: (v: Vec2, s: f32) -> Vec2 { Vec2.{ x = v.x * s, y = v.y * s } }
|
||||
len :: (v: Vec2) -> i32 { xx (v.x + v.y) }
|
||||
}
|
||||
|
||||
EdgeInsets :: struct {
|
||||
top: f32;
|
||||
right: f32;
|
||||
bottom: f32;
|
||||
left: f32;
|
||||
|
||||
all :: (v: f32) -> EdgeInsets { EdgeInsets.{ top = v, right = v, bottom = v, left = v } }
|
||||
symmetric :: (h: f32, v: f32) -> EdgeInsets { EdgeInsets.{ top = v, right = h, bottom = v, left = h } }
|
||||
horizontal :: (h: f32) -> EdgeInsets { EdgeInsets.{ top = 0.0, right = h, bottom = 0.0, left = h } }
|
||||
}
|
||||
|
||||
Trio :: struct {
|
||||
a: i32;
|
||||
b: i32;
|
||||
c: i32;
|
||||
|
||||
make :: (a: i32, b: i32, c: i32) -> Trio { Trio.{ a = a, b = b, c = c } }
|
||||
sum :: (t: Trio) -> i32 { t.a + t.b + t.c }
|
||||
}
|
||||
|
||||
Result :: enum {
|
||||
ok: i32;
|
||||
err: string;
|
||||
}
|
||||
|
||||
main :: () {
|
||||
// ============================================================
|
||||
// SECTION 1: Tagged enum backward compatibility
|
||||
// ============================================================
|
||||
print("--- tagged enum compat ---\n");
|
||||
|
||||
// T1: .variant(payload) in typed variable declaration
|
||||
{
|
||||
sh : Shape = .circle(3.14);
|
||||
print("T1: {}\n", sh.circle);
|
||||
}
|
||||
|
||||
// T2: Bare .variant (no payload) in typed variable
|
||||
{
|
||||
sh : Shape = .none;
|
||||
ms := if sh == {
|
||||
case .circle: 1;
|
||||
case .rect: 2;
|
||||
case .none: 3;
|
||||
};
|
||||
print("T2: {}\n", ms);
|
||||
}
|
||||
|
||||
// T3: .variant with struct payload
|
||||
{
|
||||
sh : Shape = .rect(.{ 5.0, 3.0 });
|
||||
print("T3: {} {}\n", sh.rect.w, sh.rect.h);
|
||||
}
|
||||
|
||||
// T4: Qualified Type.variant(payload) still works
|
||||
{
|
||||
sh := Shape.circle(2.71);
|
||||
print("T4: {}\n", sh.circle);
|
||||
}
|
||||
|
||||
// T5: Match with payload capture
|
||||
{
|
||||
sh : Shape = .circle(9.5);
|
||||
if sh == {
|
||||
case .circle: (r) { print("T5: {}\n", r); }
|
||||
case .rect: (sz) { print("T5: rect\n"); }
|
||||
case .none: print("T5: none\n");
|
||||
}
|
||||
}
|
||||
|
||||
// T6: Return .variant(payload) from function
|
||||
{
|
||||
make_shape :: (r: f32) -> Shape { .circle(r) }
|
||||
sh := make_shape(4.2);
|
||||
print("T6: {}\n", sh.circle);
|
||||
}
|
||||
|
||||
// T7: Reassignment with .variant(payload) and bare .variant
|
||||
{
|
||||
sh : Shape = .circle(1.0);
|
||||
print("T7a: {}\n", sh.circle);
|
||||
sh = .rect(.{ 2.0, 3.0 });
|
||||
print("T7b: {} {}\n", sh.rect.w, sh.rect.h);
|
||||
sh = .none;
|
||||
ms := if sh == {
|
||||
case .circle: 1;
|
||||
case .rect: 2;
|
||||
case .none: 3;
|
||||
};
|
||||
print("T7c: {}\n", ms);
|
||||
}
|
||||
|
||||
// T8: .variant(payload) as function argument (match-as-expression)
|
||||
{
|
||||
describe :: (sh: Shape) -> i32 {
|
||||
if sh == {
|
||||
case .circle: 10;
|
||||
case .rect: 20;
|
||||
case .none: 30;
|
||||
}
|
||||
}
|
||||
print("T8a: {}\n", describe(.circle(7.0)));
|
||||
print("T8b: {}\n", describe(.rect(.{ 3.0, 4.0 })));
|
||||
print("T8c: {}\n", describe(.none));
|
||||
}
|
||||
|
||||
// T9: Tagged enum with string payload
|
||||
{
|
||||
r : Result = .ok(42);
|
||||
ms := if r == {
|
||||
case .ok: (v) { v }
|
||||
case .err: (e) { -1 }
|
||||
};
|
||||
print("T9: {}\n", ms);
|
||||
}
|
||||
|
||||
// T10: Match as expression returning tagged enum
|
||||
{
|
||||
select :: (n: i32) -> Shape {
|
||||
if n == {
|
||||
case 0: .none;
|
||||
case 1: .circle(1.0);
|
||||
else: .rect(.{ 9.0, 9.0 });
|
||||
}
|
||||
}
|
||||
print("T10a: {}\n", if select(0) == { case .none: 1; else: 0; });
|
||||
print("T10b: {}\n", select(1).circle);
|
||||
print("T10c: {}\n", select(2).rect.w);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// SECTION 2: Struct static method shorthand
|
||||
// ============================================================
|
||||
print("--- struct static shorthand ---\n");
|
||||
|
||||
// S1: .method(args) as function argument (the motivating use case)
|
||||
{
|
||||
print_vec :: (v: Vec2) { print("S1: {} {}\n", v.x, v.y); }
|
||||
print_vec(.create(3.0, 4.0));
|
||||
}
|
||||
|
||||
// S2: .method(args) in typed variable declaration
|
||||
{
|
||||
v : Vec2 = .create(5.0, 6.0);
|
||||
print("S2: {} {}\n", v.x, v.y);
|
||||
}
|
||||
|
||||
// S3: Return .method(args) from function with return type
|
||||
{
|
||||
make_vec :: () -> Vec2 { .create(7.0, 8.0) }
|
||||
v := make_vec();
|
||||
print("S3: {} {}\n", v.x, v.y);
|
||||
}
|
||||
|
||||
// S4: Zero-arg static method (factory)
|
||||
{
|
||||
print_vec :: (v: Vec2) { print("S4: {} {}\n", v.x, v.y); }
|
||||
print_vec(.zero());
|
||||
print_vec(.unit_x());
|
||||
}
|
||||
|
||||
// S5: Three-arg static method (proves multi-arg works)
|
||||
{
|
||||
print_trio :: (t: Trio) { print("S5: {}\n", t.a + t.b + t.c); }
|
||||
print_trio(.make(10, 20, 30));
|
||||
}
|
||||
|
||||
// S6: Two-arg shorthand matching the EdgeInsets use case
|
||||
{
|
||||
apply_insets :: (ei: EdgeInsets) { print("S6: {} {} {} {}\n", ei.top, ei.right, ei.bottom, ei.left); }
|
||||
apply_insets(.all(8.0));
|
||||
apply_insets(.symmetric(16.0, 8.0));
|
||||
apply_insets(.horizontal(12.0));
|
||||
}
|
||||
|
||||
// S7: Result of .method() used in further computation
|
||||
{
|
||||
v : Vec2 = .create(3.0, 4.0);
|
||||
print("S7: {}\n", Vec2.len(v));
|
||||
}
|
||||
|
||||
// S8: Chained qualified + shorthand — ensure both work together
|
||||
{
|
||||
v1 := Vec2.create(1.0, 2.0);
|
||||
print_vec :: (v: Vec2) { print("S8: {} {}\n", v.x, v.y); }
|
||||
print_vec(.create(3.0, 4.0));
|
||||
print("S8q: {} {}\n", v1.x, v1.y);
|
||||
}
|
||||
|
||||
// S9: Static method taking struct of same type as args
|
||||
{
|
||||
v : Vec2 = .add(.create(1.0, 2.0), .create(3.0, 4.0));
|
||||
print("S9: {} {}\n", v.x, v.y);
|
||||
}
|
||||
|
||||
// S10: Static method + piped result
|
||||
{
|
||||
v := Vec2.create(2.0, 3.0) |> Vec2.scale(2.0);
|
||||
print("S10: {} {}\n", v.x, v.y);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// SECTION 3: Edge cases mixing both
|
||||
// ============================================================
|
||||
print("--- edge cases ---\n");
|
||||
|
||||
// E1: Both tagged enum and struct shorthand in same scope
|
||||
{
|
||||
sh : Shape = .circle(5.0);
|
||||
v : Vec2 = .create(1.0, 2.0);
|
||||
print("E1: {} {} {}\n", sh.circle, v.x, v.y);
|
||||
}
|
||||
|
||||
// E2: Function taking both types — each resolves correctly
|
||||
{
|
||||
use_both :: (sh: Shape, v: Vec2) {
|
||||
ms : i32 = 0;
|
||||
if sh == { case .circle: (r) { ms = xx r; } else: {} }
|
||||
print("E2: {} {} {}\n", ms, v.x, v.y);
|
||||
}
|
||||
use_both(.circle(9.0), .create(1.0, 2.0));
|
||||
}
|
||||
|
||||
// E3: Bare .variant (no parens) as function arg
|
||||
{
|
||||
check_none :: (sh: Shape) -> i32 {
|
||||
if sh == { case .none: 1; else: 0; }
|
||||
}
|
||||
print("E3: {}\n", check_none(.none));
|
||||
}
|
||||
|
||||
// E4: Nested shorthand — .method takes a struct param created with shorthand
|
||||
// (inner .create must resolve via the method's parameter type, not the outer type)
|
||||
{
|
||||
v : Vec2 = .add(Vec2.create(1.0, 2.0), Vec2.create(3.0, 4.0));
|
||||
print("E4: {} {}\n", v.x, v.y);
|
||||
}
|
||||
|
||||
// E5: Tagged enum .variant(payload) in match-as-expression
|
||||
{
|
||||
sh : Shape = .circle(42.0);
|
||||
r : i32 = 0;
|
||||
if sh == {
|
||||
case .circle: (v) { r = xx v; }
|
||||
case .rect: (sz) { r = xx sz.w; }
|
||||
case .none: r = xx -1;
|
||||
}
|
||||
print("E5: {}\n", r);
|
||||
}
|
||||
|
||||
// E6: Color enum (plain, not tagged) still works with bare .variant
|
||||
{
|
||||
c : Color = .green;
|
||||
ci : i32 = xx c;
|
||||
print("E6: {}\n", ci);
|
||||
}
|
||||
|
||||
// E7: Struct shorthand in typed variable, then pass to function
|
||||
{
|
||||
ei : EdgeInsets = .symmetric(10.0, 20.0);
|
||||
show :: (e: EdgeInsets) { print("E7: {} {}\n", e.top, e.left); }
|
||||
show(ei);
|
||||
}
|
||||
|
||||
print("=== DONE ===\n");
|
||||
}
|
||||
16
examples/basic/0020-basic-inline-if-return-fallthrough.sx
Normal file
16
examples/basic/0020-basic-inline-if-return-fallthrough.sx
Normal file
@@ -0,0 +1,16 @@
|
||||
// `inline if COND { return E; }` followed by a fall-through final expression:
|
||||
// when COND evaluates true at comptime, the body is spliced unconditionally
|
||||
// and the trailing expression must NOT also be emitted into the same LLVM
|
||||
// block (only one terminator per block).
|
||||
|
||||
#import "modules/std.sx";
|
||||
#import "modules/build.sx";
|
||||
|
||||
do_it :: () -> bool {
|
||||
inline if OS != .ios { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
if do_it() then 0 else 1
|
||||
}
|
||||
36
examples/basic/0021-basic-expression-bodied-fn.sx
Normal file
36
examples/basic/0021-basic-expression-bodied-fn.sx
Normal file
@@ -0,0 +1,36 @@
|
||||
// M1.0 — expression-bodied function declarations.
|
||||
//
|
||||
// sx's `=>` body form (already used for lambdas) extends to
|
||||
// top-level and struct-member function declarations:
|
||||
//
|
||||
// name :: (params) -> RetType => expr;
|
||||
//
|
||||
// Pins three positions: module-top, struct method, niladic.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
double :: (x: i32) -> i32 => x * 2;
|
||||
|
||||
sum :: (a: i32, b: i32) -> i32 => a + b;
|
||||
|
||||
answer :: () -> i32 => 42;
|
||||
|
||||
Point :: struct {
|
||||
x: i32;
|
||||
y: i32;
|
||||
|
||||
total :: (self: *Point) -> i32 => self.x + self.y;
|
||||
scaled :: (self: *Point, by: i32) -> i32 => (self.x + self.y) * by;
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("double: {}\n", double(7));
|
||||
print("sum: {}\n", sum(3, 4));
|
||||
print("answer: {}\n", answer());
|
||||
|
||||
p := Point.{ x = 10, y = 20 };
|
||||
print("total: {}\n", p.total());
|
||||
print("scaled: {}\n", p.scaled(3));
|
||||
|
||||
0
|
||||
}
|
||||
39
examples/basic/0022-basic-for-range.sx
Normal file
39
examples/basic/0022-basic-for-range.sx
Normal file
@@ -0,0 +1,39 @@
|
||||
// Range-based for loops: `for start..end (i) { }` (cursor optional, `end`
|
||||
// exclusive) is a runtime counting loop; `inline for start..end (i) { }`
|
||||
// is comptime-unrolled — the cursor is a compile-time constant each
|
||||
// iteration, so `xs[i]` over a heterogeneous pack substitutes the concrete
|
||||
// per-position element (this is what drives pack iteration).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Show :: protocol {
|
||||
show :: (self: *Self) -> string;
|
||||
}
|
||||
A :: struct { x: i64; }
|
||||
B :: struct { s: string; }
|
||||
impl Show for A { show :: (self: *A) -> string => "A"; }
|
||||
impl Show for B { show :: (self: *B) -> string => "B"; }
|
||||
|
||||
// Comptime-unrolled iteration over a pack; cursor `i` indexes the pack.
|
||||
each :: (..xs: Show) -> void {
|
||||
inline for 0..xs.len (i) {
|
||||
print("[{}]={}\n", i, xs[i].show());
|
||||
}
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
// Runtime range, cursor used.
|
||||
for 0..3 (i) { print("i={}\n", i); }
|
||||
|
||||
// Runtime range, no cursor — body runs `end - start` times.
|
||||
n := 0;
|
||||
for 0..5 { n = n + 1; }
|
||||
print("n={}\n", n);
|
||||
|
||||
// Non-zero start.
|
||||
for 2..5 (j) { print("j={}\n", j); }
|
||||
|
||||
// Inline unroll over a heterogeneous pack.
|
||||
each(A.{ x = 1 }, B.{ s = "hi" }, A.{ x = 3 });
|
||||
0
|
||||
}
|
||||
25
examples/basic/0023-basic-for-by-ref-capture.sx
Normal file
25
examples/basic/0023-basic-for-by-ref-capture.sx
Normal file
@@ -0,0 +1,25 @@
|
||||
// `for xs (*x)` binds each element by pointer — no per-element copy.
|
||||
// Mutations write back, and a pointer subject matches through the deref.
|
||||
#import "modules/std.sx";
|
||||
|
||||
Shape :: enum {
|
||||
circle: f32;
|
||||
none;
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
// By-ref mutation writes back into the array (impossible with a value copy).
|
||||
xs : [3]i64 = .[1, 2, 3];
|
||||
for xs (*x) { x.* = x + 100; }
|
||||
print("{} {} {}\n", xs[0], xs[1], xs[2]);
|
||||
|
||||
// Pointer subject matches through the deref; payload reads through the ref.
|
||||
shapes : [2]Shape = .[.circle(2.0), .none];
|
||||
for shapes (*s) {
|
||||
if s == {
|
||||
case .circle: (r) { print("circle {}\n", r); }
|
||||
case .none: { print("none\n"); }
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
40
examples/basic/0024-basic-for-list.sx
Normal file
40
examples/basic/0024-basic-for-list.sx
Normal file
@@ -0,0 +1,40 @@
|
||||
// `for` over a `List(T)` (a `{ items: [*]T, len, cap }` struct): value capture,
|
||||
// by-ref capture (mutates in place), iterating a `*List`, and a by-ref capture
|
||||
// used as a value-receiver method call (auto-deref).
|
||||
#import "modules/std.sx";
|
||||
|
||||
Box :: struct {
|
||||
v: i64;
|
||||
boxed :: (self: Box) -> i64 { self.v } // value receiver
|
||||
}
|
||||
|
||||
sum_ptr :: (xs: *List(i64)) -> i64 {
|
||||
total : i64 = 0;
|
||||
for xs (n) { total = total + n; } // iterate through a *List
|
||||
total
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
xs := List(i64).{};
|
||||
xs.append(10);
|
||||
xs.append(20);
|
||||
xs.append(30);
|
||||
|
||||
s : i64 = 0;
|
||||
for xs (n) { s = s + n; } // value capture
|
||||
print("sum {}\n", s); // 60
|
||||
|
||||
for xs (*n) { n.* = n + 100; } // by-ref: writes back
|
||||
s = 0;
|
||||
for xs (n) { s = s + n; }
|
||||
print("sum2 {}\n", s); // 360
|
||||
|
||||
print("via ptr {}\n", sum_ptr(@xs)); // 360
|
||||
|
||||
bs := List(Box).{};
|
||||
bs.append(.{ v = 7 });
|
||||
bt : i64 = 0;
|
||||
for bs (*b) { bt = bt + b.boxed(); } // *Box receiver, value-self method
|
||||
print("boxes {}\n", bt); // 7
|
||||
0
|
||||
}
|
||||
67
examples/basic/0025-basic-literals.sx
Normal file
67
examples/basic/0025-basic-literals.sx
Normal file
@@ -0,0 +1,67 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/math";
|
||||
#import "modules/build.sx";
|
||||
#import "modules/std/test.sx";
|
||||
pkg :: #import "tests/fixtures/testpkg";
|
||||
|
||||
Color :: enum { red; green; blue; }
|
||||
|
||||
main :: () {
|
||||
|
||||
// ========================================================
|
||||
// 1. LITERALS
|
||||
// ========================================================
|
||||
print("=== 1. Literals ===\n");
|
||||
|
||||
// Integer literals
|
||||
print("decimal: {}\n", 42);
|
||||
print("hex: {}\n", 0xFF);
|
||||
print("binary: {}\n", 0b1010);
|
||||
|
||||
// Float literal
|
||||
pi := 3.14;
|
||||
print("float: {}\n", pi);
|
||||
|
||||
// Explicit f64
|
||||
big : f64 = 2.718281828;
|
||||
print("f64: {}\n", big);
|
||||
|
||||
// Boolean literals
|
||||
print("true: {}\n", true);
|
||||
print("false: {}\n", false);
|
||||
|
||||
// String with escapes
|
||||
print("escapes: hello\tworld\n");
|
||||
|
||||
// Multi-line string
|
||||
ml := "line1
|
||||
line2";
|
||||
print("multiline: {}\n", ml);
|
||||
|
||||
// Heredoc string
|
||||
hd := #string END
|
||||
raw heredoc
|
||||
END;
|
||||
print("heredoc: {}\n", hd);
|
||||
|
||||
// Undefined with type
|
||||
undef_val : i32 = ---;
|
||||
undef_val = 77;
|
||||
print("undef-then-set: {}\n", undef_val);
|
||||
|
||||
// Enum literal (context-inferred)
|
||||
c : Color = .green;
|
||||
print("enum-lit: {}\n", c);
|
||||
|
||||
// Null pointer
|
||||
np : *i32 = null;
|
||||
print("null-ptr: {}\n", np);
|
||||
|
||||
// String .len
|
||||
slen := "hello";
|
||||
print("string-len: {}\n", slen.len);
|
||||
|
||||
// Empty string .len
|
||||
es := "";
|
||||
print("empty-string: {}\n", es.len);
|
||||
}
|
||||
166
examples/basic/0026-basic-operators.sx
Normal file
166
examples/basic/0026-basic-operators.sx
Normal file
@@ -0,0 +1,166 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/math";
|
||||
#import "modules/build.sx";
|
||||
#import "modules/std/test.sx";
|
||||
pkg :: #import "tests/fixtures/testpkg";
|
||||
|
||||
add :: (a: i32, b: i32) -> i32 { a + b }
|
||||
|
||||
mul :: (a: i32, b: i32) -> i32 { a * b }
|
||||
|
||||
// P4 edge: Chained default→default calls
|
||||
Chained :: protocol {
|
||||
base :: (self: *Self, msg: string) -> i32;
|
||||
wrap :: (self: *Self, msg: string) -> i32 {
|
||||
self.base(msg) + 1
|
||||
}
|
||||
double_wrap :: (self: *Self, msg: string) -> i32 {
|
||||
self.wrap(msg) + self.wrap(msg)
|
||||
}
|
||||
}
|
||||
|
||||
main :: () {
|
||||
|
||||
// ========================================================
|
||||
// 2. OPERATORS & PRECEDENCE
|
||||
// ========================================================
|
||||
print("=== 2. Operators ===\n");
|
||||
|
||||
// Arithmetic
|
||||
print("add: {}\n", 3 + 4);
|
||||
print("sub: {}\n", 10 - 3);
|
||||
print("mul: {}\n", 6 * 7);
|
||||
print("div: {}\n", 20 / 4);
|
||||
print("mod: {}\n", 17 % 5);
|
||||
print("neg: {}\n", -(5));
|
||||
|
||||
// Comparisons
|
||||
print("eq: {}\n", 5 == 5);
|
||||
print("neq: {}\n", 5 != 3);
|
||||
print("lt: {}\n", 3 < 5);
|
||||
print("gt: {}\n", 5 > 3);
|
||||
print("le: {}\n", 5 <= 5);
|
||||
print("ge: {}\n", 5 >= 3);
|
||||
|
||||
// Chained comparisons
|
||||
v := 50;
|
||||
print("chain: {}\n", 0 <= v <= 100);
|
||||
print("chain-gt: {}\n", 100 > v > 0);
|
||||
print("chain-mixed: {}\n", 100 > v >= 0);
|
||||
|
||||
// Equality chains
|
||||
print("eq-chain: {}\n", 5 == 5 == 5);
|
||||
print("eq-chain-f: {}\n", 5 == 5 == 6);
|
||||
|
||||
// Bitwise
|
||||
print("band: {}\n", 0xFF & 0x0F);
|
||||
print("bor: {}\n", 1 | 2 | 4);
|
||||
|
||||
// Bitwise XOR
|
||||
print("bxor: {}\n", 0xFF ^ 0x0F);
|
||||
print("bxor2: {}\n", 6 ^ 3);
|
||||
|
||||
// Bitwise NOT
|
||||
print("bnot: {}\n", ~0);
|
||||
print("bnot2: {}\n", ~1);
|
||||
|
||||
// Shifts
|
||||
print("shl: {}\n", 1 << 4);
|
||||
print("shr: {}\n", 256 >> 4);
|
||||
print("shl2: {}\n", 3 << 3);
|
||||
print("shr2: {}\n", 255 >> 1);
|
||||
|
||||
// Bitwise on variables
|
||||
bv1 := 0xFF;
|
||||
bv2 := 0x0F;
|
||||
print("band-var: {}\n", bv1 & bv2);
|
||||
bv3 := 1;
|
||||
bv4 := 6;
|
||||
print("bor-var: {}\n", bv3 | bv4);
|
||||
print("bxor-var: {}\n", bv1 ^ bv2);
|
||||
print("shl-var: {}\n", bv3 << 4);
|
||||
print("shr-var: {}\n", bv1 >> 4);
|
||||
print("bnot-var: {}\n", ~bv2);
|
||||
|
||||
// Bitwise compound assignment
|
||||
bca := 0xFF;
|
||||
bca &= 0x0F;
|
||||
print("and-assign: {}\n", bca);
|
||||
bco := 0x0F;
|
||||
bco |= 0xF0;
|
||||
print("or-assign: {}\n", bco);
|
||||
bcx := 0xFF;
|
||||
bcx ^= 0x0F;
|
||||
print("xor-assign: {}\n", bcx);
|
||||
bcs := 1;
|
||||
bcs <<= 8;
|
||||
print("shl-assign: {}\n", bcs);
|
||||
bcr := 256;
|
||||
bcr >>= 4;
|
||||
print("shr-assign: {}\n", bcr);
|
||||
|
||||
// Modulo on variables
|
||||
mv1 := 17;
|
||||
mv2 := 5;
|
||||
print("mod-var: {}\n", mv1 % mv2);
|
||||
|
||||
// Logical (short-circuit)
|
||||
print("and: {}\n", true and true);
|
||||
print("and-false: {}\n", true and false);
|
||||
print("or: {}\n", false or true);
|
||||
print("or-false: {}\n", false or false);
|
||||
|
||||
// Short-circuit verification
|
||||
print("short-and: {}\n", false and true);
|
||||
print("short-or: {}\n", true or false);
|
||||
|
||||
// Compound assignment
|
||||
ca := 10;
|
||||
ca += 5;
|
||||
print("ca+=: {}\n", ca);
|
||||
ca -= 3;
|
||||
print("ca-=: {}\n", ca);
|
||||
ca *= 2;
|
||||
print("ca*=: {}\n", ca);
|
||||
ca /= 6;
|
||||
print("ca/=: {}\n", ca);
|
||||
|
||||
// Precedence
|
||||
print("prec1: {}\n", 2 + 3 * 4);
|
||||
print("prec2: {}\n", (2 + 3) * 4);
|
||||
|
||||
// xx explicit cast
|
||||
big2 : f64 = 200.7;
|
||||
small : u8 = xx big2;
|
||||
print("xx-cast: {}\n", small);
|
||||
|
||||
// Implicit widening conversions
|
||||
wu : u8 = 200;
|
||||
ws : i64 = wu;
|
||||
print("widen-u8-i64: {}\n", ws);
|
||||
|
||||
wi3 : i32 = 42;
|
||||
wf : f64 = wi3;
|
||||
print("widen-i32-f64: {}\n", wf);
|
||||
|
||||
wf32 : f32 = 1.5;
|
||||
wf64 : f64 = wf32;
|
||||
print("widen-f32-f64: {}\n", wf64);
|
||||
|
||||
wu2 : u8 = 100;
|
||||
ws2 : i16 = wu2;
|
||||
print("widen-u8-i16: {}\n", ws2);
|
||||
|
||||
// More xx narrowing
|
||||
xl : i64 = 12345;
|
||||
xs : i32 = xx xl;
|
||||
print("xx-i64-i32: {}\n", xs);
|
||||
|
||||
xd : f64 = 1.5;
|
||||
xf : f32 = xx xd;
|
||||
print("xx-f64-f32: {}\n", xf);
|
||||
|
||||
xdf : f64 = 7.9;
|
||||
xdi : i32 = xx xdf;
|
||||
print("xx-f64-i32: {}\n", xdi);
|
||||
}
|
||||
201
examples/basic/0027-basic-control-flow.sx
Normal file
201
examples/basic/0027-basic-control-flow.sx
Normal file
@@ -0,0 +1,201 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/math";
|
||||
#import "modules/build.sx";
|
||||
#import "modules/std/test.sx";
|
||||
pkg :: #import "tests/fixtures/testpkg";
|
||||
|
||||
main :: () {
|
||||
|
||||
// ========================================================
|
||||
// 4. CONTROL FLOW
|
||||
// ========================================================
|
||||
print("=== 4. Control Flow ===\n");
|
||||
|
||||
// If-then-else (inline, as expression)
|
||||
ite := if true then 1 else 2;
|
||||
print("ite: {}\n", ite);
|
||||
|
||||
// If-then-else both branches
|
||||
ie_a := if true then 10 else 20;
|
||||
ie_b := if false then 10 else 20;
|
||||
print("ite-both: {} {}\n", ie_a, ie_b);
|
||||
|
||||
// If block
|
||||
if 1 < 2 {
|
||||
print("if-block: yes\n");
|
||||
}
|
||||
|
||||
// If without else (statement)
|
||||
if false { print("should-not-print\n"); }
|
||||
print("if-no-else: after\n");
|
||||
|
||||
// Nested if
|
||||
nx := 10;
|
||||
if nx > 5 {
|
||||
if nx > 8 {
|
||||
print("nested-if: deep\n");
|
||||
}
|
||||
}
|
||||
|
||||
// If-else-if chain
|
||||
eiv := 2;
|
||||
if eiv == 1 {
|
||||
print("if-else-if: first\n");
|
||||
} else if eiv == 2 {
|
||||
print("if-else-if: second\n");
|
||||
} else {
|
||||
print("if-else-if: other\n");
|
||||
}
|
||||
|
||||
// If block as expression
|
||||
ibe := 10 + if true { 5 } else { 0 };
|
||||
print("if-block-expr: {}\n", ibe);
|
||||
|
||||
// While basic
|
||||
wi := 0;
|
||||
while wi < 5 { wi += 1; }
|
||||
print("while: {}\n", wi);
|
||||
|
||||
// While with false condition (never executes)
|
||||
while false { print("should-not-print\n"); }
|
||||
print("while-false: skipped\n");
|
||||
|
||||
// While with break
|
||||
wb := 0;
|
||||
while wb < 100 {
|
||||
if wb == 7 { break; }
|
||||
wb += 1;
|
||||
}
|
||||
print("while-break: {}\n", wb);
|
||||
|
||||
// While with continue
|
||||
wsum := 0;
|
||||
wc := 0;
|
||||
while wc < 10 {
|
||||
wc += 1;
|
||||
if wc % 2 == 0 { continue; }
|
||||
wsum += wc;
|
||||
}
|
||||
print("while-continue: {}\n", wsum);
|
||||
|
||||
// While sum 1..10
|
||||
wsum2 := 0;
|
||||
wi2 := 1;
|
||||
while wi2 <= 10 {
|
||||
wsum2 += wi2;
|
||||
wi2 += 1;
|
||||
}
|
||||
print("while-sum: {}\n", wsum2);
|
||||
|
||||
// Nested while
|
||||
nw_outer := 0;
|
||||
nw_count := 0;
|
||||
while nw_outer < 3 {
|
||||
nw_inner := 0;
|
||||
while nw_inner < 3 {
|
||||
nw_count += 1;
|
||||
nw_inner += 1;
|
||||
}
|
||||
nw_outer += 1;
|
||||
}
|
||||
print("nested-while: {}\n", nw_count);
|
||||
|
||||
// Nested while with break in inner
|
||||
nb_outer := 0;
|
||||
nb_icount := 0;
|
||||
while nb_outer < 5 {
|
||||
nb_i := 0;
|
||||
while nb_i < 5 {
|
||||
if nb_i == 1 { break; }
|
||||
nb_i += 1;
|
||||
}
|
||||
nb_icount += nb_i;
|
||||
nb_outer += 1;
|
||||
if nb_outer == 2 { break; }
|
||||
}
|
||||
print("nested-break: {} {}\n", nb_outer, nb_icount);
|
||||
|
||||
// For loop basic
|
||||
farr : [4]i32 = .[10, 20, 30, 40];
|
||||
out("for:");
|
||||
for farr (it) {
|
||||
out(" ");
|
||||
out(int_to_string(it));
|
||||
}
|
||||
out("\n");
|
||||
|
||||
// For with print
|
||||
out("for-print:");
|
||||
for farr (it) {
|
||||
print(" {}", it);
|
||||
}
|
||||
out("\n");
|
||||
|
||||
// For with index
|
||||
out("for-idx:");
|
||||
for farr, 0.. (_, ix) {
|
||||
out(" ");
|
||||
out(int_to_string(ix));
|
||||
}
|
||||
out("\n");
|
||||
|
||||
// For with print two args
|
||||
out("for-2arg:");
|
||||
for farr, 0.. (it, ix) {
|
||||
print(" {}@{}", it, ix);
|
||||
}
|
||||
out("\n");
|
||||
|
||||
// For with break
|
||||
out("for-break:");
|
||||
for farr (it) {
|
||||
if it == 30 { break; }
|
||||
print(" {}", it);
|
||||
}
|
||||
out("\n");
|
||||
|
||||
// For with continue
|
||||
out("for-continue:");
|
||||
for farr (it) {
|
||||
if it == 20 { continue; }
|
||||
print(" {}", it);
|
||||
}
|
||||
out("\n");
|
||||
|
||||
// For on slice
|
||||
fsl : []i32 = .[10, 20, 30];
|
||||
out("for-slice:");
|
||||
for fsl (it) {
|
||||
print(" {}", it);
|
||||
}
|
||||
out("\n");
|
||||
|
||||
// For on slice with index
|
||||
out("for-slice-idx:");
|
||||
for fsl, 0.. (it, ix) {
|
||||
print(" {}:{}", ix, it);
|
||||
}
|
||||
out("\n");
|
||||
|
||||
// Nested for
|
||||
nf_a : [2]i32 = .[0, 1];
|
||||
nf_b : [2]i32 = .[0, 1];
|
||||
out("for-nested:");
|
||||
for nf_a (oa) {
|
||||
for nf_b (ob) {
|
||||
print(" ({},{})", oa, ob);
|
||||
}
|
||||
}
|
||||
out("\n");
|
||||
|
||||
// For with break preserving index
|
||||
fbi : [5]i32 = .[10, 20, 30, 40, 50];
|
||||
fbi_idx := 0;
|
||||
for fbi, 0.. (it, ix) {
|
||||
if it == 30 { fbi_idx = ix; break; }
|
||||
}
|
||||
print("for-break-idx: {}\n", fbi_idx);
|
||||
|
||||
// Multiple print placeholders
|
||||
print("multi: {} {} {}\n", 1, 2, 3);
|
||||
}
|
||||
106
examples/basic/0028-basic-functions.sx
Normal file
106
examples/basic/0028-basic-functions.sx
Normal file
@@ -0,0 +1,106 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/math";
|
||||
#import "modules/build.sx";
|
||||
#import "modules/std/test.sx";
|
||||
pkg :: #import "tests/fixtures/testpkg";
|
||||
|
||||
add :: (a: i32, b: i32) -> i32 { a + b }
|
||||
|
||||
mul :: (a: i32, b: i32) -> i32 { a * b }
|
||||
|
||||
identity :: (x: $T) -> T { x }
|
||||
|
||||
pair_add :: (a: $T, b: $U) -> i64 {
|
||||
cast(i64) a + cast(i64) b
|
||||
}
|
||||
|
||||
typed_sum :: (..args: []i32) -> i32 {
|
||||
result := 0;
|
||||
for args (it) { result = result + it; }
|
||||
result
|
||||
}
|
||||
|
||||
apply :: (f: (i32, i32) -> i32, x: i32, y: i32) -> i32 {
|
||||
f(x, y)
|
||||
}
|
||||
|
||||
void_return :: () {
|
||||
return;
|
||||
}
|
||||
|
||||
implicit_return :: (x: i32) -> i32 {
|
||||
x * 2
|
||||
}
|
||||
|
||||
early_return :: (x: i32) -> i32 {
|
||||
if x > 10 { return 99; }
|
||||
x
|
||||
}
|
||||
|
||||
main :: () {
|
||||
|
||||
// ========================================================
|
||||
// 5. FUNCTIONS & DECLARATIONS
|
||||
// ========================================================
|
||||
print("=== 5. Functions ===\n");
|
||||
|
||||
// Constant binding
|
||||
FORTY_TWO :: 42;
|
||||
print("const: {}\n", FORTY_TWO);
|
||||
|
||||
// Typed constant
|
||||
TYPED_PI : f64 : 3.14;
|
||||
print("typed-const: {}\n", TYPED_PI);
|
||||
|
||||
// Variable with default init
|
||||
di : i32;
|
||||
print("default-init: {}\n", di);
|
||||
|
||||
// Implicit return
|
||||
print("implicit-ret: {}\n", implicit_return(21));
|
||||
|
||||
// Explicit return
|
||||
print("early-ret: {}\n", early_return(5));
|
||||
print("early-ret2: {}\n", early_return(20));
|
||||
|
||||
// Void return
|
||||
void_return();
|
||||
print("void-return: ok\n");
|
||||
|
||||
// Generic — single param
|
||||
print("generic-i32: {}\n", identity(42));
|
||||
print("generic-f32: {}\n", identity(1.5));
|
||||
print("generic-bool: {}\n", identity(true));
|
||||
|
||||
// Generic — multiple params
|
||||
print("generic-multi: {}\n", pair_add(10, 20));
|
||||
|
||||
// Lambda
|
||||
double :: (x: i32) => x * 2;
|
||||
print("lambda: {}\n", double(7));
|
||||
|
||||
// Lambda with return type
|
||||
halve :: (x: f32) -> f32 => x / 2.0;
|
||||
print("lambda-ret: {}\n", halve(10.0));
|
||||
|
||||
// Local function (non-lambda)
|
||||
local_add :: (a: i32, b: i32) -> i32 { a + b }
|
||||
print("local-fn: {}\n", local_add(3, 4));
|
||||
|
||||
// Nested function calls
|
||||
print("fn-nested: {}\n", add(mul(2, 3), mul(4, 5)));
|
||||
|
||||
// Variadic (typed)
|
||||
print("varargs: {}\n", typed_sum(1, 2, 3, 4, 5));
|
||||
|
||||
// Spread
|
||||
spread_arr : [3]i32 = .[10, 20, 30];
|
||||
print("spread: {}\n", typed_sum(..spread_arr));
|
||||
|
||||
// Function pointers
|
||||
fp : (i32, i32) -> i32 = add;
|
||||
print("fp: {}\n", fp(3, 4));
|
||||
fp = mul;
|
||||
print("fp-reassign: {}\n", fp(3, 4));
|
||||
print("fp-apply: {}\n", apply(add, 10, 20));
|
||||
}
|
||||
79
examples/basic/0029-basic-scoping.sx
Normal file
79
examples/basic/0029-basic-scoping.sx
Normal file
@@ -0,0 +1,79 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/math";
|
||||
#import "modules/build.sx";
|
||||
#import "modules/std/test.sx";
|
||||
pkg :: #import "tests/fixtures/testpkg";
|
||||
|
||||
main :: () {
|
||||
|
||||
// ========================================================
|
||||
// 6. SCOPING & DEFER
|
||||
// ========================================================
|
||||
print("=== 6. Scoping ===\n");
|
||||
|
||||
// Scope block with shadowing
|
||||
sv := 100;
|
||||
{
|
||||
sv := 200;
|
||||
print("inner: {}\n", sv);
|
||||
}
|
||||
print("outer: {}\n", sv);
|
||||
|
||||
// Shadow with different type
|
||||
st_v := 42;
|
||||
print("shadow-type: {}\n", st_v);
|
||||
{
|
||||
st_v := 3.14;
|
||||
print("shadow-type: {}\n", st_v);
|
||||
}
|
||||
|
||||
// Nested scopes (3 levels)
|
||||
nv := 1;
|
||||
{
|
||||
nv := 2;
|
||||
{
|
||||
nv := 3;
|
||||
print("nest3: {}\n", nv);
|
||||
}
|
||||
print("nest2: {}\n", nv);
|
||||
}
|
||||
print("nest1: {}\n", nv);
|
||||
|
||||
// Scope isolation
|
||||
{ iso := 100; print("scope-isolate: {}\n", iso); }
|
||||
|
||||
// Reuse name after scope exit
|
||||
sr := 1;
|
||||
print("scope-reuse: {}\n", sr);
|
||||
{ sr := 2; print("scope-reuse: {}\n", sr); }
|
||||
print("scope-reuse: {}\n", sr);
|
||||
|
||||
// Multiple defers (LIFO order)
|
||||
{
|
||||
defer print("defer-c\n");
|
||||
defer print("defer-b\n");
|
||||
defer print("defer-a\n");
|
||||
}
|
||||
|
||||
// Four defers
|
||||
{
|
||||
defer print("d1\n");
|
||||
defer print("d2\n");
|
||||
defer print("d3\n");
|
||||
defer print("d4\n");
|
||||
}
|
||||
|
||||
// Defer in nested scopes
|
||||
{
|
||||
defer print("outer-defer\n");
|
||||
{
|
||||
defer print("inner-defer\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Defer in if block
|
||||
if true {
|
||||
defer print("defer-in-if: deferred\n");
|
||||
print("defer-in-if: body\n");
|
||||
}
|
||||
}
|
||||
127
examples/basic/0030-basic-builtins.sx
Normal file
127
examples/basic/0030-basic-builtins.sx
Normal file
@@ -0,0 +1,127 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/math";
|
||||
#import "modules/build.sx";
|
||||
#import "modules/std/test.sx";
|
||||
pkg :: #import "tests/fixtures/testpkg";
|
||||
|
||||
Point :: struct { x, y: i32; }
|
||||
|
||||
Color :: enum { red; green; blue; }
|
||||
|
||||
Shape :: enum {
|
||||
circle: f32;
|
||||
rect: struct { w, h: f32; };
|
||||
none;
|
||||
}
|
||||
|
||||
main :: () {
|
||||
|
||||
// ========================================================
|
||||
// 7. BUILT-IN FUNCTIONS
|
||||
// ========================================================
|
||||
print("=== 7. Builtins ===\n");
|
||||
|
||||
// out
|
||||
out("out-ok\n");
|
||||
|
||||
// sqrt
|
||||
print("sqrt: {}\n", sqrt(9.0));
|
||||
print("sqrt-f64: {}\n", sqrt(16.0));
|
||||
|
||||
// size_of
|
||||
print("sizeof-i32: {}\n", size_of(i32));
|
||||
print("sizeof-f64: {}\n", size_of(f64));
|
||||
print("sizeof-struct: {}\n", size_of(Point));
|
||||
|
||||
// align_of
|
||||
print("alignof-u8: {}\n", align_of(u8));
|
||||
print("alignof-i32: {}\n", align_of(i32));
|
||||
print("alignof-i64: {}\n", align_of(i64));
|
||||
print("alignof-struct: {}\n", align_of(Point));
|
||||
|
||||
// type_of + category matching
|
||||
tv := 42;
|
||||
ttype := type_of(tv);
|
||||
if ttype == {
|
||||
case int: print("typeof: int\n");
|
||||
case float: print("typeof: float\n");
|
||||
else: print("typeof: other\n");
|
||||
}
|
||||
|
||||
// type_of — float
|
||||
tf := 3.14;
|
||||
if type_of(tf) == {
|
||||
case float: print("typeof-float: float\n");
|
||||
else: print("typeof-float: other\n");
|
||||
}
|
||||
|
||||
// type_of — string
|
||||
ts := "hello";
|
||||
if type_of(ts) == {
|
||||
case string: print("typeof-string: string\n");
|
||||
else: print("typeof-string: other\n");
|
||||
}
|
||||
|
||||
// type_of — bool
|
||||
tb := true;
|
||||
if type_of(tb) == {
|
||||
case bool: print("typeof-bool: bool\n");
|
||||
else: print("typeof-bool: other\n");
|
||||
}
|
||||
|
||||
// type_of — struct
|
||||
tst := Point.{ 1, 2 };
|
||||
if type_of(tst) == {
|
||||
case struct: print("typeof-struct: struct\n");
|
||||
else: print("typeof-struct: other\n");
|
||||
}
|
||||
|
||||
// type_of — enum
|
||||
ten : Color = .red;
|
||||
if type_of(ten) == {
|
||||
case enum: print("typeof-enum: enum\n");
|
||||
else: print("typeof-enum: other\n");
|
||||
}
|
||||
|
||||
// type_name
|
||||
print("typename: {}\n", type_name(Point));
|
||||
|
||||
// field_count on struct
|
||||
print("fieldcount: {}\n", field_count(Point));
|
||||
|
||||
// field_count on enum
|
||||
print("fieldcount-enum: {}\n", field_count(Color));
|
||||
|
||||
// field_name on struct
|
||||
print("fieldname0: {}\n", field_name(Point, 0));
|
||||
print("fieldname1: {}\n", field_name(Point, 1));
|
||||
|
||||
// field_name on enum
|
||||
print("fieldname-enum0: {}\n", field_name(Color, 0));
|
||||
print("fieldname-enum2: {}\n", field_name(Color, 2));
|
||||
|
||||
// field_value (use any_to_string to avoid sext-on-Any bug)
|
||||
fv_pt := Point.{ 11, 22 };
|
||||
out("fieldval0: ");
|
||||
out(any_to_string(field_value(fv_pt, 0)));
|
||||
out("\n");
|
||||
out("fieldval1: ");
|
||||
out(any_to_string(field_value(fv_pt, 1)));
|
||||
out("\n");
|
||||
|
||||
// field_index on plain enum
|
||||
fi_c : Color = .green;
|
||||
print("fieldidx: {}\n", field_index(Color, fi_c));
|
||||
|
||||
// field_index on tagged enum
|
||||
fi_sh : Shape = .circle(1.0);
|
||||
print("fieldidx-tagged: {}\n", field_index(Shape, fi_sh));
|
||||
fi_sh2 : Shape = .none;
|
||||
print("fieldidx-tagged2: {}\n", field_index(Shape, fi_sh2));
|
||||
|
||||
// cast
|
||||
cval : f64 = 3.7;
|
||||
print("cast: {}\n", cast(i32) cval);
|
||||
cv2 : i32 = 42;
|
||||
print("cast-int-f64: {}\n", cast(f64) cv2);
|
||||
}
|
||||
30
examples/basic/0031-basic-local-fn-return.sx
Normal file
30
examples/basic/0031-basic-local-fn-return.sx
Normal file
@@ -0,0 +1,30 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/math";
|
||||
#import "modules/build.sx";
|
||||
#import "modules/std/test.sx";
|
||||
pkg :: #import "tests/fixtures/testpkg";
|
||||
|
||||
Point :: struct { x, y: i32; }
|
||||
|
||||
Shape :: enum {
|
||||
circle: f32;
|
||||
rect: struct { w, h: f32; };
|
||||
none;
|
||||
}
|
||||
|
||||
main :: () {
|
||||
|
||||
// ========================================================
|
||||
// 19. LOCAL FUNCTION RETURNING STRUCT/ENUM
|
||||
// ========================================================
|
||||
print("=== 19. Local Fn Return ===\n");
|
||||
{
|
||||
local_pt :: () -> Point { Point.{42, 99} }
|
||||
lp := local_pt();
|
||||
print("local-struct: {} {}\n", lp.x, lp.y);
|
||||
|
||||
local_sh :: () -> Shape { .circle(2.5) }
|
||||
ls := local_sh();
|
||||
print("local-enum: {}\n", ls);
|
||||
}
|
||||
}
|
||||
24
examples/basic/0032-basic-ufcs-return-type.sx
Normal file
24
examples/basic/0032-basic-ufcs-return-type.sx
Normal file
@@ -0,0 +1,24 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/math";
|
||||
#import "modules/build.sx";
|
||||
#import "modules/std/test.sx";
|
||||
pkg :: #import "tests/fixtures/testpkg";
|
||||
|
||||
Point :: struct { x, y: i32; }
|
||||
|
||||
point_sum :: (p: Point) -> i32 { p.x + p.y }
|
||||
|
||||
// #run compile-time constants
|
||||
|
||||
main :: () {
|
||||
|
||||
// ========================================================
|
||||
// 20. PIPE UFCS RETURN TYPE INFERENCE
|
||||
// ========================================================
|
||||
print("=== 20. UFCS Return Type ===\n");
|
||||
{
|
||||
p := Point.{3, 4};
|
||||
print("direct: {}\n", point_sum(p));
|
||||
print("ufcs: {}\n", p |> point_sum());
|
||||
}
|
||||
}
|
||||
22
examples/basic/0033-basic-if-struct.sx
Normal file
22
examples/basic/0033-basic-if-struct.sx
Normal file
@@ -0,0 +1,22 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/math";
|
||||
#import "modules/build.sx";
|
||||
#import "modules/std/test.sx";
|
||||
pkg :: #import "tests/fixtures/testpkg";
|
||||
|
||||
Point :: struct { x, y: i32; }
|
||||
|
||||
main :: () {
|
||||
|
||||
// ========================================================
|
||||
// 22. IF-EXPRESSION RETURNING STRUCT
|
||||
// ========================================================
|
||||
print("=== 22. If-Struct ===\n");
|
||||
{
|
||||
flag := true;
|
||||
p := if flag { Point.{10, 20} } else { Point.{30, 40} };
|
||||
print("if-struct: {} {}\n", p.x, p.y);
|
||||
q := if !flag { Point.{10, 20} } else { Point.{30, 40} };
|
||||
print("else-struct: {} {}\n", q.x, q.y);
|
||||
}
|
||||
}
|
||||
23
examples/basic/0034-basic-string-comparison.sx
Normal file
23
examples/basic/0034-basic-string-comparison.sx
Normal file
@@ -0,0 +1,23 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/math";
|
||||
#import "modules/build.sx";
|
||||
#import "modules/std/test.sx";
|
||||
pkg :: #import "tests/fixtures/testpkg";
|
||||
|
||||
main :: () {
|
||||
|
||||
// ========================================================
|
||||
// 24. STRING COMPARISON
|
||||
// ========================================================
|
||||
print("=== 24. String Comparison ===\n");
|
||||
{
|
||||
a := "hello";
|
||||
b := "hello";
|
||||
c := "world";
|
||||
print("str-eq: {}\n", a == b);
|
||||
print("str-neq: {}\n", a != c);
|
||||
print("str-diff: {}\n", a == c);
|
||||
empty := "";
|
||||
print("empty-eq: {}\n", empty == "");
|
||||
}
|
||||
}
|
||||
24
examples/basic/0035-basic-array-loop-mutation.sx
Normal file
24
examples/basic/0035-basic-array-loop-mutation.sx
Normal file
@@ -0,0 +1,24 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/math";
|
||||
#import "modules/build.sx";
|
||||
#import "modules/std/test.sx";
|
||||
pkg :: #import "tests/fixtures/testpkg";
|
||||
|
||||
main :: () {
|
||||
|
||||
// ========================================================
|
||||
// 25. ARRAY LOOP MUTATION
|
||||
// ========================================================
|
||||
print("=== 25. Array Loop Mutation ===\n");
|
||||
{
|
||||
arr : [4]i32 = .[0, 0, 0, 0];
|
||||
i := 0;
|
||||
while i < 4 {
|
||||
arr[i] = xx (i + 1);
|
||||
i += 1;
|
||||
}
|
||||
print("loop-fill: {} {} {} {}\n", arr[0], arr[1], arr[2], arr[3]);
|
||||
arr[2] += 10;
|
||||
print("compound: {}\n", arr[2]);
|
||||
}
|
||||
}
|
||||
42
examples/basic/0036-basic-ufcs-aliases.sx
Normal file
42
examples/basic/0036-basic-ufcs-aliases.sx
Normal file
@@ -0,0 +1,42 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/math";
|
||||
#import "modules/build.sx";
|
||||
#import "modules/std/test.sx";
|
||||
pkg :: #import "tests/fixtures/testpkg";
|
||||
|
||||
main :: () {
|
||||
|
||||
// --- UFCS Aliases & Pipe ---
|
||||
{
|
||||
print("=== UFCS Aliases ===\n");
|
||||
|
||||
num_sum :: (a: i64, b: i64) -> i64 { a + b }
|
||||
sum :: ufcs num_sum;
|
||||
|
||||
print("{}\n", num_sum(40, 2)); // 42 — direct call
|
||||
print("{}\n", sum(40, 2)); // 42 — alias direct call
|
||||
print("{}\n", 40 |> sum(2)); // 42 — pipe UFCS via alias
|
||||
|
||||
print("{}\n", num_sum(40, 2)); // 42 — direct (was tuple full-splat)
|
||||
print("{}\n", 40 |> sum(2)); // 42 — pipe (was tuple partial-splat)
|
||||
|
||||
compute :: (a: i64, b: i64, c: i64, d: i64) -> i64 { a + b * c - d }
|
||||
calc :: ufcs compute;
|
||||
|
||||
print("{}\n", compute(1, 2, 3, 4)); // 1+2*3-4 = 3 (was tuple full-splat)
|
||||
print("{}\n", compute(1, 2, 3, 4)); // same = 3 (was tuple partial-splat)
|
||||
print("{}\n", 1 |> calc(2, 3, 4)); // same = 3 — pipe UFCS
|
||||
|
||||
// Tuple return type
|
||||
swap :: (a: i64, b: i64) -> (i64, i64) { (b, a) }
|
||||
s := swap(1, 2);
|
||||
a := s.0;
|
||||
b := s.1;
|
||||
print("{}\n", a); // 2
|
||||
print("{}\n", b); // 1
|
||||
|
||||
wrap :: (x: i64) -> (i64) { (x,) }
|
||||
t := wrap(99);
|
||||
print("{}\n", t.0); // 99
|
||||
}
|
||||
}
|
||||
36
examples/basic/0037-basic-trailing-commas.sx
Normal file
36
examples/basic/0037-basic-trailing-commas.sx
Normal file
@@ -0,0 +1,36 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/math";
|
||||
#import "modules/build.sx";
|
||||
#import "modules/std/test.sx";
|
||||
pkg :: #import "tests/fixtures/testpkg";
|
||||
|
||||
add :: (a: i32, b: i32) -> i32 { a + b }
|
||||
|
||||
main :: () {
|
||||
|
||||
// ── Trailing commas ──────────────────────────────────────────
|
||||
print("=== Trailing Commas ===\n");
|
||||
{
|
||||
// Struct literal with trailing comma
|
||||
Vec4 :: struct { x: f64; y: f64; z: f64; w: f64; }
|
||||
v := Vec4.{
|
||||
x = 1.0,
|
||||
y = 2.0,
|
||||
z = 3.0,
|
||||
w = 4.0,
|
||||
};
|
||||
assert(v.x == 1.0);
|
||||
assert(v.w == 4.0);
|
||||
|
||||
// Function call with trailing comma
|
||||
add :: (a: i64, b: i64) -> i64 { return a + b; }
|
||||
r := add(10, 20,);
|
||||
assert(r == 30);
|
||||
|
||||
// Array literal with trailing comma
|
||||
arr := i64.[1, 2, 3,];
|
||||
assert(arr[2] == 3);
|
||||
|
||||
print("trailing commas ok\n");
|
||||
}
|
||||
}
|
||||
34
examples/basic/0038-basic-dead-code-after-terminator.sx
Normal file
34
examples/basic/0038-basic-dead-code-after-terminator.sx
Normal file
@@ -0,0 +1,34 @@
|
||||
// Dead statements after a block-terminating statement (`return` / `raise`) are
|
||||
// dropped instead of being emitted into the already-closed basic block.
|
||||
// Regression (issue 0061): a bare `return X;` / `raise` mid-block closed the
|
||||
// LLVM basic block but lowering kept emitting the trailing statements into it
|
||||
// → "Terminator found in the middle of a basic block". The canonical failable
|
||||
// closure form `{ raise error.X; return x; }` tripped this, blocking ERR E5.1.
|
||||
//
|
||||
// The fix must NOT over-reach: a CONDITIONAL `if cond { return }` (and the
|
||||
// `inline if` pack form) leaves a fresh merge block, so its trailing statements
|
||||
// must still run — exercised by `clamp` / `pick` below.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
E :: error { Neg }
|
||||
|
||||
// dead `return 99;` after an unconditional return
|
||||
const_one :: () -> i64 { return 1; return 99; }
|
||||
|
||||
// dead `return x;` after an unconditional raise (the failable closure shape)
|
||||
always_raise :: (x: i64) -> (i64, !E) { raise error.Neg; return x; }
|
||||
|
||||
// guard: a conditional return must still fall through to the trailing return
|
||||
clamp :: (x: i64) -> i64 { if x > 10 { return 10; } return x; }
|
||||
|
||||
main :: () -> i32 {
|
||||
print("const_one={}\n", const_one()); // 1
|
||||
print("raised={}\n", always_raise(5) catch (e) 0); // 0
|
||||
print("clamp_hi={}\n", clamp(42)); // 10
|
||||
print("clamp_lo={}\n", clamp(7)); // 7
|
||||
|
||||
// dead code after a `return` at main's own block level is dropped.
|
||||
return 0;
|
||||
print("unreachable\n")
|
||||
}
|
||||
26
examples/basic/0039-basic-free-fn-ufcs-pointer-receiver.sx
Normal file
26
examples/basic/0039-basic-free-fn-ufcs-pointer-receiver.sx
Normal file
@@ -0,0 +1,26 @@
|
||||
// Free-function UFCS with a pointer first-param (issue 0063). `recv.fn(args)`
|
||||
// on a value `recv` whose matching free function takes `*T` now takes the
|
||||
// receiver's address (the same implicit address-of as a struct-defined method),
|
||||
// so mutations through the pointer are visible. Also: a function reached ONLY
|
||||
// via UFCS is lazily lowered (previously declared-but-never-emitted → undefined
|
||||
// symbol at link).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Counter :: struct { n: i32; }
|
||||
|
||||
// FREE functions (defined outside the struct), pointer first param.
|
||||
bump :: ufcs (c: *Counter) -> i32 { c.n += 1; return c.n; }
|
||||
// reached ONLY via UFCS — must still be emitted.
|
||||
reset :: ufcs (c: *Counter) { c.n = 0; }
|
||||
|
||||
main :: () -> i32 {
|
||||
c := Counter.{ n = 10 };
|
||||
a := c.bump(); // 11, mutates c
|
||||
b := c.bump(); // 12
|
||||
print("a={} b={} n={}\n", a, b, c.n); // a=11 b=12 n=12
|
||||
|
||||
c.reset(); // UFCS-only free fn
|
||||
print("after reset n={}\n", c.n); // after reset n=0
|
||||
return 0;
|
||||
}
|
||||
46
examples/basic/0040-basic-block-value.sx
Normal file
46
examples/basic/0040-basic-block-value.sx
Normal file
@@ -0,0 +1,46 @@
|
||||
// Block value rule: a block's value is its last statement ONLY when that
|
||||
// statement is a trailing expression with NO `;`. A trailing `;` discards the
|
||||
// value, leaving the block void. This makes value-vs-statement explicit and lets
|
||||
// the compiler reject "forgot to produce a value".
|
||||
//
|
||||
// { … expr } → value is `expr`
|
||||
// { … expr; } → void (value discarded)
|
||||
//
|
||||
// Match arms are exempt: the arm `;` is an arm terminator, so `case .x: expr;`
|
||||
// still yields `expr` (only an explicit inner braced block follows the rule).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
// Implicit return: trailing expression, no `;`.
|
||||
double :: (n: i32) -> i32 { n * 2 }
|
||||
|
||||
// if/else as a value — each branch's last expression has no `;`.
|
||||
sign :: (n: i32) -> i32 {
|
||||
if n < 0 { -1 } else if n > 0 { 1 } else { 0 }
|
||||
}
|
||||
|
||||
// A value-producing block bound to a name.
|
||||
sum3 :: (a: i32, b: i32, c: i32) -> i32 {
|
||||
t := { x := a + b; x + c }; // block value is `x + c`
|
||||
t
|
||||
}
|
||||
|
||||
// Match arms keep their `;` (exempt): the arm `;` is an arm terminator, so each
|
||||
// arm still yields its expression as the match value.
|
||||
classify :: (n: i32) -> i32 {
|
||||
if n == {
|
||||
case 0: 100;
|
||||
case 1: 10;
|
||||
else: 7;
|
||||
}
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
total : i32 = 0;
|
||||
total = total + double(10); // 20
|
||||
total = total + sign(-7); // -1
|
||||
total = total + sum3(1, 2, 3); // 6
|
||||
total = total + classify(1); // 10
|
||||
print("block-value total: {}\n", total); // 20 - 1 + 6 + 10 = 35
|
||||
total
|
||||
}
|
||||
13
examples/basic/0041-basic-block-value-reject.sx
Normal file
13
examples/basic/0041-basic-block-value-reject.sx
Normal file
@@ -0,0 +1,13 @@
|
||||
// Rejection counterpart to 0040: a value-position block whose last expression's
|
||||
// value is discarded by a trailing `;` produces no value. A `-> T` function
|
||||
// whose body ends that way is a compile error (it used to silently return a
|
||||
// zero default). Drop the `;` to return the value, or use an explicit `return`.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
// `n * 2;` discards the value → the function returns nothing.
|
||||
double :: (n: i32) -> i32 {
|
||||
n * 2;
|
||||
}
|
||||
|
||||
main :: () -> i32 { double(5) }
|
||||
25
examples/basic/0042-basic-block-value-destructure.sx
Normal file
25
examples/basic/0042-basic-block-value-destructure.sx
Normal file
@@ -0,0 +1,25 @@
|
||||
// A value-position block (`x := { … }`, a call argument, …) parses any
|
||||
// statement form in its body — including a destructure decl — and yields its
|
||||
// trailing expression as the value. Previously a braced value block routed
|
||||
// through a restricted expression parser that rejected destructures with
|
||||
// "expected ';'".
|
||||
//
|
||||
// Regression (issue 0065).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
pair :: () -> (i32, i32) { (5, 7) }
|
||||
|
||||
main :: () -> i32 {
|
||||
// destructure decl inside a value-bound block
|
||||
sum := {
|
||||
a, b := pair();
|
||||
a + b // trailing expression → the block's value
|
||||
};
|
||||
print("sum: {}\n", sum); // 12
|
||||
|
||||
// block expression directly as a call argument
|
||||
print("sq: {}\n", { x := 4; x * x }); // 16
|
||||
|
||||
sum
|
||||
}
|
||||
31
examples/basic/0043-basic-match-value-mixed-width.sx
Normal file
31
examples/basic/0043-basic-match-value-mixed-width.sx
Normal file
@@ -0,0 +1,31 @@
|
||||
// A value-position match (`if subject == { case … }`) returning a small
|
||||
// integer type works when arms mix positive and negated literals: every arm
|
||||
// value is lowered against the merge's result type, so the phi operands all
|
||||
// share one width.
|
||||
//
|
||||
// Regression (issue 0066): a negated-literal arm (`else: -1`) previously
|
||||
// lowered at a narrower width than the positive arms, tripping LLVM's
|
||||
// "PHI node operands are not the same type as the result".
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
sign :: (n: i32) -> i32 {
|
||||
if n == {
|
||||
case 0: 0;
|
||||
else: if n > 0 then 1 else -1;
|
||||
}
|
||||
}
|
||||
|
||||
classify :: (n: i32) -> i32 {
|
||||
if n == {
|
||||
case 0: 100;
|
||||
case 1: 10;
|
||||
else: -1;
|
||||
}
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("sign: {} {} {}\n", sign(-9), sign(0), sign(9)); // -1 0 1
|
||||
print("classify: {} {} {}\n", classify(0), classify(1), classify(5)); // 100 10 -1
|
||||
0
|
||||
}
|
||||
23
examples/basic/0044-basic-default-arg-expansion.sx
Normal file
23
examples/basic/0044-basic-default-arg-expansion.sx
Normal file
@@ -0,0 +1,23 @@
|
||||
// Call-site default-argument expansion (`appendDefaultArgs` / `expandCallDefaults`
|
||||
// in lowerCall). A call that omits a trailing parameter with a default value
|
||||
// has the default expression spliced in at the call site; an explicit argument
|
||||
// overrides it. Two trailing defaults cover the "fill all remaining" path.
|
||||
// Path-free IR (literal defaults) so the `.ir` snapshot is location-stable.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
scale :: (n: i32, factor: i32 = 2) -> i32 { n * factor }
|
||||
|
||||
label :: (n: i32, prefix: string = "v", suffix: string = "!") -> i32 {
|
||||
print("{}{}{}\n", prefix, n, suffix);
|
||||
n
|
||||
}
|
||||
|
||||
main :: () {
|
||||
print("default: {}\n", scale(5));
|
||||
print("explicit: {}\n", scale(5, 3));
|
||||
|
||||
_ = label(1); // both defaults filled
|
||||
_ = label(2, "x"); // suffix default filled
|
||||
_ = label(3, "y", "?"); // no defaults
|
||||
}
|
||||
53
examples/basic/0045-basic-string-eq-short-circuit.sx
Normal file
53
examples/basic/0045-basic-string-eq-short-circuit.sx
Normal file
@@ -0,0 +1,53 @@
|
||||
// String `==`/`!=` as an operand of a short-circuit `and`/`or`.
|
||||
//
|
||||
// A string compare lowers to its own multi-block memcmp sub-CFG, so the
|
||||
// operand finishes in a later basic block than the one the short-circuit
|
||||
// started in. The `and`/`or` merge PHI must take that actual block as the
|
||||
// incoming predecessor.
|
||||
//
|
||||
// Regression (issue 0078): combining string equality with `and`/`or` used to
|
||||
// emit invalid LLVM (`PHI node entries do not match predecessors!`).
|
||||
#import "modules/std.sx";
|
||||
|
||||
Json :: enum {
|
||||
str: string;
|
||||
int_: i64;
|
||||
null_;
|
||||
}
|
||||
|
||||
main :: () {
|
||||
a := "k";
|
||||
b := "v";
|
||||
|
||||
// string == on both sides of `and`
|
||||
and_tt := a == "k" and b == "v";
|
||||
and_tf := a == "k" and b == "x";
|
||||
and_ft := a == "z" and b == "v";
|
||||
print("and: {} {} {}\n", and_tt, and_tf, and_ft);
|
||||
|
||||
// string == on both sides of `or`
|
||||
or_ff := a == "z" or b == "x";
|
||||
or_tf := a == "k" or b == "x";
|
||||
or_ft := a == "z" or b == "v";
|
||||
print("or: {} {} {}\n", or_ff, or_tf, or_ft);
|
||||
|
||||
// string == feeding both `and` and `or` in one expression
|
||||
mixed := a == "k" and b == "v" or a == "z";
|
||||
print("mixed: {}\n", mixed);
|
||||
|
||||
// string `!=` operands too
|
||||
ne := a != "z" and b != "z";
|
||||
print("ne: {}\n", ne);
|
||||
|
||||
// the larger shape: a match-expression value plus an enum-payload string
|
||||
// == combined under `and`/`or`.
|
||||
v : Json = .str("v");
|
||||
kind := if v == {
|
||||
case .str: 1;
|
||||
case .int_: 2;
|
||||
case .null_: 3;
|
||||
}
|
||||
ok := kind == 1 and v.str == "v";
|
||||
bad := kind == 2 or v.str == "x";
|
||||
print("payload: {} {}\n", ok, bad);
|
||||
}
|
||||
37
examples/basic/0046-basic-int-formatter-extremes.sx
Normal file
37
examples/basic/0046-basic-int-formatter-extremes.sx
Normal file
@@ -0,0 +1,37 @@
|
||||
// Integer `{}` formatting across the full signed/unsigned range.
|
||||
//
|
||||
// Regression (issue 0090): the `{}` formatter was i64-based — it negated
|
||||
// the value to print the sign (so i64::MIN, whose magnitude is
|
||||
// unrepresentable as a positive i64, rendered as a bare "-"), and it had
|
||||
// no unsigned-aware path (so a u64 all-ones value printed as the i64
|
||||
// reinterpretation, "-1"). Both extremes now render correctly: signed
|
||||
// MIN prints all its digits, and unsigned integers print as unsigned
|
||||
// decimal across all 64 bits.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
main :: () {
|
||||
// Signed extreme: magnitude is never negated, so MIN survives.
|
||||
print("i64.min={}\n", i64.min);
|
||||
print("i64.max={}\n", i64.max);
|
||||
|
||||
// Unsigned extreme: all 64 bits as unsigned decimal, not -1.
|
||||
print("u64.max={}\n", u64.max);
|
||||
|
||||
// Spread across widths — signed.
|
||||
print("i8.min={} i8.max={}\n", i8.min, i8.max);
|
||||
print("i16.min={} i16.max={}\n", i16.min, i16.max);
|
||||
print("i32.min={} i32.max={}\n", i32.min, i32.max);
|
||||
|
||||
// Spread across widths — unsigned (max is all-ones for that width).
|
||||
print("u8.max={} u16.max={}\n", u8.max, u16.max);
|
||||
print("u32.max={}\n", u32.max);
|
||||
|
||||
// Mins of unsigned widths and zero.
|
||||
print("u8.min={} u64.min={} zero={}\n", u8.min, u64.min, 0);
|
||||
|
||||
// Ordinary signed/unsigned values still print correctly.
|
||||
neg : i32 = -42;
|
||||
pos : u32 = 4000000000;
|
||||
print("neg={} pos={}\n", neg, pos);
|
||||
}
|
||||
26
examples/basic/0047-basic-loop-local-stack-reuse.sx
Normal file
26
examples/basic/0047-basic-loop-local-stack-reuse.sx
Normal file
@@ -0,0 +1,26 @@
|
||||
// Loop-body locals reuse one stack slot per frame: a body-declared local
|
||||
// (and every compiler temp) must not grow the stack per iteration, so
|
||||
// million-iteration loops run in constant stack. Covers body locals,
|
||||
// nested loops (the inner loop's hidden index slot), and element reads.
|
||||
// Regression (issue 0109): allocas were emitted at their use site, so each
|
||||
// iteration re-executed them — LLVM only reclaims allocas at `ret`, and
|
||||
// these loops segfaulted on stack exhaustion.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
main :: () -> i32 {
|
||||
sum := 0;
|
||||
for 0..1000000 (i) {
|
||||
buf : [128]i64 = ---;
|
||||
buf[0] = i;
|
||||
sum += buf[0];
|
||||
}
|
||||
print("sum={}\n", sum);
|
||||
|
||||
n := 0;
|
||||
for 0..3000000 (i) {
|
||||
for 0..1 (j) { n += 1; }
|
||||
}
|
||||
print("n={}\n", n);
|
||||
0
|
||||
}
|
||||
24
examples/basic/0048-basic-for-array-large.sx
Normal file
24
examples/basic/0048-basic-for-array-large.sx
Normal file
@@ -0,0 +1,24 @@
|
||||
// Collection-form `for` over an array, by-value capture: each iteration
|
||||
// reads ONE element from the array's storage (GEP + load), and the capture
|
||||
// stays a copy — mutating it never writes back to the array.
|
||||
// Regression (issue 0110): the element fetch was `index_get` on the array
|
||||
// VALUE, spilling a full copy of the array to a stack temp per iteration —
|
||||
// O(N²) bytes copied, and (pre-0109) per-iteration stack growth that made
|
||||
// this 4096-element loop segfault.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
main :: () -> i32 {
|
||||
arr : [4096]i64 = ---;
|
||||
i := 0;
|
||||
while i < 4096 { arr[i] = i; i += 1; }
|
||||
sum := 0;
|
||||
for arr (x) { sum += x; }
|
||||
print("sum={}\n", sum);
|
||||
|
||||
// By-value capture is a copy: mutating it leaves the array untouched.
|
||||
small : [3]i64 = .[10, 20, 30];
|
||||
for small (x) { x += 100; }
|
||||
print("copy-guard: {} {} {}\n", small[0], small[1], small[2]);
|
||||
0
|
||||
}
|
||||
46
examples/basic/0049-basic-defer-break-continue.sx
Normal file
46
examples/basic/0049-basic-defer-break-continue.sx
Normal file
@@ -0,0 +1,46 @@
|
||||
// `defer` runs on EVERY exit from the loop body's scope — fall-through,
|
||||
// `break`, and `continue` alike (LIFO, including entries from nested blocks
|
||||
// between the loop and the jump). Covers `for` ranges and `while`.
|
||||
// Regression (issue 0108): break/continue emitted a bare branch and the
|
||||
// breaking iteration's defers were silently skipped.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
main :: () -> i32 {
|
||||
for 0..3 (i) {
|
||||
defer print("cleanup {}\n", i);
|
||||
if i == 1 { break; }
|
||||
print("body {}\n", i);
|
||||
}
|
||||
print("after break loop\n");
|
||||
|
||||
for 0..3 (i) {
|
||||
defer print("c2 {}\n", i);
|
||||
if i == 1 { continue; }
|
||||
print("b2 {}\n", i);
|
||||
}
|
||||
print("done\n");
|
||||
|
||||
i := 0;
|
||||
while i < 3 {
|
||||
defer print("w{}\n", i);
|
||||
i += 1;
|
||||
if i == 2 { continue; }
|
||||
if i == 3 { break; }
|
||||
print("wbody{}\n", i);
|
||||
}
|
||||
print("while done\n");
|
||||
|
||||
// A break inside a nested block drains the nested block's defers AND the
|
||||
// loop body's, in LIFO order.
|
||||
for 0..2 (j) {
|
||||
defer print("outer {}\n", j);
|
||||
{
|
||||
defer print("inner {}\n", j);
|
||||
if j == 0 { break; }
|
||||
}
|
||||
print("unreached\n");
|
||||
}
|
||||
print("nested done\n");
|
||||
0
|
||||
}
|
||||
54
examples/basic/0050-basic-for-multi-iterable.sx
Normal file
54
examples/basic/0050-basic-for-multi-iterable.sx
Normal file
@@ -0,0 +1,54 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
pair_sum :: (xs: []i64, ys: []i64) -> i64 {
|
||||
total := 0;
|
||||
for xs, ys (x, y) { total += x * y; }
|
||||
total
|
||||
}
|
||||
|
||||
make :: () -> [3]i64 {
|
||||
r : [3]i64 = .[7, 8, 9];
|
||||
r
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
// Agra's example: a 1..5 inclusive, b open-ended following along.
|
||||
for 1..=5, 0.. (a, b) { print("{}:{} ", a, b); }
|
||||
print("\n");
|
||||
|
||||
// Index idiom replacing the old (x, i) form.
|
||||
xs : [3]i64 = .[10, 20, 30];
|
||||
for xs, 0.. (x, i) { print("[{}]={} ", i, x); }
|
||||
print("\n");
|
||||
|
||||
// Parallel slices.
|
||||
a4 : [4]i64 = .[1, 2, 3, 4];
|
||||
b4 : [4]i64 = .[10, 20, 30, 40];
|
||||
print("dot={}\n", pair_sum(a4, b4));
|
||||
|
||||
// Arrow bodies.
|
||||
s := 0;
|
||||
for 0..4 (i) => s += i;
|
||||
print("arrow-range s={}\n", s);
|
||||
t := 0;
|
||||
for xs (x) => t += x;
|
||||
print("arrow-coll t={}\n", t);
|
||||
|
||||
// Call iterable + capture (first group = args, last group = capture).
|
||||
for make() (v) { print("v{} ", v); }
|
||||
print("\n");
|
||||
|
||||
// No-capture call iterable via leading-group escape.
|
||||
n := 0;
|
||||
for (make()) { n += 1; }
|
||||
print("escape n={}\n", n);
|
||||
|
||||
// Three-way zip: two collections + cursor.
|
||||
for a4, b4, 100.. (p, q, k) { print("{}/{}/{} ", p, q, k); }
|
||||
print("\n");
|
||||
|
||||
// By-ref capture in a multi-iterable header.
|
||||
for a4, 0.. (*p, i) { p.* += i; }
|
||||
print("after ref: {} {} {} {}\n", a4[0], a4[1], a4[2], a4[3]);
|
||||
0
|
||||
}
|
||||
63
examples/basic/0051-basic-for-range-bounds.sx
Normal file
63
examples/basic/0051-basic-for-range-bounds.sx
Normal file
@@ -0,0 +1,63 @@
|
||||
// Range bound markers: each side of `..` takes `=` (inclusive) or `<`
|
||||
// (exclusive); defaults are start-inclusive, end-exclusive (`a..b` == `a=..<b`).
|
||||
// Covers the full matrix, open ranges with start markers, comptime unrolling,
|
||||
// runtime bounds, arbitrary expressions at EITHER end (expression parsing
|
||||
// stops at the range token), and that `<` / `<<` comparisons still lex
|
||||
// normally.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
main :: () -> i32 {
|
||||
for 0<..<5 (i) { print("{} ", i); }
|
||||
print("| 0<..<5\n");
|
||||
for 0=..=5 (i) { print("{} ", i); }
|
||||
print("| 0=..=5\n");
|
||||
for 0<..=5 (i) { print("{} ", i); }
|
||||
print("| 0<..=5\n");
|
||||
for 0=..<5 (i) { print("{} ", i); }
|
||||
print("| 0=..<5\n");
|
||||
for 0..<5 (i) { print("{} ", i); }
|
||||
print("| 0..<5\n");
|
||||
for 0..=5 (i) { print("{} ", i); }
|
||||
print("| 0..=5\n");
|
||||
|
||||
// Exclusive-start open range following a bounded first iterable.
|
||||
xs : [3]i64 = .[10, 20, 30];
|
||||
for xs, 2<.. (x, i) { print("{}@{} ", x, i); }
|
||||
print("| xs, 2<..\n");
|
||||
|
||||
// Explicit inclusive-start open form (synonym of `5..`).
|
||||
for xs, 5=.. (x, i) { print("{}@{} ", x, i); }
|
||||
print("| xs, 5=..\n");
|
||||
|
||||
// Comptime-unrolled with markers.
|
||||
s := 0;
|
||||
inline for 0<..=3 (i) { s += i; }
|
||||
print("inline 0<..=3 sum={}\n", s);
|
||||
|
||||
// Runtime bounds with markers.
|
||||
lo := 1;
|
||||
hi := 4;
|
||||
for lo<..=hi (i) { print("{} ", i); }
|
||||
print("| lo<..=hi\n");
|
||||
|
||||
// Arbitrary expressions at either end of the range token.
|
||||
x := 2;
|
||||
n := 0;
|
||||
sum := 0;
|
||||
for x+2..=42 (e) { n += 1; sum += e; } // expression start: 4 .. 42
|
||||
print("x+2..=42: n={} sum={}\n", n, sum);
|
||||
n2 := 0;
|
||||
for x+2<..<x*21 (e) => n2 += 1; // both ends: 5 .. 41
|
||||
print("x+2<..<x*21: n2={}\n", n2);
|
||||
n3 := 0;
|
||||
for 0..x*3 (i) => n3 += 1; // expression end: 0 .. 5
|
||||
print("0..x*3: n3={}\n", n3);
|
||||
|
||||
// Comparison operators still lex normally.
|
||||
a := 3;
|
||||
if a < 5 { print("cmp ok\n"); }
|
||||
b := a << 1;
|
||||
print("shl={}\n", b);
|
||||
0
|
||||
}
|
||||
32
examples/basic/0052-basic-slice-range-bounds.sx
Normal file
32
examples/basic/0052-basic-slice-range-bounds.sx
Normal file
@@ -0,0 +1,32 @@
|
||||
// Slice range bound markers — same matrix as for-header ranges: each side
|
||||
// of `..` takes `=` (inclusive) or `<` (exclusive), defaults 0-inclusive
|
||||
// start / exclusive end. Prefix form takes markers too ([..=2], [<..3]);
|
||||
// [..] is the whole slice; bounds are arbitrary expressions; strings slice
|
||||
// through the same path.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
dump :: (s: []i64, tag: string) {
|
||||
print("{}: ", tag);
|
||||
for s (v) { print("{} ", v); }
|
||||
print("(len {})\n", s.len);
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
xs : [6]i64 = .[10, 11, 12, 13, 14, 15];
|
||||
full : []i64 = xs[0..6];
|
||||
|
||||
dump(full[1..=3], "1..=3"); // 11 12 13
|
||||
dump(full[0<..<4], "0<..<4"); // 11 12 13
|
||||
dump(full[..=2], "..=2"); // 10 11 12
|
||||
dump(full[<..3], "<..3"); // 11 12
|
||||
dump(full[2<..], "2<.."); // 13 14 15
|
||||
dump(full[..], ".."); // all six
|
||||
x := 3;
|
||||
dump(full[x-1..=x+1], "x-1..=x+1"); // 12 13 14
|
||||
|
||||
s := "abcdef";
|
||||
print("str 1..=3: {}\n", s[1..=3]); // bcd
|
||||
print("str 0<..<4: {}\n", s[0<..<4]); // bcd
|
||||
0
|
||||
}
|
||||
35
examples/basic/0053-basic-ufcs-opt-in.sx
Normal file
35
examples/basic/0053-basic-ufcs-opt-in.sx
Normal file
@@ -0,0 +1,35 @@
|
||||
// Free-function dot-calls are OPT-IN. Two opt-in spellings:
|
||||
// name :: ufcs (params) { body } — the fn itself is dot-callable
|
||||
// name :: ufcs target; — dot-callable (renaming) alias
|
||||
// A plain fn is callable directly or via `|>` only (see 1166 for the
|
||||
// rejection). Generic ufcs fns dispatch through normal monomorphization,
|
||||
// and the plan-side return type binds from the receiver (structured
|
||||
// params like `[]$T` included).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
bump :: (x: i64) -> i64 { x + 1 }
|
||||
bump2 :: ufcs (x: i64) -> i64 { x + 2 }
|
||||
bump3 :: ufcs bump;
|
||||
|
||||
Counter :: struct { n: i64; }
|
||||
inc :: ufcs (c: *Counter, by: i64) -> i64 { c.n += by; c.n }
|
||||
|
||||
gfirst :: ufcs (xs: []$T) -> T { xs[0] }
|
||||
|
||||
main :: () {
|
||||
f : i64 = 40;
|
||||
print("marked: {}\n", f.bump2()); // 42
|
||||
print("alias: {}\n", f.bump3()); // 41
|
||||
print("direct: {}\n", bump(f)); // 41 — plain fn, direct
|
||||
print("pipe: {}\n", f |> bump()); // 41 — plain fn, pipe
|
||||
print("marked-direct: {}\n", bump2(f)); // 42 — marked fn callable directly
|
||||
|
||||
c := Counter.{ n = 10 };
|
||||
print("ptr-recv: {}\n", c.inc(5)); // 15 — auto address-of receiver
|
||||
|
||||
arr := .[7, 8, 9];
|
||||
xs : []i64 = arr;
|
||||
print("generic-dot: {}\n", xs.gfirst()); // 7
|
||||
print("generic-direct: {}\n", gfirst(xs)); // 7 — plan types it i64, not a T stub
|
||||
}
|
||||
33
examples/basic/0054-basic-dot-call-default-args.sx
Normal file
33
examples/basic/0054-basic-dot-call-default-args.sx
Normal file
@@ -0,0 +1,33 @@
|
||||
// Trailing parameter defaults fill on method and ufcs dot-calls (the
|
||||
// receiver-prepending dispatch paths), matching bare-call expansion (0044);
|
||||
// a `#caller_location` default and a slice variadic keep their flexible
|
||||
// arity under the call-arity check.
|
||||
// Regression (issue 0123).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Point :: struct {
|
||||
x: i64;
|
||||
scaled :: (self: Point, k: i64 = 2) -> i64 { return self.x * k; }
|
||||
}
|
||||
|
||||
bump :: ufcs (p: Point, by: i64 = 10) -> i64 { return p.x + by; }
|
||||
|
||||
sum_var :: (..xs: []i64) -> i64 {
|
||||
t := 0;
|
||||
for xs (x) { t = t + x; }
|
||||
return t;
|
||||
}
|
||||
|
||||
here :: (loc: Source_Location = #caller_location) -> i64 { return loc.line; }
|
||||
|
||||
main :: () {
|
||||
p := Point.{ x = 5 };
|
||||
print("{}\n", p.scaled()); // default filled on method dispatch
|
||||
print("{}\n", p.scaled(3)); // explicit overrides
|
||||
print("{}\n", p.bump()); // default filled on ufcs dispatch
|
||||
print("{}\n", p.bump(1));
|
||||
print("{}\n", sum_var()); // variadic: zero args
|
||||
print("{}\n", sum_var(1, 2, 3)); // variadic: many args
|
||||
print("{}\n", here() > 0); // #caller_location default
|
||||
}
|
||||
45
examples/basic/0055-basic-large-stack-array.sx
Normal file
45
examples/basic/0055-basic-large-stack-array.sx
Normal file
@@ -0,0 +1,45 @@
|
||||
// Large (64KB+) stack arrays compile and are accessed in place: `---`
|
||||
// emits no initializer store, and element reads GEP the array's storage
|
||||
// instead of loading the whole array as a value.
|
||||
//
|
||||
// Regression (issue 0124): both whole-aggregate shapes — the undef
|
||||
// store from `---` and `index_get` on the loaded array value —
|
||||
// scalarized into one SelectionDAG node per element and segfaulted
|
||||
// `sx build` at [65536]u8.
|
||||
//
|
||||
// Results print via out/int_to_string: `{}` formatting would pull the
|
||||
// any_to_string dispatcher, whose array arms materialize every interned
|
||||
// array type BY VALUE — the separate issue 0125.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
checksum :: () -> i64 {
|
||||
buf : [65536]u8 = ---;
|
||||
i := 0;
|
||||
while i < 65536 {
|
||||
buf[i] = xx (i % 251);
|
||||
i += 1;
|
||||
}
|
||||
sum := 0;
|
||||
i = 0;
|
||||
while i < 65536 {
|
||||
sum += xx buf[i];
|
||||
i += 1;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
big :: () -> i64 {
|
||||
buf : [131072]i64 = ---;
|
||||
buf[0] = 11;
|
||||
buf[131071] = 31;
|
||||
return buf[0] + buf[131071];
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
out(int_to_string(checksum()));
|
||||
out("\n");
|
||||
out(int_to_string(big()));
|
||||
out("\n");
|
||||
return 0;
|
||||
}
|
||||
27
examples/basic/0056-basic-large-array-format-no-blowup.sx
Normal file
27
examples/basic/0056-basic-large-array-format-no-blowup.sx
Normal file
@@ -0,0 +1,27 @@
|
||||
// Interning a large (~64KB) array type and using `{}` formatting elsewhere must
|
||||
// NOT scalarize into an O(N) SelectionDAG (which crashed `sx build` / made
|
||||
// `sx run` take ~12s). The array Any-unbox formats via a SLICE VIEW of its
|
||||
// storage — no whole-array load.
|
||||
//
|
||||
// Regression (issue 0125): `any_to_string`'s `case array:` arm used to do
|
||||
// `array_to_string(cast(type) val)`, loading the whole [65536]u8 by value and
|
||||
// reading each element off the loaded aggregate. Now the dispatcher builds a
|
||||
// `{ptr,len}` slice view of the payload pointer and formats that — output is
|
||||
// identical (`[a, b, c]`), and a large unrelated array type costs nothing.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
f :: () {
|
||||
buf : [65536]u8 = ---;
|
||||
buf[0] = 65; // 'A'
|
||||
out(string.{ ptr = @buf[0], len = 1 });
|
||||
out("\n");
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
f();
|
||||
print("{}\n", 5); // an int format — unaffected by the big array
|
||||
small : [3]i64 = .[7, 8, 9];
|
||||
print("{}\n", small); // array format still renders the element list
|
||||
return 0;
|
||||
}
|
||||
1
examples/basic/expected/0010-basic-basic.exit
Normal file
1
examples/basic/expected/0010-basic-basic.exit
Normal file
@@ -0,0 +1 @@
|
||||
42
|
||||
1
examples/basic/expected/0010-basic-basic.stderr
Normal file
1
examples/basic/expected/0010-basic-basic.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/basic/expected/0010-basic-basic.stdout
Normal file
1
examples/basic/expected/0010-basic-basic.stdout
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/basic/expected/0011-basic-stdout.exit
Normal file
1
examples/basic/expected/0011-basic-stdout.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/basic/expected/0011-basic-stdout.stderr
Normal file
1
examples/basic/expected/0011-basic-stdout.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/basic/expected/0011-basic-stdout.stdout
Normal file
1
examples/basic/expected/0011-basic-stdout.stdout
Normal file
@@ -0,0 +1 @@
|
||||
Hello
|
||||
1
examples/basic/expected/0012-basic-shadow.exit
Normal file
1
examples/basic/expected/0012-basic-shadow.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/basic/expected/0012-basic-shadow.stderr
Normal file
1
examples/basic/expected/0012-basic-shadow.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
4
examples/basic/expected/0012-basic-shadow.stdout
Normal file
4
examples/basic/expected/0012-basic-shadow.stdout
Normal file
@@ -0,0 +1,4 @@
|
||||
scope opened
|
||||
scoped x: 6
|
||||
scope closed
|
||||
main x: 42
|
||||
1
examples/basic/expected/0013-basic-defer.exit
Normal file
1
examples/basic/expected/0013-basic-defer.exit
Normal file
@@ -0,0 +1 @@
|
||||
42
|
||||
1
examples/basic/expected/0013-basic-defer.stderr
Normal file
1
examples/basic/expected/0013-basic-defer.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/basic/expected/0013-basic-defer.stdout
Normal file
1
examples/basic/expected/0013-basic-defer.stdout
Normal file
@@ -0,0 +1 @@
|
||||
still here
|
||||
1
examples/basic/expected/0014-basic-code.exit
Normal file
1
examples/basic/expected/0014-basic-code.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/basic/expected/0014-basic-code.stderr
Normal file
1
examples/basic/expected/0014-basic-code.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/basic/expected/0014-basic-code.stdout
Normal file
1
examples/basic/expected/0014-basic-code.stdout
Normal file
@@ -0,0 +1 @@
|
||||
hello from the other side
|
||||
1
examples/basic/expected/0015-basic-demo.exit
Normal file
1
examples/basic/expected/0015-basic-demo.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/basic/expected/0015-basic-demo.stderr
Normal file
1
examples/basic/expected/0015-basic-demo.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/basic/expected/0015-basic-demo.stdout
Normal file
1
examples/basic/expected/0015-basic-demo.stdout
Normal file
@@ -0,0 +1 @@
|
||||
[1.000000, 0.000000, -1.000000]
|
||||
1
examples/basic/expected/0016-basic-while.exit
Normal file
1
examples/basic/expected/0016-basic-while.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/basic/expected/0016-basic-while.stderr
Normal file
1
examples/basic/expected/0016-basic-while.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
4
examples/basic/expected/0016-basic-while.stdout
Normal file
4
examples/basic/expected/0016-basic-while.stdout
Normal file
@@ -0,0 +1,4 @@
|
||||
count: 5
|
||||
break at: 12
|
||||
sum of odd 1-9: 25
|
||||
sum 55
|
||||
1
examples/basic/expected/0017-basic-conditions.exit
Normal file
1
examples/basic/expected/0017-basic-conditions.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/basic/expected/0017-basic-conditions.stderr
Normal file
1
examples/basic/expected/0017-basic-conditions.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/basic/expected/0017-basic-conditions.stdout
Normal file
1
examples/basic/expected/0017-basic-conditions.stdout
Normal file
@@ -0,0 +1 @@
|
||||
containedcontainedcontained
|
||||
1
examples/basic/expected/0018-basic-quicksort.exit
Normal file
1
examples/basic/expected/0018-basic-quicksort.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/basic/expected/0018-basic-quicksort.stderr
Normal file
1
examples/basic/expected/0018-basic-quicksort.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/basic/expected/0018-basic-quicksort.stdout
Normal file
1
examples/basic/expected/0018-basic-quicksort.stdout
Normal file
@@ -0,0 +1 @@
|
||||
[1, 2, 2, 2, 3, 3, 4, 5, 5, 6, 6, 333]
|
||||
1
examples/basic/expected/0019-basic-dot-shorthand.exit
Normal file
1
examples/basic/expected/0019-basic-dot-shorthand.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/basic/expected/0019-basic-dot-shorthand.stderr
Normal file
1
examples/basic/expected/0019-basic-dot-shorthand.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
41
examples/basic/expected/0019-basic-dot-shorthand.stdout
Normal file
41
examples/basic/expected/0019-basic-dot-shorthand.stdout
Normal file
@@ -0,0 +1,41 @@
|
||||
--- tagged enum compat ---
|
||||
T1: 3.140000
|
||||
T2: 3
|
||||
T3: 5.000000 3.000000
|
||||
T4: 2.710000
|
||||
T5: 9.500000
|
||||
T6: 4.199999
|
||||
T7a: 1.000000
|
||||
T7b: 2.000000 3.000000
|
||||
T7c: 3
|
||||
T8a: 10
|
||||
T8b: 20
|
||||
T8c: 30
|
||||
T9: 42
|
||||
T10a: 1
|
||||
T10b: 1.000000
|
||||
T10c: 9.000000
|
||||
--- struct static shorthand ---
|
||||
S1: 3.000000 4.000000
|
||||
S2: 5.000000 6.000000
|
||||
S3: 7.000000 8.000000
|
||||
S4: 0.000000 0.000000
|
||||
S4: 1.000000 0.000000
|
||||
S5: 60
|
||||
S6: 8.000000 8.000000 8.000000 8.000000
|
||||
S6: 8.000000 16.000000 8.000000 16.000000
|
||||
S6: 0.000000 12.000000 0.000000 12.000000
|
||||
S7: 7
|
||||
S8: 3.000000 4.000000
|
||||
S8q: 1.000000 2.000000
|
||||
S9: 4.000000 6.000000
|
||||
S10: 4.000000 6.000000
|
||||
--- edge cases ---
|
||||
E1: 5.000000 1.000000 2.000000
|
||||
E2: 9 1.000000 2.000000
|
||||
E3: 1
|
||||
E4: 4.000000 6.000000
|
||||
E5: 42
|
||||
E6: 1
|
||||
E7: 20.000000 10.000000
|
||||
=== DONE ===
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
double: 14
|
||||
sum: 7
|
||||
answer: 42
|
||||
total: 30
|
||||
scaled: 90
|
||||
1
examples/basic/expected/0022-basic-for-range.exit
Normal file
1
examples/basic/expected/0022-basic-for-range.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/basic/expected/0022-basic-for-range.stderr
Normal file
1
examples/basic/expected/0022-basic-for-range.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
10
examples/basic/expected/0022-basic-for-range.stdout
Normal file
10
examples/basic/expected/0022-basic-for-range.stdout
Normal file
@@ -0,0 +1,10 @@
|
||||
i=0
|
||||
i=1
|
||||
i=2
|
||||
n=5
|
||||
j=2
|
||||
j=3
|
||||
j=4
|
||||
[0]=A
|
||||
[1]=B
|
||||
[2]=A
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
101 102 103
|
||||
circle 2.000000
|
||||
none
|
||||
1
examples/basic/expected/0024-basic-for-list.exit
Normal file
1
examples/basic/expected/0024-basic-for-list.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/basic/expected/0024-basic-for-list.stderr
Normal file
1
examples/basic/expected/0024-basic-for-list.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
4
examples/basic/expected/0024-basic-for-list.stdout
Normal file
4
examples/basic/expected/0024-basic-for-list.stdout
Normal file
@@ -0,0 +1,4 @@
|
||||
sum 60
|
||||
sum2 360
|
||||
via ptr 360
|
||||
boxes 7
|
||||
1
examples/basic/expected/0025-basic-literals.exit
Normal file
1
examples/basic/expected/0025-basic-literals.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/basic/expected/0025-basic-literals.stderr
Normal file
1
examples/basic/expected/0025-basic-literals.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
18
examples/basic/expected/0025-basic-literals.stdout
Normal file
18
examples/basic/expected/0025-basic-literals.stdout
Normal file
@@ -0,0 +1,18 @@
|
||||
=== 1. Literals ===
|
||||
decimal: 42
|
||||
hex: 255
|
||||
binary: 10
|
||||
float: 3.140000
|
||||
f64: 2.718281
|
||||
true: true
|
||||
false: false
|
||||
escapes: hello world
|
||||
multiline: line1
|
||||
line2
|
||||
heredoc: raw heredoc
|
||||
|
||||
undef-then-set: 77
|
||||
enum-lit: .green
|
||||
null-ptr: null
|
||||
string-len: 5
|
||||
empty-string: 0
|
||||
1
examples/basic/expected/0026-basic-operators.exit
Normal file
1
examples/basic/expected/0026-basic-operators.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/basic/expected/0026-basic-operators.stderr
Normal file
1
examples/basic/expected/0026-basic-operators.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
60
examples/basic/expected/0026-basic-operators.stdout
Normal file
60
examples/basic/expected/0026-basic-operators.stdout
Normal file
@@ -0,0 +1,60 @@
|
||||
=== 2. Operators ===
|
||||
add: 7
|
||||
sub: 7
|
||||
mul: 42
|
||||
div: 5
|
||||
mod: 2
|
||||
neg: -5
|
||||
eq: true
|
||||
neq: true
|
||||
lt: true
|
||||
gt: true
|
||||
le: true
|
||||
ge: true
|
||||
chain: true
|
||||
chain-gt: true
|
||||
chain-mixed: true
|
||||
eq-chain: true
|
||||
eq-chain-f: false
|
||||
band: 15
|
||||
bor: 7
|
||||
bxor: 240
|
||||
bxor2: 5
|
||||
bnot: -1
|
||||
bnot2: -2
|
||||
shl: 16
|
||||
shr: 16
|
||||
shl2: 24
|
||||
shr2: 127
|
||||
band-var: 15
|
||||
bor-var: 7
|
||||
bxor-var: 240
|
||||
shl-var: 16
|
||||
shr-var: 15
|
||||
bnot-var: -16
|
||||
and-assign: 15
|
||||
or-assign: 255
|
||||
xor-assign: 240
|
||||
shl-assign: 256
|
||||
shr-assign: 16
|
||||
mod-var: 2
|
||||
and: true
|
||||
and-false: false
|
||||
or: true
|
||||
or-false: false
|
||||
short-and: false
|
||||
short-or: true
|
||||
ca+=: 15
|
||||
ca-=: 12
|
||||
ca*=: 24
|
||||
ca/=: 4
|
||||
prec1: 14
|
||||
prec2: 20
|
||||
xx-cast: 200
|
||||
widen-u8-i64: 200
|
||||
widen-i32-f64: 42.000000
|
||||
widen-f32-f64: 1.500000
|
||||
widen-u8-i16: 100
|
||||
xx-i64-i32: 12345
|
||||
xx-f64-f32: 1.500000
|
||||
xx-f64-i32: 7
|
||||
1
examples/basic/expected/0027-basic-control-flow.exit
Normal file
1
examples/basic/expected/0027-basic-control-flow.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/basic/expected/0027-basic-control-flow.stderr
Normal file
1
examples/basic/expected/0027-basic-control-flow.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user