From e12f817e52bd4bbf5e38842b3a3e77875524886b Mon Sep 17 00:00:00 2001 From: agra Date: Mon, 1 Jun 2026 19:34:21 +0300 Subject: [PATCH] test: split 50-smoke.sx into per-section examples + add errors smoke MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Break the monolithic examples/50-smoke.sx into 30 focused per-section examples, filed into their category blocks (basic/types/comptime/memory/protocols/ffi), each carrying only the top-level decls its section references (the protocols section keeps the full preamble — its deps flow through UFCS method calls that name-based extraction can't see). Outputs verified identical to the original section blocks. Add examples/1036-errors-failable-smoke.sx — an end-to-end error-handling example (the E5.4 work): named + inferred error sets consumed via destructure, try (in helpers), catch (bare-expr / match-body / diverging / no-binding), or value-terminator, onfail+defer interleave, and error.X value + {} tag interpolation. Remove examples/50-smoke.sx. Suite: 324 passed, 0 failed. --- examples/0025-basic-literals.sx | 67 + examples/0026-basic-operators.sx | 166 + examples/0027-basic-control-flow.sx | 201 ++ examples/0028-basic-functions.sx | 106 + examples/0029-basic-scoping.sx | 79 + examples/0030-basic-builtins.sx | 127 + examples/0031-basic-local-fn-return.sx | 30 + examples/0032-basic-ufcs-return-type.sx | 24 + examples/0033-basic-if-struct.sx | 22 + examples/0034-basic-string-comparison.sx | 23 + examples/0035-basic-array-loop-mutation.sx | 24 + examples/0036-basic-ufcs-aliases.sx | 42 + examples/0037-basic-trailing-commas.sx | 36 + examples/0121-types-types.sx | 342 ++ examples/0122-types-flags.sx | 106 + examples/0123-types-compound-assign.sx | 24 + examples/0124-types-array-of-structs.sx | 23 + examples/0125-types-type-named-vars.sx | 19 + examples/0126-types-nested-arrays.sx | 20 + examples/0127-types-using.sx | 47 + examples/0128-types-tuples.sx | 27 + examples/0129-types-tuple-operators.sx | 1200 ++++++ examples/0130-types-struct-constants.sx | 27 + examples/0131-types-init-blocks.sx | 200 + examples/0415-protocols-protocols.sx | 617 ++++ examples/0416-protocols-auto-type-erasure.sx | 92 + examples/0608-comptime-comptime.sx | 83 + examples/0609-comptime-inline-if.sx | 46 + examples/0810-memory-slice-ptr.sx | 20 + examples/1036-errors-failable-smoke.sx | 104 + examples/1219-ffi-foreign.sx | 23 + examples/50-smoke.sx | 3214 ----------------- examples/expected/0025-basic-literals.exit | 1 + examples/expected/0025-basic-literals.stderr | 1 + examples/expected/0025-basic-literals.stdout | 18 + examples/expected/0026-basic-operators.exit | 1 + examples/expected/0026-basic-operators.stderr | 1 + examples/expected/0026-basic-operators.stdout | 60 + .../expected/0027-basic-control-flow.exit | 1 + .../expected/0027-basic-control-flow.stderr | 1 + .../expected/0027-basic-control-flow.stdout | 26 + examples/expected/0028-basic-functions.exit | 1 + examples/expected/0028-basic-functions.stderr | 1 + examples/expected/0028-basic-functions.stdout | 21 + examples/expected/0029-basic-scoping.exit | 1 + examples/expected/0029-basic-scoping.stderr | 1 + examples/expected/0029-basic-scoping.stdout | 23 + examples/expected/0030-basic-builtins.exit | 1 + examples/expected/0030-basic-builtins.stderr | 1 + examples/expected/0030-basic-builtins.stdout | 31 + .../expected/0031-basic-local-fn-return.exit | 1 + .../0031-basic-local-fn-return.stderr | 1 + .../0031-basic-local-fn-return.stdout | 3 + .../expected/0032-basic-ufcs-return-type.exit | 1 + .../0032-basic-ufcs-return-type.stderr | 1 + .../0032-basic-ufcs-return-type.stdout | 3 + examples/expected/0033-basic-if-struct.exit | 1 + examples/expected/0033-basic-if-struct.stderr | 1 + examples/expected/0033-basic-if-struct.stdout | 3 + .../0034-basic-string-comparison.exit | 1 + .../0034-basic-string-comparison.stderr | 1 + .../0034-basic-string-comparison.stdout | 5 + .../0035-basic-array-loop-mutation.exit | 1 + .../0035-basic-array-loop-mutation.stderr | 1 + .../0035-basic-array-loop-mutation.stdout | 3 + .../expected/0036-basic-ufcs-aliases.exit | 1 + .../expected/0036-basic-ufcs-aliases.stderr | 1 + .../expected/0036-basic-ufcs-aliases.stdout | 12 + .../expected/0037-basic-trailing-commas.exit | 1 + .../0037-basic-trailing-commas.stderr | 1 + .../0037-basic-trailing-commas.stdout | 2 + examples/expected/0121-types-types.exit | 1 + examples/expected/0121-types-types.stderr | 1 + examples/expected/0121-types-types.stdout | 75 + examples/expected/0122-types-flags.exit | 1 + examples/expected/0122-types-flags.stderr | 1 + examples/expected/0122-types-flags.stdout | 18 + .../expected/0123-types-compound-assign.exit | 1 + .../0123-types-compound-assign.stderr | 1 + .../0123-types-compound-assign.stdout | 3 + .../expected/0124-types-array-of-structs.exit | 1 + .../0124-types-array-of-structs.stderr | 1 + .../0124-types-array-of-structs.stdout | 4 + .../expected/0125-types-type-named-vars.exit | 1 + .../0125-types-type-named-vars.stderr | 1 + .../0125-types-type-named-vars.stdout | 3 + .../expected/0126-types-nested-arrays.exit | 1 + .../expected/0126-types-nested-arrays.stderr | 1 + .../expected/0126-types-nested-arrays.stdout | 5 + examples/expected/0127-types-using.exit | 1 + examples/expected/0127-types-using.stderr | 1 + examples/expected/0127-types-using.stdout | 12 + examples/expected/0128-types-tuples.exit | 1 + examples/expected/0128-types-tuples.stderr | 1 + examples/expected/0128-types-tuples.stdout | 8 + .../expected/0129-types-tuple-operators.exit | 1 + .../0129-types-tuple-operators.stderr | 1 + .../0129-types-tuple-operators.stdout | 203 ++ .../expected/0130-types-struct-constants.exit | 1 + .../0130-types-struct-constants.stderr | 1 + .../0130-types-struct-constants.stdout | 4 + examples/expected/0131-types-init-blocks.exit | 1 + .../expected/0131-types-init-blocks.stderr | 1 + .../expected/0131-types-init-blocks.stdout | 21 + .../expected/0415-protocols-protocols.exit | 1 + .../expected/0415-protocols-protocols.stderr | 1 + .../expected/0415-protocols-protocols.stdout | 27 + .../0416-protocols-auto-type-erasure.exit | 1 + .../0416-protocols-auto-type-erasure.stderr | 1 + .../0416-protocols-auto-type-erasure.stdout | 6 + examples/expected/0608-comptime-comptime.exit | 1 + .../expected/0608-comptime-comptime.stderr | 1 + .../expected/0608-comptime-comptime.stdout | 9 + .../expected/0609-comptime-inline-if.exit | 1 + .../expected/0609-comptime-inline-if.stderr | 1 + .../expected/0609-comptime-inline-if.stdout | 6 + examples/expected/0810-memory-slice-ptr.exit | 1 + .../expected/0810-memory-slice-ptr.stderr | 1 + .../expected/0810-memory-slice-ptr.stdout | 3 + .../expected/1036-errors-failable-smoke.exit | 1 + .../1036-errors-failable-smoke.stderr | 1 + .../1036-errors-failable-smoke.stdout | 19 + examples/expected/1219-ffi-foreign.exit | 1 + examples/expected/1219-ffi-foreign.stderr | 1 + examples/expected/1219-ffi-foreign.stdout | 2 + 125 files changed, 4667 insertions(+), 3214 deletions(-) create mode 100644 examples/0025-basic-literals.sx create mode 100644 examples/0026-basic-operators.sx create mode 100644 examples/0027-basic-control-flow.sx create mode 100644 examples/0028-basic-functions.sx create mode 100644 examples/0029-basic-scoping.sx create mode 100644 examples/0030-basic-builtins.sx create mode 100644 examples/0031-basic-local-fn-return.sx create mode 100644 examples/0032-basic-ufcs-return-type.sx create mode 100644 examples/0033-basic-if-struct.sx create mode 100644 examples/0034-basic-string-comparison.sx create mode 100644 examples/0035-basic-array-loop-mutation.sx create mode 100644 examples/0036-basic-ufcs-aliases.sx create mode 100644 examples/0037-basic-trailing-commas.sx create mode 100644 examples/0121-types-types.sx create mode 100644 examples/0122-types-flags.sx create mode 100644 examples/0123-types-compound-assign.sx create mode 100644 examples/0124-types-array-of-structs.sx create mode 100644 examples/0125-types-type-named-vars.sx create mode 100644 examples/0126-types-nested-arrays.sx create mode 100644 examples/0127-types-using.sx create mode 100644 examples/0128-types-tuples.sx create mode 100644 examples/0129-types-tuple-operators.sx create mode 100644 examples/0130-types-struct-constants.sx create mode 100644 examples/0131-types-init-blocks.sx create mode 100644 examples/0415-protocols-protocols.sx create mode 100644 examples/0416-protocols-auto-type-erasure.sx create mode 100644 examples/0608-comptime-comptime.sx create mode 100644 examples/0609-comptime-inline-if.sx create mode 100644 examples/0810-memory-slice-ptr.sx create mode 100644 examples/1036-errors-failable-smoke.sx create mode 100644 examples/1219-ffi-foreign.sx delete mode 100644 examples/50-smoke.sx create mode 100644 examples/expected/0025-basic-literals.exit create mode 100644 examples/expected/0025-basic-literals.stderr create mode 100644 examples/expected/0025-basic-literals.stdout create mode 100644 examples/expected/0026-basic-operators.exit create mode 100644 examples/expected/0026-basic-operators.stderr create mode 100644 examples/expected/0026-basic-operators.stdout create mode 100644 examples/expected/0027-basic-control-flow.exit create mode 100644 examples/expected/0027-basic-control-flow.stderr create mode 100644 examples/expected/0027-basic-control-flow.stdout create mode 100644 examples/expected/0028-basic-functions.exit create mode 100644 examples/expected/0028-basic-functions.stderr create mode 100644 examples/expected/0028-basic-functions.stdout create mode 100644 examples/expected/0029-basic-scoping.exit create mode 100644 examples/expected/0029-basic-scoping.stderr create mode 100644 examples/expected/0029-basic-scoping.stdout create mode 100644 examples/expected/0030-basic-builtins.exit create mode 100644 examples/expected/0030-basic-builtins.stderr create mode 100644 examples/expected/0030-basic-builtins.stdout create mode 100644 examples/expected/0031-basic-local-fn-return.exit create mode 100644 examples/expected/0031-basic-local-fn-return.stderr create mode 100644 examples/expected/0031-basic-local-fn-return.stdout create mode 100644 examples/expected/0032-basic-ufcs-return-type.exit create mode 100644 examples/expected/0032-basic-ufcs-return-type.stderr create mode 100644 examples/expected/0032-basic-ufcs-return-type.stdout create mode 100644 examples/expected/0033-basic-if-struct.exit create mode 100644 examples/expected/0033-basic-if-struct.stderr create mode 100644 examples/expected/0033-basic-if-struct.stdout create mode 100644 examples/expected/0034-basic-string-comparison.exit create mode 100644 examples/expected/0034-basic-string-comparison.stderr create mode 100644 examples/expected/0034-basic-string-comparison.stdout create mode 100644 examples/expected/0035-basic-array-loop-mutation.exit create mode 100644 examples/expected/0035-basic-array-loop-mutation.stderr create mode 100644 examples/expected/0035-basic-array-loop-mutation.stdout create mode 100644 examples/expected/0036-basic-ufcs-aliases.exit create mode 100644 examples/expected/0036-basic-ufcs-aliases.stderr create mode 100644 examples/expected/0036-basic-ufcs-aliases.stdout create mode 100644 examples/expected/0037-basic-trailing-commas.exit create mode 100644 examples/expected/0037-basic-trailing-commas.stderr create mode 100644 examples/expected/0037-basic-trailing-commas.stdout create mode 100644 examples/expected/0121-types-types.exit create mode 100644 examples/expected/0121-types-types.stderr create mode 100644 examples/expected/0121-types-types.stdout create mode 100644 examples/expected/0122-types-flags.exit create mode 100644 examples/expected/0122-types-flags.stderr create mode 100644 examples/expected/0122-types-flags.stdout create mode 100644 examples/expected/0123-types-compound-assign.exit create mode 100644 examples/expected/0123-types-compound-assign.stderr create mode 100644 examples/expected/0123-types-compound-assign.stdout create mode 100644 examples/expected/0124-types-array-of-structs.exit create mode 100644 examples/expected/0124-types-array-of-structs.stderr create mode 100644 examples/expected/0124-types-array-of-structs.stdout create mode 100644 examples/expected/0125-types-type-named-vars.exit create mode 100644 examples/expected/0125-types-type-named-vars.stderr create mode 100644 examples/expected/0125-types-type-named-vars.stdout create mode 100644 examples/expected/0126-types-nested-arrays.exit create mode 100644 examples/expected/0126-types-nested-arrays.stderr create mode 100644 examples/expected/0126-types-nested-arrays.stdout create mode 100644 examples/expected/0127-types-using.exit create mode 100644 examples/expected/0127-types-using.stderr create mode 100644 examples/expected/0127-types-using.stdout create mode 100644 examples/expected/0128-types-tuples.exit create mode 100644 examples/expected/0128-types-tuples.stderr create mode 100644 examples/expected/0128-types-tuples.stdout create mode 100644 examples/expected/0129-types-tuple-operators.exit create mode 100644 examples/expected/0129-types-tuple-operators.stderr create mode 100644 examples/expected/0129-types-tuple-operators.stdout create mode 100644 examples/expected/0130-types-struct-constants.exit create mode 100644 examples/expected/0130-types-struct-constants.stderr create mode 100644 examples/expected/0130-types-struct-constants.stdout create mode 100644 examples/expected/0131-types-init-blocks.exit create mode 100644 examples/expected/0131-types-init-blocks.stderr create mode 100644 examples/expected/0131-types-init-blocks.stdout create mode 100644 examples/expected/0415-protocols-protocols.exit create mode 100644 examples/expected/0415-protocols-protocols.stderr create mode 100644 examples/expected/0415-protocols-protocols.stdout create mode 100644 examples/expected/0416-protocols-auto-type-erasure.exit create mode 100644 examples/expected/0416-protocols-auto-type-erasure.stderr create mode 100644 examples/expected/0416-protocols-auto-type-erasure.stdout create mode 100644 examples/expected/0608-comptime-comptime.exit create mode 100644 examples/expected/0608-comptime-comptime.stderr create mode 100644 examples/expected/0608-comptime-comptime.stdout create mode 100644 examples/expected/0609-comptime-inline-if.exit create mode 100644 examples/expected/0609-comptime-inline-if.stderr create mode 100644 examples/expected/0609-comptime-inline-if.stdout create mode 100644 examples/expected/0810-memory-slice-ptr.exit create mode 100644 examples/expected/0810-memory-slice-ptr.stderr create mode 100644 examples/expected/0810-memory-slice-ptr.stdout create mode 100644 examples/expected/1036-errors-failable-smoke.exit create mode 100644 examples/expected/1036-errors-failable-smoke.stderr create mode 100644 examples/expected/1036-errors-failable-smoke.stdout create mode 100644 examples/expected/1219-ffi-foreign.exit create mode 100644 examples/expected/1219-ffi-foreign.stderr create mode 100644 examples/expected/1219-ffi-foreign.stdout diff --git a/examples/0025-basic-literals.sx b/examples/0025-basic-literals.sx new file mode 100644 index 0000000..545b9a8 --- /dev/null +++ b/examples/0025-basic-literals.sx @@ -0,0 +1,67 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/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 : s32 = ---; + 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 : *s32 = 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); +} diff --git a/examples/0026-basic-operators.sx b/examples/0026-basic-operators.sx new file mode 100644 index 0000000..ac8d615 --- /dev/null +++ b/examples/0026-basic-operators.sx @@ -0,0 +1,166 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +add :: (a: s32, b: s32) -> s32 { a + b; } + +mul :: (a: s32, b: s32) -> s32 { a * b; } + +// P4 edge: Chained default→default calls +Chained :: protocol { + base :: (msg: string) -> s32; + wrap :: (msg: string) -> s32 { + self.base(msg) + 1; + } + double_wrap :: (msg: string) -> s32 { + 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 : s64 = wu; + print("widen-u8-s64: {}\n", ws); + + wi3 : s32 = 42; + wf : f64 = wi3; + print("widen-s32-f64: {}\n", wf); + + wf32 : f32 = 1.5; + wf64 : f64 = wf32; + print("widen-f32-f64: {}\n", wf64); + + wu2 : u8 = 100; + ws2 : s16 = wu2; + print("widen-u8-s16: {}\n", ws2); + + // More xx narrowing + xl : s64 = 12345; + xs : s32 = xx xl; + print("xx-s64-s32: {}\n", xs); + + xd : f64 = 1.5; + xf : f32 = xx xd; + print("xx-f64-f32: {}\n", xf); + + xdf : f64 = 7.9; + xdi : s32 = xx xdf; + print("xx-f64-s32: {}\n", xdi); +} diff --git a/examples/0027-basic-control-flow.sx b/examples/0027-basic-control-flow.sx new file mode 100644 index 0000000..17cdebc --- /dev/null +++ b/examples/0027-basic-control-flow.sx @@ -0,0 +1,201 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/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]s32 = .[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: (_, ix) { + out(" "); + out(int_to_string(ix)); + } + out("\n"); + + // For with print two args + out("for-2arg:"); + for farr: (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 : []s32 = .[10, 20, 30]; + out("for-slice:"); + for fsl: (it) { + print(" {}", it); + } + out("\n"); + + // For on slice with index + out("for-slice-idx:"); + for fsl: (it, ix) { + print(" {}:{}", ix, it); + } + out("\n"); + + // Nested for + nf_a : [2]s32 = .[0, 1]; + nf_b : [2]s32 = .[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]s32 = .[10, 20, 30, 40, 50]; + fbi_idx := 0; + for fbi: (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); +} diff --git a/examples/0028-basic-functions.sx b/examples/0028-basic-functions.sx new file mode 100644 index 0000000..81820a8 --- /dev/null +++ b/examples/0028-basic-functions.sx @@ -0,0 +1,106 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +add :: (a: s32, b: s32) -> s32 { a + b; } + +mul :: (a: s32, b: s32) -> s32 { a * b; } + +identity :: (x: $T) -> T { x; } + +pair_add :: (a: $T, b: $U) -> s64 { + cast(s64) a + cast(s64) b; +} + +typed_sum :: (..args: []s32) -> s32 { + result := 0; + for args: (it) { result = result + it; } + result; +} + +apply :: (f: (s32, s32) -> s32, x: s32, y: s32) -> s32 { + f(x, y); +} + +void_return :: () { + return; +} + +implicit_return :: (x: s32) -> s32 { + x * 2; +} + +early_return :: (x: s32) -> s32 { + 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 : s32; + 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-s32: {}\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: s32) => 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: s32, b: s32) -> s32 { 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]s32 = .[10, 20, 30]; + print("spread: {}\n", typed_sum(..spread_arr)); + + // Function pointers + fp : (s32, s32) -> s32 = add; + print("fp: {}\n", fp(3, 4)); + fp = mul; + print("fp-reassign: {}\n", fp(3, 4)); + print("fp-apply: {}\n", apply(add, 10, 20)); +} diff --git a/examples/0029-basic-scoping.sx b/examples/0029-basic-scoping.sx new file mode 100644 index 0000000..924b86c --- /dev/null +++ b/examples/0029-basic-scoping.sx @@ -0,0 +1,79 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/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"); + } +} diff --git a/examples/0030-basic-builtins.sx b/examples/0030-basic-builtins.sx new file mode 100644 index 0000000..0542df4 --- /dev/null +++ b/examples/0030-basic-builtins.sx @@ -0,0 +1,127 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +Point :: struct { x, y: s32; } + +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-s32: {}\n", size_of(s32)); + 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-s32: {}\n", align_of(s32)); + print("alignof-s64: {}\n", align_of(s64)); + 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(s32) cval); + cv2 : s32 = 42; + print("cast-int-f64: {}\n", cast(f64) cv2); +} diff --git a/examples/0031-basic-local-fn-return.sx b/examples/0031-basic-local-fn-return.sx new file mode 100644 index 0000000..1d34f63 --- /dev/null +++ b/examples/0031-basic-local-fn-return.sx @@ -0,0 +1,30 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +Point :: struct { x, y: s32; } + +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); + } +} diff --git a/examples/0032-basic-ufcs-return-type.sx b/examples/0032-basic-ufcs-return-type.sx new file mode 100644 index 0000000..bb5590c --- /dev/null +++ b/examples/0032-basic-ufcs-return-type.sx @@ -0,0 +1,24 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +Point :: struct { x, y: s32; } + +point_sum :: (p: Point) -> s32 { 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()); + } +} diff --git a/examples/0033-basic-if-struct.sx b/examples/0033-basic-if-struct.sx new file mode 100644 index 0000000..7a45f11 --- /dev/null +++ b/examples/0033-basic-if-struct.sx @@ -0,0 +1,22 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +Point :: struct { x, y: s32; } + +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); + } +} diff --git a/examples/0034-basic-string-comparison.sx b/examples/0034-basic-string-comparison.sx new file mode 100644 index 0000000..e3ff8c6 --- /dev/null +++ b/examples/0034-basic-string-comparison.sx @@ -0,0 +1,23 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/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 == ""); + } +} diff --git a/examples/0035-basic-array-loop-mutation.sx b/examples/0035-basic-array-loop-mutation.sx new file mode 100644 index 0000000..9105fb0 --- /dev/null +++ b/examples/0035-basic-array-loop-mutation.sx @@ -0,0 +1,24 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +main :: () { + + // ======================================================== + // 25. ARRAY LOOP MUTATION + // ======================================================== + print("=== 25. Array Loop Mutation ===\n"); + { + arr : [4]s32 = .[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]); + } +} diff --git a/examples/0036-basic-ufcs-aliases.sx b/examples/0036-basic-ufcs-aliases.sx new file mode 100644 index 0000000..cd3c6ad --- /dev/null +++ b/examples/0036-basic-ufcs-aliases.sx @@ -0,0 +1,42 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +main :: () { + + // --- UFCS Aliases & Pipe --- + { + print("=== UFCS Aliases ===\n"); + + num_sum :: (a: s64, b: s64) -> s64 { 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: s64, b: s64, c: s64, d: s64) -> s64 { 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: s64, b: s64) -> (s64, s64) { (b, a); } + s := swap(1, 2); + a := s.0; + b := s.1; + print("{}\n", a); // 2 + print("{}\n", b); // 1 + + wrap :: (x: s64) -> (s64) { (x,); } + t := wrap(99); + print("{}\n", t.0); // 99 + } +} diff --git a/examples/0037-basic-trailing-commas.sx b/examples/0037-basic-trailing-commas.sx new file mode 100644 index 0000000..e96d791 --- /dev/null +++ b/examples/0037-basic-trailing-commas.sx @@ -0,0 +1,36 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +add :: (a: s32, b: s32) -> s32 { 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: s64, b: s64) -> s64 { return a + b; } + r := add(10, 20,); + assert(r == 30); + + // Array literal with trailing comma + arr := s64.[1, 2, 3,]; + assert(arr[2] == 3); + + print("trailing commas ok\n"); + } +} diff --git a/examples/0121-types-types.sx b/examples/0121-types-types.sx new file mode 100644 index 0000000..35f50e7 --- /dev/null +++ b/examples/0121-types-types.sx @@ -0,0 +1,342 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +Point :: struct { x, y: s32; } + +Color :: enum { red; green; blue; } + +Shape :: enum { + circle: f32; + rect: struct { w, h: f32; }; + none; +} + +Overlay :: union { + f: f32; + i: s32; +} + +Vec2 :: union { + data: [2]f32; + struct { x, y: f32; }; +} + +Defaults :: struct { + a: s32; + b: s32 = 99; + c: s32 = ---; +} + +MyFloat :: f64; + +Status :: enum u8 { ok; err; timeout; } + +add :: (a: s32, b: s32) -> s32 { a + b; } + +mul :: (a: s32, b: s32) -> s32 { a * b; } + +vec3 :: (x: f32, y: f32, z: f32) -> Vector(3, f32) { + .[x, y, z]; +} + +// Global variable for address-of test +g_smoke_val : s32 = 42; + +write_to_ptr :: (p: *s32) { + p.* = 99; +} + +main :: () { + + // ======================================================== + // 3. TYPE SYSTEM + // ======================================================== + print("=== 3. Types ===\n"); + + // Primitive types + v_s8 : s8 = 127; + v_s16 : s16 = 32000; + v_s32 : s32 = 100000; + v_u8 : u8 = 255; + v_u16 : u16 = 65000; + v_u32 : u32 = 4000000; + print("s8: {}\n", v_s8); + print("s16: {}\n", v_s16); + print("s32: {}\n", v_s32); + print("u8: {}\n", v_u8); + print("u16: {}\n", v_u16); + print("u32: {}\n", v_u32); + + // Type alias + mf : MyFloat = 1.5; + print("alias: {}\n", mf); + + // --- Structs --- + // Positional literal + p1 : Point = .{ 1, 2 }; + print("struct-pos: {}\n", p1); + + // Type-prefix literal + p2 := Point.{ 3, 4 }; + print("struct-prefix: {}\n", p2); + + // Named fields + p3 := Point.{ y=10, x=20 }; + print("struct-named: {}\n", p3); + + // Shorthand (variable name = field name) + x : s32 = 5; + y : s32 = 6; + p4 := Point.{ x, y }; + print("struct-shorthand: {}\n", p4); + + // Field defaults + d1 : Defaults; + print("defaults: a={} b={}\n", d1.a, d1.b); + + // Field access and assignment + p5 := Point.{ 0, 0 }; + p5.x = 42; + p5.y = 99; + print("field-assign: {}\n", p5); + + // --- Enum (payload-less) --- + ec : Color = .red; + print("enum: {}\n", ec); + + // Enum comparison + ce1 : Color = .red; + ce2 : Color = .red; + ce3 : Color = .blue; + print("enum-eq: {}\n", ce1 == ce2); + print("enum-neq: {}\n", ce1 != ce3); + + // Backing type + st : Status = .err; + print("backing: {}\n", st); + + // --- Enum (tagged union) --- + sh : Shape = .circle(3.14); + print("tagged: {}\n", sh); + + // Payload access + radius := sh.circle; + print("payload: {}\n", radius); + + // Void variant + sh = .none; + print("void-variant: {}\n", sh); + + // Variant reassignment + sh = .circle(1.0); + print("reassign: {}\n", sh); + sh = .rect(.{ 5, 3 }); + print("reassign2: {}\n", sh); + + // Type-prefix construction + tp := Shape.circle(2.5); + print("enum-prefix: {}\n", tp); + + // Pattern matching + sh2 : Shape = .rect(.{ 5, 3 }); + if sh2 == { + case .circle: print("match: circle\n"); + case .rect: print("match: rect\n"); + case .none: print("match: none\n"); + } + + // Match as expression + sh3 : Shape = .circle(1.0); + ms := if sh3 == { + case .circle: 10; + case .rect: 20; + case .none: 30; + } + print("match-expr: {}\n", ms); + + // Match expression with else + me_val := 42; + me_res := if me_val == { + case 1: 10; + case 2: 20; + else: 99; + } + print("match-expr-else: {}\n", me_res); + + // Payload capture (block form) + sh4 : Shape = .circle(9.5); + if sh4 == { + case .circle: (r) { print("capture: {}\n", r); } + case .rect: (sz) { print("capture: {}\n", sz); } + case .none: print("capture: none\n"); + } + + // Payload capture (arrow form) + sh_ca : Shape = .circle(7.5); + if sh_ca == { + case .circle: (r) => print("capture-arrow: {}\n", r); + case .rect: (sz) => print("capture-arrow: rect\n"); + case .none: print("capture-arrow: none\n"); + } + + // else arm in match + num := 42; + if num == { + case 1: print("else-match: one\n"); + case 2: print("else-match: two\n"); + else: print("else-match: other\n"); + } + + // Integer pattern matching + code := 2; + if code == { + case 1: print("int-match: one\n"); + case 2: print("int-match: two\n"); + case 3: print("int-match: three\n"); + } + + // Integer match with else + im_code := 99; + if im_code == { + case 1: print("int-match-else: one\n"); + case 2: print("int-match-else: two\n"); + else: print("int-match-else: unknown\n"); + } + + // Bool pattern matching + bm := true; + if bm == { + case true: print("bool-match-t: yes\n"); + case false: print("bool-match-t: no\n"); + } + bm2 := false; + if bm2 == { + case true: print("bool-match-f: yes\n"); + case false: print("bool-match-f: no\n"); + } + + // Bool conditional + flag := true; + if flag { print("bool: true\n"); } + + // --- Union (untagged) --- + o : Overlay = ---; + o.f = 3.14; + print("union-f: {}\n", o.f); + // Type punning — read same bits as s32 + print("union-i: {}\n", o.i); + + // Union member promotion + uv : Vec2 = ---; + uv.x = 1.0; + uv.y = 2.0; + print("promoted-x: {}\n", uv.x); + print("promoted-data0: {}\n", uv.data[0]); + + // --- Arrays --- + arr : [5]s32 = .[10, 20, 30, 40, 50]; + print("arr[2]: {}\n", arr[2]); + print("arr.len: {}\n", arr.len); + + // Array element assignment + aa : [3]s32 = .[1, 2, 3]; + aa[1] = 99; + print("arr-assign: {}\n", aa); + + // --- Slices --- + sl : []s32 = .[1, 2, 3, 4, 5]; + print("sl[0]: {}\n", sl[0]); + print("sl.len: {}\n", sl.len); + + // Slice element write + sla : []s32 = .[10, 20, 30]; + sla[1] = 55; + print("sl-assign: {}\n", sla); + + // Subslicing + sub := arr[1..4]; + print("sub: {}\n", sub); + head := arr[..3]; + print("head: {}\n", head); + tail := arr[2..]; + print("tail: {}\n", tail); + + // Slice of slice + sos : []s32 = .[10, 20, 30, 40, 50]; + mid := sos[1..4]; + inner := mid[0..2]; + print("slice-of-slice: {}\n", inner); + + // String subslicing + msg := "hello world"; + print("strsub: {}\n", msg[6..11]); + print("str-prefix: {}\n", msg[..5]); + print("str-suffix: {}\n", msg[6..]); + + // --- Pointers --- + // Address-of global variable + write_to_ptr(@g_smoke_val); + print("global-addr-of: {}\n", g_smoke_val); + + pv := Point.{ 10, 20 }; + ptr := @pv; + print("deref: {}\n", ptr.*); + + // Auto-deref + print("auto-deref: {}\n", ptr.x); + + // Many-pointer + mp : [*]s32 = @arr[0]; + print("mp[0]: {}\n", mp[0]); + print("mp[3]: {}\n", mp[3]); + + // Many-pointer write + mpw : [5]s32 = .[10, 20, 30, 40, 50]; + mpw_ptr : [*]s32 = @mpw[0]; + mpw_ptr[2] = 99; + print("mp-write: {}\n", mpw[2]); + + // Pointer-null comparison + np : *s32 = null; + print("ptr==null: {}\n", np == null); + print("ptr!=null: {}\n", np != null); + np2 := @pv.x; + print("ptr2==null: {}\n", np2 == null); + print("ptr2!=null: {}\n", np2 != null); + + // Pointer to nested struct field + Inner3 :: struct { a: f32; b: f32; c: f32; } + Outer3 :: struct { key: s32; inner: Inner3; } + out3 := Outer3.{ key = 42, inner = Inner3.{ a = 1.0, b = 2.0, c = 3.0 } }; + ip3 := @out3.inner; + print("ptr-nested-field: {} {} {}\n", ip3.a, ip3.b, ip3.c); + + // Store to many-pointer field must not corrupt adjacent memory + MpHolder :: struct { items: [*]s64; sentinel: s64; } + mph := MpHolder.{ items = xx 0, sentinel = 42 }; + mph.items = xx 0; + print("mp-store-sentinel: {}\n", mph.sentinel); + + // --- Vectors --- + vc := vec3(1, 3, 2); + print("vec-construct: {}\n", vc); + + va := vec3(1, 2, 3); + vb := vec3(4, 5, 6); + print("vec-add: {}\n", va + vb); + print("vec-sub: {}\n", vec3(5, 5, 5) - vec3(1, 2, 3)); + print("vec-mul: {}\n", vec3(2, 3, 4) * vec3(1, 2, 3)); + print("vec-div: {}\n", vec3(10, 9, 8) / vec3(2, 3, 4)); + + print("vec-scalar: {}\n", vec3(1, 3, 2) * 2.0); + print("vec-neg: {}\n", -vec3(1, 3, 2)); + + ve := vec3(10, 20, 30); + print("vec-x: {}\n", ve.x); + print("vec-y: {}\n", ve.y); + print("vec-z: {}\n", ve.z); + print("vec-idx: {}\n", ve[1]); +} diff --git a/examples/0122-types-flags.sx b/examples/0122-types-flags.sx new file mode 100644 index 0000000..9d1ccf0 --- /dev/null +++ b/examples/0122-types-flags.sx @@ -0,0 +1,106 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +Perms :: enum flags { read; write; execute; } + +WindowFlags :: enum flags u32 { vsync :: 64; resizable :: 4; hidden :: 128; } + +// --- Top-level functions --- + +main :: () { + + // ======================================================== + // 9. FLAGS + // ======================================================== + print("=== 9. Flags ===\n"); + + // Combine flags + perm : Perms = .read | .write; + print("flags: {}\n", perm); + + // Test flag + if perm & .read { print("has-read: yes\n"); } + if perm & .execute { print("has-exec: yes\n"); } + + // Test flag negative + pt : Perms = .write; + if pt & .read { + print("flags-neg: has-read\n"); + } else { + print("flags-neg: no-read\n"); + } + + // Single flag + ps : Perms = .execute; + print("flags-single: {}\n", ps); + + // All flags + pall : Perms = .read | .write | .execute; + print("flags-all: {}\n", pall); + + // Cast to int + print("flags-raw: {}\n", cast(s64) perm); + + // Flags with explicit values + wf : WindowFlags = .vsync | .resizable; + print("flags-explicit: {}\n", wf); + print("flags-explicit-raw: {}\n", cast(s64) wf); + + // --- Multi-target assignment (swap) --- + print("--- swap ---\n"); + + // Variable swap + { + sa := 10; + sb := 20; + sa, sb = sb, sa; + print("var swap: {} {}\n", sa, sb); + } + + // Array element swap + { + sarr : [3]s64 = .[1, 2, 3]; + sarr[0], sarr[2] = sarr[2], sarr[0]; + print("arr swap: {} {}\n", sarr[0], sarr[2]); + } + + // 3-way rotation + { + ra := 1; + rb := 2; + rc := 3; + ra, rb, rc = rc, ra, rb; + print("3-way: {} {} {}\n", ra, rb, rc); + } + + // --- Tuple destructuring --- + print("--- destructure ---\n"); + + // Basic tuple destructuring + { + da, db := (10, 20); + print("basic: {} {}\n", da, db); + } + + // Destructure from function return + { + dswap :: (a: s64, b: s64) -> (s64, s64) { (b, a); } + dx, dy := dswap(1, 2); + print("fn: {} {}\n", dx, dy); + } + + // Discard with _ + { + _, dsecond := (100, 200); + print("discard: {}\n", dsecond); + } + + // Three elements + { + da3, db3, dc3 := (1, 2, 3); + print("triple: {} {} {}\n", da3, db3, dc3); + } +} diff --git a/examples/0123-types-compound-assign.sx b/examples/0123-types-compound-assign.sx new file mode 100644 index 0000000..3be39a1 --- /dev/null +++ b/examples/0123-types-compound-assign.sx @@ -0,0 +1,24 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +main :: () { + + // ======================================================== + // 16. COMPOUND ASSIGNMENT TYPE CONVERSION + // ======================================================== + print("=== 16. Compound Assign ===\n"); + { + ca_a : f64 = 10.0; + ca_b : f32 = 3.0; + ca_a += ca_b; + print("f64+=f32: {}\n", ca_a); + + ca_c : s64 = 100; + ca_d : s32 = 7; + ca_c -= ca_d; + print("s64-=s32: {}\n", ca_c); + } +} diff --git a/examples/0124-types-array-of-structs.sx b/examples/0124-types-array-of-structs.sx new file mode 100644 index 0000000..c15167c --- /dev/null +++ b/examples/0124-types-array-of-structs.sx @@ -0,0 +1,23 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +Point :: struct { x, y: s32; } + +main :: () { + + // ======================================================== + // 18. ARRAYS OF USER-DEFINED TYPES + // ======================================================== + print("=== 18. Array of Structs ===\n"); + { + spts : [2]Point = .[Point.{1, 2}, Point.{3, 4}]; + spt2 := spts[1]; + print("arr-struct-x: {}\n", spt2.x); + for spts: (it) { + print("for-struct: {}\n", it); + } + } +} diff --git a/examples/0125-types-type-named-vars.sx b/examples/0125-types-type-named-vars.sx new file mode 100644 index 0000000..39efe1c --- /dev/null +++ b/examples/0125-types-type-named-vars.sx @@ -0,0 +1,19 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +main :: () { + + // ======================================================== + // 21. TYPE-NAMED VARIABLES (s2, u8, etc.) + // ======================================================== + print("=== 21. Type-Named Vars ===\n"); + { + s2 := 42; + print("s2: {}\n", s2); + s2 = s2 + 1; + print("s2+1: {}\n", s2); + } +} diff --git a/examples/0126-types-nested-arrays.sx b/examples/0126-types-nested-arrays.sx new file mode 100644 index 0000000..83d3cfb --- /dev/null +++ b/examples/0126-types-nested-arrays.sx @@ -0,0 +1,20 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +main :: () { + + // ======================================================== + // 23. NESTED ARRAYS (2D) + // ======================================================== + print("=== 23. Nested Arrays ===\n"); + { + matrix : [2][3]s32 = .[ .[1, 2, 3], .[4, 5, 6] ]; + print("m[0][0]: {}\n", matrix[0][0]); + print("m[0][2]: {}\n", matrix[0][2]); + print("m[1][0]: {}\n", matrix[1][0]); + print("m[1][2]: {}\n", matrix[1][2]); + } +} diff --git a/examples/0127-types-using.sx b/examples/0127-types-using.sx new file mode 100644 index 0000000..ab704fa --- /dev/null +++ b/examples/0127-types-using.sx @@ -0,0 +1,47 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +main :: () { + + // === 26. #using struct composition === + print("=== 26. #using ===\n"); + { + UBase :: struct { x: s32; y: s32; } + UExt :: struct { #using UBase; z: s32; } + e := UExt.{ x = 1, y = 2, z = 3 }; + print("using-x: {}\n", e.x); + print("using-y: {}\n", e.y); + print("using-z: {}\n", e.z); + + // #using in middle position + UHeader :: struct { version: s32; } + UPacket :: struct { id: s32; #using UHeader; payload: s32; } + p := UPacket.{ id = 10, version = 42, payload = 99 }; + print("pkt-id: {}\n", p.id); + print("pkt-ver: {}\n", p.version); + print("pkt-pay: {}\n", p.payload); + + // Multiple #using + UPos :: struct { px: s32; py: s32; } + UCol :: struct { r: s32; g: s32; } + USprite :: struct { #using UPos; #using UCol; scale: s32; } + s := USprite.{ px = 10, py = 20, r = 255, g = 128, scale = 1 }; + print("sprite-px: {}\n", s.px); + print("sprite-r: {}\n", s.r); + print("sprite-scale: {}\n", s.scale); + } + + // --- Comptime format --- + { + ct_body :: "hello"; + ct_msg :: format("say: {} (len={})", ct_body, ct_body.len); + print("{}\n", ct_msg); + + ct_num :: 42; + ct_num_msg :: format("n={}", ct_num); + print("{}\n", ct_num_msg); + } +} diff --git a/examples/0128-types-tuples.sx b/examples/0128-types-tuples.sx new file mode 100644 index 0000000..1c3c086 --- /dev/null +++ b/examples/0128-types-tuples.sx @@ -0,0 +1,27 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +main :: () { + + // --- Tuples --- + { + print("=== Tuples ===\n"); + pair := (40, 2); + print("{}\n", pair.0); + print("{}\n", pair.1); + + named := (x: 10, y: 20); + print("{}\n", named.x); + print("{}\n", named.0); + + single := (42,); + print("{}\n", single.0); + + zeroed : (s32, s32) = ---; + print("{}\n", zeroed.0); + print("{}\n", zeroed.1); + } +} diff --git a/examples/0129-types-tuple-operators.sx b/examples/0129-types-tuple-operators.sx new file mode 100644 index 0000000..8191bc6 --- /dev/null +++ b/examples/0129-types-tuple-operators.sx @@ -0,0 +1,1200 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +Point :: struct { x, y: s32; } + +OptNode :: struct { + value: s32; + next: ?s32; +} + +OptInner :: struct { val: s32; } + +OptOuter :: struct { inner: ?OptInner; } + +add :: (a: s32, b: s32) -> s32 { a + b; } + +mul :: (a: s32, b: s32) -> s32 { a * b; } + +identity :: (x: $T) -> T { x; } + +apply :: (f: (s32, s32) -> s32, x: s32, y: s32) -> s32 { + f(x, y); +} + +// P4 edge: Chained default→default calls +Chained :: protocol { + base :: (msg: string) -> s32; + wrap :: (msg: string) -> s32 { + self.base(msg) + 1; + } + double_wrap :: (msg: string) -> s32 { + self.wrap(msg) + self.wrap(msg); + } +} + +main :: () { + + // --- Tuple Operators --- + { + print("=== Tuple Operators ===\n"); + + // Equality + print("{}\n", (1, 2) == (1, 2)); // true + print("{}\n", (1, 2) == (1, 3)); // false + print("{}\n", (1, 2) != (1, 3)); // true + print("{}\n", (1, 2) != (1, 2)); // false + + // Concatenation + c := (1, 2) + (3, 4); + print("{}\n", c.0); // 1 + print("{}\n", c.1); // 2 + print("{}\n", c.2); // 3 + print("{}\n", c.3); // 4 + + // Repetition + r := (1, 2) * 3; + print("{}\n", r.0); // 1 + print("{}\n", r.1); // 2 + print("{}\n", r.2); // 1 + print("{}\n", r.3); // 2 + print("{}\n", r.4); // 1 + print("{}\n", r.5); // 2 + + // Lexicographic comparison + print("{}\n", (1, 2) < (1, 3)); // true + print("{}\n", (1, 3) < (1, 2)); // false + print("{}\n", (1, 2) < (1, 2)); // false + print("{}\n", (1, 2) <= (1, 2)); // true + print("{}\n", (2, 0) > (1, 9)); // true + print("{}\n", (1, 2) >= (1, 2)); // true + + // Membership + print("{}\n", 2 in (1, 2, 3)); // true + print("{}\n", 5 in (1, 2, 3)); // false + } + + // --- Directory imports --- + { + print("--- directory imports ---\n"); + print("{}\n", pkg.add(3, 4)); // 7 + print("{}\n", pkg.mul(5, 6)); // 30 + print("{}\n", pkg.hello()); // hello from testpkg + print("{}\n", pkg.cwd_greet()); // cwd-import-ok + } + + // --- Pipe operator --- + { + print("--- pipe operator ---\n"); + // Basic: a |> f(b) → f(a, b) + print("{}\n", 3 |> pkg.add(4)); // 7 + print("{}\n", 5 |> pkg.mul(6)); // 30 + + // Chaining: a |> f(b) |> g(c) → g(f(a, b), c) + print("{}\n", 3 |> pkg.add(4) |> pkg.mul(2)); // 14 + + // With non-namespaced functions + print("{}\n", "hello" |> concat(" world")); // hello world + + // Chained string ops + print("{}\n", "piped" |> concat(" ok") |> concat("!")); // piped ok! + } + + // ── alloc_slice ────────────────────────────────────────── + { + items := alloc_slice(s64, 5); + items[0] = 10; + items[1] = 20; + items[2] = 30; + items[3] = 40; + items[4] = 50; + print("alloc len: {}\n", items.len); // alloc len: 5 + print("alloc[0]: {}\n", items[0]); // alloc[0]: 10 + print("alloc[4]: {}\n", items[4]); // alloc[4]: 50 + + // alloc_slice with u8 + bytes := alloc_slice(u8, 3); + bytes[0] = 65; + bytes[1] = 66; + bytes[2] = 67; + print("bytes len: {}\n", bytes.len); // bytes len: 3 + } + + // ======================================================== + // ALLOCATORS + // ======================================================== + print("--- allocators ---\n"); + + // ── GPA ───────────────────────────────────────────────── + { + gpa := GPA.init(); + a : Allocator = xx gpa; + p1 := a.alloc(64); + p2 := a.alloc(128); + print("gpa allocs: {}\n", gpa.alloc_count); // gpa allocs: 2 + a.dealloc(p1); + a.dealloc(p2); + print("gpa final: {}\n", gpa.alloc_count); // gpa final: 0 + } + + // ── Arena backed by GPA (multi-chunk) ─────────────────── + { + gpa3 := GPA.init(); + arena := Arena.init(xx gpa3, 32); + a : Allocator = xx arena; + // First chunk fits 80 usable bytes + a1 := a.alloc(40); + a2 := a.alloc(40); + // Counts: just the first chunk = 1. Arena.init returns the + // state by value; the local IS the Arena struct, no parent + // allocation for the state itself. + print("arena chunks: {}\n", gpa3.alloc_count); // arena chunks: 1 + // Overflow → new chunk + a3 := a.alloc(16); + print("arena overflow: {}\n", gpa3.alloc_count); // arena overflow: 2 + // Verify memory works across chunks + p1 : [*]u8 = xx a1; + p3 : [*]u8 = xx a3; + p1[0] = 42; + p3[0] = 99; + print("arena a1: {}\n", p1[0]); // arena a1: 42 + print("arena a3: {}\n", p3[0]); // arena a3: 99 + // Reset retains the first chunk + arena.reset(); + print("arena reset idx: {}\n", arena.end_index); // arena reset idx: 0 + print("arena reset gpa: {}\n", gpa3.alloc_count); // arena reset gpa: 1 + // Deinit frees all chunks (caller's local is the state — no + // dealloc of the struct itself). + arena.deinit(); + print("arena deinit: {}\n", gpa3.alloc_count); // arena deinit: 0 + } + + // ── BufAlloc from stack array ─────────────────────────── + { + stack_buf : [128]u8 = ---; + buf := BufAlloc.init(@stack_buf[0], 128); + a : Allocator = xx buf; + b1 := a.alloc(24); + b2 := a.alloc(24); + print("buf pos: {}\n", buf.pos); // buf pos: 48 + b3 := a.alloc(200); + b3_i : s64 = xx b3; + print("buf overflow: {}\n", b3_i); // buf overflow: 0 + buf.reset(); + print("buf reset: {}\n", buf.pos); // buf reset: 0 + } + + { + if 1 == (1,) { + print("1 == (1)\n"); + } + + if (1,) == (1) { + print("(1) == 1\n"); + } + + if (1,) == 1 { + print("1 == 1\n"); + } + } + + // ======================================================== + // OPTIONALS + // ======================================================== + print("--- optionals ---\n"); + + // Basic optional creation and null + { + x: ?s32 = 42; + y: ?s32 = null; + print("opt x: {}\n", x); // opt x: 42 + print("opt y: {}\n", y); // opt y: null + } + + // Force unwrap + { + x: ?s32 = 10; + val := x!; + print("unwrap: {}\n", val); // unwrap: 10 + } + + // Null coalescing + { + x: ?s32 = 42; + y: ?s32 = null; + a := x ?? 0; + b := y ?? 99; + print("coalesce a: {}\n", a); // coalesce a: 42 + print("coalesce b: {}\n", b); // coalesce b: 99 + + // Chained ?? (right-associative): a ?? b ?? c + z: ?s32 = null; + c := x ?? y ?? 0; + d := z ?? y ?? 99; + e := z ?? z ?? 0; + print("chained ?? c: {}\n", c); // chained ?? c: 42 + print("chained ?? d: {}\n", d); // chained ?? d: 99 + print("chained ?? e: {}\n", e); // chained ?? e: 0 + } + + // If-binding (safe unwrap) + { + x: ?s32 = 7; + y: ?s32 = null; + if val := x { + print("if-bind x: {}\n", val); // if-bind x: 7 + } + if val := y { + print("if-bind y: should not print\n"); + } else { + print("if-bind y: none\n"); // if-bind y: none + } + } + + // Pattern matching on optionals + { + check :: (v: ?s32) -> s32 { + return if v == { + case .some: (val) { val; } + case .none: { 0; } + }; + } + a: ?s32 = 55; + b: ?s32 = null; + print("match some: {}\n", check(a)); // match some: 55 + print("match none: {}\n", check(b)); // match none: 0 + } + + // Optional with implicit wrapping + { + opt_wrap :: (n: s32) -> ?s32 { + if n > 0 { + return n; + } + return null; + } + r1 := opt_wrap(5); + r2 := opt_wrap(0); + print("wrap pos: {}\n", r1); // wrap pos: 5 + print("wrap neg: {}\n", r2); // wrap neg: null + } + + // Struct field defaults for ?T + { + n := OptNode.{ value = 10 }; + print("opt field default: {}\n", n.next); // opt field default: null + m := OptNode.{ value = 20, next = 42 }; + print("opt field set: {}\n", m.next); // opt field set: 42 + } + + // ?T as function parameter + { + opt_process :: (val: ?s32) -> s32 { + return val ?? 0; + } + a: ?s32 = 42; + b: ?s32 = null; + print("opt param a: {}\n", opt_process(a)); // opt param a: 42 + print("opt param b: {}\n", opt_process(b)); // opt param b: 0 + print("opt param 7: {}\n", opt_process(7)); // opt param 7: 7 + } + + // Assignment to optional variable (f32 → ?f32) + { + iw: ?f32 = null; + w: f32 = 42.5; + iw = w; + print("opt reassign: {}\n", iw ?? 0.0); // opt reassign: 42.5 + + // Assignment of computed value to optional + iw2: ?f32 = null; + a: ?f32 = 10.0; + if v := a { iw2 = v + 5.0; } + print("opt compute assign: {}\n", iw2 ?? 0.0); // opt compute assign: 15.0 + + // Re-assign optional back to null + iw2 = null; + print("opt re-null: {}\n", iw2 ?? 99.0); // opt re-null: 99.0 + } + + // Generic function with ?T return + { + first_pos :: ($T: Type, a: T, b: T) -> ?T { + if a > 0 { return a; } + if b > 0 { return b; } + return null; + } + print("generic opt 1: {}\n", first_pos(s32, 5, 10)); // generic opt 1: 5 + print("generic opt 2: {}\n", first_pos(s32, 0, 7)); // generic opt 2: 7 + print("generic opt 3: {}\n", first_pos(s32, 0, 0)); // generic opt 3: null + } + + // Optional chaining (?.) + { + p: ?OptNode = OptNode.{ value = 10, next = 20 }; + q: ?OptNode = null; + print("chain some: {}\n", p?.value ?? 0); // chain some: 10 + print("chain none: {}\n", q?.value ?? 0); // chain none: 0 + print("chain print: {}\n", p?.next); // chain print: 20 + print("chain null: {}\n", q?.next); // chain null: null + + // Chained: obj.field?.field + o1 := OptOuter.{ inner = OptInner.{ val = 99 } }; + o2 := OptOuter.{ inner = null }; + print("deep chain 1: {}\n", o1.inner?.val ?? 0); // deep chain 1: 99 + print("deep chain 2: {}\n", o2.inner?.val ?? 0); // deep chain 2: 0 + } + + // Flow-sensitive narrowing + { + x: ?s32 = 42; + y: ?s32 = null; + + // if x != null → x is narrowed to s32 + if x != null { + print("narrow x: {}\n", x); // narrow x: 42 + } + + // if y != null → not entered + if y != null { + print("should not print\n"); + } else { + print("narrow y else: null\n"); // narrow y else: null + } + + // if x == null ... else → else-branch narrowed + if x == null { + print("should not print\n"); + } else { + print("narrow else x: {}\n", x); // narrow else x: 42 + } + } + + // Guard narrowing + { + guard_fn :: (v: ?s32) -> s32 { + if v == null { return 0; } + return v; + } + print("guard some: {}\n", guard_fn(42)); // guard some: 42 + print("guard none: {}\n", guard_fn(null)); // guard none: 0 + } + + // Compound narrowing: && chains + { + a: ?s32 = 10; + b: ?s32 = 20; + c: ?s32 = null; + if a != null and b != null { + print("and both: {} {}\n", a, b); // and both: 10 20 + } + if a != null and c != null { + print("should not print\n"); + } else { + print("and one null\n"); // and one null + } + } + + // Compound guard narrowing: || chains + { + guard2 :: (a: ?s32, b: ?s32) -> s32 { + if a == null or b == null { return 0; } + return a + b; + } + print("or guard: {}\n", guard2(3, 4)); // or guard: 7 + print("or guard null: {}\n", guard2(3, null)); // or guard null: 0 + } + + // Nested if narrowing + { + a: ?s32 = 10; + b: ?s32 = 20; + if a != null { + if b != null { + print("nested narrow: {} {}\n", a, b); // nested narrow: 10 20 + } + } + } + + // Guard narrowing used in loop + { + guard_loop :: (v: ?s32) -> s32 { + if v == null { return 0; } + sum := 0; + i := 0; + while i < v { + sum = sum + 1; + i = i + 1; + } + return sum; + } + print("guard loop: {}\n", guard_loop(3)); // guard loop: 3 + } + + // --- block-body lambdas --- + { + // block-body lambda with return type + clamp := (x: s64, lo: s64, hi: s64) -> s64 { + if x < lo { return lo; } + if x > hi { return hi; } + return x; + }; + print("block-lambda: {}\n", clamp(50, 0, 100)); // block-lambda: 50 + print("block-lambda: {}\n", clamp(-10, 0, 100)); // block-lambda: 0 + print("block-lambda: {}\n", clamp(999, 0, 100)); // block-lambda: 100 + + // block-body lambda without return type annotation + greet := (name: string) { + print("hello {}\n", name); + }; + greet("block"); // hello block + } + + // --- named params in function types --- + { + // Named params are documentation only — ignored for type identity + apply_named :: (f: (x: s32, y: s32) -> s32, a: s32, b: s32) -> s32 { + return f(a, b); + } + add :: (a: s32, b: s32) -> s32 { return a + b; } + print("named-fn-type: {}\n", apply_named(add, 3, 4)); // named-fn-type: 7 + } + + // --- xx on function pointers --- + { + MyEnv :: struct { n: s32; } + typed_fn :: (e: *MyEnv, x: s32) -> s32 { + return x + e.n; + } + // xx cast: (*MyEnv, s32) -> s32 → (*void, s32) -> s32 + f : (*void, s32) -> s32 = xx typed_fn; + env := MyEnv.{ n = 100 }; + print("xx-fnptr: {}\n", f(xx @env, 42)); // xx-fnptr: 142 + } + + // --- closure type: construct and access fields --- + { + dummy_fn :: (env: *void, x: s32) -> s32 { + return x * 2; + } + fn_ptr : *void = xx dummy_fn; + null_env : *void = xx 0; + c : Closure(s32) -> s32 = .{ fn_ptr = fn_ptr, env = null_env }; + print("closure-type: fn_ptr-nonnull={}\n", c.fn_ptr != null_env); + print("closure-type: env-null={}\n", c.env == null_env); + } + + // --- closure calling convention --- + { + Env :: struct { n: s32; } + impl_fn :: (env: *void, x: s32) -> s32 { + e : *Env = xx env; + return x + e.n; + } + env := Env.{ n = 5 }; + fn_ptr : *void = xx impl_fn; + env_ptr : *void = xx @env; + c : Closure(s32) -> s32 = .{ fn_ptr = fn_ptr, env = env_ptr }; + print("closure-call: {}\n", c(10)); + } + + // --- auto-promotion: bare fn → Closure --- + { + double :: (x: s32) -> s32 { return x * 2; } + apply :: (f: Closure(s32) -> s32, x: s32) -> s32 { return f(x); } + print("auto-promote: {}\n", apply(double, 10)); + + // Named function to Closure variable + f : Closure(s32) -> s32 = double; + print("auto-promote-var: {}\n", f(5)); + } + + // --- closure() intrinsic --- + { + // capture scalar + n := 42; + f := closure((x: s32) => x + n); + print("closure-capture: {}\n", f(10)); + + // capture by value is a snapshot + m := 5; + g := closure((x: s32) => x + m); + m = 100; + print("closure-snapshot: {}\n", g(10)); + + // no captures (null env) + h := closure((x: s32) => x * 2); + print("closure-nocap: {}\n", h(7)); + + // multiple captures + a := 10; + b := 20; + multi := closure((x: s32) => x + a + b); + print("closure-multi: {}\n", multi(3)); + + // block-body closure with return + offset := 50; + clamp := closure((x: s64) -> s64 { + if x < 0 { return 0; } + if x > 100 { return 100; } + return x + offset; + }); + r1 : s64 = clamp(10); + r2 : s64 = clamp(0 - 5); + r3 : s64 = clamp(999); + print("closure-block: {}\n", r1); + print("closure-block: {}\n", r2); + print("closure-block: {}\n", r3); + + // void closure + tag := "LOG"; + logger := closure((msg: string) { + print("[{}] {}\n", tag, msg); + }); + logger("hello"); + + // pass closure to higher-order function + dbl :: (x: s32) -> s32 { return x * 2; } + apply_cl :: (f2: Closure(s32) -> s32, x: s32) -> s32 { return f2(x); } + factor : s32 = 3; + print("closure-hof: {}\n", apply_cl(closure((x: s32) -> s32 => x * factor), 10)); + + // auto-promoted bare fn passed alongside closures + print("closure-hof-bare: {}\n", apply_cl(dbl, 10)); + + // C5.A2: capture f32 + scale := 2.5; + f_f32 := closure((x: f32) -> f32 => x * scale); + print("closure-f32: {}\n", f_f32(4.0)); + + // C5.A3: capture bool + verbose := true; + f_bool := closure((msg: string) { + if verbose { print("closure-bool: {}\n", msg); } + }); + f_bool("hello"); + + // C5.B3: two params + base : s32 = 100; + f_2p := closure((x: s32, y: s32) -> s32 => x + y + base); + print("closure-2p: {}\n", f_2p(3, 4)); + + // C5.B4: three params + bias : s32 = 1; + f_3p := closure((a: s32, b: s32, c2: s32) -> s32 => a + b + c2 + bias); + print("closure-3p: {}\n", f_3p(10, 20, 30)); + + // C5.B5: mixed param types (string + s32) + extra : s32 = 5; + f_mix := closure((name: string, age: s32) { + print("closure-mix: {} is {}\n", name, age + extra); + }); + f_mix("Alice", 30); + + // C5.C3: return bool + threshold : s32 = 100; + f_rbool := closure((x: s32) -> bool { return x > threshold; }); + print("closure-rbool: {} {}\n", f_rbool(50), f_rbool(200)); + + // C5.D3: reduce / fold + reduce :: (arr: []s32, f3: Closure(s32, s32) -> s32, init: s32) -> s32 { + acc := init; + i : s64 = 0; + while i < arr.len { acc = f3(acc, arr[i]); i += 1; } + return acc; + } + r_nums : []s32 = .[1, 2, 3, 4, 5]; + r_bonus : s32 = 100; + r_total := reduce(r_nums, closure((acc: s32, x: s32) -> s32 => acc + x), r_bonus); + print("closure-reduce: {}\n", r_total); + + // C5.G1: factory function + make_adder :: (n: s32) -> Closure(s32) -> s32 { + return closure((x: s32) -> s32 => x + n); + } + add5 := make_adder(5); + add10 := make_adder(10); + print("closure-factory: {} {}\n", add5(100), add10(100)); + + // C5.A5: capture struct + origin := Point.{ x = 10, y = 20 }; + f_st := closure(() { + print("closure-struct: {} {}\n", origin.x, origin.y); + }); + f_st(); + + // C5.H1: closure captures another closure + inner_n := 10; + inner_cl := closure((x: s64) -> s64 => x + inner_n); + outer_cl := closure((x: s64) -> s64 => inner_cl(x) * 2); + print("closure-compose: {}\n", outer_cl(5)); + + // C5.M7: multiple closures from same scope capture independently + shared : s32 = 10; + cl_a := closure((x: s32) -> s32 => x + shared); + cl_b := closure((x: s32) -> s32 => x * shared); + print("closure-indep: {} {}\n", cl_a(5), cl_b(5)); + + // C6: optional closures + f_none : ?Closure(s64) -> s64 = null; + if h := f_none { + print("should not print: {}\n", h(1)); + } else { + print("opt-closure: none\n"); + } + + opt_n := 10; + f_some : ?Closure(s64) -> s64 = closure((x: s64) -> s64 => x + opt_n); + if h := f_some { + print("opt-closure: {}\n", h(5)); + } else { + print("should not print\n"); + } + + // Struct with optional closure callback + Btn :: struct { label: string; on_click: ?Closure(s64) -> void; } + btn_x := 99; + btn_cl := closure((id: s64) { + print("opt-closure-btn: {} {}\n", id, btn_x); + }); + btn1 := Btn.{ label = "OK", on_click = btn_cl }; + btn2 := Btn.{ label = "Cancel", on_click = null }; + if h := btn1.on_click { h(1); } + if h := btn2.on_click { h(2); } else { print("opt-closure-btn: null\n"); } + + // C5.A6: capture pointer (shared mutable state) + count_a6 : s32 = 0; + p_a6 := @count_a6; + inc_fn := closure(() { p_a6.* += 1; }); + inc_fn(); inc_fn(); inc_fn(); + print("closure-ptr: {}\n", count_a6); + + // C5.A9: capture enum value (as s32 tag) + c_a9 : s32 = 2; // simulate enum tag + f_a9 := closure(() -> s32 => c_a9); + print("closure-enum: {}\n", f_a9()); + + // C5.C4: return string + tag_c4 := "INFO"; + f_c4 := closure((msg: string) -> string => format("[{}] {}", tag_c4, msg)); + print("closure-rstr: {}\n", f_c4("ok")); + + // C5.C5: return struct + off_c5 := Point.{ x = 10, y = 20 }; + f_c5 := closure((p: Point) -> Point => Point.{ x = p.x + off_c5.x, y = p.y + off_c5.y }); + res_c5 := f_c5(Point.{ x = 1, y = 2 }); + print("closure-rstruct: {} {}\n", res_c5.x, res_c5.y); + + // C5.G2: factory with multiple captures + make_linear :: (m: s32, b: s32) -> Closure(s32) -> s32 { + return closure((x: s32) -> s32 => m * x + b); + } + lin := make_linear(3, 7); + print("closure-linear: {}\n", lin(10)); + + // C5.G3: factory returning clamper + make_clamper :: (lo: s32, hi: s32) -> Closure(s32) -> s32 { + return closure((x: s32) -> s32 { + if x < lo { return lo; } + if x > hi { return hi; } + return x; + }); + } + clamp_fn := make_clamper(0, 255); + cv1 : s32 = xx -10; + cv2 : s32 = 100; + cv3 : s32 = 999; + print("closure-clamp: {} {} {}\n", clamp_fn(cv1), clamp_fn(cv2), clamp_fn(cv3)); + + // C5.H2: compose + compose :: (f_h2: Closure(s32) -> s32, g_h2: Closure(s32) -> s32) -> Closure(s32) -> s32 { + return closure((x: s32) -> s32 => f_h2(g_h2(x))); + } + one_h2 : s32 = 1; + two_h2 : s32 = 2; + add1_h2 := closure((x: s32) -> s32 => x + one_h2); + mul2_h2 := closure((x: s32) -> s32 => x * two_h2); + composed := compose(mul2_h2, add1_h2); + print("closure-compose2: {}\n", composed(5)); + + // C5.H3: chain of closures + ch_k1 : s32 = 1; + ch_k2 : s32 = 2; + ch_k10 : s32 = 10; + ch_a := closure((x: s32) -> s32 => x + ch_k1); + ch_b := closure((x: s32) -> s32 => ch_a(x) * ch_k2); + ch_c := closure((x: s32) -> s32 => ch_b(x) + ch_k10); + print("closure-chain: {}\n", ch_c(5)); + + // C5.D1: map + map_cl :: (arr: [*]s32, cnt: s64, f_map: Closure(s32) -> s32, result: [*]s32) { + i := 0; + while i < cnt { result[i] = f_map(arr[i]); i += 1; } + } + map_src : [5]s32 = .[1, 2, 3, 4, 5]; + map_dst : [5]s32 = .[0, 0, 0, 0, 0]; + factor_d1 : s32 = 3; + map_cl(xx @map_src, 5, closure((x: s32) -> s32 => x * factor_d1), xx @map_dst); + print("closure-map: {} {} {} {} {}\n", map_dst[0], map_dst[1], map_dst[2], map_dst[3], map_dst[4]); + + // C5.D2: filter + filter_cl :: (arr: [*]s32, cnt: s64, pred: Closure(s32) -> bool, result: [*]s32) -> s64 { + j := 0; + i := 0; + while i < cnt { + if pred(arr[i]) { result[j] = arr[i]; j += 1; } + i += 1; + } + return j; + } + min_val : s32 = 3; + filt_dst : [5]s32 = .[0, 0, 0, 0, 0]; + kept := filter_cl(xx @map_src, 5, closure((x: s32) -> bool => x >= min_val), xx @filt_dst); + print("closure-filter: {} [{} {} {}]\n", kept, filt_dst[0], filt_dst[1], filt_dst[2]); + + // C5.D4: sort comparator (bubble sort) + sort_cl :: (arr: [*]s32, cnt: s64, less: Closure(s32, s32) -> bool) { + i := 0; + while i < cnt { + j := 0; + while j < cnt - 1 - i { + if less(arr[j + 1], arr[j]) { + tmp := arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = tmp; + } + j += 1; + } + i += 1; + } + } + sort_arr : [5]s32 = .[5, 3, 1, 4, 2]; + descending := true; + sort_cl(xx @sort_arr, 5, closure((a: s32, b: s32) -> bool { + if descending { return a > b; } + return a < b; + })); + print("closure-sort: {} {} {} {} {}\n", sort_arr[0], sort_arr[1], sort_arr[2], sort_arr[3], sort_arr[4]); + + // C5.D5: for_each with index + for_each_cl :: (arr: [*]s32, cnt: s64, f_fe: Closure(s32, s64) -> void) { + i : s64 = 0; + while i < cnt { f_fe(arr[i], i); i += 1; } + } + fe_label := "item"; + fe_arr : [3]s32 = .[10, 20, 30]; + for_each_cl(xx @fe_arr, 3, closure((val: s32, idx: s64) { + print("closure-fe: {} {}={}\n", fe_label, idx, val); + })); + + // C5.D6: find + find_cl :: (arr: [*]s32, cnt: s64, pred_f: Closure(s32) -> bool) -> s64 { + i : s64 = 0; + while i < cnt { + if pred_f(arr[i]) { return i; } + i += 1; + } + return -1; + } + target : s32 = 30; + found_idx := find_cl(xx @fe_arr, 3, closure((x: s32) -> bool => x == target)); + print("closure-find: {}\n", found_idx); + + // C5.D7: any + any_cl :: (arr: [*]s32, cnt: s64, pred_a: Closure(s32) -> bool) -> bool { + i : s64 = 0; + while i < cnt { + if pred_a(arr[i]) { return true; } + i += 1; + } + return false; + } + has_big := any_cl(xx @fe_arr, 3, closure((x: s32) -> bool => x > 100)); + has_20 := any_cl(xx @fe_arr, 3, closure((x: s32) -> bool => x == 20)); + print("closure-any: {} {}\n", has_big, has_20); + + // C5.E4: auto-promotion in struct field assignment + Widget :: struct { transform: Closure(s32) -> s32; } + negate_fn :: (x: s32) -> s32 { return 0 - x; } + w_e4 := Widget.{ transform = negate_fn }; + print("closure-struct-field: {}\n", w_e4.transform(5)); + + // C5.F1: single closure callback in struct + Button :: struct { + label: string; + on_press: Closure(s32) -> void; + } + btn_x2 := 99; + btn_cb := closure((id: s32) { + print("closure-btn: {} {}\n", id, btn_x2); + }); + btn3 := Button.{ label = "OK", on_press = btn_cb }; + btn3.on_press(1); + + // C5.J1: stateful counter via pointer capture + state_j1 : s32 = 0; + p_j1 := @state_j1; + inc_j1 := closure(() -> s32 { p_j1.* += 1; return p_j1.*; }); + print("closure-counter: {} {} {}\n", inc_j1(), inc_j1(), inc_j1()); + + // C5.J2: stateful accumulator + state_j2 : s32 = 100; + p_j2 := @state_j2; + acc_j2 := closure((x: s32) -> s32 { p_j2.* += x; return p_j2.*; }); + print("closure-acc: {} {}\n", acc_j2(5), acc_j2(10)); + + // C5.K2: block-body with local variables and loops + base_k2 : s32 = 100; + sum_fn := closure((items: [*]s32, cnt: s64) -> s32 { + total : s32 = 0; + i : s64 = 0; + while i < cnt { + total += items[i]; + i += 1; + } + return total + base_k2; + }); + k2_arr : [5]s32 = .[1, 2, 3, 4, 5]; + print("closure-loop: {}\n", sum_fn(xx @k2_arr, 5)); + + // C5.M3: reassigning a closure variable + n_m3 : s32 = 1; + f_m3 := closure((x: s32) -> s32 => x + n_m3); + print("closure-reassign: {}\n", f_m3(10)); + m_m3 : s32 = 2; + f_m3 = closure((x: s32) -> s32 => x * m_m3); + print("closure-reassign: {}\n", f_m3(10)); + + // C5.M6b: snapshot verified with struct capture + pt_m6 := Point.{ x = 5, y = 10 }; + f_m6 := closure(() -> s32 => pt_m6.x + pt_m6.y); + pt_m6 = Point.{ x = 99, y = 99 }; + print("closure-snapstruct: {}\n", f_m6()); + + // C5.M2: closure capturing auto-promoted closure + double_m2 :: (x: s32) -> s32 { return x * 2; } + base_m2 : Closure(s32) -> s32 = double_m2; + n_m2 : s32 = 1; + f_m2 := closure((x: s32) -> s32 => base_m2(x) + n_m2); + print("closure-cap-promoted: {}\n", f_m2(5)); + + // C5.M5: immediately invoked closure (via temp var) + n_m5 : s32 = 5; + iife := closure((x: s32) -> s32 => x + n_m5); + result_m5 := iife(10); + print("closure-iife: {}\n", result_m5); + + // C5.F2: optional callback (none) + Toggle :: struct { on_change: ?Closure(bool) -> void; } + t_f2 := Toggle.{ on_change = null }; + if h := t_f2.on_change { h(true); } else { print("closure-toggle: none\n"); } + + // C5.F3: optional callback (some) + t_f3_cb := closure((enabled: bool) { print("closure-toggle: {}\n", enabled); }); + t_f3 := Toggle.{ on_change = t_f3_cb }; + if h := t_f3.on_change { h(true); } + + // C5.F5: callback receiving caller context + Panel :: struct { + title: string; + on_resize: Closure(string, s32, s32) -> void; + } + p_f5_cb := closure((title: string, w: s32, h: s32) { + print("closure-panel: {} {}x{}\n", title, w, h); + }); + p_f5 := Panel.{ title = "main", on_resize = p_f5_cb }; + p_f5.on_resize(p_f5.title, 800, 600); + + // C5.E6: protocol value passed through multiple function calls + step3 :: (a: Allocator) -> *void { a.alloc(8); } + step2 :: (a: Allocator) -> *void { step3(a); } + step1 :: (a: Allocator) -> *void { step2(a); } + gpa_e6 := GPA.init(); + a_e6 : Allocator = xx gpa_e6; + ptr_e6 := step1(a_e6); + print("closure-chain-call: {}\n", ptr_e6 != null); + a_e6.dealloc(ptr_e6); + + // C5.I1: creating closures in a loop (each captures different value) + // TEMPORARILY DISABLED — closure-in-loop causes infinite loop (index_gep element size issue?) + // cl_arr : [5]Closure(s32) -> s32 = ---; + // i_loop := 0; + // while i_loop < 5 { + // val_loop : s32 = xx (i_loop * 10); + // cl_arr[i_loop] = closure((x: s32) -> s32 => x + val_loop); + // i_loop += 1; + // } + // I2: calling closures from array + // tmp_cl := cl_arr[0]; print("closure-loop-0: {}\n", tmp_cl(1)); + // tmp_cl = cl_arr[1]; print("closure-loop-1: {}\n", tmp_cl(1)); + // tmp_cl = cl_arr[4]; print("closure-loop-4: {}\n", tmp_cl(1)); + + // C5.M4: closure in conditional expression (via temp var) + use_fast := true; + k_fast : s32 = 2; + k_slow : s32 = 10; + f_fast := closure((x: s32) -> s32 => x * k_fast); + f_slow := closure((x: s32) -> s32 => x + k_slow); + f_cond : Closure(s32) -> s32 = if use_fast then f_fast else f_slow; + print("closure-cond: {}\n", f_cond(5)); + + // C5.F4: multiple callbacks on one struct + Form :: struct { + on_submit: ?Closure() -> void; + on_cancel: ?Closure() -> void; + } + msg_f4 := "submitted"; + sub_cb := closure(() { print("closure-form: {}\n", msg_f4); }); + form_f4 := Form.{ on_submit = sub_cb, on_cancel = null }; + if h := form_f4.on_submit { h(); } + if h := form_f4.on_cancel { h(); } else { print("closure-form: no cancel\n"); } + + // C5.L3: auto-promoted closure env is null (no free needed) + double_l3 :: (x: s32) -> s32 { return x * 2; } + f_l3 : Closure(s32) -> s32 = double_l3; + print("closure-null-env: {}\n", f_l3.env == null); + + // C5.A7: capture slice (fat pointer like string) + sl_a7 : [3]s32 = .[10, 20, 30]; + ptr_a7 : [*]s32 = xx @sl_a7; + f_a7 := closure((i: s64) -> s32 => ptr_a7[i]); + print("closure-slice: {} {} {}\n", f_a7(0), f_a7(1), f_a7(2)); + + // C5.L1: arena bulk free (closures allocated on arena, freed in bulk) + gpa_l1 := GPA.init(); + arena_l1 := Arena.init(xx gpa_l1, 4096); + push Context.{ allocator = xx arena_l1 } { + n_l1 : s32 = 5; + f_l1 := closure((x: s32) -> s32 => x + n_l1); + print("closure-arena: {}\n", f_l1(10)); + } + arena_l1.deinit(); + + // C5.L2: GPA manual free (verify env alloc/dealloc) + gpa_l2 := GPA.init(); + a_l2 : Allocator = xx gpa_l2; + n_l2 : s32 = 7; + result_l2 : s32 = 0; + push Context.{ allocator = a_l2 } { + f_l2 := closure((x: s32) -> s32 => x + n_l2); + result_l2 = f_l2(10); + a_l2.dealloc(f_l2.env); + } + print("closure-gpa: {} allocs={}\n", result_l2, gpa_l2.alloc_count); + + // C5.A10: capture optional + val_a10 : ?s32 = 42; + f_a10 := closure(() -> s32 { + if v := val_a10 { return v; } + return 0; + }); + print("closure-opt: {}\n", f_a10()); + + // C5.C6: return optional + limit_c6 : s32 = 100; + f_c6 := closure((x: s32) -> ?s32 { + if x > limit_c6 { return null; } + return x; + }); + r1_c6 := f_c6(50); + r2_c6 := f_c6(200); + if v := r1_c6 { print("closure-ropt: {}\n", v); } + if v := r2_c6 { print("should-not-print\n"); } else { print("closure-ropt: none\n"); } + + // C5.M8: array of closures with mixed origins + double_m8 :: (x: s32) -> s32 { return x * 2; } + n_m8 : s32 = 10; + fns_m8 : [3]Closure(s32) -> s32 = ---; + fns_m8[0] = double_m8; // auto-promoted + fns_m8[1] = closure((x: s32) -> s32 => x + n_m8); // captured + fns_m8[2] = closure((x: s32) -> s32 => x * x); // no capture + tmp_m8 := fns_m8[0]; print("closure-mixed: {}\n", tmp_m8(5)); + tmp_m8 = fns_m8[1]; print("closure-mixed: {}\n", tmp_m8(5)); + tmp_m8 = fns_m8[2]; print("closure-mixed: {}\n", tmp_m8(5)); + + // C5.E1: independent closures from same factory (each has own env) + mk_e1 :: (n: s32) -> Closure(s32) -> s32 { + return closure((x: s32) -> s32 => x * n); + } + f1_e1 := mk_e1(2); + f2_e1 := mk_e1(3); + f3_e1 := mk_e1(4); + print("closure-factory-indep: {} {} {}\n", f1_e1(10), f2_e1(10), f3_e1(10)); + + // C5.E2: deep chain — closure capturing closure capturing closure + v_e2 : s32 = 1; + k2_e2 : s32 = 2; + k100_e2 : s32 = 100; + f0_e2 := closure((x: s32) -> s32 => x + v_e2); + f1_e2 := closure((x: s32) -> s32 => f0_e2(x) * k2_e2); + f2_e2 := closure((x: s32) -> s32 => f1_e2(x) + k100_e2); + print("closure-deep-chain: {}\n", f2_e2(10)); + + // C5.E3: many captures (stress env struct) + c1_e3 : s32 = 1; + c2_e3 : s32 = 2; + c3_e3 : s32 = 3; + c4_e3 : s32 = 4; + c5_e3 : s32 = 5; + c6_e3 : s32 = 6; + c7_e3 : s32 = 7; + c8_e3 : s32 = 8; + big_env := closure(() -> s32 => c1_e3 + c2_e3 + c3_e3 + c4_e3 + c5_e3 + c6_e3 + c7_e3 + c8_e3); + print("closure-8cap: {}\n", big_env()); + + // C5.E5: closure with many parameters (4 params) + multi_param := closure((a: s32, b: s32, c: s32, d: s32) -> s32 => a + b + c + d); + a_e5 : s32 = 1; b_e5 : s32 = 2; c_e5 : s32 = 3; d_e5 : s32 = 4; + print("closure-4param: {}\n", multi_param(a_e5, b_e5, c_e5, d_e5)); + + // C5.E7: two closures sharing the same captured pointer + shared : s32 = 0; + shared_p := @shared; + inc_shared := closure(() { shared_p.* += 1; }); + add5_shared := closure(() { shared_p.* += 5; }); + inc_shared(); + add5_shared(); + inc_shared(); + print("closure-shared-ptr: {}\n", shared); + + // C5.E8: closure with f64 arithmetic + pi_e8 : f64 = 3.14159; + area_fn := closure((r: f64) -> f64 => pi_e8 * r * r); + a_e8 := area_fn(10.0); + print("closure-f64: {}\n", a_e8 > 314.0); + + // C5.E9: zero-capture closure (env should be null, like auto-promoted) + no_cap := closure((x: s32) -> s32 => x * x); + print("closure-zerocap: {} {}\n", no_cap(7), no_cap.env == null); + + // C5.E10: closure capturing and calling struct method + pt_e10 := Point.{ x = 3, y = 4 }; + p_e10 := @pt_e10; + get_xy := closure(() -> s32 => p_e10.x + p_e10.y); + print("closure-struct-method: {}\n", get_xy()); + + // C5.E11: multiple closures from same factory with different captures + fns_e11 : [3]Closure(s32) -> s32 = ---; + i_e11 := 0; + while i_e11 < 3 { + multiplier : s32 = xx (i_e11 + 1); + fns_e11[i_e11] = closure((x: s32) -> s32 => x * multiplier); + i_e11 += 1; + } + t_e11 := fns_e11[0]; print("closure-multi-factory: {}\n", t_e11(10)); + t_e11 = fns_e11[1]; print("closure-multi-factory: {}\n", t_e11(10)); + t_e11 = fns_e11[2]; print("closure-multi-factory: {}\n", t_e11(10)); + + // C5.E12: closure capturing bool + flag_e12 := true; + check_fn := closure((x: s32) -> bool { + if flag_e12 { return x > 0; } + return x < 0; + }); + pos_e12 : s32 = 5; + neg_e12 : s32 = xx -3; + print("closure-bool-cap: {} {}\n", check_fn(pos_e12), check_fn(neg_e12)); + + // C5.E13: closure as argument to another closure + apply_fn := closure((f_app: Closure(s32) -> s32, val: s32) -> s32 => f_app(val)); + k_e13 : s32 = 100; + inner_fn := closure((x: s32) -> s32 => x + k_e13); + print("closure-as-arg: {}\n", apply_fn(inner_fn, 42)); + + // C5.E14: closure capturing string and formatting + prefix_e14 := "hello"; + greet_fn := closure((name: string) -> string => format("{} {}", prefix_e14, name)); + print("closure-strfmt: {}\n", greet_fn("world")); + + // C5.E15: reassigning shared pointer target between closure calls + val_e15 : s32 = 10; + p_e15 := @val_e15; + read_fn := closure(() -> s32 => p_e15.*); + print("closure-ptr-before: {}\n", read_fn()); + val_e15 = 42; + print("closure-ptr-after: {}\n", read_fn()); + + // C5.E16: closure returning negative value + off_e16 : s32 = 100; + neg_fn := closure((x: s32) -> s32 => x - off_e16); + val_e16 : s32 = 30; + print("closure-neg: {}\n", neg_fn(val_e16)); + + // C5.E17: closure with protocol value capture (#inline protocol) + gpa_e17 := GPA.init(); + a_e17 : Allocator = xx gpa_e17; + alloc_fn := closure((size: s64) -> *void => a_e17.alloc(size)); + ptr_e17 := alloc_fn(32); + print("closure-proto-cap: {}\n", ptr_e17 != null); + a_e17.dealloc(ptr_e17); + + // C5.E18: chained factory — compose two factories + make_scaler :: (factor: s32) -> Closure(s32) -> s32 { + return closure((x: s32) -> s32 => x * factor); + } + make_offset :: (off: s32) -> Closure(s32) -> s32 { + return closure((x: s32) -> s32 => x + off); + } + s_fn := make_scaler(3); + o_fn := make_offset(7); + // manually compose: scale then offset + print("closure-chain-factory: {}\n", o_fn(s_fn(10))); + + // C5.E19: closure in while loop condition helper + threshold : s32 = 50; + above_fn := closure((x: s32) -> bool => x >= threshold); + vals_e19 : [5]s32 = .[10, 30, 50, 70, 90]; + count_above : s32 = 0; + idx_e19 : s64 = 0; + while idx_e19 < 5 { + if above_fn(vals_e19[idx_e19]) { count_above += 1; } + idx_e19 += 1; + } + print("closure-while-cond: {}\n", count_above); + + // ---- Inferred closure parameter types ---- + + // CI.1: inferred params from typed variable + f_ci1 : Closure(s32, s32) -> s32 = closure((a, b) => a + b); + a_ci1 : s32 = 3; + b_ci1 : s32 = 4; + print("closure-infer: {}\n", f_ci1(a_ci1, b_ci1)); + + // CI.2: inferred params from function argument + apply_ci :: (f: Closure(s32) -> s32, x: s32) -> s32 { return f(x); } + k_ci : s32 = 10; + v_ci : s32 = 5; + print("closure-infer-arg: {}\n", apply_ci(closure((x) => x + k_ci), v_ci)); + + // CI.3: inferred with block body + h_ci : Closure(s32, s32) -> s32 = closure((a, b) { return a * b; }); + print("closure-infer-block: {}\n", h_ci(a_ci1, b_ci1)); + + // CI.4: inferred with captures + cap_ci : s32 = 100; + f_ci4 : Closure(s32) -> s32 = closure((x) => x + cap_ci); + print("closure-infer-cap: {}\n", f_ci4(v_ci)); + + // CI.5: inferred in factory return + mk_ci :: (n: s32) -> Closure(s32) -> s32 { return closure((x) => x * n); } + f_ci5 := mk_ci(7); + print("closure-infer-factory: {}\n", f_ci5(v_ci)); + + // CI.6: inferred with higher-order (closure taking closure) + compose_ci :: (f: Closure(s32) -> s32, g: Closure(s32) -> s32) -> Closure(s32) -> s32 { + return closure((x: s32) -> s32 => f(g(x))); + } + one_ci : s32 = 1; + two_ci : s32 = 2; + c_ci := compose_ci(closure((x) => x + one_ci), closure((x) => x * two_ci)); + print("closure-infer-compose: {}\n", c_ci(v_ci)); + + // CI.7: inferred void return + msg_ci := "infer-void"; + cb_ci : Closure(s32) -> void = closure((x) { print("closure-{}: {}\n", msg_ci, x); }); + cb_ci(42); + } +} diff --git a/examples/0130-types-struct-constants.sx b/examples/0130-types-struct-constants.sx new file mode 100644 index 0000000..fbbf065 --- /dev/null +++ b/examples/0130-types-struct-constants.sx @@ -0,0 +1,27 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +// ============================================================ +// Struct constants test +Phys :: struct { + x, y: f32; + GRAVITY :f32: 9.81; + MAX_SPEED :: 100; +} + +// Init block test struct + +main :: () { + + // --- Struct Constants --- + print("=== Struct Constants ===\n"); + { + print("gravity: {}\n", Phys.GRAVITY); // gravity: 9.810000 + print("max speed: {}\n", Phys.MAX_SPEED); // max speed: 100 + p := Phys.{ x = 0.0, y = Phys.GRAVITY }; + print("p.y: {}\n", p.y); // p.y: 9.810000 + } +} diff --git a/examples/0131-types-init-blocks.sx b/examples/0131-types-init-blocks.sx new file mode 100644 index 0000000..d5ad923 --- /dev/null +++ b/examples/0131-types-init-blocks.sx @@ -0,0 +1,200 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +Point :: struct { x, y: s32; } + +add :: (a: s32, b: s32) -> s32 { a + b; } + +Counter :: protocol { + inc :: (); + get :: () -> s32; +} + +Summable :: protocol { + sum :: () -> s32; +} + +SimpleCounter :: struct { val: s32; } + +impl Counter for SimpleCounter { + inc :: (self: *SimpleCounter) { self.val += 1; } + get :: (self: *SimpleCounter) -> s32 { self.val; } +} + +impl Summable for Point { + sum :: (self: *Point) -> s32 { self.x + self.y; } +} + +// Phase 2: #inline protocol for dynamic dispatch + +// Phase 7: Generic struct impls +Pair :: struct ($T: Type) { + a: T; + b: T; +} + +impl Summable for Pair($T) { + sum :: (self: *Pair(T)) -> s32 { + xx self.a + xx self.b; + } +} + +// P6.5: Struct type param constraints + +// Init block test struct +Builder :: struct { + total: s32; + count: s32; + + add :: (self: *Builder, val: s32) { + self.total += val; + self.count += 1; + } +} + +// Global variable for address-of test + +main :: () { + + // --- Init Blocks (IB) --- + print("=== Init Blocks ===\n"); + + // IB1: basic init block with struct methods + { + b := Builder.{ total = 0, count = 0 } { + self.add(10); + self.add(20); + self.add(30); + }; + print("IB1: {} {}\n", b.total, b.count); + } + + // IB2: nested init blocks (self shadows correctly) + { + b1 := Builder.{ total = 0, count = 0 } { + self.add(100); + b2 := Builder.{ total = 0, count = 0 } { + self.add(42); + }; + self.add(b2.total); + }; + print("IB2: {} {}\n", b1.total, b1.count); + } + + // IB3: empty init block + { + b := Builder.{ total = 5, count = 1 } {}; + print("IB3: {} {}\n", b.total, b.count); + } + + // IB4: conditional inside init block + { + add_extra := true; + b := Builder.{ total = 0, count = 0 } { + self.add(10); + if add_extra { + self.add(90); + } + }; + print("IB4: {}\n", b.total); + } + + // IB5: init block + auto type erasure combined + { + use_counter :: (c: Counter) -> s32 { c.inc(); c.inc(); c.get(); } + result := use_counter(SimpleCounter.{ val = 0 } { + self.val = 50; + }); + print("IB5: {}\n", result); + } + + // ============================================================ + // SECTION: Struct static method shorthand (.method(args) syntax) + // ============================================================ + print("--- struct static method shorthand ---\n"); + + // SM1: Basic shorthand — .create(args) resolves to Dims.create(args) + { + Dims :: struct { + w: f32; + h: f32; + + create :: (w: f32, h: f32) -> Dims { + Dims.{ w = w, h = h }; + } + + square :: (size: f32) -> Dims { + Dims.{ w = size, h = size }; + } + } + use_dims :: (d: Dims) { print("SM1: {} {}\n", d.w, d.h); } + use_dims(.create(16.0, 8.0)); + use_dims(.square(5.0)); + } + + // SM2: Shorthand in variable declaration with explicit type + { + Pair :: struct { + a: s64; + b: s64; + + make :: (a: s64, b: s64) -> Pair { + Pair.{ a = a, b = b }; + } + } + p : Pair = .make(10, 20); + print("SM2: {} {}\n", p.a, p.b); + } + + // ============================================================ + // OPTIONAL IF-ELSE COERCION + // ============================================================ + { + print("--- optional if-else coercion ---\n"); + OptF :: struct { width: ?f32; } + x :f32: 10.0; + + // null in then branch + f1 := OptF.{ width = if true then null else x }; + print("opt-if1: {}\n", f1.width ?? 99.0); + + // value in then branch, null in else + f2 := OptF.{ width = if true then x else null }; + print("opt-if2: {}\n", f2.width ?? 99.0); + + // both branches are values + f3 := OptF.{ width = if false then 5.0 else x }; + print("opt-if3: {}\n", f3.width ?? 99.0); + + // standalone optional variable + val: ?f32 = if true then null else 42.0; + print("opt-if4: {}\n", val ?? 0.0); + + val2: ?f32 = if false then null else 42.0; + print("opt-if5: {}\n", val2 ?? 0.0); + } + + // --- usize / isize --- + { + a : usize = 42; + b : isize = 0 - 7; + print("usize: {}\n", a); + print("isize: {}\n", b); + + // arithmetic + c : usize = a + 8; + print("usize+8: {}\n", c); + + // coercion from s32 + x : s32 = 10; + y : usize = xx x; + print("s32->usize: {}\n", y); + + // coercion to s64 + z : s64 = xx a; + print("usize->s64: {}\n", z); + } +} diff --git a/examples/0415-protocols-protocols.sx b/examples/0415-protocols-protocols.sx new file mode 100644 index 0000000..00064fb --- /dev/null +++ b/examples/0415-protocols-protocols.sx @@ -0,0 +1,617 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +Point :: struct { x, y: s32; } + +Color :: enum { red; green; blue; } + +Shape :: enum { + circle: f32; + rect: struct { w, h: f32; }; + none; +} + +Overlay :: union { + f: f32; + i: s32; +} + +Vec2 :: union { + data: [2]f32; + struct { x, y: f32; }; +} + +Defaults :: struct { + a: s32; + b: s32 = 99; + c: s32 = ---; +} + +OptNode :: struct { + value: s32; + next: ?s32; +} + +OptInner :: struct { val: s32; } + +OptOuter :: struct { inner: ?OptInner; } + +MyFloat :: f64; + +Perms :: enum flags { read; write; execute; } + +Status :: enum u8 { ok; err; timeout; } + +WindowFlags :: enum flags u32 { vsync :: 64; resizable :: 4; hidden :: 128; } + +// --- Top-level functions --- + +add :: (a: s32, b: s32) -> s32 { a + b; } + +mul :: (a: s32, b: s32) -> s32 { a * b; } + +identity :: (x: $T) -> T { x; } + +pair_add :: (a: $T, b: $U) -> s64 { + cast(s64) a + cast(s64) b; +} + +typed_sum :: (..args: []s32) -> s32 { + result := 0; + for args: (it) { result = result + it; } + result; +} + +apply :: (f: (s32, s32) -> s32, x: s32, y: s32) -> s32 { + f(x, y); +} + +void_return :: () { + return; +} + +implicit_return :: (x: s32) -> s32 { + x * 2; +} + +early_return :: (x: s32) -> s32 { + if x > 10 { return 99; } + x; +} + +vec3 :: (x: f32, y: f32, z: f32) -> Vector(3, f32) { + .[x, y, z]; +} + +point_sum :: (p: Point) -> s32 { p.x + p.y; } + +// #run compile-time constants + +// #run compile-time constants +CT_VAL :: #run add(10, 15); + +CT_MUL :: #run mul(6, 7); + +CT_CHAIN :: #run add(CT_VAL, 5); + +// #run compile-time optional tests + +// #run compile-time optional tests +ct_opt_coalesce :: () -> s32 { + x: ?s32 = 42; + y: ?s32 = null; + return (x ?? 0) + (y ?? 99); +} + +ct_opt_unwrap :: () -> s32 { + x: ?s32 = 77; + return x!; +} + +ct_opt_guard :: () -> s32 { + x: ?s32 = 10; + if x == null { return -1; } + return x; +} + +CT_OPT_COALESCE :: #run ct_opt_coalesce(); + +CT_OPT_UNWRAP :: #run ct_opt_unwrap(); + +CT_OPT_GUARD :: #run ct_opt_guard(); + +// #insert helpers + +// #insert helpers +gen_code :: () -> string { + return "print(\"insert-ok\\n\");"; +} + +gen_val :: () -> string { + return "print(\"insert-gen: {}\\n\", 42);"; +} + +// --- Error handling (failable functions: sets, raise/try/catch/or/onfail) --- + +SmokeErr :: error { Empty, BadDigit, Overflow } + +// value-carrying, named set: raise three tags or succeed + +// value-carrying, named set: raise three tags or succeed +sm_parse :: (n: s32) -> (s32, !SmokeErr) { + if n < 0 { raise error.BadDigit; } + if n == 0 { raise error.Empty; } + if n > 99 { raise error.Overflow; } + return n * 2; +} + +// pure failable, inferred set (ad-hoc tag minted into `!`) + +// pure failable, inferred set (ad-hoc tag minted into `!`) +sm_check :: (ok: bool) -> ! { + if !ok { raise error.NotReady; } + return; +} + +// multi-value, inferred set: `try` propagates; the SCC pass absorbs SmokeErr + +// multi-value, inferred set: `try` propagates; the SCC pass absorbs SmokeErr +sm_pair :: (a: s32, b: s32) -> (s32, s32, !) { + x := try sm_parse(a); + y := try sm_parse(b); + return (x, y); +} + +// `catch` block that diverges (logs the tag, then returns a fallback) + +// `catch` block that diverges (logs the tag, then returns a fallback) +sm_or_default :: (n: s32) -> s32 { + return sm_parse(n) catch e { + print(" logged {}\n", e); + return -1; + }; +} + +// `onfail` + `defer` interleave: cleanup runs only on the error path + +// `onfail` + `defer` interleave: cleanup runs only on the error path +sm_acquire :: (fail: bool) -> (s32, !) { + defer print(" smoke defer A\n"); + onfail print(" smoke onfail B\n"); + if fail { raise error.Acquire; } + return 7; +} + +// `or`-chain: try a, fall to try b; propagate if both fail + +// `or`-chain: try a, fall to try b; propagate if both fail +sm_first :: (a: s32, b: s32) -> (s32, !) { + v := try sm_parse(a) or try sm_parse(b); + return v; +} + +// --- Foreign function binding --- + +// --- Foreign function binding --- +libc :: #library "c"; + +c_abs :: (n: s32) -> s32 #foreign libc "abs"; + +// --- Protocol declarations (Phase 1: static dispatch only) --- + +Counter :: protocol { + inc :: (); + get :: () -> s32; +} + +Summable :: protocol { + sum :: () -> s32; +} + +SimpleCounter :: struct { val: s32; } + +impl Counter for SimpleCounter { + inc :: (self: *SimpleCounter) { self.val += 1; } + get :: (self: *SimpleCounter) -> s32 { self.val; } +} + +impl Summable for Point { + sum :: (self: *Point) -> s32 { self.x + self.y; } +} + +// Phase 2: #inline protocol for dynamic dispatch + +// Phase 2: #inline protocol for dynamic dispatch +Adder :: protocol #inline { + add :: (n: s32); + value :: () -> s32; +} + +Accumulator :: struct { + total: s32; +} + +impl Adder for Accumulator { + add :: (self: *Accumulator, n: s32) { self.total += n; } + value :: (self: *Accumulator) -> s32 { self.total; } +} + +Doubler :: struct { val: s32; } + +impl Adder for Doubler { + add :: (self: *Doubler, n: s32) { self.val = self.val + n + n; } + value :: (self: *Doubler) -> s32 { self.val; } +} + +// Phase 4: default methods + +// Phase 4: default methods +Repeater :: protocol { + say :: (msg: string); + say_twice :: (msg: string) { + self.say(msg); + self.say(msg); + } +} + +Printer :: struct { count: s32; } + +impl Repeater for Printer { + say :: (self: *Printer, msg: string) { + self.count += 1; + out(msg); + } +} + +// P4 edge: Chained default→default calls + +// P4 edge: Chained default→default calls +Chained :: protocol { + base :: (msg: string) -> s32; + wrap :: (msg: string) -> s32 { + self.base(msg) + 1; + } + double_wrap :: (msg: string) -> s32 { + self.wrap(msg) + self.wrap(msg); + } +} + +ChainImpl :: struct { val: s32; } +impl Chained for ChainImpl { + base :: (self: *ChainImpl, msg: string) -> s32 { + self.val += 1; + msg.len; + } +} + +// Phase 5: Self type + +// Phase 5: Self type +Eq :: protocol { + eq :: (other: Self) -> bool; +} + +impl Eq for Point { + eq :: (self: *Point, other: Point) -> bool { + self.x == other.x and self.y == other.y; + } +} + +Cloneable :: protocol { + clone :: () -> Self; +} + +impl Cloneable for Point { + clone :: (self: *Point) -> Point { + Point.{ x = self.x, y = self.y }; + } +} + +impl Eq for s64 { + eq :: (self: *s64, other: s64) -> bool { + self.* == other; + } +} + +// Phase 6: Generic constraints + +// Phase 6: Generic constraints +are_equal :: ($T: Type/Eq, a: T, b: T) -> bool { + a.eq(b); +} + +Hashable :: protocol { + hash :: () -> s64; +} + +impl Hashable for Point { + hash :: (self: *Point) -> s64 { + xx self.x * 31 + xx self.y; + } +} + +eq_and_hash :: ($T: Type/Eq/Hashable, a: T, b: T) -> bool { + if a.hash() != b.hash() { return false; } + a.eq(b); +} + +// P6.4: inline constraint syntax ($T/Protocol) + +// P6.4: inline constraint syntax ($T/Protocol) +sum_of_inline :: (a: $T/Summable, b: T) -> s32 { + a.sum() + b.sum(); +} + +// Phase 7: Generic struct impls + +// Phase 7: Generic struct impls +Pair :: struct ($T: Type) { + a: T; + b: T; +} + +impl Summable for Pair($T) { + sum :: (self: *Pair(T)) -> s32 { + xx self.a + xx self.b; + } +} + +// P6.5: Struct type param constraints + +// P6.5: Struct type param constraints +SumBox :: struct ($T: Type/Summable) { + val: T; +} + +// ============================================================ +// Struct constants test + +// ============================================================ +// Struct constants test +Phys :: struct { + x, y: f32; + GRAVITY :f32: 9.81; + MAX_SPEED :: 100; +} + +// Init block test struct + +// Init block test struct +Builder :: struct { + total: s32; + count: s32; + + add :: (self: *Builder, val: s32) { + self.total += val; + self.count += 1; + } +} + +// Global variable for address-of test + +// Global variable for address-of test +g_smoke_val : s32 = 42; + +write_to_ptr :: (p: *s32) { + p.* = 99; +} + +main :: () { + + // ======================================================== + // PROTOCOLS (Phase 1: static dispatch) + // ======================================================== + print("=== Protocols ===\n"); + + // P1.1: Basic protocol + impl, direct call on concrete type + { + sc := SimpleCounter.{ val = 0 }; + sc.inc(); + sc.inc(); + sc.inc(); + print("P1.1: {}\n", sc.get()); + } + + // P1.2: impl in separate scope (retroactive conformance) + { + p := Point.{ x = 10, y = 20 }; + print("P1.2: {}\n", p.sum()); + } + + // P2.1: #inline protocol — xx conversion + dynamic dispatch + { + acc := Accumulator.{ total = 0 }; + a : Adder = xx @acc; + a.add(10); + a.add(20); + a.add(12); + print("P2.1: {}\n", a.value()); + } + + // P2.2: pass protocol value to function + { + use_adder :: (a: Adder, n: s32) -> s32 { + a.add(n); + a.value(); + } + acc := Accumulator.{ total = 100 }; + result := use_adder(xx @acc, 50); + print("P2.2: {}\n", result); + } + + // P2.3: different impls through same protocol type + { + acc := Accumulator.{ total = 0 }; + dbl := Doubler.{ val = 0 }; + a1 : Adder = xx @acc; + a2 : Adder = xx @dbl; + a1.add(5); + a2.add(5); + print("P2.3: {} {}\n", a1.value(), a2.value()); + } + + // P3.1: vtable-pointer protocol (default, no #inline) + { + sc := SimpleCounter.{ val = 0 }; + c : Counter = xx @sc; + c.inc(); + c.inc(); + c.inc(); + c.inc(); + c.inc(); + print("P3.1: {}\n", c.get()); + } + + // P3.2: vtable protocol passed to function + { + use_counter :: (c: Counter) -> s32 { + c.inc(); + c.inc(); + c.get(); + } + sc := SimpleCounter.{ val = 10 }; + result := use_counter(xx @sc); + print("P3.2: {}\n", result); + } + + // P4.1: default method calls required method (static dispatch) + { + pr := Printer.{ count = 0 }; + pr.say_twice("hi "); + print("\nP4.1: {}\n", pr.count); + } + + // P4.2: default method via dynamic dispatch (vtable) + { + pr := Printer.{ count = 0 }; + r : Repeater = xx @pr; + r.say_twice("yo "); + print("\nP4.2: {}\n", pr.count); + } + + // P4.3: chained default→default calls via vtable + { + ci := ChainImpl.{ val = 0 }; + ch : Chained = xx @ci; + // double_wrap calls wrap twice, wrap calls base once each + // base("hi") returns 2 (len), wrap adds 1 → 3, double_wrap = 3 + 3 = 6 + result := ch.double_wrap("hi"); + // base was called 2 times (once per wrap call) + print("P4.3: {} {}\n", result, ci.val); + } + + // P5.1: Self type in protocol — static dispatch + { + p1 := Point.{ x = 1, y = 2 }; + p2 := Point.{ x = 1, y = 2 }; + p3 := Point.{ x = 3, y = 4 }; + print("P5.1: {} {}\n", p1.eq(p2), p1.eq(p3)); + } + + // P5.2: Self in return position + { + p := Point.{ x = 10, y = 20 }; + p2 := p.clone(); + print("P5.2: {} {}\n", p2.x, p2.y); + } + + // P5.5: impl for primitive type + { + x := 42; + y := 42; + z := 99; + r1 := x.eq(y); + r2 := x.eq(z); + print("P5.5: {} {}\n", r1, r2); + } + + // P5.3: Self with dynamic dispatch (erased to *void) + { + p1 := Point.{ x = 1, y = 2 }; + p2 := Point.{ x = 1, y = 2 }; + p3 := Point.{ x = 3, y = 4 }; + e : Eq = xx p1; + print("P5.3: {} {}\n", e.eq(p2), e.eq(p3)); + } + + // P6.1: Single constraint — constrained generic function + { + p1 := Point.{ x = 1, y = 2 }; + p2 := Point.{ x = 1, y = 2 }; + p3 := Point.{ x = 3, y = 4 }; + print("P6.1: {} {}\n", are_equal(p1, p2), are_equal(p1, p3)); + } + + // P6.2: Constraint with primitive type + { + print("P6.2: {} {}\n", are_equal(42, 42), are_equal(42, 99)); + } + + // P6.3: Multiple constraints + { + p1 := Point.{ x = 1, y = 2 }; + p2 := Point.{ x = 1, y = 2 }; + p3 := Point.{ x = 3, y = 4 }; + print("P6.3: {} {}\n", eq_and_hash(p1, p2), eq_and_hash(p1, p3)); + } + + // P6.4: inline constraint syntax ($T/Protocol) + { + // sum_of_inline uses $T/Summable inline (not $T: Type/Summable) + p1 := Point.{ x = 10, y = 20 }; + p2 := Point.{ x = 3, y = 7 }; + print("P6.4: {}\n", sum_of_inline(p1, p2)); + } + + // P6.5: Struct type param constraints ($T: Type/Summable) + { + box := SumBox(Point).{ val = Point.{ x = 5, y = 15 } }; + print("P6.5: {}\n", box.val.sum()); + } + + // P7.1: impl for generic struct + { + p := Pair(s32).{ a = 10, b = 20 }; + print("P7.1: {}\n", p.sum()); + } + + // P7.2: generic struct impl with different type arg + { + p1 := Pair(s32).{ a = 3, b = 7 }; + p2 := Pair(s64).{ a = 100, b = 200 }; + print("P7.2: {} {}\n", p1.sum(), p2.sum()); + } + + // P2.4: xx in function return position (tested in standalone test_return.sx) + // Covered by: make_adder :: (acc: *Accumulator) -> Adder { xx acc; } + + // P2.6: protocol values in arrays + { + acc := Accumulator.{ total = 0 }; + dbl := Doubler.{ val = 0 }; + adders : [2]Adder = .[xx @acc, xx @dbl]; + i := 0; + while i < 2 { + adders[i].add(5); + i += 1; + } + print("P2.6: {} {}\n", acc.total, dbl.val); + } + + // P2.7: xx on inline struct literal (no intermediate variable) + { + use_adder :: (a: Adder) -> s32 { a.add(10); a.value(); } + result := use_adder(xx Accumulator.{ total = 5 }); + print("P2.7: {}\n", result); + } + + // P3.3: xx on inline struct literal with vtable protocol + { + use_counter :: (c: Counter) -> s32 { c.inc(); c.inc(); c.get(); } + result := use_counter(xx SimpleCounter.{ val = 100 }); + print("P3.3: {}\n", result); + } +} diff --git a/examples/0416-protocols-auto-type-erasure.sx b/examples/0416-protocols-auto-type-erasure.sx new file mode 100644 index 0000000..3af6f27 --- /dev/null +++ b/examples/0416-protocols-auto-type-erasure.sx @@ -0,0 +1,92 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +Point :: struct { x, y: s32; } + +add :: (a: s32, b: s32) -> s32 { a + b; } + +Counter :: protocol { + inc :: (); + get :: () -> s32; +} + +Summable :: protocol { + sum :: () -> s32; +} + +SimpleCounter :: struct { val: s32; } + +impl Counter for SimpleCounter { + inc :: (self: *SimpleCounter) { self.val += 1; } + get :: (self: *SimpleCounter) -> s32 { self.val; } +} + +impl Summable for Point { + sum :: (self: *Point) -> s32 { self.x + self.y; } +} + +// Phase 2: #inline protocol for dynamic dispatch + +// Phase 2: #inline protocol for dynamic dispatch +Adder :: protocol #inline { + add :: (n: s32); + value :: () -> s32; +} + +Accumulator :: struct { + total: s32; +} + +impl Adder for Accumulator { + add :: (self: *Accumulator, n: s32) { self.total += n; } + value :: (self: *Accumulator) -> s32 { self.total; } +} + +main :: () { + + // --- Auto type erasure (AE) --- + print("=== Auto Type Erasure ===\n"); + + // AE1: function argument — concrete passed where protocol expected (no xx) + { + use_counter :: (c: Counter) -> s32 { c.inc(); c.inc(); c.get(); } + sc := SimpleCounter.{ val = 10 }; + result := use_counter(sc); + print("AE1: {}\n", result); + } + + // AE2: variable assignment — concrete to protocol variable (no xx) + { + acc := Accumulator.{ total = 0 }; + a: Adder = acc; + a.add(5); + a.add(3); + print("AE2: {}\n", a.value()); + } + + // AE3: struct literal passed directly (no xx) + { + use_counter :: (c: Counter) -> s32 { c.inc(); c.inc(); c.get(); } + result := use_counter(SimpleCounter.{ val = 100 }); + print("AE3: {}\n", result); + } + + // AE4: explicit xx still works (not broken) + { + use_counter :: (c: Counter) -> s32 { c.inc(); c.get(); } + result := use_counter(xx SimpleCounter.{ val = 50 }); + print("AE4: {}\n", result); + } + + // AE5: pointer auto-erasure — *ConcreteType to protocol + { + use_adder :: (a: Adder) { a.add(10); } + acc := Accumulator.{ total = 5 }; + p := @acc; + use_adder(p); + print("AE5: {}\n", acc.total); + } +} diff --git a/examples/0608-comptime-comptime.sx b/examples/0608-comptime-comptime.sx new file mode 100644 index 0000000..6e87ac1 --- /dev/null +++ b/examples/0608-comptime-comptime.sx @@ -0,0 +1,83 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +add :: (a: s32, b: s32) -> s32 { a + b; } + +mul :: (a: s32, b: s32) -> s32 { a * b; } + +// #run compile-time constants +CT_VAL :: #run add(10, 15); + +CT_MUL :: #run mul(6, 7); + +CT_CHAIN :: #run add(CT_VAL, 5); + +// #run compile-time optional tests + +// #run compile-time optional tests +ct_opt_coalesce :: () -> s32 { + x: ?s32 = 42; + y: ?s32 = null; + return (x ?? 0) + (y ?? 99); +} + +ct_opt_unwrap :: () -> s32 { + x: ?s32 = 77; + return x!; +} + +ct_opt_guard :: () -> s32 { + x: ?s32 = 10; + if x == null { return -1; } + return x; +} + +CT_OPT_COALESCE :: #run ct_opt_coalesce(); + +CT_OPT_UNWRAP :: #run ct_opt_unwrap(); + +CT_OPT_GUARD :: #run ct_opt_guard(); + +// #insert helpers + +// #insert helpers +gen_code :: () -> string { + return "print(\"insert-ok\\n\");"; +} + +gen_val :: () -> string { + return "print(\"insert-gen: {}\\n\", 42);"; +} + +// --- Error handling (failable functions: sets, raise/try/catch/or/onfail) --- + +main :: () { + + // ======================================================== + // 8. COMPILE-TIME + // ======================================================== + print("=== 8. Comptime ===\n"); + + // #run constant + print("run-const: {}\n", CT_VAL); + + // #run with expression + print("run-expr: {}\n", CT_MUL); + + // #run chained dependency + print("run-chain: {}\n", CT_CHAIN); + + // #run comptime optionals + print("ct-opt-coalesce: {}\n", CT_OPT_COALESCE); // ct-opt-coalesce: 141 + print("ct-opt-unwrap: {}\n", CT_OPT_UNWRAP); // ct-opt-unwrap: 77 + print("ct-opt-guard: {}\n", CT_OPT_GUARD); // ct-opt-guard: 10 + + // #insert with function + #insert gen_code(); + + // #insert additional + #insert gen_val(); +} diff --git a/examples/0609-comptime-inline-if.sx b/examples/0609-comptime-inline-if.sx new file mode 100644 index 0000000..2499b66 --- /dev/null +++ b/examples/0609-comptime-inline-if.sx @@ -0,0 +1,46 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +main :: () { + + // --- inline if (compile-time conditionals) --- + print("=== inline if ===\n"); + { + // POINTER_SIZE is 8 on desktop (64-bit) + inline if POINTER_SIZE == 8 { + print("64-bit\n"); + } else { + print("32-bit\n"); + } + + // OS enum comparison + inline if OS == .wasm { + print("wasm\n"); + } else { + print("not wasm\n"); + } + + // != comparison + inline if OS != .unknown { + print("known os\n"); + } else { + print("unknown os\n"); + } + + // nested inline if + inline if POINTER_SIZE != 4 { + inline if OS != .wasm { + print("desktop 64-bit\n"); + } else { + print("wasm 64-bit??\n"); + } + } + + // POINTER_SIZE in regular (non-inline) if expression + ps := if POINTER_SIZE == 8 then "8" else "4"; + print("pointer size via if: {}\n", ps); + } +} diff --git a/examples/0810-memory-slice-ptr.sx b/examples/0810-memory-slice-ptr.sx new file mode 100644 index 0000000..71810df --- /dev/null +++ b/examples/0810-memory-slice-ptr.sx @@ -0,0 +1,20 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +main :: () { + + // ======================================================== + // 17. SLICE/ARRAY .ptr ACCESS + // ======================================================== + print("=== 17. Slice Ptr ===\n"); + { + sarr : [5]s32 = .[10, 20, 30, 40, 50]; + ssl := sarr[1..4]; + sp := ssl.ptr; + print("sl-ptr[0]: {}\n", sp[0]); + print("sl-ptr[1]: {}\n", sp[1]); + } +} diff --git a/examples/1036-errors-failable-smoke.sx b/examples/1036-errors-failable-smoke.sx new file mode 100644 index 0000000..2a90f32 --- /dev/null +++ b/examples/1036-errors-failable-smoke.sx @@ -0,0 +1,104 @@ +// End-to-end error handling: failable functions (named + inferred sets) consumed +// through every absorbing form — destructure, `try` (in helpers), `catch` (bare- +// expr / match-body / diverging block / no-binding), `or` value-terminator, +// `onfail` cleanup interleaved with `defer`, plus `error.X` as a value and `{}` +// tag-name interpolation. + +#import "modules/std.sx"; + +SmokeErr :: error { Empty, BadDigit, Overflow } + +// value-carrying, named set +sm_parse :: (n: s32) -> (s32, !SmokeErr) { + if n < 0 { raise error.BadDigit; } + if n == 0 { raise error.Empty; } + if n > 99 { raise error.Overflow; } + return n * 2; +} + +// pure failable, inferred set (ad-hoc tag) +sm_check :: (ok: bool) -> ! { + if !ok { raise error.NotReady; } + return; +} + +// multi-value, inferred set: `try` propagates; SCC absorbs SmokeErr +sm_pair :: (a: s32, b: s32) -> (s32, s32, !) { + x := try sm_parse(a); + y := try sm_parse(b); + return (x, y); +} + +// catch with a diverging block body +sm_or_default :: (n: s32) -> s32 { + return sm_parse(n) catch e { + print(" logged {}\n", e); + return -1; + }; +} + +// onfail + defer interleave: cleanup runs only on the error path +sm_acquire :: (fail: bool) -> (s32, !) { + defer print(" defer A\n"); + onfail print(" onfail B\n"); + if fail { raise error.Acquire; } + return 7; +} + +// or-chain: try a, fall to try b; propagate if both fail +sm_first :: (a: s32, b: s32) -> (s32, !) { + v := try sm_parse(a) or try sm_parse(b); + return v; +} + +main :: () { + // error.X as a typed value + {} interpolation renders the tag name + e0 : SmokeErr = error.BadDigit; + print("tag: {}\n", e0); + + // success destructure + error inspect + v1, err1 := sm_parse(5); + if !err1 { print("parsed: {}\n", v1); } + v2, err2 := sm_parse(-1); + if err2 == error.BadDigit { print("got: {}\n", err2); } + + // catch — bare-expr body + ce := sm_parse(0) catch e 100; + print("catch-expr: {}\n", ce); + + // catch — match-body per-tag dispatch + cm := sm_parse(200) catch e == { + case .Overflow: 1; + case .Empty: 2; + else: 3; + }; + print("catch-match: {}\n", cm); + + // catch — diverging block (in helper) + print("or-default ok: {}\n", sm_or_default(5)); + print("or-default err: {}\n", sm_or_default(-5)); + + // or — value terminator (bare LHS; non-failable result) + ov := sm_parse(0) or 55; + print("or-value: {}\n", ov); + + // or-chain via helper (first ok wins; propagation absorbed by destructure) + g, gerr := sm_first(0, 8); + if !gerr { print("or-chain: {}\n", g); } + + // multi-value failable consumed by catch (tuple body) + p, q := sm_pair(0, 3) catch e (0, 0); + print("pair-catch: {} {}\n", p, q); + p2, q2 := sm_pair(4, 5) catch e (0, 0); + print("pair-ok: {} {}\n", p2, q2); + + // pure failable: absorb with no-binding catch + sm_check(false) catch { print("check absorbed\n"); }; + + // onfail/defer interleave on error vs success + print("acquire fail:\n"); + hv, herr := sm_acquire(true); + print("acquire ok:\n"); + iv, ierr := sm_acquire(false); + print("errors ok\n"); +} diff --git a/examples/1219-ffi-foreign.sx b/examples/1219-ffi-foreign.sx new file mode 100644 index 0000000..7430774 --- /dev/null +++ b/examples/1219-ffi-foreign.sx @@ -0,0 +1,23 @@ +#import "modules/std.sx"; +#import "modules/math/math.sx"; +#import "modules/compiler.sx"; +#import "modules/test.sx"; +pkg :: #import "modules/testpkg"; + +// --- Foreign function binding --- +libc :: #library "c"; + +c_abs :: (n: s32) -> s32 #foreign libc "abs"; + +// --- Protocol declarations (Phase 1: static dispatch only) --- + +main :: () { + + // ======================================================== + // 15. FOREIGN FUNCTION BINDING + // ======================================================== + print("=== 15. Foreign ===\n"); + + // Symbol rename: c_abs maps to C's abs() + print("foreign-rename: {}\n", c_abs(xx -42)); +} diff --git a/examples/50-smoke.sx b/examples/50-smoke.sx deleted file mode 100644 index cf455ea..0000000 --- a/examples/50-smoke.sx +++ /dev/null @@ -1,3214 +0,0 @@ -#import "modules/std.sx"; -#import "modules/math/math.sx"; -#import "modules/compiler.sx"; -#import "modules/test.sx"; -pkg :: #import "modules/testpkg"; - -// ============================================================ -// Comprehensive Smoke Test — exercises every spec feature -// ============================================================ - -// --- Top-level type declarations --- - -Point :: struct { x, y: s32; } - -Color :: enum { red; green; blue; } - -Shape :: enum { - circle: f32; - rect: struct { w, h: f32; }; - none; -} - -Overlay :: union { - f: f32; - i: s32; -} - -Vec2 :: union { - data: [2]f32; - struct { x, y: f32; }; -} - -Defaults :: struct { - a: s32; - b: s32 = 99; - c: s32 = ---; -} - -OptNode :: struct { - value: s32; - next: ?s32; -} - -OptInner :: struct { val: s32; } -OptOuter :: struct { inner: ?OptInner; } - -MyFloat :: f64; - -Perms :: enum flags { read; write; execute; } - -Status :: enum u8 { ok; err; timeout; } - -WindowFlags :: enum flags u32 { vsync :: 64; resizable :: 4; hidden :: 128; } - -// --- Top-level functions --- - -add :: (a: s32, b: s32) -> s32 { a + b; } -mul :: (a: s32, b: s32) -> s32 { a * b; } - -identity :: (x: $T) -> T { x; } - -pair_add :: (a: $T, b: $U) -> s64 { - cast(s64) a + cast(s64) b; -} - -typed_sum :: (..args: []s32) -> s32 { - result := 0; - for args: (it) { result = result + it; } - result; -} - -apply :: (f: (s32, s32) -> s32, x: s32, y: s32) -> s32 { - f(x, y); -} - -void_return :: () { - return; -} - -implicit_return :: (x: s32) -> s32 { - x * 2; -} - -early_return :: (x: s32) -> s32 { - if x > 10 { return 99; } - x; -} - -vec3 :: (x: f32, y: f32, z: f32) -> Vector(3, f32) { - .[x, y, z]; -} - -point_sum :: (p: Point) -> s32 { p.x + p.y; } - -// #run compile-time constants -CT_VAL :: #run add(10, 15); -CT_MUL :: #run mul(6, 7); -CT_CHAIN :: #run add(CT_VAL, 5); - -// #run compile-time optional tests -ct_opt_coalesce :: () -> s32 { - x: ?s32 = 42; - y: ?s32 = null; - return (x ?? 0) + (y ?? 99); -} -ct_opt_unwrap :: () -> s32 { - x: ?s32 = 77; - return x!; -} -ct_opt_guard :: () -> s32 { - x: ?s32 = 10; - if x == null { return -1; } - return x; -} -CT_OPT_COALESCE :: #run ct_opt_coalesce(); -CT_OPT_UNWRAP :: #run ct_opt_unwrap(); -CT_OPT_GUARD :: #run ct_opt_guard(); - -// #insert helpers -gen_code :: () -> string { - return "print(\"insert-ok\\n\");"; -} -gen_val :: () -> string { - return "print(\"insert-gen: {}\\n\", 42);"; -} - -// --- Foreign function binding --- -libc :: #library "c"; -c_abs :: (n: s32) -> s32 #foreign libc "abs"; - -// --- Protocol declarations (Phase 1: static dispatch only) --- - -Counter :: protocol { - inc :: (); - get :: () -> s32; -} - -Summable :: protocol { - sum :: () -> s32; -} - -SimpleCounter :: struct { val: s32; } - -impl Counter for SimpleCounter { - inc :: (self: *SimpleCounter) { self.val += 1; } - get :: (self: *SimpleCounter) -> s32 { self.val; } -} - -impl Summable for Point { - sum :: (self: *Point) -> s32 { self.x + self.y; } -} - -// Phase 2: #inline protocol for dynamic dispatch -Adder :: protocol #inline { - add :: (n: s32); - value :: () -> s32; -} - -Accumulator :: struct { - total: s32; -} - -impl Adder for Accumulator { - add :: (self: *Accumulator, n: s32) { self.total += n; } - value :: (self: *Accumulator) -> s32 { self.total; } -} - -Doubler :: struct { val: s32; } - -impl Adder for Doubler { - add :: (self: *Doubler, n: s32) { self.val = self.val + n + n; } - value :: (self: *Doubler) -> s32 { self.val; } -} - -// Phase 4: default methods -Repeater :: protocol { - say :: (msg: string); - say_twice :: (msg: string) { - self.say(msg); - self.say(msg); - } -} - -Printer :: struct { count: s32; } - -impl Repeater for Printer { - say :: (self: *Printer, msg: string) { - self.count += 1; - out(msg); - } -} - -// P4 edge: Chained default→default calls -Chained :: protocol { - base :: (msg: string) -> s32; - wrap :: (msg: string) -> s32 { - self.base(msg) + 1; - } - double_wrap :: (msg: string) -> s32 { - self.wrap(msg) + self.wrap(msg); - } -} - -ChainImpl :: struct { val: s32; } -impl Chained for ChainImpl { - base :: (self: *ChainImpl, msg: string) -> s32 { - self.val += 1; - msg.len; - } -} - -// Phase 5: Self type -Eq :: protocol { - eq :: (other: Self) -> bool; -} - -impl Eq for Point { - eq :: (self: *Point, other: Point) -> bool { - self.x == other.x and self.y == other.y; - } -} - -Cloneable :: protocol { - clone :: () -> Self; -} - -impl Cloneable for Point { - clone :: (self: *Point) -> Point { - Point.{ x = self.x, y = self.y }; - } -} - -impl Eq for s64 { - eq :: (self: *s64, other: s64) -> bool { - self.* == other; - } -} - -// Phase 6: Generic constraints -are_equal :: ($T: Type/Eq, a: T, b: T) -> bool { - a.eq(b); -} - -Hashable :: protocol { - hash :: () -> s64; -} - -impl Hashable for Point { - hash :: (self: *Point) -> s64 { - xx self.x * 31 + xx self.y; - } -} - -eq_and_hash :: ($T: Type/Eq/Hashable, a: T, b: T) -> bool { - if a.hash() != b.hash() { return false; } - a.eq(b); -} - -// P6.4: inline constraint syntax ($T/Protocol) -sum_of_inline :: (a: $T/Summable, b: T) -> s32 { - a.sum() + b.sum(); -} - -// Phase 7: Generic struct impls -Pair :: struct ($T: Type) { - a: T; - b: T; -} - -impl Summable for Pair($T) { - sum :: (self: *Pair(T)) -> s32 { - xx self.a + xx self.b; - } -} - -// P6.5: Struct type param constraints -SumBox :: struct ($T: Type/Summable) { - val: T; -} - -// ============================================================ -// Struct constants test -Phys :: struct { - x, y: f32; - GRAVITY :f32: 9.81; - MAX_SPEED :: 100; -} - -// Init block test struct -Builder :: struct { - total: s32; - count: s32; - - add :: (self: *Builder, val: s32) { - self.total += val; - self.count += 1; - } -} - -// Global variable for address-of test -g_smoke_val : s32 = 42; - -write_to_ptr :: (p: *s32) { - p.* = 99; -} - -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 : s32 = ---; - 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 : *s32 = 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); - - // ======================================================== - // 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 : s64 = wu; - print("widen-u8-s64: {}\n", ws); - - wi3 : s32 = 42; - wf : f64 = wi3; - print("widen-s32-f64: {}\n", wf); - - wf32 : f32 = 1.5; - wf64 : f64 = wf32; - print("widen-f32-f64: {}\n", wf64); - - wu2 : u8 = 100; - ws2 : s16 = wu2; - print("widen-u8-s16: {}\n", ws2); - - // More xx narrowing - xl : s64 = 12345; - xs : s32 = xx xl; - print("xx-s64-s32: {}\n", xs); - - xd : f64 = 1.5; - xf : f32 = xx xd; - print("xx-f64-f32: {}\n", xf); - - xdf : f64 = 7.9; - xdi : s32 = xx xdf; - print("xx-f64-s32: {}\n", xdi); - - // ======================================================== - // 3. TYPE SYSTEM - // ======================================================== - print("=== 3. Types ===\n"); - - // Primitive types - v_s8 : s8 = 127; - v_s16 : s16 = 32000; - v_s32 : s32 = 100000; - v_u8 : u8 = 255; - v_u16 : u16 = 65000; - v_u32 : u32 = 4000000; - print("s8: {}\n", v_s8); - print("s16: {}\n", v_s16); - print("s32: {}\n", v_s32); - print("u8: {}\n", v_u8); - print("u16: {}\n", v_u16); - print("u32: {}\n", v_u32); - - // Type alias - mf : MyFloat = 1.5; - print("alias: {}\n", mf); - - // --- Structs --- - // Positional literal - p1 : Point = .{ 1, 2 }; - print("struct-pos: {}\n", p1); - - // Type-prefix literal - p2 := Point.{ 3, 4 }; - print("struct-prefix: {}\n", p2); - - // Named fields - p3 := Point.{ y=10, x=20 }; - print("struct-named: {}\n", p3); - - // Shorthand (variable name = field name) - x : s32 = 5; - y : s32 = 6; - p4 := Point.{ x, y }; - print("struct-shorthand: {}\n", p4); - - // Field defaults - d1 : Defaults; - print("defaults: a={} b={}\n", d1.a, d1.b); - - // Field access and assignment - p5 := Point.{ 0, 0 }; - p5.x = 42; - p5.y = 99; - print("field-assign: {}\n", p5); - - // --- Enum (payload-less) --- - ec : Color = .red; - print("enum: {}\n", ec); - - // Enum comparison - ce1 : Color = .red; - ce2 : Color = .red; - ce3 : Color = .blue; - print("enum-eq: {}\n", ce1 == ce2); - print("enum-neq: {}\n", ce1 != ce3); - - // Backing type - st : Status = .err; - print("backing: {}\n", st); - - // --- Enum (tagged union) --- - sh : Shape = .circle(3.14); - print("tagged: {}\n", sh); - - // Payload access - radius := sh.circle; - print("payload: {}\n", radius); - - // Void variant - sh = .none; - print("void-variant: {}\n", sh); - - // Variant reassignment - sh = .circle(1.0); - print("reassign: {}\n", sh); - sh = .rect(.{ 5, 3 }); - print("reassign2: {}\n", sh); - - // Type-prefix construction - tp := Shape.circle(2.5); - print("enum-prefix: {}\n", tp); - - // Pattern matching - sh2 : Shape = .rect(.{ 5, 3 }); - if sh2 == { - case .circle: print("match: circle\n"); - case .rect: print("match: rect\n"); - case .none: print("match: none\n"); - } - - // Match as expression - sh3 : Shape = .circle(1.0); - ms := if sh3 == { - case .circle: 10; - case .rect: 20; - case .none: 30; - } - print("match-expr: {}\n", ms); - - // Match expression with else - me_val := 42; - me_res := if me_val == { - case 1: 10; - case 2: 20; - else: 99; - } - print("match-expr-else: {}\n", me_res); - - // Payload capture (block form) - sh4 : Shape = .circle(9.5); - if sh4 == { - case .circle: (r) { print("capture: {}\n", r); } - case .rect: (sz) { print("capture: {}\n", sz); } - case .none: print("capture: none\n"); - } - - // Payload capture (arrow form) - sh_ca : Shape = .circle(7.5); - if sh_ca == { - case .circle: (r) => print("capture-arrow: {}\n", r); - case .rect: (sz) => print("capture-arrow: rect\n"); - case .none: print("capture-arrow: none\n"); - } - - // else arm in match - num := 42; - if num == { - case 1: print("else-match: one\n"); - case 2: print("else-match: two\n"); - else: print("else-match: other\n"); - } - - // Integer pattern matching - code := 2; - if code == { - case 1: print("int-match: one\n"); - case 2: print("int-match: two\n"); - case 3: print("int-match: three\n"); - } - - // Integer match with else - im_code := 99; - if im_code == { - case 1: print("int-match-else: one\n"); - case 2: print("int-match-else: two\n"); - else: print("int-match-else: unknown\n"); - } - - // Bool pattern matching - bm := true; - if bm == { - case true: print("bool-match-t: yes\n"); - case false: print("bool-match-t: no\n"); - } - bm2 := false; - if bm2 == { - case true: print("bool-match-f: yes\n"); - case false: print("bool-match-f: no\n"); - } - - // Bool conditional - flag := true; - if flag { print("bool: true\n"); } - - // --- Union (untagged) --- - o : Overlay = ---; - o.f = 3.14; - print("union-f: {}\n", o.f); - // Type punning — read same bits as s32 - print("union-i: {}\n", o.i); - - // Union member promotion - uv : Vec2 = ---; - uv.x = 1.0; - uv.y = 2.0; - print("promoted-x: {}\n", uv.x); - print("promoted-data0: {}\n", uv.data[0]); - - // --- Arrays --- - arr : [5]s32 = .[10, 20, 30, 40, 50]; - print("arr[2]: {}\n", arr[2]); - print("arr.len: {}\n", arr.len); - - // Array element assignment - aa : [3]s32 = .[1, 2, 3]; - aa[1] = 99; - print("arr-assign: {}\n", aa); - - // --- Slices --- - sl : []s32 = .[1, 2, 3, 4, 5]; - print("sl[0]: {}\n", sl[0]); - print("sl.len: {}\n", sl.len); - - // Slice element write - sla : []s32 = .[10, 20, 30]; - sla[1] = 55; - print("sl-assign: {}\n", sla); - - // Subslicing - sub := arr[1..4]; - print("sub: {}\n", sub); - head := arr[..3]; - print("head: {}\n", head); - tail := arr[2..]; - print("tail: {}\n", tail); - - // Slice of slice - sos : []s32 = .[10, 20, 30, 40, 50]; - mid := sos[1..4]; - inner := mid[0..2]; - print("slice-of-slice: {}\n", inner); - - // String subslicing - msg := "hello world"; - print("strsub: {}\n", msg[6..11]); - print("str-prefix: {}\n", msg[..5]); - print("str-suffix: {}\n", msg[6..]); - - // --- Pointers --- - // Address-of global variable - write_to_ptr(@g_smoke_val); - print("global-addr-of: {}\n", g_smoke_val); - - pv := Point.{ 10, 20 }; - ptr := @pv; - print("deref: {}\n", ptr.*); - - // Auto-deref - print("auto-deref: {}\n", ptr.x); - - // Many-pointer - mp : [*]s32 = @arr[0]; - print("mp[0]: {}\n", mp[0]); - print("mp[3]: {}\n", mp[3]); - - // Many-pointer write - mpw : [5]s32 = .[10, 20, 30, 40, 50]; - mpw_ptr : [*]s32 = @mpw[0]; - mpw_ptr[2] = 99; - print("mp-write: {}\n", mpw[2]); - - // Pointer-null comparison - np : *s32 = null; - print("ptr==null: {}\n", np == null); - print("ptr!=null: {}\n", np != null); - np2 := @pv.x; - print("ptr2==null: {}\n", np2 == null); - print("ptr2!=null: {}\n", np2 != null); - - // Pointer to nested struct field - Inner3 :: struct { a: f32; b: f32; c: f32; } - Outer3 :: struct { key: s32; inner: Inner3; } - out3 := Outer3.{ key = 42, inner = Inner3.{ a = 1.0, b = 2.0, c = 3.0 } }; - ip3 := @out3.inner; - print("ptr-nested-field: {} {} {}\n", ip3.a, ip3.b, ip3.c); - - // Store to many-pointer field must not corrupt adjacent memory - MpHolder :: struct { items: [*]s64; sentinel: s64; } - mph := MpHolder.{ items = xx 0, sentinel = 42 }; - mph.items = xx 0; - print("mp-store-sentinel: {}\n", mph.sentinel); - - // --- Vectors --- - vc := vec3(1, 3, 2); - print("vec-construct: {}\n", vc); - - va := vec3(1, 2, 3); - vb := vec3(4, 5, 6); - print("vec-add: {}\n", va + vb); - print("vec-sub: {}\n", vec3(5, 5, 5) - vec3(1, 2, 3)); - print("vec-mul: {}\n", vec3(2, 3, 4) * vec3(1, 2, 3)); - print("vec-div: {}\n", vec3(10, 9, 8) / vec3(2, 3, 4)); - - print("vec-scalar: {}\n", vec3(1, 3, 2) * 2.0); - print("vec-neg: {}\n", -vec3(1, 3, 2)); - - ve := vec3(10, 20, 30); - print("vec-x: {}\n", ve.x); - print("vec-y: {}\n", ve.y); - print("vec-z: {}\n", ve.z); - print("vec-idx: {}\n", ve[1]); - - // ======================================================== - // 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]s32 = .[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: (_, ix) { - out(" "); - out(int_to_string(ix)); - } - out("\n"); - - // For with print two args - out("for-2arg:"); - for farr: (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 : []s32 = .[10, 20, 30]; - out("for-slice:"); - for fsl: (it) { - print(" {}", it); - } - out("\n"); - - // For on slice with index - out("for-slice-idx:"); - for fsl: (it, ix) { - print(" {}:{}", ix, it); - } - out("\n"); - - // Nested for - nf_a : [2]s32 = .[0, 1]; - nf_b : [2]s32 = .[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]s32 = .[10, 20, 30, 40, 50]; - fbi_idx := 0; - for fbi: (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); - - // ======================================================== - // 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 : s32; - 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-s32: {}\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: s32) => 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: s32, b: s32) -> s32 { 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]s32 = .[10, 20, 30]; - print("spread: {}\n", typed_sum(..spread_arr)); - - // Function pointers - fp : (s32, s32) -> s32 = add; - print("fp: {}\n", fp(3, 4)); - fp = mul; - print("fp-reassign: {}\n", fp(3, 4)); - print("fp-apply: {}\n", apply(add, 10, 20)); - - // ======================================================== - // 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"); - } - - // ======================================================== - // 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-s32: {}\n", size_of(s32)); - 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-s32: {}\n", align_of(s32)); - print("alignof-s64: {}\n", align_of(s64)); - 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(s32) cval); - cv2 : s32 = 42; - print("cast-int-f64: {}\n", cast(f64) cv2); - - // ======================================================== - // 8. COMPILE-TIME - // ======================================================== - print("=== 8. Comptime ===\n"); - - // #run constant - print("run-const: {}\n", CT_VAL); - - // #run with expression - print("run-expr: {}\n", CT_MUL); - - // #run chained dependency - print("run-chain: {}\n", CT_CHAIN); - - // #run comptime optionals - print("ct-opt-coalesce: {}\n", CT_OPT_COALESCE); // ct-opt-coalesce: 141 - print("ct-opt-unwrap: {}\n", CT_OPT_UNWRAP); // ct-opt-unwrap: 77 - print("ct-opt-guard: {}\n", CT_OPT_GUARD); // ct-opt-guard: 10 - - // #insert with function - #insert gen_code(); - - // #insert additional - #insert gen_val(); - - // ======================================================== - // 9. FLAGS - // ======================================================== - print("=== 9. Flags ===\n"); - - // Combine flags - perm : Perms = .read | .write; - print("flags: {}\n", perm); - - // Test flag - if perm & .read { print("has-read: yes\n"); } - if perm & .execute { print("has-exec: yes\n"); } - - // Test flag negative - pt : Perms = .write; - if pt & .read { - print("flags-neg: has-read\n"); - } else { - print("flags-neg: no-read\n"); - } - - // Single flag - ps : Perms = .execute; - print("flags-single: {}\n", ps); - - // All flags - pall : Perms = .read | .write | .execute; - print("flags-all: {}\n", pall); - - // Cast to int - print("flags-raw: {}\n", cast(s64) perm); - - // Flags with explicit values - wf : WindowFlags = .vsync | .resizable; - print("flags-explicit: {}\n", wf); - print("flags-explicit-raw: {}\n", cast(s64) wf); - - // --- Multi-target assignment (swap) --- - print("--- swap ---\n"); - - // Variable swap - { - sa := 10; - sb := 20; - sa, sb = sb, sa; - print("var swap: {} {}\n", sa, sb); - } - - // Array element swap - { - sarr : [3]s64 = .[1, 2, 3]; - sarr[0], sarr[2] = sarr[2], sarr[0]; - print("arr swap: {} {}\n", sarr[0], sarr[2]); - } - - // 3-way rotation - { - ra := 1; - rb := 2; - rc := 3; - ra, rb, rc = rc, ra, rb; - print("3-way: {} {} {}\n", ra, rb, rc); - } - - // --- Tuple destructuring --- - print("--- destructure ---\n"); - - // Basic tuple destructuring - { - da, db := (10, 20); - print("basic: {} {}\n", da, db); - } - - // Destructure from function return - { - dswap :: (a: s64, b: s64) -> (s64, s64) { (b, a); } - dx, dy := dswap(1, 2); - print("fn: {} {}\n", dx, dy); - } - - // Discard with _ - { - _, dsecond := (100, 200); - print("discard: {}\n", dsecond); - } - - // Three elements - { - da3, db3, dc3 := (1, 2, 3); - print("triple: {} {} {}\n", da3, db3, dc3); - } - - // ======================================================== - // 15. FOREIGN FUNCTION BINDING - // ======================================================== - print("=== 15. Foreign ===\n"); - - // Symbol rename: c_abs maps to C's abs() - print("foreign-rename: {}\n", c_abs(xx -42)); - - // ======================================================== - // 16. COMPOUND ASSIGNMENT TYPE CONVERSION - // ======================================================== - print("=== 16. Compound Assign ===\n"); - { - ca_a : f64 = 10.0; - ca_b : f32 = 3.0; - ca_a += ca_b; - print("f64+=f32: {}\n", ca_a); - - ca_c : s64 = 100; - ca_d : s32 = 7; - ca_c -= ca_d; - print("s64-=s32: {}\n", ca_c); - } - - // ======================================================== - // 17. SLICE/ARRAY .ptr ACCESS - // ======================================================== - print("=== 17. Slice Ptr ===\n"); - { - sarr : [5]s32 = .[10, 20, 30, 40, 50]; - ssl := sarr[1..4]; - sp := ssl.ptr; - print("sl-ptr[0]: {}\n", sp[0]); - print("sl-ptr[1]: {}\n", sp[1]); - } - - // ======================================================== - // 18. ARRAYS OF USER-DEFINED TYPES - // ======================================================== - print("=== 18. Array of Structs ===\n"); - { - spts : [2]Point = .[Point.{1, 2}, Point.{3, 4}]; - spt2 := spts[1]; - print("arr-struct-x: {}\n", spt2.x); - for spts: (it) { - print("for-struct: {}\n", it); - } - } - - // ======================================================== - // 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); - } - - // ======================================================== - // 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()); - } - - // ======================================================== - // 21. TYPE-NAMED VARIABLES (s2, u8, etc.) - // ======================================================== - print("=== 21. Type-Named Vars ===\n"); - { - s2 := 42; - print("s2: {}\n", s2); - s2 = s2 + 1; - print("s2+1: {}\n", s2); - } - - // ======================================================== - // 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. NESTED ARRAYS (2D) - // ======================================================== - print("=== 23. Nested Arrays ===\n"); - { - matrix : [2][3]s32 = .[ .[1, 2, 3], .[4, 5, 6] ]; - print("m[0][0]: {}\n", matrix[0][0]); - print("m[0][2]: {}\n", matrix[0][2]); - print("m[1][0]: {}\n", matrix[1][0]); - print("m[1][2]: {}\n", matrix[1][2]); - } - - // ======================================================== - // 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 == ""); - } - - // ======================================================== - // 25. ARRAY LOOP MUTATION - // ======================================================== - print("=== 25. Array Loop Mutation ===\n"); - { - arr : [4]s32 = .[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]); - } - - // === 26. #using struct composition === - print("=== 26. #using ===\n"); - { - UBase :: struct { x: s32; y: s32; } - UExt :: struct { #using UBase; z: s32; } - e := UExt.{ x = 1, y = 2, z = 3 }; - print("using-x: {}\n", e.x); - print("using-y: {}\n", e.y); - print("using-z: {}\n", e.z); - - // #using in middle position - UHeader :: struct { version: s32; } - UPacket :: struct { id: s32; #using UHeader; payload: s32; } - p := UPacket.{ id = 10, version = 42, payload = 99 }; - print("pkt-id: {}\n", p.id); - print("pkt-ver: {}\n", p.version); - print("pkt-pay: {}\n", p.payload); - - // Multiple #using - UPos :: struct { px: s32; py: s32; } - UCol :: struct { r: s32; g: s32; } - USprite :: struct { #using UPos; #using UCol; scale: s32; } - s := USprite.{ px = 10, py = 20, r = 255, g = 128, scale = 1 }; - print("sprite-px: {}\n", s.px); - print("sprite-r: {}\n", s.r); - print("sprite-scale: {}\n", s.scale); - } - - // --- Comptime format --- - { - ct_body :: "hello"; - ct_msg :: format("say: {} (len={})", ct_body, ct_body.len); - print("{}\n", ct_msg); - - ct_num :: 42; - ct_num_msg :: format("n={}", ct_num); - print("{}\n", ct_num_msg); - } - - // --- Tuples --- - { - print("=== Tuples ===\n"); - pair := (40, 2); - print("{}\n", pair.0); - print("{}\n", pair.1); - - named := (x: 10, y: 20); - print("{}\n", named.x); - print("{}\n", named.0); - - single := (42,); - print("{}\n", single.0); - - zeroed : (s32, s32) = ---; - print("{}\n", zeroed.0); - print("{}\n", zeroed.1); - } - - // --- UFCS Aliases & Pipe --- - { - print("=== UFCS Aliases ===\n"); - - num_sum :: (a: s64, b: s64) -> s64 { 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: s64, b: s64, c: s64, d: s64) -> s64 { 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: s64, b: s64) -> (s64, s64) { (b, a); } - s := swap(1, 2); - a := s.0; - b := s.1; - print("{}\n", a); // 2 - print("{}\n", b); // 1 - - wrap :: (x: s64) -> (s64) { (x,); } - t := wrap(99); - print("{}\n", t.0); // 99 - } - - // --- Tuple Operators --- - { - print("=== Tuple Operators ===\n"); - - // Equality - print("{}\n", (1, 2) == (1, 2)); // true - print("{}\n", (1, 2) == (1, 3)); // false - print("{}\n", (1, 2) != (1, 3)); // true - print("{}\n", (1, 2) != (1, 2)); // false - - // Concatenation - c := (1, 2) + (3, 4); - print("{}\n", c.0); // 1 - print("{}\n", c.1); // 2 - print("{}\n", c.2); // 3 - print("{}\n", c.3); // 4 - - // Repetition - r := (1, 2) * 3; - print("{}\n", r.0); // 1 - print("{}\n", r.1); // 2 - print("{}\n", r.2); // 1 - print("{}\n", r.3); // 2 - print("{}\n", r.4); // 1 - print("{}\n", r.5); // 2 - - // Lexicographic comparison - print("{}\n", (1, 2) < (1, 3)); // true - print("{}\n", (1, 3) < (1, 2)); // false - print("{}\n", (1, 2) < (1, 2)); // false - print("{}\n", (1, 2) <= (1, 2)); // true - print("{}\n", (2, 0) > (1, 9)); // true - print("{}\n", (1, 2) >= (1, 2)); // true - - // Membership - print("{}\n", 2 in (1, 2, 3)); // true - print("{}\n", 5 in (1, 2, 3)); // false - } - - // --- Directory imports --- - { - print("--- directory imports ---\n"); - print("{}\n", pkg.add(3, 4)); // 7 - print("{}\n", pkg.mul(5, 6)); // 30 - print("{}\n", pkg.hello()); // hello from testpkg - print("{}\n", pkg.cwd_greet()); // cwd-import-ok - } - - // --- Pipe operator --- - { - print("--- pipe operator ---\n"); - // Basic: a |> f(b) → f(a, b) - print("{}\n", 3 |> pkg.add(4)); // 7 - print("{}\n", 5 |> pkg.mul(6)); // 30 - - // Chaining: a |> f(b) |> g(c) → g(f(a, b), c) - print("{}\n", 3 |> pkg.add(4) |> pkg.mul(2)); // 14 - - // With non-namespaced functions - print("{}\n", "hello" |> concat(" world")); // hello world - - // Chained string ops - print("{}\n", "piped" |> concat(" ok") |> concat("!")); // piped ok! - } - - // ── alloc_slice ────────────────────────────────────────── - { - items := alloc_slice(s64, 5); - items[0] = 10; - items[1] = 20; - items[2] = 30; - items[3] = 40; - items[4] = 50; - print("alloc len: {}\n", items.len); // alloc len: 5 - print("alloc[0]: {}\n", items[0]); // alloc[0]: 10 - print("alloc[4]: {}\n", items[4]); // alloc[4]: 50 - - // alloc_slice with u8 - bytes := alloc_slice(u8, 3); - bytes[0] = 65; - bytes[1] = 66; - bytes[2] = 67; - print("bytes len: {}\n", bytes.len); // bytes len: 3 - } - - // ======================================================== - // ALLOCATORS - // ======================================================== - print("--- allocators ---\n"); - - // ── GPA ───────────────────────────────────────────────── - { - gpa := GPA.init(); - a : Allocator = xx gpa; - p1 := a.alloc(64); - p2 := a.alloc(128); - print("gpa allocs: {}\n", gpa.alloc_count); // gpa allocs: 2 - a.dealloc(p1); - a.dealloc(p2); - print("gpa final: {}\n", gpa.alloc_count); // gpa final: 0 - } - - // ── Arena backed by GPA (multi-chunk) ─────────────────── - { - gpa3 := GPA.init(); - arena := Arena.init(xx gpa3, 32); - a : Allocator = xx arena; - // First chunk fits 80 usable bytes - a1 := a.alloc(40); - a2 := a.alloc(40); - // Counts: just the first chunk = 1. Arena.init returns the - // state by value; the local IS the Arena struct, no parent - // allocation for the state itself. - print("arena chunks: {}\n", gpa3.alloc_count); // arena chunks: 1 - // Overflow → new chunk - a3 := a.alloc(16); - print("arena overflow: {}\n", gpa3.alloc_count); // arena overflow: 2 - // Verify memory works across chunks - p1 : [*]u8 = xx a1; - p3 : [*]u8 = xx a3; - p1[0] = 42; - p3[0] = 99; - print("arena a1: {}\n", p1[0]); // arena a1: 42 - print("arena a3: {}\n", p3[0]); // arena a3: 99 - // Reset retains the first chunk - arena.reset(); - print("arena reset idx: {}\n", arena.end_index); // arena reset idx: 0 - print("arena reset gpa: {}\n", gpa3.alloc_count); // arena reset gpa: 1 - // Deinit frees all chunks (caller's local is the state — no - // dealloc of the struct itself). - arena.deinit(); - print("arena deinit: {}\n", gpa3.alloc_count); // arena deinit: 0 - } - - // ── BufAlloc from stack array ─────────────────────────── - { - stack_buf : [128]u8 = ---; - buf := BufAlloc.init(@stack_buf[0], 128); - a : Allocator = xx buf; - b1 := a.alloc(24); - b2 := a.alloc(24); - print("buf pos: {}\n", buf.pos); // buf pos: 48 - b3 := a.alloc(200); - b3_i : s64 = xx b3; - print("buf overflow: {}\n", b3_i); // buf overflow: 0 - buf.reset(); - print("buf reset: {}\n", buf.pos); // buf reset: 0 - } - - { - if 1 == (1,) { - print("1 == (1)\n"); - } - - if (1,) == (1) { - print("(1) == 1\n"); - } - - if (1,) == 1 { - print("1 == 1\n"); - } - } - - // ======================================================== - // OPTIONALS - // ======================================================== - print("--- optionals ---\n"); - - // Basic optional creation and null - { - x: ?s32 = 42; - y: ?s32 = null; - print("opt x: {}\n", x); // opt x: 42 - print("opt y: {}\n", y); // opt y: null - } - - // Force unwrap - { - x: ?s32 = 10; - val := x!; - print("unwrap: {}\n", val); // unwrap: 10 - } - - // Null coalescing - { - x: ?s32 = 42; - y: ?s32 = null; - a := x ?? 0; - b := y ?? 99; - print("coalesce a: {}\n", a); // coalesce a: 42 - print("coalesce b: {}\n", b); // coalesce b: 99 - - // Chained ?? (right-associative): a ?? b ?? c - z: ?s32 = null; - c := x ?? y ?? 0; - d := z ?? y ?? 99; - e := z ?? z ?? 0; - print("chained ?? c: {}\n", c); // chained ?? c: 42 - print("chained ?? d: {}\n", d); // chained ?? d: 99 - print("chained ?? e: {}\n", e); // chained ?? e: 0 - } - - // If-binding (safe unwrap) - { - x: ?s32 = 7; - y: ?s32 = null; - if val := x { - print("if-bind x: {}\n", val); // if-bind x: 7 - } - if val := y { - print("if-bind y: should not print\n"); - } else { - print("if-bind y: none\n"); // if-bind y: none - } - } - - // Pattern matching on optionals - { - check :: (v: ?s32) -> s32 { - return if v == { - case .some: (val) { val; } - case .none: { 0; } - }; - } - a: ?s32 = 55; - b: ?s32 = null; - print("match some: {}\n", check(a)); // match some: 55 - print("match none: {}\n", check(b)); // match none: 0 - } - - // Optional with implicit wrapping - { - opt_wrap :: (n: s32) -> ?s32 { - if n > 0 { - return n; - } - return null; - } - r1 := opt_wrap(5); - r2 := opt_wrap(0); - print("wrap pos: {}\n", r1); // wrap pos: 5 - print("wrap neg: {}\n", r2); // wrap neg: null - } - - // Struct field defaults for ?T - { - n := OptNode.{ value = 10 }; - print("opt field default: {}\n", n.next); // opt field default: null - m := OptNode.{ value = 20, next = 42 }; - print("opt field set: {}\n", m.next); // opt field set: 42 - } - - // ?T as function parameter - { - opt_process :: (val: ?s32) -> s32 { - return val ?? 0; - } - a: ?s32 = 42; - b: ?s32 = null; - print("opt param a: {}\n", opt_process(a)); // opt param a: 42 - print("opt param b: {}\n", opt_process(b)); // opt param b: 0 - print("opt param 7: {}\n", opt_process(7)); // opt param 7: 7 - } - - // Assignment to optional variable (f32 → ?f32) - { - iw: ?f32 = null; - w: f32 = 42.5; - iw = w; - print("opt reassign: {}\n", iw ?? 0.0); // opt reassign: 42.5 - - // Assignment of computed value to optional - iw2: ?f32 = null; - a: ?f32 = 10.0; - if v := a { iw2 = v + 5.0; } - print("opt compute assign: {}\n", iw2 ?? 0.0); // opt compute assign: 15.0 - - // Re-assign optional back to null - iw2 = null; - print("opt re-null: {}\n", iw2 ?? 99.0); // opt re-null: 99.0 - } - - // Generic function with ?T return - { - first_pos :: ($T: Type, a: T, b: T) -> ?T { - if a > 0 { return a; } - if b > 0 { return b; } - return null; - } - print("generic opt 1: {}\n", first_pos(s32, 5, 10)); // generic opt 1: 5 - print("generic opt 2: {}\n", first_pos(s32, 0, 7)); // generic opt 2: 7 - print("generic opt 3: {}\n", first_pos(s32, 0, 0)); // generic opt 3: null - } - - // Optional chaining (?.) - { - p: ?OptNode = OptNode.{ value = 10, next = 20 }; - q: ?OptNode = null; - print("chain some: {}\n", p?.value ?? 0); // chain some: 10 - print("chain none: {}\n", q?.value ?? 0); // chain none: 0 - print("chain print: {}\n", p?.next); // chain print: 20 - print("chain null: {}\n", q?.next); // chain null: null - - // Chained: obj.field?.field - o1 := OptOuter.{ inner = OptInner.{ val = 99 } }; - o2 := OptOuter.{ inner = null }; - print("deep chain 1: {}\n", o1.inner?.val ?? 0); // deep chain 1: 99 - print("deep chain 2: {}\n", o2.inner?.val ?? 0); // deep chain 2: 0 - } - - // Flow-sensitive narrowing - { - x: ?s32 = 42; - y: ?s32 = null; - - // if x != null → x is narrowed to s32 - if x != null { - print("narrow x: {}\n", x); // narrow x: 42 - } - - // if y != null → not entered - if y != null { - print("should not print\n"); - } else { - print("narrow y else: null\n"); // narrow y else: null - } - - // if x == null ... else → else-branch narrowed - if x == null { - print("should not print\n"); - } else { - print("narrow else x: {}\n", x); // narrow else x: 42 - } - } - - // Guard narrowing - { - guard_fn :: (v: ?s32) -> s32 { - if v == null { return 0; } - return v; - } - print("guard some: {}\n", guard_fn(42)); // guard some: 42 - print("guard none: {}\n", guard_fn(null)); // guard none: 0 - } - - // Compound narrowing: && chains - { - a: ?s32 = 10; - b: ?s32 = 20; - c: ?s32 = null; - if a != null and b != null { - print("and both: {} {}\n", a, b); // and both: 10 20 - } - if a != null and c != null { - print("should not print\n"); - } else { - print("and one null\n"); // and one null - } - } - - // Compound guard narrowing: || chains - { - guard2 :: (a: ?s32, b: ?s32) -> s32 { - if a == null or b == null { return 0; } - return a + b; - } - print("or guard: {}\n", guard2(3, 4)); // or guard: 7 - print("or guard null: {}\n", guard2(3, null)); // or guard null: 0 - } - - // Nested if narrowing - { - a: ?s32 = 10; - b: ?s32 = 20; - if a != null { - if b != null { - print("nested narrow: {} {}\n", a, b); // nested narrow: 10 20 - } - } - } - - // Guard narrowing used in loop - { - guard_loop :: (v: ?s32) -> s32 { - if v == null { return 0; } - sum := 0; - i := 0; - while i < v { - sum = sum + 1; - i = i + 1; - } - return sum; - } - print("guard loop: {}\n", guard_loop(3)); // guard loop: 3 - } - - // --- block-body lambdas --- - { - // block-body lambda with return type - clamp := (x: s64, lo: s64, hi: s64) -> s64 { - if x < lo { return lo; } - if x > hi { return hi; } - return x; - }; - print("block-lambda: {}\n", clamp(50, 0, 100)); // block-lambda: 50 - print("block-lambda: {}\n", clamp(-10, 0, 100)); // block-lambda: 0 - print("block-lambda: {}\n", clamp(999, 0, 100)); // block-lambda: 100 - - // block-body lambda without return type annotation - greet := (name: string) { - print("hello {}\n", name); - }; - greet("block"); // hello block - } - - // --- named params in function types --- - { - // Named params are documentation only — ignored for type identity - apply_named :: (f: (x: s32, y: s32) -> s32, a: s32, b: s32) -> s32 { - return f(a, b); - } - add :: (a: s32, b: s32) -> s32 { return a + b; } - print("named-fn-type: {}\n", apply_named(add, 3, 4)); // named-fn-type: 7 - } - - // --- xx on function pointers --- - { - MyEnv :: struct { n: s32; } - typed_fn :: (e: *MyEnv, x: s32) -> s32 { - return x + e.n; - } - // xx cast: (*MyEnv, s32) -> s32 → (*void, s32) -> s32 - f : (*void, s32) -> s32 = xx typed_fn; - env := MyEnv.{ n = 100 }; - print("xx-fnptr: {}\n", f(xx @env, 42)); // xx-fnptr: 142 - } - - // --- closure type: construct and access fields --- - { - dummy_fn :: (env: *void, x: s32) -> s32 { - return x * 2; - } - fn_ptr : *void = xx dummy_fn; - null_env : *void = xx 0; - c : Closure(s32) -> s32 = .{ fn_ptr = fn_ptr, env = null_env }; - print("closure-type: fn_ptr-nonnull={}\n", c.fn_ptr != null_env); - print("closure-type: env-null={}\n", c.env == null_env); - } - - // --- closure calling convention --- - { - Env :: struct { n: s32; } - impl_fn :: (env: *void, x: s32) -> s32 { - e : *Env = xx env; - return x + e.n; - } - env := Env.{ n = 5 }; - fn_ptr : *void = xx impl_fn; - env_ptr : *void = xx @env; - c : Closure(s32) -> s32 = .{ fn_ptr = fn_ptr, env = env_ptr }; - print("closure-call: {}\n", c(10)); - } - - // --- auto-promotion: bare fn → Closure --- - { - double :: (x: s32) -> s32 { return x * 2; } - apply :: (f: Closure(s32) -> s32, x: s32) -> s32 { return f(x); } - print("auto-promote: {}\n", apply(double, 10)); - - // Named function to Closure variable - f : Closure(s32) -> s32 = double; - print("auto-promote-var: {}\n", f(5)); - } - - // --- closure() intrinsic --- - { - // capture scalar - n := 42; - f := closure((x: s32) => x + n); - print("closure-capture: {}\n", f(10)); - - // capture by value is a snapshot - m := 5; - g := closure((x: s32) => x + m); - m = 100; - print("closure-snapshot: {}\n", g(10)); - - // no captures (null env) - h := closure((x: s32) => x * 2); - print("closure-nocap: {}\n", h(7)); - - // multiple captures - a := 10; - b := 20; - multi := closure((x: s32) => x + a + b); - print("closure-multi: {}\n", multi(3)); - - // block-body closure with return - offset := 50; - clamp := closure((x: s64) -> s64 { - if x < 0 { return 0; } - if x > 100 { return 100; } - return x + offset; - }); - r1 : s64 = clamp(10); - r2 : s64 = clamp(0 - 5); - r3 : s64 = clamp(999); - print("closure-block: {}\n", r1); - print("closure-block: {}\n", r2); - print("closure-block: {}\n", r3); - - // void closure - tag := "LOG"; - logger := closure((msg: string) { - print("[{}] {}\n", tag, msg); - }); - logger("hello"); - - // pass closure to higher-order function - dbl :: (x: s32) -> s32 { return x * 2; } - apply_cl :: (f2: Closure(s32) -> s32, x: s32) -> s32 { return f2(x); } - factor : s32 = 3; - print("closure-hof: {}\n", apply_cl(closure((x: s32) -> s32 => x * factor), 10)); - - // auto-promoted bare fn passed alongside closures - print("closure-hof-bare: {}\n", apply_cl(dbl, 10)); - - // C5.A2: capture f32 - scale := 2.5; - f_f32 := closure((x: f32) -> f32 => x * scale); - print("closure-f32: {}\n", f_f32(4.0)); - - // C5.A3: capture bool - verbose := true; - f_bool := closure((msg: string) { - if verbose { print("closure-bool: {}\n", msg); } - }); - f_bool("hello"); - - // C5.B3: two params - base : s32 = 100; - f_2p := closure((x: s32, y: s32) -> s32 => x + y + base); - print("closure-2p: {}\n", f_2p(3, 4)); - - // C5.B4: three params - bias : s32 = 1; - f_3p := closure((a: s32, b: s32, c2: s32) -> s32 => a + b + c2 + bias); - print("closure-3p: {}\n", f_3p(10, 20, 30)); - - // C5.B5: mixed param types (string + s32) - extra : s32 = 5; - f_mix := closure((name: string, age: s32) { - print("closure-mix: {} is {}\n", name, age + extra); - }); - f_mix("Alice", 30); - - // C5.C3: return bool - threshold : s32 = 100; - f_rbool := closure((x: s32) -> bool { return x > threshold; }); - print("closure-rbool: {} {}\n", f_rbool(50), f_rbool(200)); - - // C5.D3: reduce / fold - reduce :: (arr: []s32, f3: Closure(s32, s32) -> s32, init: s32) -> s32 { - acc := init; - i : s64 = 0; - while i < arr.len { acc = f3(acc, arr[i]); i += 1; } - return acc; - } - r_nums : []s32 = .[1, 2, 3, 4, 5]; - r_bonus : s32 = 100; - r_total := reduce(r_nums, closure((acc: s32, x: s32) -> s32 => acc + x), r_bonus); - print("closure-reduce: {}\n", r_total); - - // C5.G1: factory function - make_adder :: (n: s32) -> Closure(s32) -> s32 { - return closure((x: s32) -> s32 => x + n); - } - add5 := make_adder(5); - add10 := make_adder(10); - print("closure-factory: {} {}\n", add5(100), add10(100)); - - // C5.A5: capture struct - origin := Point.{ x = 10, y = 20 }; - f_st := closure(() { - print("closure-struct: {} {}\n", origin.x, origin.y); - }); - f_st(); - - // C5.H1: closure captures another closure - inner_n := 10; - inner_cl := closure((x: s64) -> s64 => x + inner_n); - outer_cl := closure((x: s64) -> s64 => inner_cl(x) * 2); - print("closure-compose: {}\n", outer_cl(5)); - - // C5.M7: multiple closures from same scope capture independently - shared : s32 = 10; - cl_a := closure((x: s32) -> s32 => x + shared); - cl_b := closure((x: s32) -> s32 => x * shared); - print("closure-indep: {} {}\n", cl_a(5), cl_b(5)); - - // C6: optional closures - f_none : ?Closure(s64) -> s64 = null; - if h := f_none { - print("should not print: {}\n", h(1)); - } else { - print("opt-closure: none\n"); - } - - opt_n := 10; - f_some : ?Closure(s64) -> s64 = closure((x: s64) -> s64 => x + opt_n); - if h := f_some { - print("opt-closure: {}\n", h(5)); - } else { - print("should not print\n"); - } - - // Struct with optional closure callback - Btn :: struct { label: string; on_click: ?Closure(s64) -> void; } - btn_x := 99; - btn_cl := closure((id: s64) { - print("opt-closure-btn: {} {}\n", id, btn_x); - }); - btn1 := Btn.{ label = "OK", on_click = btn_cl }; - btn2 := Btn.{ label = "Cancel", on_click = null }; - if h := btn1.on_click { h(1); } - if h := btn2.on_click { h(2); } else { print("opt-closure-btn: null\n"); } - - // C5.A6: capture pointer (shared mutable state) - count_a6 : s32 = 0; - p_a6 := @count_a6; - inc_fn := closure(() { p_a6.* += 1; }); - inc_fn(); inc_fn(); inc_fn(); - print("closure-ptr: {}\n", count_a6); - - // C5.A9: capture enum value (as s32 tag) - c_a9 : s32 = 2; // simulate enum tag - f_a9 := closure(() -> s32 => c_a9); - print("closure-enum: {}\n", f_a9()); - - // C5.C4: return string - tag_c4 := "INFO"; - f_c4 := closure((msg: string) -> string => format("[{}] {}", tag_c4, msg)); - print("closure-rstr: {}\n", f_c4("ok")); - - // C5.C5: return struct - off_c5 := Point.{ x = 10, y = 20 }; - f_c5 := closure((p: Point) -> Point => Point.{ x = p.x + off_c5.x, y = p.y + off_c5.y }); - res_c5 := f_c5(Point.{ x = 1, y = 2 }); - print("closure-rstruct: {} {}\n", res_c5.x, res_c5.y); - - // C5.G2: factory with multiple captures - make_linear :: (m: s32, b: s32) -> Closure(s32) -> s32 { - return closure((x: s32) -> s32 => m * x + b); - } - lin := make_linear(3, 7); - print("closure-linear: {}\n", lin(10)); - - // C5.G3: factory returning clamper - make_clamper :: (lo: s32, hi: s32) -> Closure(s32) -> s32 { - return closure((x: s32) -> s32 { - if x < lo { return lo; } - if x > hi { return hi; } - return x; - }); - } - clamp_fn := make_clamper(0, 255); - cv1 : s32 = xx -10; - cv2 : s32 = 100; - cv3 : s32 = 999; - print("closure-clamp: {} {} {}\n", clamp_fn(cv1), clamp_fn(cv2), clamp_fn(cv3)); - - // C5.H2: compose - compose :: (f_h2: Closure(s32) -> s32, g_h2: Closure(s32) -> s32) -> Closure(s32) -> s32 { - return closure((x: s32) -> s32 => f_h2(g_h2(x))); - } - one_h2 : s32 = 1; - two_h2 : s32 = 2; - add1_h2 := closure((x: s32) -> s32 => x + one_h2); - mul2_h2 := closure((x: s32) -> s32 => x * two_h2); - composed := compose(mul2_h2, add1_h2); - print("closure-compose2: {}\n", composed(5)); - - // C5.H3: chain of closures - ch_k1 : s32 = 1; - ch_k2 : s32 = 2; - ch_k10 : s32 = 10; - ch_a := closure((x: s32) -> s32 => x + ch_k1); - ch_b := closure((x: s32) -> s32 => ch_a(x) * ch_k2); - ch_c := closure((x: s32) -> s32 => ch_b(x) + ch_k10); - print("closure-chain: {}\n", ch_c(5)); - - // C5.D1: map - map_cl :: (arr: [*]s32, cnt: s64, f_map: Closure(s32) -> s32, result: [*]s32) { - i := 0; - while i < cnt { result[i] = f_map(arr[i]); i += 1; } - } - map_src : [5]s32 = .[1, 2, 3, 4, 5]; - map_dst : [5]s32 = .[0, 0, 0, 0, 0]; - factor_d1 : s32 = 3; - map_cl(xx @map_src, 5, closure((x: s32) -> s32 => x * factor_d1), xx @map_dst); - print("closure-map: {} {} {} {} {}\n", map_dst[0], map_dst[1], map_dst[2], map_dst[3], map_dst[4]); - - // C5.D2: filter - filter_cl :: (arr: [*]s32, cnt: s64, pred: Closure(s32) -> bool, result: [*]s32) -> s64 { - j := 0; - i := 0; - while i < cnt { - if pred(arr[i]) { result[j] = arr[i]; j += 1; } - i += 1; - } - return j; - } - min_val : s32 = 3; - filt_dst : [5]s32 = .[0, 0, 0, 0, 0]; - kept := filter_cl(xx @map_src, 5, closure((x: s32) -> bool => x >= min_val), xx @filt_dst); - print("closure-filter: {} [{} {} {}]\n", kept, filt_dst[0], filt_dst[1], filt_dst[2]); - - // C5.D4: sort comparator (bubble sort) - sort_cl :: (arr: [*]s32, cnt: s64, less: Closure(s32, s32) -> bool) { - i := 0; - while i < cnt { - j := 0; - while j < cnt - 1 - i { - if less(arr[j + 1], arr[j]) { - tmp := arr[j]; - arr[j] = arr[j + 1]; - arr[j + 1] = tmp; - } - j += 1; - } - i += 1; - } - } - sort_arr : [5]s32 = .[5, 3, 1, 4, 2]; - descending := true; - sort_cl(xx @sort_arr, 5, closure((a: s32, b: s32) -> bool { - if descending { return a > b; } - return a < b; - })); - print("closure-sort: {} {} {} {} {}\n", sort_arr[0], sort_arr[1], sort_arr[2], sort_arr[3], sort_arr[4]); - - // C5.D5: for_each with index - for_each_cl :: (arr: [*]s32, cnt: s64, f_fe: Closure(s32, s64) -> void) { - i : s64 = 0; - while i < cnt { f_fe(arr[i], i); i += 1; } - } - fe_label := "item"; - fe_arr : [3]s32 = .[10, 20, 30]; - for_each_cl(xx @fe_arr, 3, closure((val: s32, idx: s64) { - print("closure-fe: {} {}={}\n", fe_label, idx, val); - })); - - // C5.D6: find - find_cl :: (arr: [*]s32, cnt: s64, pred_f: Closure(s32) -> bool) -> s64 { - i : s64 = 0; - while i < cnt { - if pred_f(arr[i]) { return i; } - i += 1; - } - return -1; - } - target : s32 = 30; - found_idx := find_cl(xx @fe_arr, 3, closure((x: s32) -> bool => x == target)); - print("closure-find: {}\n", found_idx); - - // C5.D7: any - any_cl :: (arr: [*]s32, cnt: s64, pred_a: Closure(s32) -> bool) -> bool { - i : s64 = 0; - while i < cnt { - if pred_a(arr[i]) { return true; } - i += 1; - } - return false; - } - has_big := any_cl(xx @fe_arr, 3, closure((x: s32) -> bool => x > 100)); - has_20 := any_cl(xx @fe_arr, 3, closure((x: s32) -> bool => x == 20)); - print("closure-any: {} {}\n", has_big, has_20); - - // C5.E4: auto-promotion in struct field assignment - Widget :: struct { transform: Closure(s32) -> s32; } - negate_fn :: (x: s32) -> s32 { return 0 - x; } - w_e4 := Widget.{ transform = negate_fn }; - print("closure-struct-field: {}\n", w_e4.transform(5)); - - // C5.F1: single closure callback in struct - Button :: struct { - label: string; - on_press: Closure(s32) -> void; - } - btn_x2 := 99; - btn_cb := closure((id: s32) { - print("closure-btn: {} {}\n", id, btn_x2); - }); - btn3 := Button.{ label = "OK", on_press = btn_cb }; - btn3.on_press(1); - - // C5.J1: stateful counter via pointer capture - state_j1 : s32 = 0; - p_j1 := @state_j1; - inc_j1 := closure(() -> s32 { p_j1.* += 1; return p_j1.*; }); - print("closure-counter: {} {} {}\n", inc_j1(), inc_j1(), inc_j1()); - - // C5.J2: stateful accumulator - state_j2 : s32 = 100; - p_j2 := @state_j2; - acc_j2 := closure((x: s32) -> s32 { p_j2.* += x; return p_j2.*; }); - print("closure-acc: {} {}\n", acc_j2(5), acc_j2(10)); - - // C5.K2: block-body with local variables and loops - base_k2 : s32 = 100; - sum_fn := closure((items: [*]s32, cnt: s64) -> s32 { - total : s32 = 0; - i : s64 = 0; - while i < cnt { - total += items[i]; - i += 1; - } - return total + base_k2; - }); - k2_arr : [5]s32 = .[1, 2, 3, 4, 5]; - print("closure-loop: {}\n", sum_fn(xx @k2_arr, 5)); - - // C5.M3: reassigning a closure variable - n_m3 : s32 = 1; - f_m3 := closure((x: s32) -> s32 => x + n_m3); - print("closure-reassign: {}\n", f_m3(10)); - m_m3 : s32 = 2; - f_m3 = closure((x: s32) -> s32 => x * m_m3); - print("closure-reassign: {}\n", f_m3(10)); - - // C5.M6b: snapshot verified with struct capture - pt_m6 := Point.{ x = 5, y = 10 }; - f_m6 := closure(() -> s32 => pt_m6.x + pt_m6.y); - pt_m6 = Point.{ x = 99, y = 99 }; - print("closure-snapstruct: {}\n", f_m6()); - - // C5.M2: closure capturing auto-promoted closure - double_m2 :: (x: s32) -> s32 { return x * 2; } - base_m2 : Closure(s32) -> s32 = double_m2; - n_m2 : s32 = 1; - f_m2 := closure((x: s32) -> s32 => base_m2(x) + n_m2); - print("closure-cap-promoted: {}\n", f_m2(5)); - - // C5.M5: immediately invoked closure (via temp var) - n_m5 : s32 = 5; - iife := closure((x: s32) -> s32 => x + n_m5); - result_m5 := iife(10); - print("closure-iife: {}\n", result_m5); - - // C5.F2: optional callback (none) - Toggle :: struct { on_change: ?Closure(bool) -> void; } - t_f2 := Toggle.{ on_change = null }; - if h := t_f2.on_change { h(true); } else { print("closure-toggle: none\n"); } - - // C5.F3: optional callback (some) - t_f3_cb := closure((enabled: bool) { print("closure-toggle: {}\n", enabled); }); - t_f3 := Toggle.{ on_change = t_f3_cb }; - if h := t_f3.on_change { h(true); } - - // C5.F5: callback receiving caller context - Panel :: struct { - title: string; - on_resize: Closure(string, s32, s32) -> void; - } - p_f5_cb := closure((title: string, w: s32, h: s32) { - print("closure-panel: {} {}x{}\n", title, w, h); - }); - p_f5 := Panel.{ title = "main", on_resize = p_f5_cb }; - p_f5.on_resize(p_f5.title, 800, 600); - - // C5.E6: protocol value passed through multiple function calls - step3 :: (a: Allocator) -> *void { a.alloc(8); } - step2 :: (a: Allocator) -> *void { step3(a); } - step1 :: (a: Allocator) -> *void { step2(a); } - gpa_e6 := GPA.init(); - a_e6 : Allocator = xx gpa_e6; - ptr_e6 := step1(a_e6); - print("closure-chain-call: {}\n", ptr_e6 != null); - a_e6.dealloc(ptr_e6); - - // C5.I1: creating closures in a loop (each captures different value) - // TEMPORARILY DISABLED — closure-in-loop causes infinite loop (index_gep element size issue?) - // cl_arr : [5]Closure(s32) -> s32 = ---; - // i_loop := 0; - // while i_loop < 5 { - // val_loop : s32 = xx (i_loop * 10); - // cl_arr[i_loop] = closure((x: s32) -> s32 => x + val_loop); - // i_loop += 1; - // } - // I2: calling closures from array - // tmp_cl := cl_arr[0]; print("closure-loop-0: {}\n", tmp_cl(1)); - // tmp_cl = cl_arr[1]; print("closure-loop-1: {}\n", tmp_cl(1)); - // tmp_cl = cl_arr[4]; print("closure-loop-4: {}\n", tmp_cl(1)); - - // C5.M4: closure in conditional expression (via temp var) - use_fast := true; - k_fast : s32 = 2; - k_slow : s32 = 10; - f_fast := closure((x: s32) -> s32 => x * k_fast); - f_slow := closure((x: s32) -> s32 => x + k_slow); - f_cond : Closure(s32) -> s32 = if use_fast then f_fast else f_slow; - print("closure-cond: {}\n", f_cond(5)); - - // C5.F4: multiple callbacks on one struct - Form :: struct { - on_submit: ?Closure() -> void; - on_cancel: ?Closure() -> void; - } - msg_f4 := "submitted"; - sub_cb := closure(() { print("closure-form: {}\n", msg_f4); }); - form_f4 := Form.{ on_submit = sub_cb, on_cancel = null }; - if h := form_f4.on_submit { h(); } - if h := form_f4.on_cancel { h(); } else { print("closure-form: no cancel\n"); } - - // C5.L3: auto-promoted closure env is null (no free needed) - double_l3 :: (x: s32) -> s32 { return x * 2; } - f_l3 : Closure(s32) -> s32 = double_l3; - print("closure-null-env: {}\n", f_l3.env == null); - - // C5.A7: capture slice (fat pointer like string) - sl_a7 : [3]s32 = .[10, 20, 30]; - ptr_a7 : [*]s32 = xx @sl_a7; - f_a7 := closure((i: s64) -> s32 => ptr_a7[i]); - print("closure-slice: {} {} {}\n", f_a7(0), f_a7(1), f_a7(2)); - - // C5.L1: arena bulk free (closures allocated on arena, freed in bulk) - gpa_l1 := GPA.init(); - arena_l1 := Arena.init(xx gpa_l1, 4096); - push Context.{ allocator = xx arena_l1 } { - n_l1 : s32 = 5; - f_l1 := closure((x: s32) -> s32 => x + n_l1); - print("closure-arena: {}\n", f_l1(10)); - } - arena_l1.deinit(); - - // C5.L2: GPA manual free (verify env alloc/dealloc) - gpa_l2 := GPA.init(); - a_l2 : Allocator = xx gpa_l2; - n_l2 : s32 = 7; - result_l2 : s32 = 0; - push Context.{ allocator = a_l2 } { - f_l2 := closure((x: s32) -> s32 => x + n_l2); - result_l2 = f_l2(10); - a_l2.dealloc(f_l2.env); - } - print("closure-gpa: {} allocs={}\n", result_l2, gpa_l2.alloc_count); - - // C5.A10: capture optional - val_a10 : ?s32 = 42; - f_a10 := closure(() -> s32 { - if v := val_a10 { return v; } - return 0; - }); - print("closure-opt: {}\n", f_a10()); - - // C5.C6: return optional - limit_c6 : s32 = 100; - f_c6 := closure((x: s32) -> ?s32 { - if x > limit_c6 { return null; } - return x; - }); - r1_c6 := f_c6(50); - r2_c6 := f_c6(200); - if v := r1_c6 { print("closure-ropt: {}\n", v); } - if v := r2_c6 { print("should-not-print\n"); } else { print("closure-ropt: none\n"); } - - // C5.M8: array of closures with mixed origins - double_m8 :: (x: s32) -> s32 { return x * 2; } - n_m8 : s32 = 10; - fns_m8 : [3]Closure(s32) -> s32 = ---; - fns_m8[0] = double_m8; // auto-promoted - fns_m8[1] = closure((x: s32) -> s32 => x + n_m8); // captured - fns_m8[2] = closure((x: s32) -> s32 => x * x); // no capture - tmp_m8 := fns_m8[0]; print("closure-mixed: {}\n", tmp_m8(5)); - tmp_m8 = fns_m8[1]; print("closure-mixed: {}\n", tmp_m8(5)); - tmp_m8 = fns_m8[2]; print("closure-mixed: {}\n", tmp_m8(5)); - - // C5.E1: independent closures from same factory (each has own env) - mk_e1 :: (n: s32) -> Closure(s32) -> s32 { - return closure((x: s32) -> s32 => x * n); - } - f1_e1 := mk_e1(2); - f2_e1 := mk_e1(3); - f3_e1 := mk_e1(4); - print("closure-factory-indep: {} {} {}\n", f1_e1(10), f2_e1(10), f3_e1(10)); - - // C5.E2: deep chain — closure capturing closure capturing closure - v_e2 : s32 = 1; - k2_e2 : s32 = 2; - k100_e2 : s32 = 100; - f0_e2 := closure((x: s32) -> s32 => x + v_e2); - f1_e2 := closure((x: s32) -> s32 => f0_e2(x) * k2_e2); - f2_e2 := closure((x: s32) -> s32 => f1_e2(x) + k100_e2); - print("closure-deep-chain: {}\n", f2_e2(10)); - - // C5.E3: many captures (stress env struct) - c1_e3 : s32 = 1; - c2_e3 : s32 = 2; - c3_e3 : s32 = 3; - c4_e3 : s32 = 4; - c5_e3 : s32 = 5; - c6_e3 : s32 = 6; - c7_e3 : s32 = 7; - c8_e3 : s32 = 8; - big_env := closure(() -> s32 => c1_e3 + c2_e3 + c3_e3 + c4_e3 + c5_e3 + c6_e3 + c7_e3 + c8_e3); - print("closure-8cap: {}\n", big_env()); - - // C5.E5: closure with many parameters (4 params) - multi_param := closure((a: s32, b: s32, c: s32, d: s32) -> s32 => a + b + c + d); - a_e5 : s32 = 1; b_e5 : s32 = 2; c_e5 : s32 = 3; d_e5 : s32 = 4; - print("closure-4param: {}\n", multi_param(a_e5, b_e5, c_e5, d_e5)); - - // C5.E7: two closures sharing the same captured pointer - shared : s32 = 0; - shared_p := @shared; - inc_shared := closure(() { shared_p.* += 1; }); - add5_shared := closure(() { shared_p.* += 5; }); - inc_shared(); - add5_shared(); - inc_shared(); - print("closure-shared-ptr: {}\n", shared); - - // C5.E8: closure with f64 arithmetic - pi_e8 : f64 = 3.14159; - area_fn := closure((r: f64) -> f64 => pi_e8 * r * r); - a_e8 := area_fn(10.0); - print("closure-f64: {}\n", a_e8 > 314.0); - - // C5.E9: zero-capture closure (env should be null, like auto-promoted) - no_cap := closure((x: s32) -> s32 => x * x); - print("closure-zerocap: {} {}\n", no_cap(7), no_cap.env == null); - - // C5.E10: closure capturing and calling struct method - pt_e10 := Point.{ x = 3, y = 4 }; - p_e10 := @pt_e10; - get_xy := closure(() -> s32 => p_e10.x + p_e10.y); - print("closure-struct-method: {}\n", get_xy()); - - // C5.E11: multiple closures from same factory with different captures - fns_e11 : [3]Closure(s32) -> s32 = ---; - i_e11 := 0; - while i_e11 < 3 { - multiplier : s32 = xx (i_e11 + 1); - fns_e11[i_e11] = closure((x: s32) -> s32 => x * multiplier); - i_e11 += 1; - } - t_e11 := fns_e11[0]; print("closure-multi-factory: {}\n", t_e11(10)); - t_e11 = fns_e11[1]; print("closure-multi-factory: {}\n", t_e11(10)); - t_e11 = fns_e11[2]; print("closure-multi-factory: {}\n", t_e11(10)); - - // C5.E12: closure capturing bool - flag_e12 := true; - check_fn := closure((x: s32) -> bool { - if flag_e12 { return x > 0; } - return x < 0; - }); - pos_e12 : s32 = 5; - neg_e12 : s32 = xx -3; - print("closure-bool-cap: {} {}\n", check_fn(pos_e12), check_fn(neg_e12)); - - // C5.E13: closure as argument to another closure - apply_fn := closure((f_app: Closure(s32) -> s32, val: s32) -> s32 => f_app(val)); - k_e13 : s32 = 100; - inner_fn := closure((x: s32) -> s32 => x + k_e13); - print("closure-as-arg: {}\n", apply_fn(inner_fn, 42)); - - // C5.E14: closure capturing string and formatting - prefix_e14 := "hello"; - greet_fn := closure((name: string) -> string => format("{} {}", prefix_e14, name)); - print("closure-strfmt: {}\n", greet_fn("world")); - - // C5.E15: reassigning shared pointer target between closure calls - val_e15 : s32 = 10; - p_e15 := @val_e15; - read_fn := closure(() -> s32 => p_e15.*); - print("closure-ptr-before: {}\n", read_fn()); - val_e15 = 42; - print("closure-ptr-after: {}\n", read_fn()); - - // C5.E16: closure returning negative value - off_e16 : s32 = 100; - neg_fn := closure((x: s32) -> s32 => x - off_e16); - val_e16 : s32 = 30; - print("closure-neg: {}\n", neg_fn(val_e16)); - - // C5.E17: closure with protocol value capture (#inline protocol) - gpa_e17 := GPA.init(); - a_e17 : Allocator = xx gpa_e17; - alloc_fn := closure((size: s64) -> *void => a_e17.alloc(size)); - ptr_e17 := alloc_fn(32); - print("closure-proto-cap: {}\n", ptr_e17 != null); - a_e17.dealloc(ptr_e17); - - // C5.E18: chained factory — compose two factories - make_scaler :: (factor: s32) -> Closure(s32) -> s32 { - return closure((x: s32) -> s32 => x * factor); - } - make_offset :: (off: s32) -> Closure(s32) -> s32 { - return closure((x: s32) -> s32 => x + off); - } - s_fn := make_scaler(3); - o_fn := make_offset(7); - // manually compose: scale then offset - print("closure-chain-factory: {}\n", o_fn(s_fn(10))); - - // C5.E19: closure in while loop condition helper - threshold : s32 = 50; - above_fn := closure((x: s32) -> bool => x >= threshold); - vals_e19 : [5]s32 = .[10, 30, 50, 70, 90]; - count_above : s32 = 0; - idx_e19 : s64 = 0; - while idx_e19 < 5 { - if above_fn(vals_e19[idx_e19]) { count_above += 1; } - idx_e19 += 1; - } - print("closure-while-cond: {}\n", count_above); - - // ---- Inferred closure parameter types ---- - - // CI.1: inferred params from typed variable - f_ci1 : Closure(s32, s32) -> s32 = closure((a, b) => a + b); - a_ci1 : s32 = 3; - b_ci1 : s32 = 4; - print("closure-infer: {}\n", f_ci1(a_ci1, b_ci1)); - - // CI.2: inferred params from function argument - apply_ci :: (f: Closure(s32) -> s32, x: s32) -> s32 { return f(x); } - k_ci : s32 = 10; - v_ci : s32 = 5; - print("closure-infer-arg: {}\n", apply_ci(closure((x) => x + k_ci), v_ci)); - - // CI.3: inferred with block body - h_ci : Closure(s32, s32) -> s32 = closure((a, b) { return a * b; }); - print("closure-infer-block: {}\n", h_ci(a_ci1, b_ci1)); - - // CI.4: inferred with captures - cap_ci : s32 = 100; - f_ci4 : Closure(s32) -> s32 = closure((x) => x + cap_ci); - print("closure-infer-cap: {}\n", f_ci4(v_ci)); - - // CI.5: inferred in factory return - mk_ci :: (n: s32) -> Closure(s32) -> s32 { return closure((x) => x * n); } - f_ci5 := mk_ci(7); - print("closure-infer-factory: {}\n", f_ci5(v_ci)); - - // CI.6: inferred with higher-order (closure taking closure) - compose_ci :: (f: Closure(s32) -> s32, g: Closure(s32) -> s32) -> Closure(s32) -> s32 { - return closure((x: s32) -> s32 => f(g(x))); - } - one_ci : s32 = 1; - two_ci : s32 = 2; - c_ci := compose_ci(closure((x) => x + one_ci), closure((x) => x * two_ci)); - print("closure-infer-compose: {}\n", c_ci(v_ci)); - - // CI.7: inferred void return - msg_ci := "infer-void"; - cb_ci : Closure(s32) -> void = closure((x) { print("closure-{}: {}\n", msg_ci, x); }); - cb_ci(42); - } - - // ======================================================== - // PROTOCOLS (Phase 1: static dispatch) - // ======================================================== - print("=== Protocols ===\n"); - - // P1.1: Basic protocol + impl, direct call on concrete type - { - sc := SimpleCounter.{ val = 0 }; - sc.inc(); - sc.inc(); - sc.inc(); - print("P1.1: {}\n", sc.get()); - } - - // P1.2: impl in separate scope (retroactive conformance) - { - p := Point.{ x = 10, y = 20 }; - print("P1.2: {}\n", p.sum()); - } - - // P2.1: #inline protocol — xx conversion + dynamic dispatch - { - acc := Accumulator.{ total = 0 }; - a : Adder = xx @acc; - a.add(10); - a.add(20); - a.add(12); - print("P2.1: {}\n", a.value()); - } - - // P2.2: pass protocol value to function - { - use_adder :: (a: Adder, n: s32) -> s32 { - a.add(n); - a.value(); - } - acc := Accumulator.{ total = 100 }; - result := use_adder(xx @acc, 50); - print("P2.2: {}\n", result); - } - - // P2.3: different impls through same protocol type - { - acc := Accumulator.{ total = 0 }; - dbl := Doubler.{ val = 0 }; - a1 : Adder = xx @acc; - a2 : Adder = xx @dbl; - a1.add(5); - a2.add(5); - print("P2.3: {} {}\n", a1.value(), a2.value()); - } - - // P3.1: vtable-pointer protocol (default, no #inline) - { - sc := SimpleCounter.{ val = 0 }; - c : Counter = xx @sc; - c.inc(); - c.inc(); - c.inc(); - c.inc(); - c.inc(); - print("P3.1: {}\n", c.get()); - } - - // P3.2: vtable protocol passed to function - { - use_counter :: (c: Counter) -> s32 { - c.inc(); - c.inc(); - c.get(); - } - sc := SimpleCounter.{ val = 10 }; - result := use_counter(xx @sc); - print("P3.2: {}\n", result); - } - - // P4.1: default method calls required method (static dispatch) - { - pr := Printer.{ count = 0 }; - pr.say_twice("hi "); - print("\nP4.1: {}\n", pr.count); - } - - // P4.2: default method via dynamic dispatch (vtable) - { - pr := Printer.{ count = 0 }; - r : Repeater = xx @pr; - r.say_twice("yo "); - print("\nP4.2: {}\n", pr.count); - } - - // P4.3: chained default→default calls via vtable - { - ci := ChainImpl.{ val = 0 }; - ch : Chained = xx @ci; - // double_wrap calls wrap twice, wrap calls base once each - // base("hi") returns 2 (len), wrap adds 1 → 3, double_wrap = 3 + 3 = 6 - result := ch.double_wrap("hi"); - // base was called 2 times (once per wrap call) - print("P4.3: {} {}\n", result, ci.val); - } - - // P5.1: Self type in protocol — static dispatch - { - p1 := Point.{ x = 1, y = 2 }; - p2 := Point.{ x = 1, y = 2 }; - p3 := Point.{ x = 3, y = 4 }; - print("P5.1: {} {}\n", p1.eq(p2), p1.eq(p3)); - } - - // P5.2: Self in return position - { - p := Point.{ x = 10, y = 20 }; - p2 := p.clone(); - print("P5.2: {} {}\n", p2.x, p2.y); - } - - // P5.5: impl for primitive type - { - x := 42; - y := 42; - z := 99; - r1 := x.eq(y); - r2 := x.eq(z); - print("P5.5: {} {}\n", r1, r2); - } - - // P5.3: Self with dynamic dispatch (erased to *void) - { - p1 := Point.{ x = 1, y = 2 }; - p2 := Point.{ x = 1, y = 2 }; - p3 := Point.{ x = 3, y = 4 }; - e : Eq = xx p1; - print("P5.3: {} {}\n", e.eq(p2), e.eq(p3)); - } - - // P6.1: Single constraint — constrained generic function - { - p1 := Point.{ x = 1, y = 2 }; - p2 := Point.{ x = 1, y = 2 }; - p3 := Point.{ x = 3, y = 4 }; - print("P6.1: {} {}\n", are_equal(p1, p2), are_equal(p1, p3)); - } - - // P6.2: Constraint with primitive type - { - print("P6.2: {} {}\n", are_equal(42, 42), are_equal(42, 99)); - } - - // P6.3: Multiple constraints - { - p1 := Point.{ x = 1, y = 2 }; - p2 := Point.{ x = 1, y = 2 }; - p3 := Point.{ x = 3, y = 4 }; - print("P6.3: {} {}\n", eq_and_hash(p1, p2), eq_and_hash(p1, p3)); - } - - // P6.4: inline constraint syntax ($T/Protocol) - { - // sum_of_inline uses $T/Summable inline (not $T: Type/Summable) - p1 := Point.{ x = 10, y = 20 }; - p2 := Point.{ x = 3, y = 7 }; - print("P6.4: {}\n", sum_of_inline(p1, p2)); - } - - // P6.5: Struct type param constraints ($T: Type/Summable) - { - box := SumBox(Point).{ val = Point.{ x = 5, y = 15 } }; - print("P6.5: {}\n", box.val.sum()); - } - - // P7.1: impl for generic struct - { - p := Pair(s32).{ a = 10, b = 20 }; - print("P7.1: {}\n", p.sum()); - } - - // P7.2: generic struct impl with different type arg - { - p1 := Pair(s32).{ a = 3, b = 7 }; - p2 := Pair(s64).{ a = 100, b = 200 }; - print("P7.2: {} {}\n", p1.sum(), p2.sum()); - } - - // P2.4: xx in function return position (tested in standalone test_return.sx) - // Covered by: make_adder :: (acc: *Accumulator) -> Adder { xx acc; } - - // P2.6: protocol values in arrays - { - acc := Accumulator.{ total = 0 }; - dbl := Doubler.{ val = 0 }; - adders : [2]Adder = .[xx @acc, xx @dbl]; - i := 0; - while i < 2 { - adders[i].add(5); - i += 1; - } - print("P2.6: {} {}\n", acc.total, dbl.val); - } - - // P2.7: xx on inline struct literal (no intermediate variable) - { - use_adder :: (a: Adder) -> s32 { a.add(10); a.value(); } - result := use_adder(xx Accumulator.{ total = 5 }); - print("P2.7: {}\n", result); - } - - // P3.3: xx on inline struct literal with vtable protocol - { - use_counter :: (c: Counter) -> s32 { c.inc(); c.inc(); c.get(); } - result := use_counter(xx SimpleCounter.{ val = 100 }); - print("P3.3: {}\n", result); - } - - // --- Auto type erasure (AE) --- - print("=== Auto Type Erasure ===\n"); - - // AE1: function argument — concrete passed where protocol expected (no xx) - { - use_counter :: (c: Counter) -> s32 { c.inc(); c.inc(); c.get(); } - sc := SimpleCounter.{ val = 10 }; - result := use_counter(sc); - print("AE1: {}\n", result); - } - - // AE2: variable assignment — concrete to protocol variable (no xx) - { - acc := Accumulator.{ total = 0 }; - a: Adder = acc; - a.add(5); - a.add(3); - print("AE2: {}\n", a.value()); - } - - // AE3: struct literal passed directly (no xx) - { - use_counter :: (c: Counter) -> s32 { c.inc(); c.inc(); c.get(); } - result := use_counter(SimpleCounter.{ val = 100 }); - print("AE3: {}\n", result); - } - - // AE4: explicit xx still works (not broken) - { - use_counter :: (c: Counter) -> s32 { c.inc(); c.get(); } - result := use_counter(xx SimpleCounter.{ val = 50 }); - print("AE4: {}\n", result); - } - - // AE5: pointer auto-erasure — *ConcreteType to protocol - { - use_adder :: (a: Adder) { a.add(10); } - acc := Accumulator.{ total = 5 }; - p := @acc; - use_adder(p); - print("AE5: {}\n", acc.total); - } - - // --- Struct Constants --- - print("=== Struct Constants ===\n"); - { - print("gravity: {}\n", Phys.GRAVITY); // gravity: 9.810000 - print("max speed: {}\n", Phys.MAX_SPEED); // max speed: 100 - p := Phys.{ x = 0.0, y = Phys.GRAVITY }; - print("p.y: {}\n", p.y); // p.y: 9.810000 - } - - // --- Init Blocks (IB) --- - print("=== Init Blocks ===\n"); - - // IB1: basic init block with struct methods - { - b := Builder.{ total = 0, count = 0 } { - self.add(10); - self.add(20); - self.add(30); - }; - print("IB1: {} {}\n", b.total, b.count); - } - - // IB2: nested init blocks (self shadows correctly) - { - b1 := Builder.{ total = 0, count = 0 } { - self.add(100); - b2 := Builder.{ total = 0, count = 0 } { - self.add(42); - }; - self.add(b2.total); - }; - print("IB2: {} {}\n", b1.total, b1.count); - } - - // IB3: empty init block - { - b := Builder.{ total = 5, count = 1 } {}; - print("IB3: {} {}\n", b.total, b.count); - } - - // IB4: conditional inside init block - { - add_extra := true; - b := Builder.{ total = 0, count = 0 } { - self.add(10); - if add_extra { - self.add(90); - } - }; - print("IB4: {}\n", b.total); - } - - // IB5: init block + auto type erasure combined - { - use_counter :: (c: Counter) -> s32 { c.inc(); c.inc(); c.get(); } - result := use_counter(SimpleCounter.{ val = 0 } { - self.val = 50; - }); - print("IB5: {}\n", result); - } - - // ============================================================ - // SECTION: Struct static method shorthand (.method(args) syntax) - // ============================================================ - print("--- struct static method shorthand ---\n"); - - // SM1: Basic shorthand — .create(args) resolves to Dims.create(args) - { - Dims :: struct { - w: f32; - h: f32; - - create :: (w: f32, h: f32) -> Dims { - Dims.{ w = w, h = h }; - } - - square :: (size: f32) -> Dims { - Dims.{ w = size, h = size }; - } - } - use_dims :: (d: Dims) { print("SM1: {} {}\n", d.w, d.h); } - use_dims(.create(16.0, 8.0)); - use_dims(.square(5.0)); - } - - // SM2: Shorthand in variable declaration with explicit type - { - Pair :: struct { - a: s64; - b: s64; - - make :: (a: s64, b: s64) -> Pair { - Pair.{ a = a, b = b }; - } - } - p : Pair = .make(10, 20); - print("SM2: {} {}\n", p.a, p.b); - } - - // ============================================================ - // OPTIONAL IF-ELSE COERCION - // ============================================================ - { - print("--- optional if-else coercion ---\n"); - OptF :: struct { width: ?f32; } - x :f32: 10.0; - - // null in then branch - f1 := OptF.{ width = if true then null else x }; - print("opt-if1: {}\n", f1.width ?? 99.0); - - // value in then branch, null in else - f2 := OptF.{ width = if true then x else null }; - print("opt-if2: {}\n", f2.width ?? 99.0); - - // both branches are values - f3 := OptF.{ width = if false then 5.0 else x }; - print("opt-if3: {}\n", f3.width ?? 99.0); - - // standalone optional variable - val: ?f32 = if true then null else 42.0; - print("opt-if4: {}\n", val ?? 0.0); - - val2: ?f32 = if false then null else 42.0; - print("opt-if5: {}\n", val2 ?? 0.0); - } - - // --- usize / isize --- - { - a : usize = 42; - b : isize = 0 - 7; - print("usize: {}\n", a); - print("isize: {}\n", b); - - // arithmetic - c : usize = a + 8; - print("usize+8: {}\n", c); - - // coercion from s32 - x : s32 = 10; - y : usize = xx x; - print("s32->usize: {}\n", y); - - // coercion to s64 - z : s64 = xx a; - print("usize->s64: {}\n", z); - } - - // --- inline if (compile-time conditionals) --- - print("=== inline if ===\n"); - { - // POINTER_SIZE is 8 on desktop (64-bit) - inline if POINTER_SIZE == 8 { - print("64-bit\n"); - } else { - print("32-bit\n"); - } - - // OS enum comparison - inline if OS == .wasm { - print("wasm\n"); - } else { - print("not wasm\n"); - } - - // != comparison - inline if OS != .unknown { - print("known os\n"); - } else { - print("unknown os\n"); - } - - // nested inline if - inline if POINTER_SIZE != 4 { - inline if OS != .wasm { - print("desktop 64-bit\n"); - } else { - print("wasm 64-bit??\n"); - } - } - - // POINTER_SIZE in regular (non-inline) if expression - ps := if POINTER_SIZE == 8 then "8" else "4"; - print("pointer size via if: {}\n", ps); - } - - // ── 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: s64, b: s64) -> s64 { return a + b; } - r := add(10, 20,); - assert(r == 30); - - // Array literal with trailing comma - arr := s64.[1, 2, 3,]; - assert(arr[2] == 3); - - print("trailing commas ok\n"); - } - - print("=== DONE ===\n"); -} diff --git a/examples/expected/0025-basic-literals.exit b/examples/expected/0025-basic-literals.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0025-basic-literals.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0025-basic-literals.stderr b/examples/expected/0025-basic-literals.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0025-basic-literals.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0025-basic-literals.stdout b/examples/expected/0025-basic-literals.stdout new file mode 100644 index 0000000..8d7e67b --- /dev/null +++ b/examples/expected/0025-basic-literals.stdout @@ -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 diff --git a/examples/expected/0026-basic-operators.exit b/examples/expected/0026-basic-operators.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0026-basic-operators.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0026-basic-operators.stderr b/examples/expected/0026-basic-operators.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0026-basic-operators.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0026-basic-operators.stdout b/examples/expected/0026-basic-operators.stdout new file mode 100644 index 0000000..6ddc648 --- /dev/null +++ b/examples/expected/0026-basic-operators.stdout @@ -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-s64: 200 +widen-s32-f64: 42.000000 +widen-f32-f64: 1.500000 +widen-u8-s16: 100 +xx-s64-s32: 12345 +xx-f64-f32: 1.500000 +xx-f64-s32: 7 diff --git a/examples/expected/0027-basic-control-flow.exit b/examples/expected/0027-basic-control-flow.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0027-basic-control-flow.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0027-basic-control-flow.stderr b/examples/expected/0027-basic-control-flow.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0027-basic-control-flow.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0027-basic-control-flow.stdout b/examples/expected/0027-basic-control-flow.stdout new file mode 100644 index 0000000..f2aec93 --- /dev/null +++ b/examples/expected/0027-basic-control-flow.stdout @@ -0,0 +1,26 @@ +=== 4. Control Flow === +ite: 1 +ite-both: 10 20 +if-block: yes +if-no-else: after +nested-if: deep +if-else-if: second +if-block-expr: 15 +while: 5 +while-false: skipped +while-break: 7 +while-continue: 25 +while-sum: 55 +nested-while: 9 +nested-break: 2 2 +for: 10 20 30 40 +for-print: 10 20 30 40 +for-idx: 0 1 2 3 +for-2arg: 10@0 20@1 30@2 40@3 +for-break: 10 20 +for-continue: 10 30 40 +for-slice: 10 20 30 +for-slice-idx: 0:10 1:20 2:30 +for-nested: (0,0) (0,1) (1,0) (1,1) +for-break-idx: 2 +multi: 1 2 3 diff --git a/examples/expected/0028-basic-functions.exit b/examples/expected/0028-basic-functions.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0028-basic-functions.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0028-basic-functions.stderr b/examples/expected/0028-basic-functions.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0028-basic-functions.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0028-basic-functions.stdout b/examples/expected/0028-basic-functions.stdout new file mode 100644 index 0000000..6f2015f --- /dev/null +++ b/examples/expected/0028-basic-functions.stdout @@ -0,0 +1,21 @@ +=== 5. Functions === +const: 42 +typed-const: 3.140000 +default-init: 0 +implicit-ret: 42 +early-ret: 5 +early-ret2: 99 +void-return: ok +generic-s32: 42 +generic-f32: 1.500000 +generic-bool: true +generic-multi: 30 +lambda: 14 +lambda-ret: 5.000000 +local-fn: 7 +fn-nested: 26 +varargs: 15 +spread: 60 +fp: 7 +fp-reassign: 12 +fp-apply: 30 diff --git a/examples/expected/0029-basic-scoping.exit b/examples/expected/0029-basic-scoping.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0029-basic-scoping.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0029-basic-scoping.stderr b/examples/expected/0029-basic-scoping.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0029-basic-scoping.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0029-basic-scoping.stdout b/examples/expected/0029-basic-scoping.stdout new file mode 100644 index 0000000..9f6538b --- /dev/null +++ b/examples/expected/0029-basic-scoping.stdout @@ -0,0 +1,23 @@ +=== 6. Scoping === +inner: 200 +outer: 100 +shadow-type: 42 +shadow-type: 3.140000 +nest3: 3 +nest2: 2 +nest1: 1 +scope-isolate: 100 +scope-reuse: 1 +scope-reuse: 2 +scope-reuse: 1 +defer-a +defer-b +defer-c +d4 +d3 +d2 +d1 +inner-defer +outer-defer +defer-in-if: body +defer-in-if: deferred diff --git a/examples/expected/0030-basic-builtins.exit b/examples/expected/0030-basic-builtins.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0030-basic-builtins.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0030-basic-builtins.stderr b/examples/expected/0030-basic-builtins.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0030-basic-builtins.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0030-basic-builtins.stdout b/examples/expected/0030-basic-builtins.stdout new file mode 100644 index 0000000..d972526 --- /dev/null +++ b/examples/expected/0030-basic-builtins.stdout @@ -0,0 +1,31 @@ +=== 7. Builtins === +out-ok +sqrt: 3.000000 +sqrt-f64: 4.000000 +sizeof-s32: 4 +sizeof-f64: 8 +sizeof-struct: 8 +alignof-u8: 1 +alignof-s32: 4 +alignof-s64: 8 +alignof-struct: 4 +typeof: int +typeof-float: float +typeof-string: string +typeof-bool: bool +typeof-struct: struct +typeof-enum: enum +typename: Point +fieldcount: 2 +fieldcount-enum: 3 +fieldname0: x +fieldname1: y +fieldname-enum0: red +fieldname-enum2: blue +fieldval0: 11 +fieldval1: 22 +fieldidx: 1 +fieldidx-tagged: 0 +fieldidx-tagged2: 2 +cast: 3 +cast-int-f64: 42.000000 diff --git a/examples/expected/0031-basic-local-fn-return.exit b/examples/expected/0031-basic-local-fn-return.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0031-basic-local-fn-return.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0031-basic-local-fn-return.stderr b/examples/expected/0031-basic-local-fn-return.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0031-basic-local-fn-return.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0031-basic-local-fn-return.stdout b/examples/expected/0031-basic-local-fn-return.stdout new file mode 100644 index 0000000..d748dc5 --- /dev/null +++ b/examples/expected/0031-basic-local-fn-return.stdout @@ -0,0 +1,3 @@ +=== 19. Local Fn Return === +local-struct: 42 99 +local-enum: .circle(2.500000) diff --git a/examples/expected/0032-basic-ufcs-return-type.exit b/examples/expected/0032-basic-ufcs-return-type.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0032-basic-ufcs-return-type.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0032-basic-ufcs-return-type.stderr b/examples/expected/0032-basic-ufcs-return-type.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0032-basic-ufcs-return-type.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0032-basic-ufcs-return-type.stdout b/examples/expected/0032-basic-ufcs-return-type.stdout new file mode 100644 index 0000000..ea13288 --- /dev/null +++ b/examples/expected/0032-basic-ufcs-return-type.stdout @@ -0,0 +1,3 @@ +=== 20. UFCS Return Type === +direct: 7 +ufcs: 7 diff --git a/examples/expected/0033-basic-if-struct.exit b/examples/expected/0033-basic-if-struct.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0033-basic-if-struct.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0033-basic-if-struct.stderr b/examples/expected/0033-basic-if-struct.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0033-basic-if-struct.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0033-basic-if-struct.stdout b/examples/expected/0033-basic-if-struct.stdout new file mode 100644 index 0000000..b3f58d9 --- /dev/null +++ b/examples/expected/0033-basic-if-struct.stdout @@ -0,0 +1,3 @@ +=== 22. If-Struct === +if-struct: 10 20 +else-struct: 30 40 diff --git a/examples/expected/0034-basic-string-comparison.exit b/examples/expected/0034-basic-string-comparison.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0034-basic-string-comparison.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0034-basic-string-comparison.stderr b/examples/expected/0034-basic-string-comparison.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0034-basic-string-comparison.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0034-basic-string-comparison.stdout b/examples/expected/0034-basic-string-comparison.stdout new file mode 100644 index 0000000..3e299b1 --- /dev/null +++ b/examples/expected/0034-basic-string-comparison.stdout @@ -0,0 +1,5 @@ +=== 24. String Comparison === +str-eq: true +str-neq: true +str-diff: false +empty-eq: true diff --git a/examples/expected/0035-basic-array-loop-mutation.exit b/examples/expected/0035-basic-array-loop-mutation.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0035-basic-array-loop-mutation.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0035-basic-array-loop-mutation.stderr b/examples/expected/0035-basic-array-loop-mutation.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0035-basic-array-loop-mutation.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0035-basic-array-loop-mutation.stdout b/examples/expected/0035-basic-array-loop-mutation.stdout new file mode 100644 index 0000000..2dc388a --- /dev/null +++ b/examples/expected/0035-basic-array-loop-mutation.stdout @@ -0,0 +1,3 @@ +=== 25. Array Loop Mutation === +loop-fill: 1 2 3 4 +compound: 13 diff --git a/examples/expected/0036-basic-ufcs-aliases.exit b/examples/expected/0036-basic-ufcs-aliases.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0036-basic-ufcs-aliases.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0036-basic-ufcs-aliases.stderr b/examples/expected/0036-basic-ufcs-aliases.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0036-basic-ufcs-aliases.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0036-basic-ufcs-aliases.stdout b/examples/expected/0036-basic-ufcs-aliases.stdout new file mode 100644 index 0000000..8f11485 --- /dev/null +++ b/examples/expected/0036-basic-ufcs-aliases.stdout @@ -0,0 +1,12 @@ +=== UFCS Aliases === +42 +42 +42 +42 +42 +3 +3 +3 +2 +1 +99 diff --git a/examples/expected/0037-basic-trailing-commas.exit b/examples/expected/0037-basic-trailing-commas.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0037-basic-trailing-commas.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0037-basic-trailing-commas.stderr b/examples/expected/0037-basic-trailing-commas.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0037-basic-trailing-commas.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0037-basic-trailing-commas.stdout b/examples/expected/0037-basic-trailing-commas.stdout new file mode 100644 index 0000000..a7fbf93 --- /dev/null +++ b/examples/expected/0037-basic-trailing-commas.stdout @@ -0,0 +1,2 @@ +=== Trailing Commas === +trailing commas ok diff --git a/examples/expected/0121-types-types.exit b/examples/expected/0121-types-types.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0121-types-types.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0121-types-types.stderr b/examples/expected/0121-types-types.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0121-types-types.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0121-types-types.stdout b/examples/expected/0121-types-types.stdout new file mode 100644 index 0000000..a4c7a59 --- /dev/null +++ b/examples/expected/0121-types-types.stdout @@ -0,0 +1,75 @@ +=== 3. Types === +s8: 127 +s16: 32000 +s32: 100000 +u8: 255 +u16: 65000 +u32: 4000000 +alias: 1.500000 +struct-pos: Point{x: 1, y: 2} +struct-prefix: Point{x: 3, y: 4} +struct-named: Point{x: 20, y: 10} +struct-shorthand: Point{x: 5, y: 6} +defaults: a=0 b=99 +field-assign: Point{x: 42, y: 99} +enum: .red +enum-eq: true +enum-neq: true +backing: .err +tagged: .circle(3.140000) +payload: 3.140000 +void-variant: .none +reassign: .circle(1.000000) +reassign2: .rect(Shape.rect{w: 5.000000, h: 3.000000}) +enum-prefix: .circle(2.500000) +match: rect +match-expr: 10 +match-expr-else: 99 +capture: 9.500000 +capture-arrow: 7.500000 +else-match: other +int-match: two +int-match-else: unknown +bool-match-t: yes +bool-match-f: no +bool: true +union-f: 3.140000 +union-i: 1078523331 +promoted-x: 1.000000 +promoted-data0: 1.000000 +arr[2]: 30 +arr.len: 5 +arr-assign: [1, 99, 3] +sl[0]: 1 +sl.len: 5 +sl-assign: [10, 55, 30] +sub: [20, 30, 40] +head: [10, 20, 30] +tail: [30, 40, 50] +slice-of-slice: [20, 30] +strsub: world +str-prefix: hello +str-suffix: world +global-addr-of: 99 +deref: Point{x: 10, y: 20} +auto-deref: 10 +mp[0]: 10 +mp[3]: 40 +mp-write: 99 +ptr==null: true +ptr!=null: false +ptr2==null: false +ptr2!=null: true +ptr-nested-field: 1.000000 2.000000 3.000000 +mp-store-sentinel: 42 +vec-construct: [1.000000, 3.000000, 2.000000] +vec-add: [5.000000, 7.000000, 9.000000] +vec-sub: [4.000000, 3.000000, 2.000000] +vec-mul: [2.000000, 6.000000, 12.000000] +vec-div: [5.000000, 3.000000, 2.000000] +vec-scalar: [2.000000, 6.000000, 4.000000] +vec-neg: [-1.000000, -3.000000, -2.000000] +vec-x: 10.000000 +vec-y: 20.000000 +vec-z: 30.000000 +vec-idx: 20.000000 diff --git a/examples/expected/0122-types-flags.exit b/examples/expected/0122-types-flags.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0122-types-flags.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0122-types-flags.stderr b/examples/expected/0122-types-flags.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0122-types-flags.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0122-types-flags.stdout b/examples/expected/0122-types-flags.stdout new file mode 100644 index 0000000..962fd40 --- /dev/null +++ b/examples/expected/0122-types-flags.stdout @@ -0,0 +1,18 @@ +=== 9. Flags === +flags: .read | .write +has-read: yes +flags-neg: no-read +flags-single: .execute +flags-all: .read | .write | .execute +flags-raw: 3 +flags-explicit: .vsync | .resizable +flags-explicit-raw: 68 +--- swap --- +var swap: 20 10 +arr swap: 3 1 +3-way: 3 1 2 +--- destructure --- +basic: 10 20 +fn: 2 1 +discard: 200 +triple: 1 2 3 diff --git a/examples/expected/0123-types-compound-assign.exit b/examples/expected/0123-types-compound-assign.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0123-types-compound-assign.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0123-types-compound-assign.stderr b/examples/expected/0123-types-compound-assign.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0123-types-compound-assign.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0123-types-compound-assign.stdout b/examples/expected/0123-types-compound-assign.stdout new file mode 100644 index 0000000..b9d4acc --- /dev/null +++ b/examples/expected/0123-types-compound-assign.stdout @@ -0,0 +1,3 @@ +=== 16. Compound Assign === +f64+=f32: 13.000000 +s64-=s32: 93 diff --git a/examples/expected/0124-types-array-of-structs.exit b/examples/expected/0124-types-array-of-structs.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0124-types-array-of-structs.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0124-types-array-of-structs.stderr b/examples/expected/0124-types-array-of-structs.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0124-types-array-of-structs.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0124-types-array-of-structs.stdout b/examples/expected/0124-types-array-of-structs.stdout new file mode 100644 index 0000000..88842a2 --- /dev/null +++ b/examples/expected/0124-types-array-of-structs.stdout @@ -0,0 +1,4 @@ +=== 18. Array of Structs === +arr-struct-x: 3 +for-struct: Point{x: 1, y: 2} +for-struct: Point{x: 3, y: 4} diff --git a/examples/expected/0125-types-type-named-vars.exit b/examples/expected/0125-types-type-named-vars.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0125-types-type-named-vars.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0125-types-type-named-vars.stderr b/examples/expected/0125-types-type-named-vars.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0125-types-type-named-vars.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0125-types-type-named-vars.stdout b/examples/expected/0125-types-type-named-vars.stdout new file mode 100644 index 0000000..3210d67 --- /dev/null +++ b/examples/expected/0125-types-type-named-vars.stdout @@ -0,0 +1,3 @@ +=== 21. Type-Named Vars === +s2: 42 +s2+1: 43 diff --git a/examples/expected/0126-types-nested-arrays.exit b/examples/expected/0126-types-nested-arrays.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0126-types-nested-arrays.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0126-types-nested-arrays.stderr b/examples/expected/0126-types-nested-arrays.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0126-types-nested-arrays.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0126-types-nested-arrays.stdout b/examples/expected/0126-types-nested-arrays.stdout new file mode 100644 index 0000000..8defb8c --- /dev/null +++ b/examples/expected/0126-types-nested-arrays.stdout @@ -0,0 +1,5 @@ +=== 23. Nested Arrays === +m[0][0]: 1 +m[0][2]: 3 +m[1][0]: 4 +m[1][2]: 6 diff --git a/examples/expected/0127-types-using.exit b/examples/expected/0127-types-using.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0127-types-using.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0127-types-using.stderr b/examples/expected/0127-types-using.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0127-types-using.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0127-types-using.stdout b/examples/expected/0127-types-using.stdout new file mode 100644 index 0000000..ddf56c4 --- /dev/null +++ b/examples/expected/0127-types-using.stdout @@ -0,0 +1,12 @@ +=== 26. #using === +using-x: 1 +using-y: 2 +using-z: 3 +pkt-id: 10 +pkt-ver: 42 +pkt-pay: 99 +sprite-px: 10 +sprite-r: 255 +sprite-scale: 1 +say: hello (len=5) +n=42 diff --git a/examples/expected/0128-types-tuples.exit b/examples/expected/0128-types-tuples.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0128-types-tuples.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0128-types-tuples.stderr b/examples/expected/0128-types-tuples.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0128-types-tuples.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0128-types-tuples.stdout b/examples/expected/0128-types-tuples.stdout new file mode 100644 index 0000000..65ce963 --- /dev/null +++ b/examples/expected/0128-types-tuples.stdout @@ -0,0 +1,8 @@ +=== Tuples === +40 +2 +10 +10 +42 +0 +0 diff --git a/examples/expected/0129-types-tuple-operators.exit b/examples/expected/0129-types-tuple-operators.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0129-types-tuple-operators.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0129-types-tuple-operators.stderr b/examples/expected/0129-types-tuple-operators.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0129-types-tuple-operators.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0129-types-tuple-operators.stdout b/examples/expected/0129-types-tuple-operators.stdout new file mode 100644 index 0000000..51cbcf2 --- /dev/null +++ b/examples/expected/0129-types-tuple-operators.stdout @@ -0,0 +1,203 @@ +=== Tuple Operators === +true +false +true +false +1 +2 +3 +4 +1 +2 +1 +2 +1 +2 +true +false +false +true +true +true +true +false +--- directory imports --- +7 +30 +hello from testpkg +cwd-import-ok +--- pipe operator --- +7 +30 +14 +hello world +piped ok! +alloc len: 5 +alloc[0]: 10 +alloc[4]: 50 +bytes len: 3 +--- allocators --- +gpa allocs: 2 +gpa final: 0 +arena chunks: 1 +arena overflow: 2 +arena a1: 42 +arena a3: 99 +arena reset idx: 0 +arena reset gpa: 1 +arena deinit: 0 +buf pos: 48 +buf overflow: 0 +buf reset: 0 +1 == (1) +(1) == 1 +1 == 1 +--- optionals --- +opt x: 42 +opt y: null +unwrap: 10 +coalesce a: 42 +coalesce b: 99 +chained ?? c: 42 +chained ?? d: 99 +chained ?? e: 0 +if-bind x: 7 +if-bind y: none +match some: 55 +match none: 0 +wrap pos: 5 +wrap neg: null +opt field default: null +opt field set: 42 +opt param a: 42 +opt param b: 0 +opt param 7: 7 +opt reassign: 42.500000 +opt compute assign: 15.000000 +opt re-null: 99.000000 +generic opt 1: 5 +generic opt 2: 7 +generic opt 3: null +chain some: 10 +chain none: 0 +chain print: 20 +chain null: null +deep chain 1: 99 +deep chain 2: 0 +narrow x: 42 +narrow y else: null +narrow else x: 42 +guard some: 42 +guard none: 0 +and both: 10 20 +and one null +or guard: 7 +or guard null: 0 +nested narrow: 10 20 +guard loop: 3 +block-lambda: 50 +block-lambda: 0 +block-lambda: 100 +hello block +named-fn-type: 7 +xx-fnptr: 142 +closure-type: fn_ptr-nonnull=true +closure-type: env-null=true +closure-call: 15 +auto-promote: 20 +auto-promote-var: 10 +closure-capture: 52 +closure-snapshot: 15 +closure-nocap: 14 +closure-multi: 33 +closure-block: 60 +closure-block: 0 +closure-block: 100 +[LOG] hello +closure-hof: 30 +closure-hof-bare: 20 +closure-f32: 10.000000 +closure-bool: hello +closure-2p: 107 +closure-3p: 61 +closure-mix: Alice is 35 +closure-rbool: false true +closure-reduce: 115 +closure-factory: 105 110 +closure-struct: 10 20 +closure-compose: 30 +closure-indep: 15 50 +opt-closure: none +opt-closure: 15 +opt-closure-btn: 1 99 +opt-closure-btn: null +closure-ptr: 3 +closure-enum: 2 +closure-rstr: [INFO] ok +closure-rstruct: 11 22 +closure-linear: 37 +closure-clamp: 0 100 255 +closure-compose2: 12 +closure-chain: 22 +closure-map: 3 6 9 12 15 +closure-filter: 3 [3 4 5] +closure-sort: 5 4 3 2 1 +closure-fe: item 0=10 +closure-fe: item 1=20 +closure-fe: item 2=30 +closure-find: 2 +closure-any: false true +closure-struct-field: -5 +closure-btn: 1 99 +closure-counter: 1 2 3 +closure-acc: 105 115 +closure-loop: 115 +closure-reassign: 11 +closure-reassign: 20 +closure-snapstruct: 15 +closure-cap-promoted: 11 +closure-iife: 15 +closure-toggle: none +closure-toggle: true +closure-panel: main 800x600 +closure-chain-call: true +closure-cond: 10 +closure-form: submitted +closure-form: no cancel +closure-null-env: true +closure-slice: 10 20 30 +closure-arena: 15 +closure-gpa: 17 allocs=0 +closure-opt: 42 +closure-ropt: 50 +closure-ropt: none +closure-mixed: 10 +closure-mixed: 15 +closure-mixed: 25 +closure-factory-indep: 20 30 40 +closure-deep-chain: 122 +closure-8cap: 36 +closure-4param: 10 +closure-shared-ptr: 7 +closure-f64: true +closure-zerocap: 49 true +closure-struct-method: 7 +closure-multi-factory: 10 +closure-multi-factory: 20 +closure-multi-factory: 30 +closure-bool-cap: true false +closure-as-arg: 142 +closure-strfmt: hello world +closure-ptr-before: 10 +closure-ptr-after: 42 +closure-neg: -70 +closure-proto-cap: true +closure-chain-factory: 37 +closure-while-cond: 3 +closure-infer: 7 +closure-infer-arg: 15 +closure-infer-block: 12 +closure-infer-cap: 105 +closure-infer-factory: 35 +closure-infer-compose: 11 +closure-infer-void: 42 diff --git a/examples/expected/0130-types-struct-constants.exit b/examples/expected/0130-types-struct-constants.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0130-types-struct-constants.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0130-types-struct-constants.stderr b/examples/expected/0130-types-struct-constants.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0130-types-struct-constants.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0130-types-struct-constants.stdout b/examples/expected/0130-types-struct-constants.stdout new file mode 100644 index 0000000..9949c25 --- /dev/null +++ b/examples/expected/0130-types-struct-constants.stdout @@ -0,0 +1,4 @@ +=== Struct Constants === +gravity: 9.810000 +max speed: 100 +p.y: 9.810000 diff --git a/examples/expected/0131-types-init-blocks.exit b/examples/expected/0131-types-init-blocks.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0131-types-init-blocks.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0131-types-init-blocks.stderr b/examples/expected/0131-types-init-blocks.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0131-types-init-blocks.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0131-types-init-blocks.stdout b/examples/expected/0131-types-init-blocks.stdout new file mode 100644 index 0000000..9c5b646 --- /dev/null +++ b/examples/expected/0131-types-init-blocks.stdout @@ -0,0 +1,21 @@ +=== Init Blocks === +IB1: 60 3 +IB2: 142 2 +IB3: 5 1 +IB4: 100 +IB5: 52 +--- struct static method shorthand --- +SM1: 16.000000 8.000000 +SM1: 5.000000 5.000000 +SM2: 10 20 +--- optional if-else coercion --- +opt-if1: 99.000000 +opt-if2: 10.000000 +opt-if3: 10.000000 +opt-if4: 0.000000 +opt-if5: 42.000000 +usize: 42 +isize: -7 +usize+8: 50 +s32->usize: 10 +usize->s64: 42 diff --git a/examples/expected/0415-protocols-protocols.exit b/examples/expected/0415-protocols-protocols.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0415-protocols-protocols.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0415-protocols-protocols.stderr b/examples/expected/0415-protocols-protocols.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0415-protocols-protocols.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0415-protocols-protocols.stdout b/examples/expected/0415-protocols-protocols.stdout new file mode 100644 index 0000000..d9ff954 --- /dev/null +++ b/examples/expected/0415-protocols-protocols.stdout @@ -0,0 +1,27 @@ +=== Protocols === +P1.1: 3 +P1.2: 30 +P2.1: 42 +P2.2: 150 +P2.3: 5 10 +P3.1: 5 +P3.2: 12 +hi hi +P4.1: 2 +yo yo +P4.2: 2 +P4.3: 6 2 +P5.1: true false +P5.2: 10 20 +P5.5: true false +P5.3: true false +P6.1: true false +P6.2: true false +P6.3: true false +P6.4: 40 +P6.5: 20 +P7.1: 30 +P7.2: 10 300 +P2.6: 5 10 +P2.7: 15 +P3.3: 102 diff --git a/examples/expected/0416-protocols-auto-type-erasure.exit b/examples/expected/0416-protocols-auto-type-erasure.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0416-protocols-auto-type-erasure.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0416-protocols-auto-type-erasure.stderr b/examples/expected/0416-protocols-auto-type-erasure.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0416-protocols-auto-type-erasure.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0416-protocols-auto-type-erasure.stdout b/examples/expected/0416-protocols-auto-type-erasure.stdout new file mode 100644 index 0000000..0a637d6 --- /dev/null +++ b/examples/expected/0416-protocols-auto-type-erasure.stdout @@ -0,0 +1,6 @@ +=== Auto Type Erasure === +AE1: 12 +AE2: 8 +AE3: 102 +AE4: 51 +AE5: 15 diff --git a/examples/expected/0608-comptime-comptime.exit b/examples/expected/0608-comptime-comptime.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0608-comptime-comptime.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0608-comptime-comptime.stderr b/examples/expected/0608-comptime-comptime.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0608-comptime-comptime.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0608-comptime-comptime.stdout b/examples/expected/0608-comptime-comptime.stdout new file mode 100644 index 0000000..ff4de5a --- /dev/null +++ b/examples/expected/0608-comptime-comptime.stdout @@ -0,0 +1,9 @@ +=== 8. Comptime === +run-const: 25 +run-expr: 42 +run-chain: 30 +ct-opt-coalesce: 141 +ct-opt-unwrap: 77 +ct-opt-guard: 10 +insert-ok +insert-gen: 42 diff --git a/examples/expected/0609-comptime-inline-if.exit b/examples/expected/0609-comptime-inline-if.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0609-comptime-inline-if.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0609-comptime-inline-if.stderr b/examples/expected/0609-comptime-inline-if.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0609-comptime-inline-if.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0609-comptime-inline-if.stdout b/examples/expected/0609-comptime-inline-if.stdout new file mode 100644 index 0000000..7b790f3 --- /dev/null +++ b/examples/expected/0609-comptime-inline-if.stdout @@ -0,0 +1,6 @@ +=== inline if === +64-bit +not wasm +known os +desktop 64-bit +pointer size via if: 8 diff --git a/examples/expected/0810-memory-slice-ptr.exit b/examples/expected/0810-memory-slice-ptr.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0810-memory-slice-ptr.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0810-memory-slice-ptr.stderr b/examples/expected/0810-memory-slice-ptr.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0810-memory-slice-ptr.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0810-memory-slice-ptr.stdout b/examples/expected/0810-memory-slice-ptr.stdout new file mode 100644 index 0000000..0729f6e --- /dev/null +++ b/examples/expected/0810-memory-slice-ptr.stdout @@ -0,0 +1,3 @@ +=== 17. Slice Ptr === +sl-ptr[0]: 20 +sl-ptr[1]: 30 diff --git a/examples/expected/1036-errors-failable-smoke.exit b/examples/expected/1036-errors-failable-smoke.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/1036-errors-failable-smoke.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/1036-errors-failable-smoke.stderr b/examples/expected/1036-errors-failable-smoke.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/1036-errors-failable-smoke.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/1036-errors-failable-smoke.stdout b/examples/expected/1036-errors-failable-smoke.stdout new file mode 100644 index 0000000..26b45c5 --- /dev/null +++ b/examples/expected/1036-errors-failable-smoke.stdout @@ -0,0 +1,19 @@ +tag: BadDigit +parsed: 10 +got: BadDigit +catch-expr: 100 +catch-match: 1 +or-default ok: 10 + logged BadDigit +or-default err: -1 +or-value: 55 +or-chain: 16 +pair-catch: 0 0 +pair-ok: 8 10 +check absorbed +acquire fail: + onfail B + defer A +acquire ok: + defer A +errors ok diff --git a/examples/expected/1219-ffi-foreign.exit b/examples/expected/1219-ffi-foreign.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/1219-ffi-foreign.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/1219-ffi-foreign.stderr b/examples/expected/1219-ffi-foreign.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/1219-ffi-foreign.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/1219-ffi-foreign.stdout b/examples/expected/1219-ffi-foreign.stdout new file mode 100644 index 0000000..4aad986 --- /dev/null +++ b/examples/expected/1219-ffi-foreign.stdout @@ -0,0 +1,2 @@ +=== 15. Foreign === +foreign-rename: 42