Skip to content

Commit 05fc0c4

Browse files
committed
works
1 parent e057088 commit 05fc0c4

File tree

2 files changed

+98
-58
lines changed

2 files changed

+98
-58
lines changed

src/sci/impl/async_macro.cljc

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,32 @@
234234
with-catch)]
235235
with-finally))
236236

237+
(defn- transform-coll-with-await
238+
"Transform a collection (vector or map entries), chaining any promise-producing elements.
239+
rebuild-fn takes the transformed elements and rebuilds the collection."
240+
[ctx locals elements rebuild-fn]
241+
(let [transformed (doall (map #(transform-async-body ctx locals %) elements))]
242+
(if (some promise-form? transformed)
243+
;; Chain promises sequentially
244+
(loop [elems-before []
245+
remaining transformed]
246+
(if (seq remaining)
247+
(let [elem (first remaining)]
248+
(if (promise-form? elem)
249+
;; Found promise - chain from here
250+
(let [await-sym (gensym "await__")
251+
rest-elems (rest remaining)
252+
rebuilt (rebuild-fn (concat elems-before [await-sym] rest-elems))
253+
;; Recursively transform in case there are more promises
254+
rest-expr (transform-async-body ctx (conj locals await-sym) rebuilt)]
255+
(promise-then elem (list 'fn [await-sym] rest-expr)))
256+
;; Not a promise, accumulate
257+
(recur (conj elems-before elem) (rest remaining))))
258+
;; Shouldn't reach here
259+
(rebuild-fn transformed)))
260+
;; No promises
261+
(rebuild-fn transformed))))
262+
237263
(defn transform-expr-with-await
238264
"Transform a general expression, chaining any promise-producing subforms."
239265
[ctx locals expr]
@@ -365,8 +391,21 @@
365391

366392
;; General expression - transform subforms
367393
(transform-expr-with-await ctx locals body))
368-
;; Not a seq, return as-is
369-
body))))
394+
;; Not a seq - check for vector or map
395+
(cond
396+
;; Vector literal - transform elements
397+
(vector? body)
398+
(transform-coll-with-await ctx locals body vec)
399+
400+
;; Map literal - transform values (keys and values as pairs)
401+
(map? body)
402+
(transform-coll-with-await ctx locals
403+
(mapcat identity body) ;; flatten to [k1 v1 k2 v2 ...]
404+
#(apply hash-map %))
405+
406+
;; Other non-seq (symbol, keyword, number, etc.) - return as-is
407+
:else
408+
body)))))
370409

