nydp 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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))
|