nydp 0.5.1 → 0.6.0

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.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +77 -56
  4. data/lib/lisp/core-000.nydp +1 -1
  5. data/lib/lisp/core-010-precompile.nydp +49 -29
  6. data/lib/lisp/core-012-utils.nydp +12 -8
  7. data/lib/lisp/core-015-documentation.nydp +41 -15
  8. data/lib/lisp/core-017-builtin-dox.nydp +621 -100
  9. data/lib/lisp/core-020-utils.nydp +33 -6
  10. data/lib/lisp/core-025-warnings.nydp +1 -1
  11. data/lib/lisp/core-030-syntax.nydp +64 -48
  12. data/lib/lisp/core-035-flow-control.nydp +20 -28
  13. data/lib/lisp/core-037-list-utils.nydp +84 -21
  14. data/lib/lisp/core-040-utils.nydp +8 -5
  15. data/lib/lisp/core-041-string-utils.nydp +17 -11
  16. data/lib/lisp/core-043-list-utils.nydp +140 -77
  17. data/lib/lisp/core-045-dox-utils.nydp +1 -0
  18. data/lib/lisp/core-050-test-runner.nydp +8 -12
  19. data/lib/lisp/core-070-prefix-list.nydp +19 -15
  20. data/lib/lisp/core-080-pretty-print.nydp +13 -5
  21. data/lib/lisp/core-090-hook.nydp +11 -11
  22. data/lib/lisp/core-100-utils.nydp +51 -66
  23. data/lib/lisp/core-110-hash-utils.nydp +34 -7
  24. data/lib/lisp/core-120-settings.nydp +14 -9
  25. data/lib/lisp/core-130-validations.nydp +28 -13
  26. data/lib/lisp/core-900-benchmarking.nydp +420 -47
  27. data/lib/lisp/tests/000-empty-args-examples.nydp +5 -0
  28. data/lib/lisp/tests/andify-examples.nydp +1 -1
  29. data/lib/lisp/tests/auto-hash-examples.nydp +6 -1
  30. data/lib/lisp/tests/best-examples.nydp +1 -1
  31. data/lib/lisp/tests/boot-tests.nydp +1 -1
  32. data/lib/lisp/tests/date-examples.nydp +129 -102
  33. data/lib/lisp/tests/destructuring-examples.nydp +1 -1
  34. data/lib/lisp/tests/dox-tests.nydp +2 -2
  35. data/lib/lisp/tests/hash-examples.nydp +58 -33
  36. data/lib/lisp/tests/list-tests.nydp +137 -1
  37. data/lib/lisp/tests/pretty-print-tests.nydp +12 -0
  38. data/lib/lisp/tests/rotate-2d-array-examples.nydp +26 -0
  39. data/lib/lisp/tests/sort-examples.nydp +5 -5
  40. data/lib/lisp/tests/string-tests.nydp +16 -5
  41. data/lib/lisp/tests/syntax-tests.nydp +10 -2
  42. data/lib/lisp/tests/time-examples.nydp +8 -1
  43. data/lib/lisp/tests/unparse-tests.nydp +13 -7
  44. data/lib/nydp/assignment.rb +15 -28
  45. data/lib/nydp/builtin/abs.rb +4 -3
  46. data/lib/nydp/builtin/apply.rb +8 -10
  47. data/lib/nydp/builtin/cdr_set.rb +1 -1
  48. data/lib/nydp/builtin/comment.rb +1 -3
  49. data/lib/nydp/builtin/date.rb +11 -28
  50. data/lib/nydp/builtin/divide.rb +3 -10
  51. data/lib/nydp/builtin/ensuring.rb +6 -21
  52. data/lib/nydp/builtin/error.rb +2 -4
  53. data/lib/nydp/builtin/eval.rb +9 -4
  54. data/lib/nydp/builtin/greater_than.rb +7 -8
  55. data/lib/nydp/builtin/handle_error.rb +10 -34
  56. data/lib/nydp/builtin/hash.rb +24 -45
  57. data/lib/nydp/builtin/inspect.rb +1 -3
  58. data/lib/nydp/builtin/is_equal.rb +4 -7
  59. data/lib/nydp/builtin/less_than.rb +6 -7
  60. data/lib/nydp/builtin/log.rb +7 -0
  61. data/lib/nydp/builtin/math_ceiling.rb +1 -3
  62. data/lib/nydp/builtin/math_floor.rb +1 -3
  63. data/lib/nydp/builtin/math_power.rb +1 -3
  64. data/lib/nydp/builtin/math_round.rb +2 -2
  65. data/lib/nydp/builtin/minus.rb +7 -14
  66. data/lib/nydp/builtin/parse.rb +5 -5
  67. data/lib/nydp/builtin/parse_in_string.rb +5 -7
  68. data/lib/nydp/builtin/plus.rb +14 -31
  69. data/lib/nydp/builtin/pre_compile.rb +1 -3
  70. data/lib/nydp/builtin/puts.rb +4 -8
  71. data/lib/nydp/builtin/quit.rb +1 -1
  72. data/lib/nydp/builtin/rand.rb +6 -11
  73. data/lib/nydp/builtin/random_string.rb +2 -4
  74. data/lib/nydp/builtin/rng.rb +25 -0
  75. data/lib/nydp/builtin/ruby_wrap.rb +27 -14
  76. data/lib/nydp/builtin/script_run.rb +1 -3
  77. data/lib/nydp/builtin/set_intersection.rb +3 -4
  78. data/lib/nydp/builtin/set_union.rb +3 -4
  79. data/lib/nydp/builtin/sort.rb +2 -7
  80. data/lib/nydp/builtin/string_match.rb +5 -13
  81. data/lib/nydp/builtin/string_replace.rb +2 -7
  82. data/lib/nydp/builtin/string_split.rb +3 -8
  83. data/lib/nydp/builtin/sym.rb +2 -9
  84. data/lib/nydp/builtin/thread_locals.rb +2 -2
  85. data/lib/nydp/builtin/time.rb +38 -44
  86. data/lib/nydp/builtin/times.rb +6 -15
  87. data/lib/nydp/builtin/to_integer.rb +8 -14
  88. data/lib/nydp/builtin/to_string.rb +2 -13
  89. data/lib/nydp/builtin/type_of.rb +10 -16
  90. data/lib/nydp/builtin/vm_info.rb +2 -10
  91. data/lib/nydp/builtin.rb +15 -37
  92. data/lib/nydp/compiler.rb +29 -19
  93. data/lib/nydp/cond.rb +95 -88
  94. data/lib/nydp/context_symbol.rb +11 -9
  95. data/lib/nydp/core.rb +74 -73
  96. data/lib/nydp/core_ext.rb +87 -26
  97. data/lib/nydp/date.rb +22 -19
  98. data/lib/nydp/error.rb +2 -3
  99. data/lib/nydp/function_invocation.rb +76 -289
  100. data/lib/nydp/helper.rb +18 -9
  101. data/lib/nydp/interpreted_function.rb +159 -25
  102. data/lib/nydp/lexical_context.rb +9 -8
  103. data/lib/nydp/lexical_context_builder.rb +1 -1
  104. data/lib/nydp/literal.rb +3 -7
  105. data/lib/nydp/loop.rb +72 -0
  106. data/lib/nydp/namespace.rb +52 -0
  107. data/lib/nydp/pair.rb +146 -50
  108. data/lib/nydp/parser.rb +9 -11
  109. data/lib/nydp/plugin.rb +88 -19
  110. data/lib/nydp/runner.rb +141 -23
  111. data/lib/nydp/symbol.rb +16 -26
  112. data/lib/nydp/symbol_lookup.rb +3 -2
  113. data/lib/nydp/tokeniser.rb +1 -1
  114. data/lib/nydp/truth.rb +2 -37
  115. data/lib/nydp/version.rb +1 -1
  116. data/lib/nydp.rb +33 -44
  117. data/nydp.gemspec +2 -1
  118. data/spec/date_spec.rb +26 -32
  119. data/spec/embedded_spec.rb +22 -22
  120. data/spec/error_spec.rb +12 -16
  121. data/spec/foreign_hash_spec.rb +21 -36
  122. data/spec/hash_non_hash_behaviour_spec.rb +12 -29
  123. data/spec/hash_spec.rb +36 -49
  124. data/spec/literal_spec.rb +6 -6
  125. data/spec/nydp_spec.rb +14 -14
  126. data/spec/pair_spec.rb +8 -8
  127. data/spec/parser_spec.rb +41 -37
  128. data/spec/rand_spec.rb +1 -4
  129. data/spec/spec_helper.rb +3 -3
  130. data/spec/string_atom_spec.rb +15 -16
  131. data/spec/symbol_spec.rb +27 -52
  132. data/spec/thread_local_spec.rb +23 -8
  133. data/spec/time_spec.rb +4 -10
  134. data/spec/tokeniser_spec.rb +10 -10
  135. metadata +25 -13
  136. data/lib/nydp/builtin/modulo.rb +0 -11
  137. data/lib/nydp/builtin/regexp.rb +0 -7
  138. data/lib/nydp/builtin/sqrt.rb +0 -7
  139. data/lib/nydp/builtin/string_pad_left.rb +0 -7
  140. data/lib/nydp/builtin/string_pad_right.rb +0 -7
  141. data/lib/nydp/hash.rb +0 -9
  142. data/lib/nydp/image_store.rb +0 -21
  143. data/lib/nydp/vm.rb +0 -129
