feat(strictness): peek/pop/vec/key/val reject malformed args
- peek/pop are stack-only (vectors/lists): throw on sets/maps/strings/scalars, and pop throws on an empty vector/list - vec throws on non-seqable args (numbers/keywords/transients) - key/val require a map entry (2-element vector); throw on nil/numbers/maps/sets pop clean; peek 9/2; vec 17/2/1; key/val 12/2/1 (remaining are the 2-vector-vs-MapEntry / tuple-from-seq divergences). pass 3824->3840. spec: seq/accessor-strictness (16). jpm test green.
This commit is contained in:
parent
e7a58a0ed6
commit
b82477dac3
3 changed files with 38 additions and 13 deletions
|
|
@ -557,6 +557,8 @@
|
|||
coll))
|
||||
|
||||
(defn core-vec [coll]
|
||||
(when (not (or (nil? coll) (core-coll? coll) (string? coll)))
|
||||
(error (string "Don't know how to create a vector from " (type coll))))
|
||||
(let [coll (realize-for-iteration coll)]
|
||||
(cond
|
||||
(array? coll) (make-vec coll)
|
||||
|
|
@ -1241,25 +1243,25 @@
|
|||
(indexed? m) (do (var i 0) (each x m (set acc (f acc i x)) (++ i))))
|
||||
acc)
|
||||
|
||||
# peek/pop are defined only on stacks (vectors -> last end, lists -> front);
|
||||
# Clojure throws on sets/maps/seqs/strings/scalars.
|
||||
(defn core-peek [coll]
|
||||
(cond
|
||||
(nil? coll) nil
|
||||
(lazy-seq? coll) (ls-first coll)
|
||||
(plist? coll) (if (pl-empty? coll) nil (pl-first coll)) # list: first
|
||||
(pvec? coll) (if (= 0 (pv-count coll)) nil (pv-nth coll (- (pv-count coll) 1))) # vector: last
|
||||
(= 0 (length coll)) nil
|
||||
(tuple? coll) (in coll (- (length coll) 1)) # vector: last
|
||||
(array? coll) (in coll 0) # list: first
|
||||
(in coll 0)))
|
||||
(tuple? coll) (if (= 0 (length coll)) nil (in coll (- (length coll) 1))) # vector: last
|
||||
(array? coll) (if (= 0 (length coll)) nil (in coll 0)) # list: first
|
||||
(error (string "peek not supported on " (type coll)))))
|
||||
|
||||
(defn core-pop [coll]
|
||||
(cond
|
||||
(nil? coll) nil
|
||||
(plist? coll) (pl-rest coll) # list: drop first
|
||||
(pvec? coll) (pv-pop coll) # vector: drop last
|
||||
(tuple? coll) (tuple/slice coll 0 (- (length coll) 1)) # vector: drop last
|
||||
(array? coll) (array/slice coll 1) # list: rest
|
||||
coll))
|
||||
(plist? coll) (if (pl-empty? coll) (error "Can't pop empty list") (pl-rest coll))
|
||||
(pvec? coll) (if (= 0 (pv-count coll)) (error "Can't pop empty vector") (pv-pop coll))
|
||||
(tuple? coll) (if (= 0 (length coll)) (error "Can't pop empty vector") (tuple/slice coll 0 (- (length coll) 1)))
|
||||
(array? coll) (if (= 0 (length coll)) (error "Can't pop empty list") (array/slice coll 1))
|
||||
(error (string "pop not supported on " (type coll)))))
|
||||
|
||||
(defn core-subvec [v start &opt end]
|
||||
(let [a (vview v)]
|
||||
|
|
@ -3155,8 +3157,11 @@
|
|||
(tuple ;out))
|
||||
|
||||
# Map entries (represented as 2-element vectors)
|
||||
(defn core-key [e] (core-nth e 0))
|
||||
(defn core-val [e] (core-nth e 1))
|
||||
# key/val require a map entry (a 2-element vector/tuple in Jolt); Clojure throws
|
||||
# otherwise. (Jolt can't distinguish a 2-vector from a real MapEntry.)
|
||||
(defn- entry-like? [x] (and (or (pvec? x) (tuple? x) (array? x)) (= 2 (core-count x))))
|
||||
(defn core-key [e] (if (entry-like? e) (core-nth e 0) (error "key requires a map entry")))
|
||||
(defn core-val [e] (if (entry-like? e) (core-nth e 1) (error "val requires a map entry")))
|
||||
(defn core-map-entry? [x] (and (or (pvec? x) (tuple? x)) (= 2 (core-count x))))
|
||||
|
||||
(defn core-rand-nth [coll]
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
# Baseline: assertions Jolt currently passes across the suite. Raise as Jolt
|
||||
# improves so a regression (previously-passing assertion breaking) is caught.
|
||||
(def baseline-pass 3820)
|
||||
(def baseline-pass 3835)
|
||||
# A file is "clean" when it ran with zero failures AND zero errors.
|
||||
(def baseline-clean-files 45)
|
||||
# Per-file wall-clock budget (seconds). Normal files finish in well under 1s;
|
||||
|
|
|
|||
|
|
@ -145,3 +145,23 @@
|
|||
["symbol from keyword" "\"x\"" "(name (symbol :x))"]
|
||||
["keyword bad 2-arg" :throws "(keyword \"abc\" nil)"]
|
||||
["keyword from symbol" "\"x\"" "(name (keyword 'x))"])
|
||||
|
||||
# Stack/accessor strictness: peek/pop are stack-only; vec needs a seqable;
|
||||
# key/val need a map entry.
|
||||
(defspec "seq / accessor strictness"
|
||||
["peek vector" "3" "(peek [1 2 3])"]
|
||||
["peek list" "1" "(peek '(1 2 3))"]
|
||||
["peek empty vec" "nil" "(peek [])"]
|
||||
["peek on set" :throws "(peek #{1 2})"]
|
||||
["peek on number" :throws "(peek 42)"]
|
||||
["pop empty vec" :throws "(pop [])"]
|
||||
["pop on number" :throws "(pop 0)"]
|
||||
["pop vector" "[1 2]" "(pop [1 2 3])"]
|
||||
["vec on number" :throws "(vec 42)"]
|
||||
["vec on keyword" :throws "(vec :a)"]
|
||||
["vec ok" "[1 2]" "(vec '(1 2))"]
|
||||
["key on nil" :throws "(key nil)"]
|
||||
["key on map" :throws "(key {})"]
|
||||
["val on number" :throws "(val 0)"]
|
||||
["key of entry" ":a" "(key (first {:a 1}))"]
|
||||
["val of entry" "1" "(val (first {:a 1}))"])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue