erlang: list comprehensions (+12 tests)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
This commit is contained in:
@@ -123,6 +123,7 @@
|
||||
(= ty "send") (er-eval-send node env)
|
||||
(= ty "receive") (er-eval-receive node env)
|
||||
(= ty "try") (er-eval-try node env)
|
||||
(= ty "lc") (er-eval-lc node env)
|
||||
(= ty "match") (er-eval-match node env)
|
||||
:else (error (str "Erlang eval: unsupported node type '" ty "'"))))))
|
||||
|
||||
@@ -1281,3 +1282,84 @@
|
||||
(do
|
||||
(er-env-restore! env snap)
|
||||
(er-eval-of-clauses clauses subject env (+ i 1))))))))
|
||||
|
||||
;; ── list comprehensions ─────────────────────────────────────────
|
||||
;; `[E || Pat <- Source, FilterExpr, ...]`. Walk qualifiers in order:
|
||||
;; generators iterate their source list and bind the pattern (with
|
||||
;; env snapshot/restore so each iteration starts from the same
|
||||
;; baseline); filters skip when falsy. At the end of the qualifier
|
||||
;; chain, evaluate `head` and append to the accumulator. Build the
|
||||
;; final cons chain in O(n) with a single right-fold.
|
||||
(define
|
||||
er-eval-lc
|
||||
(fn
|
||||
(node env)
|
||||
(let
|
||||
((acc (list)))
|
||||
(er-lc-walk (get node :qualifiers) 0 (get node :head) env acc)
|
||||
(er-list-from-sx-list acc))))
|
||||
|
||||
(define
|
||||
er-lc-walk
|
||||
(fn
|
||||
(quals i head env acc)
|
||||
(if
|
||||
(>= i (len quals))
|
||||
(append! acc (er-eval-expr head env))
|
||||
(let
|
||||
((q (nth quals i)))
|
||||
(cond
|
||||
(= (get q :kind) "gen")
|
||||
(let
|
||||
((src (er-eval-expr (get q :source) env)))
|
||||
(er-lc-iter-gen
|
||||
src
|
||||
(get q :pattern)
|
||||
quals
|
||||
i
|
||||
head
|
||||
env
|
||||
acc))
|
||||
(= (get q :kind) "filter")
|
||||
(when
|
||||
(er-truthy? (er-eval-expr (get q :expr) env))
|
||||
(er-lc-walk quals (+ i 1) head env acc))
|
||||
:else (error "Erlang LC: unknown qualifier"))))))
|
||||
|
||||
(define
|
||||
er-lc-iter-gen
|
||||
(fn
|
||||
(src pat quals i head env acc)
|
||||
(cond
|
||||
(er-nil? src) nil
|
||||
(er-cons? src)
|
||||
(let
|
||||
((snap (er-env-copy env)))
|
||||
(when
|
||||
(er-match! pat (get src :head) env)
|
||||
(er-lc-walk quals (+ i 1) head env acc))
|
||||
(er-env-restore! env snap)
|
||||
(er-lc-iter-gen
|
||||
(get src :tail)
|
||||
pat
|
||||
quals
|
||||
i
|
||||
head
|
||||
env
|
||||
acc))
|
||||
:else (error "Erlang LC: generator source is not a list"))))
|
||||
|
||||
(define
|
||||
er-list-from-sx-list
|
||||
(fn
|
||||
(xs)
|
||||
(let
|
||||
((acc (list (er-mk-nil))))
|
||||
(for-each
|
||||
(fn
|
||||
(i)
|
||||
(let
|
||||
((j (- (- (len xs) 1) i)))
|
||||
(set-nth! acc 0 (er-mk-cons (nth xs j) (nth acc 0)))))
|
||||
(range 0 (len xs)))
|
||||
(nth acc 0))))
|
||||
|
||||
Reference in New Issue
Block a user