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:
@@ -666,36 +666,43 @@
|
||||
(let ((body (parse-expr))) (list :fun params body))))))
|
||||
(define
|
||||
parse-let
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((reccy false))
|
||||
(fn ()
|
||||
(let ((reccy false) (bindings (list)))
|
||||
(begin
|
||||
(when
|
||||
(at-kw? "rec")
|
||||
(when (at-kw? "rec")
|
||||
(begin (advance-tok!) (set! reccy true)))
|
||||
(let
|
||||
((name (ocaml-tok-value (consume! "ident" nil)))
|
||||
(params (list)))
|
||||
(begin
|
||||
(define
|
||||
collect-params
|
||||
(fn ()
|
||||
(let ((nm (try-consume-param!)))
|
||||
(when (not (= nm nil))
|
||||
(begin (append! params nm) (collect-params))))))
|
||||
(collect-params)
|
||||
(consume! "op" "=")
|
||||
(let
|
||||
((rhs (parse-expr)))
|
||||
(define parse-one!
|
||||
(fn ()
|
||||
(let ((nm (ocaml-tok-value (consume! "ident" nil)))
|
||||
(ps (list)))
|
||||
(begin
|
||||
(consume! "keyword" "in")
|
||||
(let
|
||||
((body (parse-expr)))
|
||||
(if
|
||||
reccy
|
||||
(list :let-rec name params rhs body)
|
||||
(list :let name params rhs body)))))))))))
|
||||
(define collect-params
|
||||
(fn ()
|
||||
(let ((p (try-consume-param!)))
|
||||
(when (not (= p nil))
|
||||
(begin (append! ps p) (collect-params))))))
|
||||
(collect-params)
|
||||
(consume! "op" "=")
|
||||
(let ((rhs (parse-expr)))
|
||||
(append! bindings (list nm ps rhs)))))))
|
||||
(parse-one!)
|
||||
(define more
|
||||
(fn ()
|
||||
(when (at-kw? "and")
|
||||
(begin (advance-tok!) (parse-one!) (more)))))
|
||||
(more)
|
||||
(consume! "keyword" "in")
|
||||
(let ((body (parse-expr)))
|
||||
(cond
|
||||
((= (len bindings) 1)
|
||||
(let ((b (first bindings)))
|
||||
(if reccy
|
||||
(list :let-rec (nth b 0) (nth b 1) (nth b 2) body)
|
||||
(list :let (nth b 0) (nth b 1) (nth b 2) body))))
|
||||
(else
|
||||
(if reccy
|
||||
(list :let-rec-mut bindings body)
|
||||
(list :let-mut bindings body)))))))))
|
||||
(define
|
||||
parse-if
|
||||
(fn
|
||||
@@ -975,7 +982,6 @@
|
||||
((and (= tt "keyword") (= tv "exception")) (set! done true))
|
||||
((and (= tt "keyword") (= tv "open")) (set! done true))
|
||||
((and (= tt "keyword") (= tv "include")) (set! done true))
|
||||
((and (= tt "keyword") (= tv "and")) (set! done true))
|
||||
((and (= tt "keyword") (= tv "let"))
|
||||
(begin (set! d (+ d 1)) (set! p (+ p 1)) (scan)))
|
||||
((and (= tt "keyword") (= tv "in"))
|
||||
|
||||
Reference in New Issue
Block a user