nydp 0.4.3 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|