Skip to content

Commit 8423ba7

Browse files
committed
wip
1 parent acc970c commit 8423ba7

File tree

3 files changed

+93
-49
lines changed

3 files changed

+93
-49
lines changed

src/sci/impl/analyzer.cljc

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{:no-doc true
33
:clj-kondo/config '{:linters {:unresolved-symbol {:exclude [ctx this bindings]}}}}
44
(:require
5+
#?(:clj [sci.impl.reflector :as reflector])
56
#?(:clj [sci.impl.types :as t :refer [#?(:cljs ->Node) ->constant]])
67
#?(:cljs [cljs.tagged-literals :refer [JSValue]])
78
#?(:cljs [goog.object :as gobj])
@@ -20,8 +21,7 @@
2021
[ana-macros constant? macro? rethrow-with-location-of-node
2122
set-namespace! recur special-syms]]
2223
[sci.impl.vars :as vars]
23-
[sci.lang]
24-
#?(:clj [sci.impl.reflector :as reflector]))
24+
[sci.lang])
2525
#?(:cljs
2626
(:require-macros
2727
[sci.impl.analyzer :refer [gen-return-recur
@@ -902,12 +902,11 @@
902902
:ex ex})
903903
(throw-error-with-location (str "Unable to resolve classname: " ex) ex))))
904904
catches)
905-
sci-error (let [fst (when (= 1 (count catches))
906-
(nth catches 0))
907-
ex (:ex fst)]
908-
(and (= #?(:clj 'Exception
909-
:cljs 'js/Error) ex)
910-
(some-> ex meta :sci/error)))
905+
sci-error (some (fn [{:keys [ex]}]
906+
(and (= #?(:clj 'Exception
907+
:cljs 'js/Error) ex)
908+
(some-> ex meta :sci/error)))
909+
catches)
911910
finally (when finally
912911
(analyze ctx (cons 'do (rest finally))))]
913912
(sci.impl.types/->Node
@@ -1444,36 +1443,36 @@
14441443
:file @utils/current-file)]
14451444
(cond (str/starts-with? meth ".")
14461445
(let [meth (subs meth 1)
1447-
arg-types (when-let [param-tags (some-> (meta expr) :param-tags)]
1448-
(let [param-count (count param-tags)
1449-
^"[Ljava.lang.Class;" arg-types (when (pos? param-count)
1450-
(make-array Class param-count))]
1451-
(areduce arg-types idx _ret nil
1452-
(when-let [t (nth param-tags idx)]
1453-
(when-not (= '_ t)
1454-
(when-let [t (interop/resolve-type-hint ctx t)]
1455-
(aset arg-types idx t)))))
1456-
arg-types))
1457-
f (fn [obj & args]
1458-
(let [args (object-array args)
1459-
arg-count (alength args)
1460-
^java.util.List methods (interop/meth-cache ctx clazz meth arg-count #(reflector/get-methods clazz arg-count meth false) :instance-methods)]
1461-
(reflector/invoke-matching-method meth methods clazz obj args arg-types)))]
1462-
(sci.impl.types/->Node
1463-
f
1464-
stack))
1446+
arg-types (when-let [param-tags (some-> (meta expr) :param-tags)]
1447+
(let [param-count (count param-tags)
1448+
^"[Ljava.lang.Class;" arg-types (when (pos? param-count)
1449+
(make-array Class param-count))]
1450+
(areduce arg-types idx _ret nil
1451+
(when-let [t (nth param-tags idx)]
1452+
(when-not (= '_ t)
1453+
(when-let [t (interop/resolve-type-hint ctx t)]
1454+
(aset arg-types idx t)))))
1455+
arg-types))
1456+
f (fn [obj & args]
1457+
(let [args (object-array args)
1458+
arg-count (alength args)
1459+
^java.util.List methods (interop/meth-cache ctx clazz meth arg-count #(reflector/get-methods clazz arg-count meth false) :instance-methods)]
1460+
(reflector/invoke-matching-method meth methods clazz obj args arg-types)))]
1461+
(sci.impl.types/->Node
1462+
f
1463+
stack))
14651464
(try (reflector/get-static-field ^Class clazz ^String meth)
14661465
(catch IllegalArgumentException _
14671466
nil))
14681467
(sci.impl.types/->Node
1469-
(interop/get-static-field clazz meth)
1470-
stack)
1468+
(interop/get-static-field clazz meth)
1469+
stack)
14711470
:else (sci.impl.types/->Node
1472-
(fn [& args]
1473-
(reflector/invoke-static-method
1474-
clazz meth
1475-
^objects (into-array Object args)))
1476-
stack)))))
1471+
(fn [& args]
1472+
(reflector/invoke-static-method
1473+
clazz meth
1474+
^objects (into-array Object args)))
1475+
stack)))))
14771476