@@ -1,32 +1,59 @@
1
1
  (chapter-start 'list-manipulation)
2
2
 
3
- (def list-length (things)
4
- (if (atom? things) 1
5
- things (+ 1 (list-length (cdr things)))
6
- 0))
3
+ ;; each call to the name 'accfn-name with an arg will append the arg to the end of a list.
4
+ ;; This form returns the resulting list.
5
+ ;; Example (collect first names from a list of people)
6
+ ;;
7
+ ;; (accum a (each person people (a person.firstname)))
8
+ ;;
9
+ ;; will return (Alice Bob Carol Declan Eliza Fionn)
10
+ ;;
11
+ (mac accum (accfn-name . body)
12
+ (w/uniq (things last-cons)
13
+ `(with (,last-cons (cons)
14
+ ,things ,last-cons
15
+ ,accfn-name (fn (a)
16
+ (= ,last-cons (cdr-set ,last-cons (cons a)))
17
+ a)
18
+ accum-end (fn (a)
19
+ (= ,last-cons (cdr-set ,last-cons a))
20
+ a))
21
+ ,@body
22
+ (cdr ,things))))
7
23
 
24
+ (def list-length (things)
25
+ (let cc 0
26
+ (loop (pair? things)
27
+ (do
28
+ (++ cc)
29
+ (= things (cdr things))))
30
+ (if things (+ cc 1) cc)))
31
+
32
+ ;; slice 'things into a list of lists each with maximum 'slice-size items
8
33
  (def list-slices (things slice-size)
9
- ; slice 'things into a list of lists each with maximum 'slice-size items
10
- (chapter pagination)
11
- (if things
12
- (if (> slice-size (len things))
13
- (list things)
14
- (cons (firstn slice-size things)
15
- (list-slices (nthcdr slice-size things)
16
- slice-size)))
17
- nil))
18
-
34
+ (chapter pagination)
35
+ (if things
36
+ (if (> slice-size (len things))
37
+ (list things)
38
+ (cons (firstn slice-size things)
39
+ (list-slices (nthcdr slice-size things)
40
+ slice-size)))
41
+ nil))
42
+
43
+ ;; return a new list with 'inbetween in between every element of 'things
19
44
  (def intersperse (inbetween things)
20
- ; return a new list with 'inbetween in between every element of 'things
21
- (if (and (pair? things) (cdr things))
22
- (apply list (car things) inbetween
23
- (intersperse inbetween (cdr things)))
24
- things))
45
+ (accum i
46
+ (while (pair? things)
47
+ (i (car things))
48
+ (if (cdr things)
49
+ (i inbetween))
50
+ (= things (cdr things)))
51
+ (if things (accum-end things))))
25
52
 
26
53
  ;; expects 'things a list of lists, joins the lists
27
- ;; returns (a b X c d X e f)
28
54
  ;; placing 'inbetween in between each list.
29
55
  ;; For example (intersperse-splicing 'X '((a b) (c d) (e f)))
56
+ ;; returns (a b X c d X e f)
30
57
  (def intersperse-splicing (inbetween things)
31
58
  (apply joinlists (intersperse (list inbetween) things)))
32
59
 
@@ -34,15 +61,19 @@
34
61
  ;; otherwise, return 'things if (f things) is non-nil
35
62
  ;; otherwise, nil
36
63
  ;; note that this preserves improper lists and may return only the lastcdr if all else fails...
37
- (def collect (f items)
38
- (if (pair? items)
39
- (if (f (car items))
40
- (cons (car items)
41
- (collect f (cdr items)))
42
- (collect f (cdr items)))
43
- items
44
- (if (f items)
45
- items)))
64
+ (def collect-helper (f things res)
65
+ (loop (pair? things)
66
+ (do
67
+ (if (f (car things))
68
+ (= res (cdr-set res (cons (car things)))))
69
+ (= things (cdr things))))
70
+ (if (and things (f things))
71
+ (= res (cdr-set res things))))
72
+
73
+ (def collect (f things)
74
+ (let res (cons)
75
+ (collect-helper f things res)
76
+ (cdr res)))
46
77
 
47
78
  (assign select collect)
48
79
 
@@ -57,28 +88,46 @@
57
88
  (def reject (f things)
58
89
  (collect !f things))
59
90
 
60
- (def each/build-expression (var things body othervars otherparams)
61
- (w/uniq (xs c)
62
- `(rfnwith ,c (,xs ,things ,@othervars)
63
- (if (pair? ,xs)
64
- (let ,var (car ,xs)
65
- ,@body
66
- (,c (cdr ,xs) ,@otherparams))))))
67
-
68
91
  ;; repeatedly assigns an element of 'things to 'var,
69
92
  ;; and executes 'body each time
70
93
  (mac each (var things . body)
71
- (each/build-expression var things body))
72
-
94
+ (w/uniq xs
95
+ `(let ,xs ,things
96
+ (loop ,xs
97
+ (let ,var (car ,xs)
98
+ ,@body
99
+ (= ,xs (cdr ,xs)))))))
100
+
101
+ ;; repeatedly assigns an element of 'things to 'var, increments 'ivar,
102
+ ;; and executes 'body each time
73
103
  (mac each-with-index (ivar var things . body)
74
- (each/build-expression var things body `(,ivar 0) `((+ ,ivar 1))))
104
+ (w/uniq xs
105
+ `(with (,xs ,things ,ivar 0)
106
+ (loop ,xs
107
+ (let ,var (car ,xs)
108
+ ,@body
109
+ (++ ,ivar)
110
+ (= ,xs (cdr ,xs)))))))
111
+
112
+
113
+ ;; used internally by 'reduce
114
+ (def reduce-helper (f a things)
115
+ (loop (pair? things)
116
+ (= a (f a (car things))
117
+ things (cdr things)))
118
+ (if things
119
+ (= a (f a things)))
120
+ a)
75
121
 
