summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-28 16:01:10 +0200
committerPaul Buetow <paul@buetow.org>2026-02-28 16:01:10 +0200
commit075bc33d15b4d11fa03f381c3e03437d9f759c22 (patch)
tree67f65db39e0f89b36f5a38189eb4a6245eab65a4 /examples
parent952357132060dd874fc550d35e0e4f8bc61efd87 (diff)
Refactor _process() by extracting per-operator handler functions [SRP]
_process() was a 510-line function with a nested switch(operator) x switch(type) structure. Extracted 17 static helper functions: - _resolve_composite_op(): maps two-token operator pairs (!=, ==, <=, >=, <<, >>) to their canonical single TokenType - _op_assign(): handles variable and array-element assignment - _op_add(), _op_sub(), _op_mult(), _op_div(): arithmetic operators - _op_eq(), _op_neq(), _op_lt(), _op_gt(), _op_le(), _op_ge(): comparison operators (result always TT_INTEGER) - _op_and(), _op_or(), _op_xor(), _op_lshift(), _op_rshift(): bitwise operators (doubles/strings coerced to int) _process() is now a ~70-line dispatcher. Assignment is guarded by `else if` so it only fires when p_token_op2 == NULL, preserving the original semantics exactly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'examples')
-rw-r--r--examples/all-examples.txt589
1 files changed, 325 insertions, 264 deletions
diff --git a/examples/all-examples.txt b/examples/all-examples.txt
index 5349073..0ca0393 100644
--- a/examples/all-examples.txt
+++ b/examples/all-examples.txt
@@ -493,329 +493,390 @@ 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.
+ * 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.
*#
-# ─── 1. COMMENTS ─────────────────────────────────────────────────────────────
+# ─── 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
-# Single-line comment — ignored completely.
+# ─── 1. COMMENTS ───────────────────────────────────────────────────────────
-#*
- * Block comment: also ignored.
- *#
+# Single-line comment — ignored.
+#* Block comment — also ignored. *#
-# Inline block comment inside an expression:
-my commentsok = 1 #* this is ignored *# + 1;
-assert 2 == say commentsok;
+# Inline block comment inside an expression — the #* *# part is discarded:
+my ok = 1 #* invisible *# + 0;
+assert 1 == ok;
-# ─── 2. VARIABLES AND BASIC ARITHMETIC ───────────────────────────────────────
+# ─── 2. BASIC ARITHMETIC AND VARIABLES ─────────────────────────────────────
-# 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
+# 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;
-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 ────────────────────────────────────────────
+# 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 n = 0;
-loop {
- n = n + 1;
- if n == 7 { break; }
+my total2 = 0, ui = 0;
+until ui >= N {
+ total2 = total2 + scores[ui];
+ incr ui;
}
-assert 7 == say n;
+assert 723 == say total2;
+
+# ─── 11. LOOP + BREAK + NEXT: COUNT PASSING SCORES ─────────────────────────
+# Scores >= 60: 72,89,91,78,63,100,82 => 7 students
-# Sum 1..10 skipping multiples of 3: 1+2+4+5+7+8+10 = 37
-my total = 0, step = 0;
+my passing = 0, li = 0;
loop {
- step = step + 1;
- if step > 10 { break; }
- if step / 3 * 3 == step { next; } # divisible by 3
- total = total + step;
+ if li >= N { break; }
+ if scores[li] < PASS { li = li + 1; next; }
+ incr passing;
+ incr li;
}
-assert 37 == say total;
+assert 7 == say passing;
-# ─── 12. WHILE WITH BREAK AND NEXT ───────────────────────────────────────────
+# ─── 12. WHILE + BREAK + NEXT: COUNT DISTINCTIONS ──────────────────────────
+# Scores >= 80: 89,91,100,82 => 4 students
-# 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;
+my dists = 0, di = 0;
+while di < N {
+ incr di;
+ if scores[di - 1] < DIST { next; }
+ incr dists;
}
-assert 31 == say wsum;
+assert 4 == say dists;
-# ─── 13. DO-WHILE / DO-UNTIL ─────────────────────────────────────────────────
+# ─── 13. DO-WHILE / DO-UNTIL ───────────────────────────────────────────────
-# Body runs once even though the condition is already false
+# 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);
+# 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);
-# Conditional return
-fun absval(v) {
- if v < 0 { ret neg v; }
- ret v;
+# Integer average (floor division).
+fun avg(arr, n) {
+ ret arr_sum(arr, n) / n;
}
-assert 7 == say absval(7);
-assert 7 == say absval(neg 7);
+assert 72 == say avg(scores, N);
-# Iterative function with local variables and decr
-fun factorial(num) {
- my result = 1;
- while num > 1 {
- result = result * num;
- decr num;
- }
- ret result;
+# 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 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;
+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 fb;
+ ret mn, mx; # prints 45 then 100
}
-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;
+say arr_minmax(scores, N);
-# 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;
+# 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;
}
-say minmax(3, 7); # prints 3 then 7
+make_summary;
+assert 7 == say summary_pass;
+assert 4 == say summary_dist;
-# ─── 16. SCOPING ─────────────────────────────────────────────────────────────
+# ─── 16. SCOPING ───────────────────────────────────────────────────────────
my outer = 100;
{
- my inner = 200;
+ my inner = 50;
outer = outer + inner;
assert 1 == defined inner;
+ scope; # prints all symbols visible here
}
-assert 300 == say outer;
-assert 0 == defined inner;
+assert 150 == say outer;
+assert 0 == defined inner; # inner vanished when the block closed
-# Variables defined in nested blocks vanish when the block closes
+# Deep nesting: mutate a counter from three levels deep.
my depth = 0;
{
- depth = depth + 1;
- {
- depth = depth + 1;
- { depth = depth + 1; }
- assert 3 == say depth;
- }
+ incr depth;
+ { incr depth; { incr depth; } }
}
assert 3 == say depth;
-# ─── 17. SYNONYMS / ALIASES ──────────────────────────────────────────────────
+# ─── 17. SYNONYMS / ALIASES ────────────────────────────────────────────────
-my orig = 42;
-my alias = \orig;
-assert 42 == say alias; # alias starts with orig's value
+my best = scores[3]; # 91
+my top = \best; # top is a synonym for best
+assert 91 == say top;
-orig = 99;
-assert 99 == say alias; # alias reflects the change
+best = 95; # update through the original name
+assert 95 == say top; # synonym 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;
+assert 2 == syms best;
+undef best;
+assert 1 == syms top;
+assert 0 == defined best;
+assert 1 == defined top;
+undef top;
-# 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;
+# 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 AND UNDEF ───────────────────────────────────────────────────
+# ─── 18. DEFINED / UNDEF ───────────────────────────────────────────────────
-my tmpvar = 5;
-assert 1 == defined tmpvar;
+my tmp = 42;
+assert 1 == defined tmp;
assert 0 == defined nosuchvar;
-undef tmpvar;
-assert 0 == defined tmpvar;
+undef tmp;
+assert 0 == defined tmp;
# ─── 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 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 head = nums[:2]; # first two elements
-assert 2 == say len head;
-assert 10 == say head[0];
-assert 20 == say head[1];
+my pid = fork;
-my tail = nums[3:]; # from index 3 to end
-assert 2 == say len tail;
-assert 40 == say tail[0];
-assert 50 == say tail[1];
+if pid {
+ put "Parent: child pid = "; say pid;
+}
-my cpy = nums[:]; # full shallow copy
-assert 5 == say len cpy;
-assert 10 == say cpy[0];
-assert 50 == say cpy[4];
+ifnot pid {
+ put "Child: score sum = "; say arr_sum(scores, N);
+ exit 0;
+}
+# ─── DONE ──────────────────────────────────────────────────────────────────
say "All assertions passed.";
#*