#!/usr/bin/env bash # Fast OCaml-on-SX test runner — epoch protocol direct to sx_server.exe. # Mirrors lib/lua/test.sh. # # Usage: # bash lib/ocaml/test.sh # run all tests # bash lib/ocaml/test.sh -v # verbose set -uo pipefail cd "$(git rev-parse --show-toplevel)" SX_SERVER="${SX_SERVER:-hosts/ocaml/_build/default/bin/sx_server.exe}" if [ ! -x "$SX_SERVER" ]; then SX_SERVER="/root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe" fi if [ ! -x "$SX_SERVER" ]; then echo "ERROR: sx_server.exe not found. Run: cd hosts/ocaml && dune build" exit 1 fi VERBOSE="${1:-}" PASS=0 FAIL=0 ERRORS="" TMPFILE=$(mktemp) trap "rm -f $TMPFILE" EXIT cat > "$TMPFILE" << 'EPOCHS' (epoch 1) (load "lib/guest/lex.sx") (load "lib/guest/prefix.sx") (load "lib/guest/pratt.sx") (load "lib/guest/match.sx") (load "lib/guest/hm.sx") (load "lib/ocaml/tokenizer.sx") (load "lib/ocaml/parser.sx") (load "lib/ocaml/eval.sx") (load "lib/ocaml/runtime.sx") (load "lib/ocaml/infer.sx") (load "lib/ocaml/tests/tokenize.sx") (eval "(ocaml-load-stdlib!)") ;; ── empty / eof ──────────────────────────────────────────────── (epoch 100) (eval "(ocaml-test-tok-count \"\")") (epoch 101) (eval "(ocaml-test-tok-type \"\" 0)") ;; ── numbers ──────────────────────────────────────────────────── (epoch 110) (eval "(ocaml-test-tok-type \"42\" 0)") (epoch 111) (eval "(ocaml-test-tok-value \"42\" 0)") (epoch 112) (eval "(ocaml-test-tok-value \"3.14\" 0)") (epoch 113) (eval "(ocaml-test-tok-value \"0xff\" 0)") (epoch 114) (eval "(ocaml-test-tok-value \"1e3\" 0)") (epoch 115) (eval "(ocaml-test-tok-value \"1_000_000\" 0)") (epoch 116) (eval "(ocaml-test-tok-value \"3.14e-2\" 0)") ;; ── identifiers / constructors / keywords ───────────────────── (epoch 120) (eval "(ocaml-test-tok-type \"foo\" 0)") (epoch 121) (eval "(ocaml-test-tok-value \"foo_bar1\" 0)") (epoch 122) (eval "(ocaml-test-tok-type \"Some\" 0)") (epoch 123) (eval "(ocaml-test-tok-value \"Some\" 0)") (epoch 124) (eval "(ocaml-test-tok-type \"let\" 0)") (epoch 125) (eval "(ocaml-test-tok-value \"match\" 0)") (epoch 126) (eval "(ocaml-test-tok-type \"true\" 0)") (epoch 127) (eval "(ocaml-test-tok-value \"false\" 0)") (epoch 128) (eval "(ocaml-test-tok-value \"name'\" 0)") ;; ── strings ──────────────────────────────────────────────────── (epoch 130) (eval "(ocaml-test-tok-type \"\\\"hi\\\"\" 0)") (epoch 131) (eval "(ocaml-test-tok-value \"\\\"hi\\\"\" 0)") (epoch 132) (eval "(ocaml-test-tok-value \"\\\"a\\\\nb\\\"\" 0)") ;; ── chars ────────────────────────────────────────────────────── (epoch 140) (eval "(ocaml-test-tok-type \"'a'\" 0)") (epoch 141) (eval "(ocaml-test-tok-value \"'a'\" 0)") (epoch 142) (eval "(ocaml-test-tok-value \"'\\\\n'\" 0)") ;; ── type variables ───────────────────────────────────────────── (epoch 145) (eval "(ocaml-test-tok-type \"'a\" 0)") (epoch 146) (eval "(ocaml-test-tok-value \"'a\" 0)") ;; ── multi-char operators ─────────────────────────────────────── (epoch 150) (eval "(ocaml-test-tok-value \"->\" 0)") (epoch 151) (eval "(ocaml-test-tok-value \"|>\" 0)") (epoch 152) (eval "(ocaml-test-tok-value \"<-\" 0)") (epoch 153) (eval "(ocaml-test-tok-value \":=\" 0)") (epoch 154) (eval "(ocaml-test-tok-value \"::\" 0)") (epoch 155) (eval "(ocaml-test-tok-value \";;\" 0)") (epoch 156) (eval "(ocaml-test-tok-value \"@@\" 0)") (epoch 157) (eval "(ocaml-test-tok-value \"<>\" 0)") (epoch 158) (eval "(ocaml-test-tok-value \"&&\" 0)") (epoch 159) (eval "(ocaml-test-tok-value \"||\" 0)") ;; ── single-char punctuation ──────────────────────────────────── (epoch 160) (eval "(ocaml-test-tok-value \"+\" 0)") (epoch 161) (eval "(ocaml-test-tok-value \"|\" 0)") (epoch 162) (eval "(ocaml-test-tok-value \";\" 0)") (epoch 163) (eval "(ocaml-test-tok-value \"(\" 0)") (epoch 164) (eval "(ocaml-test-tok-value \"!\" 0)") (epoch 165) (eval "(ocaml-test-tok-value \"@\" 0)") ;; ── comments ─────────────────────────────────────────────────── (epoch 170) (eval "(ocaml-test-tok-count \"(* hi *)\")") (epoch 171) (eval "(ocaml-test-tok-value \"(* c *) 42\" 0)") (epoch 172) (eval "(ocaml-test-tok-count \"(* outer (* inner *) end *) 1\")") (epoch 173) (eval "(ocaml-test-tok-value \"(* outer (* inner *) end *) 1\" 0)") ;; ── compound expressions ─────────────────────────────────────── (epoch 180) (eval "(ocaml-test-tok-count \"let x = 1\")") (epoch 181) (eval "(ocaml-test-tok-type \"let x = 1\" 0)") (epoch 182) (eval "(ocaml-test-tok-value \"let x = 1\" 0)") (epoch 183) (eval "(ocaml-test-tok-type \"let x = 1\" 1)") (epoch 184) (eval "(ocaml-test-tok-value \"let x = 1\" 2)") (epoch 185) (eval "(ocaml-test-tok-value \"let x = 1\" 3)") (epoch 190) (eval "(ocaml-test-tok-count \"match x with | None -> 0 | Some y -> y\")") (epoch 191) (eval "(ocaml-test-tok-value \"fun x -> x + 1\" 2)") (epoch 192) (eval "(ocaml-test-tok-type \"fun x -> x + 1\" 2)") (epoch 193) (eval "(ocaml-test-tok-type \"Some 42\" 0)") (epoch 194) (eval "(ocaml-test-tok-value \"a |> f |> g\" 1)") (epoch 195) (eval "(ocaml-test-tok-value \"x := !y\" 1)") ;; ── Phase 1.parse: parser ────────────────────────────────────── ;; Atoms (epoch 200) (eval "(ocaml-parse \"42\")") (epoch 201) (eval "(ocaml-parse \"3.14\")") (epoch 202) (eval "(ocaml-parse \"\\\"hi\\\"\")") (epoch 203) (eval "(ocaml-parse \"'a'\")") (epoch 204) (eval "(ocaml-parse \"true\")") (epoch 205) (eval "(ocaml-parse \"false\")") (epoch 206) (eval "(ocaml-parse \"x\")") (epoch 207) (eval "(ocaml-parse \"Some\")") (epoch 208) (eval "(ocaml-parse \"()\")") ;; Application (left-assoc) (epoch 210) (eval "(ocaml-parse \"f x\")") (epoch 211) (eval "(ocaml-parse \"f x y\")") (epoch 212) (eval "(ocaml-parse \"f (g x)\")") (epoch 213) (eval "(ocaml-parse \"Some 42\")") ;; Binops with precedence (epoch 220) (eval "(ocaml-parse \"1 + 2\")") (epoch 221) (eval "(ocaml-parse \"a + b * c\")") (epoch 222) (eval "(ocaml-parse \"a * b + c\")") (epoch 223) (eval "(ocaml-parse \"a && b || c\")") (epoch 224) (eval "(ocaml-parse \"a = b\")") (epoch 225) (eval "(ocaml-parse \"a ^ b ^ c\")") (epoch 226) (eval "(ocaml-parse \"a :: b :: []\")") (epoch 227) (eval "(ocaml-parse \"(a + b) * c\")") (epoch 228) (eval "(ocaml-parse \"a |> f |> g\")") (epoch 229) (eval "(ocaml-parse \"x mod 2\")") ;; Prefix (epoch 230) (eval "(ocaml-parse \"-x\")") (epoch 231) (eval "(ocaml-parse \"-1 + 2\")") ;; Tuples & lists (epoch 240) (eval "(ocaml-parse \"(1, 2, 3)\")") (epoch 241) (eval "(ocaml-parse \"[1; 2; 3]\")") (epoch 242) (eval "(ocaml-parse \"[]\")") ;; if / fun / let / let rec (epoch 250) (eval "(ocaml-parse \"if x then 1 else 2\")") (epoch 251) (eval "(ocaml-parse \"if c then x\")") (epoch 252) (eval "(ocaml-parse \"fun x -> x + 1\")") (epoch 253) (eval "(ocaml-parse \"fun x y -> x + y\")") (epoch 254) (eval "(ocaml-parse \"let x = 1 in x\")") (epoch 255) (eval "(ocaml-parse \"let f x = x + 1 in f 2\")") (epoch 256) (eval "(ocaml-parse \"let rec f x = f x in f 1\")") (epoch 257) (eval "(ocaml-parse \"let f x y = x + y in f 1 2\")") ;; begin/end (epoch 260) (eval "(ocaml-parse \"begin 1 + 2 end\")") ;; ── Top-level decls ──────────────────────────────────────────── (epoch 270) (eval "(ocaml-parse-program \"let x = 1\")") (epoch 271) (eval "(ocaml-parse-program \"let x = 1 ;;\")") (epoch 272) (eval "(ocaml-parse-program \"let f x = x + 1\")") (epoch 273) (eval "(ocaml-parse-program \"let rec fact n = if n = 0 then 1 else n * fact (n - 1)\")") (epoch 274) (eval "(ocaml-parse-program \"let x = 1 let y = 2\")") (epoch 275) (eval "(ocaml-parse-program \"1 + 2 ;;\")") (epoch 276) (eval "(ocaml-parse-program \"let x = 1 ;; let y = 2 ;; x + y\")") (epoch 277) (eval "(len (ocaml-parse-program \"let x = 1 ;; let y = 2 ;; x + y\"))") (epoch 278) (eval "(ocaml-parse-program \"\")") ;; ── Match / patterns ─────────────────────────────────────────── (epoch 300) (eval "(ocaml-parse \"match x with | None -> 0 | Some y -> y\")") (epoch 301) (eval "(ocaml-parse \"match x with None -> 0 | Some y -> y\")") (epoch 302) (eval "(ocaml-parse \"match l with | [] -> 0 | h :: t -> 1\")") (epoch 303) (eval "(ocaml-parse \"match p with | (a, b) -> a + b\")") (epoch 304) (eval "(ocaml-parse \"match n with | 0 -> 1 | _ -> n\")") (epoch 305) (eval "(ocaml-parse \"match x with | true -> 1 | false -> 0\")") (epoch 306) (eval "(ocaml-parse \"match x with | Pair (a, b) -> a + b\")") (epoch 307) (eval "(ocaml-parse \"match x with | \\\"hi\\\" -> 1 | _ -> 0\")") (epoch 308) (eval "(ocaml-parse \"match x with | () -> 0\")") ;; ── Sequences (;) ────────────────────────────────────────────── (epoch 320) (eval "(ocaml-parse \"1; 2\")") (epoch 321) (eval "(ocaml-parse \"1; 2; 3\")") (epoch 322) (eval "(ocaml-parse \"(1; 2)\")") (epoch 323) (eval "(ocaml-parse \"begin a; b; c end\")") (epoch 324) (eval "(ocaml-parse \"let x = 1 in x; x\")") (epoch 325) (eval "(ocaml-parse \"if c then (a; b) else c\")") (epoch 326) (eval "(ocaml-parse \"[1; 2; 3]\")") (epoch 327) (eval "(ocaml-parse \"1; 2;\")") (epoch 328) (eval "(ocaml-parse \"begin a; end\")") (epoch 329) (eval "(ocaml-parse \"match x with | _ -> a; b\")") ;; ── Phase 2: evaluator ───────────────────────────────────────── ;; Atoms (epoch 400) (eval "(ocaml-run \"42\")") (epoch 401) (eval "(ocaml-run \"3.14\")") (epoch 402) (eval "(ocaml-run \"true\")") (epoch 403) (eval "(ocaml-run \"false\")") (epoch 404) (eval "(ocaml-run \"\\\"hi\\\"\")") ;; Arithmetic (epoch 410) (eval "(ocaml-run \"1 + 2\")") (epoch 411) (eval "(ocaml-run \"10 - 3\")") (epoch 412) (eval "(ocaml-run \"4 * 5\")") (epoch 413) (eval "(ocaml-run \"20 / 4\")") (epoch 414) (eval "(ocaml-run \"10 mod 3\")") (epoch 415) (eval "(ocaml-run \"2 ** 10\")") (epoch 416) (eval "(ocaml-run \"(1 + 2) * 3\")") (epoch 417) (eval "(ocaml-run \"1 + 2 * 3\")") (epoch 418) (eval "(ocaml-run \"-5 + 10\")") ;; Comparison & boolean (epoch 420) (eval "(ocaml-run \"1 < 2\")") (epoch 421) (eval "(ocaml-run \"3 > 2\")") (epoch 422) (eval "(ocaml-run \"2 = 2\")") (epoch 423) (eval "(ocaml-run \"1 <> 2\")") (epoch 424) (eval "(ocaml-run \"true && false\")") (epoch 425) (eval "(ocaml-run \"true || false\")") (epoch 426) (eval "(ocaml-run \"not false\")") ;; String (epoch 430) (eval "(ocaml-run \"\\\"a\\\" ^ \\\"b\\\"\")") (epoch 431) (eval "(ocaml-run \"\\\"hello\\\" ^ \\\" \\\" ^ \\\"world\\\"\")") ;; Conditional (epoch 440) (eval "(ocaml-run \"if true then 1 else 2\")") (epoch 441) (eval "(ocaml-run \"if 1 > 2 then 100 else 200\")") ;; Let / lambda / app (epoch 450) (eval "(ocaml-run \"let x = 5 in x * 2\")") (epoch 451) (eval "(ocaml-run \"let f x = x + 1 in f 41\")") (epoch 452) (eval "(ocaml-run \"let f x y = x + y in f 3 4\")") (epoch 453) (eval "(ocaml-run \"(fun x -> x * x) 7\")") (epoch 454) (eval "(ocaml-run \"(fun x -> fun y -> x + y) 10 20\")") (epoch 455) (eval "(ocaml-run \"let f = fun x -> x + 1 in f 9\")") ;; Closures capture (epoch 460) (eval "(ocaml-run \"let x = 10 in let f y = x + y in f 5\")") (epoch 461) (eval "(ocaml-run \"let make_adder n = fun x -> n + x in (make_adder 100) 1\")") ;; Recursion (epoch 470) (eval "(ocaml-run \"let rec fact n = if n = 0 then 1 else n * fact (n - 1) in fact 5\")") (epoch 471) (eval "(ocaml-run \"let rec fib n = if n < 2 then n else fib (n - 1) + fib (n - 2) in fib 10\")") (epoch 472) (eval "(ocaml-run \"let rec sum n = if n = 0 then 0 else n + sum (n - 1) in sum 100\")") ;; Sequence (epoch 480) (eval "(ocaml-run \"1; 2; 3\")") (epoch 481) (eval "(ocaml-run \"begin 10 end\")") ;; Programs (top-level decls) (epoch 490) (eval "(ocaml-run-program \"let x = 1;; let y = 2;; x + y\")") (epoch 491) (eval "(ocaml-run-program \"let rec fact n = if n = 0 then 1 else n * fact (n - 1);; fact 6\")") (epoch 492) (eval "(ocaml-run-program \"let inc x = x + 1;; let double x = x * 2;; double (inc 4)\")") ;; Pipe (epoch 495) (eval "(ocaml-run \"let f x = x * 2 in 5 |> f\")") ;; ── Phase 3: ADTs + match (eval) ─────────────────────────────── ;; Constructors (epoch 500) (eval "(ocaml-run \"None\")") (epoch 501) (eval "(ocaml-run \"Some 42\")") (epoch 502) (eval "(ocaml-run \"Some (1, 2)\")") ;; Match — option (epoch 510) (eval "(ocaml-run \"match Some 5 with | None -> 0 | Some y -> y\")") (epoch 511) (eval "(ocaml-run \"match None with | None -> 0 | Some y -> y\")") ;; Match — literals (epoch 520) (eval "(ocaml-run \"match 3 with | 1 -> 100 | 2 -> 200 | _ -> 999\")") (epoch 521) (eval "(ocaml-run \"match true with | true -> 1 | false -> 0\")") (epoch 522) (eval "(ocaml-run \"match \\\"hi\\\" with | \\\"hi\\\" -> 1 | _ -> 0\")") ;; Match — tuples (epoch 530) (eval "(ocaml-run \"match (1, 2) with | (a, b) -> a + b\")") (epoch 531) (eval "(ocaml-run \"match (1, 2, 3) with | (a, b, c) -> a * b * c\")") ;; Match — list cons / nil (epoch 540) (eval "(ocaml-run \"match [1; 2; 3] with | [] -> 0 | h :: _ -> h\")") (epoch 541) (eval "(ocaml-run \"match [] with | [] -> 0 | h :: _ -> h\")") (epoch 542) (eval "(ocaml-run \"match [1; 2; 3] with | [a; b; c] -> a + b + c | _ -> 0\")") (epoch 543) (eval "(ocaml-run \"let rec len lst = match lst with | [] -> 0 | _ :: t -> 1 + len t in len [1; 2; 3; 4; 5]\")") (epoch 544) (eval "(ocaml-run \"let rec sum lst = match lst with | [] -> 0 | h :: t -> h + sum t in sum [1; 2; 3; 4; 5]\")") ;; Match — wildcard + var (epoch 550) (eval "(ocaml-run \"match 99 with | _ -> 1\")") (epoch 551) (eval "(ocaml-run \"match 99 with | x -> x + 1\")") ;; Constructors with tuple args (epoch 560) (eval "(ocaml-run \"match Pair (1, 2) with | Pair (a, b) -> a * b\")") ;; ── References (ref / ! / :=) ────────────────────────────────── (epoch 600) (eval "(ocaml-run \"let r = ref 5 in !r\")") (epoch 601) (eval "(ocaml-run \"let r = ref 5 in r := 10; !r\")") (epoch 602) (eval "(ocaml-run \"let r = ref 0 in r := !r + 1; r := !r + 1; !r\")") (epoch 603) (eval "(ocaml-run \"let r = ref 100 in let f x = r := !r + x in f 5; f 10; !r\")") (epoch 604) (eval "(ocaml-run \"let r = ref \\\"a\\\" in r := \\\"b\\\"; !r\")") (epoch 605) (eval "(ocaml-run \"let count = ref 0 in let rec loop n = if n = 0 then !count else (count := !count + n; loop (n - 1)) in loop 5\")") ;; ── for / while loops ────────────────────────────────────────── (epoch 620) (eval "(ocaml-run \"let s = ref 0 in for i = 1 to 5 do s := !s + i done; !s\")") (epoch 621) (eval "(ocaml-run \"let s = ref 0 in for i = 5 downto 1 do s := !s + i done; !s\")") (epoch 622) (eval "(ocaml-run \"let i = ref 0 in let s = ref 0 in while !i < 5 do i := !i + 1; s := !s + !i done; !s\")") (epoch 623) (eval "(ocaml-run \"let s = ref 0 in for i = 1 to 100 do s := !s + i done; !s\")") (epoch 624) (eval "(ocaml-run \"let p = ref 1 in for i = 1 to 5 do p := !p * i done; !p\")") ;; ── function (sugar for fun + match) ─────────────────────────── (epoch 640) (eval "(ocaml-run \"(function | None -> 0 | Some x -> x) (Some 7)\")") (epoch 641) (eval "(ocaml-run \"let f = function | None -> 0 | Some x -> x in f None\")") (epoch 642) (eval "(ocaml-run \"let rec len = function | [] -> 0 | _ :: t -> 1 + len t in len [1; 2; 3]\")") (epoch 643) (eval "(ocaml-run-program \"let rec map f = function | [] -> [] | h :: t -> f h :: map f t;; map (fun x -> x * x) [1; 2; 3; 4]\")") ;; ── try / with / raise ───────────────────────────────────────── (epoch 660) (eval "(ocaml-run \"try 1 + 2 with | _ -> 0\")") (epoch 661) (eval "(ocaml-run \"try raise (Foo 5) with | Foo x -> x | Bar -> 99\")") (epoch 662) (eval "(ocaml-run \"try raise Bar with | Foo x -> x | Bar -> 99\")") (epoch 663) (eval "(ocaml-run \"try failwith \\\"oops\\\" with | Failure msg -> msg\")") (epoch 664) (eval "(ocaml-run \"try (raise (Foo 1); 999) with | Foo x -> x + 100\")") (epoch 665) (eval "(ocaml-run \"let f x = if x < 0 then raise (NegArg x) else x * 2 in try f (-5) with | NegArg n -> n\")") ;; ── Phase 4: Modules + field access ──────────────────────────── (epoch 700) (eval "(ocaml-parse \"M.x\")") (epoch 701) (eval "(ocaml-parse \"r.field\")") (epoch 702) (eval "(ocaml-parse \"M.M2.x\")") (epoch 703) (eval "(ocaml-parse \"f r.x\")") (epoch 710) (eval "(ocaml-run-program \"module M = struct let x = 42 end ;; M.x\")") (epoch 711) (eval "(ocaml-run-program \"module M = struct let f x = x + 1 end ;; M.f 41\")") (epoch 712) (eval "(ocaml-run-program \"module M = struct let x = 1 let y = 2 end ;; M.x + M.y\")") (epoch 713) (eval "(ocaml-run-program \"module Math = struct let pi = 3.14 let square x = x * x end ;; Math.square 5\")") (epoch 714) (eval "(ocaml-run-program \"module Outer = struct module Inner = struct let v = 99 end end ;; Outer.Inner.v\")") (epoch 715) (eval "(ocaml-run-program \"module M = struct let rec fact n = if n = 0 then 1 else n * fact (n - 1) end ;; M.fact 5\")") (epoch 716) (eval "(ocaml-run-program \"module Pair = struct let make a b = (a, b) let swap p = match p with | (x, y) -> (y, x) end ;; Pair.swap (Pair.make 1 2)\")") ;; ── open / include ───────────────────────────────────────────── (epoch 730) (eval "(ocaml-run-program \"module M = struct let x = 42 let f y = y + 1 end ;; open M ;; f x\")") (epoch 731) (eval "(ocaml-run-program \"module Math = struct let pi = 3 let sq x = x * x end ;; module Sphere = struct include Math let area r = 4 * pi * sq r end ;; Sphere.area 2\")") (epoch 732) (eval "(ocaml-run-program \"module M = struct let x = 1 end ;; module N = struct open M let y = x + 10 end ;; N.y\")") (epoch 733) (eval "(ocaml-run-program \"module Math = struct let pi = 3 let sq x = x * x end ;; module Sphere = struct include Math let area r = 4 * pi * sq r end ;; Sphere.pi\")") (epoch 734) (eval "(ocaml-run-program \"module M = struct let x = 1 let y = 2 end ;; module N = struct include M let z = x + y end ;; N.z\")") ;; ── Functors ─────────────────────────────────────────────────── (epoch 750) (eval "(ocaml-run-program \"module Add (M) = struct let add x = x + M.n end ;; module Five = struct let n = 5 end ;; module AddFive = Add(Five) ;; AddFive.add 10\")") (epoch 751) (eval "(ocaml-run-program \"module M = struct let x = 1 end ;; module N = M ;; N.x\")") (epoch 752) (eval "(ocaml-run-program \"module Outer = struct module Inner = struct let v = 42 end end ;; module Alias = Outer.Inner ;; Alias.v\")") (epoch 753) (eval "(ocaml-run-program \"module Pair (A) (B) = struct let mk = (A.x, B.x) end ;; module One = struct let x = 1 end ;; module Two = struct let x = 2 end ;; module P = Pair(One)(Two) ;; P.mk\")") (epoch 754) (eval "(ocaml-run-program \"module Identity (M) = struct include M end ;; module Base = struct let v = 99 end ;; module Same = Identity(Base) ;; Same.v\")") ;; ── Phase 6: stdlib slice (List, Option, Result) ─────────────── (epoch 800) (eval "(ocaml-run \"List.length [1; 2; 3; 4]\")") (epoch 801) (eval "(ocaml-run \"List.length []\")") (epoch 802) (eval "(ocaml-run \"List.map (fun x -> x * 2) [1; 2; 3]\")") (epoch 803) (eval "(ocaml-run \"List.filter (fun x -> x > 2) [1; 2; 3; 4; 5]\")") (epoch 804) (eval "(ocaml-run \"List.fold_left (fun a b -> a + b) 0 [1; 2; 3; 4; 5]\")") (epoch 805) (eval "(ocaml-run \"List.fold_right (fun x acc -> x :: acc) [1; 2; 3] []\")") (epoch 806) (eval "(ocaml-run \"List.rev [1; 2; 3]\")") (epoch 807) (eval "(ocaml-run \"List.append [1; 2] [3; 4]\")") (epoch 808) (eval "(ocaml-run \"List.mem 3 [1; 2; 3]\")") (epoch 809) (eval "(ocaml-run \"List.mem 99 [1; 2; 3]\")") (epoch 810) (eval "(ocaml-run \"List.for_all (fun x -> x > 0) [1; 2; 3]\")") (epoch 811) (eval "(ocaml-run \"List.exists (fun x -> x > 2) [1; 2; 3]\")") (epoch 812) (eval "(ocaml-run \"List.hd [10; 20; 30]\")") (epoch 813) (eval "(ocaml-run \"List.nth [10; 20; 30] 1\")") (epoch 820) (eval "(ocaml-run \"Option.map (fun x -> x + 1) (Some 41)\")") (epoch 821) (eval "(ocaml-run \"Option.map (fun x -> x + 1) None\")") (epoch 822) (eval "(ocaml-run \"Option.value (Some 7) 0\")") (epoch 823) (eval "(ocaml-run \"Option.value None 42\")") (epoch 824) (eval "(ocaml-run \"Option.is_some (Some 1)\")") (epoch 825) (eval "(ocaml-run \"Option.is_none None\")") (epoch 830) (eval "(ocaml-run \"Result.map (fun x -> x + 1) (Ok 5)\")") (epoch 831) (eval "(ocaml-run \"Result.is_ok (Ok 1)\")") (epoch 832) (eval "(ocaml-run \"Result.is_error (Error \\\"oops\\\")\")") ;; ── let ... and ... mutual recursion ────────────────────────── (epoch 850) (eval "(ocaml-run-program \"let rec even n = if n = 0 then true else odd (n - 1) and odd n = if n = 0 then false else even (n - 1);; even 10\")") (epoch 851) (eval "(ocaml-run-program \"let rec even n = if n = 0 then true else odd (n - 1) and odd n = if n = 0 then false else even (n - 1);; odd 7\")") (epoch 852) (eval "(ocaml-run-program \"let x = 1 and y = 2;; x + y\")") ;; ── Phase 5: Hindley-Milner type inference ──────────────────── (epoch 900) (eval "(ocaml-type-of \"42\")") (epoch 901) (eval "(ocaml-type-of \"true\")") (epoch 902) (eval "(ocaml-type-of \"\\\"hi\\\"\")") (epoch 903) (eval "(ocaml-type-of \"1 + 2\")") (epoch 904) (eval "(ocaml-type-of \"fun x -> x + 1\")") (epoch 905) (eval "(ocaml-type-of \"fun x -> x\")") (epoch 906) (eval "(ocaml-type-of \"fun x y -> x + y\")") (epoch 907) (eval "(ocaml-type-of \"let f x = x + 1 in f 10\")") (epoch 908) (eval "(ocaml-type-of \"let id = fun x -> x in id 5\")") (epoch 909) (eval "(ocaml-type-of \"let id = fun x -> x in id true\")") (epoch 910) (eval "(ocaml-type-of \"if true then 1 else 2\")") (epoch 911) (eval "(ocaml-type-of \"fun f -> fun x -> f (f x)\")") (epoch 912) (eval "(ocaml-type-of \"fun b -> if b then 1 else 0\")") (epoch 913) (eval "(ocaml-type-of \"not true\")") ;; ── Phase 6 expanded: String / Char / Int / Float modules ───── (epoch 950) (eval "(ocaml-run \"String.length \\\"hello\\\"\")") (epoch 951) (eval "(ocaml-run \"String.uppercase_ascii \\\"hi\\\"\")") (epoch 952) (eval "(ocaml-run \"String.lowercase_ascii \\\"HI\\\"\")") (epoch 953) (eval "(ocaml-run \"String.sub \\\"hello\\\" 1 3\")") (epoch 954) (eval "(ocaml-run \"String.starts_with \\\"he\\\" \\\"hello\\\"\")") (epoch 955) (eval "(ocaml-run \"String.concat \\\",\\\" [\\\"a\\\"; \\\"b\\\"; \\\"c\\\"]\")") (epoch 960) (eval "(ocaml-run \"Char.code \\\"A\\\"\")") (epoch 961) (eval "(ocaml-run \"Char.chr 65\")") (epoch 970) (eval "(ocaml-run \"Int.to_string 42\")") (epoch 971) (eval "(ocaml-run \"Int.of_string \\\"123\\\"\")") (epoch 972) (eval "(ocaml-run \"Int.abs (-5)\")") (epoch 973) (eval "(ocaml-run \"Int.max 7 3\")") (epoch 974) (eval "(ocaml-run \"Int.min 7 3\")") EPOCHS OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) check() { local epoch="$1" desc="$2" expected="$3" local actual actual=$(echo "$OUTPUT" | grep -A1 "^(ok-len $epoch " | tail -1) if [ -z "$actual" ]; then actual=$(echo "$OUTPUT" | grep "^(ok $epoch " || true) fi if [ -z "$actual" ]; then actual=$(echo "$OUTPUT" | grep "^(error $epoch " || true) fi if [ -z "$actual" ]; then actual="" fi if echo "$actual" | grep -qF -- "$expected"; then PASS=$((PASS + 1)) [ "$VERBOSE" = "-v" ] && echo " ok $desc" else FAIL=$((FAIL + 1)) ERRORS+=" FAIL $desc (epoch $epoch) expected: $expected actual: $actual " fi } # empty / eof check 100 "empty tokens length" '1' check 101 "empty first is eof" '"eof"' # numbers check 110 "int type" '"number"' check 111 "int value" '42' check 112 "float value" '3.14' check 113 "hex value" '255' check 114 "exponent" '1000' check 115 "underscored int" '1000000' check 116 "neg exponent" '0.0314' # idents / ctors / keywords check 120 "ident type" '"ident"' check 121 "ident value" '"foo_bar1"' check 122 "ctor type" '"ctor"' check 123 "ctor value" '"Some"' check 124 "let keyword type" '"keyword"' check 125 "match keyword value" '"match"' check 126 "true is keyword" '"keyword"' check 127 "false value" '"false"' check 128 "primed ident" "\"name'\"" # strings check 130 "string type" '"string"' check 131 "string value" '"hi"' check 132 "escape sequence" '"a' # chars check 140 "char type" '"char"' check 141 "char value" '"a"' check 142 "char escape" '"' # tyvars check 145 "tyvar type" '"tyvar"' check 146 "tyvar value" '"a"' # multi-char ops check 150 "->" '"->"' check 151 "|>" '"|>"' check 152 "<-" '"<-"' check 153 ":=" '":="' check 154 "::" '"::"' check 155 ";;" '";;"' check 156 "@@" '"@@"' check 157 "<>" '"<>"' check 158 "&&" '"&&"' check 159 "||" '"||"' # single ops check 160 "+" '"+"' check 161 "|" '"|"' check 162 ";" '";"' check 163 "(" '"("' check 164 "!" '"!"' check 165 "@" '"@"' # comments check 170 "block comment alone -> eof" '1' check 171 "num after block comment" '42' check 172 "nested comment count" '2' check 173 "nested comment value" '1' # compound check 180 "let x = 1 count" '5' check 181 "let is keyword" '"keyword"' check 182 "let value" '"let"' check 183 "x is ident" '"ident"' check 184 "= value" '"="' check 185 "1 value" '1' check 190 "match expr count" '13' check 191 "fun -> arrow value" '"->"' check 192 "fun -> arrow type" '"op"' check 193 "Some is ctor" '"ctor"' check 194 "first |> value" '"|>"' check 195 "ref assign :=" '":="' # ── Parser tests ──────────────────────────────────────────────── check 200 "parse int" '("int" 42)' check 201 "parse float" '("float" 3.14)' check 202 "parse string" '("string" "hi")' check 203 "parse char" '("char" "a")' check 204 "parse true" '("bool" true)' check 205 "parse false" '("bool" false)' check 206 "parse var" '("var" "x")' check 207 "parse ctor" '("con" "Some")' check 208 "parse unit" '("unit")' check 210 "parse f x" '("app" ("var" "f") ("var" "x"))' check 211 "parse f x y left-assoc" '("app" ("app" ("var" "f") ("var" "x")) ("var" "y"))' check 212 "parse f (g x)" '("app" ("var" "f") ("app" ("var" "g") ("var" "x")))' check 213 "parse Some 42" '("app" ("con" "Some") ("int" 42))' check 220 "parse 1+2" '("op" "+" ("int" 1) ("int" 2))' check 221 "parse a + b * c prec" '("op" "+" ("var" "a") ("op" "*"' check 222 "parse a*b + c prec" '("op" "+" ("op" "*"' check 223 "parse && / || prec" '("op" "||" ("op" "&&"' check 224 "parse a = b" '("op" "=" ("var" "a") ("var" "b"))' check 225 "parse ^ right-assoc" '("op" "^" ("var" "a") ("op" "^"' check 226 "parse :: right-assoc" '("op" "::" ("var" "a") ("op" "::"' check 227 "parse parens override" '("op" "*" ("op" "+"' check 228 "parse |> chain" '("op" "|>" ("op" "|>"' check 229 "parse mod kw-binop" '("op" "mod" ("var" "x") ("int" 2))' check 230 "parse -x" '("neg" ("var" "x"))' check 231 "parse -1+2" '("op" "+" ("neg" ("int" 1)) ("int" 2))' check 240 "parse tuple" '("tuple" ("int" 1) ("int" 2) ("int" 3))' check 241 "parse list literal" '("list" ("int" 1) ("int" 2) ("int" 3))' check 242 "parse []" '("list")' check 250 "parse if/then/else" '("if" ("var" "x") ("int" 1) ("int" 2))' check 251 "parse if w/o else" '("if" ("var" "c") ("var" "x") ("unit"))' check 252 "parse fun x -> ..." '("fun" ("x") ("op" "+" ("var" "x") ("int" 1)))' check 253 "parse fun x y ->" '("fun" ("x" "y")' check 254 "parse let x = 1 in x" '("let" "x" () ("int" 1) ("var" "x"))' check 255 "parse let f x =" '("let" "f" ("x") ("op" "+"' check 256 "parse let rec f x =" '("let-rec" "f" ("x")' check 257 "parse let f x y =" '("let" "f" ("x" "y")' check 260 "parse begin/end" '("op" "+" ("int" 1) ("int" 2))' # ── Top-level decls ───────────────────────────────────────────── check 270 "program: let x = 1" '("program" ("def" "x" () ("int" 1)))' check 271 "program: let x = 1 ;;" '("program" ("def" "x" () ("int" 1)))' check 272 "program: let f x = x+1" '("program" ("def" "f" ("x") ("op" "+"' check 273 "program: let rec fact" '("def-rec" "fact" ("n")' check 274 "program: two decls" '("def" "x" () ("int" 1)) ("def" "y"' check 275 "program: bare expr" '("program" ("expr" ("op" "+" ("int" 1) ("int" 2))))' check 276 "program: mixed decls + expr" '("def" "y" () ("int" 2)) ("expr"' check 277 "program: 4 forms incl head" '4' check 278 "program: empty" '("program")' # ── Match / patterns ──────────────────────────────────────────── check 300 "match Some/None" '("match" ("var" "x") (("case" ("pcon" "None") ("int" 0)) ("case" ("pcon" "Some" ("pvar" "y")) ("var" "y")))' check 301 "match no leading bar" '("match" ("var" "x") (("case" ("pcon" "None") ("int" 0)) ("case" ("pcon" "Some"' check 302 "match list cons" '("case" ("plist") ("int" 0)) ("case" ("pcons" ("pvar" "h") ("pvar" "t")) ("int" 1))' check 303 "match tuple pat" '("ptuple" ("pvar" "a") ("pvar" "b"))' check 304 "match int + wildcard" '("case" ("plit" ("int" 0)) ("int" 1)) ("case" ("pwild")' check 305 "match bool literals" '("plit" ("bool" true))' check 306 "match ctor with tuple arg" '("pcon" "Pair" ("pvar" "a") ("pvar" "b"))' check 307 "match string literal" '("plit" ("string" "hi"))' check 308 "match unit pattern" '("plit" ("unit"))' # ── Sequences ─────────────────────────────────────────────────── check 320 "seq 1;2" '("seq" ("int" 1) ("int" 2))' check 321 "seq 1;2;3" '("seq" ("int" 1) ("int" 2) ("int" 3))' check 322 "seq in parens" '("seq" ("int" 1) ("int" 2))' check 323 "seq in begin/end" '("seq" ("var" "a") ("var" "b") ("var" "c"))' check 324 "let body absorbs seq" '("let" "x" () ("int" 1) ("seq" ("var" "x") ("var" "x")))' check 325 "if-branch parens for seq" '("if" ("var" "c") ("seq" ("var" "a") ("var" "b"))' check 326 "list ; is separator" '("list" ("int" 1) ("int" 2) ("int" 3))' check 327 "trailing ; OK" '("seq" ("int" 1) ("int" 2))' check 328 "begin a; end singleton seq" '("seq" ("var" "a"))' check 329 "match clause body absorbs ;" '("case" ("pwild") ("seq" ("var" "a") ("var" "b")))' # ── Phase 2: evaluator ────────────────────────────────────────── # atoms check 400 "eval int" '42' check 401 "eval float" '3.14' check 402 "eval true" 'true' check 403 "eval false" 'false' check 404 "eval string" '"hi"' # arithmetic check 410 "eval 1+2" '3' check 411 "eval 10-3" '7' check 412 "eval 4*5" '20' check 413 "eval 20/4" '5' check 414 "eval 10 mod 3" '1' check 415 "eval 2 ** 10" '1024' check 416 "eval (1+2)*3" '9' check 417 "eval 1+2*3 prec" '7' check 418 "eval -5+10" '5' # comparison & boolean check 420 "eval 1<2" 'true' check 421 "eval 3>2" 'true' check 422 "eval 2=2" 'true' check 423 "eval 1<>2" 'true' check 424 "eval true && false" 'false' check 425 "eval true || false" 'true' check 426 "eval not false" 'true' # string check 430 'eval "a" ^ "b"' '"ab"' check 431 "eval string concat 3" '"hello world"' # conditional check 440 "eval if true 1 else 2" '1' check 441 "eval if 1>2 100 else 200" '200' # let / lambda / app check 450 "eval let x=5 x*2" '10' check 451 "eval let f x = x+1; f 41" '42' check 452 "eval let f x y = x+y; f 3 4" '7' check 453 "eval (fun x -> x*x) 7" '49' check 454 "eval curried lambdas" '30' check 455 "eval named lambda" '10' # closures check 460 "eval closure capture" '15' check 461 "eval make_adder" '101' # recursion check 470 "eval fact 5" '120' check 471 "eval fib 10" '55' check 472 "eval sum 100" '5050' # sequence check 480 "eval 1; 2; 3 → 3" '3' check 481 "eval begin 10 end" '10' # programs check 490 "run-prog x+y" '3' check 491 "run-prog fact 6" '720' check 492 "run-prog inc + double" '10' # pipe check 495 "eval x |> f" '10' # ── Phase 3: ADTs + match (eval) ──────────────────────────────── # constructors check 500 "eval None" '("None")' check 501 "eval Some 42" '("Some" 42)' check 502 "eval Pair tuple-arg" '("Some" 1 2)' # option match check 510 "match Some 5 -> 5" '5' check 511 "match None -> 0" '0' # literal match check 520 "match 3 -> _ -> 999" '999' check 521 "match bool true" '1' check 522 "match string lit" '1' # tuple match check 530 "match (1,2)" '3' check 531 "match (1,2,3)" '6' # list match check 540 "match list cons head" '1' check 541 "match empty list" '0' check 542 "match list literal pat" '6' check 543 "match recursive len" '5' check 544 "match recursive sum" '15' # wildcard + var check 550 "match _ -> 1" '1' check 551 "match x -> x+1" '100' # ctor with tuple arg check 560 "Pair(a,b) → a*b" '2' # ── References ────────────────────────────────────────────────── check 600 "deref new ref" '5' check 601 ":= then deref" '10' check 602 "increment cell twice" '2' check 603 "ref captured by closure" '115' check 604 "ref of string" '"b"' check 605 "ref + recursion" '15' # ── for / while ───────────────────────────────────────────────── check 620 "for 1..5 sum" '15' check 621 "for 5 downto 1 sum" '15' check 622 "while loop" '15' check 623 "for 1..100 sum" '5050' check 624 "for 1..5 product = 120" '120' # ── function ──────────────────────────────────────────────────── check 640 "function None|Some Some 7" '7' check 641 "function None=0" '0' check 642 "rec function len" '3' check 643 "rec function map x*x" '(1 4 9 16)' # ── try / with / raise ────────────────────────────────────────── check 660 "try success" '3' check 661 "try Foo caught" '5' check 662 "try Bar caught" '99' check 663 "try failwith" '"oops"' check 664 "try sequence raises" '101' check 665 "raise from function" '-5' # ── Phase 4: Modules + field access ───────────────────────────── check 700 "parse M.x" '("field" ("con" "M") "x")' check 701 "parse r.field" '("field" ("var" "r") "field")' check 702 "parse M.M2.x left-assoc" '("field" ("field" ("con" "M") "M2") "x")' check 703 "parse f r.x bind tighter" '("app" ("var" "f") ("field" ("var" "r") "x"))' check 710 "module M.x = 42" '42' check 711 "module M.f 41 = 42" '42' check 712 "module two values" '3' check 713 "module fn: square 5" '25' check 714 "nested module Outer.Inner" '99' check 715 "module rec fact 5" '120' check 716 "module Pair.swap" '("tuple" 2 1)' # ── open / include ────────────────────────────────────────────── check 730 "open M; f x" '43' check 731 "include Math; area" '48' check 732 "module open inside" '11' check 733 "Sphere.pi via include" '3' check 734 "include M; N.z = x+y" '3' # ── Functors ──────────────────────────────────────────────────── check 750 "functor app Add(Five).add 10" '15' check 751 "module alias N = M" '1' check 752 "submodule alias" '42' check 753 "multi-param functor" '("tuple" 1 2)' check 754 "Identity functor + include" '99' # ── Phase 6: stdlib slice ─────────────────────────────────────── # List check 800 "List.length [1..4]" '4' check 801 "List.length []" '0' check 802 "List.map x*2 [1;2;3]" '(2 4 6)' check 803 "List.filter > 2" '(3 4 5)' check 804 "List.fold_left + 0 [1..5]" '15' check 805 "List.fold_right ::" '(1 2 3)' check 806 "List.rev" '(3 2 1)' check 807 "List.append" '(1 2 3 4)' check 808 "List.mem 3" 'true' check 809 "List.mem 99" 'false' check 810 "List.for_all >0" 'true' check 811 "List.exists >2" 'true' check 812 "List.hd" '10' check 813 "List.nth idx 1" '20' # Option check 820 "Option.map Some" '("Some" 42)' check 821 "Option.map None" '("None")' check 822 "Option.value Some" '7' check 823 "Option.value None" '42' check 824 "Option.is_some" 'true' check 825 "Option.is_none" 'true' # Result check 830 "Result.map Ok" '("Ok" 6)' check 831 "Result.is_ok" 'true' check 832 "Result.is_error" 'true' # ── let ... and ... mutual recursion ───────────────────────────── check 850 "even 10 (mutual rec)" 'true' check 851 "odd 7 (mutual rec)" 'true' check 852 "let x = 1 and y = 2" '3' # ── Phase 5: Hindley-Milner type inference ──────────────────── check 900 "type 42 = Int" '"Int"' check 901 "type true = Bool" '"Bool"' check 902 'type string lit' '"String"' check 903 "type 1+2 = Int" '"Int"' check 904 "type fun x->x+1 = Int->Int" '"Int -> Int"' check 905 "type fun x->x = poly" ' -> ' check 906 "type fun x y->x+y" '"Int -> Int -> Int"' check 907 "type let f x=x+1 in f 10" '"Int"' check 908 "type let id; id 5" '"Int"' check 909 "type let id; id true" '"Bool"' check 910 "type if/then/else" '"Int"' check 911 "type twice" ' -> ' check 912 "type bool branch" '"Bool -> Int"' check 913 "type not true" '"Bool"' # ── Phase 6 String / Char / Int ───────────────────────────────── check 950 "String.length" '5' check 951 "String.uppercase_ascii" '"HI"' check 952 "String.lowercase_ascii" '"hi"' check 953 "String.sub" '"ell"' check 954 "String.starts_with" 'true' check 955 "String.concat" '"a,b,c"' check 960 "Char.code A" '65' check 961 "Char.chr 65" '"A"' check 970 "Int.to_string" '"42"' check 971 "Int.of_string" '123' check 972 "Int.abs -5" '5' check 973 "Int.max" '7' check 974 "Int.min" '3' TOTAL=$((PASS + FAIL)) if [ $FAIL -eq 0 ]; then echo "ok $PASS/$TOTAL OCaml-on-SX tests passed" else echo "FAIL $PASS/$TOTAL passed, $FAIL failed:" echo "" echo "$ERRORS" fi [ $FAIL -eq 0 ]