From a4ef9a8ec9f9126c7c99d3a70cd1c5ffc584234a Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 20:58:50 +0000 Subject: [PATCH] ocaml: phase 1 type annotations on let / (e : T) (+4 tests, 473 total) let NAME [PARAMS] : T = expr and (expr : T) parse and skip the type source. Runtime no-op since SX is dynamic. Works in inline let, top-level let, and parenthesised expressions: let x : int = 5 ;; x + 1 -> 6 let f (x : int) : int = x + 1 in f 41 -> 42 (5 : int) -> 5 ((1 + 2) : int) * 3 -> 9 --- lib/ocaml/parser.sx | 40 +++++++++++++++++++++++++++++++++++++++- lib/ocaml/test.sh | 16 ++++++++++++++++ plans/ocaml-on-sx.md | 5 +++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/lib/ocaml/parser.sx b/lib/ocaml/parser.sx index 3abdd84a..c5aabfa8 100644 --- a/lib/ocaml/parser.sx +++ b/lib/ocaml/parser.sx @@ -422,7 +422,21 @@ (else (let ((e (parse-expr))) - (begin (consume! "op" ")") e)))))) + (begin + ;; Optional type annotation `(e : T)` — skip + ;; the type source before `)`. + (when (at-op? ":") + (begin + (advance-tok!) + (define skip-pty + (fn () + (cond + ((>= idx tok-len) nil) + ((= (ocaml-tok-type (peek-tok)) "eof") nil) + ((at-op? ")") nil) + (else (begin (advance-tok!) (skip-pty)))))) + (skip-pty))) + (consume! "op" ")") e)))))) ((and (= tt "op") (= tv "[")) (begin (advance-tok!) @@ -683,6 +697,18 @@ (when (not (= p nil)) (begin (append! ps p) (collect-params)))))) (collect-params) + ;; Optional type annotation: skip `: TYPE` before `=`. + (when (at-op? ":") + (begin + (advance-tok!) + (define skip-tann + (fn () + (cond + ((>= idx tok-len) nil) + ((= (ocaml-tok-type (peek-tok)) "eof") nil) + ((at-op? "=") nil) + (else (begin (advance-tok!) (skip-tann)))))) + (skip-tann))) (consume! "op" "=") (let ((rhs (parse-expr))) (append! bindings (list nm ps rhs))))))) @@ -1101,6 +1127,18 @@ (collect-params))) (else nil)))) (collect-params) + ;; Optional type annotation: skip `: TYPE` before `=`. + (when (at-op? ":") + (begin + (advance-tok!) + (define skip-tann + (fn () + (cond + ((>= idx tok-len) nil) + ((= (ocaml-tok-type (peek-tok)) "eof") nil) + ((at-op? "=") nil) + (else (begin (advance-tok!) (skip-tann)))))) + (skip-tann))) (consume! "op" "=") (let ((expr-start (cur-pos))) (begin diff --git a/lib/ocaml/test.sh b/lib/ocaml/test.sh index 88ef8c59..3b5edbef 100755 --- a/lib/ocaml/test.sh +++ b/lib/ocaml/test.sh @@ -1162,6 +1162,16 @@ cat > "$TMPFILE" << 'EPOCHS' (epoch 4601) (eval "(ocaml-run-program \"type t = int;; 42\")") +;; ── Type annotations: let x : T = e and (e : T) ────────────── +(epoch 4700) +(eval "(ocaml-run-program \"let x : int = 5;; x + 1\")") +(epoch 4701) +(eval "(ocaml-run \"let f (x : int) : int = x + 1 in f 41\")") +(epoch 4702) +(eval "(ocaml-run \"(5 : int)\")") +(epoch 4703) +(eval "(ocaml-run \"((1 + 2) : int) * 3\")") + EPOCHS OUTPUT=$(timeout 180 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) @@ -1841,6 +1851,12 @@ check 4502 "try when fall through" '1005' check 4600 "type t = int parses" '("type-alias" "t" ())' check 4601 "type alias decl + use" '42' +# ── Type annotations ─────────────────────────────────────────── +check 4700 "let x : int = 5" '6' +check 4701 "let f (x : int) : int" '42' +check 4702 "(5 : int)" '5' +check 4703 "((1+2) : int) * 3" '9' + 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 f03f97fa..74a565b6 100644 --- a/plans/ocaml-on-sx.md +++ b/plans/ocaml-on-sx.md @@ -407,6 +407,11 @@ _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 1 — type annotations on let-bindings and parens + expressions (+4 tests, 473 total). `let NAME [PARAMS] : T = expr` + and `(expr : T)` parse and skip the type source. Runtime no-op + (dynamic). Works in inline let, top-level let, and parenthesised + expressions: `let f (x : int) : int = x + 1 in f 41`. - 2026-05-08 Phase 1+5.1 — type aliases + poly_stack baseline (+3 tests, 469 total + 19 baseline). Parser dispatch on the post-`=` token: `|` or `Ctor` → sum, `{` → record, otherwise → alias (skip