ocaml: phase 4 modules + field access (+11 tests, 215 total)
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
module M = struct DECLS end parsed by sub-tokenising the body source between struct and the matching end (nesting tracked via struct/begin/ sig/end). Field access is a postfix layer above parse-atom, binding tighter than application: f r.x -> (:app f (:field r "x")). Eval (:module-def NAME DECLS) builds a dict via ocaml-eval-module running decls in a sub-env. (:field EXPR NAME) looks up dict fields, treating (:con NAME) heads as module-name lookups instead of nullary ctors so M.x works with M as a module. Phase 4 LOC so far: ~110 lines (well under 2000 budget).
This commit is contained in:
@@ -377,12 +377,32 @@
|
||||
true)
|
||||
((and (= tt "op") (or (= tv "(") (= tv "["))) true)
|
||||
(else false)))))
|
||||
(define parse-atom-postfix
|
||||
(fn ()
|
||||
;; After a primary atom, consume `.field` chains. Field name
|
||||
;; may be lower (record field, module value) or upper (module
|
||||
;; or constructor reference). Note: `M.x.y` is left-assoc:
|
||||
;; `(:field (:field M "x") "y")`.
|
||||
(let ((head (parse-atom)))
|
||||
(begin
|
||||
(define loop
|
||||
(fn ()
|
||||
(when (at-op? ".")
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(let ((tok (peek-tok)))
|
||||
(begin
|
||||
(advance-tok!)
|
||||
(set! head (list :field head (ocaml-tok-value tok)))
|
||||
(loop)))))))
|
||||
(loop)
|
||||
head))))
|
||||
(set!
|
||||
parse-app
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((head (parse-atom)))
|
||||
((head (parse-atom-postfix)))
|
||||
(begin
|
||||
(define
|
||||
loop
|
||||
@@ -391,7 +411,7 @@
|
||||
(when
|
||||
(at-app-start?)
|
||||
(let
|
||||
((arg (parse-atom)))
|
||||
((arg (parse-atom-postfix)))
|
||||
(begin (set! head (list :app head arg)) (loop))))))
|
||||
(loop)
|
||||
head))))
|
||||
@@ -767,6 +787,7 @@
|
||||
((= (ocaml-tok-type (peek-tok)) "eof") nil)
|
||||
((at-op? ";;") nil)
|
||||
((at-kw? "let") nil)
|
||||
((at-kw? "module") nil)
|
||||
(else (begin (advance-tok!) (skip-to-boundary!))))))
|
||||
(define
|
||||
parse-decl-let
|
||||
@@ -818,6 +839,43 @@
|
||||
(let
|
||||
((expr-src (slice src expr-start (cur-pos))))
|
||||
(let ((expr (ocaml-parse expr-src))) (list :expr expr)))))))
|
||||
;; module M = struct DECLS end
|
||||
;; Parsed by sub-tokenising the body source between `struct` and
|
||||
;; the matching `end`. Nested modules / sigs increment depth.
|
||||
(define
|
||||
parse-decl-module
|
||||
(fn ()
|
||||
(advance-tok!)
|
||||
(let ((name (ocaml-tok-value (consume! "ctor" nil))))
|
||||
(begin
|
||||
(consume! "op" "=")
|
||||
(consume! "keyword" "struct")
|
||||
(let ((body-start (cur-pos)) (depth 1))
|
||||
(begin
|
||||
(define skip
|
||||
(fn ()
|
||||
(cond
|
||||
((>= idx tok-len) nil)
|
||||
((= (ocaml-tok-type (peek-tok)) "eof") nil)
|
||||
((at-kw? "struct")
|
||||
(begin (set! depth (+ depth 1)) (advance-tok!) (skip)))
|
||||
((at-kw? "begin")
|
||||
(begin (set! depth (+ depth 1)) (advance-tok!) (skip)))
|
||||
((at-kw? "sig")
|
||||
(begin (set! depth (+ depth 1)) (advance-tok!) (skip)))
|
||||
((at-kw? "end")
|
||||
(cond
|
||||
((= depth 1) nil)
|
||||
(else
|
||||
(begin (set! depth (- depth 1)) (advance-tok!) (skip)))))
|
||||
(else (begin (advance-tok!) (skip))))))
|
||||
(skip)
|
||||
(let ((body-end (cur-pos)))
|
||||
(begin
|
||||
(consume! "keyword" "end")
|
||||
(let ((body-src (slice src body-start body-end)))
|
||||
(let ((body-prog (ocaml-parse-program body-src)))
|
||||
(list :module-def name (rest body-prog))))))))))))
|
||||
(define
|
||||
loop
|
||||
(fn
|
||||
@@ -830,6 +888,8 @@
|
||||
((= (ocaml-tok-type (peek-tok)) "eof") nil)
|
||||
((at-kw? "let")
|
||||
(begin (append! decls (parse-decl-let)) (loop)))
|
||||
((at-kw? "module")
|
||||
(begin (append! decls (parse-decl-module)) (loop)))
|
||||
(else (begin (append! decls (parse-decl-expr)) (loop))))))))
|
||||
(loop)
|
||||
(cons :program decls)))))
|
||||
|
||||
Reference in New Issue
Block a user