nydp 0.4.0 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +44 -0
  3. data/lib/lisp/core-010-precompile.nydp +13 -16
  4. data/lib/lisp/core-012-utils.nydp +21 -6
  5. data/lib/lisp/core-015-documentation.nydp +60 -19
  6. data/lib/lisp/core-017-builtin-dox.nydp +50 -39
  7. data/lib/lisp/core-020-utils.nydp +5 -5
  8. data/lib/lisp/core-030-syntax.nydp +103 -61
  9. data/lib/lisp/core-035-flow-control.nydp +18 -9
  10. data/lib/lisp/core-037-list-utils.nydp +36 -14
  11. data/lib/lisp/core-039-module.nydp +24 -0
  12. data/lib/lisp/core-040-utils.nydp +41 -23
  13. data/lib/lisp/core-041-string-utils.nydp +37 -9
  14. data/lib/lisp/core-042-date-utils.nydp +21 -1
  15. data/lib/lisp/core-043-list-utils.nydp +93 -67
  16. data/lib/lisp/core-045-dox-utils.nydp +5 -0
  17. data/lib/lisp/core-080-pretty-print.nydp +55 -17
  18. data/lib/lisp/core-090-hook.nydp +35 -1
  19. data/lib/lisp/core-100-utils.nydp +130 -28
  20. data/lib/lisp/core-110-hash-utils.nydp +61 -0
  21. data/lib/lisp/core-120-settings.nydp +46 -0
  22. data/lib/lisp/core-130-validations.nydp +51 -0
  23. data/lib/lisp/{core-060-benchmarking.nydp → core-900-benchmarking.nydp} +108 -5
  24. data/lib/lisp/tests/accum-examples.nydp +28 -1
  25. data/lib/lisp/tests/aif-examples.nydp +8 -3
  26. data/lib/lisp/tests/andify-examples.nydp +7 -0
  27. data/lib/lisp/tests/at-syntax-examples.nydp +17 -0
  28. data/lib/lisp/tests/best-examples.nydp +9 -0
  29. data/lib/lisp/tests/builtin-tests.nydp +19 -0
  30. data/lib/lisp/tests/case-examples.nydp +14 -0
  31. data/lib/lisp/tests/cdr-set-examples.nydp +6 -0
  32. data/lib/lisp/tests/date-examples.nydp +56 -1
  33. data/lib/lisp/tests/destructuring-examples.nydp +5 -5
  34. data/lib/lisp/tests/detect-examples.nydp +12 -0
  35. data/lib/lisp/tests/dp-examples.nydp +24 -0
  36. data/lib/lisp/tests/empty-examples.nydp +1 -1
  37. data/lib/lisp/tests/error-tests.nydp +4 -4
  38. data/lib/lisp/tests/filter-forms-examples.nydp +30 -0
  39. data/lib/lisp/tests/foundation-test.nydp +12 -0
  40. data/lib/lisp/tests/hash-examples.nydp +26 -2
  41. data/lib/lisp/tests/list-grep-examples.nydp +40 -0
  42. data/lib/lisp/tests/list-tests.nydp +58 -1
  43. data/lib/lisp/tests/map-hash-examples.nydp +11 -0
  44. data/lib/lisp/tests/mapreduce-examples.nydp +10 -0
  45. data/lib/lisp/tests/module-examples.nydp +10 -0
  46. data/lib/lisp/tests/multi-assign-examples.nydp +6 -0
  47. data/lib/lisp/tests/parser-tests.nydp +21 -0
  48. data/lib/lisp/tests/pretty-print-tests.nydp +16 -13
  49. data/lib/lisp/tests/set-difference-examples.nydp +8 -0
  50. data/lib/lisp/tests/set-intersection-examples.nydp +32 -0
  51. data/lib/lisp/tests/set-union-examples.nydp +24 -0
  52. data/lib/lisp/tests/settings-examples.nydp +40 -0
  53. data/lib/lisp/tests/sort-examples.nydp +8 -0
  54. data/lib/lisp/tests/string-tests.nydp +61 -1
  55. data/lib/lisp/tests/syntax-tests.nydp +5 -1
  56. data/lib/lisp/tests/to-integer-examples.nydp +16 -0
  57. data/lib/lisp/tests/validation-examples.nydp +15 -0
  58. data/lib/lisp/tests/zap-examples.nydp +12 -0
  59. data/lib/nydp.rb +13 -7
  60. data/lib/nydp/assignment.rb +10 -3
  61. data/lib/nydp/builtin.rb +1 -1
  62. data/lib/nydp/builtin/abs.rb +8 -0
  63. data/lib/nydp/builtin/cdr_set.rb +1 -6
  64. data/lib/nydp/builtin/date.rb +15 -1
  65. data/lib/nydp/builtin/error.rb +1 -1
  66. data/lib/nydp/builtin/handle_error.rb +1 -1
  67. data/lib/nydp/builtin/hash.rb +27 -45
  68. data/lib/nydp/builtin/inspect.rb +1 -1
  69. data/lib/nydp/builtin/plus.rb +10 -2
  70. data/lib/nydp/builtin/rand.rb +18 -0
  71. data/lib/nydp/builtin/random_string.rb +2 -2
  72. data/lib/nydp/builtin/ruby_wrap.rb +72 -0
  73. data/lib/nydp/builtin/set_intersection.rb +8 -0
  74. data/lib/nydp/builtin/set_union.rb +8 -0
  75. data/lib/nydp/builtin/string_match.rb +2 -2
  76. data/lib/nydp/builtin/string_pad_left.rb +7 -0
  77. data/lib/nydp/builtin/string_pad_right.rb +7 -0
  78. data/lib/nydp/builtin/string_replace.rb +1 -1
  79. data/lib/nydp/builtin/string_split.rb +1 -2
  80. data/lib/nydp/builtin/to_integer.rb +23 -0
  81. data/lib/nydp/builtin/to_string.rb +2 -9
  82. data/lib/nydp/builtin/type_of.rb +9 -6
  83. data/lib/nydp/closure.rb +0 -3
  84. data/lib/nydp/cond.rb +23 -1
  85. data/lib/nydp/context_symbol.rb +14 -6
  86. data/lib/nydp/core.rb +45 -33
  87. data/lib/nydp/core_ext.rb +54 -0
  88. data/lib/nydp/date.rb +37 -31
  89. data/lib/nydp/function_invocation.rb +34 -26
  90. data/lib/nydp/hash.rb +5 -6
  91. data/lib/nydp/helper.rb +41 -25
  92. data/lib/nydp/interpreted_function.rb +68 -40
  93. data/lib/nydp/literal.rb +1 -1
  94. data/lib/nydp/pair.rb +25 -9
  95. data/lib/nydp/parser.rb +8 -6
  96. data/lib/nydp/string_atom.rb +16 -22
  97. data/lib/nydp/symbol.rb +40 -27
  98. data/lib/nydp/symbol_lookup.rb +7 -7
  99. data/lib/nydp/tokeniser.rb +2 -2
  100. data/lib/nydp/truth.rb +17 -10
  101. data/lib/nydp/version.rb +1 -1
  102. data/lib/nydp/vm.rb +7 -2
  103. data/nydp.gemspec +2 -4
  104. data/spec/date_spec.rb +115 -22
  105. data/spec/embedded_spec.rb +12 -12
  106. data/spec/foreign_hash_spec.rb +14 -2
  107. data/spec/hash_non_hash_behaviour_spec.rb +7 -7
  108. data/spec/hash_spec.rb +24 -2
  109. data/spec/nydp_spec.rb +14 -2
  110. data/spec/parser_spec.rb +27 -16
  111. data/spec/rand_spec.rb +45 -0
  112. data/spec/spec_helper.rb +13 -1
  113. data/spec/symbol_spec.rb +31 -0
  114. data/spec/time_spec.rb +1 -1
  115. metadata +38 -37
  116. data/lib/nydp/builtin/car.rb +0 -7
  117. data/lib/nydp/builtin/cdr.rb +0 -7
  118. data/lib/nydp/builtin/cons.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8d9a87eb0c014a51f391ddd1ba6686165a01ab48
4
- data.tar.gz: 8c3f3146c0ae8dc18ac6e86324274423d75be651
3
+ metadata.gz: '06876fcb6832d6737b4763607cfe7b4c0ca003c3'
4
+ data.tar.gz: b45d30570c913940f93585241c1dad9cc71c5872
5
5
  SHA512:
6
- metadata.gz: f946a10304dd7422fb73243b9cd3ef40fab33aa9ff4f0b53568278761b64905d00714ed0cf7401db29b8c3613d8a683460ed48feef3f174ab0c724dd3e5f922e
7
- data.tar.gz: 1925438dd0eca5a718e6f41ff39ef9f35e1a9ed18279e58f2ebfa88c284cb46526f4864932db706dc346662a59cb153fbec70fca1047aeddc742740de971dab5
6
+ metadata.gz: d874e4fbbba55a5995f699451bbf305fe7667f4058cdab2e713fe64900bc96ed285fe5ae8d0c460c73001f0a44fb22699c634c2017a723e9c79d818779d38b7e
7
+ data.tar.gz: 5d5f3aeb4e7c0e65af1024990fdfa5f73a8f4657a06dfd11aaeec172709615a3879f0bdff0efd19475a223add58ee1dd6379951548979eda5b80f30861967e61
data/README.md CHANGED
@@ -55,6 +55,22 @@ answer = Nydp.apply_function ns, :question, :life, ["The Universe", and_also(eve
55
55
 
56
56
  You can maintain multiple `ns` instances without mutual interference. In other words, assigning global variables while one `ns` is in scope will not affect the values of variables in any other `ns` (unless you've specifically arranged it to be so by duplicating namespaces or some such sorcery).
57
57
 
58
+
59
+ #### Facing the Truth
60
+
61
+ In conditional statements, nil is false, anything else is true
62
+
63
+ ```lisp
64
+ (if) ;; same as (if nil)
65
+ (if a) ;; same as a
66
+ (if a b) ;; same as (if a b nil)
67
+ (if a b c) ;; if a is nil, return c, otherwise return b
68
+ (if a b c d) ;; same as (if a b (if c d))
69
+ (if a b c d e) ;; same as (if a b (if c d e))
70
+
71
+ ;; and so on
72
+ ```
73
+
58
74
  ## Different from Arc :
59
75
 
60
76
  #### 1. Macro-expansion runs in lisp
@@ -151,8 +167,36 @@ nydp > (map &lastname german-composers) ; ampersand-syntax creates a function
151
167
 
152
168
  As with all other syntax, you can of course override the `ampersand-syntax` macro to handle your special needs.
153
169
 
170
+ You can combine special syntaxes ("%td" comes from nydp-html gem)
171
+
172
+ ```lisp
173
+
174
+ nydp > (map %td:&lastname german-composers)
175
+
176
+ "<td>Bach</td><td>Beethoven</td><td>Wagner</td><td>Mozart</td>"
177
+
178
+ ```
179
+
180
+ So, @%td@ expands to @(percent-syntax || td)@, @&lastname@ to @(ampersand-syntax || lastname)@, and the whole @%td:&lastname@
181
+ to @(colon-syntax (percent-syntax || td) (ampersand-syntax || lastname))@. Luckily for you, there's a fine @colon-syntax@ macro
182
+ that knows how to build a function out of these bits and pieces.
183
+
184
+
154
185
  Look for `SYMBOL_OPERATORS` in [parser.rb](lib/nydp/parser.rb) to see which syntax is recognised and in which order. The order of these definitions defines special-syntax-operator precedence.
155
186
 
187
+ Any character that is not special syntax will be recognised as part of a symbol. At time of writing, this includes the plus sign, hyphen, and slash.
188
+
189
+ ```lisp
190
+
191
+ ;; nonsense code illustrating the use of certain
192
+ ;; characters as function and variable names
193
+ (def //-+ (x y z)
194
+ (let -*- (x y)
195
+ (if z (//-+ x y -*-) -*-)))
196
+
197
+ ```
198
+
199
+
156
200
  #### 3. Special list syntax
157
201
 
158
202
  The parser detects alternative list delimiters
@@ -1,17 +1,15 @@
1
- (assign mac-expand (fn (names macfn expr)
2
- (cond macfn
3
- (pre-compile-with names
4
- (apply macfn (cdr expr)))
5
- expr)))
1
+ (assign mac-expand
2
+ (fn (names macfn expr)
3
+ (cond macfn
4
+ (handle-error
5
+ (fn (errors)
6
+ (error "expanding" (inspect expr) "with" (inspect macfn)))
7
+ (fn ()
8
+ (pre-compile-with names (apply macfn (cdr expr)))))
9
+ expr)))
6
10
 
7
11
  (assign macs (hash))
8
12
 
9
- (assign pre-compile-expr
10
- (fn (names expr)
11
- (mac-expand names
12
- (hash-get names (car expr))
13
- expr)))
14
-
15
13
  (assign pre-compile-each
16
14
  (fn (names args)
17
15
  (cond args
@@ -33,7 +31,10 @@
33
31
  (cond (eq? (car arg) 'quote)
34
32
  arg
35
33
  (pre-compile-each names
36
- (pre-compile-expr names arg)))
34
+ (mac-expand names
35
+ (hash-get names
36
+ (car arg))
37
+ arg)))
37
38
  arg)))
38
39
 
39
40
  (assign pre-compile-debug
@@ -136,7 +137,3 @@
136
137
 
137
138
  (hash-set macs 'quasiquote
138
139
  (fn (arg) (qq-quasiquote arg 0)))
139
-
140
- (hash-set macs 'do
141
- (fn args
142
- `((fn nil ,@args))))
@@ -8,16 +8,31 @@
8
8
  (car args))
9
9
  nil)))
10
10
 
11
- (def map (f things)
12
- ; transforms the list 'things by applying 'f to each item
13
- ; returns the resulting list
11
+ (def map-helper-0 (f things lc)
14
12
  (if (pair? things)
15
- (cons (f (car things)) (map f (cdr things)))
13
+ (map-helper-0 f (cdr things) (cdr-set lc (cons (f (car things)))))
16
14
  things
17
- (f things)))
15
+ (cdr-set lc (f things))))
16
+
17
+ (def map-helper-1 (f things acc)
18
+ (map-helper-0 f things acc)
19
+ (cdr acc))
20
+
21
+ ;; transforms the list 'things by applying 'f to each item, returns the resulting list
22
+ ;; conceptually, does the following:
23
+ ;;
24
+ ;; (if (pair? things)
25
+ ;; (cons (f (car things)) (map f (cdr things)))
26
+ ;; things
27
+ ;; (f things))
28
+ ;;
29
+ ;; however the actual version is more complicated to allow for TCO ("modulo-cons" issue)
30
+ (def map (f things)
31
+ (map-helper-1 f things (cons)))
18
32
 
33
+ ;; push 'v onto the value for 'k in 'h
34
+ ;; the hash-values of h will all be lists, in reverse order of consing
19
35
  (def hash-cons (h k v)
20
- ; push 'v onto the value for 'k in 'h
21
36
  (hash-set h k (cons v (hash-get h k))))
22
37
 
23
38
  (def rev (things last-cdr)
@@ -1,5 +1,28 @@
1
1
  (def privately () nil)
2
2
 
3
+ (assign comments nil)
4
+
5
+ (def fetch-and-clear-comments ()
6
+ ((fn (c) (assign comments nil) c) (rev comments)))
7
+
8
+ (def filter-comments (form acc)
9
+ (if (no form)
10
+ (rev acc)
11
+ (pair? form)
12
+ (filter-comments (cdr form)
13
+ (if (if (pair? (car form))
14
+ (eq? (caar form)
15
+ 'comment))
16
+ acc
17
+ (cons (filter-comments (car form)
18
+ nil)
19
+ acc)))
20
+ form))
21
+
22
+ (hash-set macs 'do
23
+ (fn forms
24
+ `((fn nil ,@forms))))
25
+
3
26
  ((fn (this-chapter-name chapters chapter-new chapter-build chapter-add-to-chapter)
4
27
  (assign chapters (hash))
5
28
 
@@ -45,7 +68,7 @@
45
68
  (assign this-script nil)
46
69
  (assign this-plugin "Nydp Core")
47
70
 
48
- ((fn (dox examples chapters dox-new dox-build)
71
+ ((fn (dox examples chapters types types-chapters dox-new dox-build)
49
72
  (def dox-build (hsh name what texts args src chapters)
50
73
  (hash-set hsh 'name name )
51
74
  (hash-set hsh 'what what )
@@ -59,26 +82,38 @@
59
82
 
60
83
  (def dox-new (item)
61
84
  (hash-cons dox (hash-get item 'name) item)
62
- (dox-add-to-chapters item (hash-get item 'chapters)))
85
+ (hash-cons types (hash-get item 'what) item)
86
+ (dox-add-to-chapters item (hash-get item 'what) (hash-get item 'chapters) (hash)))
63
87
 
64
88
  (def dox-add-doc (name what texts args src chapters more)
65
89
  (cond (no (privately))
66
90
  (dox-new (dox-build (if more more (hash)) name what texts args src chapters))))
67
91
 
68
- (def dox-add-to-chapters (item chapters)
92
+ (def dox-add-to-chapters (item type chapters already)
69
93
  (cond chapters
70
- (do (chapter-add-item item (car chapters))
71
- (dox-add-to-chapters item (cdr chapters)))
94
+ (cond (no (hash-get already (car chapters)))
95
+ (do (hash-set already (car chapters) t)
96
+ (chapter-add-item item (car chapters))
97
+ (hash-cons types-chapters (inspect (cons type (car chapters))) item)
98
+ (dox-add-to-chapters item type (cdr chapters) already))
99
+ item)
72
100
  item))
73
101
 
74
102
  (def dox-add-examples (name example-exprs)
75
103
  (hash-cons examples name example-exprs))
76
104
 
77
- (def dox-lookup (sym) (hash-get dox sym))
105
+ (def dox-lookup (name) (hash-get dox name))
78
106
 
79
107
  (def dox? (sym) (hash-key? dox sym))
80
108
 
81
109
  (def dox-names () (hash-keys dox))
110
+ (def dox-types () (hash-keys types))
111
+ (def dox-items-by-type (type) (hash-get types type))
112
+
113
+ (def get-types-chapters () types-chapters)
114
+
115
+ (def dox-items-by-type-and-chapter (dox-type chapter)
116
+ (hash-get types-chapters (inspect (cons dox-type chapter))))
82
117
 
83
118
  (def dox-get-attr (name attr)
84
119
  (cond (dox? name)
@@ -89,7 +124,7 @@
89
124
  (def dox-examples (name) (hash-get examples name ))
90
125
  (def dox-args (name) (dox-get-attr name 'args ))
91
126
  (def dox-example-names () (hash-keys examples )))
92
- (hash) (hash) (hash) nil)
127
+ (hash) (hash) (hash) (hash) (hash) nil)
93
128
 
94
129
  (def plugin-start (name) (assign this-plugin name) (chapter-end))
95
130
  (def plugin-end (name) (assign this-plugin nil ) (chapter-end))
@@ -106,9 +141,9 @@
106
141
  (cond (eq? event 'script-end)
107
142
  (script-end name))))))
108
143
 
144
+ ;; if the car of 'form is a key of 'hsh, add the cdr of 'form to the value of the key in 'hsh
145
+ ;; otherwise add the form to the list whose key is nil
109
146
  (def filter-form (hsh form)
110
- ; if the car of 'form is a key of 'hsh, add the cdr of 'form to the value of the key in 'hsh
111
- ; otherwise add the form to the list whose key is nil
112
147
  (cond (cond (pair? form)
113
148
  (hash-key? hsh (car form)))
114
149
  (hash-cons hsh (car form) (cdr form))
@@ -127,9 +162,9 @@
127
162
  (def rev-values (hsh)
128
163
  (rev-value-keys (hash-keys hsh) hsh (hash)))
129
164
 
165
+ ;; group forms by their first element, if the first element
166
+ ;; is already a key in hsh, collect all other elements under key nil
130
167
  (def filter-forms (hsh forms)
131
- ; group forms by their first element, if the first element
132
- ; is already a key in hsh, collect all other elements under key nil
133
168
  (cond forms
134
169
  (filter-forms (filter-form hsh (car forms)) (cdr forms))
135
170
  (rev-values hsh)))
@@ -139,12 +174,14 @@
139
174
  (hash-set hsh 'chapter nil)
140
175
  hsh)
141
176
 
177
+ (def dox-build-def-name (name) name)
178
+
179
+ ;; used internally by 'mac
142
180
  (def define-mac-expr (name args body-forms)
143
- ; used internally by 'mac
144
181
  `(do (hash-set macs ',name (fun ,args ,@(hash-get body-forms nil)))
145
- (dox-add-doc ',name
182
+ (dox-add-doc ',(dox-build-def-name name)
146
183
  'mac
147
- ',(map car (hash-get body-forms 'comment))
184
+ ',(+ (fetch-and-clear-comments) (map car (hash-get body-forms 'comment)))
148
185
  ',args
149
186
  '(mac ,name ,args ,@(hash-get body-forms nil))
150
187
  ',(map car (hash-get body-forms 'chapter)))))
@@ -169,17 +206,21 @@
169
206
 
170
207
  (mac def-assign args `(assign ,@args))
171
208
 
209
+ ;; used internally by 'def
172
210
  (def define-def-expr (name args body-forms)
173
- ; used internally by 'def
174
- `(do (def-assign ,name (fun ,args ,@(hash-get body-forms nil)))
175
- (dox-add-doc ',name
211
+ `(do (def-assign ,name (fun ,args ,@(filter-comments (hash-get body-forms nil))))
212
+ (dox-add-doc ',(dox-build-def-name name)
176
213
  'def
177
- ',(map car (hash-get body-forms 'comment))
214
+ ',(+ (fetch-and-clear-comments) (map car (hash-get body-forms 'comment)))
178
215
  ',args
179
216
  '(def ,name ,args ,@(hash-get body-forms nil))
180
217
  ',(map car (hash-get body-forms 'chapter)))))
181
218
 
219
+ ;; define a new function in the global namespace
182
220
  (mac def (name args . body)
183
- ; define a new function in the global namespace
184
221
  (chapter nydp-core)
185
222
  (define-def-expr name args (filter-forms (build-def-hash (hash)) body)))
223
+
224
+ (mac comment (txt)
225
+ (assign comments (cons txt comments))
226
+ nil)
@@ -1,6 +1,7 @@
1
1
  (dox-add-doc 'cons 'def '("with args a and b, returns a new cons cell, (a . b)") '(a b) nil '(list-manipulation))
2
2
  (dox-add-doc 'car 'def '("with args a, where a is a cons cell (x . y), return x." "Commonly used to get the first element of a list") '(a) nil '(list-manipulation))
3
3
  (dox-add-doc 'cdr 'def '("with args a, where a is a cons cell (x . y), return y." "Commonly used to get contents of a list, excluding the first element") '(a) nil '(list-manipulation))
4
+ (dox-add-doc 'log 'def '("write arg to Nydp.logger ; be sure to assign Nydp.logger first!") '(arg) nil '(nydp-core))
4
5
  (dox-add-doc '+ 'def '("with rest-args things, return the sum of the elements of things." "Will also increment dates and concatenate strings and lists") 'things nil '(math))
5
6
  (dox-add-doc '- 'def '("return the result of subtracting all other args from the first arg." "(- a b c d) is equivalent to (- a (+ b c d))") 'things nil '(math))
6
7
  (dox-add-doc '* 'def '("with rest-args things, return the product of the elements of things.") 'things nil '(math))
@@ -35,18 +36,21 @@
35
36
  (dox-add-doc 'pair? 'def '("t if arg is a cons cell or (equivalently) the start of a list") '(arg) nil '(nydp-core))
36
37
  (dox-add-doc 'hash? 'def '("t if arg is a hash") '(arg) nil '(nydp-core))
37
38
  (dox-add-doc 'sym? 'def '("t if arg is a symbol, nil otherwise") '(arg) nil '(nydp-core))
38
- (dox-add-doc 'ensuring 'def '("execute 'tricky-f, then 'ensure-f afterwards"
39
- "'ensure-f will always be executed, even if there is an error in 'tricky-f"
40
- "returns the return value of 'tricky-f") '(ensure-f tricky-f) nil '(flow-control))
39
+ (dox-add-doc 'ensuring 'def '("execute 'try-f, then 'ensure-f afterwards"
40
+ "'ensure-f will always be executed, even if there is an error in 'try-f"
41
+ "returns the return value of 'try-f. Similar to try/finally in java, or begin/ensure in ruby.") '(ensure-f try-f) nil '(flow-control))
41
42
  (dox-add-doc 'inspect 'def '("return a string representing 'arg, potentially (but not always) in a way that can be parsed back in to get the original object") '(arg) nil '(nydp-core))
42
43
  (dox-add-doc 'comment 'def '("does nothing at all." "Intercepted inside 'def and 'mac and used for documentation") '(arg) nil '(nydp-core))
43
44
  (dox-add-doc 'parse-in-string 'def '("parse the given string assuming a string-open delimiter has already been encountered") '(str) nil '(nydp-core))
44
- (dox-add-doc 'random-string 'def '("return a random string of length 'len (default 10)") '(len) nil '(string-manipulation))
45
- (dox-add-doc 'to-string 'def '("return a human-readable string representation of 'arg") '(arg) nil '(string-manipulation))
46
- (dox-add-doc 'string-length 'def '("return the length of 'arg") '(arg) nil '(string-manipulation))
47
- (dox-add-doc 'string-replace 'def '("replace 'pattern with 'insert in 'str") '(pattern insert str) nil '(string-manipulation))
48
- (dox-add-doc 'string-split 'def '("split 'str delimited by 'delim") '(str delim) nil '(string-manipulation))
49
- (dox-add-doc 'string-match 'def '("if 'str matches 'pattern, return hash with keys 'match and 'captures ; otherwise nil") '(str pattern) nil '(string-manipulation))
45
+ (dox-add-doc 'rand 'def '("return a random number ; with no args, between 0 and 1"
46
+ "with 1 arg, an integer less than arg"
47
+ "with two args, an integer >= arg 0 and < arg 1") 'args nil '(math))
48
+ (dox-add-doc 'random-string 'def '("return a random string of length 'len (default 10)") '(len) nil '(string-manipulation))
49
+ (dox-add-doc 'to-string 'def '("return a human-readable string representation of 'arg") '(arg) nil '(string-manipulation))
50
+ (dox-add-doc 'string-length 'def '("return the length of 'arg") '(arg) nil '(string-manipulation))
51
+ (dox-add-doc 'string-replace 'def '("replace 'pattern with 'replacement in 'str") '(pattern replacement str) nil '(string-manipulation))
52
+ (dox-add-doc 'string-split 'def '("split 'str delimited by 'delim") '(str delim) nil '(string-manipulation))
53
+ (dox-add-doc 'string-match 'def '("if 'str matches 'pattern, return hash with keys 'match and 'captures ; otherwise nil") '(str pattern) nil '(string-manipulation))
50
54
  (dox-add-doc 'time 'def '("with no args, return the current time."
51
55
  "With one arg, if 'arg-0 is a number, return the current time plus 'arg-0 seconds."
52
56
  "With one arg, if 'arg-0 is a date, return the time at the beginning of the given date."
@@ -54,35 +58,42 @@
54
58
  "With two args, 'arg-0 must be a time."
55
59
  "If 'arg-1 is a number, return 'arg-0 plus 'arg-1 seconds as a time object."
56
60
  "If 'arg-1 is a time, return the number of seconds between the two (- 'arg-0 arg-1)."
57
- "Otherwise, expect 3, 4, 5, or 6 args, to construct a time from"
61
+ "Otherwise, expect 3 or more args, to construct a time from"
58
62
  "year, month, date, hours, minutes, seconds, milliseconds, reading arguments in that order,"
59
- "where hours, minutes, seconds, and milliseconds are optional") 'args nil '(date-time))
60
- (dox-add-doc 'thread-locals 'def '("return a hash bound to the current thread") nil nil '(nydp-core))
61
- (dox-add-doc 'type-of 'def '("return a symbol for the type of 'arg") '(arg) nil '(nydp-core))
62
- (dox-add-doc 'eq? 'def '("return 't if 'arg-0 and 'arg-1 are equal, nil otherwise") '(arg-0 arg-1) nil '(nydp-core))
63
- (dox-add-doc 'cdr-set 'def '("set the cdr of the given 'cell to 'arg, returns 'cell") '(cell arg) nil '(list-manipulation))
64
- (dox-add-doc 'hash-get 'def '("return the value stored by 'key in 'hsh") '(hsh key) nil '(hash-manipulation))
65
- (dox-add-doc 'hash-set 'def '("store 'val under 'key in 'hsh, return 'val") '(hsh key val) nil '(hash-manipulation))
66
- (dox-add-doc 'hash-keys 'def '("return the list of keys in 'hsh") '(hsh) nil '(hash-manipulation))
67
- (dox-add-doc 'hash-key? 'def '("return 't if 'key is a key of 'hsh") '(hsh key) nil '(hash-manipulation))
68
- (dox-add-doc 'hash-merge 'def '("return a new hash containing keys and values from 'h0 and 'h1, where values of 'h1 override values of 'h0") '(h0 h1) nil '(hash-manipulation))
69
- (dox-add-doc 'vm-info 'def '("return some information about the state of the current thread") nil nil '(nydp-core))
70
- (dox-add-doc 'pre-compile 'def '("transform parsed forms before the compile and eval stages") '(arg) nil '(nydp-compilation))
71
- (dox-add-doc 'script-run 'def '("announces the start of a plugin load or a script load."
72
- "'event may be one of '(script-start script-end plugin-start plugin-end)"
73
- "'name is the name of the script or plugin concerned") '(event name) nil '(nydp-core))
63
+ "where hours, minutes, seconds, and milliseconds are optional") 'args nil '(date-time))
64
+ (dox-add-doc 'thread-locals 'def '("return a hash bound to the current thread") nil nil '(nydp-core))
65
+ (dox-add-doc 'type-of 'def '("return a symbol for the type of 'arg") '(arg) nil '(nydp-core))
66
+ (dox-add-doc 'eq? 'def '("return 't if 'arg-0 and 'arg-1 are equal, nil otherwise") '(arg-0 arg-1) nil '(nydp-core))
67
+ (dox-add-doc 'cdr-set 'def '("set the cdr of the given 'cell to 'arg, returns 'cell") '(cell arg) nil '(list-manipulation))
68
+ (dox-add-doc 'hash-get 'def '("return the value stored by 'key in 'hsh") '(hsh key) nil '(hash-manipulation))
69
+ (dox-add-doc 'hash-set 'def '("store 'val under 'key in 'hsh, return 'val") '(hsh key val) nil '(hash-manipulation))
70
+ (dox-add-doc 'hash-keys 'def '("return the list of keys in 'hsh") '(hsh) nil '(hash-manipulation))
71
+ (dox-add-doc 'hash-key? 'def '("return 't if 'key is a key of 'hsh") '(hsh key) nil '(hash-manipulation))
72
+ (dox-add-doc 'hash-merge 'def '("return a new hash containing keys and values from 'h0 and 'h1, where values of 'h1 override values of 'h0") '(h0 h1) nil '(hash-manipulation))
73
+ (dox-add-doc 'vm-info 'def '("return some information about the state of the current thread") nil nil '(nydp-core))
74
+ (dox-add-doc 'pre-compile 'def '("transform parsed forms before the compile and eval stages") '(arg) nil '(nydp-compilation))
75
+ (dox-add-doc 'script-run 'def '("announces the start of a plugin load or a script load."
76
+ "'event may be one of '(script-start script-end plugin-start plugin-end)"
77
+ "'name is the name of the script or plugin concerned") '(event name) nil '(nydp-core))
74
78
 
75
- (dox-add-doc 'chapter-end 'def '("Announce the end of a chapter. Called by 'plugin-start, 'plugin-end, 'script-start, 'script-end") nil nil '(nydp/documentation))
76
- (dox-add-doc 'chapter-start 'def '("Announce the start of a chapter. Creates a new chapter if the named chapter does not already exist") '(chapter-name description) nil '(nydp/documentation))
77
- (dox-add-doc 'chapter-names 'def '("Get the names of all the chapters nydp knows about") nil nil '(nydp/documentation))
78
- (dox-add-doc 'chapter-current 'def '("Get the name of the chapter in progress right now - this is normally the last value sent to 'chapter-start") nil nil '(nydp/documentation))
79
- (dox-add-doc 'chapter-delete 'def '("Remove the named chapter") '(name) nil '(nydp/documentation))
80
- (dox-add-doc 'chapter-find 'def '("Get the named chapter") '(name) nil '(nydp/documentation))
81
- (dox-add-doc 'dox-add-doc 'def '("Store the provided documentation item."
82
- "'name is the name of the item"
83
- "'what is the type of the item ('def or 'mac or 'thingy ... this is user-definable, not related to 'type-of)"
84
- "'texts is a list of strings to store for this item"
85
- "'args is the args if the item has the notion of args"
86
- "'src the source code of the item if any"
87
- "'chapters the chapters to which the item should be added, if any") '(name what texts args src chapters) nil '(nydp/documentation))
88
- (dox-add-doc 'dox-add-examples 'def '("Add the given examples to the dox for the named item") '(name example-exprs) nil '(nydp/documentation))
79
+ (dox-add-doc 'chapter-end 'def '("Announce the end of a chapter. Called by 'plugin-start, 'plugin-end, 'script-start, 'script-end") nil nil '(nydp/documentation))
80
+ (dox-add-doc 'chapter-start 'def '("Announce the start of a chapter. Creates a new chapter if the named chapter does not already exist") '(chapter-name description) nil '(nydp/documentation))
81
+ (dox-add-doc 'chapter-names 'def '("Get the names of all the chapters nydp knows about") nil nil '(nydp/documentation))
82
+ (dox-add-doc 'chapter-current 'def '("Get the name of the chapter in progress right now - this is normally the last value sent to 'chapter-start") nil nil '(nydp/documentation))
83
+ (dox-add-doc 'chapter-delete 'def '("Remove the named chapter") '(name) nil '(nydp/documentation))
84
+ (dox-add-doc 'chapter-find 'def '("Get the named chapter") '(name) nil '(nydp/documentation))
85
+ (dox-add-doc 'set-intersection 'def '("return the intersection of the given lists") 'args nil '(list-manipulation))
86
+ (dox-add-doc '⋂ 'def '("return the intersection of the given lists") 'args nil '(list-manipulation))
87
+ (dox-add-doc 'set-union 'def '("return the union of the given lists") 'args nil '(list-manipulation))
88
+ (dox-add-doc '⋃ 'def '("return the union of the given lists") 'args nil '(list-manipulation))
89
+ (dox-add-doc 'dox-add-doc 'def '("Store the provided documentation item."
90
+ "'name is the name of the item"
91
+ "'what is the type of the item ('def or 'mac or 'thingy ... this is user-definable, not related to 'type-of)"
92
+ "'texts is a list of strings to store for this item"
93
+ "'args is the args if the item has the notion of args"
94
+ "'src the source code of the item if any"
95
+ "'chapters the chapters to which the item should be added, if any") '(name what texts args src chapters) nil '(nydp/documentation))
96
+ (dox-add-doc 'dox-add-examples 'def '("Add the given examples to the dox for the named item") '(name example-exprs) nil '(nydp/documentation))
97
+ (dox-add-doc 'dox-types 'def '("Get the list of types of documented items") nil nil '(nydp/documentation))
98
+ (dox-add-doc 'dox-lookup 'def '("Get the documentation for the given item") '(name) nil '(nydp/documentation))
99
+ (dox-add-doc 'dox-items-by-type 'def '("Get the list of dox items of a given type") '(type) nil '(nydp/documentation))
@@ -1,4 +1,4 @@
1
- (assign script-name "core-012-utils.nydp")
1
+ (assign script-name "core-020-utils.nydp")
2
2
 
3
3
  (dox-add-doc 'if
4
4
  'mac
@@ -43,12 +43,12 @@
43
43
  '(hash-set h k (cons v (hash-get h k)))
44
44
  '(hash-manipulation))
45
45
 
46
+ ;; equivalent to (join-str "~prefix~joint~(car things)" joint (cdr things)) - except
47
+ ;; 'string-pieces hasn't been defined yet, and if it were, it would be defined in terms of
48
+ ;; 'join-str, so it would be circular.
49
+ ;; see 'joinstr for a more powerful and easier-to-use implementation of the same idea
46
50
  (def join-str (prefix joint things)
47
51
  (chapter string-manipulation)
48
- ; equivalent to (join-str "~prefix~joint~(car things)" joint (cdr things)) - except
49
- ; 'string-pieces hasn't been defined yet, and if it were, it would be defined in terms of
50
- ; 'join-str, so it would be circular.
51
- ; see 'joinstr for a more powerful and easier-to-use implementation of the same idea
52
52
  (if things
53
53
  (join-str (+ (to-string prefix)
54
54
  joint
@@ -21,16 +21,26 @@ scoping, assignment, anonymous functions and more...")
21
21
  (apply orf
22
22
  (cdr args)))))
23
23
 
24
+ ; returns true if 'things is a list and the first item of the
25
+ ; list is the given object
24
26
  (def caris (obj things)
25
- ; returns true if 'things is a list and the first item of the
26
- ; list is the given object
27
27
  (and (pair? things)
28
- (eq? (car things) obj)))
28
+ (eq? (car things) obj)))
29
29
 
30
+ ; evaluate 'body if 'arg is nil
30
31
  (mac unless (arg . body)
31
- ; evaluate 'body if 'arg is nil
32
32
  `(if (no ,arg) (do ,@body)))
33
33
 
34
+ ; looks up a key in @
35
+ ; assumes local lexical context has defined a hash called '@
36
+ (mac prefix-at-syntax (name . names)
37
+ `(hash-get @ ',name))
38
+
39
+ (mac at-syntax names
40
+ (if (eq? (car names) '||)
41
+ `(prefix-at-syntax ,@(cdr names))
42
+ (error "unknown at-syntax: expected prefix-syntax (eg @name), got ~(join-str (car names) "@" (cdr names))")))
43
+
34
44
  (def expand-colon-syntax (names)
35
45
  (if (no (cdr names))
36
46
  `(apply ,(car names) args)
@@ -84,13 +94,17 @@ scoping, assignment, anonymous functions and more...")
84
94
  (cons (list (car things) (cadr things))
85
95
  (pairs (cddr things)))))
86
96
 
97
+ ;; like 'let, but creates and assigns multiple local variables.
98
+ ;; for example, "(with (a 1 b 2) (+ a b))" returns 3
87
99
  (mac with (parms . body)
88
100
  `((fun ,(map car (pairs parms))
89
101
  ,@body)
90
102
  ,@(map cadr (pairs parms))))
91
103
 
104
+ ;; same as ( (fn (var) body) val ) -> ie create a lexical scope
105
+ ;; where val is assigned to var, execute 'body in that scope
92
106
  (mac let (var val . body)
93
- `(with (,var ,val) ,@body))
107
+ `(with (,var ,val) ,@body))
94
108
 
95
109
  (mac rfn (name parms . body)
96
110
  ; creates a named, locally-scoped function
@@ -116,6 +130,17 @@ scoping, assignment, anonymous functions and more...")
116
130
  (assign ,name (fun ,(map car ppairs) ,@body))
117
131
  (,name ,@(map cadr ppairs)))))
118
132
 
133
+ ;; (andify a b c) is equivalent to
134
+ ;; (fn args (and (apply a args) (apply b args) (apply c args)))
135
+ ;; or more simply
136
+ ;; (fn (x) (and (a x) (b x) (c x)))
137
+ ;; note: alias as 'andf ??
138
+ (def andify args
139
+ (fn args2 (rfnwith self (ands args)
140
+ (if ands (if (apply (car ands) args2)
141
+ (self (cdr ands)))
142
+ t))))
143
+
119
144
  (let uniq-counter 0
120
145
  (def uniq (prefix)
121
146
  (assign uniq-counter (+ uniq-counter 1))
@@ -127,7 +152,7 @@ scoping, assignment, anonymous functions and more...")
127
152
  ; creates a lexical scope with a unique symbol assigned to
128
153
  ; each variable in 'vars ; executes the 'body.
129
154
  (if (pair? vars)
130
- `(with ,(apply + (map (fn (n) (list n '(uniq ',n))) vars))
155
+ `(with ,(apply + (map (fn (n) `(,n (uniq ',n))) vars))
131
156
  ,@body)
132
157
  `(let ,vars (uniq ',vars) ,@body)))
133
158
 
@@ -194,29 +219,23 @@ scoping, assignment, anonymous functions and more...")
194
219
  (and (pair? name)
195
220
  (caris 'ampersand-syntax (car name))))
196
221
 
222
+ ;; (= (&key (expr)) (val))
223
+ ;; (= ((ampersand-syntax key) (expr)) (val))
224
+ ;; 'place is ((ampersand-syntax || key) (expr))
225
+ ;; we need (hash-set (expr) 'key (val))
226
+ ;; however,
227
+ ;; (= (&key.subkey (expr)) (val))
228
+ ;; 'place is ((ampersand-syntax || (dot-syntax key subkey)) (expr))
229
+ ;; we need (hash-set (hash-get (expr) 'key) 'subkey (val))
197
230
  (def ampersand-expression-assignment (place value)
198
- ; (= (&key (expr)) (val))
199
- ; (= ((ampersand-syntax key) (expr)) (val))
200
- ; 'place is ((ampersand-syntax || key) (expr))
201
- ; we need (hash-set (expr) 'key (val))
202
- ; however,
203
- ; (= (&key.subkey (expr)) (val))
204
- ; 'place is ((ampersand-syntax || (dot-syntax key subkey)) (expr))
205
- ; we need (hash-set (hash-get (expr) 'key) 'subkey (val))
206
231
  (with (k (cadr:cdar place)
207
232
  hsh (cadr place))
208
233
  (if (caris 'dot-syntax k)
209
234
  (dot-syntax-assignment (cons hsh (cdr k)) value)
210
235
  `(hash-set ,hsh ',k ,value))))
211
236
 
212
- (mac = (name value)
213
- ; generic assignment which unlike builtin 'assign, knows how to assign
214
- ; to hash keys
215
- ; (= (hash-get (expr) 'key) (val) => (hash-set (expr) 'key (val))
216
- ; (= h.k (val)) => (hash-set h 'k (val))
217
- ; (= h.j.k (val)) => (hash-set (hash-get h 'j) 'k (val))
218
- ; (= (&key (expr)) (val)) => (hash-set (expr) 'key (val))
219
- ; (= (&j.k (expr)) (val)) => (hash-set (hash-get (expr) 'j) 'k (val))
237
+ ;; used internally by '= macro
238
+ (def assign-expr (name value)
220
239
  (if (isa 'symbol name)
221
240
  `(assign ,name ,value)
222
241
  (caris 'dot-syntax name)
@@ -224,15 +243,35 @@ scoping, assignment, anonymous functions and more...")
224
243
  (caris 'hash-get name)
225
244
  (hash-get-assignment (cdr name) value)
226
245
  (ampersand-expression? name)
227
- (ampersand-expression-assignment name value)))
228
-
229
- (mac def-assign args
230
- ; override previous definition to allow expressions like (def hsh.foo (arg arg2) ...)
231
- `(= ,@args))
232
-
233
- (mac or= (place val)
234
- ; evaluate ,val and assign result to ,place only if ,place is already nil
235
- `(or ,place (= ,place ,val)))
246
+ (ampersand-expression-assignment name value)
247
+ (caris 'at-syntax name)
248
+ `(hash-set @ ',(caddr name) ,value)
249
+ (error "unknown assignment to place: ~(inspect name)")))
250
+
251
+ ;; generic assignment which unlike builtin 'assign, knows how to assign
252
+ ;; to hash keys
253
+ ;; (= (hash-get (expr) 'key) (val) => (hash-set (expr) 'key (val))
254
+ ;; (= h.k (val)) => (hash-set h 'k (val))
255
+ ;; (= h.j.k (val)) => (hash-set (hash-get h 'j) 'k (val))
256
+ ;; (= (&key (expr)) (val)) => (hash-set (expr) 'key (val))
257
+ ;; (= (&j.k (expr)) (val)) => (hash-set (hash-get (expr) 'j) 'k (val))
258
+ (mac = (name value . more)
259
+ (if more
260
+ `(do ,(assign-expr name value) (= ,@more))
261
+ (assign-expr name value)))
262
+
263
+ ;; quiet assignment ; like =, but expression returns nil
264
+ (mac #= (name value)
265
+ `(do (= ,name ,value) nil))
266
+
267
+ ; increment the value at 'place by 'inc (default 1)
268
+ (mac ++ (place inc) `(= ,place (+ ,place ,(or inc 1))))
269
+
270
+ ; override previous definition to allow expressions like (def hsh.foo (arg arg2) ...)
271
+ (mac def-assign args `(= ,@args))
272
+
273
+ ; evaluate ,val and assign result to ,place only if ,place is already nil
274
+ (mac or= (place val) `(or ,place (= ,place ,val)))
236
275
 
237
276
  (def brace-list-hash-key (k)
238
277
  (if (isa 'symbol k) `(quote ,k)
@@ -259,43 +298,42 @@ scoping, assignment, anonymous functions and more...")
259
298
  (error "Irregular '& syntax: got suffix ~(inspect (cdr rest)) in ~(join-str pfx "&" rest)")
260
299
  (build-ampersand-syntax (car rest))))
261
300
 
262
- (mac brace-list-mono (arg)
263
- ; override 'brace-list-mono in order to provide a useful interpretation for "{ x }" syntax
264
- arg)
301
+ ; override 'brace-list-mono in order to provide a useful interpretation for "{ x }" syntax
302
+ (mac brace-list-mono (arg) arg)
265
303
 
266
- (mac brace-list-empty ()
267
- ; interprets "{ }" as new hash
268
- '(hash))
304
+ ; interprets "{ }" as new hash
305
+ (mac brace-list-empty () '(hash))
269
306
 
307
+ ; parser expands { foo bar } to (brace-list foo bar)
270
308
  (mac brace-list args
271
- ; parser expands { foo bar } to (brace-list foo bar)
272
309
  (if (no args)
273
310
  `(brace-list-empty)
274
311
  (no (cdr args))
275
312
  `(brace-list-mono ,(car args))
276
313
  (brace-list-build-hash args)))
277
314
 
278
- (mac returnlet (var val . body)
279
- ; stores ,val in ,var, executes ,@body, returns ,var. Saves a line of code at the end of
280
- ; 'let. Assumes 'body is going to do something destructive with 'val, but you want 'val before
281
- ; it gets changed. See also 'returning
282
- `(let ,var ,val ,@body ,var))
315
+ ; stores ,val in ,var, executes ,@body, returns ,var. Saves a line of code at the end of
316
+ ; 'let. If 'body assigns to 'var, the assigned value of 'var will be returned. See also 'returning
317
+ (mac returnlet (var val . body) `(let ,var ,val ,@body ,var))
283
318
 
284
- (mac returning (val . body)
285
- ; stores ,val, executes ,@body, and returns ,val. Assumes 'body is going to do something
286
- ; destructive with 'val, but you want 'val before it gets changed. See also 'returnlet
287
- (w/uniq retval `(returnlet ,retval ,val ,@body)))
319
+ ; stores ,val, executes ,@body, and returns ,val. Assumes 'body is going to do something
320
+ ; destructive with 'val, but you want 'val before it gets changed. Note that if 'val is mutated
321
+ ; (eg hash), the mutated value will be returned. See also 'returnlet
322
+ (mac returning (val . body) (w/uniq retval `(returnlet ,retval ,val ,@body)))
288
323
 
289
- (mac aif (expr . body)
290
- ; like if, except the value of each condition is locally bound to the variable 'it
291
- ; eg (aif (find thing) (show it))
292
- ; source: arc.arc
293
- `(let it ,expr
294
- (if it
324
+ (mac ifv (var expr . body)
325
+ `(let ,var ,expr
326
+ (if ,var
295
327
  ,@(if (cddr body)
296
- `(,(car body) (aif ,@(cdr body)))
328
+ `(,(car body) (ifv ,var ,@(cdr body)))
297
329
  body))))
298
330
 
331
+ ; like if, except the value of each condition is locally bound to the variable 'it
332
+ ; eg (aif (find thing) (show it))
333
+ ; source: arc.arc
334
+ (mac aif (expr . body)
335
+ `(ifv it ,expr ,@body))
336
+
299
337
  (def destructure/with (var args n)
300
338
  ; provides the argument expression to 'with when
301
339
  ; destructuring arguments are present in a 'fun definition
@@ -318,16 +356,20 @@ scoping, assignment, anonymous functions and more...")
318
356
  `(fn ,(rev new-args given-args) ,@body)))
319
357
 
320
358
 
321
- (def fun/approve-arg-names (orig args)
359
+ (def fun/approve-arg-names (orig args body)
322
360
  (if (pair? args)
323
- (do (fun/approve-arg-names orig (car args))
324
- (fun/approve-arg-names orig (cdr args)))
361
+ (do (fun/approve-arg-names orig (car args) body)
362
+ (fun/approve-arg-names orig (cdr args) body))
325
363
  args
326
364
  (if (hash-get macs args)
327
- (warnings/new 'arg-shadows-macro "arg " args " shadows macro " args " in arg list " orig))))
365
+ (warnings/new 'arg-shadows-macro "arg " args " shadows macro " args " in arg list " orig " and body " body))))
328
366
 
367
+ ;; build a 'fn form, changing 'args and 'body to
368
+ ;; properly handle any destructuring args if present
329
369
  (mac fun (args . body)
330
- ; build a 'fn form, changing 'args and 'body to
331
- ; properly handle any destructuring args if present
332
- (fun/approve-arg-names args args)
370
+ (fun/approve-arg-names args args body)
333
371
  (destructure/build args nil body))
372
+
373
+ ;; assign (f place) to place
374
+ (mac zap (f place . args)
375
+ `(= ,place (,f ,place ,@args)))