summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/all-examples.txt360
-rw-r--r--examples/slices.fy33
-rw-r--r--examples/uber.fy386
3 files changed, 779 insertions, 0 deletions
diff --git a/examples/all-examples.txt b/examples/all-examples.txt
index f1a81b8..5349073 100644
--- a/examples/all-examples.txt
+++ b/examples/all-examples.txt
@@ -405,6 +405,40 @@ assert 0 == (say defined bar);
+# Test array index expressions and slice notation
+
+my a = [10, 20, 30, 40, 50];
+
+# Expression-based index
+my i = 2;
+assert 30 == say a[i];
+assert 40 == say a[i + 1];
+
+# Array element assignment
+a[1] = 99;
+assert 99 == say a[1];
+
+# Basic slice (half-open range: end index is exclusive)
+my sub = a[1:4];
+assert 3 == say len sub;
+assert 99 == say sub[0];
+assert 30 == say sub[1];
+assert 40 == say sub[2];
+
+# Slice from start (low bound omitted)
+my head = a[:2];
+assert 2 == say len head;
+assert 10 == say head[0];
+
+# Slice to end (high bound omitted)
+my tail = a[3:];
+assert 2 == say len tail;
+assert 40 == say tail[0];
+
+# Full copy
+my copy = a[:];
+assert 5 == say len copy;
+
#*
* Examples of how to use synonyms
*#
@@ -459,6 +493,332 @@ assert say integer double string put say neg 12; # Nonsense but working :)
#*
+ * Fype uber-example: exercises every language feature.
+ * Every assertion must pass for the script to exit cleanly.
+ *#
+
+# ─── 1. COMMENTS ─────────────────────────────────────────────────────────────
+
+# Single-line comment — ignored completely.
+
+#*
+ * Block comment: also ignored.
+ *#
+
+# Inline block comment inside an expression:
+my commentsok = 1 #* this is ignored *# + 1;
+assert 2 == say commentsok;
+
+# ─── 2. VARIABLES AND BASIC ARITHMETIC ───────────────────────────────────────
+
+# Multiple declarations on one line; bay gets the default value 0
+my x = 10, y = 3, bay;
+assert 0 == say bay;
+assert 13 == say x + y;
+assert 7 == say x - y;
+assert 30 == say x * y;
+assert 3 == say x / y; # integer division truncates toward zero
+assert 10 == say 2 * (4 + 2) - 2;
+assert 10 == say (8 / 2) + 2 * 3;
+
+x = x + 1;
+assert 11 == say x;
+
+# ─── 3. NEGATION AND NOT ──────────────────────────────────────────────────────
+
+assert 5 == say neg neg 5;
+assert 0 == say neg neg 0;
+assert (neg 1) == (say neg not 0); # not 0 => 1, neg 1 => -1
+
+# ─── 4. INCREMENT / DECREMENT ────────────────────────────────────────────────
+
+my counter = 5;
+incr counter;
+assert 6 == say counter;
+decr counter;
+decr counter;
+assert 4 == say counter;
+
+# ─── 5. TYPE CONVERSION ───────────────────────────────────────────────────────
+
+assert 2 == say integer 2.8; # truncates toward zero
+assert 1 == say double 1; # 1.0 compared as 1
+assert 14 == say 1 + string 13; # "13" coerced to integer 13
+assert 5 == say "10 bla" / 2; # leading digits extracted
+
+# ─── 6. STRING ARITHMETIC ────────────────────────────────────────────────────
+
+assert 46 == say "12" + "34"; # "12"->12 + "34"->34 = 46
+assert 1231 == say "1234" - "3"; # 1234 - 3 = 1231
+assert 5 == say "10 bla" / 2;
+
+# ─── 7. COMPARISON OPERATORS ─────────────────────────────────────────────────
+
+assert 1 == (put 5 > 3); assert 0 == (say 5 > 5);
+assert 1 == (put 5 >= 5); assert 0 == (say 4 >= 5);
+assert 1 == (put 3 < 5); assert 0 == (say 5 < 5);
+assert 1 == (put 3 <= 5); assert 0 == (say 6 <= 5);
+assert 1 == (put 5 == 5); assert 0 == (say 4 == 5);
+assert 1 == (put 5 != 4); assert 0 == (say 5 != 5);
+
+# ─── 8. BITWISE OPERATORS ────────────────────────────────────────────────────
+
+assert 1 == say (5 and 3); # 0b101 & 0b011 = 0b001 = 1
+assert 7 == say (5 or 2); # 0b101 | 0b010 = 0b111 = 7
+assert 6 == say (5 xor 3); # 0b101 ^ 0b011 = 0b110 = 6
+assert 8 == say (2 :< 2); # 2 << 2 = 8
+assert 2 == say (8 :> 2); # 8 >> 2 = 2
+assert 0 == say (1 and 0);
+assert 1 == say (0 or 1);
+assert 0 == say (1 xor 1);
+
+# ─── 9. CONDITIONALS ─────────────────────────────────────────────────────────
+
+my flag = 0;
+if 1 { flag = 1; }
+assert 1 == say flag;
+
+ifnot 0 { flag = 2; }
+assert 2 == say flag;
+
+if 0 { flag = 99; } # must not execute
+ifnot 1 { flag = 99; } # must not execute
+assert 2 == say flag;
+
+# ─── 10. WHILE AND UNTIL ─────────────────────────────────────────────────────
+
+my cnt = 0;
+while cnt < 5 { cnt = cnt + 1; }
+assert 5 == say cnt;
+
+cnt = 0;
+until cnt >= 4 { cnt = cnt + 1; }
+assert 4 == say cnt;
+
+# ─── 11. LOOP WITH BREAK AND NEXT ────────────────────────────────────────────
+
+my n = 0;
+loop {
+ n = n + 1;
+ if n == 7 { break; }
+}
+assert 7 == say n;
+
+# Sum 1..10 skipping multiples of 3: 1+2+4+5+7+8+10 = 37
+my total = 0, step = 0;
+loop {
+ step = step + 1;
+ if step > 10 { break; }
+ if step / 3 * 3 == step { next; } # divisible by 3
+ total = total + step;
+}
+assert 37 == say total;
+
+# ─── 12. WHILE WITH BREAK AND NEXT ───────────────────────────────────────────
+
+# Sum 1..10 skipping 5, stopping after 8: 1+2+3+4 + 6+7+8 = 31
+my wsum = 0, wi = 0;
+while wi < 10 {
+ wi = wi + 1;
+ if wi == 5 { next; }
+ if wi > 8 { break; }
+ wsum = wsum + wi;
+}
+assert 31 == say wsum;
+
+# ─── 13. DO-WHILE / DO-UNTIL ─────────────────────────────────────────────────
+
+# Body runs once even though the condition is already false
+my dw = 10;
+do { dw = dw + 1; } while dw < 10;
+assert 11 == say dw;
+
+my du = 0;
+do { du = du + 1; } until du == 5;
+assert 5 == say du;
+
+# ─── 14. PROCEDURES ──────────────────────────────────────────────────────────
+
+# Procedures share the caller's scope; mutations are visible to the caller
+my acc = 0;
+proc bump { acc = acc + 10; }
+bump;
+bump;
+assert 20 == say acc;
+
+# Variables declared inside a procedure leak into the caller's scope
+proc initcoords { my cx = 3; my cy = 7; }
+initcoords;
+assert 3 == say cx;
+assert 7 == say cy;
+
+# ─── 15. FUNCTIONS ───────────────────────────────────────────────────────────
+
+# Zero-arg function with explicit return
+fun answer() { ret 42; }
+assert 42 == say answer();
+
+# Single-arg
+fun square(m) { ret m * m; }
+assert 25 == say square(5);
+assert 0 == say square(0);
+
+# Two-arg
+fun add(a, b) { ret a + b; }
+assert 9 == say add(4, 5);
+
+# Conditional return
+fun absval(v) {
+ if v < 0 { ret neg v; }
+ ret v;
+}
+assert 7 == say absval(7);
+assert 7 == say absval(neg 7);
+
+# Iterative function with local variables and decr
+fun factorial(num) {
+ my result = 1;
+ while num > 1 {
+ result = result * num;
+ decr num;
+ }
+ ret result;
+}
+assert 1 == say factorial(0);
+assert 1 == say factorial(1);
+assert 120 == say factorial(5);
+assert 720 == say factorial(6);
+
+# Iterative fibonacci using local variables
+fun fib(num) {
+ if num <= 1 { ret num; }
+ my fa = 0, fb = 1, ftmp = 0, fi = 2;
+ while fi <= num {
+ ftmp = fa + fb;
+ fa = fb;
+ fb = ftmp;
+ fi = fi + 1;
+ }
+ ret fb;
+}
+assert 0 == say fib(0);
+assert 1 == say fib(1);
+assert 1 == say fib(2);
+assert 8 == say fib(6);
+assert 55 == say fib(10);
+
+# Old-style zero-arg function (no parentheses)
+fun greet { say "hello from greet"; }
+greet;
+
+# Multiple return values both land on the caller's stack (printed here)
+fun minmax(a, b) {
+ if a < b { ret a, b; }
+ ret b, a;
+}
+say minmax(3, 7); # prints 3 then 7
+
+# ─── 16. SCOPING ─────────────────────────────────────────────────────────────
+
+my outer = 100;
+{
+ my inner = 200;
+ outer = outer + inner;
+ assert 1 == defined inner;
+}
+assert 300 == say outer;
+assert 0 == defined inner;
+
+# Variables defined in nested blocks vanish when the block closes
+my depth = 0;
+{
+ depth = depth + 1;
+ {
+ depth = depth + 1;
+ { depth = depth + 1; }
+ assert 3 == say depth;
+ }
+}
+assert 3 == say depth;
+
+# ─── 17. SYNONYMS / ALIASES ──────────────────────────────────────────────────
+
+my orig = 42;
+my alias = \orig;
+assert 42 == say alias; # alias starts with orig's value
+
+orig = 99;
+assert 99 == say alias; # alias reflects the change
+
+assert 2 == syms orig; # two symbols point to the same value
+undef orig;
+assert 1 == syms alias;
+assert 0 == defined orig;
+assert 1 == defined alias;
+undef alias;
+
+# Procedure synonym
+proc grp { say "grp called"; }
+my grp2 = \grp;
+assert 2 == syms grp;
+grp2; # still callable through the alias
+undef grp;
+grp2; # alias keeps it alive
+assert 0 == defined grp;
+undef grp2;
+
+# ─── 18. DEFINED AND UNDEF ───────────────────────────────────────────────────
+
+my tmpvar = 5;
+assert 1 == defined tmpvar;
+assert 0 == defined nosuchvar;
+undef tmpvar;
+assert 0 == defined tmpvar;
+
+# ─── 19. ARRAYS — LITERALS, INDEXING, ASSIGNMENT ────────────────────────────
+
+my nums = [10, 20, 30, 40, 50];
+assert 5 == say len nums;
+assert 10 == say nums[0];
+assert 30 == say nums[2];
+assert 50 == say nums[4];
+
+# Expression-based index
+my idx = 1;
+assert 20 == say nums[idx];
+assert 30 == say nums[idx + 1];
+
+# Element assignment
+nums[2] = 99;
+assert 99 == say nums[2];
+
+# ─── 20. ARRAY SLICES ────────────────────────────────────────────────────────
+
+# nums is now [10, 20, 99, 40, 50]
+my sl = nums[1:4]; # half-open: indices 1, 2, 3
+assert 3 == say len sl;
+assert 20 == say sl[0];
+assert 99 == say sl[1];
+assert 40 == say sl[2];
+
+my head = nums[:2]; # first two elements
+assert 2 == say len head;
+assert 10 == say head[0];
+assert 20 == say head[1];
+
+my tail = nums[3:]; # from index 3 to end
+assert 2 == say len tail;
+assert 40 == say tail[0];
+assert 50 == say tail[1];
+
+my cpy = nums[:]; # full shallow copy
+assert 5 == say len cpy;
+assert 10 == say cpy[0];
+assert 50 == say cpy[4];
+
+say "All assertions passed.";
+
+#*
* Examples of how to define variables
*#
diff --git a/examples/slices.fy b/examples/slices.fy
new file mode 100644
index 0000000..942f4bc
--- /dev/null
+++ b/examples/slices.fy
@@ -0,0 +1,33 @@
+# Test array index expressions and slice notation
+
+my a = [10, 20, 30, 40, 50];
+
+# Expression-based index
+my i = 2;
+assert 30 == say a[i];
+assert 40 == say a[i + 1];
+
+# Array element assignment
+a[1] = 99;
+assert 99 == say a[1];
+
+# Basic slice (half-open range: end index is exclusive)
+my sub = a[1:4];
+assert 3 == say len sub;
+assert 99 == say sub[0];
+assert 30 == say sub[1];
+assert 40 == say sub[2];
+
+# Slice from start (low bound omitted)
+my head = a[:2];
+assert 2 == say len head;
+assert 10 == say head[0];
+
+# Slice to end (high bound omitted)
+my tail = a[3:];
+assert 2 == say len tail;
+assert 40 == say tail[0];
+
+# Full copy
+my copy = a[:];
+assert 5 == say len copy;
diff --git a/examples/uber.fy b/examples/uber.fy
new file mode 100644
index 0000000..7c3ccdc
--- /dev/null
+++ b/examples/uber.fy
@@ -0,0 +1,386 @@
+#*
+ * Student Score Report — Fype uber-example
+ *
+ * Analyses a class of ten exam scores (0-100) and produces a brief
+ * statistical summary. Every Fype language feature is exercised in
+ * service of the analysis; all assertions must pass for the script
+ * to exit cleanly.
+ *#
+
+# ─── DATASET ───────────────────────────────────────────────────────────────
+# Ten student exam scores. We will compute sum, average, band counts, etc.
+my scores = [72, 45, 89, 91, 55, 78, 63, 100, 48, 82];
+my N = 10; # number of students
+my PASS = 60; # minimum score for a pass
+my DIST = 80; # minimum score for a distinction
+
+# ─── 1. COMMENTS ───────────────────────────────────────────────────────────
+
+# Single-line comment — ignored.
+#* Block comment — also ignored. *#
+
+# Inline block comment inside an expression — the #* *# part is discarded:
+my ok = 1 #* invisible *# + 0;
+assert 1 == ok;
+
+# ─── 2. BASIC ARITHMETIC AND VARIABLES ─────────────────────────────────────
+
+# Multiple declarations on one line; band defaults to 0.
+my a = 10, b = 3, band;
+assert 0 == say band;
+assert 13 == say a + b;
+assert 7 == say a - b;
+assert 30 == say a * b;
+assert 3 == say a / b; # integer division truncates toward zero
+assert 10 == say 2 * (4 + 2) - 2;
+assert 10 == say (8 / 2) + 2 * 3;
+
+# Assignment is also an expression that returns the new value.
+assert 15 == (a = 15);
+assert 15 == say a;
+
+# ─── 3. NEGATION AND NOT ───────────────────────────────────────────────────
+
+assert 5 == say neg neg 5;
+assert 0 == say neg neg 0;
+assert 1 == say not 0;
+assert 0 == say not 1;
+
+# Temporarily penalise the first score by 5, then restore it.
+my s0 = scores[0]; # 72
+s0 = s0 - 5;
+assert 67 == say s0;
+s0 = s0 + 5;
+assert 72 == say s0;
+
+# ─── 4. INCREMENT / DECREMENT ──────────────────────────────────────────────
+
+# Used as statements:
+my tally = 0;
+incr tally; incr tally; incr tally;
+assert 3 == say tally;
+decr tally;
+assert 2 == say tally;
+
+# Used as expressions (return the new value):
+my step = 0;
+assert 1 == say incr step;
+assert 0 == say decr step;
+
+# ─── 5. TYPE CONVERSION ────────────────────────────────────────────────────
+
+assert 7 == say integer 7.9; # truncates toward zero
+assert 80 == say double 80; # 80.0 compares equal to 80
+assert 14 == say 1 + string 13; # "13" coerced to integer 13
+assert 5 == say "10 pts" / 2; # leading digits extracted first
+
+# ─── 6. STRING ARITHMETIC ──────────────────────────────────────────────────
+
+assert 46 == say "12" + "34"; # "12"->12 + "34"->34 = 46
+assert 1231 == say "1234" - "3"; # 1234 - 3 = 1231
+
+# ─── 7. COMPARISON OPERATORS ───────────────────────────────────────────────
+
+assert 1 == (put scores[0] > PASS); ln; # 72 > 60 => 1
+assert 0 == (put scores[1] > PASS); ln; # 45 > 60 => 0
+assert 1 == (put scores[3] >= DIST); ln; # 91 >= 80 => 1
+assert 1 == (put PASS != DIST); ln;
+assert 0 == (say PASS == DIST);
+assert 1 == (put 3 < 5); assert 0 == (say 5 < 5); ln;
+assert 1 == (put 5 <= 5); assert 0 == (say 6 <= 5); ln;
+
+# ─── 8. BITWISE GRADE FLAGS ────────────────────────────────────────────────
+# Encode quality: bit 0 = passed (>=PASS), bit 1 = distinction (>=DIST).
+
+# Score 91 => passed AND distinction => 0b11 = 3
+my g91 = 0;
+if scores[3] >= PASS { g91 = g91 or 1; }
+if scores[3] >= DIST { g91 = g91 or 2; }
+assert 3 == say g91;
+
+# Score 45 => failed => 0b00 = 0
+my g45 = 0;
+if scores[1] >= PASS { g45 = g45 or 1; }
+assert 0 == say g45;
+
+assert 1 == say (g91 and 1); # extract pass bit from g91
+assert 0 == say (g45 and 1); # extract pass bit from g45
+assert 6 == say (5 xor 3); # 0b101 ^ 0b011 = 0b110 = 6
+assert 4 == say (1 :< 2); # 1 << 2 = 4
+assert 2 == say (8 :> 2); # 8 >> 2 = 2
+
+# ─── 9. CONDITIONALS ───────────────────────────────────────────────────────
+
+# 91 is a distinction
+if scores[3] >= DIST { band = 2; }
+assert 2 == say band;
+
+# 45 is a fail
+ifnot scores[1] >= PASS { band = 0; }
+assert 0 == say band;
+
+if 0 { band = 99; } # must not execute
+ifnot 1 { band = 99; } # must not execute
+assert 0 == say band;
+
+# ─── 10. WHILE + UNTIL: SUM ALL SCORES ─────────────────────────────────────
+# 72+45+89+91+55+78+63+100+48+82 = 723
+
+my total = 0, wi = 0;
+while wi < N {
+ total = total + scores[wi];
+ incr wi;
+}
+assert 723 == say total;
+
+my total2 = 0, ui = 0;
+until ui >= N {
+ total2 = total2 + scores[ui];
+ incr ui;
+}
+assert 723 == say total2;
+
+# ─── 11. LOOP + BREAK + NEXT: COUNT PASSING SCORES ─────────────────────────
+# Scores >= 60: 72,89,91,78,63,100,82 => 7 students
+
+my passing = 0, li = 0;
+loop {
+ if li >= N { break; }
+ if scores[li] < PASS { li = li + 1; next; }
+ incr passing;
+ incr li;
+}
+assert 7 == say passing;
+
+# ─── 12. WHILE + BREAK + NEXT: COUNT DISTINCTIONS ──────────────────────────
+# Scores >= 80: 89,91,100,82 => 4 students
+
+my dists = 0, di = 0;
+while di < N {
+ incr di;
+ if scores[di - 1] < DIST { next; }
+ incr dists;
+}
+assert 4 == say dists;
+
+# ─── 13. DO-WHILE / DO-UNTIL ───────────────────────────────────────────────
+
+# Body runs once even though the condition is already false.
+my dw = 10;
+do { dw = dw + 1; } while dw < 10;
+assert 11 == say dw;
+
+# Accumulate scores until the running total exceeds 500 (runs at least once).
+# After 8 iterations: 72+45+89+91+55+78+63+100 = 593.
+my rsum = 0, ri = 0;
+do {
+ rsum = rsum + scores[ri];
+ incr ri;
+} while rsum < 500;
+assert 593 == say rsum;
+assert 8 == say ri;
+
+# do-until: count down from 3 to 0.
+my cd = 3;
+do { decr cd; } until cd == 0;
+assert 0 == say cd;
+
+# ─── 14. FUNCTIONS ─────────────────────────────────────────────────────────
+
+# Sum the first n elements of an array.
+fun arr_sum(arr, n) {
+ my s = 0, i = 0;
+ while i < n {
+ s = s + arr[i];
+ incr i;
+ }
+ ret s;
+}
+assert 723 == say arr_sum(scores, N);
+
+# Integer average (floor division).
+fun avg(arr, n) {
+ ret arr_sum(arr, n) / n;
+}
+assert 72 == say avg(scores, N);
+
+# Conditional return: grade band (0=fail, 1=pass, 2=distinction).
+fun grade_band(score) {
+ if score >= DIST { ret 2; }
+ if score >= PASS { ret 1; }
+ ret 0;
+}
+assert 2 == say grade_band(91);
+assert 1 == say grade_band(72);
+assert 0 == say grade_band(45);
+
+# Multiple return values: minimum and maximum of an array.
+fun arr_minmax(arr, n) {
+ my mn = arr[0], mx = arr[0], i = 1;
+ while i < n {
+ if arr[i] < mn { mn = arr[i]; }
+ if arr[i] > mx { mx = arr[i]; }
+ incr i;
+ }
+ ret mn, mx; # prints 45 then 100
+}
+say arr_minmax(scores, N);
+
+# Nested function: range check (returns 1 if 0 <= score <= 100).
+fun valid_score(score) {
+ fun in_range(v) {
+ if v >= 0 { if v <= 100 { ret 1; } }
+ ret 0;
+ }
+ ret in_range(score);
+}
+assert 1 == say valid_score(72);
+assert 0 == say valid_score(neg 1);
+assert 0 == defined in_range; # nested function gone after the call
+
+# Old-style zero-arg function (no parentheses).
+fun banner { say "=== Student Score Report ==="; }
+banner;
+
+# Self-undefining one-shot function.
+fun init_once { say "Initialising report..."; undef init_once; }
+init_once;
+assert 0 == defined init_once;
+
+# ─── 15. PROCEDURES ────────────────────────────────────────────────────────
+# Procedures share the caller's scope; mutations are visible to the caller.
+
+my accum = total; # start from the already-computed sum
+proc apply_bonus { accum = accum + 10; }
+apply_bonus; apply_bonus;
+assert 743 == say accum; # 723 + 20
+
+# Variables declared inside a procedure leak into the caller's scope.
+proc make_summary {
+ my summary_pass = passing;
+ my summary_dist = dists;
+}
+make_summary;
+assert 7 == say summary_pass;
+assert 4 == say summary_dist;
+
+# ─── 16. SCOPING ───────────────────────────────────────────────────────────
+
+my outer = 100;
+{
+ my inner = 50;
+ outer = outer + inner;
+ assert 1 == defined inner;
+ scope; # prints all symbols visible here
+}
+assert 150 == say outer;
+assert 0 == defined inner; # inner vanished when the block closed
+
+# Deep nesting: mutate a counter from three levels deep.
+my depth = 0;
+{
+ incr depth;
+ { incr depth; { incr depth; } }
+}
+assert 3 == say depth;
+
+# ─── 17. SYNONYMS / ALIASES ────────────────────────────────────────────────
+
+my best = scores[3]; # 91
+my top = \best; # top is a synonym for best
+assert 91 == say top;
+
+best = 95; # update through the original name
+assert 95 == say top; # synonym reflects the change
+
+assert 2 == syms best;
+undef best;
+assert 1 == syms top;
+assert 0 == defined best;
+assert 1 == defined top;
+undef top;
+
+# Procedure synonym keeps the procedure alive after the original is undefined.
+proc show_band { put "band="; say grade_band(91); }
+my show_band2 = \show_band;
+assert 2 == syms show_band;
+show_band2;
+undef show_band;
+show_band2; # alias still callable
+assert 0 == defined show_band;
+undef show_band2;
+
+# ─── 18. DEFINED / UNDEF ───────────────────────────────────────────────────
+
+my tmp = 42;
+assert 1 == defined tmp;
+assert 0 == defined nosuchvar;
+undef tmp;
+assert 0 == defined tmp;
+
+# ─── 19. ARRAYS — LITERALS, INDEXING, ASSIGNMENT ────────────────────────────
+
+my extra = [5, 10, 15, 20, 25];
+assert 5 == say len extra;
+assert 5 == say extra[0];
+assert 15 == say extra[2];
+
+# Element assignment.
+extra[2] = 99;
+assert 99 == say extra[2];
+
+# Expression-based index.
+my ei = 1;
+assert 10 == say extra[ei];
+assert 99 == say extra[ei + 1];
+
+# ─── 20. ARRAY SLICES ──────────────────────────────────────────────────────
+# scores is [72, 45, 89, 91, 55, 78, 63, 100, 48, 82]
+
+# Half-open slice: indices 2, 3, 4 => [89, 91, 55]
+my mid = scores[2:5];
+assert 3 == say len mid;
+assert 89 == say mid[0];
+assert 55 == say mid[2];
+
+# Slice from start (low bound omitted): first three => [72, 45, 89]
+my first3 = scores[:3];
+assert 3 == say len first3;
+assert 72 == say first3[0];
+assert 89 == say first3[2];
+
+# Slice to end (high bound omitted): from index 7 => [100, 48, 82]
+my tail = scores[7:];
+assert 3 == say len tail;
+assert 100 == say tail[0];
+assert 82 == say tail[2];
+
+# Full shallow copy.
+my copy = scores[:];
+assert 10 == say len copy;
+assert 72 == say copy[0];
+assert 82 == say copy[9];
+
+# ─── 21. I/O ───────────────────────────────────────────────────────────────
+
+put "Total: "; put total; ln;
+put "Average: "; put avg(scores, N); ln;
+put "Passing: "; put passing; ln;
+put "Distincts: "; say dists;
+
+# ─── 22. FORK ──────────────────────────────────────────────────────────────
+# Child process computes the same sum independently; parent waits.
+
+my pid = fork;
+
+if pid {
+ put "Parent: child pid = "; say pid;
+}
+
+ifnot pid {
+ put "Child: score sum = "; say arr_sum(scores, N);
+ exit 0;
+}
+
+# ─── DONE ──────────────────────────────────────────────────────────────────
+say "All assertions passed.";