(ns ^:typed.clojure com.tailrecursion.blacktide.compiler.passes.prepare
"Make function casts and resolved JVM argument conversions explicit before
ordering operands. A failing conversion must prevent subsequent evaluation."
(:require [com.tailrecursion.nanopass :as np]
[com.tailrecursion.nanopass.pipeline :as pipeline]
[com.tailrecursion.blacktide.compiler.languages :as l]
[com.tailrecursion.blacktide.compiler.jvm :as jvm]
[typed.clojure :as-alias t]))
(np/defpass conversion
{:from [l/Prepared Expr] :to [l/Prepared Expr] :args [(t/Option l/JVM-Conversion)] :body true}
[conversion expr]
(if conversion
(let [fact (jvm/fact (.isPrimitive ^Class (:type conversion)) {:hint nil :var-meta {}} (:type conversion))]
;; The consumer still sees Object, but evaluating an Object cast cannot
;; fail. Operand normalization supplies the required value snapshot.
(if (= Object (:type conversion)) (assoc expr :jvm fact)
(assoc expr :jvm fact :node {:op :convert :conversion conversion :value expr}))) expr))
(np/defpasses
(prepare-forms
{:from [l/Collections Exprs] :to [l/Prepared Exprs] :processors {Expr prepare}}
[forms])
(prepare-node
{:from [l/Collections Node] :to [l/Prepared Node]
:processors {Expr prepare Exprs prepare-forms Binding prepare-binding Raw clojure.core/identity Local clojure.core/identity
CollectionKind clojure.core/identity RecurTarget clojure.core/identity CaseSpec clojure.core/identity}}
[node]
:invoke {:op :invoke :function (conversion {:type clojure.lang.IFn :parameter? false} (prepare (:function node)))
:args (mapv prepare (:args node))}
:host
(let [plan (jvm/prepare-call (mapv #(:type (:jvm %)) (:args node)) (:operation node))]
{:op :host-call :operation (:operation plan)
:args (mapv (fn [how value] (conversion how (prepare value))) (:conversions plan) (:args node))}))
(prepare-binding
{:from [l/Collections Binding] :to [l/Prepared Binding]
:processors {Expr prepare Local clojure.core/identity}}
[binding])
(prepare
{:from [l/Collections Expr] :to [l/Prepared Expr] :body true}
[expr]
(assoc expr :node (prepare-node (:node expr)))))
(np/defpass stage
{:from [l/Collections Compilation] :to [l/Prepared Compilation] :body true}
[compilation]
(pipeline/map-value prepare compilation))