From 34d518d55583b3dc549deecc9ada6cf5951836c8 Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 9 May 2026 01:11:53 +0000 Subject: [PATCH] ocaml: phase 5.1 frequency.ml baseline + Format module alias (+2 tests, 498 total) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit frequency.ml exercises the recently-added Hashtbl.iter / fold + Hashtbl.find_opt + s.[i] indexing + for-loop together: build a char-count table for 'abracadabra' then take the max via Hashtbl.fold. Expected = 5 (a x 5). Total 25 baseline programs. Format module added as a thin alias of Printf — sprintf, printf, and asprintf all delegate to Printf.sprintf. The dynamic runtime doesn't distinguish boxes/breaks, so format strings work the same as in Printf and most Format-using OCaml programs now compile. --- lib/ocaml/baseline/expected.json | 1 + lib/ocaml/baseline/frequency.ml | 18 ++++++++++++++++++ lib/ocaml/runtime.sx | 9 +++++++++ lib/ocaml/test.sh | 10 ++++++++++ plans/ocaml-on-sx.md | 6 ++++++ 5 files changed, 44 insertions(+) create mode 100644 lib/ocaml/baseline/frequency.ml diff --git a/lib/ocaml/baseline/expected.json b/lib/ocaml/baseline/expected.json index 37aab475..fe38a370 100644 --- a/lib/ocaml/baseline/expected.json +++ b/lib/ocaml/baseline/expected.json @@ -8,6 +8,7 @@ "exception_handle.ml": 4, "expr_eval.ml": 16, "factorial.ml": 3628800, + "frequency.ml": 5, "fizzbuzz.ml": 57, "list_ops.ml": 30, "lambda_calc.ml": 7, diff --git a/lib/ocaml/baseline/frequency.ml b/lib/ocaml/baseline/frequency.ml new file mode 100644 index 00000000..3c6d22ae --- /dev/null +++ b/lib/ocaml/baseline/frequency.ml @@ -0,0 +1,18 @@ +let count_chars s = + let t = Hashtbl.create 8 in + for i = 0 to String.length s - 1 do + let c = s.[i] in + let n = match Hashtbl.find_opt t c with + | Some v -> v + 1 + | None -> 1 + in + Hashtbl.replace t c n + done; + t + +let max_count t = + Hashtbl.fold (fun _ v acc -> if v > acc then v else acc) t 0 + +;; + +max_count (count_chars "abracadabra") diff --git a/lib/ocaml/runtime.sx b/lib/ocaml/runtime.sx index 02bc9597..cd5eea0f 100644 --- a/lib/ocaml/runtime.sx +++ b/lib/ocaml/runtime.sx @@ -455,6 +455,15 @@ let printf fmt = sprintf fmt end ;; + module Format = struct + (* Thin alias of Printf for pretty-printing parity. The dynamic + runtime doesn't distinguish boxes/breaks — fmt strings work + the same as in Printf. *) + let sprintf fmt = Printf.sprintf fmt + let printf fmt = Printf.sprintf fmt + let asprintf fmt = Printf.sprintf fmt + end ;; + module Lazy = struct let force lz = _lazy_force lz end ;; diff --git a/lib/ocaml/test.sh b/lib/ocaml/test.sh index 4092275f..326fa9f1 100755 --- a/lib/ocaml/test.sh +++ b/lib/ocaml/test.sh @@ -1234,6 +1234,12 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 4961) (eval "(ocaml-run \"let counter = ref 0 in let lz = lazy (counter := !counter + 1; 42) in let a = Lazy.force lz in let b = Lazy.force lz in (a + b) * 100 + !counter\")") +;; ── Format alias of Printf ──────────────────────────────────── +(epoch 4970) +(eval "(ocaml-run \"Format.sprintf \\\"%d\\\" 99\")") +(epoch 4971) +(eval "(ocaml-run \"Format.asprintf \\\"%s=%d\\\" \\\"n\\\" 7\")") + EPOCHS OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) @@ -1958,6 +1964,10 @@ check 4951 "Hashtbl.iter ref accum 10+20" '30' check 4960 "lazy 1+2 force" '3' check 4961 "lazy memoization counter=1" '8401' +# ── Format alias ───────────────────────────────────────────────── +check 4970 "Format.sprintf %d" '"99"' +check 4971 "Format.asprintf %s=%d" '"n=7"' + TOTAL=$((PASS + FAIL)) if [ $FAIL -eq 0 ]; then echo "ok $PASS/$TOTAL OCaml-on-SX tests passed" diff --git a/plans/ocaml-on-sx.md b/plans/ocaml-on-sx.md index 66de51c2..0e87915f 100644 --- a/plans/ocaml-on-sx.md +++ b/plans/ocaml-on-sx.md @@ -407,6 +407,12 @@ _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-09 Phase 5.1 — frequency.ml baseline + Format module alias + (+2 tests, 498 total). frequency.ml builds a Hashtbl of char→count + via `Hashtbl.find_opt` + `Hashtbl.replace` inside a `for` loop, then + uses `Hashtbl.fold` to find the maximum count. `count_chars + "abracadabra"` → max is 5 (a×5). Format module added as a thin + alias of Printf — sprintf / printf / asprintf all delegate. - 2026-05-09 Phase 4 — `lazy EXPR` + `Lazy.force` (+2 tests, 496 total). Tokenizer already had `lazy` as a keyword. parse-prefix now emits `(:lazy EXPR)`; eval creates a one-element cell with state