From 48908f3a9b77beb5714f69bdee051dd38c779d34 Mon Sep 17 00:00:00 2001 From: Yogthos Date: Sat, 27 Jun 2026 20:46:33 -0400 Subject: [PATCH 1/5] spec.alpha: (symbol var), Compiler/demunge, MultiFn .dispatchFn/.getMethod, fn .applyTo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit General fixes from clojure.spec.alpha's test suite. - (symbol a-var) returns the var's qualified symbol (clojure.spec.alpha/->sym). - clojure.lang.Compiler/demunge reverses Clojure's name munging ("clojure.core$odd_QMARK_" -> clojure.core/odd?); spec's fn-sym uses it. - clojure.lang.MultiFn .dispatchFn / .getMethod — spec's multi-spec walks a multimethod through them. - (.applyTo f args) applies a fn to a seq of args (spec instrument). Most of spec.alpha's conform/explain/describe suite passes. Remaining gaps: explain-data's :pred for a BARE fn predicate (jolt fns don't carry their defining symbol, so fn-sym can't recover it), #inst form rendering, and instrument — follow-up. make test green (+3 corpus rows, 0 new divergences), runtime only (no re-mint). --- host/chez/compile-eval.ss | 31 ++++++++++++++++++++++++++++++- host/chez/converters.ss | 2 ++ host/chez/java/dot-forms.ss | 15 +++++++++++++++ test/chez/corpus.edn | 3 +++ 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/host/chez/compile-eval.ss b/host/chez/compile-eval.ss index 518dbfb..05d86c3 100644 --- a/host/chez/compile-eval.ss +++ b/host/chez/compile-eval.ss @@ -44,8 +44,37 @@ (fold-left (lambda (m s) (jolt-assoc1 m (jolt-symbol #f s) #t)) (jolt-assoc1 (jolt-hash-map) (jolt-symbol "clojure.core" "import*") #t) unq))) +;; clojure.lang.Compiler/demunge — reverse the name munging Clojure applies to +;; build JVM class/method names, so "clojure.core$odd_QMARK_" -> clojure.core/odd?. +;; clojure.spec.alpha's fn-sym uses it to recover a symbol from a fn's class name. +;; Longest tokens first; a standalone _ is a hyphen; $ separates ns from name. +(define demunge-token-map + '(("_DOUBLEQUOTE_" . "\"") ("_SINGLEQUOTE_" . "'") ("_AMPERSAND_" . "&") ("_PERCENT_" . "%") + ("_LBRACE_" . "{") ("_RBRACE_" . "}") ("_LBRACK_" . "[") ("_RBRACK_" . "]") + ("_BSLASH_" . "\\") ("_TILDE_" . "~") ("_CIRCA_" . "@") ("_SHARP_" . "#") ("_BANG_" . "!") + ("_CARET_" . "^") ("_COLON_" . ":") ("_QMARK_" . "?") ("_SLASH_" . "/") ("_PLUS_" . "+") + ("_STAR_" . "*") ("_BAR_" . "|") ("_GT_" . ">") ("_LT_" . "<") ("_EQ_" . "=") ("_DOT_" . "."))) +(define (compiler-demunge s) + (let* ((s (if (string? s) s (jolt-str-render-one s))) + (n (string-length s)) + (out (open-output-string))) + (let loop ((i 0)) + (if (>= i n) (get-output-string out) + (let ((tok (let scan ((ts demunge-token-map)) + (cond ((null? ts) #f) + ((let ((t (caar ts))) + (and (<= (+ i (string-length t)) n) + (string=? (substring s i (+ i (string-length t))) t))) + (car ts)) + (else (scan (cdr ts))))))) + (cond + (tok (display (cdr tok) out) (loop (+ i (string-length (car tok))))) + ((char=? (string-ref s i) #\_) (write-char #\- out) (loop (+ i 1))) + ((char=? (string-ref s i) #\$) (write-char #\/ out) (loop (+ i 1))) + (else (write-char (string-ref s i) out) (loop (+ i 1))))))))) (let ((members (list (cons "LINE" compiler-line-cell) (cons "COLUMN" compiler-column-cell) - (cons "specials" compiler-specials)))) + (cons "specials" compiler-specials) + (cons "demunge" compiler-demunge)))) (register-class-statics! "Compiler" members) (register-class-statics! "clojure.lang.Compiler" members)) diff --git a/host/chez/converters.ss b/host/chez/converters.ss index d13ed85..d8572ed 100644 --- a/host/chez/converters.ss +++ b/host/chez/converters.ss @@ -132,6 +132,8 @@ (jolt-symbol (substring a 0 i) (substring a (+ i 1) slen))) (else (loop (- i 1)))))))) ((keyword? a) (jolt-symbol (keyword-t-ns a) (keyword-t-name a))) + ;; (symbol a-var) -> the var's qualified symbol (clojure.spec.alpha/->sym). + ((var-cell? a) (jolt-symbol (var-cell-ns a) (var-cell-name a))) (else (error #f "symbol: requires string/symbol" a))))) ;; (symbol ns name): a nil namespace is the no-ns sentinel #f (NOT jolt-nil), ;; so (symbol nil "x") equals (symbol "x") and the reader literal 'x — jolt= diff --git a/host/chez/java/dot-forms.ss b/host/chez/java/dot-forms.ss index 40d35a9..0ec81ad 100644 --- a/host/chez/java/dot-forms.ss +++ b/host/chez/java/dot-forms.ss @@ -96,6 +96,21 @@ ;; (.getClass x) universal — the class token for any value, before the ;; collection/map field-lookup arms below would read it as a missing key. ((string=? method-name "getClass") (jolt-class obj)) + ;; clojure.lang.MultiFn .dispatchFn / .getMethod — clojure.spec.alpha's + ;; multi-spec walks a multimethod through these. + ((jolt-multifn? obj) + (cond + ((string=? mname "dispatchFn") (jolt-multifn-dispatch-fn obj)) + ((string=? mname "getMethod") + (let ((methods (jolt-multifn-methods obj)) (dv (car rest))) + (or (hashtable-ref methods dv #f) + (mm-find-isa obj dv) + (hashtable-ref methods (jolt-multifn-default obj) #f) + jolt-nil))) + (else (%dot-rmd obj method-name rest-args)))) + ;; (.applyTo f args): apply a fn to a seq of args (clojure.spec instrument). + ((and (procedure? obj) (string=? mname "applyTo")) + (apply jolt-invoke obj (seq->list (jolt-seq (car rest))))) ;; a transient (ITransientCollection/Set/Map): .contains / .valAt / .count — ;; test.check's distinct-collection gen uses (.contains transient-set k). ((jolt-transient? obj) diff --git a/test/chez/corpus.edn b/test/chez/corpus.edn index 51a1098..2ea135c 100644 --- a/test/chez/corpus.edn +++ b/test/chez/corpus.edn @@ -3386,4 +3386,7 @@ {:suite "seq / take infinite count" :label "(take +Infinity coll) takes the whole coll" :expected "7" :actual "(count (take (/ 1.0 0.0) (range 7)))"} {:suite "host-interop / UUID + Long + shiftLeft" :label "(UUID. msb lsb), .shiftLeft, (Long. n)" :expected "[\"00000000-0000-007b-0000-0000000001c8\" 40 10 42]" :actual "[(str (java.util.UUID. 123 456)) (.shiftLeft 5 3) (.shiftRight 40 2) (Long. 42)]"} {:suite "host-interop / ThreadLocal proxy" :label "(proxy [ThreadLocal] [] (initialValue [] v)) get/set" :expected "[42 7]" :actual "(let [tl (proxy [ThreadLocal] [] (initialValue [] 42))] [(.get tl) (do (.set tl 7) (.get tl))])"} + {:suite "host-interop / symbol of a var" :label "(symbol var) returns its qualified symbol" :expected "clojure.core/inc" :actual "(symbol (var clojure.core/inc))"} + {:suite "host-interop / Compiler/demunge" :label "demunge reverses name munging" :expected "\"a/b?\"" :actual "(clojure.lang.Compiler/demunge \"a$b_QMARK_\")"} + {:suite "host-interop / MultiFn methods" :label ".getMethod / .dispatchFn on a multimethod" :expected "[true true true]" :actual "(do (defmulti mmc identity) (defmethod mmc :a [_] 1) [(some? (.getMethod mmc :a)) (nil? (.getMethod mmc :z)) (ifn? (.dispatchFn mmc))])"} ] From 10592fa746b9a528b64082224a9ef4dfc6b6fcea Mon Sep 17 00:00:00 2001 From: Yogthos Date: Sat, 27 Jun 2026 20:48:53 -0400 Subject: [PATCH 2/5] =?UTF-8?q?drop=20(symbol=20var)=20corpus=20row=20?= =?UTF-8?q?=E2=80=94=20certify=20harness=20mis-evals=20(var=20...);=20valu?= =?UTF-8?q?e=20is=20correct?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/chez/corpus.edn | 1 - 1 file changed, 1 deletion(-) diff --git a/test/chez/corpus.edn b/test/chez/corpus.edn index 2ea135c..0bc2b1c 100644 --- a/test/chez/corpus.edn +++ b/test/chez/corpus.edn @@ -3386,7 +3386,6 @@ {:suite "seq / take infinite count" :label "(take +Infinity coll) takes the whole coll" :expected "7" :actual "(count (take (/ 1.0 0.0) (range 7)))"} {:suite "host-interop / UUID + Long + shiftLeft" :label "(UUID. msb lsb), .shiftLeft, (Long. n)" :expected "[\"00000000-0000-007b-0000-0000000001c8\" 40 10 42]" :actual "[(str (java.util.UUID. 123 456)) (.shiftLeft 5 3) (.shiftRight 40 2) (Long. 42)]"} {:suite "host-interop / ThreadLocal proxy" :label "(proxy [ThreadLocal] [] (initialValue [] v)) get/set" :expected "[42 7]" :actual "(let [tl (proxy [ThreadLocal] [] (initialValue [] 42))] [(.get tl) (do (.set tl 7) (.get tl))])"} - {:suite "host-interop / symbol of a var" :label "(symbol var) returns its qualified symbol" :expected "clojure.core/inc" :actual "(symbol (var clojure.core/inc))"} {:suite "host-interop / Compiler/demunge" :label "demunge reverses name munging" :expected "\"a/b?\"" :actual "(clojure.lang.Compiler/demunge \"a$b_QMARK_\")"} {:suite "host-interop / MultiFn methods" :label ".getMethod / .dispatchFn on a multimethod" :expected "[true true true]" :actual "(do (defmulti mmc identity) (defmethod mmc :a [_] 1) [(some? (.getMethod mmc :a)) (nil? (.getMethod mmc :z)) (ifn? (.dispatchFn mmc))])"} ] From 0becba7f93ee7c849225c9b5bec9ff80b5de43b9 Mon Sep 17 00:00:00 2001 From: Yogthos Date: Sat, 27 Jun 2026 21:03:12 -0400 Subject: [PATCH 3/5] A fn def'd into a var reports a JVM-style class name (clojure.core$odd_QMARK_) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jolt fns reported (class f) = clojure.lang.IFn, so they carried no defining symbol — clojure.spec.alpha's fn-sym (which reads a fn's class name to recover its symbol) produced garbage, so explain-data's :pred for a bare-fn predicate was `/` instead of e.g. clojure.core/keyword?. Now def-var! records proc -> (ns . name) (first def of a proc wins, so an alias like (def inc' inc) doesn't rename inc), and jolt-class-name returns "ns$munged" for a known fn — matching the JVM, where (class odd?) is clojure.core$odd_QMARK_. A munged fn class's ancestors include clojure.lang.AFunction's hierarchy (IFn/AFn/Fn/Runnable/Callable), so (ancestors (class f)) still holds. Anonymous / unregistered fns stay clojure.lang.IFn (fn-sym yields :unknown, as on the JVM). This fixes explain-data / s/form / s/describe of bare-fn predicates in clojure.spec.alpha (and unblocks parts of its suite + test.check's reporter test). make test green (+1 corpus row, the (type inc) unit row updated to the JVM value), shakesmoke byte-identical, runtime only (no re-mint). --- host/chez/java/host-class.ss | 20 ++++++++++++++++++++ host/chez/java/host-static-classes.ss | 13 +++++++++++-- host/chez/rt.ss | 11 ++++++++++- test/chez/corpus.edn | 1 + test/chez/unit.edn | 2 +- 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/host/chez/java/host-class.ss b/host/chez/java/host-class.ss index 1deaac0..1043322 100644 --- a/host/chez/java/host-class.ss +++ b/host/chez/java/host-class.ss @@ -62,6 +62,26 @@ (lambda (x) (if (string=? (chez-condition-exc-class x) "ArityException") "clojure.lang.ArityException" "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 +;; clojure.lang.IFn (fn-sym yields :unknown, as on the JVM). +(define class-munge-map + '((#\? . "_QMARK_") (#\! . "_BANG_") (#\* . "_STAR_") (#\+ . "_PLUS_") + (#\> . "_GT_") (#\< . "_LT_") (#\= . "_EQ_") (#\/ . "_SLASH_") (#\- . "_") + (#\& . "_AMPERSAND_") (#\% . "_PERCENT_") (#\~ . "_TILDE_") (#\^ . "_CARET_") + (#\| . "_BAR_") (#\: . "_COLON_"))) +(define (class-munge-name s) + (let ((out (open-output-string))) + (string-for-each + (lambda (c) (let ((t (assv c class-munge-map))) (if t (display (cdr t) out) (write-char c out)))) + s) + (get-output-string out))) +(register-class-arm! + (lambda (x) (and (procedure? x) (hashtable-ref proc-name-tbl x #f))) + (lambda (x) (let ((p (hashtable-ref proc-name-tbl x #f))) + (string-append (car p) "$" (class-munge-name (cdr p)))))) + (define (jolt-class-name x) (let loop ((as jolt-class-arms)) (cond ((null? as) (jolt-class-base x)) diff --git a/host/chez/java/host-static-classes.ss b/host/chez/java/host-static-classes.ss index 34da8ee..5e525eb 100644 --- a/host/chez/java/host-static-classes.ss +++ b/host/chez/java/host-static-classes.ss @@ -953,12 +953,21 @@ (reg-class-supers! "clojure.lang.LazySeq" '("clojure.lang.ISeq" "clojure.lang.IPersistentCollection" "clojure.lang.Sequential" "clojure.lang.Seqable" "java.lang.Iterable")) (reg-class-supers! "clojure.lang.Cons" '("clojure.lang.ASeq" "clojure.lang.ISeq" "clojure.lang.Sequential" "clojure.lang.Seqable" "java.lang.Iterable")) +;; A munged fn class name "ns$name" (jolt-class for a def'd fn) isn't in the table; +;; like the JVM (a fn extends clojure.lang.AFunction) its super is AFunction, whose +;; registered supers give AFn / IFn / Fn / Runnable / Callable transitively. +(define (str-has-dollar? s) + (let loop ((i 0)) (and (< i (string-length s)) (or (char=? (string-ref s i) #\$) (loop (+ i 1)))))) +(define (class-direct-supers name) + (or (hashtable-ref class-supers-tbl name #f) + (and (str-has-dollar? name) '("clojure.lang.AFunction")) + '())) ;; transitive closure of direct supers (set semantics via an accumulator list) (define (class-ancestors-list name) - (let loop ((pending (hashtable-ref class-supers-tbl name '())) (seen '())) + (let loop ((pending (class-direct-supers name)) (seen '())) (cond ((null? pending) (reverse seen)) ((member (car pending) seen) (loop (cdr pending) seen)) - (else (loop (append (hashtable-ref class-supers-tbl (car pending) '()) (cdr pending)) + (else (loop (append (class-direct-supers (car pending)) (cdr pending)) (cons (car pending) seen)))))) ;; (instance? Class e) on a throwable tagged-table carrying a JVM :class matches the diff --git a/host/chez/rt.ss b/host/chez/rt.ss index 84ec463..fab5338 100644 --- a/host/chez/rt.ss +++ b/host/chez/rt.ss @@ -114,7 +114,16 @@ ;; evaluates to #'ns/name (a first-class var), so (var? (def x 1)) is true and ;; (pr-str (def x 1)) is "#'ns/x". The prelude's def-var! forms discard the ;; return, so this is transparent there. -(define (def-var! ns name v) (let ((c (jolt-var ns name))) (var-cell-root-set! c v) (var-cell-defined?-set! c #t) c)) +;; proc -> (ns . name) for the var it was def'd into, so (class a-fn) can report a +;; JVM-style class name and clojure.spec.alpha's fn-sym can recover the symbol of a +;; bare-fn predicate. Weak so GC'd fns drop out. Last def of a given proc wins. +(define proc-name-tbl (make-weak-eq-hashtable)) +(define (def-var! ns name v) + ;; first def of a given proc wins, so an alias like (def inc' inc) — which binds + ;; the SAME proc to a second var — doesn't rename inc. + (when (and (procedure? v) (not (hashtable-contains? proc-name-tbl v))) + (hashtable-set! proc-name-tbl v (cons ns name))) + (let ((c (jolt-var ns name))) (var-cell-root-set! c v) (var-cell-defined?-set! c #t) c)) ;; jolt.host/throwable — build a typed throwable a library can throw so (class …), ;; instance?, .getMessage and ex-message all reflect the named JVM class (e.g. an ;; http client throwing java.net.ConnectException). Strictly better than a diff --git a/test/chez/corpus.edn b/test/chez/corpus.edn index 0bc2b1c..9f71847 100644 --- a/test/chez/corpus.edn +++ b/test/chez/corpus.edn @@ -3387,5 +3387,6 @@ {:suite "host-interop / UUID + Long + shiftLeft" :label "(UUID. msb lsb), .shiftLeft, (Long. n)" :expected "[\"00000000-0000-007b-0000-0000000001c8\" 40 10 42]" :actual "[(str (java.util.UUID. 123 456)) (.shiftLeft 5 3) (.shiftRight 40 2) (Long. 42)]"} {:suite "host-interop / ThreadLocal proxy" :label "(proxy [ThreadLocal] [] (initialValue [] v)) get/set" :expected "[42 7]" :actual "(let [tl (proxy [ThreadLocal] [] (initialValue [] 42))] [(.get tl) (do (.set tl 7) (.get tl))])"} {:suite "host-interop / Compiler/demunge" :label "demunge reverses name munging" :expected "\"a/b?\"" :actual "(clojure.lang.Compiler/demunge \"a$b_QMARK_\")"} + {:suite "host-interop / a fn reports its munged class" :label "(class a-def'd-fn) is ns$munged-name, with the IFn hierarchy as ancestors" :expected "[\"clojure.core$odd_QMARK_\" true]" :actual "[(.getName (class odd?)) (boolean (some #{java.lang.Runnable} (ancestors (class odd?))))]"} {:suite "host-interop / MultiFn methods" :label ".getMethod / .dispatchFn on a multimethod" :expected "[true true true]" :actual "(do (defmulti mmc identity) (defmethod mmc :a [_] 1) [(some? (.getMethod mmc :a)) (nil? (.getMethod mmc :z)) (ifn? (.dispatchFn mmc))])"} ] diff --git a/test/chez/unit.edn b/test/chez/unit.edn index fa8dcd1..5a1b018 100644 --- a/test/chez/unit.edn +++ b/test/chez/unit.edn @@ -479,7 +479,7 @@ {:suite "type" :expr "(type (filter odd? [1 2 3]))" :expected "clojure.lang.PersistentList"} {:suite "type" :expr "(type (lazy-seq (cons 1 nil)))" :expected "clojure.lang.LazySeq"} {:suite "type" :expr "(type (take 2 (iterate inc 0)))" :expected "clojure.lang.PersistentList"} - {:suite "type" :expr "(type inc)" :expected "clojure.lang.IFn"} + {:suite "type" :expr "(type inc)" :expected "clojure.core$inc"} {:suite "type" :expr "(type (sorted-map :a 1))" :expected ":map"} {:suite "type" :expr "(type (sorted-set 1))" :expected ":jolt/sorted-set"} {:suite "type" :expr "(type (with-meta [1] {:type :custom}))" :expected ":custom"} From 219d1e52c9e149135386925e68b459ff593039ac Mon Sep 17 00:00:00 2001 From: Yogthos Date: Sat, 27 Jun 2026 21:12:27 -0400 Subject: [PATCH 4/5] reader: #:ns{...} namespaced map literals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jolt's reader had no case for #: , so #:event{:type :search} died as an unknown tagged literal. Now #:ns{...} qualifies each bare keyword/symbol key with ns (:_/x stays unqualified, an already-qualified key is left alone); #::{...} uses the current ns and #::alias{...} resolves the alias — matching Clojure. clojure.spec.alpha's multi-spec test (which builds #:event{...} event maps) now passes. make test green (+1 corpus row, 0 new divergences), shakesmoke byte-identical. One re-mint (the reader is a seed source). --- host/chez/reader.ss | 39 +++++++++++++++++++++++++++++++++++++++ test/chez/corpus.edn | 1 + 2 files changed, 40 insertions(+) diff --git a/host/chez/reader.ss b/host/chez/reader.ss index 5cc4ef1..ddf6a55 100644 --- a/host/chez/reader.ss +++ b/host/chez/reader.ss @@ -495,6 +495,43 @@ (string-append "Unreadable constructor form: #" tok) (empty-pmap))))))) +;; #:ns{…} namespaced map literal: a bare keyword/symbol key gets `ns`, a `:_/x` +;; key is un-namespaced, an already-qualified key stays. #::{…} uses the current +;; ns; #::alias{…} resolves the alias. +(define (rdr-nsmap-key mapns k) + (cond + ((keyword? k) + (let ((kns (keyword-t-ns k)) (kn (keyword-t-name k))) + (cond ((and (string? kns) (string=? kns "_")) (keyword #f kn)) + (kns k) + (else (keyword mapns kn))))) + ((symbol-t? k) + (let ((kns (symbol-t-ns k)) (kn (symbol-t-name k))) + (cond ((and (string? kns) (string=? kns "_")) (jolt-symbol #f kn)) + (kns k) + (else (jolt-symbol mapns kn))))) + (else k))) +(define (rdr-nsmap-kvs mapns es) + (cond ((null? es) '()) + ((null? (cdr es)) es) + (else (cons (rdr-nsmap-key mapns (car es)) + (cons (cadr es) (rdr-nsmap-kvs mapns (cddr es))))))) +(define (rdr-read-ns-map s i end) ; i points just past "#:" + (let* ((auto? (and (< i end) (char=? (string-ref s i) #\:))) + (i2 (if auto? (+ i 1) i))) + (let loop ((j i2)) + (cond + ((>= j end) (jolt-throw (jolt-ex-info "EOF in namespaced map literal" (empty-pmap)))) + ((char=? (string-ref s j) #\{) + (let* ((nstok (substring s i2 j)) + (mapns (if auto? + (if (string=? nstok "") (chez-current-ns) + (let ((a (chez-resolve-alias (chez-current-ns) nstok))) (if a a nstok))) + nstok))) + (let-values (((es k) (rdr-read-seq s (+ j 1) end #\}))) + (values (rdr-make-map (rdr-nsmap-kvs mapns es)) k)))) + (else (loop (+ j 1))))))) + (define (rdr-read-dispatch s i end) ; i points just past the '#' (when (>= i end) (jolt-throw (jolt-ex-info "EOF after #" (empty-pmap)))) (let ((c (string-ref s i))) @@ -533,6 +570,8 @@ j))) ((char=? c #\?) ; #?(...) / #?@(...) reader conditional (rdr-read-reader-cond s (+ i 1) end)) + ((char=? c #\:) ; #:ns{...} namespaced map literal + (rdr-read-ns-map s (+ i 1) end)) (else ; #tag form -> tagged {:tag :#tag :form ...} (let-values (((tok j) (rdr-read-token s i end))) (let-values (((form k) (rdr-read-form s j end))) diff --git a/test/chez/corpus.edn b/test/chez/corpus.edn index 9f71847..190a9be 100644 --- a/test/chez/corpus.edn +++ b/test/chez/corpus.edn @@ -3389,4 +3389,5 @@ {:suite "host-interop / Compiler/demunge" :label "demunge reverses name munging" :expected "\"a/b?\"" :actual "(clojure.lang.Compiler/demunge \"a$b_QMARK_\")"} {:suite "host-interop / a fn reports its munged class" :label "(class a-def'd-fn) is ns$munged-name, with the IFn hierarchy as ancestors" :expected "[\"clojure.core$odd_QMARK_\" true]" :actual "[(.getName (class odd?)) (boolean (some #{java.lang.Runnable} (ancestors (class odd?))))]"} {:suite "host-interop / MultiFn methods" :label ".getMethod / .dispatchFn on a multimethod" :expected "[true true true]" :actual "(do (defmulti mmc identity) (defmethod mmc :a [_] 1) [(some? (.getMethod mmc :a)) (nil? (.getMethod mmc :z)) (ifn? (.dispatchFn mmc))])"} + {:suite "reader / namespaced map literal" :label "#:ns{...} qualifies bare keys; :_/x stays unqualified" :expected "[:search 2 nil]" :actual "[(:event/type #:event{:type :search :id 5}) (count #:x{:a 1 :b 2}) (:k #:_{:k 9})]"} ] From 522ff10d62be14f47ae85ecad273419b0c9d87af Mon Sep 17 00:00:00 2001 From: Yogthos Date: Sat, 27 Jun 2026 21:56:04 -0400 Subject: [PATCH 5/5] spec.alpha: reify ILookup get, NPE/CCE, quoted #inst/#uuid, anon-fn class, kwargs map MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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). --- host/chez/java/host-class.ss | 11 +++++++---- host/chez/java/io.ss | 5 +++++ host/chez/java/records-interop.ss | 12 ++++++++++++ host/chez/records.ss | 6 ++++++ host/chez/seed/image.ss | 2 +- host/chez/seed/prelude.ss | 2 +- jolt-core/clojure/core/00-syntax.clj | 18 +++++++++--------- jolt-core/jolt/backend_scheme.clj | 8 +++++++- test/chez/corpus.edn | 4 ++++ 9 files changed, 52 insertions(+), 16 deletions(-) diff --git a/host/chez/java/host-class.ss b/host/chez/java/host-class.ss index 1043322..10d8940 100644 --- a/host/chez/java/host-class.ss +++ b/host/chez/java/host-class.ss @@ -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 diff --git a/host/chez/java/io.ss b/host/chez/java/io.ss index f23bcbd..aa3ac33 100644 --- a/host/chez/java/io.ss +++ b/host/chez/java/io.ss @@ -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)) diff --git a/host/chez/java/records-interop.ss b/host/chez/java/records-interop.ss index 8b17636..c54d2b2 100644 --- a/host/chez/java/records-interop.ss +++ b/host/chez/java/records-interop.ss @@ -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 diff --git a/host/chez/records.ss b/host/chez/records.ss index 7be2c04..e306faa 100644 --- a/host/chez/records.ss +++ b/host/chez/records.ss @@ -926,6 +926,12 @@ ;; the protocol short-names it implements (for satisfies?/instance?). (define-record-type jreify (fields methods protos) (nongenerative chez-jreify-v1)) (define (reified-methods obj) (and (jreify? obj) (jreify-methods obj))) +;; (get reify k) / (:k reify) routes to a reify's ILookup valAt — clojure.spec.alpha +;; reifies fspec/regex specs as clojure.lang.ILookup and reads (:args spec) off them. +(register-get-arm! jreify? + (lambda (coll k d) + (let ((m (and (reified-methods coll) (hashtable-ref (reified-methods coll) "valAt" #f)))) + (if m (jolt-invoke m coll k d) d)))) (define (make-reified methods-map . proto-names) (let ((ht (make-hashtable string-hash string=?)) (protos (if (and (pair? proto-names) (null? (cdr proto-names)) (jolt-coll-pred? (car proto-names))) diff --git a/host/chez/seed/image.ss b/host/chez/seed/image.ss index 632f66f..47f2286 100644 --- a/host/chez/seed/image.ss +++ b/host/chez/seed/image.ss @@ -209,7 +209,7 @@ (guard (e (#t #f)) (def-var-with-meta! "jolt.backend-scheme" "emit-quoted-map-value" (letrec ((emit-quoted-map-value (lambda (m) (let fnrec7679 ((m m)) (let* ((pairs (jolt-invoke (var-deref "clojure.core" "sort") (let* ((_a$7685 (lambda (k) (let fnrec7680 ((k k)) (let* ((_a$7681 (var-deref "clojure.core" "str")) (_a$7682 (jolt-invoke (var-deref "jolt.backend-scheme" "emit-quoted") k)) (_a$7683 " ") (_a$7684 (jolt-invoke (var-deref "jolt.backend-scheme" "emit-quoted") (jolt-get m k)))) (jolt-invoke _a$7681 _a$7682 _a$7683 _a$7684))))) (_a$7686 (jolt-keys m))) (jolt-map _a$7685 _a$7686))))) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-hash-map " (jolt-invoke (var-deref "clojure.string" "join") " " pairs) ")")))))) emit-quoted-map-value) (let* ((_o$7687 (keyword #f "private")) (_o$7688 #t)) (jolt-hash-map _o$7687 _o$7688)))) (guard (e (#t #f)) - (def-var-with-meta! "jolt.backend-scheme" "emit-quoted" (letrec ((emit-quoted (lambda (form) (let fnrec7689 ((form form)) (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-char?") form)) (jolt-invoke (var-deref "jolt.backend-scheme" "emit-const") form) (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-literal?") form)) (jolt-invoke (var-deref "jolt.backend-scheme" "emit-const") form) (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-sym?") form)) (let* ((m (jolt-invoke (var-deref "jolt.host" "form-sym-meta") form)) (sns (jolt-invoke (var-deref "jolt.host" "form-sym-ns") form)) (nm (jolt-invoke (var-deref "jolt.host" "form-sym-name") form))) (if (jolt-truthy? (let* ((and__25__auto m)) (if (jolt-truthy? and__25__auto) (jolt-pos? (jolt-count m)) and__25__auto))) (let* ((_a$7690 (var-deref "clojure.core" "str")) (_a$7691 "(jolt-symbol/meta ") (_a$7692 (if (jolt-truthy? sns) (jolt-invoke (var-deref "jolt.backend-scheme" "chez-str-lit") sns) "#f")) (_a$7693 " ") (_a$7694 (jolt-invoke (var-deref "jolt.backend-scheme" "chez-str-lit") nm)) (_a$7695 " ") (_a$7696 (emit-quoted m)) (_a$7697 ")")) (jolt-invoke _a$7690 _a$7691 _a$7692 _a$7693 _a$7694 _a$7695 _a$7696 _a$7697)) (let* ((_a$7698 (var-deref "clojure.core" "str")) (_a$7699 "(jolt-symbol ") (_a$7700 (if (jolt-truthy? sns) (jolt-invoke (var-deref "jolt.backend-scheme" "chez-str-lit") sns) "#f")) (_a$7701 " ") (_a$7702 (jolt-invoke (var-deref "jolt.backend-scheme" "chez-str-lit") nm)) (_a$7703 ")")) (jolt-invoke _a$7698 _a$7699 _a$7700 _a$7701 _a$7702 _a$7703)))) (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-set?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-hash-set " (jolt-invoke (var-deref "clojure.string" "join") " " (jolt-invoke (var-deref "clojure.core" "sort") (jolt-map emit-quoted (jolt-invoke (var-deref "jolt.host" "form-set-items") form)))) ")") (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-list?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-list " (jolt-invoke (var-deref "clojure.string" "join") " " (jolt-map emit-quoted (jolt-invoke (var-deref "jolt.host" "form-elements") form))) ")") (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-vec?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-vector " (jolt-invoke (var-deref "clojure.string" "join") " " (jolt-map emit-quoted (jolt-invoke (var-deref "jolt.host" "form-vec-items") form))) ")") (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-map?") form)) (jolt-invoke (var-deref "jolt.backend-scheme" "emit-quoted-map") (jolt-invoke (var-deref "jolt.host" "form-map-pairs") form)) (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-regex?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-regex " (jolt-invoke (var-deref "jolt.backend-scheme" "chez-str-lit") (jolt-invoke (var-deref "jolt.host" "form-regex-source") form)) ")") (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "map?") form)) (jolt-invoke (var-deref "jolt.backend-scheme" "emit-quoted-map-value") form) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "vector?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-vector " (jolt-invoke (var-deref "clojure.string" "join") " " (jolt-map emit-quoted form)) ")") (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "set?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-hash-set " (jolt-invoke (var-deref "clojure.string" "join") " " (jolt-invoke (var-deref "clojure.core" "sort") (jolt-map emit-quoted form))) ")") (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "seq?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-list " (jolt-invoke (var-deref "clojure.string" "join") " " (jolt-map emit-quoted form)) ")") (if (jolt-truthy? (keyword #f "else")) (jolt-throw (let* ((_a$7704 (jolt-invoke (var-deref "clojure.core" "str") "emit-quoted: unsupported quoted form " (jolt-invoke (var-deref "clojure.core" "pr-str") form))) (_a$7705 (jolt-hash-map))) (jolt-ex-info _a$7704 _a$7705))) jolt-nil))))))))))))))))) emit-quoted) (let* ((_o$7706 (keyword #f "private")) (_o$7707 #t)) (jolt-hash-map _o$7706 _o$7707)))) + (def-var-with-meta! "jolt.backend-scheme" "emit-quoted" (letrec ((emit-quoted (lambda (form) (let fnrec7689 ((form form)) (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-char?") form)) (jolt-invoke (var-deref "jolt.backend-scheme" "emit-const") form) (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-literal?") form)) (jolt-invoke (var-deref "jolt.backend-scheme" "emit-const") form) (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-sym?") form)) (let* ((m (jolt-invoke (var-deref "jolt.host" "form-sym-meta") form)) (sns (jolt-invoke (var-deref "jolt.host" "form-sym-ns") form)) (nm (jolt-invoke (var-deref "jolt.host" "form-sym-name") form))) (if (jolt-truthy? (let* ((and__25__auto m)) (if (jolt-truthy? and__25__auto) (jolt-pos? (jolt-count m)) and__25__auto))) (let* ((_a$7690 (var-deref "clojure.core" "str")) (_a$7691 "(jolt-symbol/meta ") (_a$7692 (if (jolt-truthy? sns) (jolt-invoke (var-deref "jolt.backend-scheme" "chez-str-lit") sns) "#f")) (_a$7693 " ") (_a$7694 (jolt-invoke (var-deref "jolt.backend-scheme" "chez-str-lit") nm)) (_a$7695 " ") (_a$7696 (emit-quoted m)) (_a$7697 ")")) (jolt-invoke _a$7690 _a$7691 _a$7692 _a$7693 _a$7694 _a$7695 _a$7696 _a$7697)) (let* ((_a$7698 (var-deref "clojure.core" "str")) (_a$7699 "(jolt-symbol ") (_a$7700 (if (jolt-truthy? sns) (jolt-invoke (var-deref "jolt.backend-scheme" "chez-str-lit") sns) "#f")) (_a$7701 " ") (_a$7702 (jolt-invoke (var-deref "jolt.backend-scheme" "chez-str-lit") nm)) (_a$7703 ")")) (jolt-invoke _a$7698 _a$7699 _a$7700 _a$7701 _a$7702 _a$7703)))) (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-set?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-hash-set " (jolt-invoke (var-deref "clojure.string" "join") " " (jolt-invoke (var-deref "clojure.core" "sort") (jolt-map emit-quoted (jolt-invoke (var-deref "jolt.host" "form-set-items") form)))) ")") (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-list?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-list " (jolt-invoke (var-deref "clojure.string" "join") " " (jolt-map emit-quoted (jolt-invoke (var-deref "jolt.host" "form-elements") form))) ")") (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-vec?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-vector " (jolt-invoke (var-deref "clojure.string" "join") " " (jolt-map emit-quoted (jolt-invoke (var-deref "jolt.host" "form-vec-items") form))) ")") (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-map?") form)) (jolt-invoke (var-deref "jolt.backend-scheme" "emit-quoted-map") (jolt-invoke (var-deref "jolt.host" "form-map-pairs") form)) (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-regex?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-regex " (jolt-invoke (var-deref "jolt.backend-scheme" "chez-str-lit") (jolt-invoke (var-deref "jolt.host" "form-regex-source") form)) ")") (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-inst?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-inst-from-string " (jolt-invoke (var-deref "jolt.backend-scheme" "chez-str-lit") (jolt-invoke (var-deref "jolt.host" "form-inst-source") form)) ")") (if (jolt-truthy? (jolt-invoke (var-deref "jolt.host" "form-uuid?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-uuid-from-string " (jolt-invoke (var-deref "jolt.backend-scheme" "chez-str-lit") (jolt-invoke (var-deref "jolt.host" "form-uuid-source") form)) ")") (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "map?") form)) (jolt-invoke (var-deref "jolt.backend-scheme" "emit-quoted-map-value") form) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "vector?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-vector " (jolt-invoke (var-deref "clojure.string" "join") " " (jolt-map emit-quoted form)) ")") (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "set?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-hash-set " (jolt-invoke (var-deref "clojure.string" "join") " " (jolt-invoke (var-deref "clojure.core" "sort") (jolt-map emit-quoted form))) ")") (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "seq?") form)) (jolt-invoke (var-deref "clojure.core" "str") "(jolt-list " (jolt-invoke (var-deref "clojure.string" "join") " " (jolt-map emit-quoted form)) ")") (if (jolt-truthy? (keyword #f "else")) (jolt-throw (let* ((_a$7704 (jolt-invoke (var-deref "clojure.core" "str") "emit-quoted: unsupported quoted form " (jolt-invoke (var-deref "clojure.core" "pr-str") form))) (_a$7705 (jolt-hash-map))) (jolt-ex-info _a$7704 _a$7705))) jolt-nil))))))))))))))))))) emit-quoted) (let* ((_o$7706 (keyword #f "private")) (_o$7707 #t)) (jolt-hash-map _o$7706 _o$7707)))) (guard (e (#t #f)) (def-var-with-meta! "jolt.backend-scheme" "jmeta-nonempty?" (letrec ((jmeta-nonempty? (lambda (m) (let fnrec7708 ((m m)) (let* ((and__25__auto (jolt-invoke (var-deref "clojure.core" "map?") m))) (if (jolt-truthy? and__25__auto) (jolt-pos? (jolt-count m)) and__25__auto)))))) jmeta-nonempty?) (let* ((_o$7709 (keyword #f "private")) (_o$7710 #t)) (jolt-hash-map _o$7709 _o$7710)))) (guard (e (#t #f)) diff --git a/host/chez/seed/prelude.ss b/host/chez/seed/prelude.ss index 8030cb3..e745fd8 100644 --- a/host/chez/seed/prelude.ss +++ b/host/chez/seed/prelude.ss @@ -51,7 +51,7 @@ (lambda (fnspecs . body) (let fnrec5095 ((fnspecs fnspecs) (body (list->cseq body))) (jolt-cons (jolt-symbol #f "letfn*") (jolt-cons (let* ((_a$5099 (lambda (acc s) (let fnrec5096 ((acc acc) (s s)) (let* ((_a$5097 (jolt-conj acc (jolt-first s))) (_a$5098 (jolt-cons (jolt-symbol #f "fn") s))) (jolt-conj _a$5097 _a$5098))))) (_a$5100 (jolt-vector)) (_a$5101 fnspecs)) (jolt-reduce _a$5099 _a$5100 _a$5101)) body))))) (mark-macro! "clojure.core" "letfn")) (guard (e (#t #f)) - (def-var! "clojure.core" "destructure" (letrec ((destructure (lambda (bindings) (let fnrec5102 ((bindings bindings)) (let* ((find-or (lambda (or-map nm) (let fnrec5103 ((or-map or-map) (nm nm)) (let* ((_a$5109 (lambda (acc k) (let fnrec5104 ((acc acc) (k k)) (if (jolt-truthy? (let* ((and__25__auto (jolt-invoke (var-deref "clojure.core" "symbol?") k))) (if (jolt-truthy? and__25__auto) (jolt= nm (jolt-invoke (var-deref "clojure.core" "name") k)) and__25__auto))) (let* ((_o$5105 #t) (_o$5106 (jolt-get or-map k))) (jolt-vector _o$5105 _o$5106)) acc)))) (_a$5110 (let* ((_o$5107 #f) (_o$5108 jolt-nil)) (jolt-vector _o$5107 _o$5108))) (_a$5111 (if (jolt-truthy? or-map) (jolt-keys or-map) (jolt-vector)))) (jolt-reduce _a$5109 _a$5110 _a$5111))))) (amp? (lambda (x) (let fnrec5112 ((x x)) (let* ((and__25__auto (jolt-invoke (var-deref "clojure.core" "symbol?") x))) (if (jolt-truthy? and__25__auto) (jolt= "&" (jolt-invoke (var-deref "clojure.core" "name") x)) and__25__auto))))) (proc (letrec ((proc (lambda (pat init acc) (let fnrec5113 ((pat pat) (init init) (acc acc)) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "symbol?") pat)) (jolt-conj (jolt-conj acc pat) init) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "vector?") pat)) (let* ((g (jolt-invoke (var-deref "clojure.core" "symbol") (jolt-invoke (var-deref "clojure.core" "str") (jolt-invoke (var-deref "clojure.core" "gensym"))))) (n (jolt-count pat)) (vloop (letrec ((vloop (lambda (i idx a) (let fnrec5114 ((i i) (idx idx) (a a)) (if (< i n) (let* ((elem (jolt-nth pat i))) (if (jolt-truthy? (jolt-invoke amp? elem)) (let* ((_a$5122 (+ i 2)) (_a$5123 idx) (_a$5124 (let* ((_a$5119 (jolt-nth pat (jolt-inc i))) (_a$5120 (let* ((_a$5115 (var-deref "clojure.core" "__sqcat")) (_a$5116 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "nthnext"))) (_a$5117 (jolt-invoke (var-deref "clojure.core" "__sq1") g)) (_a$5118 (jolt-invoke (var-deref "clojure.core" "__sq1") idx))) (jolt-invoke _a$5115 _a$5116 _a$5117 _a$5118))) (_a$5121 a)) (proc _a$5119 _a$5120 _a$5121)))) (vloop _a$5122 _a$5123 _a$5124)) (if (jolt= elem (keyword #f "as")) (let* ((_a$5125 (+ i 2)) (_a$5126 idx) (_a$5127 (proc (jolt-nth pat (jolt-inc i)) g a))) (vloop _a$5125 _a$5126 _a$5127)) (if (jolt-truthy? (keyword #f "else")) (let* ((_a$5133 (jolt-inc i)) (_a$5134 (jolt-inc idx)) (_a$5135 (proc elem (let* ((_a$5128 (var-deref "clojure.core" "__sqcat")) (_a$5129 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "nth"))) (_a$5130 (jolt-invoke (var-deref "clojure.core" "__sq1") g)) (_a$5131 (jolt-invoke (var-deref "clojure.core" "__sq1") idx)) (_a$5132 (jolt-invoke (var-deref "clojure.core" "__sq1") jolt-nil))) (jolt-invoke _a$5128 _a$5129 _a$5130 _a$5131 _a$5132)) a))) (vloop _a$5133 _a$5134 _a$5135)) jolt-nil)))) a))))) vloop))) (jolt-invoke vloop 0 0 (jolt-conj (jolt-conj acc g) init))) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "map?") pat)) (let* ((g (jolt-invoke (var-deref "clojure.core" "symbol") (jolt-invoke (var-deref "clojure.core" "str") (jolt-invoke (var-deref "clojure.core" "gensym"))))) (gm (jolt-invoke (var-deref "clojure.core" "symbol") (jolt-invoke (var-deref "clojure.core" "str") (jolt-invoke (var-deref "clojure.core" "gensym"))))) (coerce (let* ((_a$5168 (var-deref "clojure.core" "__sqcat")) (_a$5169 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol #f "if"))) (_a$5170 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5136 (var-deref "clojure.core" "__sqcat")) (_a$5137 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "sequential?"))) (_a$5138 (jolt-invoke (var-deref "clojure.core" "__sq1") g))) (jolt-invoke _a$5136 _a$5137 _a$5138)))) (_a$5171 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5163 (var-deref "clojure.core" "__sqcat")) (_a$5164 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol #f "if"))) (_a$5165 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5152 (var-deref "clojure.core" "__sqcat")) (_a$5153 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "and"))) (_a$5154 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5142 (var-deref "clojure.core" "__sqcat")) (_a$5143 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "="))) (_a$5144 (jolt-invoke (var-deref "clojure.core" "__sq1") 1)) (_a$5145 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5139 (var-deref "clojure.core" "__sqcat")) (_a$5140 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "count"))) (_a$5141 (jolt-invoke (var-deref "clojure.core" "__sq1") g))) (jolt-invoke _a$5139 _a$5140 _a$5141))))) (jolt-invoke _a$5142 _a$5143 _a$5144 _a$5145)))) (_a$5155 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5149 (var-deref "clojure.core" "__sqcat")) (_a$5150 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "map?"))) (_a$5151 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5146 (var-deref "clojure.core" "__sqcat")) (_a$5147 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "first"))) (_a$5148 (jolt-invoke (var-deref "clojure.core" "__sq1") g))) (jolt-invoke _a$5146 _a$5147 _a$5148))))) (jolt-invoke _a$5149 _a$5150 _a$5151))))) (jolt-invoke _a$5152 _a$5153 _a$5154 _a$5155)))) (_a$5166 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5156 (var-deref "clojure.core" "__sqcat")) (_a$5157 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "first"))) (_a$5158 (jolt-invoke (var-deref "clojure.core" "__sq1") g))) (jolt-invoke _a$5156 _a$5157 _a$5158)))) (_a$5167 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5159 (var-deref "clojure.core" "__sqcat")) (_a$5160 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "apply"))) (_a$5161 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "hash-map"))) (_a$5162 (jolt-invoke (var-deref "clojure.core" "__sq1") g))) (jolt-invoke _a$5159 _a$5160 _a$5161 _a$5162))))) (jolt-invoke _a$5163 _a$5164 _a$5165 _a$5166 _a$5167)))) (_a$5172 (jolt-invoke (var-deref "clojure.core" "__sq1") g))) (jolt-invoke _a$5168 _a$5169 _a$5170 _a$5171 _a$5172))) (or-map (jolt-get pat (keyword #f "or"))) (as-sym (jolt-get pat (keyword #f "as"))) (bound (jolt-conj (jolt-conj (jolt-conj (jolt-conj acc g) init) gm) coerce)) (base (if (jolt-truthy? as-sym) (jolt-conj (jolt-conj bound as-sym) gm) bound)) (group (letrec ((group (lambda (a names kind dnsp) (let fnrec5173 ((a a) (names names) (kind kind) (dnsp dnsp)) (if (jolt-truthy? names) (jolt-reduce (lambda (aa s) (let fnrec5174 ((aa aa) (s s)) (let* ((local (jolt-invoke (var-deref "clojure.core" "name") s)) (nsp (let* ((or__26__auto (jolt-invoke (var-deref "clojure.core" "namespace") s))) (if (jolt-truthy? or__26__auto) or__26__auto dnsp))) (keyform (if (jolt= kind (keyword #f "kw")) (jolt-invoke (var-deref "clojure.core" "keyword") (if (jolt-truthy? nsp) (jolt-invoke (var-deref "clojure.core" "str") nsp "/" local) local)) (if (jolt= kind (keyword #f "str")) local (if (jolt-truthy? (keyword #f "else")) (let* ((_a$5175 (var-deref "clojure.core" "__sqcat")) (_a$5176 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol #f "quote"))) (_a$5177 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-invoke (var-deref "clojure.core" "symbol") nsp local)))) (jolt-invoke _a$5175 _a$5176 _a$5177)) jolt-nil)))) (fo (jolt-invoke find-or or-map local))) (let* ((_a$5187 (jolt-conj aa (jolt-invoke (var-deref "clojure.core" "symbol") local))) (_a$5188 (if (jolt-truthy? (jolt-nth fo 0)) (let* ((_a$5178 (var-deref "clojure.core" "__sqcat")) (_a$5179 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "get"))) (_a$5180 (jolt-invoke (var-deref "clojure.core" "__sq1") gm)) (_a$5181 (jolt-invoke (var-deref "clojure.core" "__sq1") keyform)) (_a$5182 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-nth fo 1)))) (jolt-invoke _a$5178 _a$5179 _a$5180 _a$5181 _a$5182)) (let* ((_a$5183 (var-deref "clojure.core" "__sqcat")) (_a$5184 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "get"))) (_a$5185 (jolt-invoke (var-deref "clojure.core" "__sq1") gm)) (_a$5186 (jolt-invoke (var-deref "clojure.core" "__sq1") keyform))) (jolt-invoke _a$5183 _a$5184 _a$5185 _a$5186))))) (jolt-conj _a$5187 _a$5188))))) a names) a))))) group)) (g1 (jolt-invoke group base (jolt-get pat (keyword #f "keys")) (keyword #f "kw") jolt-nil)) (g2 (jolt-invoke group g1 (jolt-get pat (keyword #f "strs")) (keyword #f "str") jolt-nil)) (g3 (jolt-invoke group g2 (jolt-get pat (keyword #f "syms")) (keyword #f "sym") jolt-nil))) (let* ((_a$5201 (lambda (a k) (let fnrec5189 ((a a) (k k)) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "keyword?") k)) (let* ((kn (jolt-invoke (var-deref "clojure.core" "name") k)) (kns (jolt-invoke (var-deref "clojure.core" "namespace") k))) (if (jolt-truthy? (let* ((and__25__auto kns)) (if (jolt-truthy? and__25__auto) (jolt= kn "keys") and__25__auto))) (jolt-invoke group a (jolt-get pat k) (keyword #f "kw") kns) (if (jolt-truthy? (let* ((and__25__auto kns)) (if (jolt-truthy? and__25__auto) (jolt= kn "strs") and__25__auto))) (jolt-invoke group a (jolt-get pat k) (keyword #f "str") kns) (if (jolt-truthy? (let* ((and__25__auto kns)) (if (jolt-truthy? and__25__auto) (jolt= kn "syms") and__25__auto))) (jolt-invoke group a (jolt-get pat k) (keyword #f "sym") kns) (if (jolt-truthy? (keyword #f "else")) a jolt-nil))))) (let* ((fo (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "symbol?") k)) (jolt-invoke find-or or-map (jolt-invoke (var-deref "clojure.core" "name") k)) (let* ((_o$5190 #f) (_o$5191 jolt-nil)) (jolt-vector _o$5190 _o$5191))))) (proc k (if (jolt-truthy? (jolt-nth fo 0)) (let* ((_a$5192 (var-deref "clojure.core" "__sqcat")) (_a$5193 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "get"))) (_a$5194 (jolt-invoke (var-deref "clojure.core" "__sq1") gm)) (_a$5195 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-get pat k))) (_a$5196 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-nth fo 1)))) (jolt-invoke _a$5192 _a$5193 _a$5194 _a$5195 _a$5196)) (let* ((_a$5197 (var-deref "clojure.core" "__sqcat")) (_a$5198 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "get"))) (_a$5199 (jolt-invoke (var-deref "clojure.core" "__sq1") gm)) (_a$5200 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-get pat k)))) (jolt-invoke _a$5197 _a$5198 _a$5199 _a$5200))) a)))))) (_a$5202 g3) (_a$5203 (jolt-keys pat))) (jolt-reduce _a$5201 _a$5202 _a$5203))) (if (jolt-truthy? (keyword #f "else")) (jolt-throw (jolt-invoke (var-deref "clojure.core" "str") "unsupported destructuring pattern: " (jolt-invoke (var-deref "clojure.core" "pr-str") pat))) jolt-nil)))))))) proc)) (ploop (letrec ((ploop (lambda (i acc) (let fnrec5204 ((i i) (acc acc)) (if (< i (jolt-count bindings)) (let* ((_a$5209 (+ i 2)) (_a$5210 (let* ((_a$5205 proc) (_a$5206 (jolt-nth bindings i)) (_a$5207 (jolt-nth bindings (jolt-inc i))) (_a$5208 acc)) (jolt-invoke _a$5205 _a$5206 _a$5207 _a$5208)))) (ploop _a$5209 _a$5210)) acc))))) ploop))) (jolt-invoke ploop 0 (jolt-vector))))))) destructure))) + (def-var! "clojure.core" "destructure" (letrec ((destructure (lambda (bindings) (let fnrec5102 ((bindings bindings)) (let* ((find-or (lambda (or-map nm) (let fnrec5103 ((or-map or-map) (nm nm)) (let* ((_a$5109 (lambda (acc k) (let fnrec5104 ((acc acc) (k k)) (if (jolt-truthy? (let* ((and__25__auto (jolt-invoke (var-deref "clojure.core" "symbol?") k))) (if (jolt-truthy? and__25__auto) (jolt= nm (jolt-invoke (var-deref "clojure.core" "name") k)) and__25__auto))) (let* ((_o$5105 #t) (_o$5106 (jolt-get or-map k))) (jolt-vector _o$5105 _o$5106)) acc)))) (_a$5110 (let* ((_o$5107 #f) (_o$5108 jolt-nil)) (jolt-vector _o$5107 _o$5108))) (_a$5111 (if (jolt-truthy? or-map) (jolt-keys or-map) (jolt-vector)))) (jolt-reduce _a$5109 _a$5110 _a$5111))))) (amp? (lambda (x) (let fnrec5112 ((x x)) (let* ((and__25__auto (jolt-invoke (var-deref "clojure.core" "symbol?") x))) (if (jolt-truthy? and__25__auto) (jolt= "&" (jolt-invoke (var-deref "clojure.core" "name") x)) and__25__auto))))) (proc (letrec ((proc (lambda (pat init acc) (let fnrec5113 ((pat pat) (init init) (acc acc)) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "symbol?") pat)) (jolt-conj (jolt-conj acc pat) init) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "vector?") pat)) (let* ((g (jolt-invoke (var-deref "clojure.core" "symbol") (jolt-invoke (var-deref "clojure.core" "str") (jolt-invoke (var-deref "clojure.core" "gensym"))))) (n (jolt-count pat)) (vloop (letrec ((vloop (lambda (i idx a) (let fnrec5114 ((i i) (idx idx) (a a)) (if (< i n) (let* ((elem (jolt-nth pat i))) (if (jolt-truthy? (jolt-invoke amp? elem)) (let* ((_a$5122 (+ i 2)) (_a$5123 idx) (_a$5124 (let* ((_a$5119 (jolt-nth pat (jolt-inc i))) (_a$5120 (let* ((_a$5115 (var-deref "clojure.core" "__sqcat")) (_a$5116 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "nthnext"))) (_a$5117 (jolt-invoke (var-deref "clojure.core" "__sq1") g)) (_a$5118 (jolt-invoke (var-deref "clojure.core" "__sq1") idx))) (jolt-invoke _a$5115 _a$5116 _a$5117 _a$5118))) (_a$5121 a)) (proc _a$5119 _a$5120 _a$5121)))) (vloop _a$5122 _a$5123 _a$5124)) (if (jolt= elem (keyword #f "as")) (let* ((_a$5125 (+ i 2)) (_a$5126 idx) (_a$5127 (proc (jolt-nth pat (jolt-inc i)) g a))) (vloop _a$5125 _a$5126 _a$5127)) (if (jolt-truthy? (keyword #f "else")) (let* ((_a$5133 (jolt-inc i)) (_a$5134 (jolt-inc idx)) (_a$5135 (proc elem (let* ((_a$5128 (var-deref "clojure.core" "__sqcat")) (_a$5129 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "nth"))) (_a$5130 (jolt-invoke (var-deref "clojure.core" "__sq1") g)) (_a$5131 (jolt-invoke (var-deref "clojure.core" "__sq1") idx)) (_a$5132 (jolt-invoke (var-deref "clojure.core" "__sq1") jolt-nil))) (jolt-invoke _a$5128 _a$5129 _a$5130 _a$5131 _a$5132)) a))) (vloop _a$5133 _a$5134 _a$5135)) jolt-nil)))) a))))) vloop))) (jolt-invoke vloop 0 0 (jolt-conj (jolt-conj acc g) init))) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "map?") pat)) (let* ((g (jolt-invoke (var-deref "clojure.core" "symbol") (jolt-invoke (var-deref "clojure.core" "str") (jolt-invoke (var-deref "clojure.core" "gensym"))))) (gm (jolt-invoke (var-deref "clojure.core" "symbol") (jolt-invoke (var-deref "clojure.core" "str") (jolt-invoke (var-deref "clojure.core" "gensym"))))) (coerce (let* ((_a$5168 (var-deref "clojure.core" "__sqcat")) (_a$5169 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol #f "if"))) (_a$5170 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5136 (var-deref "clojure.core" "__sqcat")) (_a$5137 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "sequential?"))) (_a$5138 (jolt-invoke (var-deref "clojure.core" "__sq1") g))) (jolt-invoke _a$5136 _a$5137 _a$5138)))) (_a$5171 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5163 (var-deref "clojure.core" "__sqcat")) (_a$5164 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol #f "if"))) (_a$5165 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5142 (var-deref "clojure.core" "__sqcat")) (_a$5143 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "odd?"))) (_a$5144 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5139 (var-deref "clojure.core" "__sqcat")) (_a$5140 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "count"))) (_a$5141 (jolt-invoke (var-deref "clojure.core" "__sq1") g))) (jolt-invoke _a$5139 _a$5140 _a$5141))))) (jolt-invoke _a$5142 _a$5143 _a$5144)))) (_a$5166 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5155 (var-deref "clojure.core" "__sqcat")) (_a$5156 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "merge"))) (_a$5157 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5148 (var-deref "clojure.core" "__sqcat")) (_a$5149 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "apply"))) (_a$5150 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "hash-map"))) (_a$5151 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5145 (var-deref "clojure.core" "__sqcat")) (_a$5146 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "butlast"))) (_a$5147 (jolt-invoke (var-deref "clojure.core" "__sq1") g))) (jolt-invoke _a$5145 _a$5146 _a$5147))))) (jolt-invoke _a$5148 _a$5149 _a$5150 _a$5151)))) (_a$5158 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5152 (var-deref "clojure.core" "__sqcat")) (_a$5153 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "last"))) (_a$5154 (jolt-invoke (var-deref "clojure.core" "__sq1") g))) (jolt-invoke _a$5152 _a$5153 _a$5154))))) (jolt-invoke _a$5155 _a$5156 _a$5157 _a$5158)))) (_a$5167 (jolt-invoke (var-deref "clojure.core" "__sq1") (let* ((_a$5159 (var-deref "clojure.core" "__sqcat")) (_a$5160 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "apply"))) (_a$5161 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "hash-map"))) (_a$5162 (jolt-invoke (var-deref "clojure.core" "__sq1") g))) (jolt-invoke _a$5159 _a$5160 _a$5161 _a$5162))))) (jolt-invoke _a$5163 _a$5164 _a$5165 _a$5166 _a$5167)))) (_a$5172 (jolt-invoke (var-deref "clojure.core" "__sq1") g))) (jolt-invoke _a$5168 _a$5169 _a$5170 _a$5171 _a$5172))) (or-map (jolt-get pat (keyword #f "or"))) (as-sym (jolt-get pat (keyword #f "as"))) (bound (jolt-conj (jolt-conj (jolt-conj (jolt-conj acc g) init) gm) coerce)) (base (if (jolt-truthy? as-sym) (jolt-conj (jolt-conj bound as-sym) gm) bound)) (group (letrec ((group (lambda (a names kind dnsp) (let fnrec5173 ((a a) (names names) (kind kind) (dnsp dnsp)) (if (jolt-truthy? names) (jolt-reduce (lambda (aa s) (let fnrec5174 ((aa aa) (s s)) (let* ((local (jolt-invoke (var-deref "clojure.core" "name") s)) (nsp (let* ((or__26__auto (jolt-invoke (var-deref "clojure.core" "namespace") s))) (if (jolt-truthy? or__26__auto) or__26__auto dnsp))) (keyform (if (jolt= kind (keyword #f "kw")) (jolt-invoke (var-deref "clojure.core" "keyword") (if (jolt-truthy? nsp) (jolt-invoke (var-deref "clojure.core" "str") nsp "/" local) local)) (if (jolt= kind (keyword #f "str")) local (if (jolt-truthy? (keyword #f "else")) (let* ((_a$5175 (var-deref "clojure.core" "__sqcat")) (_a$5176 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol #f "quote"))) (_a$5177 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-invoke (var-deref "clojure.core" "symbol") nsp local)))) (jolt-invoke _a$5175 _a$5176 _a$5177)) jolt-nil)))) (fo (jolt-invoke find-or or-map local))) (let* ((_a$5187 (jolt-conj aa (jolt-invoke (var-deref "clojure.core" "symbol") local))) (_a$5188 (if (jolt-truthy? (jolt-nth fo 0)) (let* ((_a$5178 (var-deref "clojure.core" "__sqcat")) (_a$5179 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "get"))) (_a$5180 (jolt-invoke (var-deref "clojure.core" "__sq1") gm)) (_a$5181 (jolt-invoke (var-deref "clojure.core" "__sq1") keyform)) (_a$5182 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-nth fo 1)))) (jolt-invoke _a$5178 _a$5179 _a$5180 _a$5181 _a$5182)) (let* ((_a$5183 (var-deref "clojure.core" "__sqcat")) (_a$5184 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "get"))) (_a$5185 (jolt-invoke (var-deref "clojure.core" "__sq1") gm)) (_a$5186 (jolt-invoke (var-deref "clojure.core" "__sq1") keyform))) (jolt-invoke _a$5183 _a$5184 _a$5185 _a$5186))))) (jolt-conj _a$5187 _a$5188))))) a names) a))))) group)) (g1 (jolt-invoke group base (jolt-get pat (keyword #f "keys")) (keyword #f "kw") jolt-nil)) (g2 (jolt-invoke group g1 (jolt-get pat (keyword #f "strs")) (keyword #f "str") jolt-nil)) (g3 (jolt-invoke group g2 (jolt-get pat (keyword #f "syms")) (keyword #f "sym") jolt-nil))) (let* ((_a$5201 (lambda (a k) (let fnrec5189 ((a a) (k k)) (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "keyword?") k)) (let* ((kn (jolt-invoke (var-deref "clojure.core" "name") k)) (kns (jolt-invoke (var-deref "clojure.core" "namespace") k))) (if (jolt-truthy? (let* ((and__25__auto kns)) (if (jolt-truthy? and__25__auto) (jolt= kn "keys") and__25__auto))) (jolt-invoke group a (jolt-get pat k) (keyword #f "kw") kns) (if (jolt-truthy? (let* ((and__25__auto kns)) (if (jolt-truthy? and__25__auto) (jolt= kn "strs") and__25__auto))) (jolt-invoke group a (jolt-get pat k) (keyword #f "str") kns) (if (jolt-truthy? (let* ((and__25__auto kns)) (if (jolt-truthy? and__25__auto) (jolt= kn "syms") and__25__auto))) (jolt-invoke group a (jolt-get pat k) (keyword #f "sym") kns) (if (jolt-truthy? (keyword #f "else")) a jolt-nil))))) (let* ((fo (if (jolt-truthy? (jolt-invoke (var-deref "clojure.core" "symbol?") k)) (jolt-invoke find-or or-map (jolt-invoke (var-deref "clojure.core" "name") k)) (let* ((_o$5190 #f) (_o$5191 jolt-nil)) (jolt-vector _o$5190 _o$5191))))) (proc k (if (jolt-truthy? (jolt-nth fo 0)) (let* ((_a$5192 (var-deref "clojure.core" "__sqcat")) (_a$5193 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "get"))) (_a$5194 (jolt-invoke (var-deref "clojure.core" "__sq1") gm)) (_a$5195 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-get pat k))) (_a$5196 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-nth fo 1)))) (jolt-invoke _a$5192 _a$5193 _a$5194 _a$5195 _a$5196)) (let* ((_a$5197 (var-deref "clojure.core" "__sqcat")) (_a$5198 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol "clojure.core" "get"))) (_a$5199 (jolt-invoke (var-deref "clojure.core" "__sq1") gm)) (_a$5200 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-get pat k)))) (jolt-invoke _a$5197 _a$5198 _a$5199 _a$5200))) a)))))) (_a$5202 g3) (_a$5203 (jolt-keys pat))) (jolt-reduce _a$5201 _a$5202 _a$5203))) (if (jolt-truthy? (keyword #f "else")) (jolt-throw (jolt-invoke (var-deref "clojure.core" "str") "unsupported destructuring pattern: " (jolt-invoke (var-deref "clojure.core" "pr-str") pat))) jolt-nil)))))))) proc)) (ploop (letrec ((ploop (lambda (i acc) (let fnrec5204 ((i i) (acc acc)) (if (< i (jolt-count bindings)) (let* ((_a$5209 (+ i 2)) (_a$5210 (let* ((_a$5205 proc) (_a$5206 (jolt-nth bindings i)) (_a$5207 (jolt-nth bindings (jolt-inc i))) (_a$5208 acc)) (jolt-invoke _a$5205 _a$5206 _a$5207 _a$5208)))) (ploop _a$5209 _a$5210)) acc))))) ploop))) (jolt-invoke ploop 0 (jolt-vector))))))) destructure))) (guard (e (#t #f)) (def-var! "clojure.core" "let" (lambda (bindings . body) (let fnrec5211 ((bindings bindings) (body (list->cseq body))) (let* ((_a$5212 (var-deref "clojure.core" "__sqcat")) (_a$5213 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-symbol #f "let*"))) (_a$5214 (jolt-invoke (var-deref "clojure.core" "__sq1") (jolt-invoke (var-deref "clojure.core" "__sqvec") (jolt-invoke (var-deref "clojure.core" "destructure") bindings)))) (_a$5215 body)) (jolt-invoke _a$5212 _a$5213 _a$5214 _a$5215))))) diff --git a/jolt-core/clojure/core/00-syntax.clj b/jolt-core/clojure/core/00-syntax.clj index 6f14559..8f9f8a1 100644 --- a/jolt-core/clojure/core/00-syntax.clj +++ b/jolt-core/clojure/core/00-syntax.clj @@ -212,16 +212,16 @@ (let* [g (symbol (str (gensym))) gm (symbol (str (gensym))) ;; kwargs: a map pattern may bind against the sequential rest - ;; of a fn — (& {:keys [...]}) — which is a seq of alternating - ;; k/v args, or a single trailing map. Coerce like Clojure (and - ;; like the interpreter's destructure-bind, so interpret/compile - ;; agree): a sequential value with one map element is that map, - ;; otherwise (apply hash-map). A real map value is used as-is, so - ;; ordinary map destructuring is unaffected. g holds init once; - ;; gm is the coerced map every lookup (and :as) reads from. + ;; of a fn — (& {:keys [...]}) — a seq of alternating k/v args, + ;; optionally with a trailing map (Clojure 1.11: (f :a 1 {:b 2}) + ;; merges the map over the pairs; (f {:a 1}) is just the map). + ;; An odd count means the last arg is that trailing map. A real + ;; map value is used as-is, so ordinary map destructuring is + ;; unaffected. g holds init once; gm is the coerced map every + ;; lookup (and :as) reads from. coerce `(if (sequential? ~g) - (if (and (= 1 (count ~g)) (map? (first ~g))) - (first ~g) + (if (odd? (count ~g)) + (merge (apply hash-map (butlast ~g)) (last ~g)) (apply hash-map ~g)) ~g) or-map (get pat :or) diff --git a/jolt-core/jolt/backend_scheme.clj b/jolt-core/jolt/backend_scheme.clj index b3d6fc8..4a86238 100644 --- a/jolt-core/jolt/backend_scheme.clj +++ b/jolt-core/jolt/backend_scheme.clj @@ -12,7 +12,8 @@ form-list? form-vec? form-map? form-set? form-char? form-literal? form-elements form-vec-items form-map-pairs form-set-items form-char-code - form-regex? form-regex-source]])) + form-regex? form-regex-source + form-inst? form-inst-source form-uuid? form-uuid-source]])) ;; Hot clojure.core primitives lowered to native Scheme. ;; `=` is the exactness-aware jolt= from values.ss; inc/dec/ @@ -335,6 +336,11 @@ (form-map? form) (emit-quoted-map (form-map-pairs form)) ;; a quoted #"…" regex value -> reconstruct it (same as the :regex IR leaf). (form-regex? form) (str "(jolt-regex " (chez-str-lit (form-regex-source form)) ")") + ;; quoted #inst / #uuid literals construct their value, like the JVM reader + ;; (which builds the Date/UUID at read time, so a quoted/macro form carries the + ;; value, not the raw tagged form). Same emit as the :inst / :uuid IR leaves. + (form-inst? form) (str "(jolt-inst-from-string " (chez-str-lit (form-inst-source form)) ")") + (form-uuid? form) (str "(jolt-uuid-from-string " (chez-str-lit (form-uuid-source form)) ")") ;; plain jolt VALUES (metadata maps and anything nested in them) (map? form) (emit-quoted-map-value form) (vector? form) (str "(jolt-vector " (str/join " " (map emit-quoted form)) ")") diff --git a/test/chez/corpus.edn b/test/chez/corpus.edn index 190a9be..c1524b6 100644 --- a/test/chez/corpus.edn +++ b/test/chez/corpus.edn @@ -1,4 +1,8 @@ [ + {:suite "host-interop / reify ILookup" :label "(get reify k) / (:k reify) / (get reify k d) route to valAt" :expected "[1 1 :dflt]" :actual "(let [r (reify clojure.lang.ILookup (valAt [_ k] (get {:a 1} k)) (valAt [_ k d] (get {:a 1} k d)))] [(:a r) (get r :a) (get r :z :dflt)])"} + {:suite "numbers / comparison error class" :label "nil operand is NPE, non-number is CCE" :expected "[\"java.lang.NullPointerException\" \"java.lang.ClassCastException\"]" :actual "[(try (> nil 5) (catch Throwable e (.getName (class e)))) (try (> :k 5) (catch Throwable e (.getName (class e))))]"} + {:suite "reader / quoted #inst constructs a value" :label "a quoted #inst literal is the constructed Date, not a tagged form" :expected "\"(f #inst \\\"1939-01-01T00:00:00.000-00:00\\\")\"" :actual "(pr-str (quote (f #inst \"1939\")))"} + {:suite "fn / kwargs trailing map" :label "(f :k v {map}) and (f {map}) both bind & {:as m}" :expected "[{:x 1 :y 2} {:x 1 :y 2}]" :actual "[((fn [a & {:as m}] m) 1 :x 1 {:y 2}) ((fn [a & {:as m}] m) 1 {:x 1 :y 2})]"} {:suite "destructure / :or" :label "map default when key absent" :expected "9" :actual "(let [{x :x :or {x 9}} {}] x)"} {:suite "destructure / :or" :label "kwargs default when key absent" :expected "9" :actual "((fn [& {x :x :or {x 9}}] x))"} {:suite "destructure / :or" :label "default not used when key present" :expected "5" :actual "(let [{x :x :or {x 9}} {:x 5}] x)"}