spec.alpha: reify ILookup get, NPE/CCE, quoted #inst/#uuid, anon-fn class, kwargs map
Close clojure.spec.alpha's remaining gaps — its conform/explain/describe/multi-spec
suite (clojure.test-clojure.spec, multi-spec) now passes fully.
- (get reify k) / (:k reify) routes to a reify's clojure.lang.ILookup valAt. spec
reifies fspec/regex specs as ILookup and reads (:args spec) off them, so before
this instrument never saw the args spec.
- A failed numeric comparison reports the JVM class: a nil operand is
NullPointerException, a non-number is ClassCastException (was an opaque :object
condition). conform-explain checks the thrown class.
- A quoted / macro-form #inst / #uuid literal constructs its Date/UUID value, like
the JVM reader (which builds it at read time). emit-quoted was emitting the raw
tagged form, so #inst "1939" and #inst "1939-01-01T00:00:00.000-00:00" weren't =.
- An anonymous fn reports class clojure.lang.AFunction$fn (the $fn marker), so
spec's fn-sym returns ::s/unknown for it, matching the JVM's ns$fn__N.
- A fn with & {:as m} kwargs accepts a trailing map (Clojure 1.11): (f :a 1 {:b 2})
and (f {:a 1}) both bind m, by merging an odd trailing map over the pairs.
- A thread responds to .getStackTrace (empty — jolt does TCO).
clojure.test-clojure.instr does not fully pass: its ::caller assertions need the
calling fn's stack frame, which TCO erases (an inherent host divergence, like the
JVM keeping tail frames).
make test green (+4 corpus rows, 0 new divergences), shakesmoke byte-identical.
Re-mint (backend emit-quoted + the destructure macro).
This commit is contained in:
parent
219d1e52c9
commit
522ff10d62
9 changed files with 52 additions and 16 deletions
|
|
@ -35,7 +35,11 @@
|
|||
((jolt-atom? x) "clojure.lang.Atom")
|
||||
((char? x) "java.lang.Character")
|
||||
((regex-t? x) "java.util.regex.Pattern")
|
||||
((procedure? x) "clojure.lang.IFn")
|
||||
;; an anonymous / unregistered fn — like the JVM, where (class #(..)) is a
|
||||
;; concrete ns$fn__N subclass. The $fn marker lets clojure.spec.alpha's fn-sym
|
||||
;; recognize it as anonymous and return ::s/unknown. A named fn is registered
|
||||
;; (proc-name-tbl) and handled by a class-arm with its real ns$name.
|
||||
((procedure? x) "clojure.lang.AFunction$fn")
|
||||
;; an exception value (ex-info / host-constructed throwable) reports its JVM
|
||||
;; class, so (= clojure.lang.ExceptionInfo (class e)) and clojure.test's
|
||||
;; (thrown? Class …) match (records.ss ex-info-map?/ex-info-class).
|
||||
|
|
@ -59,9 +63,8 @@
|
|||
;; (thrown? ArityException …) test match — not the opaque :object fallback.
|
||||
(register-class-arm!
|
||||
(lambda (x) (and (chez-condition-exc-class x) #t))
|
||||
(lambda (x) (if (string=? (chez-condition-exc-class x) "ArityException")
|
||||
"clojure.lang.ArityException"
|
||||
"java.lang.IllegalArgumentException")))
|
||||
(lambda (x) (let ((p (assoc (chez-condition-exc-class x) class-token-alist)))
|
||||
(if p (cdr p) "java.lang.IllegalArgumentException"))))
|
||||
;; A fn def'd into a var reports a JVM-style class name "ns$munged-name" (the
|
||||
;; forward CHAR_MAP), so clojure.spec.alpha's fn-sym (which splits on $ and
|
||||
;; demunges) recovers the predicate's symbol. Anonymous / unregistered fns stay
|
||||
|
|
|
|||
|
|
@ -487,6 +487,11 @@
|
|||
(register-host-methods! "thread"
|
||||
(list (cons "getContextClassLoader" (lambda (self) the-classloader))
|
||||
(cons "getName" (lambda (self) "main"))
|
||||
;; no reified call stack (jolt does TCO, so caller frames are erased) — an
|
||||
;; empty StackTraceElement[]. clojure.spec.test.alpha's instrument reads it
|
||||
;; to name the caller var; it degrades to no ::caller, the conform error
|
||||
;; (the ExceptionInfo) is still thrown.
|
||||
(cons "getStackTrace" (lambda (self) (jolt-vector)))
|
||||
(cons "interrupt" (lambda (self)
|
||||
(when (box? (jhost-state self)) (set-box! (jhost-state self) #t))
|
||||
jolt-nil))
|
||||
|
|
|
|||
|
|
@ -68,6 +68,18 @@
|
|||
(and (string? m)
|
||||
(cond ((ri-substring? "incorrect number of arguments" m) "ArityException")
|
||||
((ri-substring? "not seqable" m) "IllegalArgumentException")
|
||||
;; Chez's numeric ops raise "~s is not a real number" on a bad
|
||||
;; operand. The JVM throws NullPointerException for a nil operand
|
||||
;; (null deref) and ClassCastException for a non-number (can't
|
||||
;; cast to Number) — clojure.spec.alpha's conform-explain relies
|
||||
;; on the distinction. The offending value rides in the irritants.
|
||||
((or (ri-substring? "is not a real number" m)
|
||||
(ri-substring? "is not a number" m))
|
||||
(if (and (irritants-condition? v)
|
||||
(let loop ((xs (condition-irritants v)))
|
||||
(and (pair? xs) (or (jolt-nil? (car xs)) (loop (cdr xs))))))
|
||||
"NullPointerException"
|
||||
"ClassCastException"))
|
||||
(else #f))))))
|
||||
|
||||
;; instance-check: (type-sym val) — type/protocol membership. Host shims loaded
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue