From bc4f4a5477544dea330ac7e0a401af5c36766876 Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 23:40:36 +0000 Subject: [PATCH] ocaml: phase 5.1 roman.ml baseline + top-level 'let () = expr' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Side-quest emerged from adding roman.ml baseline (Roman numeral greedy encoding): top-level 'let () = expr' was unsupported because ocaml-parse-program's parse-decl-let consumed an ident strictly. Now parse-decl-let recognises a leading '()' as a unit binding and synthesises a __unit_NN name (matching how parse-let already handles inner-let unit patterns). roman.ml exercises: * tuple list literal [(int * string); ...] * recursive pattern match on tuple-cons * String.length + List.fold_left * the new top-level let () support (sanity in a comment, even though the program ends with a bare expression for the test harness) Bumped lib/ocaml/test.sh server timeout 180->360s — the recent surge in test count plus a CPU-contended host was crowding out the sole epoch reaching the deeper smarts. --- lib/ocaml/baseline/expected.json | 1 + lib/ocaml/baseline/roman.ml | 20 ++++++++++++++++++++ lib/ocaml/parser.sx | 11 ++++++++++- lib/ocaml/test.sh | 2 +- plans/ocaml-on-sx.md | 9 +++++++++ 5 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 lib/ocaml/baseline/roman.ml diff --git a/lib/ocaml/baseline/expected.json b/lib/ocaml/baseline/expected.json index 7ddf40cd..86ceac8d 100644 --- a/lib/ocaml/baseline/expected.json +++ b/lib/ocaml/baseline/expected.json @@ -17,6 +17,7 @@ "poly_stack.ml": 5, "queens.ml": 2, "quicksort.ml": 44, + "roman.ml": 44, "sum_squares.ml": 385, "word_count.ml": 3 } diff --git a/lib/ocaml/baseline/roman.ml b/lib/ocaml/baseline/roman.ml new file mode 100644 index 00000000..5dec490d --- /dev/null +++ b/lib/ocaml/baseline/roman.ml @@ -0,0 +1,20 @@ +let to_roman n = + let pairs = [ + (1000, "M"); (900, "CM"); (500, "D"); (400, "CD"); + (100, "C"); (90, "XC"); (50, "L"); (40, "XL"); + (10, "X"); (9, "IX"); (5, "V"); (4, "IV"); (1, "I") + ] in + let rec aux n pairs acc = + match pairs with + | [] -> acc + | (v, s) :: rest -> + if n >= v then aux (n - v) pairs (acc ^ s) + else aux n rest acc + in + aux n pairs "" +;; + +List.fold_left + (fun acc n -> acc + String.length (to_roman n)) + 0 + [1; 4; 9; 14; 49; 99; 444; 1994; 3888] diff --git a/lib/ocaml/parser.sx b/lib/ocaml/parser.sx index 642bc607..c686a257 100644 --- a/lib/ocaml/parser.sx +++ b/lib/ocaml/parser.sx @@ -1147,7 +1147,16 @@ (when (at-kw? "rec") (begin (advance-tok!) (set! reccy true))) (define parse-one! (fn () - (let ((nm (ocaml-tok-value (consume! "ident" nil))) + (let ((nm (cond + ((and (at-op? "(") + (< (+ idx 1) tok-len) + (let ((t1 (nth tokens (+ idx 1)))) + (and (= (ocaml-tok-type t1) "op") + (= (ocaml-tok-value t1) ")")))) + (begin (advance-tok!) (advance-tok!) + (str "__unit_" idx))) + (else + (ocaml-tok-value (consume! "ident" nil))))) (ps (list))) (begin (define collect-params diff --git a/lib/ocaml/test.sh b/lib/ocaml/test.sh index 59e816f5..cdaf806b 100755 --- a/lib/ocaml/test.sh +++ b/lib/ocaml/test.sh @@ -1196,7 +1196,7 @@ cat > "$TMPFILE" << 'EPOCHS' EPOCHS -OUTPUT=$(timeout 180 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) +OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) check() { local epoch="$1" desc="$2" expected="$3" diff --git a/plans/ocaml-on-sx.md b/plans/ocaml-on-sx.md index 1b8ec2b9..1dec9472 100644 --- a/plans/ocaml-on-sx.md +++ b/plans/ocaml-on-sx.md @@ -407,6 +407,15 @@ _Newest first._ binary search tree (`type 'a tree = Leaf | Node of 'a * 'a tree * 'a tree`) with insert + in-order traversal. Tests parametric ADT, recursive match, List.append, List.fold_left. +- 2026-05-08 Phase 5.1 — roman.ml baseline (Roman numeral greedy + encoding). Side-quest: top-level `let () = expr` was unsupported by + ocaml-parse-program — now parse-decl-let recognises `()` as a unit + binding (`__unit_NN` synthetic name), matching the inner-let handling + in parse-let. roman.ml uses recursive pattern match on + `(int * string) list` greedy table + `List.fold_left + String.length` + to compute the cumulative length of 9 encoded numbers (44). + Bumped test.sh server timeout 180→360s for headroom on contended + systems. - 2026-05-08 Phase 4 — `M.(expr)` local-open expression form (+3 tests, 481 total). Implemented in parse-atom-postfix: after consuming `.`, if next token is `(`, parse the inner expression and