summaryrefslogtreecommitdiff
path: root/examples/uber.fy
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-20 21:53:23 +0200
committerPaul Buetow <paul@buetow.org>2026-02-20 21:53:23 +0200
commit43614694706ac61b2cebef486b7fa9368c78fe6a (patch)
tree06fc10249b5f5e02449d93cf5f52bf80590f1bea /examples/uber.fy
parent03b874818315e7dc9fb2ccf26716a0fb65242a57 (diff)
Add README.md and array slicing support
Diffstat (limited to 'examples/uber.fy')
-rw-r--r--examples/uber.fy386
1 files changed, 386 insertions, 0 deletions
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.";