#* * Examples of how to use bitwise operators *# # Prints "01\n" assert 0 == (put 1 and 0); assert 1 == (say 1 and 1); # Prints "01\n" assert 0 == (put 0 or 0); assert 1 == (say 0 or 1); # Prints "01\n" assert 0 == (put 1 xor 1); assert 1 == (say 1 xor 0); # Prints "82\n" assert 8 == (put 2 :< 2); assert 2 == (say 8 :> 2); # A bit more complex, prints "9\n" assert 9 == (say 1 :< 5 :> 5 or 2 and 5 xor 8); # Same result, but with parenthesis: assert 9 == (say ((((1 :< 5) :> 5) or 2) and 5) xor 8); # Different parenthesis, different result: "1\n" assert 1 == (say 1 :< 5 :> 5 or 2 and (5 xor 8)); # Prints "-1" assert (neg 1) == (say neg not 0); # break exits the while loop early when i reaches 5 my i = 0; while i < 10 { i = i + 1; if i == 5 { break; } } assert 5 == say i; # expected: 5 # next skips adding j when j == 3, so sum = 1+2+4+5 = 12 my sum = 0; my j = 0; while j < 5 { j = j + 1; if j == 3 { next; } sum = sum + j; } assert 12 == say sum; # expected: 12 # break inside an until loop stops when k reaches 7 my k = 0; until k == 10 { k = k + 1; if k == 7 { break; } } assert 7 == say k; # expected: 7 #* * Simple examples how to write comments *# # This is a single lined comment say 1 + 1; # This is a comment at the end of the line say 1 #* This is an embedded comment *# + 1; #* This is a multiline comment *# #* * This is * a nicer looking * multiline comment *# #* * Simple conditional tests *# # "0010\n" assert 0 == (put 1 < 1); assert 0 == (put 1 < 0); assert 1 == (put 0 < 1); assert 0 == (say 0 < 0); # "0100\n" assert 0 == (put 1 > 1); assert 1 == (put 1 > 0); assert 0 == (put 0 > 1); assert 0 == (say 0 > 0); # "1001\n" assert 1 == (put 1 == 1); assert 0 == (put 1 == 0); assert 0 == (put 0 == 1); assert 1 == (say 0 == 0); # "0110\n" assert 0 == (put 1 != 1); assert 1 == (put 1 != 0); assert 1 == (put 0 != 1); assert 0 == (say 0 != 0); # "1011\n" assert 1 == (put 1 <= 1); assert 0 == (put 1 <= 0); assert 1 == (put 0 <= 1); assert 1 == (say 0 <= 0); ## "1101\n" assert 1 == (put 1 >= 1); assert 1 == (put 1 >= 0); assert 0 == (put 0 >= 1); assert 1 == (say 0 >= 0); #* * Examples of how to use control statements *# if 1 { say "if 1"; } ifnot 0 == 1 { say "ifnot 0 == 1"; } # Calculate 10! my n = 10, fac = 0; while n > 1 { ifnot fac { fac = 1; } say fac = (fac * n); decr n; } # Count up to 10 n = 0; until n == 10 { say incr n; } #* * Simple expression tests *# # Result 10 assert 10 == say (8 / 2) + 2 * 3; # Result 12 assert 12 == say 2 * (4 + 2); # Result 4 assert 4 == say 2 * (4 / 2); # Result 4 assert 4 == say 2 * (4 / 2); # Result 4 assert 4 == say 2 * (4 / 2); # Result 46 assert 46 == say "12" + "34"; # Result 1231 assert 1231 == say "1234" - "3"; # Result 24 assert "24" == say "2ab" * "12"; # Result 5.0 assert 5 == say "10 bla" / 2; #* * Examples of how to use fork *# my pid = fork; if pid { put "I am the parent process and the child has the pid "; say pid; } ifnot pid { say "I am the child process"; } # Test: function named arguments, explicit ret, and multiple return values # zero-arg function with explicit return fun answer() { ret 42; } assert 42 == say answer(); # single-arg function — factorial with a while loop and ret fun factorial(n) { my result = 1; while n > 1 { result = result * n; decr n; } ret result; } assert 120 == say factorial(5); # two-arg function fun add(a, b) { ret a + b; } assert 8 == say add(3, 5); # conditional return inside if fun absval(n) { if n < 0 { ret neg n; } ret n; } assert 5 == say absval(5); assert 5 == say absval(neg 5); # multiple return values — both land on the caller's stack fun minmax(a, b) { if a < b { ret a, b; } ret b, a; } say minmax(3, 7); # old-style zero-arg function without parens still works fun greet { say "hello"; } greet; #* * Examples of how to use functions *# fun foo { say 1 + a * 3 + b; fun bar { say "Hello i am nested"; } bar; # Calling nested } my a = 2, b = 4; # Create global variables foo; assert 0 == (defined bar); # bar is not available anymore fun baz { say "I am baz"; undef baz; } baz; # Baz deletes itself assert 0 == (defined baz); # baz is not available anymore #* * Simple builtin function tests *# # Print "-20\n" assert (neg 20) == (say neg 20); # Print "30\n" assert 30 == (say 10 - neg 20); # Print "-30\n" assert (neg 30) == (say neg neg neg 10 - neg 20); # Print "Hello\n" put "Hello"; ln; # Exit with exit code 0 exit 10 + 10 - 5 - 15; #* * Simple I/O examples. Currently only output is supported. *# # Print out 10 followed by a newline say 10; # Print out 20 without a newline followed put 20; # Print out a newline ln; # loop — infinite loop, break exits after 5 iterations my i = 0; loop { i = i + 1; if i == 5 { break; } } assert 5 == say i; # expected: 5 # loop with next — skips j==3, so sum = 1+2+4+5 = 12 my sum = 0; my j = 0; loop { j = j + 1; if j > 5 { break; } if j == 3 { next; } sum = sum + j; } assert 12 == say sum; # expected: 12 # do...while — body runs once even though k >= 10 already my k = 10; do { k = k + 1; } while k < 10; assert 11 == say k; # expected: 11 # do...until — stops when m reaches 5 my m = 0; do { m = m + 1; } until m == 5; assert 5 == say m; # expected: 5 #* * Examples of how to use procedures *# proc foo { say 1 + a * 3 + b; my c = 6; } my a = 2, b = 4; foo; # Run the procedure. Print out "11\n" say c; # Print out "6\n"; proc bar { say "I am bar"; undef baz; proc baz { say "I am baz"; } } # Here bar would produce an error because the proc is not yet defined! # bar; bar; # Here the procedure bar will define the procedure baz! baz; # Now the procedure baz is defined! bar; # Here the procedure bar will redefine baz again! #* * Examples of how to use scopeing *# my foo = 1; { # Prints out 1 assert 1 == (put defined foo); { my bar = 2; # Prints out 1 assert 1 == (put defined bar); # Prints out all available symbols at # the current program position. scope; } # Prints out 0 assert 0 == (put defined bar); my baz = 3; } # Prints out 0 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 *# # Create a variable foo, and bar is a synonym for foo my foo = "foo"; my bar = \foo; # Reset the value of foo foo = "bar"; # The synonym variable should now also set to "bar" assert "bar" == say bar; # Create a new procedure baz proc baz { say "I am baz"; } # Make a synonym baz, and undefine baz my bay = \baz; # Should be the num of syms for the same value assert 2 == syms baz; assert 2 == syms bay; undef baz; assert 1 == syms bay; # bay still has a reference of the original procedure baz bay; # this prints aut "I am baz" assert 0 == defined baz; assert 1 == defined bay; # This removes the procedure from memory undef bay; #* * Examples how to convert types *# assert 1 == say 1; # Integer output assert 1 == say double 1; # Double output assert 14 == say 1 + string 13; # Implicit type conversion to Integer assert 2 == say integer 2.8; # Rounds down to the Integer 2 assert say integer double string put say neg 12; # Nonsense but working :) #* * 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."; #* * Examples of how to define variables *# # Defines the variables my foo = 1 + 1; my bar = 4 - 1, baz = 100 + 1, bay; # bay has been initialized with the default value of 0 say bay; # Prints out "5\n" assert 5 == (say foo + bar); # Pritns out "51101\n" assert 51 == (put baz - 50); assert 101 == (say baz); # Change the value of the variable to 99 and print it out assert 99 == (baz = 99); say baz;