122
+ ;; applies f to each element of 'things and the result of f, returning the result
123
+ ;;
124
+ ;; for example, (reduce + '(1 2 3)) returns 6
125
+ ;;
76
126
  (def reduce (f things)
77
- (rfnwith rd (acc (car things) list (cdr things))
78
- (if (pair? list)
79
- (rd (f acc (car list))
80
- (cdr list))
81
- acc)))
127
+ (if (pair? things)
128
+ (reduce-helper f (car things) (cdr things))
129
+ things
130
+ (f things)))
82
131
 
83
132
  ;; t if this is a proper list (last cdr is nil)
84
133
  ;; nil otherwise (last cdr is neither cons nor nil)
@@ -94,17 +143,11 @@
94
143
  (firstn (- n 1)
95
144
  (cdr things)))))
96
145
 
97
- (def nthcdr (n things)
98
- ; returns the nth cdr of the list 'things
99
- (if (> n 0)
100
- (nthcdr (- n 1) (cdr things))
101
- things))
102
-
146
+ ;; return a new list which is the concatenation of all the given lists
147
+ ;; 'things is a list
148
+ ;; 'more-thingses is a list of lists
149
+ ;; call like this: (joinlists '(a b c) '(x y z) '(1 2 3))
103
150
  (def joinlists (things . more-thingses)
104
- ; return a new list which is the concatenation of all the given lists
105
- ; 'things is a list
106
- ; 'more-thingses is a list of lists
107
- ; call like this: (joinlists '(a b c) '(x y z) '(1 2 3))
108
151
  (if things
109
152
  (cons (car things)
110
153
  (apply joinlists
@@ -113,28 +156,28 @@
113
156
  more-thingses
114
157
  (apply joinlists more-thingses)))
115
158
 
159
+ (def detect-helper (f things found)
160
+ (loop (and (no found) (pair? things))
161
+ (let it (car things)
162
+ (= found (and (f it) (or it t))
163
+ things (cdr things))))
164
+ (if (and (no found) things)
165
+ (= found (and (f things) things)))
166
+ found)
167
+
168
+ ;; if 'f is a function,
169
+ ;; if 'things is a list, return the first item in the list for which 'f returns non-nil
170
+ ;; otherwise, return 'things if (f things) is non-nil
171
+ ;; otherwise, nil
172
+ ;; if 'f is not a function, self-invoke with a function checking for equality with f
173
+ ;;
174
+ ;; WARNING: if the detected thing is nil, returns t instead. A return value of nil
175
+ ;; means the thing was not found ; non-nil means the thing was found, including when
176
+ ;; the found thing is itself nil.
116
177
  (def detect (f things)
117
- ; if 'f is a function,
118
- ; if 'things is a list, return the first item in the list for which 'f returns non-nil
119
- ; otherwise, return 'things if (f things) is non-nil
120
- ; otherwise, nil
121
- ; if 'f is not a function, self-invoke with a function checking for equality with f
122
- ;
123
- ; WARNING: if the detected thing is nil, returns t instead. A return value of nil
124
- ; means the thing was not found ; non-nil means the thing was found, including when
125
- ; the found thing is itself nil.
126
178
  (if (isa 'fn f)
127
- (rfnwith d (items things)
128
- (if (pair? items)
129
- (let it (car items)
130
- (or
131
- (and (f it)
132
- (or it t))
133
- (d:cdr items)))
134
- (f items)
135
- items))
136
- (detect (curry eq? f)
137
- things)))
179
+ (detect-helper f things nil)
180
+ (detect-helper (fn (thing) (eq? f thing)) things nil)))
138
181
 
139
182
  ;; split things into a list of lists each n long
140
183
  (def tuples (n things)
@@ -148,7 +191,9 @@
148
191
  ;; "better-p" -> takes two args a and b, return t if a is "better" than b, nil otherwise
149
192
  (def best (better-p things)
150
193
  (reduce (fn (a b)
151
- (if (better-p a b) a b))
194
+ (if (no b) a
195
+ (no a) b
196
+ (better-p a b) a b))
152
197
  things))
153
198
 
154
199
  (def min things (best < things))
@@ -235,9 +280,19 @@
235
280
  (matchers things)
236
281
  t))
237
282
 
238
- ; given an arg 'f, invoke 'f with no args
283
+ ;; given an arg 'f, invoke 'f with no args
239
284
  (def self-invoke (f) (f))
240
285
 
286
+ ;; returns a function @r@ that takes one argument, @f@
287
+ ;; which when called, applies @f@ to the given @args@
288
+ ;;
289
+ ;; example: @(map (self-invoker 3) (list sqrt sqr ln inv exp fib fact))@
290
+ ;; returns (1.732 9 1.098 0.333 20.085 4 6)
291
+ ;; being respectively the sqrt, square, log, inverse, e**x, fibonacci, factorial of 3 (assuming such functions are previously defined)
292
+ ;;
293
+ (def self-invoker args
294
+ λf(apply f args))
295
+
241
296
  ;; returns the first element of 'things iff it is the only element of 'things
242
297
  (def list-single-element (things)
243
298
  (if (no (cdr things)) (car things)))
@@ -247,3 +302,11 @@
247
302
  (let c (counter)
248
303
  (map (fn (thing) (f thing (c)))
249
304
  things)))
