Contract fixes from the baseline audit; every residual suite failure traced
Auditing the remaining cts baseline for R7 exposed real contract gaps hiding among the model residue — all fixed to reference behavior: - stale no-ratio-era stubs: numerator/denominator now work over jolt's exact rationals (non-ratio is the Ratio cast failure); rational? includes decimals - casts and pending: peek/pop demand an IPersistentStack (pop nil is nil), realized? demands an IPending (a plain list/range throws), transient demands an editable COLLECTION (non-colls throw; the RFC 0003 sorted/list/seq superset keeps the copy-on-write fallback), empty on a plain record throws - nil and empties: (nth nil i) is nil, (nth nil i d) is d, a nil index is NPE, keys/vals of anything empty are nil, (conj nil) is nil - lookups: contains? on a string is index-only (other keys IAE), get on an array is lenient (nth still throws), a VECTOR invocation has nth semantics (([1 2] 5) throws — call position and jolt-invoke both) - into only transients editable collections; a PersistentQueue/sorted target folds through conj (RT's IEditableCollection split) - numbers: number?/num accept BigDecimal, quot/rem throw on an Infinite/NaN quotient, even?/odd? demand integers - ordering: keywords compare namespace-first with nil first (Symbol.compareTo) - misc: run! honors reduced, eval self-evaluates non-form values, intern demands an existing namespace, counted? excludes strings, seqable? includes arrays, shuffle rejects maps, sort-by rejects a collection comparator, when-let demands one binding pair, case*/deftype*/letfn*/reify*/& are special symbols Two mis-certified corpus rows fixed (they threw on the JVM too and hid in the tolerated bucket): a raw \d string escape and duplicate literal map keys. SPEC.md gains the baseline-traceability section: every one of the 146 remaining suite failures maps to a documented divergence (integer-box, no-single-float, RFC 0003 transients, seq/chunking model, stm-refs, parse-uuid strictness, vec-array adoption). cts baseline 5955 -> 6042 pass, 5 errors, 30 namespaces. 9 JVM-certified corpus rows.
This commit is contained in:
parent
3fb8082802
commit
ce8e89ca86
19 changed files with 728 additions and 578 deletions
|
|
@ -545,6 +545,8 @@
|
|||
;; name binds only in the taken branch (temp# tests the value); via `let` so the
|
||||
;; binding form may itself destructure, matching Clojure.
|
||||
(defmacro when-let [bindings & body]
|
||||
(when (not= 2 (count bindings))
|
||||
(throw (new IllegalArgumentException "when-let requires exactly 2 forms in binding vector")))
|
||||
(let [form (bindings 0) tst (bindings 1)]
|
||||
`(let [temp# ~tst]
|
||||
(if temp# (let [~form temp#] ~@body) nil))))
|
||||
|
|
|
|||
|
|
@ -219,7 +219,8 @@
|
|||
;; compiler emit/inference path) — see predicates.ss.
|
||||
(defn ratio? [x]
|
||||
(and (number? x) (jolt.host/exact? x) (jolt.host/rational-type? x) (not (integer? x))))
|
||||
(defn rational? [x] (and (number? x) (jolt.host/exact? x)))
|
||||
(defn rational? [x]
|
||||
(or (and (number? x) (jolt.host/exact? x)) (decimal? x)))
|
||||
;; No first-class Class objects: class names are symbols the evaluator handles in
|
||||
;; instance?/new positions, never values — so nothing is a class.
|
||||
(defn class? [x] false)
|
||||
|
|
@ -274,7 +275,8 @@
|
|||
(loop [i 0 s (seq coll)]
|
||||
(if (and s (< i n)) (recur (inc i) (next s)) i))))
|
||||
|
||||
(defn run! [proc coll] (reduce (fn [_ x] (proc x) nil) nil coll) nil)
|
||||
;; the reducing fn returns proc's result, so a Reduced from proc short-circuits
|
||||
(defn run! [proc coll] (reduce (fn [_ x] (proc x)) nil coll) nil)
|
||||
|
||||
(defn completing
|
||||
([f] (completing f identity))
|
||||
|
|
@ -457,7 +459,8 @@
|
|||
(defn sequential? [x] (or (vector? x) (seq? x)))
|
||||
(defn associative? [x] (or (map? x) (vector? x)))
|
||||
(defn counted? [x]
|
||||
(or (vector? x) (map? x) (set? x) (list? x) (string? x)))
|
||||
;; a String is not Counted on the JVM (count works via CharSequence, not O(1))
|
||||
(or (vector? x) (map? x) (set? x) (list? x)))
|
||||
(defn indexed? [x] (vector? x))
|
||||
;; sorted? is defined by the next tier (25-sorted) — declared here so this
|
||||
;; tier compiles (forward references are analysis errors).
|
||||
|
|
@ -465,7 +468,7 @@
|
|||
|
||||
(defn reversible? [x] (or (vector? x) (sorted? x)))
|
||||
(defn seqable? [x]
|
||||
(or (nil? x) (coll? x) (string? x)))
|
||||
(if (or (nil? x) (coll? x) (string? x) (jolt.host/array-value? x)) true false))
|
||||
|
||||
(defn boolean? [x] (or (true? x) (false? x)))
|
||||
(defn double? [x] (and (number? x) (not (integer? x))))
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@
|
|||
;; Clojure. Collections only — a string is seqable but not shuffleable, as on
|
||||
;; the JVM (Collections/shuffle wants a Collection).
|
||||
(defn shuffle [coll]
|
||||
(when-not (coll? coll)
|
||||
;; Collections/shuffle wants a java.util.Collection — a map is not one
|
||||
(when (or (not (coll? coll)) (map? coll))
|
||||
(throw (ex-info (str "shuffle requires a collection, got: " coll) {})))
|
||||
(loop [v (vec coll) i (dec (count v))]
|
||||
(if (pos? i)
|
||||
|
|
@ -28,6 +29,10 @@
|
|||
(defn sort-by
|
||||
([keyfn coll] (sort-by keyfn compare coll))
|
||||
([keyfn comp coll]
|
||||
;; a collection is never a Comparator (the JVM cast would fail); catching it
|
||||
;; here beats silently "sorting" through coll-as-fn lookups
|
||||
(when (coll? comp)
|
||||
(throw (new ClassCastException (str (class comp) " cannot be cast to java.util.Comparator"))))
|
||||
(sort (fn [x y] (comp (keyfn x) (keyfn y))) coll)))
|
||||
|
||||
;; parse-uuid: nil unless s is a canonical 8-4-4-4-12 hex UUID string; throws
|
||||
|
|
@ -348,8 +353,8 @@
|
|||
(defn clojure-version [] "1.11.0-jolt")
|
||||
|
||||
;; bigdec is a host fn (host/chez/java/bigdec.ss) — a real BigDecimal value type.
|
||||
(defn numerator [x] (throw (ex-info "numerator requires a ratio (Jolt has no ratios)" {})))
|
||||
(defn denominator [x] (throw (ex-info "denominator requires a ratio (Jolt has no ratios)" {})))
|
||||
;; numerator/denominator are host natives (converters.ss) over Chez's exact
|
||||
;; rationals; a non-ratio is the Ratio cast failure.
|
||||
|
||||
;; jolt has no reflection, but a few common JVM interfaces carry a modeled
|
||||
;; ancestry (jolt.host/class-supers) so reflective checks like
|
||||
|
|
|
|||
|
|
@ -136,6 +136,9 @@
|
|||
;; a deftype/record with its own empty (IPersistentCollection) — e.g.
|
||||
;; data.priority-map — uses it, before the generic map/set/vector arms.
|
||||
(jolt.host/jrec-method? coll "empty") (.empty coll)
|
||||
;; a defrecord without its own empty can't have one (RT: UnsupportedOperation)
|
||||
(record? coll) (throw (new UnsupportedOperationException
|
||||
(str "Can't create empty: " (.getName (class coll)))))
|
||||
(sorted? coll) ((get (jolt.host/ref-get coll :ops) :empty) coll)
|
||||
(map? coll) (with-meta {} (meta coll))
|
||||
(set? coll) (with-meta #{} (meta coll))
|
||||
|
|
@ -330,7 +333,8 @@
|
|||
;; stays an unevaluated reader form on jolt and contains? can't see into it.
|
||||
(def ^:private special-syms
|
||||
#{'if 'do 'let* 'fn* 'quote 'var 'def 'loop* 'recur 'throw 'try 'catch
|
||||
'finally 'new 'set! '. 'monitor-enter 'monitor-exit})
|
||||
'finally 'new 'set! '. 'monitor-enter 'monitor-exit
|
||||
'& 'case* 'deftype* 'letfn* 'reify*})
|
||||
|
||||
(defn special-symbol? [s] (contains? special-syms s))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue