Skip to content
44 changes: 29 additions & 15 deletions src/sci/impl/analyzer.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -1226,21 +1226,35 @@
:file @utils/current-file)
nil))
(throw-error-with-location (str "Unable to resolve classname: " class-sym) class-sym)))
:clj (if-let [class (:class (interop/resolve-class-opts ctx class-sym))]
(invoke-constructor-node ctx class args)
(if-let [record (records/resolve-record-class ctx class-sym)]
(let [args (analyze-children ctx args)]
;; _ctx expr f analyzed-children stack
(return-call ctx
;; for backwards compatibility with error reporting
expr
(:sci.impl/constructor (meta record))
args
(assoc (meta expr)
:ns @utils/current-ns
:file @utils/current-file)
nil))
(throw-error-with-location (str "Unable to resolve classname: " class-sym) class-sym)))
:clj (let [class-opts (interop/resolve-class-opts ctx class-sym)
ctor (:constructor class-opts)]
(case (interop/member-disposition ctor class-opts nil)
:override (let [args (analyze-children ctx args)]
(return-call ctx
expr
ctor
args
(assoc (meta expr)
:ns @utils/current-ns
:file @utils/current-file)
nil))
:deny (utils/throw-error-with-location
(str "Constructor of " class-sym " not allowed!") expr)
:reflect (if-let [class (:class class-opts)]
(invoke-constructor-node ctx class args)
(if-let [record (records/resolve-record-class ctx class-sym)]
(let [args (analyze-children ctx args)]
;; _ctx expr f analyzed-children stack
(return-call ctx
;; for backwards compatibility with error reporting
expr
(:sci.impl/constructor (meta record))
args
(assoc (meta expr)
:ns @utils/current-ns
:file @utils/current-file)
nil))
(throw-error-with-location (str "Unable to resolve classname: " class-sym) class-sym)))))
:cljs (if (symbol? class-sym)
;; try to statically analyze class for better performance
(if-let [class (or
Expand Down
32 changes: 30 additions & 2 deletions test/sci/interop_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
:instance-fields {:closed true 'x true}}}})))
(is (thrown-with-msg? Exception #"Field x on .*PublicFields not allowed"
(sci/eval-string "(.-x (PublicFields.))"
{:classes {'PublicFields {:class PublicFields :closed true}}})))
{:classes {'PublicFields {:class PublicFields :closed true :constructor true}}})))
(is (thrown-with-msg? Exception #"Field x on .*PublicFields not allowed"
(sci/eval-string "(.-x (PublicFields.))"
{:classes {'PublicFields {:class PublicFields
Expand Down Expand Up @@ -152,7 +152,35 @@
#?(:clj
(deftest constructor-test
(is (= "dude" (eval* "(String. (str \"dude\"))")))
(is (= "dude" (eval* "(new String (str \"dude\"))")))))
(is (= "dude" (eval* "(new String (str \"dude\"))")))

;; Manipulate constructors by configuring other classes and functions.
;; Don't test in native because the config is not correctly serialized in this case
(when-not tu/native?
(is (instance? java.io.File (tu/eval* "(String. \"dude\")" {:classes {'String {:class java.io.File}}})))

(is (= 123 (tu/eval* "(String. \"dude\")" {:classes {'String {:constructor (fn [_] 123)}}})))
(is (= 123 (tu/eval* "(String. \"dude\")" {:classes {'String {:class String
:constructor (fn [_] 123)}}})))

;; Constructors and :closed classes
(is (thrown-with-msg? Exception #"Constructor of String not allowed" (tu/eval* "(String. \"dude\")" {:classes {'String {:class String
:closed true}}})))

(is (= "dude" (tu/eval* "(String. \"dude\")" {:classes {'String {:class String
:closed true
:constructor true}}})))
(is (= 123 (tu/eval* "(String. \"dude\")" {:classes {'String {:class String
:closed true
:constructor (fn [_] 123)}}})))
;; If you *just* want to deny a constructor you have to override it with a function that throws
(let [deny-ctor-opts {:classes {'String {:class String
:constructor (fn [_] (throw (ex-info "Constructor of String not allowed" {})))}}}]
(is (thrown-with-msg? Exception #"Constructor of String not allowed" (tu/eval* "(String. \"dude\")" deny-ctor-opts)))
(is (= 4 (tu/eval* "(.length \"dude\")" deny-ctor-opts))))


)))

#?(:clj
(deftest import-test
Expand Down
Loading