-
Notifications
You must be signed in to change notification settings - Fork 0
/
macros.cljc
137 lines (132 loc) · 6.57 KB
/
macros.cljc
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
(ns mayu.macros
(:require [wayra.core :as w
:refer [mdo defnm fnm <#>]]
[mayu.tags :as tags]
[mayu.dom :as dom])
#?(:cljs (:require-macros [mayu.macros :refer [ui defui]])))
(comment :special-cases
<[if bool
<[then ...]
<[else ...]]
<[case x
<[1 <[]]
]
)
#?(:clj
(defmacro ui [& body]
(let [mk-args
(fn [els]
(let [[f & args] els]
(condp = f
;; TODO ensure valid syntax and error message if not
'if `(if ~(nth args 0)
(dom/step ::if-then (ui ~@(drop 1 (nth args 2))))
(dom/step ::if-else (ui ~@(drop 1 (nth args 4)))))
'when `(if ~(nth args 0)
(dom/step ::when (ui ~@(drop 1 args)))
(w/pure nil))
'when-not `(if ~(nth args 0)
(w/pure nil)
(dom/step ::when-not (ui ~@(drop 1 args))))
'case `(case ~(nth args 0)
~@(mapcat (fn [clause id]
(let [matcher (nth clause 0)
else? (= :else matcher)
body
`(dom/step ~(str "case." id)
(ui ~@(drop 1 clause)))]
(if else? [body] [matcher body])))
(filter vector? (drop 1 args))
(range)))
'condp `(condp ~(nth args 0) ~(nth args 1)
~@(mapcat (fn [clause id]
(let [matcher (nth clause 0)
else? (= :else matcher)
body
`(dom/step ~(str "condp." id)
(ui ~@(drop 1 clause)))]
(if else? [body] [matcher body])))
(filter vector? (drop 2 args))
(range)))
'cond `(cond
~@(mapcat (fn [clause id]
(let [matcher (nth clause 0)
body
`(dom/step ~(str "cond." id)
(ui ~@(drop 1 clause)))]
[matcher body]))
(filter vector? args)
(range)))
'for `(w/mapm (fn ~(nth args 2)
(ui ~@(drop 4 args)))
~(nth args 0))
'apply `(<#> (ui ~@(drop 1 args))
~(nth args 0))
'ssr-await `(dom/ssr-await ~(nth args 0)
~(nth args 1)
(ui ~@(drop 1 (nth args 3)))
(ui ~@(drop 1 (nth args 5))))
'multi (let [[pre _ multis] (partition-by #(= %1 '$=) args)]
(concat pre [(->> multis
(filter vector?)
(reduce (fn [agg [id & body]]
(assoc agg id
`(ui ~@body)))
{}))]))
(let [f (cond
(get tags/tag-map (name f))
`(partial mayu.dom/create-element ~(name f))
(get tags/tag_-map (name f))
`(partial mayu.dom/create-element_
~(subs (name f) 0 (dec (count (name f)))))
:else f)
els (concat [f] args)
split (partition-by #(or (= '$ %1)
(= '= %1)
(= '$= %1))
els)
scount (count split)]
(cond
(= 3 scount) (concat (nth split 0)
[`(ui ~@(nth split 2))])
(= 5 scount) (concat (nth split 0)
[`(fn ~(first (nth split 2))
(ui ~@(nth split 4)))])
:else els)))))]
`(mdo
~@(mapcat (fn [pthd psnd prev curr scnd thrd frth]
(cond
(and (= '< curr)
(vector? scnd)) []
(and (= '> curr)
(or (and (vector? prev)
(= '< psnd))
(and (vector? psnd)
(= '< pthd)))) []
(and (vector? prev)
(= '> scnd)
(= '< psnd)) []
(and (vector? curr)
(= '< prev)
(= '> thrd)) [scnd '<- `(~@(mk-args curr))]
(and (vector? curr)
(= '< prev)) [`(~@(mk-args curr))]
(or (= '> curr)
(= '< curr))
(throw (Exception.
(str "\"<\" and \">\" are assumed to be the "
"opening and closing of MDOM tags within "
"Mayu's UI macros. If you need to you can "
"use `mayu.util/lt` and `mayu.util/gt` "
"instead.")))
:else [curr]))
(concat [nil nil nil] body)
(concat [nil nil] body)
(concat [nil] body)
body
(concat (drop 1 body) [nil])
(concat (drop 2 body) [nil nil])
(concat (drop 3 body) [nil nil nil]))))))
#?(:clj
(defmacro defui [label args & body]
`(defn ~label ~args (dom/step ~(str label) (ui ~@body)))))