erlang: fold lists/proplists BIFs into transpile.sx + runtime.sx (completes 27dedf9b)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m9s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m9s
27dedf9b deleted lists-ext.sx but a botched git-add left the actual
fold-in unstaged, so HEAD briefly referenced functions that weren't
registered. This commit lands them:
- transpile.sx: function bodies appended next to existing er-bif-lists-*
- runtime.sx: registrations inside er-register-builtin-bifs!
- conformance.sh: drop the lists-ext.sx load; keep the lists_ext suite
Conformance 874/874 (verified on the combined tree before push).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -51,7 +51,6 @@ cat > "$TMPFILE" << 'EPOCHS'
|
||||
(load "lib/erlang/parser-module.sx")
|
||||
(load "lib/erlang/transpile.sx")
|
||||
(load "lib/erlang/runtime.sx")
|
||||
(load "lib/erlang/lists-ext.sx")
|
||||
(load "lib/erlang/tests/tokenize.sx")
|
||||
(load "lib/erlang/tests/parse.sx")
|
||||
(load "lib/erlang/tests/eval.sx")
|
||||
|
||||
@@ -1753,6 +1753,42 @@
|
||||
(er-register-pure-bif! "lists" "any" 2 er-bif-lists-any)
|
||||
(er-register-pure-bif! "lists" "all" 2 er-bif-lists-all)
|
||||
(er-register-pure-bif! "lists" "duplicate" 2 er-bif-lists-duplicate)
|
||||
(er-register-pure-bif! "lists" "sort" 1 er-bif-lists-sort)
|
||||
(er-register-pure-bif! "lists" "sort" 2 er-bif-lists-sort)
|
||||
(er-register-pure-bif! "lists" "usort" 1 er-bif-lists-usort)
|
||||
(er-register-pure-bif! "lists" "keyfind" 3 er-bif-lists-keyfind)
|
||||
(er-register-pure-bif! "lists" "keymember" 3 er-bif-lists-keymember)
|
||||
(er-register-pure-bif! "lists" "keydelete" 3 er-bif-lists-keydelete)
|
||||
(er-register-pure-bif! "lists" "keyreplace" 4 er-bif-lists-keyreplace)
|
||||
(er-register-pure-bif! "lists" "keystore" 4 er-bif-lists-keystore)
|
||||
(er-register-pure-bif! "lists" "keytake" 3 er-bif-lists-keytake)
|
||||
(er-register-pure-bif! "lists" "keysort" 2 er-bif-lists-keysort)
|
||||
(er-register-pure-bif! "lists" "foldr" 3 er-bif-lists-foldr)
|
||||
(er-register-pure-bif! "lists" "partition" 2 er-bif-lists-partition)
|
||||
(er-register-pure-bif! "lists" "takewhile" 2 er-bif-lists-takewhile)
|
||||
(er-register-pure-bif! "lists" "dropwhile" 2 er-bif-lists-dropwhile)
|
||||
(er-register-pure-bif! "lists" "splitwith" 2 er-bif-lists-splitwith)
|
||||
(er-register-pure-bif! "lists" "flatten" 1 er-bif-lists-flatten)
|
||||
(er-register-pure-bif! "lists" "max" 1 er-bif-lists-max)
|
||||
(er-register-pure-bif! "lists" "min" 1 er-bif-lists-min)
|
||||
(er-register-pure-bif! "lists" "zip" 2 er-bif-lists-zip)
|
||||
(er-register-pure-bif! "lists" "zipwith" 3 er-bif-lists-zipwith)
|
||||
(er-register-pure-bif! "lists" "unzip" 1 er-bif-lists-unzip)
|
||||
(er-register-pure-bif! "lists" "sublist" 2 er-bif-lists-sublist)
|
||||
(er-register-pure-bif! "lists" "sublist" 3 er-bif-lists-sublist)
|
||||
(er-register-pure-bif! "lists" "nthtail" 2 er-bif-lists-nthtail)
|
||||
(er-register-pure-bif! "lists" "split" 2 er-bif-lists-split)
|
||||
(er-register-pure-bif! "lists" "droplast" 1 er-bif-lists-droplast)
|
||||
(er-register-pure-bif! "lists" "flatmap" 2 er-bif-lists-flatmap)
|
||||
(er-register-pure-bif! "lists" "filtermap" 2 er-bif-lists-filtermap)
|
||||
(er-register-pure-bif! "lists" "mapfoldl" 3 er-bif-lists-mapfoldl)
|
||||
(er-register-pure-bif! "lists" "search" 2 er-bif-lists-search)
|
||||
(er-register-pure-bif! "proplists" "get_value" 2 er-bif-pl-get-value)
|
||||
(er-register-pure-bif! "proplists" "get_value" 3 er-bif-pl-get-value)
|
||||
(er-register-pure-bif! "proplists" "get_all_values" 2 er-bif-pl-get-all-values)
|
||||
(er-register-pure-bif! "proplists" "is_defined" 2 er-bif-pl-is-defined)
|
||||
(er-register-pure-bif! "proplists" "lookup" 2 er-bif-pl-lookup)
|
||||
(er-register-pure-bif! "proplists" "delete" 2 er-bif-pl-delete)
|
||||
;; io module — side-effecting (writes to io buffer)
|
||||
(er-register-bif! "io" "format" 1 er-bif-io-format)
|
||||
(er-register-bif! "io" "format" 2 er-bif-io-format)
|
||||
|
||||
@@ -2039,4 +2039,657 @@
|
||||
(range 0 (len ks)))
|
||||
out)))
|
||||
|
||||
;; ── extra lists + proplists BIFs (folded from lists-ext.sx) ──
|
||||
;; ── cons <-> SX-list bridges ──────────────────────────────────────
|
||||
(define
|
||||
er-cons->sxlist
|
||||
(fn (lst)
|
||||
(cond
|
||||
(er-nil? lst) (list)
|
||||
(er-cons? lst) (cons (get lst :head) (er-cons->sxlist (get lst :tail)))
|
||||
:else (raise (er-mk-error-marker (er-mk-atom "badarg"))))))
|
||||
|
||||
(define
|
||||
er-sxlist->cons
|
||||
(fn (xs)
|
||||
(if (= (len xs) 0)
|
||||
(er-mk-nil)
|
||||
(er-mk-cons (first xs) (er-sxlist->cons (rest xs))))))
|
||||
|
||||
;; ── merge sort over SX lists (stable) ─────────────────────────────
|
||||
(define
|
||||
er-ext-take
|
||||
(fn (xs n)
|
||||
(if (or (= n 0) (= (len xs) 0))
|
||||
(list)
|
||||
(cons (first xs) (er-ext-take (rest xs) (- n 1))))))
|
||||
|
||||
(define
|
||||
er-ext-drop
|
||||
(fn (xs n)
|
||||
(if (or (= n 0) (= (len xs) 0))
|
||||
xs
|
||||
(er-ext-drop (rest xs) (- n 1)))))
|
||||
|
||||
;; le? returns a truthy value (Erlang bool atom or SX bool) iff a
|
||||
;; should sort at-or-before b. Taking from the left half first on a
|
||||
;; true result keeps the sort stable.
|
||||
(define
|
||||
er-ext-merge
|
||||
(fn (a b le?)
|
||||
(cond
|
||||
(= (len a) 0) b
|
||||
(= (len b) 0) a
|
||||
(er-truthy? (le? (first a) (first b)))
|
||||
(cons (first a) (er-ext-merge (rest a) b le?))
|
||||
:else (cons (first b) (er-ext-merge a (rest b) le?)))))
|
||||
|
||||
(define
|
||||
er-ext-msort
|
||||
(fn (xs le?)
|
||||
(if (<= (len xs) 1)
|
||||
xs
|
||||
(let ((mid (quotient (len xs) 2)))
|
||||
(er-ext-merge
|
||||
(er-ext-msort (er-ext-take xs mid) le?)
|
||||
(er-ext-msort (er-ext-drop xs mid) le?)
|
||||
le?)))))
|
||||
|
||||
;; Full Erlang term order. The shared er-lt? (transpile.sx) only
|
||||
;; deep-compares numbers/atoms/strings and otherwise falls back to a
|
||||
;; coarse type rank — so any two tuples (or two lists) compare as
|
||||
;; order-equal there. er-ext-lt? adds the missing structural cases:
|
||||
;; tuples by arity then elementwise, lists elementwise with a shorter
|
||||
;; proper prefix sorting first. Cross-type cases delegate to er-lt?.
|
||||
(define
|
||||
er-ext-lt-seq
|
||||
(fn (ea eb i)
|
||||
(cond
|
||||
(>= i (len ea)) false
|
||||
(er-ext-lt? (nth ea i) (nth eb i)) true
|
||||
(er-ext-lt? (nth eb i) (nth ea i)) false
|
||||
:else (er-ext-lt-seq ea eb (+ i 1)))))
|
||||
|
||||
(define
|
||||
er-ext-lt?
|
||||
(fn (a b)
|
||||
(cond
|
||||
(and (er-tuple? a) (er-tuple? b))
|
||||
(let ((ea (get a :elements)) (eb (get b :elements)))
|
||||
(cond
|
||||
(< (len ea) (len eb)) true
|
||||
(> (len ea) (len eb)) false
|
||||
:else (er-ext-lt-seq ea eb 0)))
|
||||
(and (er-cons? a) (er-cons? b))
|
||||
(cond
|
||||
(er-ext-lt? (get a :head) (get b :head)) true
|
||||
(er-ext-lt? (get b :head) (get a :head)) false
|
||||
:else (er-ext-lt? (get a :tail) (get b :tail)))
|
||||
(and (er-nil? a) (er-cons? b)) true
|
||||
(and (er-cons? a) (er-nil? b)) false
|
||||
(and (er-nil? a) (er-nil? b)) false
|
||||
:else (er-lt? a b))))
|
||||
|
||||
;; Default Erlang term order: a =< b == not (b < a).
|
||||
(define
|
||||
er-ext-term-le
|
||||
(fn (a b) (er-bool (not (er-ext-lt? b a)))))
|
||||
|
||||
;; ── lists:sort/1, lists:sort/2 ────────────────────────────────────
|
||||
(define
|
||||
er-bif-lists-sort
|
||||
(fn (vs)
|
||||
(cond
|
||||
(= (len vs) 1)
|
||||
(er-sxlist->cons
|
||||
(er-ext-msort (er-cons->sxlist (nth vs 0)) er-ext-term-le))
|
||||
(= (len vs) 2)
|
||||
(let ((f (nth vs 0)) (lst (nth vs 1)))
|
||||
(er-sxlist->cons
|
||||
(er-ext-msort
|
||||
(er-cons->sxlist lst)
|
||||
(fn (a b) (er-apply-fun f (list a b))))))
|
||||
:else (error "Erlang: lists:sort: wrong arity"))))
|
||||
|
||||
;; ── lists:usort/1 (sort then drop adjacent term-equal dups) ───────
|
||||
(define
|
||||
er-ext-dedup
|
||||
(fn (xs)
|
||||
(cond
|
||||
(= (len xs) 0) (list)
|
||||
(= (len xs) 1) xs
|
||||
(er-equal? (first xs) (nth xs 1)) (er-ext-dedup (rest xs))
|
||||
:else (cons (first xs) (er-ext-dedup (rest xs))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-usort
|
||||
(fn (vs)
|
||||
(let ((lst (er-bif-arg1 vs "lists:usort")))
|
||||
(er-sxlist->cons
|
||||
(er-ext-dedup
|
||||
(er-ext-msort (er-cons->sxlist lst) er-ext-term-le))))))
|
||||
|
||||
;; ── keylists (lists of tuples keyed on element N, 1-indexed) ──────
|
||||
;; keyfind/keymember/keydelete/keyreplace/keystore/keytake/keysort.
|
||||
;; Key comparison is == (er-equal?), matching the standard lib. Only
|
||||
;; the FIRST matching tuple is acted on. Non-tuples / tuples shorter
|
||||
;; than N never match and are passed through unchanged.
|
||||
(define
|
||||
er-ext-tup-elem
|
||||
(fn (tup n)
|
||||
(if (er-tuple? tup)
|
||||
(let ((es (get tup :elements)))
|
||||
(if (and (>= n 1) (<= n (len es))) (nth es (- n 1)) nil))
|
||||
nil)))
|
||||
|
||||
(define
|
||||
er-ext-key-match?
|
||||
(fn (key n tup)
|
||||
(and
|
||||
(er-tuple? tup)
|
||||
(>= n 1)
|
||||
(<= n (len (get tup :elements)))
|
||||
(er-equal? key (nth (get tup :elements) (- n 1))))))
|
||||
|
||||
(define
|
||||
er-ext-keyfind
|
||||
(fn (key n lst)
|
||||
(cond
|
||||
(er-nil? lst) (er-mk-atom "false")
|
||||
(er-cons? lst)
|
||||
(if (er-ext-key-match? key n (get lst :head))
|
||||
(get lst :head)
|
||||
(er-ext-keyfind key n (get lst :tail)))
|
||||
:else (er-mk-atom "false"))))
|
||||
|
||||
(define
|
||||
er-ext-keydelete
|
||||
(fn (key n lst)
|
||||
(cond
|
||||
(er-nil? lst) (er-mk-nil)
|
||||
(er-cons? lst)
|
||||
(if (er-ext-key-match? key n (get lst :head))
|
||||
(get lst :tail)
|
||||
(er-mk-cons (get lst :head) (er-ext-keydelete key n (get lst :tail))))
|
||||
:else lst)))
|
||||
|
||||
(define
|
||||
er-ext-keyreplace
|
||||
(fn (key n lst new)
|
||||
(cond
|
||||
(er-nil? lst) (er-mk-nil)
|
||||
(er-cons? lst)
|
||||
(if (er-ext-key-match? key n (get lst :head))
|
||||
(er-mk-cons new (get lst :tail))
|
||||
(er-mk-cons (get lst :head) (er-ext-keyreplace key n (get lst :tail) new)))
|
||||
:else lst)))
|
||||
|
||||
(define
|
||||
er-ext-keystore
|
||||
(fn (key n lst new)
|
||||
(cond
|
||||
(er-nil? lst) (er-mk-cons new (er-mk-nil))
|
||||
(er-cons? lst)
|
||||
(if (er-ext-key-match? key n (get lst :head))
|
||||
(er-mk-cons new (get lst :tail))
|
||||
(er-mk-cons (get lst :head) (er-ext-keystore key n (get lst :tail) new)))
|
||||
:else lst)))
|
||||
|
||||
(define
|
||||
er-bif-lists-keyfind
|
||||
(fn (vs) (er-ext-keyfind (nth vs 0) (nth vs 1) (nth vs 2))))
|
||||
|
||||
(define
|
||||
er-bif-lists-keymember
|
||||
(fn (vs)
|
||||
(er-bool (not (er-atom? (er-ext-keyfind (nth vs 0) (nth vs 1) (nth vs 2)))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-keydelete
|
||||
(fn (vs) (er-ext-keydelete (nth vs 0) (nth vs 1) (nth vs 2))))
|
||||
|
||||
(define
|
||||
er-bif-lists-keyreplace
|
||||
(fn (vs) (er-ext-keyreplace (nth vs 0) (nth vs 1) (nth vs 2) (nth vs 3))))
|
||||
|
||||
(define
|
||||
er-bif-lists-keystore
|
||||
(fn (vs) (er-ext-keystore (nth vs 0) (nth vs 1) (nth vs 2) (nth vs 3))))
|
||||
|
||||
(define
|
||||
er-bif-lists-keytake
|
||||
(fn (vs)
|
||||
(let ((key (nth vs 0)) (n (nth vs 1)) (lst (nth vs 2)))
|
||||
(let ((hit (er-ext-keyfind key n lst)))
|
||||
(if (er-atom? hit)
|
||||
(er-mk-atom "false")
|
||||
(er-mk-tuple
|
||||
(list (er-mk-atom "value") hit (er-ext-keydelete key n lst))))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-keysort
|
||||
(fn (vs)
|
||||
(let ((n (nth vs 0)) (lst (nth vs 1)))
|
||||
(er-sxlist->cons
|
||||
(er-ext-msort
|
||||
(er-cons->sxlist lst)
|
||||
(fn (a b)
|
||||
(er-bool
|
||||
(not (er-ext-lt? (er-ext-tup-elem b n) (er-ext-tup-elem a n))))))))))
|
||||
|
||||
;; ── higher-order traversal (foldr / partition / *while) ───────────
|
||||
(define
|
||||
er-ext-foldr
|
||||
(fn (f acc lst)
|
||||
(cond
|
||||
(er-nil? lst) acc
|
||||
(er-cons? lst)
|
||||
(er-apply-fun f (list (get lst :head) (er-ext-foldr f acc (get lst :tail))))
|
||||
:else (raise (er-mk-error-marker (er-mk-atom "badarg"))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-foldr
|
||||
(fn (vs) (er-ext-foldr (nth vs 0) (nth vs 1) (nth vs 2))))
|
||||
|
||||
(define
|
||||
er-ext-partition
|
||||
(fn (pred lst yes no)
|
||||
(cond
|
||||
(er-nil? lst)
|
||||
(er-mk-tuple
|
||||
(list
|
||||
(er-list-reverse-iter yes (er-mk-nil))
|
||||
(er-list-reverse-iter no (er-mk-nil))))
|
||||
(er-cons? lst)
|
||||
(if (er-truthy? (er-apply-fun pred (list (get lst :head))))
|
||||
(er-ext-partition pred (get lst :tail) (er-mk-cons (get lst :head) yes) no)
|
||||
(er-ext-partition pred (get lst :tail) yes (er-mk-cons (get lst :head) no)))
|
||||
:else (raise (er-mk-error-marker (er-mk-atom "badarg"))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-partition
|
||||
(fn (vs) (er-ext-partition (nth vs 0) (nth vs 1) (er-mk-nil) (er-mk-nil))))
|
||||
|
||||
(define
|
||||
er-ext-takewhile
|
||||
(fn (pred lst)
|
||||
(cond
|
||||
(er-nil? lst) (er-mk-nil)
|
||||
(er-cons? lst)
|
||||
(if (er-truthy? (er-apply-fun pred (list (get lst :head))))
|
||||
(er-mk-cons (get lst :head) (er-ext-takewhile pred (get lst :tail)))
|
||||
(er-mk-nil))
|
||||
:else (er-mk-nil))))
|
||||
|
||||
(define
|
||||
er-bif-lists-takewhile
|
||||
(fn (vs) (er-ext-takewhile (nth vs 0) (nth vs 1))))
|
||||
|
||||
(define
|
||||
er-ext-dropwhile
|
||||
(fn (pred lst)
|
||||
(cond
|
||||
(er-nil? lst) (er-mk-nil)
|
||||
(er-cons? lst)
|
||||
(if (er-truthy? (er-apply-fun pred (list (get lst :head))))
|
||||
(er-ext-dropwhile pred (get lst :tail))
|
||||
lst)
|
||||
:else lst)))
|
||||
|
||||
(define
|
||||
er-bif-lists-dropwhile
|
||||
(fn (vs) (er-ext-dropwhile (nth vs 0) (nth vs 1))))
|
||||
|
||||
(define
|
||||
er-bif-lists-splitwith
|
||||
(fn (vs)
|
||||
(let ((pred (nth vs 0)) (lst (nth vs 1)))
|
||||
(er-mk-tuple
|
||||
(list (er-ext-takewhile pred lst) (er-ext-dropwhile pred lst))))))
|
||||
|
||||
;; ── structural / aggregate (flatten / max / min) ──────────────────
|
||||
(define
|
||||
er-ext-flatten
|
||||
(fn (lst)
|
||||
(cond
|
||||
(er-nil? lst) (er-mk-nil)
|
||||
(er-cons? lst)
|
||||
(let ((h (get lst :head)))
|
||||
(if (or (er-nil? h) (er-cons? h))
|
||||
(er-list-append (er-ext-flatten h) (er-ext-flatten (get lst :tail)))
|
||||
(er-mk-cons h (er-ext-flatten (get lst :tail)))))
|
||||
:else (raise (er-mk-error-marker (er-mk-atom "badarg"))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-flatten
|
||||
(fn (vs) (er-ext-flatten (er-bif-arg1 vs "lists:flatten"))))
|
||||
|
||||
(define
|
||||
er-ext-extreme
|
||||
(fn (lst best lt?)
|
||||
(cond
|
||||
(er-nil? lst) best
|
||||
(er-cons? lst)
|
||||
(er-ext-extreme
|
||||
(get lst :tail)
|
||||
(if (lt? best (get lst :head)) (get lst :head) best)
|
||||
lt?)
|
||||
:else best)))
|
||||
|
||||
(define
|
||||
er-bif-lists-max
|
||||
(fn (vs)
|
||||
(let ((lst (er-bif-arg1 vs "lists:max")))
|
||||
(if (er-cons? lst)
|
||||
(er-ext-extreme (get lst :tail) (get lst :head)
|
||||
(fn (a b) (er-ext-lt? a b)))
|
||||
(raise (er-mk-error-marker (er-mk-atom "badarg")))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-min
|
||||
(fn (vs)
|
||||
(let ((lst (er-bif-arg1 vs "lists:min")))
|
||||
(if (er-cons? lst)
|
||||
(er-ext-extreme (get lst :tail) (get lst :head)
|
||||
(fn (a b) (er-ext-lt? b a)))
|
||||
(raise (er-mk-error-marker (er-mk-atom "badarg")))))))
|
||||
|
||||
;; ── zip family (zip / zipwith / unzip) ────────────────────────────
|
||||
;; Length mismatch raises badarg (real Erlang raises function_clause;
|
||||
;; badarg is the closest in-port equivalent).
|
||||
(define
|
||||
er-ext-zip
|
||||
(fn (a b)
|
||||
(cond
|
||||
(and (er-nil? a) (er-nil? b)) (er-mk-nil)
|
||||
(and (er-cons? a) (er-cons? b))
|
||||
(er-mk-cons
|
||||
(er-mk-tuple (list (get a :head) (get b :head)))
|
||||
(er-ext-zip (get a :tail) (get b :tail)))
|
||||
:else (raise (er-mk-error-marker (er-mk-atom "badarg"))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-zip
|
||||
(fn (vs) (er-ext-zip (nth vs 0) (nth vs 1))))
|
||||
|
||||
(define
|
||||
er-ext-zipwith
|
||||
(fn (f a b)
|
||||
(cond
|
||||
(and (er-nil? a) (er-nil? b)) (er-mk-nil)
|
||||
(and (er-cons? a) (er-cons? b))
|
||||
(er-mk-cons
|
||||
(er-apply-fun f (list (get a :head) (get b :head)))
|
||||
(er-ext-zipwith f (get a :tail) (get b :tail)))
|
||||
:else (raise (er-mk-error-marker (er-mk-atom "badarg"))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-zipwith
|
||||
(fn (vs) (er-ext-zipwith (nth vs 0) (nth vs 1) (nth vs 2))))
|
||||
|
||||
(define
|
||||
er-ext-unzip
|
||||
(fn (lst as bs)
|
||||
(cond
|
||||
(er-nil? lst)
|
||||
(er-mk-tuple
|
||||
(list
|
||||
(er-list-reverse-iter as (er-mk-nil))
|
||||
(er-list-reverse-iter bs (er-mk-nil))))
|
||||
(and (er-cons? lst) (er-tuple? (get lst :head)))
|
||||
(let ((es (get (get lst :head) :elements)))
|
||||
(if (= (len es) 2)
|
||||
(er-ext-unzip (get lst :tail)
|
||||
(er-mk-cons (nth es 0) as)
|
||||
(er-mk-cons (nth es 1) bs))
|
||||
(raise (er-mk-error-marker (er-mk-atom "badarg")))))
|
||||
:else (raise (er-mk-error-marker (er-mk-atom "badarg"))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-unzip
|
||||
(fn (vs)
|
||||
(er-ext-unzip (er-bif-arg1 vs "lists:unzip") (er-mk-nil) (er-mk-nil))))
|
||||
|
||||
;; ── slicing (sublist / nthtail / split / droplast) ────────────────
|
||||
(define
|
||||
er-ext-sublist2
|
||||
(fn (lst n)
|
||||
(cond
|
||||
(or (<= n 0) (er-nil? lst)) (er-mk-nil)
|
||||
(er-cons? lst)
|
||||
(er-mk-cons (get lst :head) (er-ext-sublist2 (get lst :tail) (- n 1)))
|
||||
:else (er-mk-nil))))
|
||||
|
||||
;; lenient drop (used by sublist/3); never raises
|
||||
(define
|
||||
er-ext-drop-cons
|
||||
(fn (lst n)
|
||||
(cond
|
||||
(or (<= n 0) (er-nil? lst)) lst
|
||||
(er-cons? lst) (er-ext-drop-cons (get lst :tail) (- n 1))
|
||||
:else lst)))
|
||||
|
||||
;; strict drop (used by nthtail/2 + split/2); raises if list too short
|
||||
(define
|
||||
er-ext-nthtail
|
||||
(fn (n lst)
|
||||
(cond
|
||||
(<= n 0) lst
|
||||
(er-cons? lst) (er-ext-nthtail (- n 1) (get lst :tail))
|
||||
:else (raise (er-mk-error-marker (er-mk-atom "badarg"))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-sublist
|
||||
(fn (vs)
|
||||
(cond
|
||||
(= (len vs) 2) (er-ext-sublist2 (nth vs 0) (nth vs 1))
|
||||
(= (len vs) 3)
|
||||
(er-ext-sublist2
|
||||
(er-ext-drop-cons (nth vs 0) (- (nth vs 1) 1))
|
||||
(nth vs 2))
|
||||
:else (error "Erlang: lists:sublist: wrong arity"))))
|
||||
|
||||
(define
|
||||
er-bif-lists-nthtail
|
||||
(fn (vs) (er-ext-nthtail (nth vs 0) (nth vs 1))))
|
||||
|
||||
(define
|
||||
er-bif-lists-split
|
||||
(fn (vs)
|
||||
(let ((n (nth vs 0)) (lst (nth vs 1)))
|
||||
(er-mk-tuple
|
||||
(list (er-ext-sublist2 lst n) (er-ext-nthtail n lst))))))
|
||||
|
||||
(define
|
||||
er-ext-droplast
|
||||
(fn (lst)
|
||||
(cond
|
||||
(and (er-cons? lst) (er-nil? (get lst :tail))) (er-mk-nil)
|
||||
(er-cons? lst) (er-mk-cons (get lst :head) (er-ext-droplast (get lst :tail)))
|
||||
:else (raise (er-mk-error-marker (er-mk-atom "badarg"))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-droplast
|
||||
(fn (vs) (er-ext-droplast (er-bif-arg1 vs "lists:droplast"))))
|
||||
|
||||
;; ── more higher-order (flatmap / filtermap / mapfoldl / search) ───
|
||||
(define
|
||||
er-ext-flatmap
|
||||
(fn (f lst)
|
||||
(cond
|
||||
(er-nil? lst) (er-mk-nil)
|
||||
(er-cons? lst)
|
||||
(er-list-append
|
||||
(er-apply-fun f (list (get lst :head)))
|
||||
(er-ext-flatmap f (get lst :tail)))
|
||||
:else (raise (er-mk-error-marker (er-mk-atom "badarg"))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-flatmap
|
||||
(fn (vs) (er-ext-flatmap (nth vs 0) (nth vs 1))))
|
||||
|
||||
(define
|
||||
er-ext-atom-true?
|
||||
(fn (v) (and (er-atom? v) (= (get v :name) "true"))))
|
||||
|
||||
(define
|
||||
er-ext-filtermap
|
||||
(fn (f lst)
|
||||
(cond
|
||||
(er-nil? lst) (er-mk-nil)
|
||||
(er-cons? lst)
|
||||
(let ((r (er-apply-fun f (list (get lst :head)))))
|
||||
(cond
|
||||
(er-ext-atom-true? r)
|
||||
(er-mk-cons (get lst :head) (er-ext-filtermap f (get lst :tail)))
|
||||
(and
|
||||
(er-tuple? r)
|
||||
(= (len (get r :elements)) 2)
|
||||
(er-ext-atom-true? (nth (get r :elements) 0)))
|
||||
(er-mk-cons (nth (get r :elements) 1) (er-ext-filtermap f (get lst :tail)))
|
||||
:else (er-ext-filtermap f (get lst :tail))))
|
||||
:else (raise (er-mk-error-marker (er-mk-atom "badarg"))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-filtermap
|
||||
(fn (vs) (er-ext-filtermap (nth vs 0) (nth vs 1))))
|
||||
|
||||
(define
|
||||
er-ext-mapfoldl
|
||||
(fn (f acc lst mapped)
|
||||
(cond
|
||||
(er-nil? lst)
|
||||
(er-mk-tuple (list (er-list-reverse-iter mapped (er-mk-nil)) acc))
|
||||
(er-cons? lst)
|
||||
(let ((r (er-apply-fun f (list (get lst :head) acc))))
|
||||
(let ((es (get r :elements)))
|
||||
(er-ext-mapfoldl f (nth es 1) (get lst :tail)
|
||||
(er-mk-cons (nth es 0) mapped))))
|
||||
:else (raise (er-mk-error-marker (er-mk-atom "badarg"))))))
|
||||
|
||||
(define
|
||||
er-bif-lists-mapfoldl
|
||||
(fn (vs) (er-ext-mapfoldl (nth vs 0) (nth vs 1) (nth vs 2) (er-mk-nil))))
|
||||
|
||||
(define
|
||||
er-ext-search
|
||||
(fn (pred lst)
|
||||
(cond
|
||||
(er-nil? lst) (er-mk-atom "false")
|
||||
(er-cons? lst)
|
||||
(if (er-truthy? (er-apply-fun pred (list (get lst :head))))
|
||||
(er-mk-tuple (list (er-mk-atom "value") (get lst :head)))
|
||||
(er-ext-search pred (get lst :tail)))
|
||||
:else (er-mk-atom "false"))))
|
||||
|
||||
(define
|
||||
er-bif-lists-search
|
||||
(fn (vs) (er-ext-search (nth vs 0) (nth vs 1))))
|
||||
|
||||
;; ── proplists module ──────────────────────────────────────────────
|
||||
;; A property list element is either a bare atom A (shorthand for
|
||||
;; {A, true}) or a tuple whose first element is the key (value = its
|
||||
;; second element, or true for a 1-tuple). Lookups use the FIRST match.
|
||||
(define
|
||||
er-ext-pl-key-of
|
||||
(fn (e)
|
||||
(cond
|
||||
(er-atom? e) e
|
||||
(and (er-tuple? e) (>= (len (get e :elements)) 1)) (nth (get e :elements) 0)
|
||||
:else nil)))
|
||||
|
||||
(define
|
||||
er-ext-pl-val-of
|
||||
(fn (e)
|
||||
(cond
|
||||
(and (er-tuple? e) (>= (len (get e :elements)) 2)) (nth (get e :elements) 1)
|
||||
:else (er-mk-atom "true"))))
|
||||
|
||||
(define
|
||||
er-ext-pl-match?
|
||||
(fn (key e)
|
||||
(let ((k (er-ext-pl-key-of e)))
|
||||
(and (not (= k nil)) (er-equal? key k)))))
|
||||
|
||||
(define
|
||||
er-ext-pl-get-value
|
||||
(fn (key lst default)
|
||||
(cond
|
||||
(er-nil? lst) default
|
||||
(er-cons? lst)
|
||||
(if (er-ext-pl-match? key (get lst :head))
|
||||
(er-ext-pl-val-of (get lst :head))
|
||||
(er-ext-pl-get-value key (get lst :tail) default))
|
||||
:else default)))
|
||||
|
||||
(define
|
||||
er-bif-pl-get-value
|
||||
(fn (vs)
|
||||
(cond
|
||||
(= (len vs) 2)
|
||||
(er-ext-pl-get-value (nth vs 0) (nth vs 1) (er-mk-atom "undefined"))
|
||||
(= (len vs) 3)
|
||||
(er-ext-pl-get-value (nth vs 0) (nth vs 1) (nth vs 2))
|
||||
:else (error "Erlang: proplists:get_value: wrong arity"))))
|
||||
|
||||
(define
|
||||
er-ext-pl-all
|
||||
(fn (key lst acc)
|
||||
(cond
|
||||
(er-nil? lst) (er-list-reverse-iter acc (er-mk-nil))
|
||||
(er-cons? lst)
|
||||
(er-ext-pl-all key (get lst :tail)
|
||||
(if (er-ext-pl-match? key (get lst :head))
|
||||
(er-mk-cons (er-ext-pl-val-of (get lst :head)) acc)
|
||||
acc))
|
||||
:else (er-list-reverse-iter acc (er-mk-nil)))))
|
||||
|
||||
(define
|
||||
er-bif-pl-get-all-values
|
||||
(fn (vs) (er-ext-pl-all (nth vs 0) (nth vs 1) (er-mk-nil))))
|
||||
|
||||
(define
|
||||
er-ext-pl-defined?
|
||||
(fn (key lst)
|
||||
(cond
|
||||
(er-nil? lst) false
|
||||
(er-cons? lst)
|
||||
(if (er-ext-pl-match? key (get lst :head))
|
||||
true
|
||||
(er-ext-pl-defined? key (get lst :tail)))
|
||||
:else false)))
|
||||
|
||||
(define
|
||||
er-bif-pl-is-defined
|
||||
(fn (vs) (er-bool (er-ext-pl-defined? (nth vs 0) (nth vs 1)))))
|
||||
|
||||
(define
|
||||
er-ext-pl-lookup
|
||||
(fn (key lst)
|
||||
(cond
|
||||
(er-nil? lst) (er-mk-atom "none")
|
||||
(er-cons? lst)
|
||||
(if (er-ext-pl-match? key (get lst :head))
|
||||
(let ((e (get lst :head)))
|
||||
(if (er-tuple? e) e (er-mk-tuple (list e (er-mk-atom "true")))))
|
||||
(er-ext-pl-lookup key (get lst :tail)))
|
||||
:else (er-mk-atom "none"))))
|
||||
|
||||
(define
|
||||
er-bif-pl-lookup
|
||||
(fn (vs) (er-ext-pl-lookup (nth vs 0) (nth vs 1))))
|
||||
|
||||
(define
|
||||
er-ext-pl-delete
|
||||
(fn (key lst)
|
||||
(cond
|
||||
(er-nil? lst) (er-mk-nil)
|
||||
(er-cons? lst)
|
||||
(if (er-ext-pl-match? key (get lst :head))
|
||||
(er-ext-pl-delete key (get lst :tail))
|
||||
(er-mk-cons (get lst :head) (er-ext-pl-delete key (get lst :tail))))
|
||||
:else lst)))
|
||||
|
||||
(define
|
||||
er-bif-pl-delete
|
||||
(fn (vs) (er-ext-pl-delete (nth vs 0) (nth vs 1))))
|
||||
|
||||
Reference in New Issue
Block a user