nydp 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +77 -56
- data/lib/lisp/core-000.nydp +1 -1
- data/lib/lisp/core-010-precompile.nydp +49 -29
- data/lib/lisp/core-012-utils.nydp +12 -8
- data/lib/lisp/core-015-documentation.nydp +41 -15
- data/lib/lisp/core-017-builtin-dox.nydp +621 -100
- data/lib/lisp/core-020-utils.nydp +33 -6
- data/lib/lisp/core-025-warnings.nydp +1 -1
- data/lib/lisp/core-030-syntax.nydp +64 -48
- data/lib/lisp/core-035-flow-control.nydp +20 -28
- data/lib/lisp/core-037-list-utils.nydp +84 -21
- data/lib/lisp/core-040-utils.nydp +8 -5
- data/lib/lisp/core-041-string-utils.nydp +17 -11
- data/lib/lisp/core-043-list-utils.nydp +140 -77
- data/lib/lisp/core-045-dox-utils.nydp +1 -0
- data/lib/lisp/core-050-test-runner.nydp +8 -12
- data/lib/lisp/core-070-prefix-list.nydp +19 -15
- data/lib/lisp/core-080-pretty-print.nydp +13 -5
- data/lib/lisp/core-090-hook.nydp +11 -11
- data/lib/lisp/core-100-utils.nydp +51 -66
- data/lib/lisp/core-110-hash-utils.nydp +34 -7
- data/lib/lisp/core-120-settings.nydp +14 -9
- data/lib/lisp/core-130-validations.nydp +28 -13
- data/lib/lisp/core-900-benchmarking.nydp +420 -47
- data/lib/lisp/tests/000-empty-args-examples.nydp +5 -0
- data/lib/lisp/tests/andify-examples.nydp +1 -1
- data/lib/lisp/tests/auto-hash-examples.nydp +6 -1
- data/lib/lisp/tests/best-examples.nydp +1 -1
- data/lib/lisp/tests/boot-tests.nydp +1 -1
- data/lib/lisp/tests/date-examples.nydp +129 -102
- data/lib/lisp/tests/destructuring-examples.nydp +1 -1
- data/lib/lisp/tests/dox-tests.nydp +2 -2
- data/lib/lisp/tests/hash-examples.nydp +58 -33
- data/lib/lisp/tests/list-tests.nydp +137 -1
- data/lib/lisp/tests/pretty-print-tests.nydp +12 -0
- data/lib/lisp/tests/rotate-2d-array-examples.nydp +26 -0
- data/lib/lisp/tests/sort-examples.nydp +5 -5
- data/lib/lisp/tests/string-tests.nydp +16 -5
- data/lib/lisp/tests/syntax-tests.nydp +10 -2
- data/lib/lisp/tests/time-examples.nydp +8 -1
- data/lib/lisp/tests/unparse-tests.nydp +13 -7
- data/lib/nydp/assignment.rb +15 -28
- data/lib/nydp/builtin/abs.rb +4 -3
- data/lib/nydp/builtin/apply.rb +8 -10
- data/lib/nydp/builtin/cdr_set.rb +1 -1
- data/lib/nydp/builtin/comment.rb +1 -3
- data/lib/nydp/builtin/date.rb +11 -28
- data/lib/nydp/builtin/divide.rb +3 -10
- data/lib/nydp/builtin/ensuring.rb +6 -21
- data/lib/nydp/builtin/error.rb +2 -4
- data/lib/nydp/builtin/eval.rb +9 -4
- data/lib/nydp/builtin/greater_than.rb +7 -8
- data/lib/nydp/builtin/handle_error.rb +10 -34
- data/lib/nydp/builtin/hash.rb +24 -45
- data/lib/nydp/builtin/inspect.rb +1 -3
- data/lib/nydp/builtin/is_equal.rb +4 -7
- data/lib/nydp/builtin/less_than.rb +6 -7
- data/lib/nydp/builtin/log.rb +7 -0
- data/lib/nydp/builtin/math_ceiling.rb +1 -3
- data/lib/nydp/builtin/math_floor.rb +1 -3
- data/lib/nydp/builtin/math_power.rb +1 -3
- data/lib/nydp/builtin/math_round.rb +2 -2
- data/lib/nydp/builtin/minus.rb +7 -14
- data/lib/nydp/builtin/parse.rb +5 -5
- data/lib/nydp/builtin/parse_in_string.rb +5 -7
- data/lib/nydp/builtin/plus.rb +14 -31
- data/lib/nydp/builtin/pre_compile.rb +1 -3
- data/lib/nydp/builtin/puts.rb +4 -8
- data/lib/nydp/builtin/quit.rb +1 -1
- data/lib/nydp/builtin/rand.rb +6 -11
- data/lib/nydp/builtin/random_string.rb +2 -4
- data/lib/nydp/builtin/rng.rb +25 -0
- data/lib/nydp/builtin/ruby_wrap.rb +27 -14
- data/lib/nydp/builtin/script_run.rb +1 -3
- data/lib/nydp/builtin/set_intersection.rb +3 -4
- data/lib/nydp/builtin/set_union.rb +3 -4
- data/lib/nydp/builtin/sort.rb +2 -7
- data/lib/nydp/builtin/string_match.rb +5 -13
- data/lib/nydp/builtin/string_replace.rb +2 -7
- data/lib/nydp/builtin/string_split.rb +3 -8
- data/lib/nydp/builtin/sym.rb +2 -9
- data/lib/nydp/builtin/thread_locals.rb +2 -2
- data/lib/nydp/builtin/time.rb +38 -44
- data/lib/nydp/builtin/times.rb +6 -15
- data/lib/nydp/builtin/to_integer.rb +8 -14
- data/lib/nydp/builtin/to_string.rb +2 -13
- data/lib/nydp/builtin/type_of.rb +10 -16
- data/lib/nydp/builtin/vm_info.rb +2 -10
- data/lib/nydp/builtin.rb +15 -37
- data/lib/nydp/compiler.rb +29 -19
- data/lib/nydp/cond.rb +95 -88
- data/lib/nydp/context_symbol.rb +11 -9
- data/lib/nydp/core.rb +74 -73
- data/lib/nydp/core_ext.rb +87 -26
- data/lib/nydp/date.rb +22 -19
- data/lib/nydp/error.rb +2 -3
- data/lib/nydp/function_invocation.rb +76 -289
- data/lib/nydp/helper.rb +18 -9
- data/lib/nydp/interpreted_function.rb +159 -25
- data/lib/nydp/lexical_context.rb +9 -8
- data/lib/nydp/lexical_context_builder.rb +1 -1
- data/lib/nydp/literal.rb +3 -7
- data/lib/nydp/loop.rb +72 -0
- data/lib/nydp/namespace.rb +52 -0
- data/lib/nydp/pair.rb +146 -50
- data/lib/nydp/parser.rb +9 -11
- data/lib/nydp/plugin.rb +88 -19
- data/lib/nydp/runner.rb +141 -23
- data/lib/nydp/symbol.rb +16 -26
- data/lib/nydp/symbol_lookup.rb +3 -2
- data/lib/nydp/tokeniser.rb +1 -1
- data/lib/nydp/truth.rb +2 -37
- data/lib/nydp/version.rb +1 -1
- data/lib/nydp.rb +33 -44
- data/nydp.gemspec +2 -1
- data/spec/date_spec.rb +26 -32
- data/spec/embedded_spec.rb +22 -22
- data/spec/error_spec.rb +12 -16
- data/spec/foreign_hash_spec.rb +21 -36
- data/spec/hash_non_hash_behaviour_spec.rb +12 -29
- data/spec/hash_spec.rb +36 -49
- data/spec/literal_spec.rb +6 -6
- data/spec/nydp_spec.rb +14 -14
- data/spec/pair_spec.rb +8 -8
- data/spec/parser_spec.rb +41 -37
- data/spec/rand_spec.rb +1 -4
- data/spec/spec_helper.rb +3 -3
- data/spec/string_atom_spec.rb +15 -16
- data/spec/symbol_spec.rb +27 -52
- data/spec/thread_local_spec.rb +23 -8
- data/spec/time_spec.rb +4 -10
- data/spec/tokeniser_spec.rb +10 -10
- metadata +25 -13
- data/lib/nydp/builtin/modulo.rb +0 -11
- data/lib/nydp/builtin/regexp.rb +0 -7
- data/lib/nydp/builtin/sqrt.rb +0 -7
- data/lib/nydp/builtin/string_pad_left.rb +0 -7
- data/lib/nydp/builtin/string_pad_right.rb +0 -7
- data/lib/nydp/hash.rb +0 -9
- data/lib/nydp/image_store.rb +0 -21
- data/lib/nydp/vm.rb +0 -129
@@ -16,7 +16,7 @@
|
|
16
16
|
`(cond ,(car args) ,(cadr args)))
|
17
17
|
(car args))
|
18
18
|
nil)
|
19
|
-
|
19
|
+
(dox/attrs (flow-control)))
|
20
20
|
|
21
21
|
(dox-add-doc 'map
|
22
22
|
'def
|
@@ -27,21 +27,23 @@
|
|
27
27
|
(cons (f (car things)) (map f (cdr things)))
|
28
28
|
things
|
29
29
|
(f things))
|
30
|
-
|
30
|
+
(dox/attrs (list-manipulation)))
|
31
31
|
|
32
32
|
(dox-add-doc 'rev
|
33
33
|
'def
|
34
|
-
'("
|
34
|
+
'("@things@ - the list to be reversed"
|
35
|
+
"@last-cdr@ - (normally nil) - an item (atom, list, nil, anything) "
|
36
|
+
"to be consed to the end of the reversed list.")
|
35
37
|
'(things)
|
36
|
-
'(
|
37
|
-
|
38
|
+
'(def rev (things last-cdr) (loop (pair? things) ((fn nil (assign last-cdr (cons (car things) last-cdr)) (assign things (cdr things))))) last-cdr)
|
39
|
+
(dox/attrs (list-manipulation)))
|
38
40
|
|
39
41
|
(dox-add-doc 'hash-cons
|
40
42
|
'def
|
41
43
|
'("push 'v onto the value for 'k in 'h")
|
42
44
|
'(h k v)
|
43
45
|
'(hash-set h k (cons v (hash-get h k)))
|
44
|
-
|
46
|
+
(dox/attrs (hash-manipulation)))
|
45
47
|
|
46
48
|
;; equivalent to (join-str "~prefix~joint~(car things)" joint (cdr things)) - except
|
47
49
|
;; 'string-pieces hasn't been defined yet, and if it were, it would be defined in terms of
|
@@ -56,3 +58,28 @@
|
|
56
58
|
joint
|
57
59
|
(cdr things))
|
58
60
|
prefix))
|
61
|
+
|
62
|
+
;; returns the 'thing if the 'thing is present? ; otherwise nil
|
63
|
+
;; useful for compressing forms like
|
64
|
+
;;
|
65
|
+
;; (let thing (get-the-thing)
|
66
|
+
;; (if (present? thing)
|
67
|
+
;; (do-thing-stuff thing)))
|
68
|
+
;;
|
69
|
+
;; down to
|
70
|
+
;;
|
71
|
+
;; (aif (nb thing) (do-thing-stuff it))
|
72
|
+
;;
|
73
|
+
;;
|
74
|
+
;; or, alternatively, compressing
|
75
|
+
;;
|
76
|
+
;; (let thing (get-the-thing)
|
77
|
+
;; (if (present? thing)
|
78
|
+
;; thing
|
79
|
+
;; (get-the-other-thing)))
|
80
|
+
;;
|
81
|
+
;; down to
|
82
|
+
;;
|
83
|
+
;; (or (nb (get-the-thing)) (get-the-other-thing))
|
84
|
+
;;
|
85
|
+
(def nb (thing) (if (present? thing) thing nil))
|
@@ -6,8 +6,8 @@
|
|
6
6
|
|
7
7
|
(warnings/clear)
|
8
8
|
|
9
|
+
;; apply f to each stored warning. For example, (warnings p) to print warnings to console
|
9
10
|
(def warnings (f)
|
10
|
-
; apply f to each stored warning. For example, (warnings p) to print warnings to console
|
11
11
|
(mapply f warnings))
|
12
12
|
|
13
13
|
(def warnings/new (kind . info)
|
@@ -106,17 +106,17 @@ scoping, assignment, anonymous functions and more...")
|
|
106
106
|
(mac let (var val . body)
|
107
107
|
`((fun (,var) ,@body) ,val))
|
108
108
|
|
109
|
+
;; creates a named, locally-scoped function
|
110
|
+
;; with the given parameter names. It is possible
|
111
|
+
;; to reference the function by its name from within
|
112
|
+
;; the function (to pass as an argument or for
|
113
|
+
;; recursive invocation)
|
109
114
|
(mac rfn (name parms . body)
|
110
|
-
; creates a named, locally-scoped function
|
111
|
-
; with the given parameter names. It is possible
|
112
|
-
; to reference the function by its name from within
|
113
|
-
; the function (to pass as an argument or for
|
114
|
-
; recursive invocation)
|
115
115
|
`(let ,name nil
|
116
116
|
(assign ,name (fn ,parms ,@body))))
|
117
117
|
|
118
|
+
;; same as @rfn@, but using the name @self@
|
118
119
|
(mac afn (parms . body)
|
119
|
-
; same as 'rfn, but using the name 'self
|
120
120
|
`(rfn self ,parms ,@body))
|
121
121
|
|
122
122
|
;; a mix of rfn and with; creates a locally-scoped named function with
|
@@ -130,23 +130,17 @@ scoping, assignment, anonymous functions and more...")
|
|
130
130
|
(assign ,name (fun ,(map car ppairs) ,@body))
|
131
131
|
(,name ,@(map cadr ppairs)))))
|
132
132
|
|
133
|
-
;;
|
134
|
-
;;
|
135
|
-
;;
|
136
|
-
;;
|
137
|
-
;;
|
138
|
-
(def
|
139
|
-
(
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
(let uniq-counter 0
|
145
|
-
(def uniq (prefix)
|
146
|
-
(assign uniq-counter (+ uniq-counter 1))
|
147
|
-
(sym (join-str prefix "-" (list uniq-counter))))
|
148
|
-
(def reset-uniq-counter ()
|
149
|
-
(assign uniq-counter 0)))
|
133
|
+
;; increments a counter and appends it to prefix
|
134
|
+
;; return value should be unique until @unique-counter@ is reset
|
135
|
+
;; @unique-counter@ is reset before compiling a new expression, so under normal circumstances,
|
136
|
+
;; the returned value is unique within an expression, but not across the entire system.
|
137
|
+
;; Don't use these values for global variables!
|
138
|
+
(def uniq (prefix)
|
139
|
+
(assign uniq-counter (+ uniq-counter 1))
|
140
|
+
(sym (join-str prefix "-" (list uniq-counter))))
|
141
|
+
|
142
|
+
(def reset-uniq-counter ()
|
143
|
+
(assign uniq-counter 0))
|
150
144
|
|
151
145
|
;; creates a lexical scope with a unique symbol assigned to
|
152
146
|
;; each variable in 'vars ; executes the 'body.
|
@@ -156,9 +150,19 @@ scoping, assignment, anonymous functions and more...")
|
|
156
150
|
,@body)
|
157
151
|
`(let ,vars (uniq ',vars) ,@body)))
|
158
152
|
|
153
|
+
;; @(andify a b c)@ is equivalent to
|
154
|
+
;; @(fn args (and (apply a args) (apply b args) (apply c args)))@
|
155
|
+
;; or more simply
|
156
|
+
;; @(fn (x) (and (a x) (b x) (c x)))@
|
157
|
+
;; note: alias as 'andf ??
|
158
|
+
(mac andify args
|
159
|
+
(w/uniq a2
|
160
|
+
`(fn ,a2
|
161
|
+
(and ,@(map (fn (a) `(apply ,a ,a2)) args)))))
|
162
|
+
|
163
|
+
;; lazy-evaluates each argument, returns the first
|
164
|
+
;; non-nil result, or nil if all evaluate to nil.
|
159
165
|
(mac or args
|
160
|
-
; lazy-evaluates each argument, returns the first
|
161
|
-
; non-nil result, or nil if all evaluate to nil.
|
162
166
|
(if (cdr args)
|
163
167
|
(let arg (car args)
|
164
168
|
(if (isa 'symbol arg)
|
@@ -184,8 +188,8 @@ scoping, assignment, anonymous functions and more...")
|
|
184
188
|
name)
|
185
189
|
(list 'quote name)))
|
186
190
|
|
191
|
+
;; (build-hash-getters '(a b c)) => (hash-get (hash-get a 'b) 'c)
|
187
192
|
(def build-hash-getters (names acc)
|
188
|
-
;; (build-hash-getters '(a b c)) => (hash-get (hash-get a 'b) 'c)
|
189
193
|
(if (no acc)
|
190
194
|
(build-hash-getters (cdr names) (car names))
|
191
195
|
names
|
@@ -198,12 +202,12 @@ scoping, assignment, anonymous functions and more...")
|
|
198
202
|
(mac hash-lookup (names)
|
199
203
|
(build-hash-getters names nil))
|
200
204
|
|
205
|
+
;; parser expands a.b to (dot-syntax a b)
|
201
206
|
(mac dot-syntax names
|
202
|
-
; parser expands a.b to (dot-syntax a b)
|
203
207
|
`(hash-lookup ,names))
|
204
208
|
|
209
|
+
;; parser expands a$b to (dollar-syntax a b)
|
205
210
|
(mac dollar-syntax (_ name)
|
206
|
-
; parser expands a$b to (dollar-syntax a b)
|
207
211
|
`(,name))
|
208
212
|
|
209
213
|
(def dot-syntax-assignment (names value-expr)
|
@@ -293,13 +297,16 @@ scoping, assignment, anonymous functions and more...")
|
|
293
297
|
(mac #= (name value)
|
294
298
|
`(do (= ,name ,value) nil))
|
295
299
|
|
296
|
-
|
300
|
+
;; increment the value at 'place by 'inc (default 1)
|
297
301
|
(mac ++ (place inc) `(= ,place (+ ,place ,(or inc 1))))
|
298
302
|
|
299
|
-
|
303
|
+
;; decrement the value at 'place by 'inc (default 1)
|
304
|
+
(mac -- (place inc) `(= ,place (- ,place ,(or inc 1))))
|
305
|
+
|
306
|
+
;; override previous definition to allow expressions like (def hsh.foo (arg arg2) ...)
|
300
307
|
(mac def-assign args `(= ,@args))
|
301
308
|
|
302
|
-
|
309
|
+
;; evaluate ,val and assign result to ,place only if ,place is already nil
|
303
310
|
(mac or= (place val) `(or ,place (= ,place ,val)))
|
304
311
|
|
305
312
|
(def brace-list-hash-key (k)
|
@@ -307,33 +314,34 @@ scoping, assignment, anonymous functions and more...")
|
|
307
314
|
(caris 'unquote k) (cadr k)
|
308
315
|
k))
|
309
316
|
|
317
|
+
;; TODO instead expand to: (hash 'k1 v1 'k2 v2 'k3 v3 ...)
|
318
|
+
;; TODO builtin-hash function takes care of constructing the hash
|
310
319
|
(def brace-list-build-hash (args)
|
311
|
-
(
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
,hash))))
|
320
|
+
`(hash ,@(apply
|
321
|
+
+
|
322
|
+
(map (fn (kv) (list (brace-list-hash-key (car kv)) (cadr kv)))
|
323
|
+
(pairs args)))))
|
316
324
|
|
317
325
|
(def build-ampersand-syntax (arg)
|
318
326
|
(if (caris 'dot-syntax arg)
|
319
327
|
`(fn (obj) ,(build-hash-lookup-from 'obj (cdr arg)))
|
320
328
|
`(fn (obj) ,(build-hash-lookup-from 'obj (list arg)))))
|
321
329
|
|
330
|
+
;; parser expands a&b to (ampersand-syntax a b)
|
322
331
|
(mac ampersand-syntax (pfx . rest)
|
323
|
-
; parser expands a&b to (ampersand-syntax a b)
|
324
332
|
(if (no (eq? pfx '||))
|
325
333
|
(error "Irregular '& syntax: got prefix ~(inspect pfx) in ~(join-str pfx "&" rest)"))
|
326
334
|
(if (cdr rest)
|
327
335
|
(error "Irregular '& syntax: got suffix ~(inspect (cdr rest)) in ~(join-str pfx "&" rest)")
|
328
336
|
(build-ampersand-syntax (car rest))))
|
329
337
|
|
330
|
-
|
338
|
+
;; override 'brace-list-mono in order to provide a useful interpretation for "{ x }" syntax
|
331
339
|
(mac brace-list-mono (arg) arg)
|
332
340
|
|
333
|
-
|
341
|
+
;; interprets "{ }" as new hash
|
334
342
|
(mac brace-list-empty () '(hash))
|
335
343
|
|
336
|
-
|
344
|
+
;; parser expands { foo bar } to (brace-list foo bar)
|
337
345
|
(mac brace-list args
|
338
346
|
(if (no args)
|
339
347
|
`(brace-list-empty)
|
@@ -341,13 +349,13 @@ scoping, assignment, anonymous functions and more...")
|
|
341
349
|
`(brace-list-mono ,(car args))
|
342
350
|
(brace-list-build-hash args)))
|
343
351
|
|
344
|
-
|
345
|
-
|
352
|
+
;; stores ,val in ,var, executes ,@body, returns ,var. Saves a line of code at the end of
|
353
|
+
;; 'let. If 'body assigns to 'var, the assigned value of 'var will be returned. See also 'returning
|
346
354
|
(mac returnlet (var val . body) `(let ,var ,val ,@body ,var))
|
347
355
|
|
348
|
-
|
349
|
-
|
350
|
-
|
356
|
+
;; stores ,val, executes ,@body, and returns ,val. Assumes 'body is going to do something
|
357
|
+
;; destructive with 'val, but you want 'val before it gets changed. Note that if 'val is mutated
|
358
|
+
;; (eg hash), the mutated value will be returned. See also 'returnlet
|
351
359
|
(mac returning (val . body) (w/uniq retval `(returnlet ,retval ,val ,@body)))
|
352
360
|
|
353
361
|
(mac ifv (var expr . body)
|
@@ -363,11 +371,19 @@ scoping, assignment, anonymous functions and more...")
|
|
363
371
|
(mac aif (expr . body)
|
364
372
|
`(ifv it ,expr ,@body))
|
365
373
|
|
374
|
+
;; returns the nth cdr of the list 'things
|
375
|
+
(def nthcdr (n things)
|
376
|
+
(loop (> n 0)
|
377
|
+
(= things (cdr things)
|
378
|
+
n (- n 1)))
|
379
|
+
things)
|
380
|
+
|
366
381
|
;; returns the n-th item in the list 'things
|
367
382
|
(def nth (n things)
|
368
|
-
(
|
369
|
-
|
370
|
-
|
383
|
+
(loop (> n 0)
|
384
|
+
(= things (cdr things)
|
385
|
+
n (- n 1)))
|
386
|
+
(car things))
|
371
387
|
|
372
388
|
(def destructure/with (var args n)
|
373
389
|
; provides the argument expression to 'with when
|
@@ -4,40 +4,33 @@
|
|
4
4
|
; executes 'body. If an error is raised, executes 'handler. Inside
|
5
5
|
; 'handler, the parameter 'errors is a list of error messages extracted from
|
6
6
|
; the sequence of errors that led here (Exception#cause in ruby or Throwable.getCause() in java)
|
7
|
-
`(handle-error (fn (errors) ,handler)
|
8
|
-
(fn ()
|
7
|
+
`(handle-error (fn (errors traces) ,handler)
|
8
|
+
(fn () ,@body)))
|
9
9
|
|
10
|
+
;; executes 'body. Afterwards, executes 'protection.
|
11
|
+
;; 'protection is always executed even if there is an error.
|
10
12
|
(mac ensure (protection . body)
|
11
|
-
; executes 'body. Afterwards, executes 'protection.
|
12
|
-
; 'protection is always executed even if there is an error.
|
13
13
|
`(ensuring (fn () ,protection)
|
14
14
|
(fn () ,@body)))
|
15
15
|
|
16
16
|
;; tests 'test, as long as 'test is non-nil,
|
17
17
|
;; repeatedly executes 'body
|
18
18
|
(mac while (test . body)
|
19
|
-
(
|
20
|
-
`(rfnwith ,rfname (,pred ,test)
|
21
|
-
(when ,pred
|
22
|
-
,@body
|
23
|
-
(,rfname ,test)))))
|
19
|
+
`(loop ,test (do ,@body)))
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
(
|
29
|
-
|
30
|
-
|
31
|
-
(if ,gparm
|
32
|
-
(do ,@body ,update (,gfn ,test))))
|
33
|
-
,test))))
|
21
|
+
;; execute 'start, then for as long as 'test returns non-nil,
|
22
|
+
;; execute 'body and 'update
|
23
|
+
(mac looping (start test update . body)
|
24
|
+
`(do
|
25
|
+
,start
|
26
|
+
(while ,test ,@body ,update)))
|
34
27
|
|
28
|
+
;; assign 'init to 'v, then execute 'body 'max times,
|
29
|
+
;; incrementing 'v at each iteration
|
35
30
|
(mac for (v init max . body)
|
36
|
-
; assign 'init to 'v, then execute 'body 'max times,
|
37
|
-
; incrementing 'v at each iteration
|
38
31
|
(w/uniq (gi gm)
|
39
32
|
`(with (,v nil ,gi ,init ,gm (+ ,max 1))
|
40
|
-
(
|
33
|
+
(looping (assign ,v ,gi) (< ,v ,gm) (assign ,v (+ ,v 1))
|
41
34
|
,@body))))
|
42
35
|
|
43
36
|
;; return a new function which is the original function with
|
@@ -56,14 +49,13 @@
|
|
56
49
|
`(fn (arg)
|
57
50
|
(,f ,@args arg)))
|
58
51
|
|
52
|
+
;; if ,key is already in ,hsh - return the associated value.
|
53
|
+
;; if ,key is not already in ,hsh - evaluate ,val, store the result
|
54
|
+
;; under ,key in ,hsh, and return it
|
59
55
|
(mac cache-get (hsh key val)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
(w/uniq (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)))))))
|
56
|
+
(w/uniq (h k)
|
57
|
+
`(with (,h ,hsh ,k ,key)
|
58
|
+
(or= (hash-get ,h ,k) ,val))))
|
67
59
|
|
68
60
|
;; same as 'def, but caches the result, keyed on args, so for a given set of args the result
|
69
61
|
;; is only ever calculated once
|
@@ -9,40 +9,103 @@
|
|
9
9
|
; invokes 'f for each element of 'things, first element processed first
|
10
10
|
; ( "l" in "eachl" = "leftmost first" )
|
11
11
|
(def eachl (f things)
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
(loop (pair? things)
|
13
|
+
(do
|
14
|
+
(f (car things))
|
15
|
+
(= things (cdr things)))))
|
15
16
|
|
16
17
|
;; if things is a pair,
|
17
18
|
;; if (cdr things) is nil, return (car things)
|
18
19
|
;; else recurse on (cdr things)
|
19
20
|
;; else return things
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
;;
|
22
|
+
;; 'it is used internally
|
23
|
+
;;
|
24
|
+
(def list/last (things it)
|
25
|
+
(loop (pair? things)
|
26
|
+
(= it (car things)
|
27
|
+
things (cdr things)))
|
28
|
+
(or things it))
|
29
|
+
|
30
|
+
;; finds the index in 'things for which 'f returns non-nil,
|
31
|
+
;; or nil if not found
|
32
|
+
(def list/find-index (f things)
|
33
|
+
(with (found nil
|
34
|
+
i -1)
|
35
|
+
(loop (and things
|
36
|
+
(no found))
|
37
|
+
(= found (f (car things))
|
38
|
+
things (cdr things)
|
39
|
+
i (+ i 1)))
|
40
|
+
(and found i)))
|
41
|
+
|
42
|
+
;; finds the index of 'thing in a list 'things, such that for example,
|
43
|
+
;; given a list 'my-list and an item 'thingy in the list,
|
44
|
+
;; (nth (list/index-of thingy my-list) my-list) will return the value of thingy.
|
45
|
+
;; returns nil if not found
|
46
|
+
(def list/index-of (thing things)
|
47
|
+
(list/find-index
|
48
|
+
(fn (it) (eq? it thing))
|
49
|
+
things))
|
50
|
+
|
51
|
+
;; given a number 'n and a list 'things, return (a b) where a is
|
52
|
+
;; the item at index n-1 or nil if not possible, and b is the item
|
53
|
+
;; at index n+1 or nil if not possible
|
54
|
+
(def list/around (n things)
|
55
|
+
(if (and n
|
56
|
+
(< -1 n (len things)))
|
57
|
+
(list
|
58
|
+
(and (> n 0)
|
59
|
+
(nth (- n 1) things))
|
60
|
+
(nth (+ n 1) things))
|
61
|
+
(list nil nil)))
|
62
|
+
|
63
|
+
;; finds the item before and the item after the given item in the given list.
|
64
|
+
;; For example,
|
65
|
+
;; (list/around λx(eq? x 'd) '(a b c d e f) ) will return '(c e)
|
66
|
+
(def list/around-f (f things)
|
67
|
+
(list/around
|
68
|
+
(list/find-index f things)
|
69
|
+
things))
|
70
|
+
|
71
|
+
;; finds the item before and the item after the given item in the given list.
|
72
|
+
;; For example,
|
73
|
+
;; (list/around '(a b c d e f) 'd) will return '(c e)
|
74
|
+
(def list/around-thing (thing things)
|
75
|
+
(list/around
|
76
|
+
(list/index-of thing things)
|
77
|
+
things))
|
26
78
|
|
27
79
|
; invokes 'f for each element of 'things, last element processed first
|
28
80
|
; ( "r" in "eachr" = "rightmost first" )
|
29
81
|
(def eachr (f things)
|
30
|
-
|
31
|
-
(eachr f (cdr things))
|
32
|
-
(f (car things))))
|
82
|
+
(eachl f (rev things)))
|
33
83
|
|
34
84
|
; assign (cons x things) to things
|
35
|
-
(mac push (x things)
|
85
|
+
(mac push (x things)
|
86
|
+
`(= ,things (cons ,x ,things)))
|
87
|
+
|
88
|
+
;; used internally by 'flatmap
|
89
|
+
(def flatmap-helper (f things res)
|
90
|
+
(loop (pair? things)
|
91
|
+
(let a (car things)
|
92
|
+
(= res
|
93
|
+
(if (pair? a)
|
94
|
+
(flatmap-helper f a res)
|
95
|
+
a
|
96
|
+
(cdr-set res (cons (f a)))
|
97
|
+
res)
|
98
|
+
things
|
99
|
+
(cdr things))))
|
100
|
+
(if things
|
101
|
+
(= res (set-cdr res (f things))))
|
102
|
+
res)
|
36
103
|
|
37
|
-
|
104
|
+
;; flatten the given list, transforming each leaf-item, recursively
|
38
105
|
(def flatmap (f things)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
(eachr flattenize x)
|
43
|
-
x
|
44
|
-
(push (f x) acc)))
|
45
|
-
acc))
|
106
|
+
(let res (cons)
|
107
|
+
(flatmap-helper f things res)
|
108
|
+
(cdr res)))
|
46
109
|
|
47
110
|
; flatten the given list, recursively
|
48
111
|
(def flatten (things) (flatmap x1 things))
|
@@ -59,16 +59,16 @@
|
|
59
59
|
(mac in-private body
|
60
60
|
`(w/privately t ,@body))
|
61
61
|
|
62
|
+
;; a macro wrapper for 'map
|
63
|
+
;; 'things is a list, 'x is the name of a variable, and 'expr
|
64
|
+
;; is evaluated and collected for each 'x in 'things
|
65
|
+
;; usage: (mapx items v (to-string v)) equivalent to (map to-string items)
|
62
66
|
(mac mapx (things x expr)
|
63
|
-
; a macro wrapper for 'map
|
64
|
-
; 'things is a list, 'x is the name of a variable, and 'expr
|
65
|
-
; is evaluated and collected for each 'x in 'things
|
66
|
-
; usage: (mapx items v (to-string v)) equivalent to (map to-string items)
|
67
67
|
(chapter list-manipulation)
|
68
68
|
`(map (fun (,x) ,expr) ,things))
|
69
69
|
|
70
|
+
;; 't if 'thing is not nil or a list or a hash
|
70
71
|
(def atom? (thing)
|
71
|
-
; 't if 'thing is not a list or a hash
|
72
72
|
(chapter nydp-core)
|
73
73
|
(and thing
|
74
74
|
(!pair? thing)
|
@@ -93,6 +93,8 @@
|
|
93
93
|
|
94
94
|
;; returns the first non-empty item in 'args
|
95
95
|
;; mac equivalent of (detect present? args)
|
96
|
+
;; useful to obtain a non-blank value from a set of variables, for example
|
97
|
+
;; (%span.name (dp {first} {last} {email} "unknown"))
|
96
98
|
(mac dp args
|
97
99
|
(if args
|
98
100
|
(w/uniq nearg
|
@@ -108,6 +110,7 @@
|
|
108
110
|
;; (p (c)) ;;=> 1
|
109
111
|
;; (p (c))) ;;=> 2
|
110
112
|
;;
|
113
|
+
;; see also 'seqf which does almost exactly the same thing
|
111
114
|
(def counter ()
|
112
115
|
(let i -1
|
113
116
|
(fn () (++ i))))
|
@@ -4,26 +4,26 @@
|
|
4
4
|
(def string-strip (txt)
|
5
5
|
(string-replace "(\\A\\s+|\\s+\\z)" "" txt))
|
6
6
|
|
7
|
+
;; flatten 'things into a single list (ie unnest lists)
|
8
|
+
;; convert each item to a string
|
9
|
+
;; return a single string which is the concatenation of each
|
10
|
+
;; stringified item, with given 'txt inserted in between
|
11
|
+
;; each item
|
7
12
|
(def joinstr (txt . things)
|
8
|
-
; flatten 'things into a single list (ie unnest lists)
|
9
|
-
; convert each item to a string
|
10
|
-
; return a single string which is the concatenation of each
|
11
|
-
; stringified item, with given 'txt inserted in between
|
12
|
-
; each item
|
13
13
|
(let joinables (flatten things)
|
14
14
|
(apply +
|
15
15
|
(to-string:car joinables)
|
16
16
|
(flatten (map (fn (x) (list txt x))
|
17
17
|
(cdr joinables))))))
|
18
18
|
|
19
|
-
|
19
|
+
;; stringify join all the things and join them with no separator, like (joinstr "" things)
|
20
20
|
(def j things
|
21
|
-
(apply + (flatmap to-string things)))
|
21
|
+
(apply + "" (flatmap to-string things)))
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
;; string-interpolation syntax emits this form. Default implementation
|
24
|
+
;; is to delegate to 'j , but containing forms may use macros that
|
25
|
+
;; override this in order to provide specific interpolation behaviour
|
26
|
+
;; (for example, formatting numbers or stripping HTML tags)
|
27
27
|
(def string-pieces pieces
|
28
28
|
(j pieces))
|
29
29
|
|
@@ -54,3 +54,9 @@
|
|
54
54
|
"\nand args " (inspect args)))
|
55
55
|
(apply (string-eval-fn str arg-names)
|
56
56
|
args)))
|
57
|
+
|
58
|
+
;; if txt is not blank/empty, return concatenation of before, txt, after
|
59
|
+
(def maybe-wrap-text (txt before after)
|
60
|
+
(if (nb txt)
|
61
|
+
(j before txt after)
|
62
|
+
txt))
|