14781477
(defn analyze-call [ctx expr m top-level?]
14791478
(with-top-level-loc top-level? m
@@ -1569,12 +1568,11 @@
15691568
:sci.impl/f-meta f-meta)
15701569
^"[Ljava.lang.Class;" arg-types (when (pos? arg-count)
15711570
(make-array Class arg-count))
1572-
has-types? (volatile! nil)
1573-
]
1571+
has-types? (volatile! nil)]
15741572
(when arg-types
15751573
(or (when-let [param-tags (-> f* (some-> meta :param-tags))]
15761574
(vreset! has-types? true)
1577-
(areduce arg-types idx _ret nil
1575+
(areduce arg-types idx _ret nil
15781576
(when-let [t (nth param-tags idx)]
15791577
(when-not (= '_ t)
15801578
(when-let [t (interop/resolve-type-hint ctx t)]
@@ -1690,7 +1688,7 @@
16901688
arg1 (nth children 1)]
16911689
(sci.impl.types/->Node
16921690
(f* (t/eval arg0 ctx bindings)
1693-
(t/eval arg1 ctx bindings))
1691+
(t/eval arg1 ctx bindings))
16941692
nil))
16951693
(throw-error-with-location (str "Wrong number of args (" ccount ") passed to: " f*) expr)))
16961694
:else

src/sci/impl/evaluator.cljc

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@
7373
(types/eval case-default ctx bindings)
7474
(types/eval found ctx bindings)))))
7575

76+
(defn- sci-error-ex?
77+
"Returns true if e is a sci/error wrapper exception"
78+
[e]
79+
(and (instance? #?(:clj clojure.lang.ExceptionInfo :cljs cljs.core/ExceptionInfo) e)
80+
(isa? (:type (ex-data e)) :sci/error)))
81+
7682
(defn eval-try
7783
[ctx bindings body catches finally sci-error]
7884
(try
@@ -86,13 +92,20 @@
8692
(if-let
8793
[[_ r]
8894
(reduce (fn [_ c]
89-
(let [clazz (:class c)]
95+
(let [clazz (:class c)
96+
;; For catch matching, check both e and its cause if e is a sci/error wrapper
97+
;; This allows specific catches to work even when sci-error wraps exceptions
98+
e-for-match (if (and sci-error
99+
(sci-error-ex? e)
100+
(ex-cause e))
101+
(ex-cause e)
102+
e)]
90103
(when #?(:cljs
91104
(or (kw-identical? :default clazz)
92105
(if (instance? sci.impl.types/NodeR clazz)
93-
(instance? (types/eval clazz ctx bindings) e)
94-
(instance? clazz e)))
95-
:clj (instance? clazz e))
106+
(instance? (types/eval clazz ctx bindings) e-for-match)
107+
(instance? clazz e-for-match)))
108+
:clj (instance? clazz e-for-match))
96109
(reduced
97110
[::try-result
98111
(do (aset ^objects bindings (:ex-idx c) e)

test/sci/core_test.cljc

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
(ns sci.core-test
22
(:require
3+
#?(:clj [sci.ctx-store :as store])
34
[clojure.edn :as edn]
45
[clojure.string :as str]
56
[clojure.test :as test :refer [deftest is testing]]
6-
#?(:clj [sci.ctx-store :as store])
77
[sci.copy-ns-test-ns]
88
[sci.core :as sci :refer [eval-string]]
99
[sci.impl.unrestrict :as unrestrict]
@@ -755,7 +755,7 @@
755755
(def state (atom []))
756756
(doseq [i [1 2 3]] (swap! state conj i))
757757
@state"
758-
{}))))
758+
{}))))
759759

760760
(deftest for-test
761761
(is (= '([1 4] [1 6])
@@ -902,7 +902,7 @@
902902
(is (thrown? js/Error
903903
(sci/eval-string "(try (throw \"blah\") (catch js/Error e (str e e)))")))
904904
(is (= "blahblah" (sci/eval-string "(try (throw \"blah\") (catch :default e (str e e)))")))))
905-
(is (= [1](sci/eval-string "(defn catch [] 1) (try [(catch)])"))))
905+
(is (= [1] (sci/eval-string "(defn catch [] 1) (try [(catch)])"))))
906906

907907
(deftest syntax-quote-test
908908
(is (= '(clojure.core/list 10 10)
@@ -1107,8 +1107,7 @@
11071107
(is (= '(clojure.core/defrecord Foo []) (eval* "(macroexpand '(defrecord Foo []))")))
11081108
(is (= '(. nil log) (eval* "(macroexpand-1 '(.log))")))
11091109
(is (= '(. js/console log) (eval* "(macroexpand-1 '(.log js/console))")))
1110-
(is (= '(. js/console log 1 2 3) (eval* "(macroexpand-1 '(.log js/console 1 2 3))")))
1111-
)
1110+
(is (= '(. js/console log 1 2 3) (eval* "(macroexpand-1 '(.log js/console 1 2 3))"))))
11121111

11131112
(deftest macroexpand-call-test
11141113
(is (= [1 1] (eval* "(defmacro foo [x] `(bar ~x)) (defmacro bar [x] [x x]) (macroexpand '(foo 1))")))
@@ -1157,7 +1156,7 @@
11571156
{:load-fn (fn [{:keys [:namespace]}]
11581157
(case namespace
11591158
foo {:file "foo.clj"
1160-
:source "(ns foo) (println \"hello\")"}))})))))))
1159+
:source "(ns foo) (println \"hello\")"}))})))))))
11611160

