|
31 | 31 | (defonce namespaces (atom '{cljs.core {:name cljs.core}
|
32 | 32 | cljs.user {:name cljs.user}}))
|
33 | 33 |
|
34 |
| -(defonce ns-first-segments (atom '#{"cljs" "clojure"})) |
35 |
| - |
36 | 34 | (defn reset-namespaces! []
|
37 | 35 | (reset! namespaces
|
38 | 36 | '{cljs.core {:name cljs.core}
|
|
360 | 358 | (when export-as {:export export-as})
|
361 | 359 | (when init-expr {:children [init-expr]})))))
|
362 | 360 |
|
363 |
| -(defn- analyze-fn-method [env locals meth gthis] |
364 |
| - (letfn [(uniqify [[p & r]] |
365 |
| - (when p |
366 |
| - (cons (if (some #{p} r) (gensym (str p)) p) |
367 |
| - (uniqify r)))) |
368 |
| - (prevent-ns-shadow [p] |
369 |
| - (if (@ns-first-segments (str p)) |
370 |
| - (symbol (str p "$")) |
371 |
| - p))] |
372 |
| - (let [params (first meth) |
373 |
| - variadic (boolean (some '#{&} params)) |
374 |
| - params (vec (uniqify (remove '#{&} params))) |
375 |
| - fixed-arity (count (if variadic (butlast params) params)) |
376 |
| - body (next meth) |
377 |
| - locals (reduce (fn [m name] |
378 |
| - (assoc m name {:name (prevent-ns-shadow name) |
379 |
| - :tag (-> name meta :tag)})) |
380 |
| - locals params) |
381 |
| - params (vec (map prevent-ns-shadow params)) |
382 |
| - recur-frame {:names params :flag (atom nil)} |
383 |
| - block (binding [*recur-frames* (cons recur-frame *recur-frames*)] |
384 |
| - (analyze-block (assoc env :context :return :locals locals) body))] |
385 |
| - (merge {:env env :variadic variadic :params params :max-fixed-arity fixed-arity |
386 |
| - :gthis gthis :recurs @(:flag recur-frame)} |
387 |
| - block)))) |
| 361 | +(defn- analyze-fn-method [env locals meth type] |
| 362 | + (let [param-names (first meth) |
| 363 | + variadic (boolean (some '#{&} param-names)) |
| 364 | + param-names (vec (remove '#{&} param-names)) |
| 365 | + body (next meth) |
| 366 | + [locals params] (reduce (fn [[locals params] name] |
| 367 | + (let [param {:name name |
| 368 | + :tag (-> name meta :tag) |
| 369 | + :shadow (locals name)}] |
| 370 | + [(assoc locals name param) (conj params param)])) |
| 371 | + [locals []] param-names) |
| 372 | + fixed-arity (count (if variadic (butlast params) params)) |
| 373 | + recur-frame {:params params :flag (atom nil)} |
| 374 | + block (binding [*recur-frames* (cons recur-frame *recur-frames*)] |
| 375 | + (analyze-block (assoc env :context :return :locals locals) body))] |
| 376 | + (merge {:env env :variadic variadic :params params :max-fixed-arity fixed-arity |
| 377 | + :type type :recurs @(:flag recur-frame)} |
| 378 | + block))) |
388 | 379 |
|
389 | 380 | (defmethod parse 'fn*
|
390 | 381 | [op env [_ & args :as form] name]
|
|
394 | 385 | ;;turn (fn [] ...) into (fn ([]...))
|
395 | 386 | meths (if (vector? (first meths)) (list meths) meths)
|
396 | 387 | locals (:locals env)
|
397 |
| - locals (if name (assoc locals name {:name name}) locals) |
| 388 | + locals (if name (assoc locals name {:name name :shadow (locals name)}) locals) |
| 389 | + type (-> form meta ::type) |
398 | 390 | fields (-> form meta ::fields)
|
399 | 391 | protocol-impl (-> form meta :protocol-impl)
|
400 | 392 | protocol-inline (-> form meta :protocol-inline)
|
401 |
| - gthis (and fields (gensym "this__")) |
402 | 393 | locals (reduce (fn [m fld]
|
403 | 394 | (assoc m fld
|
404 |
| - {:name (symbol (str gthis "." fld)) |
| 395 | + {:name fld |
405 | 396 | :field true
|
406 | 397 | :mutable (-> fld meta :mutable)
|
407 |
| - :tag (-> fld meta :tag)})) |
| 398 | + :tag (-> fld meta :tag) |
| 399 | + :shadow (m fld)})) |
408 | 400 | locals fields)
|
409 | 401 |
|
410 | 402 | menv (if (> (count meths) 1) (assoc env :context :expr) env)
|
411 | 403 | menv (merge menv
|
412 | 404 | {:protocol-impl protocol-impl
|
413 | 405 | :protocol-inline protocol-inline})
|
414 |
| - methods (map #(analyze-fn-method menv locals % gthis) meths) |
| 406 | + methods (map #(analyze-fn-method menv locals % type) meths) |
415 | 407 | max-fixed-arity (apply max (map :max-fixed-arity methods))
|
416 | 408 | variadic (boolean (some :variadic methods))
|
417 |
| - locals (if name (assoc locals name {:name name :fn-var true |
418 |
| - :variadic variadic |
419 |
| - :max-fixed-arity max-fixed-arity |
420 |
| - :method-params (map :params methods)})) |
| 409 | + locals (if name |
| 410 | + (update-in locals [name] assoc |
| 411 | + :fn-var true |
| 412 | + :variadic variadic |
| 413 | + :max-fixed-arity max-fixed-arity |
| 414 | + :method-params (map :params methods)) |
| 415 | + locals) |
421 | 416 | methods (if name
|
422 | 417 | ;; a second pass with knowledge of our function-ness/arity
|
423 | 418 | ;; lets us optimize self calls
|
424 |
| - (map #(analyze-fn-method menv locals % gthis) meths) |
| 419 | + (map #(analyze-fn-method menv locals % type) meths) |
425 | 420 | methods)]
|
426 | 421 | ;;todo - validate unique arities, at most one variadic, variadic takes max required args
|
427 | 422 | {:env env :op :fn :form form :name name :methods methods :variadic variadic
|
|
438 | 433 | (assert (and (vector? bindings) (even? (count bindings))) "bindings must be vector of even number of elements")
|
439 | 434 | (let [n->fexpr (into {} (map (juxt first second) (partition 2 bindings)))
|
440 | 435 | names (keys n->fexpr)
|
441 |
| - n->gsym (into {} (map (juxt identity #(gensym (str % "__"))) names)) |
442 |
| - gsym->n (into {} (map (juxt n->gsym identity) names)) |
443 | 436 | context (:context env)
|
444 |
| - bes (reduce (fn [bes n] |
445 |
| - (let [g (n->gsym n)] |
446 |
| - (conj bes {:name g |
447 |
| - :tag (-> n meta :tag) |
448 |
| - :local true}))) |
449 |
| - [] |
450 |
| - names) |
451 |
| - meth-env (reduce (fn [env be] |
452 |
| - (let [n (gsym->n (be :name))] |
453 |
| - (assoc-in env [:locals n] be))) |
454 |
| - (assoc env :context :expr) |
455 |
| - bes) |
456 |
| - [meth-env finits] |
457 |
| - (reduce (fn [[env finits] n] |
458 |
| - (let [finit (analyze meth-env (n->fexpr n)) |
459 |
| - be (-> (get-in env [:locals n]) |
460 |
| - (assoc :init finit))] |
| 437 | + [meth-env bes] |
| 438 | + (reduce (fn [[{:keys [locals] :as env} bes] n] |
| 439 | + (let [be {:name n |
| 440 | + :tag (-> n meta :tag) |
| 441 | + :local true |
| 442 | + :shadow (locals n)}] |
461 | 443 | [(assoc-in env [:locals n] be)
|
462 |
| - (conj finits finit)])) |
463 |
| - [meth-env []] |
464 |
| - names) |
| 444 | + (conj bes be)])) |
| 445 | + [env []] names) |
| 446 | + meth-env (assoc meth-env :context :expr) |
| 447 | + bes (vec (map (fn [{:keys [name shadow] :as be}] |
| 448 | + (let [env (assoc-in meth-env [:locals name] shadow)] |
| 449 | + (assoc be :init (analyze env (n->fexpr name))))) |
| 450 | + bes)) |
465 | 451 | {:keys [statements ret]}
|
466 |
| - (analyze-block (assoc meth-env :context (if (= :expr context) :return context)) exprs) |
467 |
| - bes (vec (map #(get-in meth-env [:locals %]) names))] |
| 452 | + (analyze-block (assoc meth-env :context (if (= :expr context) :return context)) exprs)] |
468 | 453 | {:env env :op :letfn :bindings bes :statements statements :ret ret :form form
|
469 | 454 | :children (into (vec (map :init bes))
|
470 | 455 | (conj (vec statements) ret))}))
|
|
487 | 472 | (do
|
488 | 473 | (assert (not (or (namespace name) (.contains (str name) "."))) (str "Invalid local name: " name))
|
489 | 474 | (let [init-expr (analyze env init)
|
490 |
| - be {:name (gensym (str name "__")) |
| 475 | + be {:name name |
491 | 476 | :init init-expr
|
492 | 477 | :tag (or (-> name meta :tag)
|
493 | 478 | (-> init-expr :tag)
|
494 | 479 | (-> init-expr :info :tag))
|
495 |
| - :local true} |
| 480 | + :local true |
| 481 | + :shadow (-> env :locals name)} |
496 | 482 | be (if (= (:op init-expr) :fn)
|
497 | 483 | (merge be
|
498 | 484 | {:fn-var true
|
|
504 | 490 | (assoc-in env [:locals name] be)
|
505 | 491 | (next bindings))))
|
506 | 492 | [bes env])))
|
507 |
| - recur-frame (when is-loop {:names (vec (map :name bes)) :flag (atom nil)}) |
| 493 | + recur-frame (when is-loop {:params bes :flag (atom nil)}) |
508 | 494 | {:keys [statements ret]}
|
509 | 495 | (binding [*recur-frames* (if recur-frame (cons recur-frame *recur-frames*) *recur-frames*)
|
510 | 496 | *loop-lets* (cond
|
511 | 497 | is-loop (or *loop-lets* ())
|
512 |
| - *loop-lets* (cons {:names (vec (map :name bes))} *loop-lets*))] |
| 498 | + *loop-lets* (cons {:params bes} *loop-lets*))] |
513 | 499 | (analyze-block (assoc env :context (if (= :expr context) :return context)) exprs))]
|
514 | 500 | {:env encl-env :op :let :loop is-loop
|
515 | 501 | :bindings bes :statements statements :ret ret :form form
|
|
530 | 516 | frame (first *recur-frames*)
|
531 | 517 | exprs (disallowing-recur (vec (map #(analyze (assoc env :context :expr) %) exprs)))]
|
532 | 518 | (assert frame "Can't recur here")
|
533 |
| - (assert (= (count exprs) (count (:names frame))) "recur argument count mismatch") |
| 519 | + (assert (= (count exprs) (count (:params frame))) "recur argument count mismatch") |
534 | 520 | (reset! (:flag frame) true)
|
535 | 521 | (assoc {:env env :op :recur :form form}
|
536 | 522 | :frame frame
|
|
682 | 668 | (load-core)
|
683 | 669 | (doseq [nsym (concat (vals requires-macros) (vals uses-macros))]
|
684 | 670 | (clojure.core/require nsym))
|
685 |
| - (swap! ns-first-segments conj (first (string/split (str name) #"\."))) |
686 | 671 | (swap! namespaces #(-> %
|
687 | 672 | (assoc-in [name :name] name)
|
688 | 673 | (assoc-in [name :excludes] excludes)
|
|
0 commit comments