forked from carp-lang/Carp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Macros.carp
292 lines (238 loc) · 8.8 KB
/
Macros.carp
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
;; Defining the meta data macros early so that they can be used by all the other code.
(meta-set! doc "doc" "Set documentation for a binding.")
(defmacro doc [name string]
(list 'meta-set! name "doc" string))
(doc print-doc "Print the documentation for a binding.")
(defmacro print-doc [name]
(list 'macro-log (list 'meta name "doc")))
(doc sig "Annotate a binding with the desired signature.")
(defmacro sig [name signature]
(list 'meta-set! name "sig" signature))
(doc print-sig "Print the annotated signature for a binding.")
(defmacro print-sig [name]
(list 'macro-log (list 'meta name "sig")))
(doc hide "Mark a binding as hidden, this will make it not print with the 'info' command.")
(defmacro hidden [name]
(list 'meta-set! name "hidden" true))
(doc private "Mark a binding as private, this will make it inaccessible from other modules.")
(defmacro private [name]
(list 'meta-set! name "private" true))
(doc private? "Is this binding private?")
(defmacro private? [name]
(list 'not (list '= () (list 'meta name "private")))) ;; TODO: This is buggy, will report true when meta is set to 'false'!
(doc hidden? "Is this binding hidden?")
(defmacro hidden? [name]
(list 'not (list '= () (list 'meta name "hidden")))) ;; TODO: This is buggy, will report true when meta is set to 'false'!
(defmodule Dynamic
(defdynamic caar [pair] (car (car pair)))
(defdynamic cadr [pair] (car (cdr pair)))
(defdynamic cdar [pair] (cdr (car pair)))
(defdynamic cddr [pair] (cdr (cdr pair)))
(defdynamic caaar [pair] (car (car (car pair))))
(defdynamic caadr [pair] (car (car (cdr pair))))
(defdynamic cadar [pair] (car (cdr (car pair))))
(defdynamic cdaar [pair] (cdr (car (car pair))))
(defdynamic caddr [pair] (car (cdr (cdr pair))))
(defdynamic cdadr [pair] (cdr (car (cdr pair))))
(defdynamic cddar [pair] (cdr (cdr (car pair))))
(defdynamic cdddr [pair] (cdr (cdr (cdr pair))))
(defdynamic caaaar [pair] (car (car (car (car pair)))))
(defdynamic caaadr [pair] (car (car (car (cdr pair)))))
(defdynamic caadar [pair] (car (car (cdr (car pair)))))
(defdynamic caaddr [pair] (car (car (cdr (cdr pair)))))
(defdynamic cadaar [pair] (car (cdr (car (car pair)))))
(defdynamic cadadr [pair] (car (cdr (car (cdr pair)))))
(defdynamic caddar [pair] (car (cdr (cdr (car pair)))))
(defdynamic cadddr [pair] (car (cdr (cdr (cdr pair)))))
(defdynamic cdaaar [pair] (cdr (car (car (car pair)))))
(defdynamic cdaadr [pair] (cdr (car (car (cdr pair)))))
(defdynamic cdadar [pair] (cdr (car (cdr (car pair)))))
(defdynamic cdaddr [pair] (cdr (car (cdr (cdr pair)))))
(defdynamic cddaar [pair] (cdr (cdr (car (car pair)))))
(defdynamic cddadr [pair] (cdr (cdr (car (cdr pair)))))
(defdynamic cdddar [pair] (cdr (cdr (cdr (car pair)))))
(defdynamic cddddr [pair] (cdr (cdr (cdr (cdr pair)))))
(defdynamic eval-internal [form]
(list 'do
(list 'defn 'main [] (list 'IO.println* form))
(list 'build)
(list 'run)))
(defmacro eval [form]
(eval-internal form))
(defmacro e [form]
(eval-internal form))
)
(defdynamic cond-internal [xs]
(if (= (length xs) 0)
(list)
(if (= (length xs) 2)
(macro-error "cond has even number of branches; add an else branch")
(if (= (length xs) 1)
(car xs)
(list
'if
(car xs)
(cadr xs)
(cond-internal (cddr xs)))))))
(defmacro cond [:rest xs]
(cond-internal xs))
(defmacro for [settings :rest body] ;; settings = variable, from, to, <step>
(if (> (length body) 1)
(macro-error "Warning: the body of the 'for' loop can only contain one expression")
(list
'let
(array (car settings) (cadr settings))
(list
'while
(list 'Int.< (car settings) (caddr settings))
(list 'do
(if (= (length body) 0)
()
(if (list? body)
(car body)
body))
(list
'set! (car settings)
(list 'Int.+
(car settings)
(if (= 4 (length settings)) ;; optional arg for step
(cadddr settings)
1))))))))
(defmacro refstr [x]
(list 'ref
(list 'str x)))
;; Old foreach, what's a better name for this? (it's just 'map' with side effects)
;; (defmacro foreach [f xs]
;; (list 'for ['i 0 (list 'Array.length (list 'ref xs))]
;; (list f (list 'Array.nth (list 'ref xs) 'i))))
(defdynamic foreach-internal [var xs expr]
(list 'let ['xs xs
'len (list 'Array.length 'xs)]
(list 'for ['i 0 'len]
(list 'let [var (list 'Array.nth 'xs 'i)]
expr))))
(defmacro foreach [binding expr]
(if (array? binding)
(foreach-internal (car binding) (cadr binding) expr)
(macro-error "Binding has to be an array.")))
(defdynamic thread-first-internal [xs]
(if (= (length xs) 2)
(if (list? (last xs))
(cons (caadr xs)
(cons (car xs)
(cdadr xs)))
(list (cadr xs) (car xs)))
(if (list? (last xs))
(append
(list
(car (last xs))
(thread-first-internal (all-but-last xs)))
(cdr (last xs)))
(list (last xs) (thread-first-internal (all-but-last xs))))))
(defdynamic thread-last-internal [xs]
(if (= (length xs) 2)
(if (list? (last xs))
(cons-last (car xs) (last xs))
(list (cadr xs) (car xs)))
(if (list? (last xs))
(cons-last (thread-last-internal (all-but-last xs)) (last xs))
(list (last xs) (thread-last-internal (all-but-last xs))))))
(defmacro => [:rest forms]
(thread-first-internal forms))
(defmacro ==> [:rest forms]
(thread-last-internal forms))
(defmacro swap! [x y]
(list 'let (array 'tmp y) (list 'do (list 'set! y x) (list 'set! x 'tmp))))
(defmacro update! [x f]
(list 'set! x (list f x)))
(defmacro mac-only [:rest forms]
(if (= "darwin" (os))
(cons (quote do) forms)
()))
(defmacro linux-only [:rest forms]
(if (= "linux" (os))
(cons (quote do) forms)
()))
(defmacro windows-only [:rest forms]
(if (= "windows" (os))
(cons (quote do) forms)
()))
(defmacro not-on-windows [:rest forms]
(if (not (= "windows" (os)))
(cons (quote do) forms)
()))
(defdynamic use-all-fn [names]
(if (= (length names) 0)
(macro-error "Trying to call use-all without arguments")
(if (= (length names) 1)
(list (list 'use (car names)))
(cons (list 'use (car names)) (use-all-fn (cdr names))))));(use-all (cdr names))))))
(defmacro use-all [:rest names]
(cons 'do (use-all-fn names)))
(defmacro load-and-use [name]
(list 'do
(list 'load (str name ".carp"))
(list 'use name)))
(defmacro when [condition form]
(list 'if condition form (list)))
(defmacro unless [condition form]
(list 'if condition (list) form))
(defmacro let-do [bindings :rest forms]
(list 'let bindings
(cons 'do forms)))
(defmacro defn-do [name arguments :rest body]
(list 'defn name arguments (cons 'do body)))
(defmacro comment [:rest forms]
())
(defmacro forever-do [:rest forms]
(list 'while true (cons 'do forms)))
(defdynamic case-internal [name xs]
(if (= (length xs) 0)
(list)
(if (= (length xs) 2)
(macro-error "case has even number of branches; add an else branch")
(if (= (length xs) 1)
(car xs)
(list 'if
(list '= name (car xs))
(cadr xs)
(case-internal name (cddr xs)))))))
(defmacro case [name :rest forms]
(case-internal name forms))
(defmacro and [x y]
(list 'if x y false))
(defmacro or [x y]
(list 'if x true y))
(defdynamic build-vararg [func forms]
(if (= (length forms) 0)
(macro-error "vararg macro needs at least one argument")
(if (= (length forms) 1)
(car forms)
(list func (car forms) (build-vararg func (cdr forms))))))
(defmacro and* [:rest forms]
(build-vararg 'and forms))
(defmacro or* [:rest forms]
(build-vararg 'or forms))
(defdynamic build-str* [forms]
(if (= (length forms) 0)
(list "")
(if (= (length forms) 1)
(list 'str (car forms))
(list 'StringCopy.append (list 'str (car forms)) (build-str* (cdr forms))))))
(defmacro str* [:rest forms]
(build-str* forms))
(defmacro println* [:rest forms]
(list 'IO.println (list 'ref (build-str* forms))))
(defmacro print* [:rest forms]
(list 'IO.print (list 'ref (build-str* forms))))
(defmacro ignore [form]
(list 'let (array '_ form) (list)))
;; Allows inclusion of C headers relative to the Carp file in which this macro is called.
(defmacro relative-include [file]
(list 'local-include
(list 'Dynamic.String.join [(list 'Dynamic.String.directory (list 'file))
"/"
file])))
(defmacro save-docs [:rest modules]
;; A trick to be able to send unquoted symbols to 'save-docs'
(list 'save-docs-internal (list 'quote modules)))