nydp 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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)
|