erlang: lists flatten/1 + max/1 + min/1 (833/833)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 58s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 58s
Structural/aggregate ops in lib/erlang/lists-ext.sx: flatten/1 deep flatten, max/1 and min/1 by full Erlang term order (badarg on empty). Extreme-finder uses er-ext-lt?'s SX boolean directly in if (er-truthy? only recognises Erlang bool atoms). lists_ext suite 52 -> 62. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -319,6 +319,53 @@
|
||||
(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")))))))
|
||||
|
||||
;; ── register ──────────────────────────────────────────────────────
|
||||
;; Hook into er-register-builtin-bifs! rather than registering once:
|
||||
;; the registry can be reset + rebuilt mid-run (tests/runtime.sx does
|
||||
@@ -340,7 +387,10 @@
|
||||
(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" "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)))
|
||||
|
||||
(define er-ext-prev-register-builtins er-register-builtin-bifs!)
|
||||
(define er-register-builtin-bifs!
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"language": "erlang",
|
||||
"total_pass": 823,
|
||||
"total": 823,
|
||||
"total_pass": 833,
|
||||
"total": 833,
|
||||
"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":52,"total":52,"status":"ok"}
|
||||
{"name":"lists_ext","pass":62,"total":62,"status":"ok"}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Erlang-on-SX Scoreboard
|
||||
|
||||
**Total: 823 / 823 tests passing**
|
||||
**Total: 833 / 833 tests passing**
|
||||
|
||||
| | Suite | Pass | Total |
|
||||
|---|---|---|---|
|
||||
@@ -16,7 +16,7 @@
|
||||
| ✅ | ffi | 37 | 37 |
|
||||
| ✅ | vm | 78 | 78 |
|
||||
| ✅ | send_after | 10 | 10 |
|
||||
| ✅ | lists_ext | 52 | 52 |
|
||||
| ✅ | lists_ext | 62 | 62 |
|
||||
|
||||
|
||||
Generated by `lib/erlang/conformance.sh`.
|
||||
|
||||
@@ -205,3 +205,36 @@
|
||||
|
||||
(er-lx-test "splitwith empty"
|
||||
(er-lx-nm "lists:splitwith(fun(_) -> true end, []) =:= {[],[]}") "true")
|
||||
|
||||
;; ── lists:flatten/1 ───────────────────────────────────────────────
|
||||
(er-lx-test "flatten nested"
|
||||
(er-lx-nm "lists:flatten([1,[2,[3,4]],5]) =:= [1,2,3,4,5]") "true")
|
||||
|
||||
(er-lx-test "flatten already flat"
|
||||
(er-lx-nm "lists:flatten([1,2,3]) =:= [1,2,3]") "true")
|
||||
|
||||
(er-lx-test "flatten empty"
|
||||
(er-lx-nm "lists:flatten([]) =:= []") "true")
|
||||
|
||||
(er-lx-test "flatten deep empties"
|
||||
(er-lx-nm "lists:flatten([[],[1],[[]]]) =:= [1]") "true")
|
||||
|
||||
(er-lx-test "flatten length"
|
||||
(erlang-eval-ast "length(lists:flatten([[1,2],[3],[4,5,6]]))") 6)
|
||||
|
||||
;; ── lists:max/1 ───────────────────────────────────────────────────
|
||||
(er-lx-test "max ints"
|
||||
(erlang-eval-ast "lists:max([3,1,4,1,5,9,2,6])") 9)
|
||||
|
||||
(er-lx-test "max single"
|
||||
(erlang-eval-ast "lists:max([7])") 7)
|
||||
|
||||
(er-lx-test "max atoms term order"
|
||||
(er-lx-nm "lists:max([a,c,b]) =:= c") "true")
|
||||
|
||||
;; ── lists:min/1 ───────────────────────────────────────────────────
|
||||
(er-lx-test "min ints"
|
||||
(erlang-eval-ast "lists:min([3,1,4,1,5])") 1)
|
||||
|
||||
(er-lx-test "min mixed term order"
|
||||
(er-lx-nm "lists:min([a,1,b]) =:= 1") "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` 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.
|
||||
|
||||
- **2026-06-30 stdlib hardening — `lists` keylists** — Added the keylist family to `lib/erlang/lists-ext.sx`: `keyfind/3`, `keymember/3`, `keydelete/3`, `keyreplace/4`, `keystore/4`, `keytake/3`, `keysort/2`. All operate on lists of tuples keyed on element N (1-indexed), act on the first match only, and pass through non-tuples / tuples shorter than N. Key comparison is `==` (`er-equal?`) per the stdlib; `keysort/2` reuses the stable `er-ext-msort` + `er-ext-lt?` from the sort commit, comparing extracted keys. `keytake/3` returns `{value, Tuple, Rest}` / `false`. Registered through the same `er-register-builtin-bifs!` wrapper so they survive registry resets. `lists_ext` suite 17→**38** (+21: hit/miss/first-match-only/short-tuple-skip across all seven, keysort by elem 1 and 2 + stability). Conformance **788 → 809/809**. Test-harness note: `element(2, T)` returns an integer (no `:name`), so those two cases compare the raw number via `erlang-eval-ast` rather than `er-lx-nm`. loops/erlang only.
|
||||
|
||||
Reference in New Issue
Block a user