nydp 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ebd833948c836f583d77adc0028df3838bd30ed3
4
- data.tar.gz: 85458c42aa0466e0802771a3a62b3593cc26d25d
3
+ metadata.gz: 031f54326dfa57ae2a067c931bd600bd9e2cc6c0
4
+ data.tar.gz: aa49dab4d81173e02e968958028c1cad2948079c
5
5
  SHA512:
6
- metadata.gz: 6b0981f75b8ecf590694377973f0bc9b013250cd54ad0278d0b79cfba43cc6c8f870f4842238e1df43448fdcfad15a2cb7634c2b30c141b60dbb1bca87a610ee
7
- data.tar.gz: cd44bec0ad3c3fe9b1bfc8c38937ac5850de8529b0f74004378bbbae3dbe376d9e39c02ea5db3c1383888b26bcf8f6fea34fc50adf634a1e8a3ef134587d598a
6
+ metadata.gz: e263b9ce4dff11cd6ac7e7d7ef5787ad553807eb1f2048bbd357973ddbbc910feaaf7c340c0bb8347f31d90e07c4e5b23af3992ed31cb8e61edef8e878c480b5
7
+ data.tar.gz: 0966de059bcf3658fe137c9a436bf817d84b5bc4ad443b8afd14e22fbecc7e392c23732d6a5a5db8862345bd5ba70b7ae09e87e67e0a910484792e1882e27eda
data/README.md CHANGED
@@ -275,10 +275,117 @@ error
275
275
  nydp > (parse "; blah blah")
276
276
 
277
277
  ==> (comment "blah blah")
278
+ ```
279
+
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.
281
+
282
+ #### 8 Prefix lists
283
+
284
+ The parser emits a special form if it detects a prefix-list, that is, a list with non-delimiter characters immediately preceding
285
+ the opening delimiter. For example:
286
+
287
+ ```lisp
288
+ nydp > (parse "%w(a b c)")
289
+
290
+ ==> (prefix-list "%w" (a b c))
291
+ ```
292
+
293
+ This allows for preprocessing lists in a way not possible for macros. nydp uses this feature to implement shortcut oneline
294
+ functions, as in
295
+
296
+ ```lisp
297
+ nydp > (parse "λx(len x)")
298
+
299
+ ==> ((prefix-list "λx" (len x)))
300
+
301
+ nydp > (pre-compile '(prefix-list "λx" (len x)))
302
+
303
+ ==> (fn (x) (len x))
304
+ ```
305
+
306
+ Each character after 'λ becomes a function argument:
307
+
308
+ ```lisp
309
+ nydp > (parse "λxy(* x y)")
310
+
311
+ ==> ((prefix-list "λxy" (* x y)))
312
+
313
+ nydp > (pre-compile '(prefix-list "λxy" (* x y)))
314
+
315
+ ==> (fn (x y) (* x y))
316
+ ```
317
+
318
+ Use 'define-prefix-list-macro to define a new handler for a prefix-list. Here's the code for the 'λ shortcut:
319
+
320
+ ```lisp
321
+ (define-prefix-list-macro "^λ.+" vars expr
322
+ (let var-list (map sym (cdr:string-split vars))
323
+ `(fn ,var-list ,expr)))
324
+ ```
325
+
326
+ In this case, the regex matches an initial 'λ ; there is no constraint however on the kind of regex a prefix-list-macro might use.
327
+
328
+
329
+ #### 9 Self-documenting
278
330
 
279
- By default, `comment` is a macro that expands to nil. If you have a better idea, go for it. (doc-comments for example)
331
+ Once the 'dox system is bootstrapped, any further use of 'mac or 'def will create documentation.
332
+
333
+ Any comments at the start of the form body will be used to generate help text. For example:
334
+
335
+ ```lisp
336
+ nydp > (def foo (x y)
337
+ ; return the foo of x and y
338
+ (* x y))
339
+
340
+ nydp > (dox foo)
341
+
342
+ Function : foo
343
+ args : (x y)
344
+ return the foo of x and y
345
+
346
+ source
347
+ ======
348
+ (def foo (x y)
349
+ (* x y))
280
350
  ```
281
351
 
352
+ 'dox is a macro that generates code to output documentation to stdout. 'dox-lookup is a function that returns structured documentation.
353
+
354
+ ```lisp
355
+ nydp > (dox-lookup 'foo)
356
+ ((foo def ("return the foo of x and y") (x y) (def foo (x y) (* x y))))
357
+ ```
358
+
359
+ Not as friendly, but more amenable to programmatic manipulation. Each subsequent definition of 'foo (if you override it, define
360
+ it as a macro, or define it again in some other context) will generate a new documentation structure, which will simply be preprended to
361
+ the existing list.
362
+
363
+ #### 10 Pretty-Printing
364
+
365
+ 'dox above uses the pretty printer to display code source. The pretty-printer is hard-coded to handle some special cases,
366
+ so it will unparse special syntax, prefix-lists, quote, quasiquote, unquote, and unquote-splicing.
367
+
368
+ You can examine its behaviour at the repl:
369
+
370
+ ```lisp
371
+ nydp > (p:pp '(string-pieces "hello " (bang-syntax || (dot-syntax x y (ampersand-syntax foo bar))) " and welcome to " (prefix-list "%%" (a b c d)) " and friends!"))
372
+
373
+ ==> "hello ~!x.y.foo&bar and welcome to ~%%(a b c d) and friends!"
374
+
375
+ nydp > (p:pp:dox-src 'pp/find-breaks)
376
+
377
+ (def pp/find-breaks (form)
378
+ (if (eq? 'if (car form))
379
+ (let if-args (cdr form)
380
+ (cons (list 'if (car if-args)) (map list (cdr if-args))))
381
+ (or
382
+ (pp/find-breaks/mac form)
383
+ (list form))))
384
+ ```
385
+
386
+ The pretty-printer is still rather primitive in that it only indents according to some hard-coded rules, and according to argument-count
387
+ for documented macros. It has no means of wrapping forms that get too long, or that extend beyond a certain predefined margin or column number.
388
+
282
389
  ## Installation
283
390
 
284
391
  Add this line to your application's Gemfile:
@@ -0,0 +1,18 @@
1
+ ; -*- lisp -*-
2
+ ;;
3
+ ;; Acknowledgements to Paul Graham, Robert Morris, and their ancestor programmers.
4
+ ;; nydp's main inspiration is arc, and many nydp features (including, but not limited
5
+ ;; to, 'do, 'rfn, 'loop, 'for) were directly inspired by (aka stolen from) arc.arc
6
+ ;;
7
+
8
+ (assign list (fn args args))
9
+ (assign caar (fn (arg) (car (car arg))))
10
+ (assign cadr (fn (arg) (car (cdr arg))))
11
+ (assign cdar (fn (arg) (cdr (car arg))))
12
+ (assign cddr (fn (arg) (cdr (cdr arg))))
13
+ (assign cadar (fn (arg) (car (cdr (car arg)))))
14
+ (assign caddr (fn (arg) (car (cdr (cdr arg)))))
15
+ (assign cdddr (fn (arg) (cdr (cdr (cdr arg)))))
16
+ (assign cadddr (fn (arg) (car (cdr (cdr (cdr arg))))))
17
+ (assign no (fn (arg) (cond arg nil t)))
18
+ (assign just (fn (arg) arg))
@@ -42,6 +42,7 @@
42
42
 
43
43
  (debug-pre-compile nil)
44
44
 
45
+ ; we override this later to provide automatic documentation
45
46
  (hash-set macs 'def
46
47
  (fn (name args . body)
47
48
  (list 'assign
@@ -118,13 +119,6 @@
118
119
  (hash-set macs 'quasiquote
119
120
  (fn (arg) (qq-quasiquote arg 0)))
120
121
 
121
- (hash-set macs 'mac (fn (name args . body)
122
- `(hash-set macs ',name (fn ,args ,@body))))
123
-
124
- (mac if args
125
- (cond (no args) nil
126
- (cond (cdr args)
127
- (cond (cddr args)
128
- `(cond ,(car args) ,(cadr args) (if ,@(cddr args)))
129
- `(cond ,(car args) ,(cadr args)))
130
- (car args))))
122
+ (hash-set macs 'do
123
+ (fn args
124
+ `((fn nil ,@args))))
@@ -0,0 +1,89 @@
1
+ ((fn (dox)
2
+ (def dox-add-doc (name what texts args src)
3
+ (hash-set dox
4
+ name
5
+ (cons (list name what texts args src)
6
+ (hash-get dox sym))))
7
+
8
+ (def dox-lookup (sym) (hash-get dox sym))
9
+
10
+ (def dox? (sym) (hash-key? dox sym))
11
+
12
+ (def dox-names () (hash-keys dox))
13
+
14
+ (def dox-what-is? (name)
15
+ (cond (dox? name)
16
+ (cadr (car (dox-lookup name)))))
17
+
18
+ (def dox-src (name)
19
+ (cond (dox? name)
20
+ (car (cddr (cddr (car (dox-lookup name)))))))
21
+
22
+ (def dox-arg-names (name)
23
+ (cond (dox? name)
24
+ (cadddr (car (dox-lookup name))))))
25
+ (hash))
26
+
27
+ (def isa-comment? (thing)
28
+ (cond (pair? thing)
29
+ (eq? (car thing) 'comment)))
30
+
31
+ (def rev-accum (things acc)
32
+ (cond (no things)
33
+ acc
34
+ (rev-accum (cdr things)
35
+ (cons (car things)
36
+ acc))))
37
+
38
+ (def rev (things) (rev-accum things nil))
39
+
40
+ (def dox-gather-comments (body acc)
41
+ (cond (isa-comment? (car body))
42
+ (dox-gather-comments (cdr body)
43
+ (cons (cadar body)
44
+ acc))
45
+ (list (rev acc) body)))
46
+
47
+ (def define-mac-expr (name args documentation body)
48
+ ; used internally by 'mac
49
+ `(do (hash-set macs ',name (fn ,args ,@body))
50
+ (dox-add-doc ',name
51
+ 'mac
52
+ ',documentation
53
+ ',args
54
+ '(mac ,name ,args ,@body))))
55
+
56
+ (hash-set macs 'mac
57
+ (fn (name args . body)
58
+ (apply define-mac-expr
59
+ name
60
+ args
61
+ (dox-gather-comments body))))
62
+
63
+ (dox-add-doc 'mac
64
+ 'mac
65
+ '("define a new global macro")
66
+ '(name args . body)
67
+ (dox-src 'define-mac-expr))
68
+
69
+ (dox-add-doc 'do
70
+ 'mac
71
+ '("perform a series of operations")
72
+ 'args
73
+ '`((fn nil ,@args)))
74
+
75
+ (def define-def-expr (name args documentation body)
76
+ ; used internally by 'def
77
+ `(do (assign ,name (fn ,args ,@body))
78
+ (dox-add-doc ',name
79
+ 'def
80
+ ',documentation
81
+ ',args
82
+ '(def ,name ,args ,@body))))
83
+
84
+ (mac def (name args . body)
85
+ ; define a new function in the global namespace
86
+ (apply define-def-expr
87
+ name
88
+ args
89
+ (dox-gather-comments body)))
@@ -0,0 +1,22 @@
1
+ (mac if args
2
+ ; with arguments a, return a
3
+ ; with arguments a b, return b if a is true, otherwise nil
4
+ ; with arguments a b c, return b if a is true, otherwise return c
5
+ ; with arguments a b c d, return b if a is true, otherwise return d if c is true, otherwise nil
6
+ ; with arguments a b c d e, return b if a is true, otherwise return d if c is true, otherwise e
7
+ ; and so on for subsequent arguments
8
+ (cond (no args) nil
9
+ (cond (cdr args)
10
+ (cond (cddr args)
11
+ `(cond ,(car args) ,(cadr args) (if ,@(cddr args)))
12
+ `(cond ,(car args) ,(cadr args)))
13
+ (car args))))
14
+
15
+ (def map (f things)
16
+ ; transforms the list 'things by applying 'f to each item
17
+ ; returns the resulting list
18
+ (if (no things)
19
+ nil
20
+ (pair? things)
21
+ (cons (f (car things)) (map f (cdr things)))
22
+ (map f (list things))))
@@ -27,9 +27,6 @@
27
27
  (car args))
28
28
  't))
29
29
 
30
- (mac do args
31
- `((fn nil ,@args)))
32
-
33
30
  (mac when (condition . body)
34
31
  `(cond ,condition (do ,@body)))
35
32
 
@@ -84,9 +81,8 @@
84
81
  name)
85
82
  (list 'quote name)))
86
83
 
87
- ;; (build-hash-getters '(a b c))
88
- ;; => (hash-get (hash-get a 'b) 'c)
89
84
  (def build-hash-getters (names acc)
85
+ ;; (build-hash-getters '(a b c)) => (hash-get (hash-get a 'b) 'c)
90
86
  (if (no acc)
91
87
  (build-hash-getters (cdr names) (car names))
92
88
  names
@@ -4,18 +4,11 @@
4
4
  (f (car things))))
5
5
 
6
6
  (def zip (a b)
7
+ ; takes two lists, (p q r) and (1 2 3), returns ((p 1) (q 2) (r 3))
7
8
  (if a
8
9
  (cons (list (car a) (car b))
9
10
  (zip (cdr a) (cdr b)))))
10
11
 
11
- (def reversify (things acc)
12
- (if (no things)
13
- acc
14
- (reversify (cdr things)
15
- (cons (car things) acc))))
16
-
17
- (def rev (things) (reversify things nil))
18
-
19
12
  (mac push (x things)
20
13
  `(assign ,things (cons ,x ,things)))
21
14
 
@@ -29,6 +22,13 @@
29
22
  (flattenize things))
30
23
  acc))
31
24
 
25
+ (def string-strip (txt)
26
+ (string-replace "\\s+$"
27
+ ""
28
+ (string-replace "^\\s+"
29
+ ""
30
+ txt)))
31
+
32
32
  (def joinstr (txt . things)
33
33
  (let joinables (flatten things)
34
34
  (apply +
@@ -60,6 +60,7 @@
60
60
  (iso (car x) (car y))
61
61
  (iso (cdr x) (cdr y)))))
62
62
 
63
+ (def x1 (thing) thing)
63
64
  (def isa (type obj) (eq? (type-of obj) type))
64
65
  (def sym? (arg) (isa 'symbol arg))
65
66
  (def string? (arg) (isa 'string arg))
@@ -141,3 +142,51 @@
141
142
  (cdr list))
142
143
  acc))
143
144
  (car things) (cdr things)))
145
+
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
+ (p)
155
+ (cond (eq? what 'mac) (p "Macro : ~name" ))
156
+ (cond (eq? what 'def) (p "Function : ~name" ))
157
+ (p "args : ~(inspect args)")
158
+ (p (joinstr "\n" texts))
159
+ (p "")
160
+ (p "source")
161
+ (p "======")
162
+ (p (dox-show-src src))
163
+ (p))
164
+
165
+ (mac dox (name)
166
+ ; show dox for the given name
167
+ `(let infos (dox-lookup ',name)
168
+ (if (or (no infos)
169
+ (eq? (len infos) 0))
170
+ (p "No documentation for " ',name)
171
+ (each info infos
172
+ (apply dox-show-info info)))))
173
+
174
+ (def proper? (list)
175
+ ; t if this is a proper list (last cdr is nil)
176
+ ; nil otherwise (last cdr is neither cons nor nil)
177
+ (or (no list)
178
+ (and (pair? list)
179
+ (proper? (cdr list)))))
180
+
181
+ (def firstn (n things)
182
+ ; returns the first 'n items in the list 'things
183
+ (if (eq? n 0) nil
184
+ (cons (car things)
185
+ (firstn (- n 1)
186
+ (cdr things)))))
187
+
188
+ (def nthcdr (n things)
189
+ ; returns the nth cdr of the list 'things
190
+ (if (> n 0)
191
+ (nthcdr (- n 1) (cdr things))
192
+ things))
@@ -0,0 +1,33 @@
1
+
2
+ (assign prefix-list-prefixes ())
3
+
4
+ (def prefix-match-fn (txt)
5
+ (fn (rule) (string-match txt (car rule))))
6
+
7
+ (def find-prefix-rule (prefix)
8
+ (cdr:detect (prefix-match-fn prefix)
9
+ prefix-list-prefixes))
10
+
11
+ (mac prefix-list (prefix list)
12
+ ; looks up a handler in 'prefix-list-prefixes
13
+ ; whose 'car matches the prefix, and whose 'cdr
14
+ ; is a function, which behaves like a macro, in that
15
+ ; it processes the prefix name and the prefixed list,
16
+ ; returning more code
17
+ (let handler (find-prefix-rule prefix)
18
+ (and handler (handler prefix list))))
19
+
20
+ (mac define-prefix-list-macro (regex prefix-var list-var . body)
21
+ ; define a macro to process a prefix-list where the prefix matches the given regex
22
+ ; param: 'regex is the regex which should match the list prefix
23
+ ; param: 'prefix-var is the variable whose value will be the actual matched prefix
24
+ ; param: 'list-var is the variable whose value will be the corresponding list
25
+ ; param: 'body the code which will actually transform the list
26
+ `(push (cons ,regex (fn (,prefix-var ,list-var) ,@body))
27
+ prefix-list-prefixes))
28
+
29
+ (define-prefix-list-macro "^λ.+" vars expr
30
+ ;; allows (map λa(upcase a.name) people)
31
+ ;; as shortcut for (map (fn (a) (upcase a.name)) people)
32
+ (let var-list (map sym (cdr:string-split vars))
33
+ `(fn ,var-list ,expr)))
@@ -0,0 +1,101 @@
1
+ (assign pp/special-forms (hash))
2
+ (assign pp/line-break (uniq 'line-break))
3
+
4
+ (def pp/escape-char (char)
5
+ (if (eq? char "\"") "\\\""
6
+ (eq? char "\~") "\\\~"
7
+ (eq? char "\\") "\\\\"
8
+ (eq? char "\n") "\\n"
9
+ char))
10
+
11
+ (def pp/escape-string-literal (txt)
12
+ (joinstr "" (map pp/escape-char (string-split txt))))
13
+
14
+ (def pp/string-piece (thing)
15
+ (if (isa 'string thing) (pp/escape-string-literal thing)
16
+ "\~~(pp thing)"))
17
+
18
+ (def pp/string-pieces (things) "\"~(joinstr "" (map pp/string-piece things))\"")
19
+
20
+ (def pp/literal (thing)
21
+ (if (eq? thing '||)
22
+ ""
23
+ (isa 'string thing)
24
+ (pp/escape-string-literal thing)
25
+ (inspect thing)))
26
+
27
+ (mac pp/def (name args . body)
28
+ `(do
29
+ (hash-set pp/special-forms ',name
30
+ (fn ,args ,@body))
31
+ (dox-add-doc ',name
32
+ 'pp/def
33
+ '("pretty-printer for forms starting with ~(quote ,name)")
34
+ ',args
35
+ '(pp/def ,name ,args ,@body))))
36
+
37
+ (mac pp/syntax syntaxes
38
+ (if syntaxes
39
+ `(do (pp/def ,(car syntaxes) (form indent)
40
+ (joinstr ,(cadr syntaxes) (map pp (cdr form))))
41
+ (pp/syntax ,@(cddr syntaxes)))))
42
+
43
+ (pp/def string-pieces (form indent) (pp/string-pieces (cdr form)))
44
+ (pp/def quasiquote (form indent) "`~(pp/main (cadr form) indent)" )
45
+ (pp/def quote (form indent) "'~(pp/main (cadr form) indent)" )
46
+ (pp/def unquote (form indent) ",~(pp/main (cadr form) indent)" )
47
+ (pp/def unquote-splicing (form indent) ",@~(pp/main (cadr form) indent)")
48
+ (pp/def comment (form indent) ";~(cadr form)\n")
49
+ (pp/def prefix-list (form indent) "~(cadr form)~(pp (caddr form))")
50
+
51
+ (pp/syntax
52
+ colon-syntax ":"
53
+ dot-syntax "."
54
+ bang-syntax "!"
55
+ ampersand-syntax "&"
56
+ dollar-syntax "$"
57
+ colon-colon-syntax "::"
58
+ arrow-syntax "->"
59
+ rocket-syntax "=>" )
60
+
61
+ (def pp/spaces (n) (if (> n 0) " ~(pp/spaces (- n 1))" ""))
62
+
63
+ (def pp/dotify (form)
64
+ (if (pair? (cdr form))
65
+ (cons (car form) (pp/dotify (cdr form)))
66
+ (no:cdr form)
67
+ form
68
+ (list (car form) '. (cdr form))))
69
+
70
+ (def pp/find-breaks/mac (form)
71
+ (if (eq? (dox-what-is? (car form)) 'mac)
72
+ (let arg-count (+ 1 (len (dox-arg-names (car form))))
73
+ (cons (firstn arg-count form)
74
+ (map list (nthcdr arg-count form))))))
75
+
76
+ (def pp/find-breaks (form)
77
+ (if (eq? 'if (car form))
78
+ (let if-args (cdr form)
79
+ (cons (list 'if (car if-args)) (map list (cdr if-args))))
80
+ (or (pp/find-breaks/mac form)
81
+ (list form))))
82
+
83
+ (def pp/inline (forms indent)
84
+ (joinstr " " (map λf(pp/main f (+ indent 1)) forms)))
85
+
86
+ (def pp/pair (form indent)
87
+ (let special-form (hash-get pp/special-forms (car form))
88
+ (if special-form
89
+ (special-form form indent)
90
+ (let form-with-breaks (pp/find-breaks form)
91
+ "(~(joinstr "\n~(pp/spaces (+ 4 indent))" (map λf(pp/inline f (+ indent 1)) (pp/dotify form-with-breaks))))"))))
92
+
93
+ (def pp/main (form indent)
94
+ (if (pair? form) (pp/pair form indent)
95
+ (pp/literal form)))
96
+
97
+ (def pp (form) (pp/main form 0))
98
+
99
+ (def dox-show-src (src)
100
+ ; use the pretty-printer to elegantly display the given source code
101
+ (pp src))
@@ -66,6 +66,14 @@
66
66
  (let zi 10 "finds the ~{zi}th item")
67
67
  "finds the 10th item")
68
68
 
69
+ ("detects key presence"
70
+ (hash-key? { foo 1 bar 2 } 'foo)
71
+ t)
72
+
73
+ ("detects key absence"
74
+ (hash-key? { foo 1 bar 2 } 'zed)
75
+ nil)
76
+
69
77
  ("unquotes hash keys"
70
78
  (with (zi 'foo chi 'bar yi 'grr)
71
79
  (let hsh { ,zi 10 ,chi 11 ,yi 12 }
@@ -78,11 +86,6 @@
78
86
  (list "hello world" (hash-get hsh "hello world") "yesterday" (hash-get hsh "yesterday"))))
79
87
  ("hello world" 10 "yesterday" 11)))
80
88
 
81
- (suite "strings"
82
- ("length"
83
- (len "foo-bar")
84
- 7))
85
-
86
89
  (suite "list management"
87
90
  ("'pair breaks a list into pairs"
88
91
  (pairs '(1 a 2 b 3 c))
@@ -100,26 +103,6 @@
100
103
  (rev '(a b (c d e) f g))
101
104
  (g f (c d e) b a))
102
105
 
103
- ("joins elements into a string"
104
- (joinstr "" '("foo" "bar" "bax"))
105
- "foobarbax")
106
-
107
- ("joins separate elements into a string"
108
- (joinstr "/" "foo" "bar" "bax")
109
- "foo/bar/bax")
110
-
111
- ("joins a single thing"
112
- (joinstr "/" "foo")
113
- "foo")
114
-
115
- ("joins nested and separate elements into a string"
116
- (joinstr "/" "foo" "bar" '(twiddle diddle) "bax")
117
- "foo/bar/twiddle/diddle/bax")
118
-
119
- ("joins elements into a string"
120
- (joinstr " - " '(1 2 3))
121
- "1 - 2 - 3")
122
-
123
106
  ("'flatten returns a flat list of things"
124
107
  (flatten '((poo (x) (* x x)) (1 2 3)))
125
108
  (poo x * x x 1 2 3)))
@@ -0,0 +1,103 @@
1
+ (mac this-is-a-well-documented-macro (a b c)
2
+ ; documentation for me!
3
+ `(foo ,a ,b ,c))
4
+
5
+ (mac this-is-an-undocumented-macro (a b c)
6
+ `(baz ,a ,b ,c))
7
+
8
+ (def this-is-a-well-documented-def (a b c)
9
+ ; documentation for me!
10
+ (foo a b c))
11
+
12
+ (def this-is-an-undocumented-def (a b c)
13
+ (baz a b c))
14
+
15
+ (register-test
16
+ '(suite "Documentation Tests"
17
+ (suite "comment detection"
18
+ ("identify comment"
19
+ (isa-comment? '(comment "yes, it is"))
20
+ t)
21
+
22
+ ("identify non-comment"
23
+ (isa-comment? "not this time")
24
+ nil))
25
+
26
+ (suite "gather comments from 'body argument"
27
+ ("no comment"
28
+ (dox-gather-comments '((this) (that)))
29
+ (nil ((this) (that))))
30
+
31
+ ("one comment"
32
+ (dox-gather-comments '((comment "hello") (this) (that)))
33
+ (("hello") ((this) (that))))
34
+
35
+ ("more comments"
36
+ (dox-gather-comments '((comment "hello")
37
+ (comment "more details")
38
+ (comment "very rigourous")
39
+ (this)
40
+ (that)))
41
+ (("hello" "more details" "very rigourous") ((this) (that)))))
42
+
43
+ (suite "mac"
44
+ ("a documented macro"
45
+ (dox-lookup 'this-is-a-well-documented-macro)
46
+ ((this-is-a-well-documented-macro
47
+ mac
48
+ ("documentation for me!")
49
+ (a b c)
50
+ (mac this-is-a-well-documented-macro (a b c)
51
+ `(foo ,a ,b ,c)))))
52
+
53
+ ("arg list"
54
+ (dox-arg-names 'this-is-a-well-documented-macro)
55
+ (a b c))
56
+
57
+ ("src"
58
+ (dox-src 'this-is-a-well-documented-macro)
59
+ (mac this-is-a-well-documented-macro (a b c) (quasiquote (foo (unquote a) (unquote b) (unquote c)))))
60
+
61
+ ("is a def"
62
+ (dox-what-is? 'this-is-a-well-documented-macro)
63
+ mac)
64
+
65
+ ("an undocumented macro"
66
+ (dox-lookup 'this-is-an-undocumented-macro)
67
+ ((this-is-an-undocumented-macro
68
+ mac
69
+ nil
70
+ (a b c)
71
+ (mac this-is-an-undocumented-macro (a b c)
72
+ `(baz ,a ,b ,c)))))
73
+
74
+ (suite "def"
75
+ ("a documented def"
76
+ (dox-lookup 'this-is-a-well-documented-def)
77
+ ((this-is-a-well-documented-def
78
+ def
79
+ ("documentation for me!")
80
+ (a b c)
81
+ (def this-is-a-well-documented-def (a b c)
82
+ (foo a b c)))))
83
+
84
+ ("arg list"
85
+ (dox-arg-names 'this-is-a-well-documented-def)
86
+ (a b c))
87
+
88
+ ("is a def"
89
+ (dox-what-is? 'this-is-a-well-documented-def)
90
+ def)
91
+
92
+ ("src"
93
+ (dox-src 'this-is-a-well-documented-def)
94
+ (def this-is-a-well-documented-def (a b c) (foo a b c)))
95
+
96
+ ("an undocumented def"
97
+ (dox-lookup 'this-is-an-undocumented-def)
98
+ ((this-is-an-undocumented-def
99
+ def
100
+ nil
101
+ (a b c)
102
+ (def this-is-an-undocumented-def (a b c)
103
+ (baz a b c)))))))))
@@ -0,0 +1,66 @@
1
+ (register-test
2
+ '(suite "List Tests"
3
+ (suite "firstn"
4
+ ("returns no items for n = 0"
5
+ (firstn 0 '(a b c d))
6
+ nil)
7
+
8
+ ("returns first n items for n > 0 and n < size of list"
9
+ (firstn 3 '(a b c d e))
10
+ (a b c))
11
+
12
+ ("returns all items for n > size of list"
13
+ (firstn 33 '(a b c d e))
14
+ (a b c d e)))
15
+
16
+ (suite "nthcdr"
17
+ ("returns all items for n = 0"
18
+ (nthcdr 0 '(a b c d))
19
+ (a b c d))
20
+
21
+ ("returns nth cdr of list for n > 0 and n < size of list"
22
+ (nthcdr 3 '(a b c d e))
23
+ (d e))
24
+
25
+ ("returns nothing for n > size of list"
26
+ (nthcdr 33 '(a b c d e))
27
+ nil))
28
+
29
+ (suite "car/cdr combinations"
30
+ ("caar of list" (caar '((x y) (1 2))) x )
31
+ ("caar of nil" (caar nil) nil )
32
+ ("cadr of list" (cadr '((x y) (1 2))) (1 2) )
33
+ ("cadr of nil" (cadr nil) nil )
34
+ ("cdar of list" (cdar '((x y) (1 2))) (y) )
35
+ ("cdar of nil" (cdar nil) nil )
36
+ ("cddr of list" (cddr '(x y 1 2)) (1 2) )
37
+ ("cddr of nil" (cddr nil) nil )
38
+ ("cadar of list" (cadar '((x y) (1 2))) y )
39
+ ("cadar of nil" (cadar nil) nil )
40
+ ("caddr of list" (caddr '(x y 1 2)) 1 )
41
+ ("caddr of nil" (caddr nil) nil )
42
+ ("cdddr of list" (cdddr '(x y 1 2)) (2) )
43
+ ("cdddr of nil" (cdddr nil) nil )
44
+ ("cadddr of list" (cadddr '(x y 1 2 3)) 2 )
45
+ ("cadddr of nil" (cadddr nil) nil ))
46
+
47
+ (suite "proper?"
48
+ ("t for a proper list"
49
+ (proper? '(a b c d))
50
+ t)
51
+
52
+ ("t for a proper list, even if we write it funny"
53
+ (proper? '(a b . (c d)))
54
+ t)
55
+
56
+ ("t for a proper list, even if we write it funny with nil"
57
+ (proper? '(a b . nil))
58
+ t)
59
+
60
+ ("nil for an improper list"
61
+ (proper? '(a b . c))
62
+ nil)
63
+
64
+ ("nil for a very improper list"
65
+ (proper? '(a b . (c . d)))
66
+ nil))))
@@ -0,0 +1,25 @@
1
+ (register-test
2
+ '(suite "Pretty Printing Tests"
3
+ ("a macro invocation"
4
+ (pp '(mac pp/def (name args . body) `(hash-set pp/special-forms ',name (fn ,args ,@body))))
5
+ "(mac pp/def (name args body)\n `(hash-set pp/special-forms ',name (fn ,args ,@body)))")
6
+
7
+ ("a 'def invocation"
8
+ (pp '(def pp (form) (pp/main form 0)))
9
+ "(def pp (form)\n (pp/main form 0))")
10
+
11
+ ("combined with dox system"
12
+ (pp:dox-src 'pp/find-breaks)
13
+ "(def pp/find-breaks (form)
14
+ (if (eq? 'if (car form))
15
+ (let if-args (cdr form)
16
+ (cons (list 'if (car if-args)) (map list (cdr if-args))))
17
+ (or
18
+ (pp/find-breaks/mac form)
19
+ (list form))))")
20
+
21
+ ("special syntax"
22
+ (pp '(string-pieces "hello " (bang-syntax || (dot-syntax x y (ampersand-syntax foo bar))) " and welcome to " (prefix-list "%%" (a b c d)) " and friends!"))
23
+ "\"hello ~~!x.y.foo&bar and welcome to ~~%%(a b c d) and friends!\"")
24
+
25
+ ))
@@ -0,0 +1,31 @@
1
+ (register-test
2
+ '(suite "String Tests"
3
+ (suite "length"
4
+ ("nonzero" (len "foo-bar") 7)
5
+ ("zero" (len "") 0))
6
+
7
+ (suite "joinstr"
8
+ ("joins elements into a string"
9
+ (joinstr "" '("foo" "bar" "bax"))
10
+ "foobarbax")
11
+
12
+ ("joins separate elements into a string"
13
+ (joinstr "/" "foo" "bar" "bax")
14
+ "foo/bar/bax")
15
+
16
+ ("joins a single thing"
17
+ (joinstr "/" "foo")
18
+ "foo")
19
+
20
+ ("joins nested and separate elements into a string"
21
+ (joinstr "/" "foo" "bar" '(twiddle diddle) "bax")
22
+ "foo/bar/twiddle/diddle/bax")
23
+
24
+ ("joins elements into a string"
25
+ (joinstr " - " '(1 2 3))
26
+ "1 - 2 - 3"))
27
+
28
+ (suite "strip"
29
+ ("removes leading whitespace" (string-strip " hello!") "hello!" )
30
+ ("removes trailing whitespace" (string-strip "(world) ") "(world)" )
31
+ ("removes leading and trailing whitespace" (string-strip "\n\nme\n\n") "me" ))))
@@ -0,0 +1,7 @@
1
+ (register-test '(suite "pair to-string"
2
+ ("unquote" (to-string '(unquote a)) ",a" )
3
+ ("quote" (to-string '(quote a)) "'a" )
4
+ ("quasiquote" (to-string '(quasiquote a)) "`a" )
5
+ ("unquote-splicing" (to-string '(unquote-splicing a)) ",@a" )
6
+ ("brace-list" (to-string '(brace-list a b c d)) "{ a b c d }" )
7
+ ))
@@ -74,6 +74,24 @@ class Nydp::Builtin::HashKeys
74
74
  end
75
75
  end
76
76
 
77
+ class Nydp::Builtin::HashKeyPresent
78
+ include Nydp::Helper, Nydp::Builtin::Base
79
+ attr_accessor :ns
80
+ def initialize ns ; @ns = ns; end
81
+ def builtin_invoke vm, args
82
+ hash = args.car
83
+ key = args.cdr.car
84
+ truth = case hash
85
+ when Nydp::Hash
86
+ hash.key? key
87
+ else
88
+ hash.key? n2r key
89
+ end
90
+ vm.push_arg(truth ? Nydp.T : Nydp.NIL)
91
+ end
92
+ def name ; "hash-key?" ; end
93
+ end
94
+
77
95
  class Nydp::Builtin::HashMerge
78
96
  include Nydp::Helper, Nydp::Builtin::Base
79
97
 
@@ -2,8 +2,12 @@ class Nydp::Builtin::Puts
2
2
  include Nydp::Builtin::Base
3
3
 
4
4
  def builtin_invoke vm, args
5
- s = args.map { |a| a.to_s }
6
- puts s.join ' '
5
+ if Nydp.NIL.is? args
6
+ puts
7
+ else
8
+ s = args.map { |a| a.to_s }
9
+ puts s.join ' '
10
+ end
7
11
  vm.push_arg args.car
8
12
  end
9
13
 
data/lib/nydp/core.rb CHANGED
@@ -63,6 +63,7 @@ module Nydp
63
63
  Symbol.mk(:"hash-get", ns).assign(Nydp::Builtin::HashGet.new ns)
64
64
  Symbol.mk(:"hash-set", ns).assign(Nydp::Builtin::HashSet.new)
65
65
  Symbol.mk(:"hash-keys", ns).assign(Nydp::Builtin::HashKeys.new(ns))
66
+ Symbol.mk(:"hash-key?", ns).assign(Nydp::Builtin::HashKeyPresent.new(ns))
66
67
  Symbol.mk(:"hash-merge", ns).assign(Nydp::Builtin::HashMerge.new)
67
68
  Symbol.mk(:"vm-info", ns).assign Nydp::Builtin::VmInfo.new
68
69
  Symbol.mk(:"pre-compile", ns).assign Nydp::Builtin::PreCompile.new
data/lib/nydp/hash.rb CHANGED
@@ -3,15 +3,8 @@ class Nydp::Hash < ::Hash
3
3
 
4
4
  def nydp_type ; :hash ; end
5
5
  def to_ruby
6
- @_ruby_hash ||= Hash.new { |h, k|
7
- self[case k
8
- when String
9
- Nydp::StringAtom.new(k)
10
- when Symbol
11
- Nydp::Symbol.new(k)
12
- else
13
- k
14
- end]
15
- }
6
+ h = Hash.new
7
+ self.each { |k,v| h[n2r k] = n2r v }
8
+ h
16
9
  end
17
10
  end
data/lib/nydp/pair.rb CHANGED
@@ -75,6 +75,12 @@ class Nydp::Pair
75
75
  else
76
76
  "'#{cdr.to_s}"
77
77
  end
78
+ elsif car.is_a?(Nydp::Symbol) && car.is?(:"brace-list")
79
+ if Nydp.NIL.is? cdr.cdr
80
+ "{}"
81
+ else
82
+ "{ #{cdr.to_s_rest} }"
83
+ end
78
84
  elsif car.is_a?(Nydp::Symbol) && car.is?(:quasiquote)
79
85
  if Nydp.NIL.is? cdr.cdr
80
86
  "`#{cdr.car.to_s}"
data/lib/nydp/parser.rb CHANGED
@@ -105,7 +105,7 @@ module Nydp
105
105
  when :symbol
106
106
  parse_symbol token.last
107
107
  when :comment
108
- Pair.from_list [sym(:comment), token.last]
108
+ Pair.from_list [sym(:comment), Nydp::StringAtom.new(token.last)]
109
109
  else
110
110
  token.last
111
111
  end
data/lib/nydp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Nydp
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/spec/hash_spec.rb CHANGED
@@ -24,6 +24,7 @@ describe Nydp::Hash do
24
24
 
25
25
  rhash = hash.to_ruby
26
26
  expect(rhash[:boo]).to eq 42
27
+ expect(rhash.keys) .to eq [:boo]
27
28
  end
28
29
 
29
30
  it "converts ruby string key to nydp string key" do
@@ -32,6 +33,7 @@ describe Nydp::Hash do
32
33
 
33
34
  rhash = hash.to_ruby
34
35
  expect(rhash["boo"]).to eq 42
36
+ expect(rhash.keys) .to eq ["boo"]
35
37
  end
36
38
 
37
39
  it "uses integer keys unconverted" do
@@ -40,6 +42,7 @@ describe Nydp::Hash do
40
42
 
41
43
  rhash = hash.to_ruby
42
44
  expect(rhash[21]).to eq 42
45
+ expect(rhash.keys) .to eq [21]
43
46
  end
44
47
  end
45
48
 
@@ -92,6 +95,28 @@ describe Nydp::Hash do
92
95
  end
93
96
  end
94
97
 
98
+ describe "key?" do
99
+ it "returns t when key is present" do
100
+ h = Nydp::Hash.new
101
+ k = sym "jerry"
102
+ v = 42
103
+ h[k] = v
104
+
105
+ Nydp::Builtin::HashKeyPresent.new(ns).invoke vm, pair_list([h, k])
106
+
107
+ expect(vm.pop_arg).to eq Nydp.T
108
+ end
109
+
110
+ it "returns nil when key is absent" do
111
+ h = Nydp::Hash.new
112
+ k = sym "benjamin"
113
+
114
+ Nydp::Builtin::HashKeyPresent.new(ns).invoke vm, pair_list([h, k])
115
+
116
+ expect(vm.pop_arg).to eq Nydp.NIL
117
+ end
118
+ end
119
+
95
120
  describe "hash keys" do
96
121
  it "returns a list of keys" do
97
122
  h = Nydp::Hash.new
@@ -154,6 +179,27 @@ describe Nydp::Hash do
154
179
  end
155
180
  end
156
181
 
182
+ describe "key?" do
183
+ it "returns t when key is present" do
184
+ ahash[:simon] = 24
185
+ k = sym("simon")
186
+ args = [ ahash, k ]
187
+
188
+ Nydp::Builtin::HashKeyPresent.new(ns).invoke vm, pair_list(args)
189
+
190
+ expect(vm.pop_arg).to eq Nydp.T
191
+ end
192
+
193
+ it "returns nil when key is absent" do
194
+ k = sym("simon")
195
+ args = [ ahash, k ]
196
+
197
+ Nydp::Builtin::HashKeyPresent.new(ns).invoke vm, pair_list(args)
198
+
199
+ expect(vm.pop_arg).to eq Nydp.NIL
200
+ end
201
+ end
202
+
157
203
  describe "hash keys" do
158
204
  it "returns a list of keys" do
159
205
  ahash[:k0] = 42
data/spec/pair_spec.rb CHANGED
@@ -8,6 +8,14 @@ describe Nydp::Pair do
8
8
  let(:foo) { Nydp::Symbol.mk :foo, ns }
9
9
  let(:dot) { Nydp::Symbol.mk ".".to_sym, ns }
10
10
 
11
+ describe "#map" do
12
+ it "behaves like ruby #map" do
13
+ list = pair_list [1,2,3]
14
+ mapped = list.map { |x| x * 2 }
15
+ expect(mapped).to eq [2,4,6]
16
+ end
17
+ end
18
+
11
19
  describe :== do
12
20
  it "should be true for two empty lists" do
13
21
  expect(Nydp::Pair.new(NIL, NIL)).to eq Nydp::Pair.new(NIL, NIL)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nydp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Conan Dalton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-09 00:00:00.000000000 Z
11
+ date: 2015-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -84,23 +84,30 @@ files:
84
84
  - Rakefile
85
85
  - bin/nydp
86
86
  - bin/nydp-tests
87
- - lib/lisp/core-00.nydp
88
- - lib/lisp/core-01-precompile.nydp
89
- - lib/lisp/core-02-utils.nydp
90
- - lib/lisp/core-03-syntax.nydp
91
- - lib/lisp/core-04-utils.nydp
92
- - lib/lisp/core-05-test-runner.nydp
93
- - lib/lisp/core-06-benchmarking.nydp
94
- - lib/lisp/core-07-prefix-list.nydp
87
+ - lib/lisp/core-000.nydp
88
+ - lib/lisp/core-010-precompile.nydp
89
+ - lib/lisp/core-015-documentation.nydp
90
+ - lib/lisp/core-020-utils.nydp
91
+ - lib/lisp/core-030-syntax.nydp
92
+ - lib/lisp/core-040-utils.nydp
93
+ - lib/lisp/core-050-test-runner.nydp
94
+ - lib/lisp/core-060-benchmarking.nydp
95
+ - lib/lisp/core-070-prefix-list.nydp
96
+ - lib/lisp/core-080-pretty-print.nydp
95
97
  - lib/lisp/tests/boot-tests.nydp
96
98
  - lib/lisp/tests/builtin-tests.nydp
99
+ - lib/lisp/tests/dox-tests.nydp
97
100
  - lib/lisp/tests/dynamic-scope-test.nydp
98
101
  - lib/lisp/tests/each-tests.nydp
99
102
  - lib/lisp/tests/error-tests.nydp
100
103
  - lib/lisp/tests/foundation-test.nydp
101
104
  - lib/lisp/tests/invocation-tests.nydp
105
+ - lib/lisp/tests/list-tests.nydp
102
106
  - lib/lisp/tests/parser-tests.nydp
107
+ - lib/lisp/tests/pretty-print-tests.nydp
108
+ - lib/lisp/tests/string-tests.nydp
103
109
  - lib/lisp/tests/syntax-tests.nydp
110
+ - lib/lisp/tests/unparse-tests.nydp
104
111
  - lib/nydp.rb
105
112
  - lib/nydp/assignment.rb
106
113
  - lib/nydp/builtin.rb
@@ -1,13 +0,0 @@
1
- ; -*- lisp -*-
2
- ;;
3
- ;; Acknowledgements to Paul Graham. Some nydp features (including,
4
- ;; but not limited to, 'do, 'rfn, 'loop, 'for) are stolen directly from arc.arc
5
- ;;
6
-
7
- (assign list (fn args args))
8
- (assign caar (fn (arg) (car (car arg))))
9
- (assign cadr (fn (arg) (car (cdr arg))))
10
- (assign cdar (fn (arg) (cdr (car arg))))
11
- (assign cddr (fn (arg) (cdr (cdr arg))))
12
- (assign no (fn (arg) (cond arg nil t)))
13
- (assign just (fn (arg) arg))
@@ -1,6 +0,0 @@
1
- (def map (f things)
2
- (if (no things)
3
- nil
4
- (pair? things)
5
- (cons (f (car things)) (map f (cdr things)))
6
- (map f (list things))))
@@ -1,26 +0,0 @@
1
-
2
- (assign prefix-list-prefixes ())
3
-
4
- (def prefix-match-fn (txt)
5
- (fn (rule) (string-match txt (car rule))))
6
-
7
- (def find-prefix-rule (prefix)
8
- (cdr:detect (prefix-match-fn prefix)
9
- prefix-list-prefixes))
10
-
11
- (mac prefix-list (prefix list)
12
- (let handler (find-prefix-rule prefix)
13
- (and handler (handler prefix list))))
14
-
15
- (mac define-prefix-list-macro (regex prefix-var list-var . body)
16
- `(push (cons ,regex (fn (,prefix-var ,list-var) ,@body))
17
- prefix-list-prefixes))
18
-
19
- ;;
20
- ;; so you can write (map λa(upcase a.name) people)
21
- ;;
22
- ;; instead of (map (fn (a) (upcase a.name)) people)
23
- ;;
24
- (define-prefix-list-macro "^λ.+" vars expr
25
- (let var-list (map sym (cdr:string-split vars))
26
- `(fn ,var-list ,expr)))