nydp 0.4.1 → 0.5.0

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 +5 -5
  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 +58 -24
  6. data/lib/lisp/core-017-builtin-dox.nydp +49 -42
  7. data/lib/lisp/core-020-utils.nydp +5 -5
  8. data/lib/lisp/core-030-syntax.nydp +191 -96
  9. data/lib/lisp/core-035-flow-control.nydp +41 -14
  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 +51 -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 +99 -73
  16. data/lib/lisp/core-045-dox-utils.nydp +5 -0
  17. data/lib/lisp/core-070-prefix-list.nydp +1 -1
  18. data/lib/lisp/core-080-pretty-print.nydp +57 -17
  19. data/lib/lisp/core-090-hook.nydp +35 -1
  20. data/lib/lisp/core-100-utils.nydp +110 -15
  21. data/lib/lisp/core-110-hash-utils.nydp +61 -0
  22. data/lib/lisp/core-120-settings.nydp +46 -0
  23. data/lib/lisp/core-130-validations.nydp +51 -0
  24. data/lib/lisp/{core-060-benchmarking.nydp → core-900-benchmarking.nydp} +107 -19
  25. data/lib/lisp/tests/accum-examples.nydp +28 -1
  26. data/lib/lisp/tests/aif-examples.nydp +8 -3
  27. data/lib/lisp/tests/andify-examples.nydp +7 -0
  28. data/lib/lisp/tests/at-syntax-examples.nydp +17 -0
  29. data/lib/lisp/tests/best-examples.nydp +9 -0
  30. data/lib/lisp/tests/builtin-tests.nydp +19 -0
  31. data/lib/lisp/tests/case-examples.nydp +14 -0
  32. data/lib/lisp/tests/cdr-set-examples.nydp +6 -0
  33. data/lib/lisp/tests/date-examples.nydp +56 -1
  34. data/lib/lisp/tests/destructuring-examples.nydp +46 -14
  35. data/lib/lisp/tests/detect-examples.nydp +12 -0
  36. data/lib/lisp/tests/dp-examples.nydp +24 -0
  37. data/lib/lisp/tests/each-tests.nydp +5 -0
  38. data/lib/lisp/tests/empty-examples.nydp +1 -1
  39. data/lib/lisp/tests/error-tests.nydp +4 -4
  40. data/lib/lisp/tests/explain-mac-examples.nydp +1 -1
  41. data/lib/lisp/tests/filter-forms-examples.nydp +15 -0
  42. data/lib/lisp/tests/foundation-test.nydp +12 -0
  43. data/lib/lisp/tests/hash-examples.nydp +26 -2
  44. data/lib/lisp/tests/list-grep-examples.nydp +40 -0
  45. data/lib/lisp/tests/list-tests.nydp +58 -1
  46. data/lib/lisp/tests/map-hash-examples.nydp +11 -0
  47. data/lib/lisp/tests/module-examples.nydp +10 -0
  48. data/lib/lisp/tests/multi-assign-examples.nydp +6 -0
  49. data/lib/lisp/tests/parser-tests.nydp +25 -0
  50. data/lib/lisp/tests/pretty-print-tests.nydp +17 -14
  51. data/lib/lisp/tests/set-difference-examples.nydp +8 -0
  52. data/lib/lisp/tests/set-intersection-examples.nydp +16 -0
  53. data/lib/lisp/tests/set-union-examples.nydp +8 -0
  54. data/lib/lisp/tests/settings-examples.nydp +40 -0
  55. data/lib/lisp/tests/sort-examples.nydp +8 -0
  56. data/lib/lisp/tests/string-tests.nydp +65 -1
  57. data/lib/lisp/tests/syntax-tests.nydp +5 -1
  58. data/lib/lisp/tests/to-integer-examples.nydp +16 -0
  59. data/lib/lisp/tests/validation-examples.nydp +15 -0
  60. data/lib/lisp/tests/zap-examples.nydp +12 -0
  61. data/lib/nydp.rb +13 -7
  62. data/lib/nydp/assignment.rb +10 -3
  63. data/lib/nydp/builtin.rb +1 -1
  64. data/lib/nydp/builtin/abs.rb +8 -0
  65. data/lib/nydp/builtin/cdr_set.rb +1 -6
  66. data/lib/nydp/builtin/date.rb +15 -1
  67. data/lib/nydp/builtin/error.rb +1 -1
  68. data/lib/nydp/builtin/handle_error.rb +1 -1
  69. data/lib/nydp/builtin/hash.rb +27 -45
  70. data/lib/nydp/builtin/inspect.rb +1 -1
  71. data/lib/nydp/builtin/plus.rb +10 -2
  72. data/lib/nydp/builtin/random_string.rb +2 -2
  73. data/lib/nydp/builtin/{car.rb → regexp.rb} +2 -2
  74. data/lib/nydp/builtin/ruby_wrap.rb +72 -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 +4 -3
  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 +36 -28
  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 +22 -5
  95. data/lib/nydp/parser.rb +11 -7
  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/pair_spec.rb +3 -1
  111. data/spec/parser_spec.rb +31 -20
  112. data/spec/rand_spec.rb +3 -3
  113. data/spec/spec_helper.rb +13 -1
  114. data/spec/symbol_spec.rb +31 -0
  115. data/spec/time_spec.rb +1 -1
  116. metadata +31 -38
  117. data/lib/nydp/builtin/cdr.rb +0 -7
  118. data/lib/nydp/builtin/cons.rb +0 -9
