erlang: lists zip/2 + zipwith/3 + unzip/1 (841/841)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 57s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 57s
Zip family in lib/erlang/lists-ext.sx; length mismatch and malformed pairs raise badarg. lists_ext suite 62 -> 70. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -366,6 +366,62 @@
|
||||
(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))))
|
||||
|
||||
;; ── register ──────────────────────────────────────────────────────
|
||||
;; Hook into er-register-builtin-bifs! rather than registering once:
|
||||
;; the registry can be reset + rebuilt mid-run (tests/runtime.sx does
|
||||
@@ -390,7 +446,10 @@
|
||||
(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" "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)))
|
||||
|
||||
(define er-ext-prev-register-builtins er-register-builtin-bifs!)
|
||||
(define er-register-builtin-bifs!
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"language": "erlang",
|
||||
"total_pass": 833,
|
||||
"total": 833,
|
||||
"total_pass": 841,
|
||||
"total": 841,
|
||||
"suites": [
|
||||
{"name":"tokenize","pass":62,"total":62,"status":"ok"},
|
||||
{"name":"parse","pass":52,"total":52,"status":"ok"},
|
||||
@@ -15,6 +15,6 @@
|
||||
{"name":"ffi","pass":37,"total":37,"status":"ok"},
|
||||
{"name":"vm","pass":78,"total":78,"status":"ok"},
|
||||
{"name":"send_after","pass":10,"total":10,"status":"ok"},
|
||||
{"name":"lists_ext","pass":62,"total":62,"status":"ok"}
|
||||
{"name":"lists_ext","pass":70,"total":70,"status":"ok"}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Erlang-on-SX Scoreboard
|
||||
|
||||
**Total: 833 / 833 tests passing**
|
||||
**Total: 841 / 841 tests passing**
|
||||
|
||||
| | Suite | Pass | Total |
|
||||
|---|---|---|---|
|
||||
@@ -16,7 +16,7 @@
|
||||
| ✅ | ffi | 37 | 37 |
|
||||
| ✅ | vm | 78 | 78 |
|
||||
| ✅ | send_after | 10 | 10 |
|
||||
| ✅ | lists_ext | 62 | 62 |
|
||||
| ✅ | lists_ext | 70 | 70 |
|
||||
|
||||
|
||||
Generated by `lib/erlang/conformance.sh`.
|
||||
|
||||
@@ -238,3 +238,32 @@
|
||||
|
||||
(er-lx-test "min mixed term order"
|
||||
(er-lx-nm "lists:min([a,1,b]) =:= 1") "true")
|
||||
|
||||
;; ── lists:zip/2 ───────────────────────────────────────────────────
|
||||
(er-lx-test "zip pairs"
|
||||
(er-lx-nm "lists:zip([a,b,c],[1,2,3]) =:= [{a,1},{b,2},{c,3}]") "true")
|
||||
|
||||
(er-lx-test "zip empty"
|
||||
(er-lx-nm "lists:zip([],[]) =:= []") "true")
|
||||
|
||||
(er-lx-test "zip length"
|
||||
(erlang-eval-ast "length(lists:zip([1,2],[3,4]))") 2)
|
||||
|
||||
;; ── lists:zipwith/3 ───────────────────────────────────────────────
|
||||
(er-lx-test "zipwith sum"
|
||||
(er-lx-nm
|
||||
"lists:zipwith(fun(X,Y) -> X+Y end, [1,2,3], [10,20,30]) =:= [11,22,33]")
|
||||
"true")
|
||||
|
||||
(er-lx-test "zipwith tuple"
|
||||
(er-lx-nm "lists:zipwith(fun(X,Y) -> {X,Y} end, [a], [1]) =:= [{a,1}]") "true")
|
||||
|
||||
;; ── lists:unzip/1 ─────────────────────────────────────────────────
|
||||
(er-lx-test "unzip"
|
||||
(er-lx-nm "lists:unzip([{a,1},{b,2},{c,3}]) =:= {[a,b,c],[1,2,3]}") "true")
|
||||
|
||||
(er-lx-test "unzip empty"
|
||||
(er-lx-nm "lists:unzip([]) =:= {[],[]}") "true")
|
||||
|
||||
(er-lx-test "zip/unzip roundtrip"
|
||||
(er-lx-nm "lists:unzip(lists:zip([1,2],[3,4])) =:= {[1,2],[3,4]}") "true")
|
||||
|
||||
@@ -159,6 +159,8 @@ The Phase 9 opcodes are registered, tested, and bridged SX↔OCaml, but inert: n
|
||||
|
||||
_Newest first._
|
||||
|
||||
- **2026-06-30 stdlib hardening — `lists` zip family** — Added `zip/2`, `zipwith/3`, `unzip/1` to `lib/erlang/lists-ext.sx`. Length mismatch (zip/zipwith) and malformed/non-pair elements (unzip) raise `badarg` (port equivalent of Erlang's `function_clause`). `lists_ext` suite 62→**70** (+8, incl. a zip/unzip roundtrip). Conformance **833 → 841/841**. loops/erlang only.
|
||||
|
||||
- **2026-06-30 stdlib hardening — `lists` flatten/max/min** — Added `flatten/1` (deep recursive flatten via `er-list-append`), `max/1`, `min/1` (full term order via `er-ext-lt?`, `badarg` on empty) to `lib/erlang/lists-ext.sx`. Gotcha caught: `er-ext-lt?` returns a raw SX boolean, so the extreme-finder uses it directly in `if` rather than wrapping in `er-truthy?` (which only recognises Erlang bool atoms, not SX booleans — the first cut wrapped it and silently never updated the running best). `lists_ext` suite 52→**62** (+10). Conformance **823 → 833/833**. loops/erlang only.
|
||||
|
||||
- **2026-06-30 stdlib hardening — `lists` higher-order traversal** — Added `foldr/3`, `partition/2`, `takewhile/2`, `dropwhile/2`, `splitwith/2` to `lib/erlang/lists-ext.sx`, registered pure through the `er-register-builtin-bifs!` wrapper (consistent with the existing pure `map`/`filter`/`foldl`). `foldr` right-folds (order-preserving when consing); `partition` returns `{Satisfying, NotSatisfying}` order-preserved via `er-list-reverse-iter`; `splitwith` = `{takewhile, dropwhile}`. `lists_ext` suite 38→**52** (+14). Conformance **809 → 823/823**. loops/erlang only.
|
||||
|
||||
Reference in New Issue
Block a user