diff --git a/lib/ocaml/test.sh b/lib/ocaml/test.sh index 0351d0f3..413f0645 100755 --- a/lib/ocaml/test.sh +++ b/lib/ocaml/test.sh @@ -936,6 +936,16 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 2405) (eval "(ocaml-run \"Float.ceil 3.2\")") +;; ── Polymorphic variants ────────────────────────────────────── +(epoch 2500) +(eval "(ocaml-run \"\`Red\")") +(epoch 2501) +(eval "(ocaml-run \"\`Some 42\")") +(epoch 2502) +(eval "(ocaml-run \"match \`Red with | \`Red -> 1 | \`Green -> 2 | \`Blue -> 3\")") +(epoch 2503) +(eval "(ocaml-run \"match \`Pair (1, 2) with | \`Pair (a, b) -> a + b\")") + EPOCHS OUTPUT=$(timeout 180 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) @@ -1480,6 +1490,12 @@ check 2403 "Float.pow 2 10" '1024' check 2404 "Float.floor 3.7" '3' check 2405 "Float.ceil 3.2" '4' +# ── Polymorphic variants ─────────────────────────────────────── +check 2500 "polyvar Red" '("Red")' +check 2501 "polyvar Some 42" '("Some" 42)' +check 2502 "polyvar match" '1' +check 2503 "polyvar Pair (a,b)" '3' + TOTAL=$((PASS + FAIL)) if [ $FAIL -eq 0 ]; then echo "ok $PASS/$TOTAL OCaml-on-SX tests passed" diff --git a/lib/ocaml/tokenizer.sx b/lib/ocaml/tokenizer.sx index 245b83f3..3949a556 100644 --- a/lib/ocaml/tokenizer.sx +++ b/lib/ocaml/tokenizer.sx @@ -381,6 +381,20 @@ (slice src (+ start 1) pos) start) (step))) + ;; Polymorphic variant tag: `Tag — emits a ctor token + ;; identical to a nominal ctor. Runtime is dynamic, so + ;; the distinction only matters for HM (deferred). + ((and (= c "`") + (< (+ pos 1) src-len) + (ocaml-upper? (ocaml-peek 1))) + (begin + (advance! 1) + (let ((ctor-start pos)) + (begin + (when (and (< pos src-len) (ocaml-ident-char? (cur))) + (begin (advance! 1) (read-ident ctor-start))) + (push! "ctor" (slice src ctor-start pos) start))) + (step))) ((try-punct start) (step)) (else (error diff --git a/plans/ocaml-on-sx.md b/plans/ocaml-on-sx.md index 2d34bf31..44e30220 100644 --- a/plans/ocaml-on-sx.md +++ b/plans/ocaml-on-sx.md @@ -182,7 +182,10 @@ SX CEK evaluator (both JS and OCaml hosts) `(:exception-def NAME [ARG-TYPE-SRC])`. Runtime no-op since raise/match work on tagged ctor values. Built-ins: `Failure`/`Invalid_argument` via `failwith`/`invalid_arg`. -- [ ] Polymorphic variants (surface syntax `\`Tag value`; runtime same tagged list). +- [x] Polymorphic variants (surface syntax `` `Tag value ``; runtime same + tagged list as nominal ctors). Tokenizer recognises backtick + ctor; + parser/eval treat them identically to nominal ctors. Type system + handling deferred (proper row types). - [ ] Tests in `lib/ocaml/tests/adt.sx` — 40+ tests: ADTs, match, option/result. ### Phase 4 — Modules + functors @@ -374,6 +377,12 @@ the "mother tongue" closure: OCaml → SX → OCaml. This means: _Newest first._ +- 2026-05-08 Phase 3 — polymorphic variants `` `Tag `` (+4 tests, 382 + total). Tokenizer recognises backtick followed by an upper ident, + tokenizing identically to nominal ctors. Parser and evaluator treat + them as ctors — same tagged-list runtime. Match patterns `` `Red `` + / `` `Pair (a, b) `` work without any extra wiring. Proper row + types in HM deferred. - 2026-05-08 Phase 6 — Float module: sqrt/sin/cos/pow/floor/ceil/round + pi constant (+6 tests, 378 total). Wraps host SX math primitives via `_float_*` builtins.