From 14b52cfaa7d8c6d1468fcf568809017b187b141c Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 9 May 2026 00:32:35 +0000 Subject: [PATCH] ocaml: phase 4 'assert EXPR' (+3 tests, 487 total) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tokenizer already classified 'assert' as a keyword; this commit wires it through: parser : parse-prefix dispatches like 'not' — advance, recur, wrap as (:assert EXPR). eval : evaluate operand; nil on truthy, host-error 'Assert_failure' on false. Caught cleanly by existing try/with. assert true; 42 = 42 let x = 5 in assert (x = 5); x + 1 = 6 try (assert false; 0) with _ -> 99 = 99 --- lib/ocaml/eval.sx | 5 +++++ lib/ocaml/parser.sx | 2 ++ lib/ocaml/test.sh | 13 +++++++++++++ plans/ocaml-on-sx.md | 6 ++++++ 4 files changed, 26 insertions(+) diff --git a/lib/ocaml/eval.sx b/lib/ocaml/eval.sx index 83111b9a..76ed38a7 100644 --- a/lib/ocaml/eval.sx +++ b/lib/ocaml/eval.sx @@ -430,6 +430,11 @@ (else (error (str "ocaml-eval: unbound variable " name)))))) ((= tag "neg") (- 0 (ocaml-eval (nth ast 1) env))) ((= tag "not") (not (ocaml-eval (nth ast 1) env))) + ((= tag "assert") + (let ((v (ocaml-eval (nth ast 1) env))) + (cond + ((= v false) (error "Assert_failure")) + (else nil)))) ((= tag "deref") (let ((cell (ocaml-eval (nth ast 1) env))) (nth cell 0))) diff --git a/lib/ocaml/parser.sx b/lib/ocaml/parser.sx index 23f5f13e..806d1963 100644 --- a/lib/ocaml/parser.sx +++ b/lib/ocaml/parser.sx @@ -622,6 +622,8 @@ (begin (advance-tok!) (list :deref (parse-prefix)))) ((at-kw? "not") (begin (advance-tok!) (list :not (parse-prefix)))) + ((at-kw? "assert") + (begin (advance-tok!) (list :assert (parse-prefix)))) (else (parse-app))))) (set! parse-binop-rhs diff --git a/lib/ocaml/test.sh b/lib/ocaml/test.sh index 47fac6a2..8382b86d 100755 --- a/lib/ocaml/test.sh +++ b/lib/ocaml/test.sh @@ -1202,6 +1202,14 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 4922) (eval "(ocaml-run \"let s = \\\"hi\\\" in let n = ref 0 in for i = 0 to String.length s - 1 do n := !n + Char.code s.[i] done; !n\")") +;; ── assert ──────────────────────────────────────────────────── +(epoch 4930) +(eval "(ocaml-run \"assert true; 42\")") +(epoch 4931) +(eval "(ocaml-run \"let x = 5 in assert (x = 5); x + 1\")") +(epoch 4932) +(eval "(ocaml-run \"try (assert false; 0) with _ -> 99\")") + EPOCHS OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) @@ -1906,6 +1914,11 @@ check 4920 "s.[0] hello" '"h"' check 4921 "Char.code s.[2] abc" '99' check 4922 "for i s.[i] sum hi" '209' +# ── assert ─────────────────────────────────────────────────────── +check 4930 "assert true; 42" '42' +check 4931 "assert (x = 5); x + 1" '6' +check 4932 "try (assert false; ...) with" '99' + 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 42479586..5d124532 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 4 — `assert EXPR` (+3 tests, 487 total). Tokenizer + already classified `assert` as a keyword; parse-prefix now handles + it like `not` (advance, recur, wrap). Eval evaluates the operand and + returns nil on truthy, raises `Assert_failure` on false (host-side + error so existing try/with handles it). `try (assert false; 0) with + _ -> 99` → 99. - 2026-05-09 Phase 5.1 — levenshtein.ml baseline (recursive edit distance, no memo). Sums distances for five short pairs: ("abc","abx")=1 + ("ab","ba")=2 + ("abc","axyc")=2 +