nydp 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +77 -56
  4. data/lib/lisp/core-000.nydp +1 -1
  5. data/lib/lisp/core-010-precompile.nydp +49 -29
  6. data/lib/lisp/core-012-utils.nydp +12 -8
  7. data/lib/lisp/core-015-documentation.nydp +41 -15
  8. data/lib/lisp/core-017-builtin-dox.nydp +621 -100
  9. data/lib/lisp/core-020-utils.nydp +33 -6
  10. data/lib/lisp/core-025-warnings.nydp +1 -1
  11. data/lib/lisp/core-030-syntax.nydp +64 -48
  12. data/lib/lisp/core-035-flow-control.nydp +20 -28
  13. data/lib/lisp/core-037-list-utils.nydp +84 -21
  14. data/lib/lisp/core-040-utils.nydp +8 -5
  15. data/lib/lisp/core-041-string-utils.nydp +17 -11
  16. data/lib/lisp/core-043-list-utils.nydp +140 -77
  17. data/lib/lisp/core-045-dox-utils.nydp +1 -0
  18. data/lib/lisp/core-050-test-runner.nydp +8 -12
  19. data/lib/lisp/core-070-prefix-list.nydp +19 -15
  20. data/lib/lisp/core-080-pretty-print.nydp +13 -5
  21. data/lib/lisp/core-090-hook.nydp +11 -11
  22. data/lib/lisp/core-100-utils.nydp +51 -66
  23. data/lib/lisp/core-110-hash-utils.nydp +34 -7
  24. data/lib/lisp/core-120-settings.nydp +14 -9
  25. data/lib/lisp/core-130-validations.nydp +28 -13
  26. data/lib/lisp/core-900-benchmarking.nydp +420 -47
  27. data/lib/lisp/tests/000-empty-args-examples.nydp +5 -0
  28. data/lib/lisp/tests/andify-examples.nydp +1 -1
  29. data/lib/lisp/tests/auto-hash-examples.nydp +6 -1
  30. data/lib/lisp/tests/best-examples.nydp +1 -1
  31. data/lib/lisp/tests/boot-tests.nydp +1 -1
  32. data/lib/lisp/tests/date-examples.nydp +129 -102
  33. data/lib/lisp/tests/destructuring-examples.nydp +1 -1
  34. data/lib/lisp/tests/dox-tests.nydp +2 -2
  35. data/lib/lisp/tests/hash-examples.nydp +58 -33
  36. data/lib/lisp/tests/list-tests.nydp +137 -1
  37. data/lib/lisp/tests/pretty-print-tests.nydp +12 -0
  38. data/lib/lisp/tests/rotate-2d-array-examples.nydp +26 -0
  39. data/lib/lisp/tests/sort-examples.nydp +5 -5
  40. data/lib/lisp/tests/string-tests.nydp +16 -5
  41. data/lib/lisp/tests/syntax-tests.nydp +10 -2
  42. data/lib/lisp/tests/time-examples.nydp +8 -1
  43. data/lib/lisp/tests/unparse-tests.nydp +13 -7
  44. data/lib/nydp/assignment.rb +15 -28
  45. data/lib/nydp/builtin/abs.rb +4 -3
  46. data/lib/nydp/builtin/apply.rb +8 -10
  47. data/lib/nydp/builtin/cdr_set.rb +1 -1
  48. data/lib/nydp/builtin/comment.rb +1 -3
  49. data/lib/nydp/builtin/date.rb +11 -28
  50. data/lib/nydp/builtin/divide.rb +3 -10
  51. data/lib/nydp/builtin/ensuring.rb +6 -21
  52. data/lib/nydp/builtin/error.rb +2 -4
  53. data/lib/nydp/builtin/eval.rb +9 -4
  54. data/lib/nydp/builtin/greater_than.rb +7 -8
  55. data/lib/nydp/builtin/handle_error.rb +10 -34
  56. data/lib/nydp/builtin/hash.rb +24 -45
  57. data/lib/nydp/builtin/inspect.rb +1 -3
  58. data/lib/nydp/builtin/is_equal.rb +4 -7
  59. data/lib/nydp/builtin/less_than.rb +6 -7
  60. data/lib/nydp/builtin/log.rb +7 -0
  61. data/lib/nydp/builtin/math_ceiling.rb +1 -3
  62. data/lib/nydp/builtin/math_floor.rb +1 -3
  63. data/lib/nydp/builtin/math_power.rb +1 -3
  64. data/lib/nydp/builtin/math_round.rb +2 -2
  65. data/lib/nydp/builtin/minus.rb +7 -14
  66. data/lib/nydp/builtin/parse.rb +5 -5
  67. data/lib/nydp/builtin/parse_in_string.rb +5 -7
  68. data/lib/nydp/builtin/plus.rb +14 -31
  69. data/lib/nydp/builtin/pre_compile.rb +1 -3
  70. data/lib/nydp/builtin/puts.rb +4 -8
  71. data/lib/nydp/builtin/quit.rb +1 -1
  72. data/lib/nydp/builtin/rand.rb +6 -11
  73. data/lib/nydp/builtin/random_string.rb +2 -4
  74. data/lib/nydp/builtin/rng.rb +25 -0
  75. data/lib/nydp/builtin/ruby_wrap.rb +27 -14
  76. data/lib/nydp/builtin/script_run.rb +1 -3
  77. data/lib/nydp/builtin/set_intersection.rb +3 -4
  78. data/lib/nydp/builtin/set_union.rb +3 -4
  79. data/lib/nydp/builtin/sort.rb +2 -7
  80. data/lib/nydp/builtin/string_match.rb +5 -13
  81. data/lib/nydp/builtin/string_replace.rb +2 -7
  82. data/lib/nydp/builtin/string_split.rb +3 -8
  83. data/lib/nydp/builtin/sym.rb +2 -9
  84. data/lib/nydp/builtin/thread_locals.rb +2 -2
  85. data/lib/nydp/builtin/time.rb +38 -44
  86. data/lib/nydp/builtin/times.rb +6 -15
  87. data/lib/nydp/builtin/to_integer.rb +8 -14
  88. data/lib/nydp/builtin/to_string.rb +2 -13
  89. data/lib/nydp/builtin/type_of.rb +10 -16
  90. data/lib/nydp/builtin/vm_info.rb +2 -10
  91. data/lib/nydp/builtin.rb +15 -37
  92. data/lib/nydp/compiler.rb +29 -19
  93. data/lib/nydp/cond.rb +95 -88
  94. data/lib/nydp/context_symbol.rb +11 -9
  95. data/lib/nydp/core.rb +74 -73
  96. data/lib/nydp/core_ext.rb +87 -26
  97. data/lib/nydp/date.rb +22 -19
  98. data/lib/nydp/error.rb +2 -3
  99. data/lib/nydp/function_invocation.rb +76 -289
  100. data/lib/nydp/helper.rb +18 -9
  101. data/lib/nydp/interpreted_function.rb +159 -25
  102. data/lib/nydp/lexical_context.rb +9 -8
  103. data/lib/nydp/lexical_context_builder.rb +1 -1
  104. data/lib/nydp/literal.rb +3 -7
  105. data/lib/nydp/loop.rb +72 -0
  106. data/lib/nydp/namespace.rb +52 -0
  107. data/lib/nydp/pair.rb +146 -50
  108. data/lib/nydp/parser.rb +9 -11
  109. data/lib/nydp/plugin.rb +88 -19
  110. data/lib/nydp/runner.rb +141 -23
  111. data/lib/nydp/symbol.rb +16 -26
  112. data/lib/nydp/symbol_lookup.rb +3 -2
  113. data/lib/nydp/tokeniser.rb +1 -1
  114. data/lib/nydp/truth.rb +2 -37
  115. data/lib/nydp/version.rb +1 -1
  116. data/lib/nydp.rb +33 -44
  117. data/nydp.gemspec +2 -1
  118. data/spec/date_spec.rb +26 -32
  119. data/spec/embedded_spec.rb +22 -22
  120. data/spec/error_spec.rb +12 -16
  121. data/spec/foreign_hash_spec.rb +21 -36
  122. data/spec/hash_non_hash_behaviour_spec.rb +12 -29
  123. data/spec/hash_spec.rb +36 -49
  124. data/spec/literal_spec.rb +6 -6
  125. data/spec/nydp_spec.rb +14 -14
  126. data/spec/pair_spec.rb +8 -8
  127. data/spec/parser_spec.rb +41 -37
  128. data/spec/rand_spec.rb +1 -4
  129. data/spec/spec_helper.rb +3 -3
  130. data/spec/string_atom_spec.rb +15 -16
  131. data/spec/symbol_spec.rb +27 -52
  132. data/spec/thread_local_spec.rb +23 -8
  133. data/spec/time_spec.rb +4 -10
  134. data/spec/tokeniser_spec.rb +10 -10
  135. metadata +25 -13
  136. data/lib/nydp/builtin/modulo.rb +0 -11
  137. data/lib/nydp/builtin/regexp.rb +0 -7
  138. data/lib/nydp/builtin/sqrt.rb +0 -7
  139. data/lib/nydp/builtin/string_pad_left.rb +0 -7
  140. data/lib/nydp/builtin/string_pad_right.rb +0 -7
  141. data/lib/nydp/hash.rb +0 -9
  142. data/lib/nydp/image_store.rb +0 -21
  143. 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
