Compile data readers that return code forms
A registered #tag data reader whose fn returns a FORM (borkdude/html's #html expands to (->Html (str …))) was rewritten to a runtime call (reader-fn 'inner), so the returned code became a runtime list value instead of being compiled — (str #html [:div]) rendered the code, not "<div>". Clojure applies a data reader at read time and substitutes its result as code. loader.ss now applies the reader at load time: a code form (a list) is spliced in to be compiled, a value (time-literals #time/date -> a Date) keeps the runtime call, which also keeps a non-serializable constant out of an AOT build. The build emit path never applied data readers at all (a #tag literal failed a `jolt build` with "unsupported form"); emit-image.ss gets an ei-emit-form-hook the build sets to the same rewrite, left as a no-op elsewhere so the seed mint (which doesn't load loader.ss) is unaffected and the self-host byte-fixpoint holds. Also make clojure.test report the actual values of a failing (is (= a b)) — it printed only the form. Restricted to the common pure predicates so a macro head still takes the plain path. Fixture test/chez/datareader-app + a smoke check (interpreted) and a build-smoke check (AOT). make test green, no corpus change.
This commit is contained in:
parent
1008e922d8
commit
908ad63caa
10 changed files with 88 additions and 8 deletions
|
|
@ -57,9 +57,25 @@
|
|||
((and (pmap? x) (eq? (jolt-get x rdr-kw-jolt-type) rdr-kw-jolt-tagged))
|
||||
(let ((rdr (data-reader-symbol (jolt-get x rdr-kw-tag)))
|
||||
(inner (ldr-apply-readers (jolt-get x rdr-kw-form))))
|
||||
(cond (rdr (jolt-list rdr (jolt-list (jolt-symbol #f "quote") inner)))
|
||||
((eq? inner (jolt-get x rdr-kw-form)) x)
|
||||
(else (rdr-make-tagged (jolt-get x rdr-kw-tag) inner)))))
|
||||
(cond
|
||||
(rdr
|
||||
;; Clojure applies a data reader at read time and substitutes its result
|
||||
;; as code. A reader that returns a FORM (a list — e.g. borkdude.html's
|
||||
;; #html expands to (->Html (str …))) must be compiled, so splice it in.
|
||||
;; A reader that returns a VALUE (time-literals #time/date -> a Date) is
|
||||
;; left as a runtime call (reader-fn 'inner): the value rebuilds at
|
||||
;; startup, which also keeps a non-serializable constant out of an AOT
|
||||
;; build. Apply is guarded — a reader that can't run at load time (its
|
||||
;; deps not ready) falls back to the runtime call too.
|
||||
(let ((result (and (symbol-t? rdr) (not (jolt-nil? (symbol-t-ns rdr)))
|
||||
(guard (e (#t #f))
|
||||
(let ((fn (var-deref (symbol-t-ns rdr) (symbol-t-name rdr))))
|
||||
(and (procedure? fn) (jolt-invoke fn inner)))))))
|
||||
(if (cseq? result)
|
||||
result
|
||||
(jolt-list rdr (jolt-list (jolt-symbol #f "quote") inner)))))
|
||||
((eq? inner (jolt-get x rdr-kw-form)) x)
|
||||
(else (rdr-make-tagged (jolt-get x rdr-kw-tag) inner)))))
|
||||
((rdr-set-form? x)
|
||||
(let-values (((items changed) (ldr-conv-each (seq->list (jolt-get x rdr-kw-value)))))
|
||||
(if changed (rdr-carry-meta x (rdr-make-set items)) x)))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue