nydp 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -13
  3. data/lib/lisp/core-015-documentation.nydp +11 -2
  4. data/lib/lisp/core-030-syntax.nydp +52 -8
  5. data/lib/lisp/core-040-utils.nydp +35 -47
  6. data/lib/lisp/core-045-dox-utils.nydp +85 -0
  7. data/lib/lisp/core-050-test-runner.nydp +20 -2
  8. data/lib/lisp/core-080-pretty-print.nydp +5 -1
  9. data/lib/lisp/tests/boot-tests.nydp +125 -255
  10. data/lib/lisp/tests/car-examples.nydp +16 -0
  11. data/lib/lisp/tests/collect-tests.nydp +28 -0
  12. data/lib/lisp/tests/cons-examples.nydp +8 -0
  13. data/lib/lisp/tests/curry-tests.nydp +17 -18
  14. data/lib/lisp/tests/detect-examples.nydp +24 -0
  15. data/lib/lisp/tests/dot-syntax-examples.nydp +40 -0
  16. data/lib/lisp/tests/dox-tests.nydp +116 -100
  17. data/lib/lisp/tests/dynamic-scope-test.nydp +10 -10
  18. data/lib/lisp/tests/each-tests.nydp +4 -5
  19. data/lib/lisp/tests/error-tests.nydp +17 -16
  20. data/lib/lisp/tests/explain-mac-examples.nydp +24 -0
  21. data/lib/lisp/tests/foundation-test.nydp +57 -223
  22. data/lib/lisp/tests/hash-examples.nydp +41 -0
  23. data/lib/lisp/tests/isa-examples.nydp +7 -0
  24. data/lib/lisp/tests/len-examples.nydp +11 -0
  25. data/lib/lisp/tests/list-tests.nydp +110 -75
  26. data/lib/lisp/tests/parser-tests.nydp +67 -109
  27. data/lib/lisp/tests/pretty-print-tests.nydp +19 -20
  28. data/lib/lisp/tests/quasiquote-examples.nydp +10 -0
  29. data/lib/lisp/tests/rfnwith-tests.nydp +7 -0
  30. data/lib/lisp/tests/string-tests.nydp +60 -31
  31. data/lib/lisp/tests/syntax-tests.nydp +22 -24
  32. data/lib/lisp/tests/type-of-examples.nydp +48 -0
  33. data/lib/lisp/tests/unparse-tests.nydp +2 -3
  34. data/lib/nydp.rb +2 -1
  35. data/lib/nydp/version.rb +1 -1
  36. metadata +14 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 63983bd000bf898d3987e7878f25a16e0be94924
4
- data.tar.gz: ec47cf4bf570c09a63d17a53008fe92671460cbc
3
+ metadata.gz: f4074a517649b09d3911d3b593e19ff0f0bc6d66
4
+ data.tar.gz: cf2d6625885b45055f2e09601dc5914da308d5e2
5
5
  SHA512:
6
- metadata.gz: 02e72f25772989690a4ba44cee9e5f054528d0d2202779674fd232fab1806bf24d2840bd0e6e1ce289875b6aac739cfdd94e7e4da86513d1020cecce1cc7ac62
7
- data.tar.gz: 680159117248665c00a5166bf6d9e1a58247170d28d532215529f35f7a562add5464db10ee1bcbc617a38ee7eb3402777c484f27b388834c9da0aef68189947c
6
+ metadata.gz: 722eb57b1b40efaed06e432f3d70e00e18cda57ccef51b404f755b4b35dab3456a68a3542bb2185e68a22c5c1b2463c0320b5a223fa6901c1240ad542c07a0f3
7
+ data.tar.gz: 4d5a6a702eb006751548d594515022f1c2e2f8b2697d45b95973db83abb2ad2d53d29d6495fbde9281f21c9ae98bf02e87b5b6c19e6ae9c053ad9152804f41d8
data/README.md CHANGED
@@ -1,16 +1,18 @@
1
- # NYDP
1
+ # `'nydp`
2
2
 