- '(flow-control))
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
- '(list-manipulation))
30
+ (dox/attrs (list-manipulation)))
31
31
 
32
32
  (dox-add-doc 'rev
33
33
  'def
34
- '("returns 'things in reverse order")
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
- '(if (pair? things) (rev (cdr things) (cons (car things) last-cdr)) last-cdr)
37
- '(list-manipulation))
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
- '(hash-manipulation))
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
- ;; (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
-
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
- ; increment the value at 'place by 'inc (default 1)
300
+ ;; increment the value at 'place by 'inc (default 1)
297
301
  (mac ++ (place inc) `(= ,place (+ ,place ,(or inc 1))))
298
302
 
299
- ; override previous definition to allow expressions like (def hsh.foo (arg arg2) ...)
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
- ; evaluate ,val and assign result to ,place only if ,place is already nil
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
- (w/uniq hash
312
- (let mappings (pairs args)
313
- `(let ,hash (hash)
314
- ,@(map (fn (m) `(hash-set ,hash ,(brace-list-hash-key (car m)) ,(cadr m))) mappings)
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
- ; override 'brace-list-mono in order to provide a useful interpretation for "{ x }" syntax
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
- ; interprets "{ }" as new hash
341
+ ;; interprets "{ }" as new hash
334
342
  (mac brace-list-empty () '(hash))
335
343
 
336
- ; parser expands { foo bar } to (brace-list foo bar)
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
- ; 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
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
- ; 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
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
- (if (eq? n 0)
369
- (car things)
370
- (nth (- n 1) (cdr things))))
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 () ,@body)))
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
- (w/uniq (rfname pred)
20
- `(rfnwith ,rfname (,pred ,test)
21
- (when ,pred
22
- ,@body
23
- (,rfname ,test)))))
19
+ `(loop ,test (do ,@body)))
24
20
 
25
- (mac loop (start test update . body)
26
- ; execute 'start, then for as long as 'test returns non-nil,
27
- ; execute 'body and 'update
28
- (w/uniq (gfn gparm)
29
- `(do ,start
30
- ((rfn ,gfn (,gparm)
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
- (loop (assign ,v ,gi) (< ,v ,gm) (assign ,v (+ ,v 1))
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
- ; if ,key is already in ,hsh - return the associated value.
61
- ; if ,key is not already in ,hsh - evaluate ,val, store the result
62
- ; under ,key in ,hsh, and return it
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
- (when things
13
- (f (car things))
14
- (eachl f (cdr things))))
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
- (def list/last (things)
21
- (if (pair? things)
22
- (aif (cdr things)
23
- (list/last it)
24
- (car things))
25
- things))
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
- (when things
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) `(= ,things (cons ,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
- ; flatten the given list, transforming each leaf-item, recursively
104
+ ;; flatten the given list, transforming each leaf-item, recursively
38
105
  (def flatmap (f things)
39
- (let acc nil
40
- (rfnwith flattenize (x things)
41
- (if (pair? x)
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
- ; stringify join all the things and join them with no separator, like (joinstr "" things)
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
- ; 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)
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))