@@ -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
- `((fun ,(map car (pairs parms))
89
- ,@body)
90
- ,@(map cadr (pairs parms))))
100
+ `((fun ,(map car (pairs parms))
101
+ ,@body)
102
+ ,@(map cadr (pairs parms))))
91
103
 
104
+ ;; 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
+ `((fun (,var) ,@body) ,val))
94
108
 
95
109
  (mac rfn (name parms . body)
96
110
  ; creates a named, locally-scoped function
@@ -105,17 +119,28 @@ scoping, assignment, anonymous functions and more...")
105
119
  ; same as 'rfn, but using the name 'self
106
120
  `(rfn self ,parms ,@body))
107
121
 
122
+ ;; a mix of rfn and with; creates a locally-scoped named function with
123
+ ;; the given parameter names, and invokes it with the given parameter
124
+ ;; values. It is possible to reference the function by its name from
125
+ ;; within the function (to pass as an argument or for recursive
126
+ ;; invocation)
108
127
  (mac rfnwith (name params . body)
109
- ; a mix of rfn and with; creates a locally-scoped named function with
110
- ; the given parameter names, and invokes it with the given parameter
111
- ; values. It is possible to reference the function by its name from
112
- ; within the function (to pass as an argument or for recursive
113
- ; invocation)
114
128
  (let ppairs (pairs params)
115
129
  `(let ,name nil
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))
@@ -123,11 +148,11 @@ scoping, assignment, anonymous functions and more...")
123
148
  (def reset-uniq-counter ()
124
149
  (assign uniq-counter 0)))
125
150
 
151
+ ;; creates a lexical scope with a unique symbol assigned to
152
+ ;; each variable in 'vars ; executes the 'body.
126
153
  (mac w/uniq (vars . body)
127
- ; creates a lexical scope with a unique symbol assigned to
128
- ; 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,45 +219,88 @@ 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
- (with (k (cadr:cdar place)
207
- hsh (cadr place))
208
- (if (caris 'dot-syntax k)
209
- (dot-syntax-assignment (cons hsh (cdr k)) value)
210
- `(hash-set ,hsh ',k ,value))))
211
-
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))
220
- (if (isa 'symbol name)
221
- `(assign ,name ,value)
222
- (caris 'dot-syntax name)
223
- (dot-syntax-assignment (cdr name) value)
224
- (caris 'hash-get name)
225
- (hash-get-assignment (cdr name) value)
226
- (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)))
231
+ (let k (cadr:cdar place)
232
+ (let hsh (cadr place)
233
+ (if (caris 'dot-syntax k)
234
+ (dot-syntax-assignment (cons hsh (cdr k)) value)
235
+ `(hash-set ,hsh ',k ,value)))))
236
+
237
+ ;; used internally by 'destructuring-assign
238
+ (def destructuring-assigns (names values acc)
239
+ (if names
240
+ (if (pair? names)
241
+ (destructuring-assigns
242
+ (cdr names)
243
+ `(cdr ,values)
244
+ (cons `(= ,(car names) (car ,values)) acc))
245
+ (cons `(= ,names ,values) acc))
246
+ (rev acc)))
247
+
248
+ ;; used internally by 'assign-expr
249
+ (def destructuring-assign (name value)
250
+ (w/uniq destructuring-assign
251
+ `(let ,destructuring-assign ,value
252
+ ,@(destructuring-assigns name destructuring-assign))))
253
+
254
+ ;; used internally by '= macro
255
+ (def assign-expr (nv)
256
+ (let name (car nv)
257
+ (let value (cadr nv)
258
+ (if (isa 'symbol name)
259
+ `(assign ,name ,value)
260
+ (caris 'dot-syntax name)
261
+ (dot-syntax-assignment (cdr name) value)
262
+ (caris 'hash-get name)
263
+ (hash-get-assignment (cdr name) value)
264
+ (ampersand-expression? name)
265
+ (ampersand-expression-assignment name value)
266
+ (caris 'at-syntax name)
267
+ `(hash-set @ ',(caddr name) ,value)
268
+ (pair? name)
269
+ (destructuring-assign name value)
270
+ (error "unknown assignment to place: " (inspect name))))))
271
+
272
+ ;; generic assignment which unlike builtin 'assign, knows how to assign
273
+ ;; to hash keys
274
+ ;; (= (hash-get (expr) 'key) (val) => (hash-set (expr) 'key (val))
275
+ ;; (= h.k (val)) => (hash-set h 'k (val))
276
+ ;; (= h.j.k (val)) => (hash-set (hash-get h 'j) 'k (val))
277
+ ;; (= (&key (expr)) (val)) => (hash-set (expr) 'key (val))
278
+ ;; (= (&j.k (expr)) (val)) => (hash-set (hash-get (expr) 'j) 'k (val))
279
+ (mac = assignments
280
+ `(do ,@(map assign-expr (pairs assignments))))
281
+
282
+ ;; like 'let, but creates and assigns multiple local variables.
283
+ ;; for example, "(with (a 1 b 2) (+ a b))" returns 3
284
+ ;;
285
+ ;; later variables can references earlier ones:
286
+ ;; (with (a 1 b 2 c (+ a b)) (list a b c)) ;; returns (1 2 3)
287
+ (mac with (assignments . body)
288
+ `((fun ,(map car (pairs assignments))
289
+ (= ,@assignments)
290
+ ,@body) nil))
291
+
292
+ ;; quiet assignment ; like =, but expression returns nil
293
+ (mac #= (name value)
294
+ `(do (= ,name ,value) nil))
295
+
296
+ ; increment the value at 'place by 'inc (default 1)
297
+ (mac ++ (place inc) `(= ,place (+ ,place ,(or inc 1))))
298
+
299
+ ; override previous definition to allow expressions like (def hsh.foo (arg arg2) ...)
300
+ (mac def-assign args `(= ,@args))
301
+
302
+ ; evaluate ,val and assign result to ,place only if ,place is already nil
303
+ (mac or= (place val) `(or ,place (= ,place ,val)))
236
304
 
237
305
  (def brace-list-hash-key (k)
238
306
  (if (isa 'symbol k) `(quote ,k)
@@ -259,43 +327,48 @@ scoping, assignment, anonymous functions and more...")
259
327
  (error "Irregular '& syntax: got suffix ~(inspect (cdr rest)) in ~(join-str pfx "&" rest)")
260
328
  (build-ampersand-syntax (car rest))))
261
329
 
262
- (mac brace-list-mono (arg)
263
- ; override 'brace-list-mono in order to provide a useful interpretation for "{ x }" syntax
264
- arg)
330
+ ; override 'brace-list-mono in order to provide a useful interpretation for "{ x }" syntax
331
+ (mac brace-list-mono (arg) arg)
265
332
 
266
- (mac brace-list-empty ()
267
- ; interprets "{ }" as new hash
268
- '(hash))
333
+ ; interprets "{ }" as new hash
334
+ (mac brace-list-empty () '(hash))
269
335
 
336
+ ; parser expands { foo bar } to (brace-list foo bar)
270
337
  (mac brace-list args
271
- ; parser expands { foo bar } to (brace-list foo bar)
272
338
  (if (no args)
273
339
  `(brace-list-empty)
274
340
  (no (cdr args))
275
341
  `(brace-list-mono ,(car args))
276
342
  (brace-list-build-hash args)))
277
343
 
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))
344
+ ; stores ,val in ,var, executes ,@body, returns ,var. Saves a line of code at the end of
345
+ ; 'let. If 'body assigns to 'var, the assigned value of 'var will be returned. See also 'returning
346
+ (mac returnlet (var val . body) `(let ,var ,val ,@body ,var))
283
347
 
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)))
348
+ ; stores ,val, executes ,@body, and returns ,val. Assumes 'body is going to do something
349
+ ; destructive with 'val, but you want 'val before it gets changed. Note that if 'val is mutated
350
+ ; (eg hash), the mutated value will be returned. See also 'returnlet
351
+ (mac returning (val . body) (w/uniq retval `(returnlet ,retval ,val ,@body)))
288
352
 
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
353
+ (mac ifv (var expr . body)
354
+ `(let ,var ,expr
355
+ (if ,var
295
356
  ,@(if (cddr body)
296
- `(,(car body) (aif ,@(cdr body)))
357
+ `(,(car body) (ifv ,var ,@(cdr body)))
297
358
  body))))
298
359
 
360
+ ; like if, except the value of each condition is locally bound to the variable 'it
361
+ ; eg (aif (find thing) (show it))
362
+ ; source: arc.arc
363
+ (mac aif (expr . body)
364
+ `(ifv it ,expr ,@body))
365
+
366
+ ;; returns the n-th item in the list 'things
367
+ (def nth (n things)
368
+ (if (eq? n 0)
369
+ (car things)
370
+ (nth (- n 1) (cdr things))))
371
+
299
372
  (def destructure/with (var args n)
300
373
  ; provides the argument expression to 'with when
301
374
  ; destructuring arguments are present in a 'fun definition
@@ -304,30 +377,52 @@ scoping, assignment, anonymous functions and more...")
304
377
  args
305
378
  `(,args (nthcdr ,n ,var))))
306
379
 
307
- (def destructure/build (given-args new-args body)
308
- ; used internally by 'fun
380
+ ;; issue a warning if any arg name is the name of a macro
381
+ (def fun/approve-arg-names (orig args body)
382
+ (if (pair? args)
383
+ (do (fun/approve-arg-names orig (car args) body)
384
+ (fun/approve-arg-names orig (cdr args) body))
385
+ args
386
+ (if (hash-get macs args)
387
+ (warnings/new 'arg-shadows-macro "arg " args " shadows macro " args " in arg list " orig " and body " body))))
388
+
389
+ ;; used internally by 'fun
390
+ (def destructure/build (given-args new-args body next)
309
391
  (if (pair? given-args)
310
392
  (if (sym? (car given-args))
311
393
  (destructure/build (cdr given-args)
312
394
  (cons (car given-args) new-args)
313
- body)
395
+ body
396
+ next)
314
397
  (w/uniq destructure
315
398
  (destructure/build (cdr given-args)
316
399
  (cons destructure new-args)
317
- `((with ,(destructure/with destructure (car given-args) 0) ,@body)))))
318
- `(fn ,(rev new-args given-args) ,@body)))
319
-
320
-
321
- (def fun/approve-arg-names (orig args)
322
- (if (pair? args)
323
- (do (fun/approve-arg-names orig (car args))
324
- (fun/approve-arg-names orig (cdr args)))
325
- args
326
- (if (hash-get macs args)
327
- (warnings/new 'arg-shadows-macro "arg " args " shadows macro " args " in arg list " orig))))
328
-
400
+ `((with ,(destructure/with destructure (car given-args) 0) ,@body))
401
+ next)))
402
+ (next (rev new-args given-args) body)))
403
+
404
+ (def fun/destructuring-args (args body next)
405
+ (fun/approve-arg-names args args body)
406
+ (destructure/build args nil body next))
407
+
408
+ (assign fun/expanders
409
+ (list
410
+ (cons 'destructuring-args fun/destructuring-args)
411
+ (cons 'core-builder (fn (args body next) `(fn ,args ,@body)))))
412
+
413
+ (def fun/expand (args body expanders)
414
+ (if expanders
415
+ ((cdar expanders)
416
+ args
417
+ body
418
+ (fn (a b)
419
+ (fun/expand a b (cdr expanders))))))
420
+
421
+ ;; build a 'fn form, changing 'args and 'body to
422
+ ;; properly handle any destructuring args if present
329
423
  (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)
333
- (destructure/build args nil body))
424
+ (fun/expand args body fun/expanders))
425
+
426
+ ;; assign (f place) to place
427
+ (mac zap (f place . args)
428
+ `(= ,place (,f ,place ,@args)))
@@ -13,9 +13,9 @@
13
13
  `(ensuring (fn () ,protection)
14
14
  (fn () ,@body)))
15
15
 
16
+ ;; tests 'test, as long as 'test is non-nil,
17
+ ;; repeatedly executes 'body
16
18
  (mac while (test . body)
17
- ; tests 'test, as long as 'test is non-nil,
18
- ; repeatedly executes 'body
19
19
  (w/uniq (rfname pred)
20
20
  `(rfnwith ,rfname (,pred ,test)
21
21
  (when ,pred
@@ -40,29 +40,56 @@
40
40
  (loop (assign ,v ,gi) (< ,v ,gm) (assign ,v (+ ,v 1))
41
41
  ,@body))))
42
42
 
43
- (mac curry (func . args1)
44
- ; return a new function which is the original function with
45
- ; the given args1 already applied
46
- ; arguments to the new function are whatever arguments remain
47
- ; for the old function
48
- `(fn args (apply ,func ,@args1 args)))
43
+ ;; return a new function which is the original function with
44
+ ;; the given args1 already applied
45
+ ;; arguments to the new function are whatever arguments remain
46
+ ;; for the old function
47
+ ;; Could be (mac curry things `(fn args (apply ,@things args))) but less readable
48
+ (mac curry (f . args0)
49
+ `(fn args
50
+ (apply ,f ,@args0 args)))
51
+
52
+ ;; like curry, but the returned function takes only a single arg (assumes all
53
+ ;; args but one are provided here)
54
+ ;; Could be (mac curry1 things `(fn (arg) (,@things arg))) but less readable
55
+ (mac curry1 (f . args)
56
+ `(fn (arg)
57
+ (,f ,@args arg)))
49
58
 
50
59
  (mac cache-get (hsh key val)
51
60
  ; if ,key is already in ,hsh - return the associated value.
52
61
  ; if ,key is not already in ,hsh - evaluate ,val, store the result
53
62
  ; under ,key in ,hsh, and return it
54
63
  (w/uniq (h k v)
55
- `(with (,h ,hsh ,k ,key)
56
- (let ,v (hash-get ,h ,k)
57
- (or ,v (returnlet ,v ,val (hash-set ,h ,k ,v)))))))
64
+ `(with (,h ,hsh ,k ,key)
65
+ (let ,v (hash-get ,h ,k)
66
+ (or ,v (returnlet ,v ,val (hash-set ,h ,k ,v)))))))
58
67
 
68
+ ;; same as 'def, but caches the result, keyed on args, so for a given set of args the result
69
+ ;; is only ever calculated once
70
+ ;;
71
+ ;; WARNING: in current incarnation, won't work with destructuring args
59
72
  (mac defmemo (name args . body)
60
- ; same as 'def, but caches the result, keyed on args, so for a given set of args the result
61
- ; is only ever calculated once
62
- (let forms (filter-forms (build-def-hash (hash)) body)
73
+ (let forms (filter-forms (build-def-hash) body)
63
74
  (w/uniq h
64
75
  `(let ,h (hash)
65
76
  (def ,name ,args
66
77
  ,@(map (fn (c) (cons 'comment c)) forms.comment)
67
78
  ,@(map (fn (c) (cons 'chapter c)) forms.chapter)
68
79
  (cache-get ,h (list ,@args) (do ,@(hash-get forms nil))))))))
80
+
81
+ ;; memoises a function expression
82
+ ;; args: the function arguments
83
+ ;; body: a list of function body expressions
84
+ ;; next: a function to assemble a function expression from 'args and 'body
85
+ ;; returns whatever 'next returns, where 'body is memoised based on the value of 'args
86
+ (def memoise (args body next)
87
+ (let (memo newbody) (filter-remove '#memoise body)
88
+ (if memo
89
+ (w/uniq h
90
+ `(let ,h (hash) ,(next args `((cache-get ,h (list ,@args) (do ,@newbody))))))
91
+ (next args body))))
92
+
93
+ (assign fun/expanders
94
+ (cons
95
+ (cons 'memoise memoise) fun/expanders))
@@ -6,35 +6,57 @@
6
6
  (cons (map car args)
7
7
  (apply zip (map cdr args)))))
8
8
 
9
+ ; invokes 'f for each element of 'things, first element processed first
10
+ ; ( "l" in "eachl" = "leftmost first" )
11
+ (def eachl (f things)
12
+ (when things
13
+ (f (car things))
14
+ (eachl f (cdr things))))
15
+
16
+ ;; if things is a pair,
17
+ ;; if (cdr things) is nil, return (car things)
18
+ ;; else recurse on (cdr things)
19
+ ;; else return things
20
+ (def list/last (things)
21
+ (if (pair? things)
22
+ (aif (cdr things)
23
+ (list/last it)
24
+ (car things))
25
+ things))
26
+
27
+ ; invokes 'f for each element of 'things, last element processed first
28
+ ; ( "r" in "eachr" = "rightmost first" )
9
29
  (def eachr (f things)
10
30
  (when things
11
31
  (eachr f (cdr things))
12
32
  (f (car things))))
13
33
 
14
- (mac push (x things)
15
- ; assign (cons x things) to things
16
- `(= ,things (cons ,x ,things)))
34
+ ; assign (cons x things) to things
35
+ (mac push (x things) `(= ,things (cons ,x ,things)))
17
36
 
18
- (def flatten (things)
19
- ; flatten the given list, recursively
37
+ ; flatten the given list, transforming each leaf-item, recursively
38
+ (def flatmap (f things)
20
39
  (let acc nil
21
40
  (rfnwith flattenize (x things)
22
41
  (if (pair? x)
23
42
  (eachr flattenize x)
24
- (push x acc)))
43
+ x
44
+ (push (f x) acc)))
25
45
  acc))
26
46
 
47
+ ; flatten the given list, recursively
48
+ (def flatten (things) (flatmap x1 things))
49
+
50
+ ; given a list 'al of form '( (k0 v0) (k1 v1) (k2 v2) ... (kn vn) ) and
51
+ ; a 'key, returns the list (kx vx) from 'al where kx is equal to 'key
52
+ ; #attribution: inspiration from arc.arc
27
53
  (def assoc (key al)
28
- ; given a list 'al of form '( (k0 v0) (k1 v1) (k2 v2) ... (kn vn) ) and
29
- ; a 'key, returns the list (kx vx) from 'al where kx is equal to 'key
30
- ; #attribution: inspiration from arc.arc
31
54
  (if (pair? al)
32
55
  (if (caris key (car al))
33
56
  (car al)
34
57
  (assoc key (cdr al)))))
35
58
 
36
- (def alref (key al)
37
- ; given a list 'al of form '( (k0 v0) (k1 v1) (k2 v2) ... (kn vn) ) and
38
- ; a 'key, returns vx from 'al where kx is equal to 'key
39
- ; #attribution: lifted almost directly from arc.arc
40
- (cadr (assoc key al)))
59
+ ; given a list 'al of form '( (k0 v0) (k1 v1) (k2 v2) ... (kn vn) ) and
60
+ ; a 'key, returns vx from 'al where kx is equal to 'key
61
+ ; #attribution: lifted almost directly from arc.arc
62
+ (def alref (key al) (cadr (assoc key al)))