ocaml: phase 5.1 calc.ml baseline (11/11 pass) + inline let-rec-and parser fix
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 54s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 54s
Recursive-descent calculator parses '(1 + 2) * 3 + 4' = 13. Two parser bugs fixed: 1. parse-let now handles inline 'let rec a () = ... and b () = ... in body' via new (:let-rec-mut BINDINGS BODY) and (:let-mut BINDINGS BODY) AST shapes; eval handles both. 2. has-matching-in? lookahead no longer stops at 'and' — 'and' is internal to let-rec, not a decl boundary. Without this fix, the inner 'let rec a () = ... and b () = ...' inside a let-decl rhs would have been treated as the start of a new top-level decl. Baseline exercises mutually-recursive functions, while-loops, ref-cell imperative parsing, and ADT-based AST construction.
This commit is contained in:
@@ -619,6 +619,57 @@
|
||||
(ocaml-eval rhs env)
|
||||
(ocaml-make-curried params rhs env))))
|
||||
(ocaml-eval body (ocaml-env-extend env name rhs-val)))))
|
||||
((= tag "let-mut")
|
||||
;; (:let-mut BINDINGS BODY) — non-rec multi-binding let-in.
|
||||
;; Each rhs evaluated in the parent env, then names bound
|
||||
;; sequentially before evaluating BODY.
|
||||
(let ((bindings (nth ast 1)) (body (nth ast 2)) (env-cur env))
|
||||
(begin
|
||||
(define one
|
||||
(fn (b)
|
||||
(let ((nm (nth b 0)) (ps (nth b 1)) (rh (nth b 2)))
|
||||
(let ((v (if (= (len ps) 0)
|
||||
(ocaml-eval rh env-cur)
|
||||
(ocaml-make-curried ps rh env-cur))))
|
||||
(set! env-cur (ocaml-env-extend env-cur nm v))))))
|
||||
(define loop
|
||||
(fn (xs)
|
||||
(when (not (= xs (list)))
|
||||
(begin (one (first xs)) (loop (rest xs))))))
|
||||
(loop bindings)
|
||||
(ocaml-eval body env-cur))))
|
||||
((= tag "let-rec-mut")
|
||||
;; (:let-rec-mut BINDINGS BODY) — mutually-recursive let-in.
|
||||
(let ((bindings (nth ast 1)) (body (nth ast 2))
|
||||
(env2 env) (cells (list)))
|
||||
(begin
|
||||
(define alloc
|
||||
(fn (xs)
|
||||
(when (not (= xs (list)))
|
||||
(let ((b (first xs)))
|
||||
(let ((c (list nil)) (nm (nth b 0)))
|
||||
(begin
|
||||
(append! cells c)
|
||||
(set! env2 (ocaml-env-extend env2 nm
|
||||
(fn (a) ((nth c 0) a))))
|
||||
(alloc (rest xs))))))))
|
||||
(alloc bindings)
|
||||
(let ((idx 0))
|
||||
(begin
|
||||
(define fill
|
||||
(fn (xs)
|
||||
(when (not (= xs (list)))
|
||||
(let ((b (first xs)))
|
||||
(let ((nm (nth b 0)) (ps (nth b 1)) (rh (nth b 2)))
|
||||
(let ((v (if (= (len ps) 0)
|
||||
(ocaml-eval rh env2)
|
||||
(ocaml-make-curried ps rh env2))))
|
||||
(begin
|
||||
(set-nth! (nth cells idx) 0 v)
|
||||
(set! idx (+ idx 1))
|
||||
(fill (rest xs)))))))))
|
||||
(fill bindings)
|
||||
(ocaml-eval body env2))))))
|
||||
((= tag "let-rec")
|
||||
;; Tie the knot via a mutable cell when rhs is function-typed.
|
||||
;; The placeholder closure dereferences the cell on each call.
|
||||
|
||||
Reference in New Issue
Block a user