-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathmacros.jisp
More file actions
179 lines (144 loc) · 5.07 KB
/
Copy pathmacros.jisp
File metadata and controls
179 lines (144 loc) · 5.07 KB
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
; Built-in Macros Module
; Default macros to add:
; (test x (case func0 body) (case func1 body)) -> applies func in each case,
; expands to series of elifs; tests for equality against literals and for type against undefined.
; ...
; For embedding purposes, macros should not enclose any objects.
; They must be fully self-sufficient when printed with .toString.
; Meaning, all utilities in this file must be macros themselves, and nothing must be imported.
; A possible exception is the macros that can't be referenced by name (like ?!).
(= utils (require "./utils"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Utilities ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(mac macCheckVar exp
; a very approximate check if exp is an identifier
(if (and (isa exp "string")
(/^[$#_A-Za-z]{1}$|^[$#_A-Za-z]+[$_\w]*(?:[$_\w](?!\.))+$/.test exp))
true
(throw Error (+ "expecting valid identifier, got " exp))))
(mac macOneArg name rest
`(if (or (?! ,name) (> (get ,rest "length") 0))
(throw (Error (+ "expecting one argument, got: " ,name ", " ,rest)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Definitions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; `:` hash table macro
(mac macHash ...args
(if (is args.length 1)
; runtime hash
`(do (= #_res (:)
#_ref ,(car args))
(while (> #_ref.length 0)
(= #_res[(#_ref.shift)] (#_ref.shift)))
#_res)
; compile-time hash
(do (= buffer (:))
(while (> args.length 0)
(= buffer[(args.shift)] (args.shift)))
buffer)))
(= exports[":"] macHash)
; `::` concat hash table macro
(mac macConcatHash ...args
`(: (concat ,...(for arg args `(spread ,arg)))))
(= exports["::"] macConcatHash)
; `prn`: short alias for console.log
(mac macPrn ...x
`(console.log ,...x))
(= exports.prn macPrn)
; `car`: x[0]
; `head`: x[0]
(mac macCar x ...other (do
(macOneArg x other)
`(get ,x 0)))
(= exports.car macCar)
(= exports.head macCar)
; `cdr`: x.slice(1)
; `tail`: x.slice(1)
(mac macCdr x ...other (do
(macOneArg x other)
`((get ,x "slice") 1)))
(= exports.cdr macCdr)
(= exports.tail macCdr)
; `init`: x.slice(0, -1)
(mac macInit x ...other (do
(macOneArg x other)
`((get ,x "slice") 0 -1)))
(= exports.init macInit)
; `last`: x.slice(-1)[0]
(mac macLast x ...other (do
(macOneArg x other)
`(get ((get ,x "slice") -1) 0)))
(= exports.last macLast)
; `let`: self-executing lambda with auto-passed arguments
(mac macLet ...args body (do
(if (isnt (% args.length 2) 0)
(throw Error (+ "expecting an even number of arguments, got " args.length)))
(if (?! body) (= body `()))
(= names `()
callArgs `())
(while (> args.length 0)
(do (= name (args.shift))
(if (macCheckVar name)
(names.push name))
(callArgs.push (args.shift))))
`((fn ,...names ,body) ,...callArgs)))
(= exports.let macLet)
; helper for `?`
; takes a form and makes an array of property references, starting with base object
; with existence check wrapped around each
(def compartmentaliseExist form
(if (and (utils.isList form) (is (car form) "get"))
(list ...(compartmentaliseExist form[1]) `("isnta" form "'undefined'"))
(elif (and (isa form "string") (utils.isIdentifier form) (not (utils.isSpecialValueStr form)))
(for val i (= split (utils.splitName form))
`("isnta" ,(do (split.slice 0 (+ i 1)) (.join "")) "'undefined'")))
`(("isnta" form "'undefined'"))))
; `?`: existence check
; (not (isa x "undefined"))
; (or (? x) (? y) ...)
(mac macExist ...values (do
(= elements (for value values (do
(= comp (compartmentaliseExist value))
(if (> comp.length 1)
`(and ,...comp)
(car comp)))))
(if (> elements.length 1)
`(or ,...elements)
(car elements))))
(= exports["?"] macExist)
; helper for `?!`
; takes a form and makes an array of property references, starting with base object
; with inexistence check wrapped around each
(def compartmentaliseNotExist form
(if (and (utils.isList form) (is (car form) "get"))
(list ...(compartmentaliseNotExist form[1]) `("isa" form "'undefined'"))
(elif (and (isa form "string") (utils.isIdentifier form) (not (utils.isSpecialValueStr form)))
(for val i (= split (utils.splitName form))
`("isa" ,(do (split.slice 0 (+ i 1)) (.join "")) "'undefined'")))
`(("isa" form "'undefined'"))))
; `?!`: inexistence check
; (isa x "undefined")
; (or (?! x) (?! y) ...)
(mac macNotExist ...values (do
(= elements (for value values (do
(= comp (compartmentaliseNotExist value))
(if (> comp.length 1)
`(or ,...comp)
(car comp)))))
(if (> elements.length 1)
`(and ,...elements)
(car elements))))
(= exports["?!"] macNotExist)
; `isa`: (is (typeof x) y)
(mac macIsA obj ...types
`(is (typeof ,obj) ,...types))
(= exports.isa macIsA)
; `isnta`: (isnt (typeof x) y)
(mac macIsNa obj ...types
`(isnt (typeof ,obj) ,...types))
(= exports.isnta macIsNa)
; `any`: picks first existing value
(mac macAny ...values (do
(= elements (for value values
`(and (? ,value) ,value)))
(if (> elements.length 1)
`(or ,...elements)
(car elements))))
(= exports.any macAny)