305
+
306
+ ;; takes a list of lists, returns a list of lists
307
+ ;; transforms ((1 2 3) (a b c) (+ - *)) into ((1 a +) (2 b -) (3 c *))
308
+ ;; the number of lists returned will be the number of items in the first of the given lists
309
+ (def rotate-2d-array (list-of-lists)
310
+ (with (size (len:car list-of-lists)
311
+ maps (map (fn (i) (fn (things) (nth i things))) (range 0 size)))
312
+ (map (fn (mapper) (map mapper list-of-lists)) maps)))
@@ -75,6 +75,7 @@ Examples for ~name
75
75
  nil
76
76
  target))))
77
77
 
78
+ ;; like mac-expand but only goes n steps
78
79
  (def explain-mac (n expr)
79
80
  (if (eq? n 0)
80
81
  expr
@@ -1,8 +1,8 @@
1
1
  (assign show-failed-only t)
2
2
  (assign all-tests nil)
3
3
 
4
+ ;; register a test to be run later by 'run-all-tests
4
5
  (def register-test (test)
5
- ; register a test to be run later by 'run-all-tests
6
6
  (push test all-tests))
7
7
 
8
8
  (def run-all-tests (verbose)
@@ -37,17 +37,13 @@
37
37
  (failf))))))
38
38
 
39
39
  (def execute-tests (desc tests passf failf verbose)
40
- (execute-test desc
41
- (car tests)
42
- passf
43
- failf
44
- verbose)
45
- (if (cdr tests)
46
- (execute-tests desc
47
- (cdr tests)
48
- passf
49
- failf
50
- verbose)))
40
+ (while tests
41
+ (execute-test desc
42
+ (car tests)
43
+ passf
44
+ failf
45
+ verbose)
46
+ (= tests (cdr tests))))
51
47
 
52
48
  (mac examples-for (name . examples)
53
49
  (let suite-name "examples for ~(pp name)"
@@ -1,4 +1,3 @@
1
-
2
1
  (assign prefix-list-prefixes ())
3
2
 
4
3
  (def prefix-match-fn (txt)
@@ -6,28 +5,33 @@
6
5
 
7
6
  (def find-prefix-rule (prefix)
8
7
  (cdr:detect (prefix-match-fn prefix)
9
- prefix-list-prefixes))
8
+ prefix-list-prefixes))
10
9
 
10
+ ;; looks up a handler in 'prefix-list-prefixes
11
+ ;; whose 'car matches the prefix, and whose 'cdr
12
+ ;; is a function, which behaves like a macro, in that
13
+ ;; it processes the prefix name and the prefixed list,
14
+ ;; returning more code
11
15
  (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
16
  (let handler (find-prefix-rule prefix)
18
- (and handler (handler prefix list))))
17
+ (if handler
18
+ (handler prefix list)
19
+ (error "unknown prefix-list syntax : ~(inspect prefix)"))))
19
20
 
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
20
26
  (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
27
  `(push (cons ,regex (fn (,prefix-var ,list-var) ,@body))
27
28
  prefix-list-prefixes))
28
29
 
30
+ ;; allows (map λa(upcase a.name) people)
31
+ ;; as shortcut for (map (fn (a) (upcase a.name)) people)
29
32
  (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
33
  (let var-list (map sym (collect !empty? (cdr:string-split vars "")))
33
34
  `(fn ,var-list ,expr)))
35
+
36
+ (define-prefix-list-macro "\~" vars expr
37
+ `(to-string ,expr))
@@ -74,8 +74,8 @@
74
74
  'pp/def
75
75
  (list "pretty-printer for forms starting with ~(quote ,name)")
76
76
  ',args
77
- '(pp/def ,name ,args ,@body))))
78
-
77
+ '(pp/def ,name ,args ,@body)
78
+ (hash))))
79
79
 
80
80
  (pp/def string-pieces (pp form indent) (pp/string-pieces pp (cdr form)))
81
81
  (pp/def quasiquote (pp form indent) "`~(pp (cadr form) (cons "" indent))" )
@@ -85,7 +85,6 @@
85
85
  (pp/def comment (pp form indent) "; ~(cadr form)\n")
86
86
  (pp/def prefix-list (pp form indent) "~(cadr form)~(pp (caddr form))")
87
87
 
88
-
89
88
  (def pp/brace-list-pair (pp (k v) indent) "~k ~(pp v indent)")
90
89
 
91
90
  (pp/def brace-list (pp form indent)
@@ -124,7 +123,7 @@
124
123
  (cons (firstn n form)
125
124
  (map list (nthcdr n form))))
126
125
 
127
- (def pp/flatly (form)
126
+ (def pp/flatly (form indent)
128
127
  (if (pair? form)
129
128
  (let special (hash-get pp/special-forms (car form))
130
129
  (if special
@@ -136,8 +135,15 @@
136
135
  (and (pair? form)
137
136
  (> (len:pp/flatly form) 40)))
138
137
 
138
+ (def percent-syntax? (form)
139
+ (and (pair? form)
140
+ (sym? (car form))
141
+ (string-match (to-string (car form)) "^%")))
142
+
139
143
  (def pp/breaker (form)
140
- (if (pair? form)
144
+ (if (percent-syntax? form)
145
+ (pp/split-form form 1)
146
+ (pair? form)
141
147
  (let key (car form)
142
148
  (if (or (eq? 'if key)
143
149
  (eq? 'cond key))
@@ -164,6 +170,8 @@
164
170
  (def pp/indent (sym indent)
165
171
  (if (or (no sym) (pair? sym))
166
172
  indent
173
+ (string-match (to-string sym) "^%")
174
+ (cons " " indent)
167
175
  (cons (string-replace "." " " " ~sym") indent)))
168
176
 
169
177
  (def pprint (form indent)
@@ -1,37 +1,37 @@
1
1
  (chapter-start 'nydp/hooks "event management - execute a piece of code when something happens")
2
2
 
3
3
  (let hooks {}
4
+ ;; return the list of hook-names
4
5
  (def hook-names ()
5
- ; return the list of hook-names
6
6
  (hash-keys hooks))
7
7
 
8
+ ;; return the list of hooks for 'hook-name
8
9
  (def hooks-for (hook-name)
9
- ; return the list of hooks for 'hook-name
10
10
  hooks.,hook-name)
11
11
 
12
+ ;; add a function 'f to execute when 'hook-name is fired
12
13
  (def add-hook (hook-name f)
13
- ; add a function 'f to execute when 'hook-name is fired
14
14
  (hash-cons hooks hook-name f))
15
15
 
16
+ ;; remove all hooks for 'hook-name
16
17
  (def clear-hooks (hook-name)
17
- ; remove all hooks for 'hook-name
18
18
  (= hooks.,hook-name nil))
19
19
 
20
+ ;; temporarily remove all hooks for 'hook-name, restoring them after running 'f
20
21
  (def without-hooks (hook-name f)
21
- ; temporarily remove all hooks for 'hook-name, restoring them after running 'f
22
22
  (let previous-hooks (hooks-for hook-name)
23
23
  (ensure (= hooks.,hook-name previous-hooks)
24
24
  (clear-hooks hook-name)
25
25
  (f))))
26
26
 
27
+ ;; only works if you have a reference to the original function
27
28
  (def remove-hook (hook-name f)
28
- ; only works if you have a reference to the original function
29
29
  (= hooks.,hook-name
30
30
  (collect (curry !eq? f)
31
31
  hooks.,hook-name)))
32
32
 
33
+ ;; apply all functions attached to 'hook-name to given 'args
33
34
  (def run-hooks (hook-name . args)
34
- ; apply all functions attached to 'hook-name to given 'args
35
35
  (each hook (hooks-for hook-name)
36
36
  (apply hook args))))
37
37
 
@@ -42,9 +42,9 @@
42
42
  ;;
43
43
  ;; same as (add-hook 'transaction (fn (account amount) (update account total (+ account.total amount))))
44
44
  ;;
45
- ;; if 'body is nil and 'args is a symbol, for example
45
+ ;; if 'body is a symbol and 'args is nil, for example
46
46
  ;;
47
- ;; (on transaction notify)
47
+ ;; (on transaction () notify)
48
48
  ;;
49
49
  ;; 'notify must be a predefined function accepting any arguments to the 'transaction event ; the example is equivalent to
50
50
  ;;
@@ -59,8 +59,8 @@
59
59
  (car body)
60
60
  `(fn ,args ,@body))
61
61
  (w/uniq dox-item
62
- `(let ,dox-item (car:dox-lookup ',event)
63
- (if (no ,dox-item) (error "unknown hook ~(just ',event)"))
62
+ `(let ,dox-item (or (car:dox-lookup ',event)
63
+ (dox-add-doc ',event 'hook))
64
64
  (add-hook ',event ,hookfn)
65
65
  (hash-cons ,dox-item 'hooks
66
66
  { src ',hookfn