aboutsummaryrefslogtreecommitdiff
path: root/src/lang/analyser.clj
diff options
context:
space:
mode:
authorEduardo Julian2015-01-02 01:36:06 -0400
committerEduardo Julian2015-01-02 01:36:06 -0400
commitf28db7decf3330379f3f4ab190a9bc01deb50b91 (patch)
tree8bb62dbe50a8751135f9d190a829ae3888365985 /src/lang/analyser.clj
parent6eebd55535254e82230ce0ad11f7eb8b7907a9ca (diff)
Pattern matching compiler now generates optimized code.
Diffstat (limited to 'src/lang/analyser.clj')
-rw-r--r--src/lang/analyser.clj299
1 files changed, 150 insertions, 149 deletions
diff --git a/src/lang/analyser.clj b/src/lang/analyser.clj
index 72ea43e69..f45f44138 100644
--- a/src/lang/analyser.clj
+++ b/src/lang/analyser.clj
@@ -117,22 +117,6 @@
=return)
)))
-(defn ^:private with-anon-locals [amount k]
- (fn [state]
- (let [env (-> state :env first)
- $scope (:id env)
- =locals (for [$local (take amount (iterate inc (:counter env)))]
- (annotated [::local $scope $local] [::&type/object "java.lang.Object" []]))
- =return ((k =locals) (update-in state [:env] #(cons (update-in (first %) [:counter] + amount) (rest %))))]
- (match =return
- [::&util/ok [?state ?value]]
- (do ;; (prn 'POST-WITH-LOCAL name (-> ?state :env first))
- [::&util/ok [(update-in ?state [:env] #(cons (update-in (first %) [:counter] - amount) (rest %)))
- ?value]])
-
- _
- =return))))
-
(defn ^:private with-locals [mappings monad]
(fn [state]
(let [=return (monad (update-in state [:env] #(cons (update-in (first %) [:mappings] merge mappings)
@@ -423,142 +407,159 @@
(exec [=exprs (map-m analyse-form* ?exprs)]
(return (annotated [::do =exprs] (-> =exprs last :type)))))
+(let [fold-branches (fn [struct entry]
+ (let [struct* (clojure.core.match/match (nth entry 0)
+ [::pm-text ?text]
+ (clojure.core.match/match (:type struct)
+ ::text-tests (update-in struct [:patterns ?text] (fn [bodies]
+ (if bodies
+ (conj bodies (nth entry 1))
+ #{(nth entry 1)})))
+ nil (-> struct
+ (assoc :type ::text-tests)
+ (assoc-in [:patterns ?text] #{(nth entry 1)}))
+ _ (assert false "Can't do match."))
+ [::pm-variant ?tag ?members]
+ (clojure.core.match/match (:type struct)
+ ::adt (update-in struct [:patterns]
+ (fn [branches]
+ (if-let [{:keys [arity cases]} (get branches ?tag)]
+ (if (= arity (count ?members))
+ (-> branches
+ (update-in [?tag :cases] conj {:case ?members
+ :body (nth entry 1)})
+ (update-in [?tag :branches] conj (nth entry 1)))
+ (assert false (str "Arity doesn't match. " (count ?members) "=/=" arity)))
+ (assoc branches ?tag {:arity (count ?members)
+ :cases [{:case ?members
+ :body (nth entry 1)}]
+ :branches #{(nth entry 1)}}))))
+ nil (-> struct
+ (assoc :type ::adt)
+ (assoc-in [:patterns ?tag] {:arity (count ?members)
+ :cases [{:case ?members
+ :body (nth entry 1)}]
+ :branches #{(nth entry 1)}}))
+ _ (assert false "Can't do match."))
+
+ [::pm-local ?local]
+ (update-in struct [:defaults] conj [::default ?local (nth entry 1)]))]
+ (update-in struct* [:branches] conj (nth entry 1))))
+ base-struct {:type nil
+ :patterns {}
+ :defaults []
+ :branches #{}}
+ generate-branches (fn generate-branches [data]
+ (let [branches* (reduce fold-branches base-struct data)]
+ ;; (prn 'generate-branches data)
+ ;; (prn 'branches* branches*)
+ ;; (.print System/out (prn-str 'branches* branches*))
+ ;; (.print System/out (prn-str '(:type branches*) (:type branches*)))
+ (clojure.core.match/match (:type branches*)
+ ::text-tests branches*
+ ::adt (do (assert (<= (count (:defaults branches*)) 1))
+ {:type ::adt*
+ :patterns (into {} (for [[?tag ?struct] (:patterns branches*)
+ ;; :let [_ (prn '(:patterns branches*) ?tag ?struct)]
+ ]
+ [?tag {:parts (let [grouped-parts (apply map list (for [{:keys [case body]} (:cases ?struct)]
+ (map #(vector % body) case)))]
+ (map generate-branches grouped-parts))
+ :branches (:branches ?struct)}]))
+ :default (-> branches* :defaults first)
+ :branches (:branches branches*)})
+ nil {:type ::defaults,
+ :stores (reduce (fn [total [_ ?store ?body]]
+ (update-in total [?store] (fn [mapping]
+ (if mapping
+ (conj mapping ?body)
+ #{?body}))))
+ {}
+ (:defaults branches*))
+ :branches (:branches branches*)})))
+ get-vars (fn get-vars [pattern]
+ (clojure.core.match/match pattern
+ [::&parser/ident ?name]
+ (list ?name)
+
+ [::&parser/variant ?tag ?members]
+ (mapcat get-vars ?members)
+
+ [::&parser/string ?text]
+ '()))
+ ->instructions (fn ->instructions [locals pattern]
+ (clojure.core.match/match pattern
+ [::&parser/variant ?tag ?members]
+ [::pm-variant ?tag (map (partial ->instructions locals) ?members)]
+
+ [::&parser/ident ?name]
+ [::pm-local (get locals ?name)]
+
+ [::&parser/string ?text]
+ [::pm-text ?text]
+ ))]
+ (defn ->decision-tree [$scope $base branches]
+ (let [;; Step 1: Get all vars
+ vars+body (for [branch branches]
+ (clojure.core.match/match branch
+ [::&parser/case-branch ?pattern ?body]
+ [(get-vars ?pattern) ?body]))
+ max-registers (reduce max 0 (map (comp count first) vars+body))
+ ;; Step 2: Analyse bodies
+ [_ branch-mappings branches*] (reduce (fn [[$link links branches*] branch]
+ (clojure.core.match/match branch
+ [::&parser/case-branch ?pattern ?body]
+ [(inc $link) (assoc links $link ?body) (conj branches* [::&parser/case-branch ?pattern $link])]))
+ [0 {} []]
+ branches)
+ ;; Step 4: Pattens -> Instructions
+ branches** (for [[branch branch-vars] (map vector branches* (map first vars+body))
+ :let [[_ locals] (reduce (fn [[$local =locals] $var]
+ [(inc $local) (assoc =locals $var [::local $scope $local])])
+ [$base {}] branch-vars)]]
+ (clojure.core.match/match branch
+ [::&parser/case-branch ?pattern ?body]
+ [(->instructions locals ?pattern) ?body]))
+ ;; _ (prn branches**)
+ ;; Step 5: Re-structure branching
+ ]
+ [max-registers branch-mappings (generate-branches branches**)])))
+
(defanalyser analyse-case
[::&parser/case ?variant ?branches]
- (exec [;; :let [_ (prn '?variant ?variant)]
- =variant (analyse-form* ?variant)
- ;; :let [_ (prn '=variant =variant)]
- ;; {:registers 3,
- ;; :patterns {"Cons" {:arity 2, :branches [{:test [:lang/case-try "Cons" [[:lang/case-sub-bind 1] [:lang/case-sub-bind 2]]], :link 1}]},
- ;; "Nil" {:arity 0, :branches [{:test [:lang/case-try "Nil" []], :link 0}]}},
- ;; :paths {:total 2,
- ;; :links {1 [:lang.parser/variant "Cons" ([:lang.parser/ident "x"] [:lang.parser/fn-call [:lang.parser/ident "++"] ([:lang.parser/ident "xs*"] [:lang.parser/ident "ys"])])],
- ;; 0 [:lang.parser/ident "ys"]}}}
- [$base =branches] (with-anon-locals 1
- (fn [=locals]
- ;; (prn 'analyse-case '=locals (map :form =locals))
- (exec [=branches (map-m (fn [?branch]
- ;; (prn '?branch ?branch)
- (match ?branch
- [::&parser/case-branch [::&parser/variant ?tag ?members] ?body]
- (let [num-members (count ?members)]
- (with-anon-locals num-members
- (fn [=locals]
- ;; (prn '?branch/=locals (map :form =locals))
- (exec [[inner-num locals+ members+] (reduce-m (fn member-fold [[?inner-num locals-map =members] [?local ?member]]
- (match ?member
- [::&parser/ident ?name]
- (return [?inner-num
- (assoc locals-map ?name ?local)
- (conj =members (:form ?local))])
-
- [::&parser/string ?text]
- (return [?inner-num
- locals-map
- (conj =members [::match-text ?text])])
-
- [::&parser/variant ?subtag ?submembers]
- (let [num-submembers (count ?submembers)]
- (with-anon-locals num-submembers
- (fn [=sublocals]
- (exec [[subinner-num sublocals+ submembers+] (reduce-m member-fold [0 {} []] (map vector =sublocals ?submembers))
- ;; :let [_ (prn 'subinner-num subinner-num 'sublocals+ sublocals+ 'submembers+ submembers+)]
- ]
- (return [(+ ?inner-num num-submembers subinner-num)
- (merge locals-map sublocals+)
- (conj =members [::subcase ?subtag submembers+])])))))
- ))
- [0 {} []]
- (map vector =locals ?members))
- ;; :let [_ (prn 'inner-num inner-num 'locals+ locals+ 'members+ members+)]
- ;; :let [_ (prn (first =members) ?body)]
- =body (with-locals locals+
- (analyse-form* ?body))
- ;; :let [_ (prn '?body ?body =body)]
- ]
- (return [(+ num-members inner-num) [::branch-adt ?tag members+ =body]])))))))
- ?branches)]
- (return [(first =locals) =branches]))))
- :let [total-registers (+ 1 (reduce max 0 (map first =branches)))
- ;; _ (prn '=branches total-registers (map second =branches))
- ;; _ (assert false)
- ]
- ;; ([::&parser/case-branch [::&parser/variant "Nil" ()]
- ;; [::&parser/ident "ys"]]
- ;; [::&parser/case-branch [::&parser/variant "Cons" ([::&parser/ident "x"] [::&parser/ident "xs*"])]
- ;; [::&parser/variant "Cons" ([::&parser/ident "x"] [::&parser/fn-call [::&parser/ident "++"] ([::&parser/ident "xs*"] [::&parser/ident "ys"])])]])
- ;; :let [_ (prn '?branches ?branches)
- ;; case-analysis (let [gen-impl (fn gen-impl [offset pattern]
- ;; (clojure.core.match/match pattern
- ;; [::&parser/ident _]
- ;; [1 [::case-bind -1 offset]]
-
- ;; [::&parser/variant ?tag ?members]
- ;; (let [regs+insns (mapv (fn [idx member]
- ;; (clojure.core.match/match member
- ;; [::&parser/ident _]
- ;; [1 [::case-sub-bind (+ offset (inc idx))]]))
- ;; (range (count ?members))
- ;; ?members)]
- ;; [(reduce + 1 (map first regs+insns)) [::case-try ?tag (mapv second regs+insns)]])
- ;; (reduce + (count ?members) (map gen-impl ?members))))]
- ;; (reduce (fn [accum branch]
- ;; (clojure.core.match/match branch
- ;; [::&parser/case-branch ?pattern ?body]
- ;; (clojure.core.match/match ?pattern
- ;; [::&parser/variant ?tag ?members]
- ;; (let [[extra-registers impl] (gen-impl 0 ?pattern)
- ;; _ (prn 'impl extra-registers impl)
- ;; $branch (get-in accum [:paths :total])]
- ;; (-> accum
- ;; (update-in [:patterns]
- ;; (fn [patterns]
- ;; (if (contains? patterns ?tag)
- ;; (if (= (get patterns [?tag :arity]) (count ?members))
- ;; (update-in patterns [?tag :branches] conj {:test impl
- ;; :link $branch})
- ;; (assert "Pattern arity doesn't match!"))
- ;; (assoc patterns ?tag {:arity (count ?members)
- ;; :branches [{:test impl
- ;; :link $branch}]}))))
- ;; (update-in [:paths]
- ;; (fn [paths]
- ;; (-> paths
- ;; (update-in [:total] inc)
- ;; (assoc-in [:links $branch] ?body))))
- ;; (update-in [:registers] + (dec extra-registers)))))
- ;; ))
- ;; {:registers 1
- ;; :patterns {}
- ;; :paths {:total 0
- ;; :links {}}}
- ;; ?branches))
- ;; _ (prn 'case-analysis case-analysis)
- ;; _ (assert false)]
- ;; =branches (map-m identity ;; (fn [branch]
- ;; ;; ;; (prn 'branch branch)
- ;; ;; (match branch
- ;; ;; [::&parser/case-branch [::&parser/variant ?tag ?parts] ?body]
- ;; ;; (exec [;; :let [_ (prn ?tag ?label '?body ?body)]
- ;; ;; ;; (reduce-m (fn [?part]
- ;; ;; ;; (match ?part
- ;; ;; ;; [::&parser/ident ?label]
- ;; ;; ;; (exec [idx next-local-idx
- ;; ;; ;; =body (with-local ?label [::&type/object "java.lang.Object" []]
- ;; ;; ;; (analyse-form* ?body))]
- ;; ;; ;; (return ...)))
- ;; ;; ;; )
- ;; ;; ;; ?parts)
- ;; ;; idx next-local-idx
- ;; ;; =body (with-local ?label [::&type/object "java.lang.Object" []]
- ;; ;; (analyse-form* ?body))
- ;; ;; ;; :let [_ (prn ?tag ?label '=body =body)]
- ;; ;; ]
- ;; ;; (return [?tag ?label idx =body]))))
- ;; ?branches)
- ;; :let [_ (prn '=branches =branches)]
+ (exec [=variant (analyse-form* ?variant)
+ ;; :let [_ (prn 'analyse-case '=variant =variant)]
+ $scope scope-id
+ ;; :let [_ (prn 'analyse-case '$scope $scope)]
+ $base next-local-idx
+ ;; :let [_ (prn 'analyse-case '$base $base)]
+ [registers mappings tree] (exec [=branches (map-m (fn [?branch]
+ (match ?branch
+ [::&parser/case-branch [::&parser/variant ?tag ?members] ?body]
+ (exec [[_ locals+] (reduce-m (fn member-fold [[$local locals-map] ?member]
+ (match ?member
+ [::&parser/ident ?name]
+ (return [(inc $local) (assoc locals-map ?name (annotated [::local $scope $local] [::&type/object "java.lang.Object" []]))])
+
+ [::&parser/variant ?subtag ?submembers]
+ (reduce-m member-fold [$local locals-map] ?submembers)
+
+ _
+ (return [$local locals-map])
+ ))
+ [$base {}]
+ ?members)
+ ;; :let [_ (prn 'analyse-case 'locals+ locals+)]
+ =body (with-locals locals+
+ (analyse-form* ?body))
+ ;; :let [_ (prn 'analyse-case '=body =body)]
+ ]
+ (return [::&parser/case-branch [::&parser/variant ?tag ?members] =body]))))
+ ?branches)]
+ (return (->decision-tree $scope $base =branches)))
+ ;; :let [_ (prn 'analyse-case '[registers mappings tree] [registers mappings tree])]
]
- (return (annotated [::case $base =variant total-registers (map second =branches)] ::&type/nothing))))
+ (return (annotated [::case (dec $base) =variant registers mappings tree] ::&type/nothing))))
(defanalyser analyse-let
[::&parser/let ?label ?value ?body]