371410
(defn transform-async-fn-body
372411
"Transform async function body expressions and ensure result is a promise.

test/sci/async_await_test.cljs

Lines changed: 57 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -450,75 +450,76 @@
450450
(-> (p/let [ctx (sci/init {:classes {'js js/globalThis :allow :all}})
451451
v (sci/eval-string* ctx
452452
"(defn ^:async test-complex []
453-
(let [a (await (js/Promise.resolve 1))
454-
b (-> a inc (* 2) (+ (await (js/Promise.resolve 3))))
455-
c (if (await (js/Promise.resolve true))
456-
(let [x (await (js/Promise.resolve 10))]
457-
(+ x b))
458-
0)
459-
d (loop [i 0 acc 0]
460-
(if (< i 3)
461-
(recur (inc i) (+ acc (await (js/Promise.resolve i))))
462-
acc))
463-
e (try
464-
(+ (await (js/Promise.resolve 100))
465-
(throw (js/Error. \"oops\")))
466-
(catch :default err
467-
(await (js/Promise.resolve 42))))
468-
f (case (await (js/Promise.resolve :x))
469-
:x (await (js/Promise.resolve :matched-x))
470-
:y :matched-y
471-
:default)
472-
g (letfn [(double [n] (* 2 n))]
473-
(let [v (await (js/Promise.resolve 5))]
474-
(double v)))
475-
h (await ((^:async fn [x] (+ x (await (js/Promise.resolve 1)))) 10))
476-
i ((fn [x] (+ x 1)) (await (js/Promise.resolve 100)))
477-
j (or (await (js/Promise.resolve nil))
478-
(await (js/Promise.resolve false))
479-
(await (js/Promise.resolve :found)))
480-
k (and (await (js/Promise.resolve 1))
481-
(await (js/Promise.resolve 2))
482-
(await (js/Promise.resolve 3)))
453+
;; All results boxed in vectors to detect unwrapped promises
454+
(let [a [(await (js/Promise.resolve 1))]
455+
b [(-> (first a) inc (* 2) (+ (await (js/Promise.resolve 3))))]
456+
c [(if (await (js/Promise.resolve true))
457+
(let [x (await (js/Promise.resolve 10))]
458+
(+ x (first b)))
459+
0)]
460+
d [(loop [i 0 acc 0]
461+
(if (< i 3)
462+
(recur (inc i) (+ acc (await (js/Promise.resolve i))))
463+
acc))]
464+
e [(try
465+
(+ (await (js/Promise.resolve 100))
466+
(throw (js/Error. \"oops\")))
467+
(catch :default err
468+
(await (js/Promise.resolve 42))))]
469+
f [(case (await (js/Promise.resolve :x))
470+
:x (await (js/Promise.resolve :matched-x))
471+
:y :matched-y
472+
:default)]
473+
g [(letfn [(double [n] (* 2 n))]
474+
(let [v (await (js/Promise.resolve 5))]
475+
(double v)))]
476+
h [(await ((^:async fn [x] (+ x (await (js/Promise.resolve 1)))) 10))]
477+
i [((fn [x] (+ x 1)) (await (js/Promise.resolve 100)))]
478+
j [(or (await (js/Promise.resolve nil))
479+
(await (js/Promise.resolve false))
480+
(await (js/Promise.resolve :found)))]
481+
k [(and (await (js/Promise.resolve 1))
482+
(await (js/Promise.resolve 2))
483+
(await (js/Promise.resolve 3)))]
483484
;; test and short-circuit with falsy
484485
and-atom (atom 0)
485-
l (and (await (js/Promise.resolve false))
486-
(do (swap! and-atom inc) :never))
487-
l-side-effects @and-atom
486+
l [(and (await (js/Promise.resolve false))
487+
(do (swap! and-atom inc) :never))]
488+
l-side-effects [@and-atom]
488489
;; test or short-circuit with truthy
489490
or-atom (atom 0)
490-
m (or (await (js/Promise.resolve :truthy))
491-
(do (swap! or-atom inc) :never))
492-
m-side-effects @or-atom
491+
m [(or (await (js/Promise.resolve :truthy))
492+
(do (swap! or-atom inc) :never))]
493+
m-side-effects [@or-atom]
493494
;; async fn calling another async fn
494-
n (let [async-add (^:async fn [x y]
495-
(+ (await (js/Promise.resolve x))
496-
(await (js/Promise.resolve y))))
497-
async-mul (^:async fn [x y]
498-
(* (await (async-add x 1))
499-
(await (js/Promise.resolve y))))]
500-
(await (async-mul 2 3)))
495+
n [(let [async-add (^:async fn [x y]
496+
(+ (await (js/Promise.resolve x))
497+
(await (js/Promise.resolve y))))
498+
async-mul (^:async fn [x y]
499+
(* (await (async-add x 1))
500+
(await (js/Promise.resolve y))))]
501+
(await (async-mul 2 3)))]
501502
;; nested do blocks
502-
o (do
503-
(do
504-
(await (js/Promise.resolve :inner))
505-
(do
506-
(await (js/Promise.resolve :deeper))
507-
:nested-result)))
503+
o [(do
504+
(do
505+
(await (js/Promise.resolve :inner))
506+
(do
507+
(await (js/Promise.resolve :deeper))
508+
:nested-result)))]
508509
;; for comprehension with await
509-
p (vec (for [x (await (js/Promise.resolve [1 2]))]
510-
(* x 2)))]
510+
p [(vec (for [x (await (js/Promise.resolve [1 2]))]
511+
(* x 2)))]]
511512
{:a a :b b :c c :d d :e e :f f :g g :h h :i i :j j :k k
512513
:l l :l-side-effects l-side-effects
513514
:m m :m-side-effects m-side-effects
514515
:n n :o o :p p}))
515516
(test-complex)")]
516517
(p/let [result v]
517-
(is (= {:a 1 :b 7 :c 17 :d 3 :e 42 :f :matched-x :g 10 :h 11 :i 101
518-
:j :found :k 3
519-
:l false :l-side-effects 0
520-
:m :truthy :m-side-effects 0
521-
:n 9 :o :nested-result :p [2 4]} result))))
518+
(is (= {:a [1] :b [7] :c [17] :d [3] :e [42] :f [:matched-x] :g [10] :h [11] :i [101]
519+
:j [:found] :k [3]
520+
:l [false] :l-side-effects [0]
521+
:m [:truthy] :m-side-effects [0]
522+
:n [9] :o [:nested-result] :p [[2 4]]} result))))
522523
(p/catch (fn [err]
523524
(is false (str err))))
524525
(p/finally done)))))

0 commit comments

Comments
 (0)