nydp 0.4.3 → 0.4.5
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/lib/lisp/core-010-precompile.nydp +5 -6
- data/lib/lisp/core-012-utils.nydp +2 -1
- data/lib/lisp/core-015-documentation.nydp +17 -11
- data/lib/lisp/core-020-utils.nydp +5 -5
- data/lib/lisp/core-030-syntax.nydp +29 -9
- data/lib/lisp/core-035-flow-control.nydp +15 -6
- data/lib/lisp/core-037-list-utils.nydp +22 -0
- data/lib/lisp/core-039-module.nydp +24 -0
- data/lib/lisp/core-040-utils.nydp +11 -12
- data/lib/lisp/core-041-string-utils.nydp +24 -0
- data/lib/lisp/core-042-date-utils.nydp +16 -0
- data/lib/lisp/core-043-list-utils.nydp +72 -50
- data/lib/lisp/core-080-pretty-print.nydp +50 -17
- data/lib/lisp/core-090-hook.nydp +13 -1
- data/lib/lisp/core-100-utils.nydp +82 -2
- data/lib/lisp/core-110-hash-utils.nydp +38 -0
- data/lib/lisp/core-120-settings.nydp +11 -2
- data/lib/lisp/core-900-benchmarking.nydp +17 -17
- data/lib/lisp/tests/accum-examples.nydp +28 -1
- 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 +10 -0
- data/lib/lisp/tests/case-examples.nydp +14 -0
- data/lib/lisp/tests/date-examples.nydp +54 -1
- data/lib/lisp/tests/detect-examples.nydp +12 -0
- data/lib/lisp/tests/dp-examples.nydp +24 -0
- data/lib/lisp/tests/empty-examples.nydp +1 -1
- data/lib/lisp/tests/error-tests.nydp +4 -4
- data/lib/lisp/tests/hash-examples.nydp +17 -0
- data/lib/lisp/tests/list-grep-examples.nydp +40 -0
- data/lib/lisp/tests/list-tests.nydp +39 -0
- data/lib/lisp/tests/module-examples.nydp +10 -0
- data/lib/lisp/tests/parser-tests.nydp +16 -0
- data/lib/lisp/tests/pretty-print-tests.nydp +8 -2
- data/lib/lisp/tests/settings-examples.nydp +1 -1
- data/lib/lisp/tests/string-tests.nydp +48 -0
- data/lib/lisp/tests/syntax-tests.nydp +5 -1
- data/lib/nydp.rb +6 -3
- 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/date.rb +9 -0
- data/lib/nydp/builtin/error.rb +1 -1
- data/lib/nydp/builtin/hash.rb +11 -1
- data/lib/nydp/builtin/ruby_wrap.rb +69 -0
- data/lib/nydp/builtin/string_pad_left.rb +7 -0
- data/lib/nydp/builtin/string_pad_right.rb +7 -0
- 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 +33 -29
- data/lib/nydp/core_ext.rb +5 -4
- data/lib/nydp/date.rb +17 -17
- data/lib/nydp/function_invocation.rb +33 -25
- data/lib/nydp/helper.rb +12 -2
- data/lib/nydp/interpreted_function.rb +68 -40
- data/lib/nydp/literal.rb +1 -1
- data/lib/nydp/pair.rb +13 -2
- data/lib/nydp/parser.rb +3 -0
- data/lib/nydp/symbol_lookup.rb +7 -7
- data/lib/nydp/version.rb +1 -1
- data/nydp.gemspec +2 -4
- data/spec/date_spec.rb +79 -0
- data/spec/parser_spec.rb +11 -0
- metadata +15 -36
- data/lib/nydp/builtin/car.rb +0 -7
- data/lib/nydp/builtin/cdr.rb +0 -7
- data/lib/nydp/builtin/cons.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1360fe08561240c0e05c70a69629b42b38078275
|
4
|
+
data.tar.gz: 70c0dfe6df1a0b2bf24ef39aca70646d7f8c3cac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5db0e86f33a7ebe4afc33478d1fe6a2da5a6a8d07b85d66532cd155adb9b8b567d6edbe90f3ab0b437f59a03ec2047ca51778c2d0923355131b8e9b718260c83
|
7
|
+
data.tar.gz: 0d4491009c98301ab947668fd396bf7f3544b229de8d1820065073f0bfb01e7db509cba3f749f07f6575b791222d1aa7870c3d0e86d96dce4e95a1ddac8cba00
|
@@ -1,8 +1,11 @@
|
|
1
1
|
(assign mac-expand
|
2
2
|
(fn (names macfn expr)
|
3
3
|
(cond macfn
|
4
|
-
(
|
5
|
-
|
4
|
+
(handle-error
|
5
|
+
(fn (errors)
|
6
|
+
(error "expanding" (inspect expr) "with" (inspect macfn)))
|
7
|
+
(fn ()
|
8
|
+
(pre-compile-with names (apply macfn (cdr expr)))))
|
6
9
|
expr)))
|
7
10
|
|
8
11
|
(assign macs (hash))
|
@@ -134,7 +137,3 @@
|
|
134
137
|
|
135
138
|
(hash-set macs 'quasiquote
|
136
139
|
(fn (arg) (qq-quasiquote arg 0)))
|
137
|
-
|
138
|
-
(hash-set macs 'do
|
139
|
-
(fn args
|
140
|
-
`((fn nil ,@args))))
|
@@ -30,8 +30,9 @@
|
|
30
30
|
(def map (f things)
|
31
31
|
(map-helper-1 f things (cons)))
|
32
32
|
|
33
|
+
;; push 'v onto the value for 'k in 'h
|
34
|
+
;; the hash-values of h will all be lists, in reverse order of consing
|
33
35
|
(def hash-cons (h k v)
|
34
|
-
; push 'v onto the value for 'k in 'h
|
35
36
|
(hash-set h k (cons v (hash-get h k))))
|
36
37
|
|
37
38
|
(def rev (things last-cdr)
|
@@ -19,6 +19,10 @@
|
|
19
19
|
acc)))
|
20
20
|
form))
|
21
21
|
|
22
|
+
(hash-set macs 'do
|
23
|
+
(fn forms
|
24
|
+
`((fn nil ,@forms))))
|
25
|
+
|
22
26
|
((fn (this-chapter-name chapters chapter-new chapter-build chapter-add-to-chapter)
|
23
27
|
(assign chapters (hash))
|
24
28
|
|
@@ -88,7 +92,7 @@
|
|
88
92
|
(def dox-add-to-chapters (item type chapters)
|
89
93
|
(cond chapters
|
90
94
|
(do (chapter-add-item item (car chapters))
|
91
|
-
(hash-cons types-chapters (cons type (car chapters)) item)
|
95
|
+
(hash-cons types-chapters (inspect (cons type (car chapters))) item)
|
92
96
|
(dox-add-to-chapters item type (cdr chapters)))
|
93
97
|
item))
|
94
98
|
|
@@ -103,8 +107,10 @@
|
|
103
107
|
(def dox-types () (hash-keys types))
|
104
108
|
(def dox-items-by-type (type) (hash-get types type))
|
105
109
|
|
106
|
-
(def
|
107
|
-
|
110
|
+
(def get-types-chapters () types-chapters)
|
111
|
+
|
112
|
+
(def dox-items-by-type-and-chapter (dox-type chapter)
|
113
|
+
(hash-get types-chapters (inspect (cons dox-type chapter))))
|
108
114
|
|
109
115
|
(def dox-get-attr (name attr)
|
110
116
|
(cond (dox? name)
|
@@ -132,9 +138,9 @@
|
|
132
138
|
(cond (eq? event 'script-end)
|
133
139
|
(script-end name))))))
|
134
140
|
|
141
|
+
;; if the car of 'form is a key of 'hsh, add the cdr of 'form to the value of the key in 'hsh
|
142
|
+
;; otherwise add the form to the list whose key is nil
|
135
143
|
(def filter-form (hsh form)
|
136
|
-
; if the car of 'form is a key of 'hsh, add the cdr of 'form to the value of the key in 'hsh
|
137
|
-
; otherwise add the form to the list whose key is nil
|
138
144
|
(cond (cond (pair? form)
|
139
145
|
(hash-key? hsh (car form)))
|
140
146
|
(hash-cons hsh (car form) (cdr form))
|
@@ -153,9 +159,9 @@
|
|
153
159
|
(def rev-values (hsh)
|
154
160
|
(rev-value-keys (hash-keys hsh) hsh (hash)))
|
155
161
|
|
162
|
+
;; group forms by their first element, if the first element
|
163
|
+
;; is already a key in hsh, collect all other elements under key nil
|
156
164
|
(def filter-forms (hsh forms)
|
157
|
-
; group forms by their first element, if the first element
|
158
|
-
; is already a key in hsh, collect all other elements under key nil
|
159
165
|
(cond forms
|
160
166
|
(filter-forms (filter-form hsh (car forms)) (cdr forms))
|
161
167
|
(rev-values hsh)))
|
@@ -165,12 +171,12 @@
|
|
165
171
|
(hash-set hsh 'chapter nil)
|
166
172
|
hsh)
|
167
173
|
|
174
|
+
;; used internally by 'mac
|
168
175
|
(def define-mac-expr (name args body-forms)
|
169
|
-
; used internally by 'mac
|
170
176
|
`(do (hash-set macs ',name (fun ,args ,@(hash-get body-forms nil)))
|
171
177
|
(dox-add-doc ',name
|
172
178
|
'mac
|
173
|
-
',(map car (hash-get body-forms 'comment))
|
179
|
+
',(+ (fetch-and-clear-comments) (map car (hash-get body-forms 'comment)))
|
174
180
|
',args
|
175
181
|
'(mac ,name ,args ,@(hash-get body-forms nil))
|
176
182
|
',(map car (hash-get body-forms 'chapter)))))
|
@@ -195,8 +201,8 @@
|
|
195
201
|
|
196
202
|
(mac def-assign args `(assign ,@args))
|
197
203
|
|
204
|
+
;; used internally by 'def
|
198
205
|
(def define-def-expr (name args body-forms)
|
199
|
-
; used internally by 'def
|
200
206
|
`(do (def-assign ,name (fun ,args ,@(filter-comments (hash-get body-forms nil))))
|
201
207
|
(dox-add-doc ',name
|
202
208
|
'def
|
@@ -205,8 +211,8 @@
|
|
205
211
|
'(def ,name ,args ,@(hash-get body-forms nil))
|
206
212
|
',(map car (hash-get body-forms 'chapter)))))
|
207
213
|
|
214
|
+
;; define a new function in the global namespace
|
208
215
|
(mac def (name args . body)
|
209
|
-
; define a new function in the global namespace
|
210
216
|
(chapter nydp-core)
|
211
217
|
(define-def-expr name args (filter-forms (build-def-hash (hash)) body)))
|
212
218
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
(assign script-name "core-
|
1
|
+
(assign script-name "core-020-utils.nydp")
|
2
2
|
|
3
3
|
(dox-add-doc 'if
|
4
4
|
'mac
|
@@ -43,12 +43,12 @@
|
|
43
43
|
'(hash-set h k (cons v (hash-get h k)))
|
44
44
|
'(hash-manipulation))
|
45
45
|
|
46
|
+
;; equivalent to (join-str "~prefix~joint~(car things)" joint (cdr things)) - except
|
47
|
+
;; 'string-pieces hasn't been defined yet, and if it were, it would be defined in terms of
|
48
|
+
;; 'join-str, so it would be circular.
|
49
|
+
;; see 'joinstr for a more powerful and easier-to-use implementation of the same idea
|
46
50
|
(def join-str (prefix joint things)
|
47
51
|
(chapter string-manipulation)
|
48
|
-
; equivalent to (join-str "~prefix~joint~(car things)" joint (cdr things)) - except
|
49
|
-
; 'string-pieces hasn't been defined yet, and if it were, it would be defined in terms of
|
50
|
-
; 'join-str, so it would be circular.
|
51
|
-
; see 'joinstr for a more powerful and easier-to-use implementation of the same idea
|
52
52
|
(if things
|
53
53
|
(join-str (+ (to-string prefix)
|
54
54
|
joint
|
@@ -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)
|
@@ -89,8 +99,10 @@ scoping, assignment, anonymous functions and more...")
|
|
89
99
|
,@body)
|
90
100
|
,@(map cadr (pairs parms))))
|
91
101
|
|
102
|
+
;; same as ( (fn (var) body) val ) -> ie create a lexical scope
|
103
|
+
;; where val is assigned to var, execute 'body in that scope
|
92
104
|
(mac let (var val . body)
|
93
|
-
|
105
|
+
`(with (,var ,val) ,@body))
|
94
106
|
|
95
107
|
(mac rfn (name parms . body)
|
96
108
|
; creates a named, locally-scoped function
|
@@ -120,6 +132,7 @@ scoping, assignment, anonymous functions and more...")
|
|
120
132
|
;; (fn args (and (apply a args) (apply b args) (apply c args)))
|
121
133
|
;; or more simply
|
122
134
|
;; (fn (x) (and (a x) (b x) (c x)))
|
135
|
+
;; note: alias as 'andf ??
|
123
136
|
(def andify args
|
124
137
|
(fn args2 (rfnwith self (ands args)
|
125
138
|
(if ands (if (apply (car ands) args2)
|
@@ -234,7 +247,14 @@ scoping, assignment, anonymous functions and more...")
|
|
234
247
|
(caris 'hash-get name)
|
235
248
|
(hash-get-assignment (cdr name) value)
|
236
249
|
(ampersand-expression? name)
|
237
|
-
(ampersand-expression-assignment name value)
|
250
|
+
(ampersand-expression-assignment name value)
|
251
|
+
(caris 'at-syntax name)
|
252
|
+
`(hash-set @ ',(caddr name) ,value)
|
253
|
+
(error "unknown assignment to place: ~(inspect name)")))
|
254
|
+
|
255
|
+
;; quiet assignment ; like =, but expression returns nil
|
256
|
+
(mac #= (name value)
|
257
|
+
`(do (= ,name ,value) nil))
|
238
258
|
|
239
259
|
; increment the value at 'place by 'inc (default 1)
|
240
260
|
(mac ++ (place inc) `(= ,place (+ ,place ,(or inc 1))))
|
@@ -336,12 +356,12 @@ scoping, assignment, anonymous functions and more...")
|
|
336
356
|
(if (hash-get macs args)
|
337
357
|
(warnings/new 'arg-shadows-macro "arg " args " shadows macro " args " in arg list " orig " and body " body))))
|
338
358
|
|
359
|
+
;; build a 'fn form, changing 'args and 'body to
|
360
|
+
;; properly handle any destructuring args if present
|
339
361
|
(mac fun (args . body)
|
340
|
-
; build a 'fn form, changing 'args and 'body to
|
341
|
-
; properly handle any destructuring args if present
|
342
362
|
(fun/approve-arg-names args args body)
|
343
363
|
(destructure/build args nil body))
|
344
364
|
|
345
|
-
|
365
|
+
;; assign (f place) to place
|
346
366
|
(mac zap (f place . args)
|
347
367
|
`(= ,place (,f ,place ,@args)))
|
@@ -40,12 +40,21 @@
|
|
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.
|
@@ -13,6 +13,17 @@
|
|
13
13
|
(f (car things))
|
14
14
|
(eachl f (cdr things))))
|
15
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
|
+
|
16
27
|
; invokes 'f for each element of 'things, last element processed first
|
17
28
|
; ( "r" in "eachr" = "rightmost first" )
|
18
29
|
(def eachr (f things)
|
@@ -49,3 +60,14 @@
|
|
49
60
|
; a 'key, returns vx from 'al where kx is equal to 'key
|
50
61
|
; #attribution: lifted almost directly from arc.arc
|
51
62
|
(def alref (key al) (cadr (assoc key al)))
|
63
|
+
|
64
|
+
;; returns the first non-empty item in 'args
|
65
|
+
;; mac equivalent of (detect present? args)
|
66
|
+
(mac dp args
|
67
|
+
(if args
|
68
|
+
(w/uniq nearg
|
69
|
+
`(let ,nearg ,(car args)
|
70
|
+
(if (empty? ,nearg)
|
71
|
+
(dp ,@(cdr args))
|
72
|
+
,nearg)))
|
73
|
+
nil))
|
@@ -0,0 +1,24 @@
|
|
1
|
+
;; creates a private namespace for support functions for one or more explicitly exported/public functions
|
2
|
+
;;
|
3
|
+
;; (module foo
|
4
|
+
;; (def h ...)
|
5
|
+
;; (def u ...)
|
6
|
+
;; (export bar (x y) (h u x y)))
|
7
|
+
;;
|
8
|
+
;; results in 'foo/bar being universally available, but 'h and 'u are visible only within the module and override
|
9
|
+
;; any other 'h or 'u defined elsewhere, in the scope of the module.
|
10
|
+
(mac module (module-name . forms)
|
11
|
+
(let private-names nil
|
12
|
+
(let module-forms
|
13
|
+
{ def (fn (name args . body)
|
14
|
+
(push nil private-names)
|
15
|
+
(push name private-names)
|
16
|
+
`(assign ,name (fn ,args ,@body)))
|
17
|
+
export-def macs.def
|
18
|
+
export (fn (name args . body)
|
19
|
+
`(export-def
|
20
|
+
,(sym (+ (to-string module-name) "/" (to-string name)))
|
21
|
+
,args
|
22
|
+
,@body)) }
|
23
|
+
(let module-body (pre-compile-each module-forms forms)
|
24
|
+
`(with (,@private-names) ,@module-body)))))
|
@@ -11,21 +11,20 @@
|
|
11
11
|
(def num? (arg) (comment "true if arg is a number") (isa 'number arg))
|
12
12
|
(def string? (arg) (comment "true if arg is a string") (isa 'string arg))
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
expr)
|
14
|
+
;; this is useful sometimes when 'expr can't stand on its own due to lexical ambiguity, most often in string interpolations
|
15
|
+
;; for example, in "hello ~person, how are you", the parser will try to interpolate the symbol "person," rather than the
|
16
|
+
;; expected "person". In this case, use "hello ~(just person), how are you"
|
17
|
+
(mac just (expr) expr)
|
19
18
|
|
20
19
|
(def quotify (arg) `(quote ,arg))
|
21
20
|
|
22
|
-
|
21
|
+
;; return a function that always returns 'arg, similar to K in SKI calculus
|
23
22
|
(defmemo k (arg) (fn nil arg))
|
24
23
|
|
24
|
+
;; return the length of 'things where 'things may be nil, a string, list or hash
|
25
|
+
;; length of nil is zero, length of hash is number of keys, length of string
|
26
|
+
;; is number of characters, length of list is number of direct items - no recursive counting
|
25
27
|
(def len (things)
|
26
|
-
; return the length of 'things where 'things may be nil, a string, list or hash
|
27
|
-
; length of nil is zero, length of hash is number of keys, length of string
|
28
|
-
; is number of characters, length of list is number of direct items - no recursive counting
|
29
28
|
(chapter list-manipulation)
|
30
29
|
(chapter string-manipulation)
|
31
30
|
(chapter hash-manipulation)
|
@@ -37,8 +36,8 @@
|
|
37
36
|
|
38
37
|
(assign dynamics (hash))
|
39
38
|
|
39
|
+
;; creates a dynamic variable.
|
40
40
|
(mac dynamic (name initial)
|
41
|
-
; creates a dynamic variable.
|
42
41
|
(let with-mac-name (sym:+ "w/" name)
|
43
42
|
(w/uniq prev
|
44
43
|
`(do
|
@@ -53,10 +52,10 @@
|
|
53
52
|
(def ,name () (hash-get (thread-locals) ',name))))))
|
54
53
|
|
55
54
|
|
56
|
-
|
55
|
+
;; overrides 'privately defined earlier in documentation manager
|
57
56
|
(dynamic privately)
|
58
57
|
|
59
|
-
|
58
|
+
;; suppress documentation of anything defined in 'body
|
60
59
|
(mac in-private body
|
61
60
|
`(w/privately t ,@body))
|
62
61
|
|
@@ -30,3 +30,27 @@
|
|
30
30
|
; return the first 'length chars of string 'str
|
31
31
|
(def string-truncate (str length)
|
32
32
|
(string-replace "(.{~|length|}).*" "\\1" str))
|
33
|
+
|
34
|
+
;; returns a function with args 'args whose body is 'str. 'str should be a string,
|
35
|
+
;; 'args should correspond to interpolations within 'str
|
36
|
+
;;
|
37
|
+
;; example: (string-eval-fn "hello \~u.firstname" 'u)
|
38
|
+
;; returns (fn (u) (string-pieces "hello " u.firstname))
|
39
|
+
(defmemo string-eval-fn (str args)
|
40
|
+
(eval `(fn ,args
|
41
|
+
,(parse-in-string str))))
|
42
|
+
|
43
|
+
;; assigns 'args respectively to 'arg-names and evals 'str in that context.
|
44
|
+
;; Assumes 'str contains interpolations which reference 'arg-names.
|
45
|
+
;; Useful for evaluating user-supplied strings ; dangerous for the same reason.
|
46
|
+
;;
|
47
|
+
;; example: (string/eval-with-args "\~x + \~y is \~(+ x y)" '(x y) 2 3)
|
48
|
+
;; returns "2 + 3 is 5"
|
49
|
+
;;
|
50
|
+
(def string/eval-with-args (str arg-names . args)
|
51
|
+
(on-err
|
52
|
+
(error (j "error evaluating " (inspect str)
|
53
|
+
"\nwith arg names " (inspect arg-names)
|
54
|
+
"\nand args " (inspect args)))
|
55
|
+
(apply (string-eval-fn str arg-names)
|
56
|
+
args)))
|
@@ -7,3 +7,19 @@
|
|
7
7
|
;; return a Time object representing the time 's seconds ago
|
8
8
|
(def seconds-ago (s)
|
9
9
|
(- (time) s))
|
10
|
+
|
11
|
+
(def anniversary/previous (anchor anniv)
|
12
|
+
(let d (date anchor.year
|
13
|
+
anniv.month
|
14
|
+
anniv.day)
|
15
|
+
(if (< d anchor)
|
16
|
+
d
|
17
|
+
d.last-year)))
|
18
|
+
|
19
|
+
(def anniversary/next (anchor anniv)
|
20
|
+
(let d (date anchor.year
|
21
|
+
anniv.month
|
22
|
+
anniv.day)
|
23
|
+
(if (> d anchor)
|
24
|
+
d
|
25
|
+
d.next-year)))
|
@@ -23,75 +23,71 @@
|
|
23
23
|
(intersperse inbetween (cdr things)))
|
24
24
|
things))
|
25
25
|
|
26
|
+
;; expects 'things a list of lists, joins the lists
|
27
|
+
;; returns (a b X c d X e f)
|
28
|
+
;; placing 'inbetween in between each list.
|
29
|
+
;; For example (intersperse-splicing 'X '((a b) (c d) (e f)))
|
26
30
|
(def intersperse-splicing (inbetween things)
|
27
|
-
; expects 'things a list of lists, joins the lists
|
28
|
-
; placing 'inbetween in between each list.
|
29
|
-
; For example (intersperse-splicing 'X '((a b) (c d) (e f)))
|
30
|
-
; returns (a b X c d X e f)
|
31
31
|
(apply joinlists (intersperse (list inbetween) things)))
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
(
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
(f items)
|
47
|
-
items)))
|
33
|
+
;; if 'things is a list, return all the items in the list for which 'f returns non-nil
|
34
|
+
;; otherwise, return 'things if (f things) is non-nil
|
35
|
+
;; otherwise, nil
|
36
|
+
;; note that this preserves improper lists and may return only the lastcdr if all else fails...
|
37
|
+
(def collect (f items)
|
38
|
+
(if (pair? items)
|
39
|
+
(if (f (car items))
|
40
|
+
(cons (car items)
|
41
|
+
(collect f (cdr items)))
|
42
|
+
(collect f (cdr items)))
|
43
|
+
items
|
44
|
+
(if (f items)
|
45
|
+
items)))
|
48
46
|
|
49
47
|
(assign select collect)
|
50
48
|
|
51
|
-
|
49
|
+
;; return a new list containing only 'present? items from the given list
|
52
50
|
(def compact (things) (collect present? things))
|
53
51
|
|
52
|
+
;; return the sum of all non-nil values (consider nil as zero)
|
54
53
|
(def +nz args
|
55
|
-
; return the sum of all non-nil values (consider nil as zero)
|
56
54
|
(apply + (compact args)))
|
57
55
|
|
56
|
+
;; return all the items in 'things for which 'f returns nil
|
58
57
|
(def reject (f things)
|
59
|
-
; return all the items in 'things for which 'f returns nil
|
60
58
|
(collect !f things))
|
61
59
|
|
60
|
+
;; returns the n-th item in the list 'things
|
62
61
|
(def nth (n things)
|
63
|
-
; returns the n-th item in the list 'things
|
64
62
|
(if (eq? n 0)
|
65
63
|
(car things)
|
66
64
|
(nth (- n 1) (cdr things))))
|
67
65
|
|
66
|
+
;; repeatedly assigns an element of 'things to 'var,
|
67
|
+
;; and executes 'body each time
|
68
68
|
(mac each (var things . body)
|
69
|
-
; repeatedly assigns an element of 'things to 'var,
|
70
|
-
; and executes 'body each time
|
71
69
|
(w/uniq (xs c)
|
72
|
-
`(
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
,things)))
|
70
|
+
`(rfnwith ,c (,xs ,things)
|
71
|
+
(if (pair? ,xs)
|
72
|
+
(do (let ,var (car ,xs) ,@body)
|
73
|
+
(,c (cdr ,xs)))))))
|
77
74
|
|
78
75
|
(def reduce (f things)
|
79
|
-
(
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
76
|
+
(rfnwith rd (acc (car things) list (cdr things))
|
77
|
+
(if (pair? list)
|
78
|
+
(rd (f acc (car list))
|
79
|
+
(cdr list))
|
80
|
+
acc)))
|
81
|
+
|
82
|
+
;; t if this is a proper list (last cdr is nil)
|
83
|
+
;; nil otherwise (last cdr is neither cons nor nil)
|
86
84
|
(def proper? (list)
|
87
|
-
; t if this is a proper list (last cdr is nil)
|
88
|
-
; nil otherwise (last cdr is neither cons nor nil)
|
89
85
|
(or (no list)
|
90
86
|
(and (pair? list)
|
91
87
|
(proper? (cdr list)))))
|
92
88
|
|
89
|
+
;; returns the first 'n items in the list 'things
|
93
90
|
(def firstn (n things)
|
94
|
-
; returns the first 'n items in the list 'things
|
95
91
|
(if (eq? n 0) nil
|
96
92
|
things (cons (car things)
|
97
93
|
(firstn (- n 1)
|
@@ -139,25 +135,39 @@
|
|
139
135
|
(detect (curry eq? f)
|
140
136
|
things)))
|
141
137
|
|
138
|
+
;; split things into a list of lists each n long
|
142
139
|
(def tuples (n things)
|
143
|
-
;; split things into a list of lists each n long
|
144
140
|
(rfnwith _ (list things)
|
145
141
|
(if (no list)
|
146
142
|
nil
|
147
143
|
(cons (firstn n list) (_ (nthcdr n list))))))
|
148
144
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
(if (
|
155
|
-
|
156
|
-
winner)))
|
145
|
+
;; iterates through 'things pairwise (a,b then b,c then c,d etc), returns whichever is preferred by 'better-p
|
146
|
+
;; example (best > '(3 1 4 1 5 9 2)) returns 9
|
147
|
+
;; "better-p" -> takes two args a and b, return t if a is "better" than b, nil otherwise
|
148
|
+
(def best (better-p things)
|
149
|
+
(reduce (fn (a b)
|
150
|
+
(if (better-p a b) a b))
|
151
|
+
things))
|
157
152
|
|
158
153
|
(def min things (best < things))
|
159
154
|
(def max things (best > things))
|
160
155
|
|
156
|
+
;; returns a function taking two args a and b, that compares attributes of two objects
|
157
|
+
;; 'map-f takes one arg a returning a1
|
158
|
+
;; 'compare-p takes two args a1 and b1, returns t if a1 is "better" than b1
|
159
|
+
;;
|
160
|
+
;; useful in conjunction with 'best : (best (map-compare-f > &size) (list { size 1 } { size 7 } { size 3 })) returns { size 7 }
|
161
|
+
(def map-compare-f (compare-p map-f)
|
162
|
+
(fn (a b) (compare-p (map-f a) (map-f b))))
|
163
|
+
|
164
|
+
;; iterate over 'things, calling 'on-atom for each non-list element, and calling
|
165
|
+
;; 'on-list for each list element.
|
166
|
+
;; 'on-atom takes one parameter, the element in question;
|
167
|
+
;; 'on-list takes two parameters: a function to call for recursing, and the list in question.
|
168
|
+
;; 'on-list should be something like (fn (rec xs) (foo xs) (map rec xs)) to construct a new list,
|
169
|
+
;; or (fn (rec xs) (foo xs) (eachl rec xs)) to iterate without constructing a new list
|
170
|
+
;; see 'list-gsub for an example of constructing a new list using this.
|
161
171
|
(def map-recurse (on-atom on-list things)
|
162
172
|
((afn (xs)
|
163
173
|
(if (pair? xs)
|
@@ -166,8 +176,20 @@
|
|
166
176
|
(on-atom xs)))
|
167
177
|
things))
|
168
178
|
|
179
|
+
;; like map-recurse, but doesn't depend on caller to initiate recursion
|
180
|
+
;; 'on-atom and 'on-list are functions each taking one parameter
|
181
|
+
;; return value is last returned item from on-atom or on-list
|
182
|
+
(def list/traverse (on-atom on-list things)
|
183
|
+
(map-recurse
|
184
|
+
(fn (s)
|
185
|
+
(on-atom s))
|
186
|
+
(fn (rec xs)
|
187
|
+
(on-list xs)
|
188
|
+
(eachl rec xs))
|
189
|
+
things))
|
190
|
+
|
191
|
+
;; recursively replaces 'old with 'new inside 'list
|
169
192
|
(def list-gsub (list old new)
|
170
|
-
; recursively replaces 'old with 'new inside 'list
|
171
193
|
(map-recurse (fn (s) (if (eq? s old) new s))
|
172
194
|
(fn (m things)
|
173
195
|
(if (eq? things old)
|