ocaml: phase 5.1 baseline OCaml programs (5/5 pass) + lookahead boundary
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 33s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 33s
lib/ocaml/baseline/{factorial,list_ops,option_match,module_use,sum_squares}.ml
exercised through ocaml-run-program (file-read F). lib/ocaml/baseline/
run.sh runs them and compares against expected.json — all 5 pass.
To make module_use.ml (with nested let-in) parse, parser's
skip-let-rhs-boundary! now uses has-matching-in? lookahead: a let at
depth 0 in a let-decl rhs opens a nested block IFF a matching in
exists before any decl-keyword. Without that in, the let is a new
top-level decl (preserves test 274 'let x = 1 let y = 2').
This is the first piece of Phase 5.1 'vendor a slice of OCaml
testsuite' — handcrafted fixtures for now, real testsuite TBD.
This commit is contained in:
7
lib/ocaml/baseline/expected.json
Normal file
7
lib/ocaml/baseline/expected.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"factorial.ml": 3628800,
|
||||
"list_ops.ml": 30,
|
||||
"option_match.ml": 5,
|
||||
"module_use.ml": 3,
|
||||
"sum_squares.ml": 385
|
||||
}
|
||||
4
lib/ocaml/baseline/factorial.ml
Normal file
4
lib/ocaml/baseline/factorial.ml
Normal file
@@ -0,0 +1,4 @@
|
||||
(* Baseline: factorial via let-rec *)
|
||||
let rec fact n =
|
||||
if n = 0 then 1 else n * fact (n - 1) ;;
|
||||
fact 10
|
||||
5
lib/ocaml/baseline/list_ops.ml
Normal file
5
lib/ocaml/baseline/list_ops.ml
Normal file
@@ -0,0 +1,5 @@
|
||||
(* Baseline: List functions exercise *)
|
||||
let xs = [1; 2; 3; 4; 5] ;;
|
||||
let doubled = List.map (fun x -> x * 2) xs ;;
|
||||
let total = List.fold_left (fun a b -> a + b) 0 doubled ;;
|
||||
total
|
||||
14
lib/ocaml/baseline/module_use.ml
Normal file
14
lib/ocaml/baseline/module_use.ml
Normal file
@@ -0,0 +1,14 @@
|
||||
(* Baseline: module declaration + use *)
|
||||
module Counter = struct
|
||||
let make () =
|
||||
let n = ref 0 in
|
||||
fun () ->
|
||||
n := !n + 1 ;
|
||||
!n
|
||||
end ;;
|
||||
let result =
|
||||
let c = Counter.make () in
|
||||
let _ = c () in
|
||||
let _ = c () in
|
||||
c () ;;
|
||||
result
|
||||
8
lib/ocaml/baseline/option_match.ml
Normal file
8
lib/ocaml/baseline/option_match.ml
Normal file
@@ -0,0 +1,8 @@
|
||||
(* Baseline: option type + pattern matching *)
|
||||
let safe_div a b =
|
||||
if b = 0 then None else Some (a / b) ;;
|
||||
let result =
|
||||
match safe_div 20 4 with
|
||||
| None -> 0
|
||||
| Some x -> x ;;
|
||||
result
|
||||
75
lib/ocaml/baseline/run.sh
Executable file
75
lib/ocaml/baseline/run.sh
Executable file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
# lib/ocaml/baseline/run.sh — run each baseline OCaml program through
|
||||
# ocaml-run-program and compare to expected.json.
|
||||
|
||||
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
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
ERRORS=""
|
||||
|
||||
for f in lib/ocaml/baseline/*.ml; do
|
||||
name=$(basename "$f")
|
||||
expected=$(grep -oE "\"$name\"[[:space:]]*:[[:space:]]*[0-9-]+" lib/ocaml/baseline/expected.json | sed -E 's/.*:[[:space:]]*//')
|
||||
if [ -z "$expected" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
TMP=$(mktemp)
|
||||
cat > "$TMP" << EPOCHS
|
||||
(epoch 1)
|
||||
(load "lib/guest/lex.sx")
|
||||
(load "lib/guest/prefix.sx")
|
||||
(load "lib/guest/pratt.sx")
|
||||
(load "lib/ocaml/tokenizer.sx")
|
||||
(load "lib/ocaml/parser.sx")
|
||||
(load "lib/ocaml/eval.sx")
|
||||
(load "lib/ocaml/runtime.sx")
|
||||
(eval "(ocaml-load-stdlib!)")
|
||||
(epoch 2)
|
||||
(eval "(ocaml-run-program (file-read \\"$f\\"))")
|
||||
EPOCHS
|
||||
|
||||
output=$(timeout 60 "$SX_SERVER" < "$TMP" 2>/dev/null | grep -E '^\(ok-len 2|^\(ok 2' | head -1)
|
||||
rm -f "$TMP"
|
||||
|
||||
# Pull the next line which has the value
|
||||
result=$(timeout 60 "$SX_SERVER" < <(cat <<EPOCHS
|
||||
(epoch 1)
|
||||
(load "lib/guest/lex.sx")
|
||||
(load "lib/guest/prefix.sx")
|
||||
(load "lib/guest/pratt.sx")
|
||||
(load "lib/ocaml/tokenizer.sx")
|
||||
(load "lib/ocaml/parser.sx")
|
||||
(load "lib/ocaml/eval.sx")
|
||||
(load "lib/ocaml/runtime.sx")
|
||||
(eval "(ocaml-load-stdlib!)")
|
||||
(epoch 2)
|
||||
(eval "(ocaml-run-program (file-read \"$f\"))")
|
||||
EPOCHS
|
||||
) 2>/dev/null | awk '/^\(ok-len 2 / {getline; print; exit} /^\(ok 2 / {sub(/^\(ok 2 /, ""); sub(/\)$/, ""); print; exit}')
|
||||
|
||||
if [ "$result" = "$expected" ]; then
|
||||
PASS=$((PASS + 1))
|
||||
echo " ok $name → $result"
|
||||
else
|
||||
FAIL=$((FAIL + 1))
|
||||
ERRORS+=" FAIL $name expected=$expected got=$result
|
||||
"
|
||||
fi
|
||||
done
|
||||
|
||||
TOTAL=$((PASS + FAIL))
|
||||
if [ $FAIL -eq 0 ]; then
|
||||
echo "ok $PASS/$TOTAL baseline OCaml programs run correctly"
|
||||
else
|
||||
echo "FAIL $PASS/$TOTAL baseline programs"
|
||||
echo "$ERRORS"
|
||||
fi
|
||||
[ $FAIL -eq 0 ]
|
||||
6
lib/ocaml/baseline/sum_squares.ml
Normal file
6
lib/ocaml/baseline/sum_squares.ml
Normal file
@@ -0,0 +1,6 @@
|
||||
(* Baseline: imperative loop summing squares *)
|
||||
let total = ref 0 ;;
|
||||
for i = 1 to 10 do
|
||||
total := !total + i * i
|
||||
done ;;
|
||||
!total
|
||||
Reference in New Issue
Block a user