ocaml: phase 4 'let PATTERN = expr in body' tuple destructuring (+3 tests, 541 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 44s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 44s
When 'let' is followed by '(', parse-let now reads a full pattern
(via the existing parse-pattern used by match), expects '=', then
'in', and desugars to:
let PATTERN = EXPR in BODY => match EXPR with PATTERN -> BODY
This reuses the entire pattern-matching machinery, so any pattern
the match parser accepts works here too — paren-tuples, nested
tuples, cons patterns, list patterns. No 'rec' allowed for pattern
bindings (real OCaml's restriction).
let (a, b) = (1, 2) in a + b = 3
let (a, b, c) = (10, 20, 30) in a + b + c = 60
let pair = (5, 7) in
let (x, y) = pair in x * y = 35
Also retroactively cleaned up Printf's iter-97 width-pos packing
hack ('width * 1000000 + spec_pos') — it's now
'let (width, spec_pos) = parse_width_loop after_flags in ...' like
real OCaml.
This commit is contained in:
@@ -765,6 +765,19 @@
|
|||||||
(consume! "keyword" "in")
|
(consume! "keyword" "in")
|
||||||
(let ((body (parse-expr)))
|
(let ((body (parse-expr)))
|
||||||
(list :let-open path body))))))
|
(list :let-open path body))))))
|
||||||
|
;; `let PATTERN = expr in body` — non-trivial pattern
|
||||||
|
;; desugars to `match expr with PATTERN -> body`. Triggers
|
||||||
|
;; on `(` (paren-tuple, possibly nested) immediately after
|
||||||
|
;; `let` (no `rec` allowed for pattern bindings).
|
||||||
|
((at-op? "(")
|
||||||
|
(let ((pat (parse-pattern)))
|
||||||
|
(begin
|
||||||
|
(consume! "op" "=")
|
||||||
|
(let ((rhs (parse-expr)))
|
||||||
|
(begin
|
||||||
|
(consume! "keyword" "in")
|
||||||
|
(let ((body (parse-expr)))
|
||||||
|
(list :match rhs (list (list :case pat body)))))))))
|
||||||
(else
|
(else
|
||||||
(let ((reccy false) (bindings (list)))
|
(let ((reccy false) (bindings (list)))
|
||||||
(begin
|
(begin
|
||||||
|
|||||||
@@ -562,7 +562,7 @@
|
|||||||
else cont := false
|
else cont := false
|
||||||
else cont := false
|
else cont := false
|
||||||
done;
|
done;
|
||||||
(!w) * 1000000 + (!i)
|
(!w, !i)
|
||||||
in
|
in
|
||||||
let rec walk pos prefix =
|
let rec walk pos prefix =
|
||||||
if pos >= n then prefix
|
if pos >= n then prefix
|
||||||
@@ -573,9 +573,7 @@
|
|||||||
let left_flag = ref false in
|
let left_flag = ref false in
|
||||||
let zero_flag = ref false in
|
let zero_flag = ref false in
|
||||||
let after_flags = parse_flags_loop (pos + 1) left_flag zero_flag in
|
let after_flags = parse_flags_loop (pos + 1) left_flag zero_flag in
|
||||||
let packed = parse_width_loop after_flags in
|
let (width, spec_pos) = parse_width_loop after_flags in
|
||||||
let width = packed / 1000000 in
|
|
||||||
let spec_pos = packed - width * 1000000 in
|
|
||||||
if spec_pos < n && is_spec (_string_get fmt spec_pos) then
|
if spec_pos < n && is_spec (_string_get fmt spec_pos) then
|
||||||
let spec = _string_get fmt spec_pos in
|
let spec = _string_get fmt spec_pos in
|
||||||
let left = !left_flag in
|
let left = !left_flag in
|
||||||
|
|||||||
@@ -1342,6 +1342,14 @@ cat > "$TMPFILE" << 'EPOCHS'
|
|||||||
(epoch 5084)
|
(epoch 5084)
|
||||||
(eval "(ocaml-run \"Printf.sprintf \\\"hi=%-3d, hex=%04x\\\" 9 15\")")
|
(eval "(ocaml-run \"Printf.sprintf \\\"hi=%-3d, hex=%04x\\\" 9 15\")")
|
||||||
|
|
||||||
|
;; ── let (a, b) = expr in body — tuple destructure ─────────────
|
||||||
|
(epoch 5090)
|
||||||
|
(eval "(ocaml-run \"let (a, b) = (1, 2) in a + b\")")
|
||||||
|
(epoch 5091)
|
||||||
|
(eval "(ocaml-run \"let (a, b, c) = (10, 20, 30) in a + b + c\")")
|
||||||
|
(epoch 5092)
|
||||||
|
(eval "(ocaml-run \"let pair = (5, 7) in let (x, y) = pair in x * y\")")
|
||||||
|
|
||||||
EPOCHS
|
EPOCHS
|
||||||
|
|
||||||
OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
|
OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
|
||||||
@@ -2132,6 +2140,11 @@ check 5082 "%05d 42 zero-pad" '"00042"'
|
|||||||
check 5083 "%4s hi" '" hi"'
|
check 5083 "%4s hi" '" hi"'
|
||||||
check 5084 "%-3d %04x mixed" '"hi=9 , hex=000f"'
|
check 5084 "%-3d %04x mixed" '"hi=9 , hex=000f"'
|
||||||
|
|
||||||
|
# ── let (a, b) = expr in body ───────────────────────────────────
|
||||||
|
check 5090 "let (a, b) = (1,2)" '3'
|
||||||
|
check 5091 "let (a, b, c) = (10,20,30)" '60'
|
||||||
|
check 5092 "let pair; let (x, y) = pair" '35'
|
||||||
|
|
||||||
TOTAL=$((PASS + FAIL))
|
TOTAL=$((PASS + FAIL))
|
||||||
if [ $FAIL -eq 0 ]; then
|
if [ $FAIL -eq 0 ]; then
|
||||||
echo "ok $PASS/$TOTAL OCaml-on-SX tests passed"
|
echo "ok $PASS/$TOTAL OCaml-on-SX tests passed"
|
||||||
|
|||||||
@@ -407,6 +407,14 @@ _Newest first._
|
|||||||
binary search tree (`type 'a tree = Leaf | Node of 'a * 'a tree *
|
binary search tree (`type 'a tree = Leaf | Node of 'a * 'a tree *
|
||||||
'a tree`) with insert + in-order traversal. Tests parametric ADT,
|
'a tree`) with insert + in-order traversal. Tests parametric ADT,
|
||||||
recursive match, List.append, List.fold_left.
|
recursive match, List.append, List.fold_left.
|
||||||
|
- 2026-05-09 Phase 4 — `let PATTERN = expr in body` tuple
|
||||||
|
destructuring (+3 tests, 541 total). When `let` is followed by `(`,
|
||||||
|
parse-let now reads a full pattern, expects `=`, then `in`, and
|
||||||
|
desugars to `(:match expr ((:case PATTERN body)))`. Reuses the
|
||||||
|
pattern parser used by match. `let (a, b, c) = (10, 20, 30) in
|
||||||
|
a+b+c` → 60. Also retroactively cleans up the Printf width-pos
|
||||||
|
packing hack from iteration 97 — it's now `let (width, spec_pos)
|
||||||
|
= parse_width_loop after_flags in ...` like real OCaml.
|
||||||
- 2026-05-09 Phase 6 — Printf width specifiers `%5d` / `%-5d` /
|
- 2026-05-09 Phase 6 — Printf width specifiers `%5d` / `%-5d` /
|
||||||
`%05d` / `%4s` etc. (+5 tests, 538 total). Walker now parses
|
`%05d` / `%4s` etc. (+5 tests, 538 total). Walker now parses
|
||||||
optional `-` (left-align) and `0` (zero-pad) flags after `%`, then
|
optional `-` (left-align) and `0` (zero-pad) flags after `%`, then
|
||||||
|
|||||||
Reference in New Issue
Block a user