-
-
Notifications
You must be signed in to change notification settings - Fork 54
Description
version
3ac045b
problem
Commit 3ac045b introduced a situation where the statement function in compiler_common.cljc can receive a Code record instead of a String resulting int:
java.lang.ClassCastException: class squint.compiler_common.Code cannot be cast to class java.lang.CharSequence (squint.compiler_common.Code is in unnamed module of loader clojure.lang.DynamicClassLoader @37b470df; java.lang.CharSequence is in module java.base of loader 'bootstrap')
at clojure.string$blank_QMARK_.invokeStatic (string.clj:294)
The issue seems to be that the removed (str ";") would implicitly convert Code records to strings, but (statement) expects its input to already be a string. When emit returns a Code record (which happens for boolean-tagged js* expressions), the new code passes it directly to statement, which calls str/blank? and crashes.
repro
(require '[clojure.string :as str])
(require '[squint.compiler :as compiler])
(def compiler-macros
{'custom {'expr-and (fn [_ _ & args]
(let [js (str/join " && " (repeat (count args) "(~{})"))]
(vary-meta
(concat (list 'js* js) args)
assoc :tag 'boolean)))}})
;; This should work on old squint, fail on new squint
(compiler/compile-string
"(let [value 1]
(custom/expr-and (= value 1) (= 2 2)))"
{:context :expr
:macros compiler-macros
:elide-imports true
:elide-exports true
:top-level false})The fact that the expr-and form is in the return/tail position seems to be important. If you move it in to the let block as a right hand value, then it works.
expected behavior
(() => {
const value1 = 1;
return ((value1) === (1)) && ((2) === (2));;
})()The expr-and macro is a real macro I use in datastar-expressions to ensure that a (and ...) form is always transpiled to a javascript expression using &&.