nydp 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitattributes +1 -0
- data/README.md +228 -14
- data/lib/lisp/bm.nydp +18 -0
- data/lib/lisp/boot.nydp +69 -10
- data/lib/lisp/tests/boot-tests.nydp +65 -1
- data/lib/lisp/tests/error-tests.nydp +22 -0
- data/lib/lisp/tests/foundation-test.nydp +14 -22
- data/lib/lisp/tests/parser-tests.nydp +55 -0
- data/lib/nydp.rb +22 -12
- data/lib/nydp/assignment.rb +3 -1
- data/lib/nydp/builtin.rb +2 -5
- data/lib/nydp/builtin/ensuring.rb +3 -0
- data/lib/nydp/builtin/eval.rb +5 -1
- data/lib/nydp/builtin/handle_error.rb +39 -0
- data/lib/nydp/builtin/parse_in_string.rb +11 -0
- data/lib/nydp/builtin/sqrt.rb +5 -0
- data/lib/nydp/context_symbol.rb +38 -6
- data/lib/nydp/core.rb +9 -6
- data/lib/nydp/error.rb +4 -0
- data/lib/nydp/function_invocation.rb +1 -1
- data/lib/nydp/lexical_context.rb +13 -3
- data/lib/nydp/parser.rb +19 -18
- data/lib/nydp/runner.rb +9 -4
- data/lib/nydp/string_atom.rb +6 -7
- data/lib/nydp/symbol_lookup.rb +2 -1
- data/lib/nydp/tokeniser.rb +7 -1
- data/lib/nydp/version.rb +1 -1
- data/lib/nydp/vm.rb +35 -12
- data/nydp.gemspec +2 -2
- data/spec/parser_spec.rb +10 -0
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1cb1c4582106367e04bc3ac5163db7401782331c
|
4
|
+
data.tar.gz: 3c8be4535a704cdbe02674796f4068d6f079880c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7523046a3da0fb43634736645674566d77c10a3178b911765d849503c9b66cdb32e9b17810365795bddc7f2bf5fe655d24c1e2f10b6253054987cdfdbe5a6a16
|
7
|
+
data.tar.gz: 82f1f13fb1e3badf6f80c8a9ca6077019b01c0f8e571c61b1e1ade4ba1c640c4c8945f9e3d77442d69e77382e5ecee60587d51b9010ff03ec10ee4bb422664c8
|
data/.gitattributes
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.nydp linguist-language=NYDP
|
data/README.md
CHANGED
@@ -1,35 +1,252 @@
|
|
1
|
-
#
|
1
|
+
# NYDP
|
2
|
+
|
3
|
+
NYDP is a new LISP dialect, much inspired by [Arc](http://arclanguage.org/), and implemented in Ruby.
|
2
4
|
|
3
5
|
NYDP is "Not Your Daddy's Parentheses", a reference to [Xkcd 297](http://xkcd.com/297/) (itself a reference
|
4
6
|
to Star Wars), as well as to the meme [Not Your Daddy's Q](http://tvtropes.org/pmwiki/pmwiki.php/Main/NotYourDaddysX), where Q is a modern,
|
5
7
|
improved Q unlike the Q your daddy used. "NYDP" also shamelessly piggypacks on the
|
6
8
|
catchiness and popularity of the [NYPD](https://en.wikipedia.org/wiki/NYPD_Blue) abbreviation ("New York Police Department",
|
7
|
-
for those who have no interest in popular US
|
9
|
+
for those who have no interest in popular US politics or TV).
|
10
|
+
|
11
|
+
We do not wish to suggest by "Not Your Daddy's Parentheses" that Common Lisp, Scheme, Racket, Arc, Clojure or your favourite other lisp are somehow old-fashioned, inferior, or in need of improvement in any way.
|
12
|
+
|
13
|
+
The goal of NYDP is to allow untrusted users run sandboxed server-side scripts. By default, NYDP provides no system access :
|
14
|
+
|
15
|
+
* no file functions
|
16
|
+
* no network functions
|
17
|
+
* no IO other than $stdin and $stdout
|
18
|
+
* no process functions
|
19
|
+
* no threading functions
|
20
|
+
* no ruby calls
|
21
|
+
|
22
|
+
[Peruse NYDP's features here](lib/lisp/tests) in the `tests` directory.
|
23
|
+
|
24
|
+
## Running
|
25
|
+
|
26
|
+
#### Get a REPL :
|
27
|
+
|
28
|
+
```Shell
|
29
|
+
$ bundle exec bin/nydp
|
30
|
+
welcome to nydp
|
31
|
+
^D to exit
|
32
|
+
nydp >
|
33
|
+
```
|
34
|
+
|
35
|
+
The REPL uses the readline library so you can use up- and down-arrows to navigate history.
|
36
|
+
|
37
|
+
#### Invoking from Ruby
|
38
|
+
|
39
|
+
Suppose you want to invoke the function named `question` with some arguments. Do this:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
ns = Nydp.build_nydp # keep this for later re-use, it's expensive to set up
|
8
43
|
|
9
|
-
|
10
|
-
the expression to compile as an argument. You can override 'pre-compile to transform the expression in any way you wish. By default,
|
11
|
-
nydp provides an implementation of 'pre-compile that performs macro-expansion.
|
44
|
+
answer = Nydp.apply_function ns, :question, :life, ("The Universe" and everything())
|
12
45
|
|
46
|
+
==> 42
|
13
47
|
```
|
48
|
+
|
49
|
+
`ns` is just a plain old ruby hash, mapping ruby symbols to nydp symbols for quick lookup at nydp compile-time. The nydp symbols maintain the values of global variables, including all builtin functions and any other functions defined using `def`.
|
50
|
+
|
51
|
+
You can maintain multiple `ns` instances without mutual interference. In other words, assigning global variables while one `ns` is in scope will not affect the values of variables in any other `ns` (unless you've specifically arranged it to be so by duplicating namespaces or some such sorcery).
|
52
|
+
|
53
|
+
|
54
|
+
## Different from Arc :
|
55
|
+
|
56
|
+
#### 1. Macro-expansion runs in lisp
|
57
|
+
|
58
|
+
After parsing its input, NYDP passes the result as an argument to the `pre-compile` function. This is where things get a little bit circular: initially, `pre-compile` is a builtin function that just returns its argument. `pre-compile` bootstraps itself into existence in [boot.nydp](lib/lisp/boot.nydp).
|
59
|
+
|
60
|
+
You can override `pre-compile` to transform the expression in any way you wish. By default, the `boot.nydp` implementation of `pre-compile` performs macro-expansion.
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
```lisp
|
14
65
|
(def pre-compile (expr)
|
15
66
|
(map pre-compile
|
16
67
|
(if (mac-names (car expr))
|
17
68
|
(pre-compile (mac-expand (car expr) (cdr expr)))
|
18
69
|
expr)))
|
70
|
+
|
71
|
+
(mac yoyo (thing) `(do-yoyo ,thing))
|
72
|
+
|
73
|
+
nydp > (pre-compile '(yoyo 42))
|
74
|
+
|
75
|
+
==> (do-yoyo 42)
|
76
|
+
```
|
77
|
+
|
78
|
+
|
79
|
+
#### 2. Special symbol syntax
|
80
|
+
|
81
|
+
The parser detects syntax embedded in smybol names and emits a form whose first element names the syntax used. Here's an example:
|
82
|
+
|
83
|
+
```lisp
|
84
|
+
|
85
|
+
nydp > (parse "x.y")
|
86
|
+
|
87
|
+
==> (dot-syntax x y)
|
88
|
+
|
89
|
+
nydp > (parse "$x x$ x$x $x$ $$")
|
90
|
+
|
91
|
+
==> (dollar-syntax || x) ; '|| is the empty symbol.
|
92
|
+
==> (dollar-syntax x ||)
|
93
|
+
==> (dollar-syntax x x)
|
94
|
+
==> (dollar-syntax || x ||)
|
95
|
+
==> (dollar-syntax || || ||)
|
96
|
+
|
97
|
+
nydp > (parse "!foo")
|
98
|
+
|
99
|
+
==> (bang-syntax || foo)
|
100
|
+
|
101
|
+
nydp > (parse "!x.$y")
|
102
|
+
|
103
|
+
==> (bang-syntax || (dot-syntax x (dollar-syntax || y)))
|
104
|
+
|
105
|
+
```
|
106
|
+
|
107
|
+
Nydp provides macros for some but not all possible special syntax
|
108
|
+
|
109
|
+
```lisp
|
110
|
+
nydp > (pre-compile 'x.y)
|
111
|
+
|
112
|
+
==> (hash-get x 'y) ; 'dot-syntax is a macro that expands to perform hash lookups
|
113
|
+
|
114
|
+
nydp > (pre-compile 'x.y.z)
|
115
|
+
|
116
|
+
==> (hash-get (hash-get x 'y) 'z)
|
117
|
+
|
118
|
+
|
119
|
+
nydp > (pre-compile '!eq?)
|
120
|
+
|
121
|
+
==> (fn args (no (apply eq? args)))
|
122
|
+
|
123
|
+
nydp > (pre-compile '(!eq? a b))
|
124
|
+
|
125
|
+
==> ((fn args (no (apply eq? args))) a b) ; equivalent to (no (eq? a b))
|
19
126
|
```
|
20
127
|
|
21
|
-
|
128
|
+
Look for `SYMBOL_OPERATORS` in [parser.rb](lib/nydp/parser.rb) to see which syntax is recognised and in which order. The order of these definitions defines special-syntax-operator precedence.
|
129
|
+
|
130
|
+
#### 3. Special list syntax
|
131
|
+
|
132
|
+
The parser detects alternative list delimiters
|
133
|
+
|
134
|
+
```lisp
|
135
|
+
nydp > (parse "{ a 1 b 2 }")
|
136
|
+
|
137
|
+
==> (brace-list a 1 b 2)
|
22
138
|
|
23
139
|
```
|
24
|
-
==> (comment "blah blah")
|
25
140
|
|
26
|
-
|
141
|
+
`brace-list` is a macro that expands to create a hash literal. It assumes every (2n+1)th items are literal symbol keys, and every (2(n+1))th item is the corresponding value which is evaluated at run time.
|
142
|
+
|
143
|
+
```lisp
|
144
|
+
|
145
|
+
nydp > { a 1 b (author-name) }
|
146
|
+
|
147
|
+
==> {a=>1, b=>"conanite"}
|
148
|
+
|
149
|
+
```
|
150
|
+
|
151
|
+
|
152
|
+
|
153
|
+
#### 4. Sensible, nestable string interpolation
|
154
|
+
|
155
|
+
The parser detects lisp code inside strings. When this happens, instead of emitting a string literal, the parser emits a form whose car is the symbol `string-pieces`.
|
156
|
+
|
157
|
+
```lisp
|
158
|
+
nydp > (parse "\"foo\"")
|
159
|
+
|
160
|
+
==> "foo"
|
161
|
+
|
162
|
+
nydp > (let bar "Mister Nice Guy" "hello, ~bar")
|
163
|
+
|
164
|
+
==> hello, Mister Nice Guy
|
165
|
+
|
166
|
+
; this is a more tricky example because we need to make a string with an interpolation token in it
|
167
|
+
|
168
|
+
nydp > (let s (joinstr "" "\"hello, " '~ "world\"") (parse s))
|
169
|
+
|
170
|
+
==> (string-pieces "hello, " world "") ; "hello, ", followed by the interpolation 'world, followed by the empty string after 'world
|
171
|
+
|
172
|
+
nydp > (def also (str) "\nAND ALSO, ~str")
|
173
|
+
nydp > (with (a 1 b 2)
|
174
|
+
(p "Consider ~a : the first thing,
|
175
|
+
~(also "Consider ~b : the second thing,
|
176
|
+
~(also "Consider ~(+ a b), the third (and final) thing")")"))
|
177
|
+
|
178
|
+
==> Consider 1 : the first thing,
|
179
|
+
==> AND ALSO, Consider 2 : the second thing,
|
180
|
+
==> AND ALSO, Consider 3, the third (and final) thing
|
27
181
|
```
|
28
182
|
|
29
|
-
|
30
|
-
|
31
|
-
|
183
|
+
By default, `string-pieces` is a function that just concatenates the string value of its arguments. You can redefine it as a macro to perform more fun stuff, or you can detect it within another macro to do extra-special stuff with it.
|
184
|
+
|
185
|
+
|
186
|
+
#### 5. No continuations.
|
187
|
+
|
188
|
+
Sorry. While technically possible ... why bother?
|
189
|
+
|
190
|
+
#### 6. No argument destructuring
|
32
191
|
|
192
|
+
However, this doesn't need to be built-in, it can be done with macros alone.
|
193
|
+
|
194
|
+
|
195
|
+
## Besides that, what can Nydp do?
|
196
|
+
|
197
|
+
#### 1. Functions and variables exist in the same namespace.
|
198
|
+
#### 2. Macros are maintained in a hash called 'macs in the main namespace.
|
199
|
+
#### 3. General [tail call elimination](https://en.wikipedia.org/wiki/Tail_call) allowing recursion without stack overflow in some cases.
|
200
|
+
#### 4. 'if like Arc:
|
201
|
+
|
202
|
+
```lisp
|
203
|
+
(if a b c d e) ; equivalent to ruby :
|
204
|
+
```
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
if a
|
208
|
+
b
|
209
|
+
elsif c
|
210
|
+
d
|
211
|
+
else e
|
212
|
+
```
|
213
|
+
|
214
|
+
#### 5. Lexically scoped, but with macros to define dynamic variables backed by ruby threadlocals.
|
215
|
+
|
216
|
+
```lisp
|
217
|
+
nydp> (dynamic foo)
|
218
|
+
|
219
|
+
nydp> (def do-something () (+ (foo) 1))
|
220
|
+
|
221
|
+
nydp> (w/foo 99 (do-something))
|
222
|
+
|
223
|
+
==> 100
|
224
|
+
|
225
|
+
nydp> (foo)
|
226
|
+
|
227
|
+
==> nil
|
228
|
+
```
|
229
|
+
|
230
|
+
#### 6. Basic error handling
|
231
|
+
|
232
|
+
```lisp
|
233
|
+
nydp> (on-err (p "error")
|
234
|
+
(ensure (p "make sure this happens")
|
235
|
+
(/ 1 0)))
|
236
|
+
|
237
|
+
make sure this happens
|
238
|
+
error
|
239
|
+
```
|
240
|
+
|
241
|
+
#### 7 Intercept comments
|
242
|
+
|
243
|
+
```lisp
|
244
|
+
nydp > (parse "; blah blah")
|
245
|
+
|
246
|
+
==> (comment "blah blah")
|
247
|
+
|
248
|
+
By default, `comment` is a macro that expands to nil. If you have a better idea, go for it. (doc-comments for example)
|
249
|
+
```
|
33
250
|
|
34
251
|
## Installation
|
35
252
|
|
@@ -45,9 +262,6 @@ Or install it yourself as:
|
|
45
262
|
|
46
263
|
$ gem install nydp
|
47
264
|
|
48
|
-
## Usage
|
49
|
-
|
50
|
-
TODO: Write usage instructions here
|
51
265
|
|
52
266
|
## Contributing
|
53
267
|
|
data/lib/lisp/bm.nydp
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
(def bm-pythag ()
|
2
|
+
(for i 1 100
|
3
|
+
(for j 1 100
|
4
|
+
(sqrt (+ (* i i) (* j j))))))
|
5
|
+
|
6
|
+
(def bmf (f n)
|
7
|
+
(for b 1 n (f)))
|
8
|
+
|
9
|
+
(def bm (f n)
|
10
|
+
(let time (millisecs)
|
11
|
+
(bmf f n)
|
12
|
+
(let elapsed (- (millisecs) time)
|
13
|
+
(p "took: ~elapsed ms")
|
14
|
+
(p "~n iterations, ~(/ elapsed n) ms per iteration")))
|
15
|
+
nil)
|
16
|
+
|
17
|
+
(def rbs ()
|
18
|
+
(bm bm-pythag 20))
|
data/lib/lisp/boot.nydp
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
; -*- lisp -*-
|
2
2
|
|
3
|
+
;;
|
4
|
+
;; Acknowledgements to Paul Graham. Some nydp features defined in this file (including,
|
5
|
+
;; but not limited to, 'do, 'rfn, 'loop, 'for) are stolen directly from arc.arc
|
6
|
+
;;
|
7
|
+
|
3
8
|
(assign last-cons (fn (xs)
|
4
9
|
(cond (pair? (cdr xs))
|
5
10
|
(last-cons (cdr xs))
|
6
11
|
xs)))
|
7
12
|
|
8
13
|
|
9
|
-
(assign append-list
|
14
|
+
(assign append-list (fn (list-1 list-2)
|
10
15
|
(cdr-set (last-cons list-1) list-2)
|
11
16
|
list-1))
|
12
17
|
|
@@ -15,7 +20,7 @@
|
|
15
20
|
(assign caar (fn (arg) (car (car arg))))
|
16
21
|
(assign cadr (fn (arg) (car (cdr arg))))
|
17
22
|
(assign cddr (fn (arg) (cdr (cdr arg))))
|
18
|
-
(assign no (fn (arg) (
|
23
|
+
(assign no (fn (arg) (cond arg nil t)))
|
19
24
|
(assign just (fn (arg) arg))
|
20
25
|
(assign pargs (fn args (apply p args) (last args)))
|
21
26
|
|
@@ -145,6 +150,14 @@
|
|
145
150
|
`(cond ,(car args) ,(cadr args)))
|
146
151
|
(car args))))
|
147
152
|
|
153
|
+
(mac bang-syntax (pfx . rest)
|
154
|
+
(if (no (eq? pfx '||))
|
155
|
+
(error "Irregular ! syntax: got prefix ~(inspect pfx) in ~(joinstr "!" (cons pfx rest))"))
|
156
|
+
(if (cdr rest)
|
157
|
+
(error "Irregular ! syntax: got suffix ~(inspect (cdr rest)) in ~(joinstr "!" (cons pfx rest))"))
|
158
|
+
`(fn args
|
159
|
+
(no (apply ,(car rest) args))))
|
160
|
+
|
148
161
|
(mac and args
|
149
162
|
(if args
|
150
163
|
(if (cdr args)
|
@@ -215,13 +228,12 @@
|
|
215
228
|
(flattenize things))
|
216
229
|
acc))
|
217
230
|
|
218
|
-
(def joinstr (txt things)
|
219
|
-
(
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
(map to-string (cdr things))))))
|
231
|
+
(def joinstr (txt . things)
|
232
|
+
(let joinables (flatten things)
|
233
|
+
(apply +
|
234
|
+
(to-string (car joinables))
|
235
|
+
(flatten (zip (map (fn (_) txt) (cdr joinables))
|
236
|
+
(map to-string (cdr joinables)))))))
|
225
237
|
|
226
238
|
(let uniq-counter 0
|
227
239
|
(def uniq (prefix)
|
@@ -263,6 +275,7 @@
|
|
263
275
|
(iso (cdr x) (cdr y)))))
|
264
276
|
|
265
277
|
(def isa (type obj) (eq? (type-of obj) type))
|
278
|
+
(def sym? (arg) (isa 'symbol arg))
|
266
279
|
(mac just (arg) arg)
|
267
280
|
(def quotify (arg) `(quote ,arg))
|
268
281
|
|
@@ -317,5 +330,51 @@
|
|
317
330
|
(mac = (name value)
|
318
331
|
(if (isa 'symbol name)
|
319
332
|
`(assign ,name ,value)
|
320
|
-
|
333
|
+
(caris 'dot-syntax name)
|
321
334
|
(dot-syntax-assignment (cdr name) value)))
|
335
|
+
|
336
|
+
(def brace-list-hash-key (k)
|
337
|
+
(if (isa 'symbol k) `(quote ,k)
|
338
|
+
(caris 'unquote k) (cadr k)
|
339
|
+
k))
|
340
|
+
|
341
|
+
(def brace-list-build-hash (args)
|
342
|
+
(w/uniq hash
|
343
|
+
(let mappings (pairs args)
|
344
|
+
`(let ,hash (hash)
|
345
|
+
,@(map (fn (m) `(hash-set ,hash ,(brace-list-hash-key (car m)) ,(cadr m))) mappings)
|
346
|
+
,hash))))
|
347
|
+
|
348
|
+
(mac brace-list args
|
349
|
+
(if (no (cdr args))
|
350
|
+
(car args)
|
351
|
+
(brace-list-build-hash args)))
|
352
|
+
|
353
|
+
(mac on-err (handler . body)
|
354
|
+
`(handle-error (fn (err) ,handler)
|
355
|
+
(fn () ,@body)))
|
356
|
+
|
357
|
+
(mac ensure (protection . body)
|
358
|
+
`(ensuring (fn () ,protection)
|
359
|
+
(fn () ,@body)))
|
360
|
+
|
361
|
+
(mac rfn (name parms . body)
|
362
|
+
`(let ,name nil
|
363
|
+
(assign ,name (fn ,parms ,@body))))
|
364
|
+
|
365
|
+
(mac afn (parms . body)
|
366
|
+
`(rfn self ,parms ,@body))
|
367
|
+
|
368
|
+
(mac loop (start test update . body)
|
369
|
+
(w/uniq (gfn gparm)
|
370
|
+
`(do ,start
|
371
|
+
((rfn ,gfn (,gparm)
|
372
|
+
(if ,gparm
|
373
|
+
(do ,@body ,update (,gfn ,test))))
|
374
|
+
,test))))
|
375
|
+
|
376
|
+
(mac for (v init max . body)
|
377
|
+
(w/uniq (gi gm)
|
378
|
+
`(with (,v nil ,gi ,init ,gm (+ ,max 1))
|
379
|
+
(loop (assign ,v ,gi) (< ,v ,gm) (assign ,v (+ ,v 1))
|
380
|
+
,@body))))
|
@@ -20,8 +20,39 @@
|
|
20
20
|
(make-plus +seven 7)
|
21
21
|
(make-plus +eleven 11)
|
22
22
|
|
23
|
+
;
|
24
|
+
; another contrived example to check deeply nested lexical scoping
|
25
|
+
;
|
26
|
+
(let test-a0 "a0"
|
27
|
+
(def test-foo (f0 f1)
|
28
|
+
(with (w0 "w0" w1 "w1" w2 "w2" w3 "w3")
|
29
|
+
(let f (fn (x0) (joinstr " " test-a0 x0 f0 x0 f1))
|
30
|
+
(map f (list w0 w1 w2 w3))))))
|
31
|
+
|
23
32
|
(register-test
|
24
33
|
'(suite "Boot Tests"
|
34
|
+
(suite "hashtables"
|
35
|
+
("build a hash table from brace-list syntax"
|
36
|
+
(let hsh { foo 1 bar 2 }
|
37
|
+
(list 'foo hsh.foo 'bar hsh.bar))
|
38
|
+
(foo 1 bar 2))
|
39
|
+
|
40
|
+
("single-item brace list is just the thing itself"
|
41
|
+
(let zi 10 "finds the ~{zi}th item")
|
42
|
+
"finds the 10th item")
|
43
|
+
|
44
|
+
("unquotes hash keys"
|
45
|
+
(with (zi 'foo chi 'bar yi 'grr)
|
46
|
+
(let hsh { ,zi 10 ,chi 11 ,yi 12 }
|
47
|
+
(list zi hsh.foo chi hsh.bar yi hsh.grr)))
|
48
|
+
(foo 10 bar 11 grr 12))
|
49
|
+
|
50
|
+
("allows literal and invocation hash keys"
|
51
|
+
(with (zi "hello" chi "world")
|
52
|
+
(let hsh { (joinstr " " zi chi) 10 "yesterday" 11 }
|
53
|
+
(list "hello world" (hash-get hsh "hello world") "yesterday" (hash-get hsh "yesterday"))))
|
54
|
+
("hello world" 10 "yesterday" 11)))
|
55
|
+
|
25
56
|
(suite "list management"
|
26
57
|
("'pair breaks a list into pairs"
|
27
58
|
(pairs '(1 a 2 b 3 c))
|
@@ -43,6 +74,18 @@
|
|
43
74
|
(joinstr "" '("foo" "bar" "bax"))
|
44
75
|
"foobarbax")
|
45
76
|
|
77
|
+
("joins separate elements into a string"
|
78
|
+
(joinstr "/" "foo" "bar" "bax")
|
79
|
+
"foo/bar/bax")
|
80
|
+
|
81
|
+
("joins a single thing"
|
82
|
+
(joinstr "/" "foo")
|
83
|
+
"foo")
|
84
|
+
|
85
|
+
("joins nested and separate elements into a string"
|
86
|
+
(joinstr "/" "foo" "bar" '(twiddle diddle) "bax")
|
87
|
+
"foo/bar/twiddle/diddle/bax")
|
88
|
+
|
46
89
|
("joins elements into a string"
|
47
90
|
(joinstr " - " '(1 2 3))
|
48
91
|
"1 - 2 - 3")
|
@@ -54,9 +97,30 @@
|
|
54
97
|
(suite "map"
|
55
98
|
("maps a function over a list of numbers"
|
56
99
|
(map (fn (x) (* x x)) '(1 2 3))
|
57
|
-
(1 4 9))
|
100
|
+
(1 4 9))
|
101
|
+
|
102
|
+
("maps a string join function over a list of strings"
|
103
|
+
(test-foo "x" "y")
|
104
|
+
("a0 w0 x w0 y" "a0 w1 x w1 y" "a0 w2 x w2 y" "a0 w3 x w3 y"))
|
58
105
|
|
59
106
|
(suite "pre-compile"
|
107
|
+
(suite "bang-syntax"
|
108
|
+
("expansion"
|
109
|
+
(pre-compile '(!eq? a b))
|
110
|
+
((fn args (no (apply eq? args))) a b))
|
111
|
+
|
112
|
+
("bang-syntax for 'eq?"
|
113
|
+
(!eq? 1 2)
|
114
|
+
t)
|
115
|
+
|
116
|
+
("bang-syntax for 'caris"
|
117
|
+
(!caris 'foo '(foo bar))
|
118
|
+
nil)
|
119
|
+
|
120
|
+
("bang-syntax for 'caris"
|
121
|
+
(!caris 'foo '(zozo foo bar))
|
122
|
+
t))
|
123
|
+
|
60
124
|
("expands 'let"
|
61
125
|
(do
|
62
126
|
(def x+3*z (x y)
|