11621161
(deftest reload-all-test
11631162
(when-not tu/native?
@@ -1454,7 +1453,7 @@
14541453
(is (= 2 (sci/eval-form @C 'n/foo)))))
14551454

14561455
(deftest merge-opts-preserves-features-test
1457-
(let [ctx(sci/init {:features #{:cljs}})]
1456+
(let [ctx (sci/init {:features #{:cljs}})]
14581457
(is (= 2 (sci/eval-string* ctx "#?(:clj 1 :cljs 2)")))
14591458
(is (= 2 (sci/eval-string* (sci/merge-opts ctx {}) "#?(:clj 1 :cljs 2)")))))
14601459

@@ -1654,6 +1653,40 @@
16541653
'format-stacktrace sci/format-stacktrace}}})]
16551654
(is (str/includes? (str st) "1:31"))))
16561655

1656+
#?(:clj
1657+
(deftest sci-error-multiple-catches-test
1658+
(testing "^:sci/error works with multiple catch clauses"
1659+
(let [result (sci/eval-string
1660+
"(defn foo [] (/ 1 0))
1661+
(defn bar []
1662+
(try (foo)
1663+
(catch ArithmeticException e
1664+
{:caught :arithmetic :msg (ex-message e)})
1665+
(catch ^:sci/error Exception e
1666+
{:caught :exception})))
1667+
(bar)"
1668+
{:classes {'ArithmeticException ArithmeticException}})]
1669+
(is (= :arithmetic (:caught result)))
1670+
(is (str/includes? (:msg result) "Divide by zero"))))
1671+
(testing "^:sci/error Exception catch still gets location info"
1672+
(let [result (sci/eval-string
1673+
"(require '[sci.core :as sci])
1674+
(defn foo [] (assoc :foo :bar))
1675+
(defn bar []
1676+
(try (foo)
1677+
(catch ArithmeticException e
1678+
{:caught :arithmetic})
1679+
(catch ^:sci/error Exception e
1680+
{:caught :exception :st (sci/format-stacktrace (sci/stacktrace e))})))
1681+
(bar)"
1682+
{:classes {'ArithmeticException ArithmeticException}
1683+
:namespaces {'sci.core {'stacktrace sci/stacktrace
1684+
'format-stacktrace sci/format-stacktrace}}})]
1685+
(is (= :exception (:caught result)))
1686+
;; Check that we have location info (user/foo on line 2)
1687+
(is (str/includes? (str (:st result)) "user/foo"))
1688+
(is (str/includes? (str (:st result)) ":2:"))))))
1689+
16571690
(deftest var->sym-test
16581691
(is (= 'clojure.core/inc (sci/var->symbol (sci/eval-string "#'inc")))))
16591692

@@ -1726,7 +1759,7 @@
17261759
(is (true? (sci/eval-string "(exists? js/console.log)" {:classes {'js js/globalThis
17271760
:allow :all}})))
17281761
(is (false? (sci/eval-string "(exists? js/foo.bar)" {:classes {'js js/globalThis
1729-
:allow :all}})))
1762+
:allow :all}})))
17301763
(is (false? (sci/eval-string "(exists? js/console.log.foobar)" {:classes {'js js/globalThis
17311764
:allow :all}})))
17321765
(is (false? (sci/eval-string "(exists? console.log)" {:classes {'js js/globalThis

0 commit comments

Comments
 (0)