Skip to content

Commit af55d62

Browse files
committed
wip
1 parent d6abfba commit af55d62

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

src/sci/impl/async_macro.cljc

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,51 @@
108108
(first acc)
109109
(list* 'do acc)))))
110110

111+
(defn transform-try
112+
"Transform try/catch/finally with await into Promise .catch/.finally chains.
113+
(try (await p) (catch :default e handler) (finally cleanup))
114+
->
115+
(-> (js/Promise.resolve p) (.catch (fn [e] handler)) (.finally (fn [] cleanup)))"
116+
[ctx exprs]
117+
(let [;; Separate body from catch/finally clauses
118+
catch-finally? (fn [form]
119+
(and (seq? form)
120+
(#{'catch 'finally} (first form))))
121+
body-exprs (take-while (complement catch-finally?) exprs)
122+
clauses (drop-while (complement catch-finally?) exprs)
123+
catch-clauses (filter #(and (seq? %) (= 'catch (first %))) clauses)
124+
finally-clause (first (filter #(and (seq? %) (= 'finally (first %))) clauses))
125+
;; Transform body as a do block
126+
transformed-body (if (= 1 (count body-exprs))
127+
(transform-async-body ctx (first body-exprs))
128+
(transform-do ctx body-exprs))
129+
;; Wrap in Promise.resolve if not already a promise chain
130+
promise-chain (if (and (seq? transformed-body)
131+
(or (= '.then (first transformed-body))
132+
(= 'js/Promise.resolve (first transformed-body))))
133+
transformed-body
134+
(wrap-promise transformed-body))]
135+
;; Add .catch clauses
136+
(let [with-catch (reduce
137+
(fn [chain catch-clause]
138+
;; (catch Type e handler-body...)
139+
(let [[_ _type binding & handler-body] catch-clause
140+
transformed-handler (if (= 1 (count handler-body))
141+
(transform-async-body ctx (first handler-body))
142+
(transform-do ctx handler-body))]
143+
(list '.catch chain (list 'fn [binding] transformed-handler))))
144+
promise-chain
145+
catch-clauses)
146+
;; Add .finally if present
147+
with-finally (if finally-clause
148+
(let [[_ & finally-body] finally-clause
149+
transformed-finally (if (= 1 (count finally-body))
150+
(transform-async-body ctx (first finally-body))
151+
(transform-do ctx finally-body))]
152+
(list '.finally with-catch (list 'fn [] transformed-finally)))
153+
with-catch)]
154+
with-finally)))
155+
111156
(defn transform-expr-with-await
112157
"Transform an expression containing await by extracting the await
113158
and wrapping in .then."
@@ -147,7 +192,7 @@
147192
expanded (if (and (seq? body)
148193
(symbol? (first body))
149194
(not (await-call? body))
150-
(not (#{'let 'let* 'do 'fn 'fn* 'if 'quote} (first body))))
195+
(not (#{'let 'let* 'do 'fn 'fn* 'if 'quote 'try} (first body))))
151196
(macroexpand/macroexpand ctx body)
152197
body)
153198
;; If expansion changed the form, recursively transform
@@ -162,6 +207,9 @@
162207
(and (seq? body) (= 'do (first body)))
163208
(transform-do ctx (rest body))
164209

210+
(and (seq? body) (= 'try (first body)))
211+
(transform-try ctx (rest body))
212+
165213
;; Handle any other expression containing await
166214
(contains-await? body)
167215
(transform-expr-with-await ctx body)

test/sci/async_await_test.cljs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,31 @@
153153
(p/catch (fn [err]
154154
(is false (str err))))
155155
(p/finally done)))))
156+
157+
(deftest async-fn-try-catch-test
158+
(testing "^:async fn with try/catch"
159+
(async done
160+
(-> (p/let [ctx (sci/init {:classes {'js js/globalThis :allow :all}})
161+
;; Test catching a rejected promise
162+
v1 (sci/eval-string* ctx
163+
"(defn ^:async safe-fetch []
164+
(try
165+
(await (js/Promise.reject (js/Error. \"oops\")))
166+
(catch :default e
167+
\"caught\")))
168+
(safe-fetch)")
169+
;; Test successful try (no catch)
170+
v2 (sci/eval-string* ctx
171+
"(defn ^:async safe-fetch2 []
172+
(try
173+
(await (js/Promise.resolve 42))
174+
(catch :default e
175+
\"caught\")))
176+
(safe-fetch2)")]
177+
(p/let [r1 v1
178+
r2 v2]
179+
(is (= "caught" r1))
180+
(is (= 42 r2))))
181+
(p/catch (fn [err]
182+
(is false (str err))))
183+
(p/finally done)))))

0 commit comments

Comments
 (0)