-
Notifications
You must be signed in to change notification settings - Fork 10
/
mux.clj
71 lines (63 loc) · 2.22 KB
/
mux.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
(ns piplin.mux
(:require [clojure.core :as clj])
(:refer-clojure :exclude [cond condp cast])
(:use [piplin types protocols])
(:use [slingshot.slingshot]))
(defn mux2-impl
[sel v1 v2]
(when-not (clj/= (typeof v1) (typeof v2))
(throw+ (error v1 "and" v2 "are different types" (typeof v1) (typeof v2))))
(let [sel (cast (anontype :boolean) sel)]
(if (pipinst? sel)
(if sel v1 v2)
(->
(mkast (typeof v1) :mux2 [sel v1 v2] mux2-impl)
(assoc-dist-fn
#(mux2-impl sel (cast % v1) (cast % v2)))))))
(defn mux2-helper
[sel v1-thunk v2-thunk]
(let [v1 (v1-thunk)
v2 (v2-thunk)]
(mux2-impl sel v1 v2)))
(defmacro mux2
[sel v1 v2]
`(mux2-helper ~sel (fn [] ~v1) (fn [] ~v2)))
(defn cond-helper [predicates thunks]
(if (some #(instance? piplin.types.ASTNode %) predicates)
(let [last-pred (last predicates)
predicates (butlast predicates)
mux-tree (->> thunks
(interleave predicates)
(partition 2)
reverse
(reduce (fn [prev [p t]]
(fn [] (mux2-helper p t prev)))
(last thunks)))]
(if (clj/= last-pred :else)
(mux-tree)
(throw+ (error "Must include :else in simulated cond"))))
(let [thunk (->> thunks
(interleave predicates)
(partition 2)
(keep (fn [[p t]] (if p t nil)))
first)]
(if (nil? thunk)
nil
(thunk)))))
(defmacro cond [& more]
(when-not (even? (count more))
(throw (RuntimeException. "cond takes an even number of clauses")))
(let [bodies (->> more rest (take-nth 2))
thunks (map (fn [body]
`(fn [] ~body))
bodies)
predicates (take-nth 2 more)]
`(cond-helper [~@predicates] [~@thunks])))
(defmacro condp [pred expr & clauses]
(let [pairs (partition 2 clauses)
else (if (even? (count clauses)) nil (last clauses))
body (mapcat (fn [[test body]]
`((~pred ~test ~expr) ~body))
pairs)
body (if (nil? else) body (concat body [:else else]))]
`(cond ~@body)))