ocaml: phase 2 mutable record fields r.f <- v (+4 tests, 451 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 27s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 27s
<- added to op-table at level 1 (same as :=). Eval short-circuits on
<- to mutate the lhs's field via host SX dict-set!. The lhs must be a
:field expression; otherwise raises.
Tested:
let r = { x = 1; y = 2 } in r.x <- 5; r.x (5)
let r = { x = 0 } in for i = 1 to 5 do r.x <- r.x + i done; r.x (15)
let r = { name = ...; age = 30 } in r.name <- "Alice"; r.name
The 'mutable' keyword in record type decls is parsed-and-discarded;
runtime semantics: every field is mutable. Phase 2 closes this gap
without changing the dict-based record representation.
This commit is contained in:
@@ -442,6 +442,18 @@
|
||||
(let ((cell (ocaml-eval (nth ast 2) env))
|
||||
(new-val (ocaml-eval (nth ast 3) env)))
|
||||
(begin (set-nth! cell 0 new-val) nil)))
|
||||
;; <- mutates a record field. The lhs must be a (:field ...).
|
||||
((= op "<-")
|
||||
(let ((lhs-ast (nth ast 2)) (new-val (ocaml-eval (nth ast 3) env)))
|
||||
(cond
|
||||
((= (ocaml-tag-of lhs-ast) "field")
|
||||
(let ((target (ocaml-eval (nth lhs-ast 1) env))
|
||||
(fname (nth lhs-ast 2)))
|
||||
(begin (dict-set! target fname new-val) nil)))
|
||||
(else
|
||||
(error
|
||||
(str "ocaml-eval: <- expects a field-access lhs, got "
|
||||
(ocaml-tag-of lhs-ast)))))))
|
||||
(else
|
||||
(ocaml-eval-op op
|
||||
(ocaml-eval (nth ast 2) env)
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
ocaml-op-table
|
||||
(list
|
||||
(list ":=" 1 :right)
|
||||
(list "<-" 1 :right)
|
||||
(list "||" 2 :right)
|
||||
(list "or" 2 :right)
|
||||
(list "&&" 3 :right)
|
||||
|
||||
@@ -1106,6 +1106,16 @@ cat > "$TMPFILE" << 'EPOCHS'
|
||||
(epoch 4002)
|
||||
(eval "(ocaml-run-program \"type point = { x : int; y : int };; let p = { x = 3; y = 4 };; p.x + p.y\")")
|
||||
|
||||
;; ── Mutable record fields (r.f <- v) ──────────────────────────
|
||||
(epoch 4100)
|
||||
(eval "(ocaml-run \"let r = { x = 1; y = 2 } in r.x <- 5; r.x\")")
|
||||
(epoch 4101)
|
||||
(eval "(ocaml-run \"let r = { x = 0 } in for i = 1 to 5 do r.x <- r.x + i done; r.x\")")
|
||||
(epoch 4102)
|
||||
(eval "(ocaml-run \"let r = { name = \\\"Bob\\\"; age = 30 } in r.name <- \\\"Alice\\\"; r.name\")")
|
||||
(epoch 4103)
|
||||
(eval "(ocaml-run \"let r = { x = 1; y = 2 } in r.x <- r.y * 10; r.x\")")
|
||||
|
||||
EPOCHS
|
||||
|
||||
OUTPUT=$(timeout 180 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
|
||||
@@ -1751,6 +1761,12 @@ check 4000 "record type decl" '("type-def-record" "point" () (("x")
|
||||
check 4001 "mutable field decl" '("mutable" "x")'
|
||||
check 4002 "record decl + use" '7'
|
||||
|
||||
# ── Mutable record fields ──────────────────────────────────────
|
||||
check 4100 "r.x <- 5; r.x" '5'
|
||||
check 4101 "for-loop accum r.x" '15'
|
||||
check 4102 "r.name <- str" '"Alice"'
|
||||
check 4103 "r.x <- r.y * 10" '20'
|
||||
|
||||
TOTAL=$((PASS + FAIL))
|
||||
if [ $FAIL -eq 0 ]; then
|
||||
echo "ok $PASS/$TOTAL OCaml-on-SX tests passed"
|
||||
|
||||
@@ -157,6 +157,10 @@ SX CEK evaluator (both JS and OCaml hosts)
|
||||
- [x] Arithmetic, comparison, boolean ops, string `^`, `mod`.
|
||||
- [x] Unit `()` value; `ignore`.
|
||||
- [x] References: `ref`, `!`, `:=`.
|
||||
- [x] Mutable record fields via `r.f <- v` — uses host SX `dict-set!`
|
||||
to mutate the underlying record dict in place. All record fields
|
||||
are de-facto mutable (the `mutable` keyword in type-decls is
|
||||
currently parsed-and-discarded).
|
||||
- [ ] Mutable record fields.
|
||||
- [x] `for i = lo to hi do ... done` loop; `while cond do ... done` (incl.
|
||||
`downto` direction).
|
||||
@@ -403,6 +407,13 @@ _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 2 — mutable record fields `r.f <- v` (+4 tests, 451
|
||||
total). `<-` added to op-table at level 1 (same as `:=`). Eval
|
||||
short-circuits on `<-` to mutate the lhs's field via host SX
|
||||
`dict-set!`. Tested with for-loop accumulator (`for i = 1 to 5 do
|
||||
r.x <- r.x + i done`) and string-field reassignment. The `mutable`
|
||||
keyword in record-type decls is parsed-and-discarded; runtime
|
||||
semantics: every field is mutable.
|
||||
- 2026-05-08 Phase 1+3 — record type declarations `type r = { x : int;
|
||||
mutable y : string }` (+3 tests, 447 total). Parser dispatches on
|
||||
`{` after `=` to parse field list (`mutable` keyword tracked).
|
||||
|
||||
Reference in New Issue
Block a user