3
- NYDP is a new LISP dialect, much inspired by [Arc](http://arclanguage.org/), and implemented in Ruby.
3
+ `'nydp` is a new LISP dialect, much inspired by [Arc](http://arclanguage.org/), and hence indirectly by all of `'arc`'s ancestors,
4
+ and implemented in Ruby.
4
5
 
5
- NYDP is "Not Your Daddy's Parentheses", a reference to [Xkcd 297](http://xkcd.com/297/) (itself a reference
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,
7
- improved Q unlike the Q your daddy used. "NYDP" also shamelessly piggypacks on the
6
+ `'nydp` is "Not Your Daddy's Parentheses", a reference to [Xkcd 297](http://xkcd.com/297/) (itself a reference
7
+ 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
8
+ modern, improved Q quite unlike the Q your daddy used. `'nydp` also shamelessly piggypacks on the
8
9
  catchiness and popularity of the [NYPD](https://en.wikipedia.org/wiki/NYPD_Blue) abbreviation ("New York Police Department",
9
10
  for those who have no interest in popular US politics or TV).
10
11
 
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
+ We do not wish to suggest by "Not Your Daddy's Parentheses" that Common Lisp, Scheme, Racket, Arc, Clojure or your favourite
13
+ other lisp are somehow old-fashioned, inferior, or in need of improvement in any way.
12
14
 
13
- The goal of NYDP is to allow untrusted users run sandboxed server-side scripts. By default, NYDP provides no system access :
15
+ The goal of `'nydp` is to allow untrusted users run sandboxed server-side scripts. By default, `'nydp` provides no system access :
14
16
 
15
17
  * no file functions
16
18
  * no network functions
@@ -19,7 +21,10 @@ The goal of NYDP is to allow untrusted users run sandboxed server-side scripts.
19
21
  * no threading functions
20
22
  * no ruby calls
21
23
 
22
- [Peruse NYDP's features here](lib/lisp/tests) in the `tests` directory.
24
+ [Peruse `'nydp`'s features here](lib/lisp/tests) in the `tests` directory.
25
+
26
+ Pronunciation guide: there is no fixed canonical pronunciation of `'nydp`. Just keep in mind that if you find yourself
27
+ wading _knee-deep_ through raw sewage, it's still better than working on a java project in a bank.
23
28
 
24
29
  ## Running
25
30
 
@@ -41,7 +46,7 @@ Suppose you want to invoke the function named `question` with some arguments. Do
41
46
  ```ruby
42
47
  ns = Nydp.build_nydp # keep this for later re-use, it's expensive to set up
43
48
 
44
- answer = Nydp.apply_function ns, :question, :life, ("The Universe" and everything())
49
+ answer = Nydp.apply_function ns, :question, :life, ["The Universe" and(everything)]
45
50
 
46
51
  ==> 42
47
52
  ```
@@ -55,7 +60,7 @@ You can maintain multiple `ns` instances without mutual interference. In other w
55
60
 
56
61
  #### 1. Macro-expansion runs in lisp
57
62
 
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).
63
+ 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
64
 
60
65
  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
66
 
@@ -185,7 +190,7 @@ nydp > (parse "\"foo\"")
185
190
 
186
191
  nydp > (let bar "Mister Nice Guy" "hello, ~bar")
187
192
 
188
- ==> hello, Mister Nice Guy
193
+ ==> "hello, Mister Nice Guy"
189
194
 
190
195
  ; this is a more tricky example because we need to make a string with an interpolation token in it
191
196
 
@@ -193,6 +198,8 @@ nydp > (let s (joinstr "" "\"hello, " '~ "world\"") (parse s))
193
198
 
194
199
  ==> (string-pieces "hello, " world "") ; "hello, ", followed by the interpolation 'world, followed by the empty string after 'world
195
200
 
201
+ ; It is possible to nest interpolations. Note that as with many popular language features, just because you can do something, does not mean you should:
202
+
196
203
  nydp > (def also (str) "\nAND ALSO, ~str")
197
204
  nydp > (with (a 1 b 2)
198
205
  (p "Consider ~a : the first thing,
@@ -204,13 +211,17 @@ nydp > (with (a 1 b 2)
204
211
  ==> AND ALSO, Consider 3, the third (and final) thing
205
212
  ```
206
213
 
207
- 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. The 'nydp-html gem detects 'string-pieces and gives it special treatment in order to render haml and textile efficiently, and also to capture and report errors inside interpolations and report them correctly.
214
+ By default, `string-pieces` is a function that just concatenates the string value of its arguments. You can redefine it as a macro to
215
+ perform more fun stuff, or you can detect it within another macro to do extra-special stuff with it. The 'nydp-html gem detects
216
+ 'string-pieces and gives it special treatment in order to render haml and textile efficiently, and also to capture and report errors
217
+ inside interpolations and report them correctly.
208
218
 
209
219
 
210
220
  #### 5. No continuations.
211
221
 
212
222
  Sorry. While technically possible ... why bother?
213
223
 
224
+
214
225
  #### 6. No argument destructuring
215
226
 
216
227
  However, this doesn't need to be built-in, it can be done with macros alone. On the other hand, "rest" arguments are implicitly available using the same syntax as Arc uses:
@@ -277,7 +288,8 @@ nydp > (parse "; blah blah")
277
288
  ==> (comment "blah blah")
278
289
  ```
279
290
 
280
- Except in 'mac and 'def forms, by default, `comment` is a macro that expands to nil. If you have a better idea, go for it.
291
+ Except in 'mac and 'def forms, by default, `comment` is a macro that expands to nil. If you have a better idea, go for it. Any comments present at the
292
+ beginning of the `body` argument to `mac` or `def` are considered documentation. (See "self-documenting" below).
281
293
 
282
294
  #### 8 Prefix lists
283
295
 
@@ -1,10 +1,16 @@
1
- ((fn (dox)
1
+ ((fn (dox examples)
2
2
  (def dox-add-doc (name what texts args src)
3
3
  (hash-set dox
4
4
  name
5
5
  (cons (list name what texts args src)
6
6
  (hash-get dox sym))))
7
7
 
8
+ (def dox-add-examples (name example-exprs)
9
+ (hash-set examples
10
+ name
11
+ (cons example-exprs
12
+ (hash-get examples sym))))
13
+
8
14
  (def dox-lookup (sym) (hash-get dox sym))
9
15
 
10
16
  (def dox? (sym) (hash-key? dox sym))
@@ -19,10 +25,13 @@
19
25
  (cond (dox? name)
20
26
  (car (cddr (cddr (car (dox-lookup name)))))))
21
27
 
28
+ (def dox-examples (name)
29
+ (hash-get examples name))
30
+
22
31
  (def dox-arg-names (name)
23
32
  (cond (dox? name)
24
33
  (cadddr (car (dox-lookup name))))))
25
- (hash))
34
+ (hash) (hash))
26
35
 
27
36
  (def isa-comment? (thing)
28
37
  (cond (pair? thing)
@@ -1,4 +1,7 @@
1
1
  (def orf args
2
+ ; evaluates each arg in 'args, returns the
3
+ ; first non-nil value, or nil if they are
4
+ ; all nil
2
5
  (cond args
3
6
  (cond (car args)
4
7
  (car args)
@@ -6,6 +9,7 @@
6
9
  (cdr args)))))
7
10
 
8
11
  (mac unless (arg . body)
12
+ ; evaluate 'body if 'arg is nil
9
13
  `(if (no ,arg) (do ,@body)))
10
14
 
11
15
  (def expand-colon-syntax (names)
@@ -27,11 +31,23 @@
27
31
  (error "Irregular ': syntax: got ~(inspect names) : not prefix-syntax : in ~(joinstr ":" names)"))
28
32
 
29
33
  (mac colon-syntax names
34
+ ; handle syntax of the form a:b, which the parser expands to
35
+ ; (colon-syntax a b). By default, this complains if colon is used
36
+ ; as a prefix (ie it disallows ":foo"), otherwise creates a new
37
+ ; function which is the composition of the functions named in its
38
+ ; arguments. For example,
39
+ ; (count:parts spaceship) is the same as (count (parts spaceship))
30
40
  ((orf (hash-get colon-syntax-overrides (car names))
31
41
  default-colon-syntax)
32
42
  names))
33
43
 
34
44
  (mac bang-syntax (pfx . rest)
45
+ ; handle syntax of the form !x, which the parser expands to
46
+ ; (bang-syntax || x). By default, this complains if there is
47
+ ; a non-empty prefix (ie it disallows x!y), otherwise it creates
48
+ ; a new function which is the negation of the given named function.
49
+ ; For example,
50
+ ; (!eq? a 10) is the same as (no:eq? a 10), which is the same as (no (eq? a 10))
35
51
  (if (no (eq? pfx '||))
36
52
  (error "Irregular '! syntax: got prefix ~(inspect pfx) in ~(joinstr "!" (cons pfx rest))"))
37
53
  (if (cdr rest)
@@ -64,6 +80,30 @@
64
80
  (mac let (var val . body)
65
81
  `(with (,var ,val) ,@body))
66
82
 
83
+ (mac rfn (name parms . body)
84
+ ; creates a named, locally-scoped function
85
+ ; with the given parameter names. It is possible
86
+ ; to reference the function by its name from within
87
+ ; the function (to pass as an argument or for
88
+ ; recursive invocation)
89
+ `(let ,name nil
90
+ (assign ,name (fn ,parms ,@body))))
91
+
92
+ (mac afn (parms . body)
93
+ ; same as 'rfn, but using the name 'self
94
+ `(rfn self ,parms ,@body))
95
+
96
+ (mac rfnwith (name params . body)
97
+ ; a mix of rfn and with; creates a locally-scoped named function with
98
+ ; the given parameter names, and invokes it with the given parameter
99
+ ; values. It is possible to reference the function by its name from
100
+ ; within the function (to pass as an argument or for recursive
101
+ ; invocation)
102
+ (let ppairs (pairs params)
103
+ `(let ,name nil
104
+ (assign ,name (fn ,(map car ppairs) ,@body))
105
+ (,name ,@(map cadr ppairs)))))
106
+
67
107
  (let uniq-counter 0
68
108
  (def uniq (prefix)
69
109
  (sym (joinstr "-"
@@ -74,16 +114,20 @@
74
114
  (assign uniq-counter 0)))
75
115
 
76
116
  (mac w/uniq (vars . body)
77
- (if (pair? vars)
78
- `(with ,(apply + (map (fn (n) (list n '(uniq ',n))) vars))
79
- ,@body)
80
- `(let ,vars (uniq ',vars) ,@body)))
117
+ ; creates a lexical scope with a unique symbol assigned to
118
+ ; each variable in 'vars ; executes the 'body.
119
+ (if (pair? vars)
120
+ `(with ,(apply + (map (fn (n) (list n '(uniq ',n))) vars))
121
+ ,@body)
122
+ `(let ,vars (uniq ',vars) ,@body)))
81
123
 
82
124
  (mac or args
83
- (cond args
84
- (w/uniq ora
85
- `(let ,ora ,(car args)
86
- (cond ,ora ,ora (or ,@(cdr args)))))))
125
+ ; lazy-evaluates each argument, returns the first
126
+ ; non-nil result, or nil if all evaluate to nil.
127
+ (cond args
128
+ (w/uniq ora
129
+ `(let ,ora ,(car args)
130
+ (cond ,ora ,ora (or ,@(cdr args)))))))
87
131
 
88
132
  (mac pop (xs)
89
133
  (w/uniq gp
@@ -14,12 +14,10 @@
14
14
 
15
15
  (def flatten (things)
16
16
  (let acc nil
17
- (let flattenize nil
18
- (assign flattenize (fn (x)
19
- (if (pair? x)
20
- (eachr flattenize x)
21
- (push x acc))))
22
- (flattenize things))
17
+ (rfnwith flattenize (x things)
18
+ (if (pair? x)
19
+ (eachr flattenize x)
20
+ (push x acc)))
23
21
  acc))
24
22
 
25
23
  (def string-strip (txt)
@@ -40,6 +38,9 @@
40
38
  (joinstr "" pieces))
41
39
 
42
40
  (def detect (f things)
41
+ ; if 'things is a list, return the first item in the list for which 'f returns non-nil
42
+ ; otherwise, return 'things if (f things) is non-nil
43
+ ; otherwise, nil
43
44
  (if (pair? things)
44
45
  (let it (car things)
45
46
  (or
@@ -48,10 +49,26 @@
48
49
  (f things)
49
50
  things))
50
51
 
52
+ (def collect (f things)
53
+ ; if 'things is a list, return all the items in the list for which 'f returns non-nil
54
+ ; otherwise, return 'things if (f things) is non-nil
55
+ ; otherwise, nil
56
+ (rfnwith collector (items things)
57
+ (if (no items)
58
+ nil
59
+ (pair? items)
60
+ (if (f (car items))
61
+ (cons (car items)
62
+ (collector (cdr items)))
63
+ (collector (cdr items)))
64
+ (f items)
65
+ items)))
66
+
51
67
  (def nth (n things)
52
- (if (eq? n 0)
53
- (car things)
54
- (nth (- n 1) (cdr things))))
68
+ ; returns the n-th item in the list 'things
69
+ (if (eq? n 0)
70
+ (car things)
71
+ (nth (- n 1) (cdr things))))
55
72
 
56
73
  (def iso (x y)
57
74
  (or (eq? x y)
@@ -68,8 +85,10 @@
68
85
  (def quotify (arg) `(quote ,arg))
69
86
 
70
87
  (def caris (obj things)
71
- (and (isa 'pair things)
72
- (eq? (car things) obj)))
88
+ ; returns true if 'things is a list and the first item of the
89
+ ; list is the given object
90
+ (and (isa 'pair things)
91
+ (eq? (car things) obj)))
73
92
 
74
93
  (def len (xs)
75
94
  (if (pair? xs) (+ 1 (len (cdr xs)))
@@ -79,6 +98,7 @@
79
98
  (assign dynamics (hash))
80
99
 
81
100
  (mac dynamic (name)
101
+ ; creates a dynamic variable.
82
102
  (hash-set dynamics name t)
83
103
  (let with-mac-name (sym "w/~name")
84
104
  (w/uniq prev
@@ -93,20 +113,17 @@
93
113
  (def ,name () (hash-get (thread-locals) ',name))))))
94
114
 
95
115
  (mac on-err (handler . body)
116
+ ; executes 'body. If an error is raised, executes 'handler. Inside
117
+ ; 'handler, the parameter 'err refers to the error that was raised.
96
118
  `(handle-error (fn (err) ,handler)
97
119
  (fn () ,@body)))
98
120
 
99
121
  (mac ensure (protection . body)
122
+ ; executes 'body. Afterwards, executes 'protection.
123
+ ; 'protection is always executed even if there is an error.
100
124
  `(ensuring (fn () ,protection)
101
125
  (fn () ,@body)))
102
126
 
103
- (mac rfn (name parms . body)
104
- `(let ,name nil
105
- (assign ,name (fn ,parms ,@body))))
106
-
107
- (mac afn (parms . body)
108
- `(rfn self ,parms ,@body))
109
-
110
127
  (mac loop (start test update . body)
111
128
  (w/uniq (gfn gparm)
112
129
  `(do ,start
@@ -143,35 +160,6 @@
143
160
  acc))
144
161
  (car things) (cdr things)))
145
162
 
146
- (def dox-show-src (src)
147
- ; show 'src as source code.
148
- ; expect to override this later when pretty-printing is available
149
- (inspect src))
150
-
151
- (def dox-show-info (name what texts args src)
152
- ; show the given dox info
153
- ; 'info arg is a dox object from the dox system
154
- "~(if (eq? what 'mac) "Macro"
155
- (eq? what 'def) "Function"
156
- what) : ~name
157
-
158
- args : ~(inspect args)
159
-
160
- ~(joinstr "\n" texts)
161
-
162
- source
163
- ======
164
- ~(dox-show-src src)
165
- ")
166
-
167
- (mac dox (name)
168
- ; show dox for the given name
169
- `(let infos (dox-lookup ',name)
170
- (if (no infos)
171
- (p "No documentation for" ',name)
172
- (each info infos
173
- (p:apply dox-show-info info)))))
174
-
175
163
  (def proper? (list)
176
164
  ; t if this is a proper list (last cdr is nil)
177
165
  ; nil otherwise (last cdr is neither cons nor nil)
@@ -0,0 +1,85 @@
1
+ (def dox-show-src (src)
2
+ ; show 'src as source code.
3
+ ; expect to override this later when pretty-printing is available
4
+ (inspect src))
5
+
6
+ (def dox-show-info (name what texts args src)
7
+ ; show the given dox info
8
+ ; 'info arg is a dox object from the dox system
9
+ "~(if (eq? what 'mac) "Macro"
10
+ (eq? what 'def) "Function"
11
+ what) : ~name
12
+
13
+ args : ~(inspect args)
14
+
15
+ ~(joinstr "\n" texts)
16
+
17
+ source
18
+ ======
19
+ ~(dox-show-src src)
20
+ ")
21
+
22
+ (def dox-show-one-example (name example)
23
+ "~|name| ~(car example)
24
+
25
+ running :
26
+ ~(dox-show-src:cadr example)
27
+
28
+ produces : ~(dox-show-src:caddr example)
29
+
30
+ --------------------------------
31
+ ")
32
+
33
+ (def dox-show-examples (name examples)
34
+ (if examples
35
+ "
36
+ Examples for ~name
37
+ ==================
38
+
39
+ ~(joinstr "\n\n" (map (curry dox-show-one-example name) examples))
40
+
41
+ "))
42
+
43
+ (def dox-all-items ()
44
+ ; return all documentation items in a single list
45
+ (apply joinlists (map dox-lookup (dox-names))))
46
+
47
+ (def dox-with-documentation (dox-item)
48
+ ; a documentation filter that returns non-nil for items with text documentation
49
+ ; use with 'dox-all-items to gather dox items that are explicitly documented
50
+ ; for example (cleverly-show (collect dox-with-documentation (dox-all-items)))
51
+ (nth 2 dox-item))
52
+
53
+ (mac dox (name)
54
+ ; show dox for the given name, or all available dox if name is not given
55
+ (if name
56
+ `(let infos (dox-lookup ',name)
57
+ (if (no infos)
58
+ (p "No documentation for" ',name)
59
+ (each info infos
60
+ (p:apply dox-show-info info)))
61
+ (let examples (dox-examples ',name)
62
+ (if (no examples)
63
+ (p "No examples for" ',name)
64
+ (p (joinstr "\n" (map (curry dox-show-examples ',name) examples)))))
65
+ nil)
66
+ `(let infos (collect dox-with-documentation (dox-all-items))
67
+ (p "documentation available for the following:")
68
+ (each info infos
69
+ (p:inspect:firstn 2 info)))))
70
+
71
+ (def-colon-syntax dox names
72
+ (let target (cadr names)
73
+ `(dox ,(if (eq? target '||)
74
+ nil
75
+ target))))
76
+
77
+ (def explain-mac (n expr)
78
+ (if (eq? n 0)
79
+ expr
80
+ (let macfn (hash-get macs (car expr))
81
+ (if macfn
82
+ (explain-mac (- n 1)
83
+ (apply macfn
84
+ (cdr expr)))
85
+ expr))))