|
92 | 92 | (if (seq acc) |
93 | 93 | ;; Have accumulated expressions before promise - mark the do as promise-producing |
94 | 94 | (let [then-expr (if rest-body |
95 | | - (promise-then transformed (list 'fn ['_] rest-body)) |
| 95 | + (promise-then transformed (list 'fn* ['_] rest-body)) |
96 | 96 | transformed)] |
97 | 97 | (mark-promise (list* 'do (conj acc then-expr)))) |
98 | 98 | ;; No accumulated expressions |
99 | 99 | (if rest-body |
100 | | - (promise-then transformed (list 'fn ['_] rest-body)) |
| 100 | + (promise-then transformed (list 'fn* ['_] rest-body)) |
101 | 101 | transformed))) |
102 | 102 | ;; No promise, accumulate |
103 | 103 | (recur rest-exprs (conj acc transformed)))) |
|
150 | 150 | transformed-body |
151 | 151 | (wrap-promise transformed-body)) |
152 | 152 | ;; Build the loop function |
153 | | - loop-fn (list 'fn loop-fn-name param-names promised-body) |
| 153 | + loop-fn (list 'fn* loop-fn-name param-names promised-body) |
154 | 154 | ;; Immediately invoke with initial values |
155 | 155 | loop-call (apply list loop-fn init-values)] |
156 | 156 | ;; Wrap in js/Promise.resolve so it's recognized as promise-producing |
|
175 | 175 | (if (seq acc-bindings) |
176 | 176 | (list 'let* (vec acc-bindings) |
177 | 177 | (promise-then transformed-init |
178 | | - (list 'fn [binding-name] rest-body))) |
| 178 | + (list 'fn* [binding-name] rest-body))) |
179 | 179 | (promise-then transformed-init |
180 | | - (list 'fn [binding-name] rest-body)))) |
| 180 | + (list 'fn* [binding-name] rest-body)))) |
181 | 181 | ;; No await in this binding - accumulate and continue |
182 | 182 | (recur (rest pairs) |
183 | 183 | (conj acc-bindings binding-name transformed-init) |
|
213 | 213 | (wrap-promise transformed-body)) |
214 | 214 | ;; Add .catch clauses |
215 | 215 | with-catch (reduce |
216 | | - (fn [chain catch-clause] |
217 | | - ;; (catch Type e handler-body...) |
218 | | - (let [[_ _type binding & handler-body] catch-clause |
219 | | - ;; Add catch binding to locals for handler |
220 | | - handler-locals (conj locals binding) |
221 | | - transformed-handler (if (= 1 (count handler-body)) |
222 | | - (transform-async-body ctx handler-locals (first handler-body)) |
223 | | - (transform-do ctx handler-locals handler-body))] |
224 | | - (promise-catch chain (list 'fn [binding] transformed-handler)))) |
225 | | - promise-chain |
226 | | - catch-clauses) |
227 | | - ;; Add .finally if present |
228 | | - with-finally (if finally-clause |
229 | | - (let [[_ & finally-body] finally-clause |
230 | | - transformed-finally (if (= 1 (count finally-body)) |
231 | | - (transform-async-body ctx locals (first finally-body)) |
232 | | - (transform-do ctx locals finally-body))] |
233 | | - (promise-finally with-catch (list 'fn [] transformed-finally))) |
234 | | - with-catch)] |
| 216 | + (fn [chain catch-clause] |
| 217 | + ;; (catch Type e handler-body...) |
| 218 | + (let [[_ _type binding & handler-body] catch-clause |
| 219 | + ;; Add catch binding to locals for handler |
| 220 | + handler-locals (conj locals binding) |
| 221 | + transformed-handler (if (= 1 (count handler-body)) |
| 222 | + (transform-async-body ctx handler-locals (first handler-body)) |
| 223 | + (transform-do ctx handler-locals handler-body))] |
| 224 | + (promise-catch chain (list 'fn* [binding] transformed-handler)))) |
| 225 | + promise-chain |
| 226 | + catch-clauses) |
| 227 | + ;; Add .finally if present |
| 228 | + with-finally (if finally-clause |
| 229 | + (let [[_ & finally-body] finally-clause |
| 230 | + transformed-finally (if (= 1 (count finally-body)) |
| 231 | + (transform-async-body ctx locals (first finally-body)) |
| 232 | + (transform-do ctx locals finally-body))] |
| 233 | + (promise-finally with-catch (list 'fn* [] transformed-finally))) |
| 234 | + with-catch)] |
235 | 235 | with-finally)) |
236 | 236 |
|
237 | 237 | (defn- transform-coll-with-await |
|
240 | 240 | [ctx locals elements rebuild-fn] |
241 | 241 | (let [transformed (doall (map #(transform-async-body ctx locals %) elements))] |
242 | 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))) |
| 243 | + ;; Chain promises sequentially - don't re-transform already transformed elements |
| 244 | + (letfn [(chain-remaining [elems-before remaining] |
| 245 | + (if (seq remaining) |
| 246 | + (let [elem (first remaining)] |
| 247 | + (if (promise-form? elem) |
| 248 | + ;; Found promise - chain from here |
| 249 | + (let [await-sym (gensym "await__") |
| 250 | + rest-transformed (rest remaining) |
| 251 | + ;; Recursively chain the rest WITHOUT re-transforming |
| 252 | + rest-expr (chain-remaining (conj elems-before await-sym) |
| 253 | + rest-transformed)] |
| 254 | + (promise-then elem (list 'fn* [await-sym] rest-expr))) |
| 255 | + ;; Not a promise, accumulate |
| 256 | + (chain-remaining (conj elems-before elem) |
| 257 | + (rest remaining)))) |
| 258 | + ;; No more elements - rebuild collection |
| 259 | + (rebuild-fn elems-before)))] |
| 260 | + (chain-remaining [] transformed)) |
260 | 261 | ;; No promises |
261 | 262 | (rebuild-fn transformed)))) |
262 | 263 |
|
|
281 | 282 | rebuilt (apply list op (concat args-before [await-sym] rest-args)) |
282 | 283 | ;; Recursively transform in case there are more promises |
283 | 284 | rest-expr (transform-async-body ctx (conj locals await-sym) rebuilt)] |
284 | | - (promise-then arg (list 'fn [await-sym] rest-expr))) |
| 285 | + (promise-then arg (list 'fn* [await-sym] rest-expr))) |
285 | 286 | ;; Not a promise, accumulate |
286 | 287 | (recur (conj args-before arg) |
287 | 288 | (rest remaining-args)))) |
|
302 | 303 | expanded (if (and (seq? body) |
303 | 304 | (symbol? op) |
304 | 305 | (not (contains? locals op)) ;; Don't expand if locally bound |
305 | | - (not (#{'await 'let* 'loop* 'do 'fn 'fn* 'if 'quote 'try 'case* |
| 306 | + (not (#{'await 'let* 'loop* 'do 'fn* 'if 'quote 'try 'case* |
306 | 307 | 'sci.impl.async-await/promise} op))) |
307 | 308 | (macroexpand/macroexpand-1 ctx body) |
308 | 309 | body)] |
|
355 | 356 | (if (promise-form? transformed-test) |
356 | 357 | (let [test-binding (gensym "case_test__")] |
357 | 358 | (promise-then transformed-test |
358 | | - (list 'fn [test-binding] |
| 359 | + (list 'fn* [test-binding] |
359 | 360 | (apply list case*-sym test-binding all-transformed)))) |
360 | 361 | rebuilt-case)) |
361 | 362 |
|
|
377 | 378 | (if (promise-form? transformed-test) |
378 | 379 | (let [test-binding (gensym "test__")] |
379 | 380 | (promise-then transformed-test |
380 | | - (list 'fn [test-binding] |
| 381 | + (list 'fn* [test-binding] |
381 | 382 | (if transformed-else |
382 | 383 | (list 'if test-binding transformed-then transformed-else) |
383 | 384 | (list 'if test-binding transformed-then))))) |
384 | 385 | (if transformed-else |
385 | 386 | (list 'if transformed-test transformed-then transformed-else) |
386 | 387 | (list 'if transformed-test transformed-then)))) |
387 | 388 |
|
388 | | - ;; fn/fn* - don't recurse into (handled by analyzer) |
389 | | - (fn fn*) |
390 | | - body |
| 389 | + ;; fn* - don't recurse into (handled by analyzer) |
| 390 | + fn* body |
391 | 391 |
|
392 | 392 | ;; General expression - transform subforms |
393 | 393 | (transform-expr-with-await ctx locals body)) |
394 | | - ;; Not a seq - check for vector or map |
| 394 | + ;; Not a seq - check for vector, set, or map |
395 | 395 | (cond |
396 | 396 | ;; Vector literal - transform elements |
397 | 397 | (vector? body) |
398 | 398 | (transform-coll-with-await ctx locals body vec) |
399 | 399 |
|
400 | | - ;; Map literal - transform values (keys and values as pairs) |
| 400 | + ;; Set literal - transform elements |
| 401 | + (set? body) |
| 402 | + (transform-coll-with-await ctx locals body set) |
| 403 | + |
| 404 | + ;; Map literal - transform keys and values as pairs |
401 | 405 | (map? body) |
402 | 406 | (transform-coll-with-await ctx locals |
403 | 407 | (mapcat identity body) ;; flatten to [k1 v1 k2 v2 ...] |
|
0 commit comments