ruby: WIP — parser Phase 1 in-progress changes (save before session close)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 46s

228 insertions, 75 deletions on lib/ruby/parser.sx. Work mid-flight
when the tmux session was wrapped up. Saving here so it isn't lost;
not validated, not under test. Pick up from here when the Ruby loop
resumes.
This commit is contained in:
2026-06-06 15:20:09 +00:00
parent fa3274c394
commit f6dfc034d1

View File

@@ -725,8 +725,133 @@
(rb-p-advance!) (rb-p-advance!)
{:type "massign" :targets targets :value (rb-p-parse-multi-val)}))) {:type "massign" :targets targets :value (rb-p-parse-multi-val)})))
;; if cond [then] body [elsif cond [then] body ...] [else body] end
(define rb-p-parse-if
(fn ()
(rb-p-advance!)
(let ((cond-val (rb-p-parse-expr)))
(when (and (= (rb-p-type) "keyword") (= (rb-p-val) "then"))
(rb-p-advance!))
(rb-p-skip-seps!)
(let ((then-body (rb-p-parse-stmts (list "end" "else" "elsif"))))
(let ((elsifs (list)) (else-body nil))
(define rb-p-elsif-loop
(fn ()
(when (and (= (rb-p-type) "keyword") (= (rb-p-val) "elsif"))
(do
(rb-p-advance!)
(let ((ec (rb-p-parse-expr)))
(when (and (= (rb-p-type) "keyword") (= (rb-p-val) "then"))
(rb-p-advance!))
(rb-p-skip-seps!)
(let ((eb (rb-p-parse-stmts (list "end" "else" "elsif"))))
(append! elsifs {:cond ec :then eb})
(rb-p-elsif-loop)))))))
(rb-p-elsif-loop)
(when (and (= (rb-p-type) "keyword") (= (rb-p-val) "else"))
(do
(rb-p-advance!)
(rb-p-skip-seps!)
(set! else-body (rb-p-parse-stmts (list "end")))))
(rb-p-expect-kw! "end")
{:type "if" :cond cond-val :then then-body
:elsif elsifs :else else-body})))))
;; unless cond [then] body [else body] end
(define rb-p-parse-unless
(fn ()
(rb-p-advance!)
(let ((cond-val (rb-p-parse-expr)))
(when (and (= (rb-p-type) "keyword") (= (rb-p-val) "then"))
(rb-p-advance!))
(rb-p-skip-seps!)
(let ((then-body (rb-p-parse-stmts (list "end" "else"))))
(let ((else-body nil))
(when (and (= (rb-p-type) "keyword") (= (rb-p-val) "else"))
(do
(rb-p-advance!)
(rb-p-skip-seps!)
(set! else-body (rb-p-parse-stmts (list "end")))))
(rb-p-expect-kw! "end")
{:type "unless" :cond cond-val :then then-body :else else-body})))))
;; while cond [do] body end
(define rb-p-parse-while
(fn ()
(rb-p-advance!)
(let ((cond-val (rb-p-parse-expr)))
(when (and (= (rb-p-type) "keyword") (= (rb-p-val) "do"))
(rb-p-advance!))
(rb-p-skip-seps!)
(let ((body (rb-p-parse-stmts (list "end"))))
(rb-p-expect-kw! "end")
{:type "while" :cond cond-val :body body}))))
;; until cond [do] body end
(define rb-p-parse-until
(fn ()
(rb-p-advance!)
(let ((cond-val (rb-p-parse-expr)))
(when (and (= (rb-p-type) "keyword") (= (rb-p-val) "do"))
(rb-p-advance!))
(rb-p-skip-seps!)
(let ((body (rb-p-parse-stmts (list "end"))))
(rb-p-expect-kw! "end")
{:type "until" :cond cond-val :body body}))))
;; for var in iter [do] body end
(define rb-p-parse-for
(fn ()
(rb-p-advance!)
(let ((var (rb-p-val)))
(rb-p-advance!)
(rb-p-expect-kw! "in")
(let ((iter (rb-p-parse-expr)))
(when (and (= (rb-p-type) "keyword") (= (rb-p-val) "do"))
(rb-p-advance!))
(rb-p-skip-seps!)
(let ((body (rb-p-parse-stmts (list "end"))))
(rb-p-expect-kw! "end")
{:type "for" :var var :iter iter :body body})))))
;; case [expr] when val[, val] [then] body... [else body] end
(define rb-p-parse-case
(fn ()
(rb-p-advance!)
(let ((case-val (if (rb-p-sep?) nil (rb-p-parse-expr))))
(rb-p-skip-seps!)
(let ((whens (list)) (else-body nil))
(define rb-p-when-loop
(fn ()
(when (and (= (rb-p-type) "keyword") (= (rb-p-val) "when"))
(do
(rb-p-advance!)
(let ((wvals (list)))
(define rb-p-wval-loop
(fn ()
(append! wvals (rb-p-parse-assign))
(when (= (rb-p-type) "comma")
(do (rb-p-advance!) (rb-p-skip-newlines!) (rb-p-wval-loop)))))
(rb-p-wval-loop)
(when (and (= (rb-p-type) "keyword") (= (rb-p-val) "then"))
(rb-p-advance!))
(rb-p-skip-seps!)
(let ((wb (rb-p-parse-stmts (list "end" "else" "when"))))
(append! whens {:values wvals :body wb})
(rb-p-when-loop)))))))
(rb-p-when-loop)
(when (and (= (rb-p-type) "keyword") (= (rb-p-val) "else"))
(do
(rb-p-advance!)
(rb-p-skip-seps!)
(set! else-body (rb-p-parse-stmts (list "end")))))
(rb-p-expect-kw! "end")
{:type "case" :value case-val :whens whens :else else-body}))))
(define rb-p-parse-stmt (define rb-p-parse-stmt
(fn () (fn ()
(let ((node
(cond (cond
((and (= (rb-p-type) "keyword") (= (rb-p-val) "def")) ((and (= (rb-p-type) "keyword") (= (rb-p-val) "def"))
(rb-p-parse-def)) (rb-p-parse-def))
@@ -734,6 +859,18 @@
(rb-p-parse-class)) (rb-p-parse-class))
((and (= (rb-p-type) "keyword") (= (rb-p-val) "module")) ((and (= (rb-p-type) "keyword") (= (rb-p-val) "module"))
(rb-p-parse-module)) (rb-p-parse-module))
((and (= (rb-p-type) "keyword") (= (rb-p-val) "if"))
(rb-p-parse-if))
((and (= (rb-p-type) "keyword") (= (rb-p-val) "unless"))
(rb-p-parse-unless))
((and (= (rb-p-type) "keyword") (= (rb-p-val) "while"))
(rb-p-parse-while))
((and (= (rb-p-type) "keyword") (= (rb-p-val) "until"))
(rb-p-parse-until))
((and (= (rb-p-type) "keyword") (= (rb-p-val) "case"))
(rb-p-parse-case))
((and (= (rb-p-type) "keyword") (= (rb-p-val) "for"))
(rb-p-parse-for))
((and (= (rb-p-type) "keyword") (= (rb-p-val) "return")) ((and (= (rb-p-type) "keyword") (= (rb-p-val) "return"))
(do (rb-p-advance!) (do (rb-p-advance!)
{:type "return" {:type "return"
@@ -770,18 +907,16 @@
(= (get (rb-p-peek 1) :type) "comma")) (= (get (rb-p-peek 1) :type) "comma"))
(rb-p-parse-massign)) (rb-p-parse-massign))
(:else (:else
(let ((node (rb-p-parse-assign))) (let ((nd (rb-p-parse-assign)))
(if (and (= (get node :type) "send") (if (and (= (get nd :type) "send")
(= (len (get node :args)) 0) (= (len (get nd :args)) 0)
(nil? (get node :block))) (nil? (get nd :block)))
;; Bare send: check for block or no-paren args
(cond (cond
;; Block immediately follows (do or {)
((or (and (= (rb-p-type) "keyword") (= (rb-p-val) "do")) ((or (and (= (rb-p-type) "keyword") (= (rb-p-val) "do"))
(= (rb-p-type) "lbrace")) (= (rb-p-type) "lbrace"))
(let ((blk (rb-p-parse-block))) (let ((blk (rb-p-parse-block)))
{:type "send" :name (get node :name) :args (list) :block blk})) {:type "send" :name (get nd :name)
;; No-paren args (stop before block/sep/end keywords) :args (list) :block blk}))
((and (not (rb-p-sep?)) ((and (not (rb-p-sep?))
(not (= (rb-p-type) "eof")) (not (= (rb-p-type) "eof"))
(not (= (rb-p-type) "op")) (not (= (rb-p-type) "op"))
@@ -792,17 +927,35 @@
(not (= (rb-p-type) "rbrace")) (not (= (rb-p-type) "rbrace"))
(not (= (rb-p-type) "lbrace")) (not (= (rb-p-type) "lbrace"))
(not (and (= (rb-p-type) "keyword") (not (and (= (rb-p-type) "keyword")
(contains? (list "end" "else" "elsif" "when" (contains? (list "end" "else" "elsif"
"rescue" "ensure" "then" "do" "when" "rescue" "ensure"
"and" "or" "not") "then" "do" "and" "or"
"not" "if" "unless"
"while" "until")
(rb-p-val))))) (rb-p-val)))))
(let ((args (rb-p-parse-args-bare)) (let ((args (rb-p-parse-args-bare))
(blk (rb-p-parse-block))) (blk (rb-p-parse-block)))
(if (> (len args) 0) (if (> (len args) 0)
{:type "send" :name (get node :name) :args args :block blk} {:type "send" :name (get nd :name)
node))) :args args :block blk}
(:else node)) nd)))
node)))))) (:else nd))
nd))))))
;; Postfix modifiers
(cond
((and (= (rb-p-type) "keyword") (= (rb-p-val) "if"))
(do (rb-p-advance!)
{:type "postfix-if" :cond (rb-p-parse-expr) :body node}))
((and (= (rb-p-type) "keyword") (= (rb-p-val) "unless"))
(do (rb-p-advance!)
{:type "postfix-unless" :cond (rb-p-parse-expr) :body node}))
((and (= (rb-p-type) "keyword") (= (rb-p-val) "while"))
(do (rb-p-advance!)
{:type "postfix-while" :cond (rb-p-parse-expr) :body node}))
((and (= (rb-p-type) "keyword") (= (rb-p-val) "until"))
(do (rb-p-advance!)
{:type "postfix-until" :cond (rb-p-parse-expr) :body node}))
(:else node)))))
(define rb-p-parse-stmts (define rb-p-parse-stmts
(fn (terminators) (fn (terminators)