nydp 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +44 -0
- data/lib/lisp/core-010-precompile.nydp +13 -16
- data/lib/lisp/core-012-utils.nydp +21 -6
- data/lib/lisp/core-015-documentation.nydp +58 -24
- data/lib/lisp/core-017-builtin-dox.nydp +49 -42
- data/lib/lisp/core-020-utils.nydp +5 -5
- data/lib/lisp/core-030-syntax.nydp +191 -96
- data/lib/lisp/core-035-flow-control.nydp +41 -14
- data/lib/lisp/core-037-list-utils.nydp +36 -14
- data/lib/lisp/core-039-module.nydp +24 -0
- data/lib/lisp/core-040-utils.nydp +51 -23
- data/lib/lisp/core-041-string-utils.nydp +37 -9
- data/lib/lisp/core-042-date-utils.nydp +21 -1
- data/lib/lisp/core-043-list-utils.nydp +99 -73
- data/lib/lisp/core-045-dox-utils.nydp +5 -0
- data/lib/lisp/core-070-prefix-list.nydp +1 -1
- data/lib/lisp/core-080-pretty-print.nydp +57 -17
- data/lib/lisp/core-090-hook.nydp +35 -1
- data/lib/lisp/core-100-utils.nydp +110 -15
- data/lib/lisp/core-110-hash-utils.nydp +61 -0
- data/lib/lisp/core-120-settings.nydp +46 -0
- data/lib/lisp/core-130-validations.nydp +51 -0
- data/lib/lisp/{core-060-benchmarking.nydp → core-900-benchmarking.nydp} +107 -19
- data/lib/lisp/tests/accum-examples.nydp +28 -1
- data/lib/lisp/tests/aif-examples.nydp +8 -3
- data/lib/lisp/tests/andify-examples.nydp +7 -0
- data/lib/lisp/tests/at-syntax-examples.nydp +17 -0
- data/lib/lisp/tests/best-examples.nydp +9 -0
- data/lib/lisp/tests/builtin-tests.nydp +19 -0
- data/lib/lisp/tests/case-examples.nydp +14 -0
- data/lib/lisp/tests/cdr-set-examples.nydp +6 -0
- data/lib/lisp/tests/date-examples.nydp +56 -1
- data/lib/lisp/tests/destructuring-examples.nydp +46 -14
- data/lib/lisp/tests/detect-examples.nydp +12 -0
- data/lib/lisp/tests/dp-examples.nydp +24 -0
- data/lib/lisp/tests/each-tests.nydp +5 -0
- data/lib/lisp/tests/empty-examples.nydp +1 -1
- data/lib/lisp/tests/error-tests.nydp +4 -4
- data/lib/lisp/tests/explain-mac-examples.nydp +1 -1
- data/lib/lisp/tests/filter-forms-examples.nydp +15 -0
- data/lib/lisp/tests/foundation-test.nydp +12 -0
- data/lib/lisp/tests/hash-examples.nydp +26 -2
- data/lib/lisp/tests/list-grep-examples.nydp +40 -0
- data/lib/lisp/tests/list-tests.nydp +58 -1
- data/lib/lisp/tests/map-hash-examples.nydp +11 -0
- data/lib/lisp/tests/module-examples.nydp +10 -0
- data/lib/lisp/tests/multi-assign-examples.nydp +6 -0
- data/lib/lisp/tests/parser-tests.nydp +25 -0
- data/lib/lisp/tests/pretty-print-tests.nydp +17 -14
- data/lib/lisp/tests/set-difference-examples.nydp +8 -0
- data/lib/lisp/tests/set-intersection-examples.nydp +16 -0
- data/lib/lisp/tests/set-union-examples.nydp +8 -0
- data/lib/lisp/tests/settings-examples.nydp +40 -0
- data/lib/lisp/tests/sort-examples.nydp +8 -0
- data/lib/lisp/tests/string-tests.nydp +65 -1
- data/lib/lisp/tests/syntax-tests.nydp +5 -1
- data/lib/lisp/tests/to-integer-examples.nydp +16 -0
- data/lib/lisp/tests/validation-examples.nydp +15 -0
- data/lib/lisp/tests/zap-examples.nydp +12 -0
- data/lib/nydp.rb +13 -7
- data/lib/nydp/assignment.rb +10 -3
- data/lib/nydp/builtin.rb +1 -1
- data/lib/nydp/builtin/abs.rb +8 -0
- data/lib/nydp/builtin/cdr_set.rb +1 -6
- data/lib/nydp/builtin/date.rb +15 -1
- data/lib/nydp/builtin/error.rb +1 -1
- data/lib/nydp/builtin/handle_error.rb +1 -1
- data/lib/nydp/builtin/hash.rb +27 -45
- data/lib/nydp/builtin/inspect.rb +1 -1
- data/lib/nydp/builtin/plus.rb +10 -2
- data/lib/nydp/builtin/random_string.rb +2 -2
- data/lib/nydp/builtin/{car.rb → regexp.rb} +2 -2
- data/lib/nydp/builtin/ruby_wrap.rb +72 -0
- data/lib/nydp/builtin/string_match.rb +2 -2
- data/lib/nydp/builtin/string_pad_left.rb +7 -0
- data/lib/nydp/builtin/string_pad_right.rb +7 -0
- data/lib/nydp/builtin/string_replace.rb +1 -1
- data/lib/nydp/builtin/string_split.rb +4 -3
- data/lib/nydp/builtin/to_integer.rb +23 -0
- data/lib/nydp/builtin/to_string.rb +2 -9
- data/lib/nydp/builtin/type_of.rb +9 -6
- data/lib/nydp/closure.rb +0 -3
- data/lib/nydp/cond.rb +23 -1
- data/lib/nydp/context_symbol.rb +14 -6
- data/lib/nydp/core.rb +36 -28
- data/lib/nydp/core_ext.rb +54 -0
- data/lib/nydp/date.rb +37 -31
- data/lib/nydp/function_invocation.rb +34 -26
- data/lib/nydp/hash.rb +5 -6
- data/lib/nydp/helper.rb +41 -25
- data/lib/nydp/interpreted_function.rb +68 -40
- data/lib/nydp/literal.rb +1 -1
- data/lib/nydp/pair.rb +22 -5
- data/lib/nydp/parser.rb +11 -7
- data/lib/nydp/string_atom.rb +16 -22
- data/lib/nydp/symbol.rb +40 -27
- data/lib/nydp/symbol_lookup.rb +7 -7
- data/lib/nydp/tokeniser.rb +2 -2
- data/lib/nydp/truth.rb +17 -10
- data/lib/nydp/version.rb +1 -1
- data/lib/nydp/vm.rb +7 -2
- data/nydp.gemspec +2 -4
- data/spec/date_spec.rb +115 -22
- data/spec/embedded_spec.rb +12 -12
- data/spec/foreign_hash_spec.rb +14 -2
- data/spec/hash_non_hash_behaviour_spec.rb +7 -7
- data/spec/hash_spec.rb +24 -2
- data/spec/nydp_spec.rb +14 -2
- data/spec/pair_spec.rb +3 -1
- data/spec/parser_spec.rb +31 -20
- data/spec/rand_spec.rb +3 -3
- data/spec/spec_helper.rb +13 -1
- data/spec/symbol_spec.rb +31 -0
- data/spec/time_spec.rb +1 -1
- metadata +31 -38
- data/lib/nydp/builtin/cdr.rb +0 -7
- 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)
|
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
|
-
|
89
|
-
|
90
|
-
|
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
|
-
|
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) (
|
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
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
(
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
(
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
(
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
(
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
(
|
234
|
-
|
235
|
-
|
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
|
-
|
263
|
-
|
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
|
-
|
267
|
-
|
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
|
-
|
279
|
-
|
280
|
-
|
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
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
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
|
290
|
-
|
291
|
-
|
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) (
|
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
|
-
|
308
|
-
|
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
|
-
|
319
|
-
|
320
|
-
|
321
|
-
(def fun/
|
322
|
-
(
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
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
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
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
|
-
|
15
|
-
|
16
|
-
`(= ,things (cons ,x ,things)))
|
34
|
+
; assign (cons x things) to things
|
35
|
+
(mac push (x things) `(= ,things (cons ,x ,things)))
|
17
36
|
|
18
|
-
|
19
|
-
|
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
|
-
|
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
|
-
(
|
37
|
-
|
38
|
-
|
39
|
-
|
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)))
|