nydp 0.1.0 → 0.1.1

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 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)))