nydp 0.4.2 → 0.5.1
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 +5 -5
- data/README.md +44 -0
- data/lib/lisp/core-010-precompile.nydp +13 -16
- data/lib/lisp/core-012-utils.nydp +3 -2
- data/lib/lisp/core-015-documentation.nydp +54 -23
- data/lib/lisp/core-017-builtin-dox.nydp +14 -12
- data/lib/lisp/core-020-utils.nydp +5 -5
- data/lib/lisp/core-030-syntax.nydp +166 -72
- data/lib/lisp/core-035-flow-control.nydp +38 -11
- data/lib/lisp/core-037-list-utils.nydp +12 -0
- data/lib/lisp/core-039-module.nydp +24 -0
- data/lib/lisp/core-040-utils.nydp +32 -12
- data/lib/lisp/core-041-string-utils.nydp +25 -1
- data/lib/lisp/core-042-date-utils.nydp +21 -1
- data/lib/lisp/core-043-list-utils.nydp +96 -64
- data/lib/lisp/core-070-prefix-list.nydp +1 -1
- data/lib/lisp/core-080-pretty-print.nydp +57 -17
- data/lib/lisp/core-090-hook.nydp +35 -1
- data/lib/lisp/core-100-utils.nydp +82 -2
- data/lib/lisp/core-110-hash-utils.nydp +56 -2
- data/lib/lisp/core-120-settings.nydp +16 -5
- data/lib/lisp/core-130-validations.nydp +51 -0
- data/lib/lisp/core-900-benchmarking.nydp +78 -20
- data/lib/lisp/tests/accum-examples.nydp +28 -1
- data/lib/lisp/tests/aif-examples.nydp +8 -3
- data/lib/lisp/tests/andify-examples.nydp +7 -0
- 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 +19 -0
- data/lib/lisp/tests/case-examples.nydp +14 -0
- data/lib/lisp/tests/date-examples.nydp +54 -1
- data/lib/lisp/tests/destructuring-examples.nydp +46 -14
- data/lib/lisp/tests/detect-examples.nydp +12 -0
- data/lib/lisp/tests/dp-examples.nydp +24 -0
- data/lib/lisp/tests/each-tests.nydp +5 -0
- data/lib/lisp/tests/empty-examples.nydp +1 -1
- data/lib/lisp/tests/error-tests.nydp +4 -4
- data/lib/lisp/tests/explain-mac-examples.nydp +1 -1
- data/lib/lisp/tests/filter-forms-examples.nydp +15 -0
- data/lib/lisp/tests/hash-examples.nydp +25 -1
- data/lib/lisp/tests/list-grep-examples.nydp +40 -0
- data/lib/lisp/tests/list-tests.nydp +58 -1
- data/lib/lisp/tests/map-hash-examples.nydp +11 -0
- data/lib/lisp/tests/module-examples.nydp +10 -0
- data/lib/lisp/tests/multi-assign-examples.nydp +6 -0
- data/lib/lisp/tests/parser-tests.nydp +25 -0
- data/lib/lisp/tests/pretty-print-tests.nydp +17 -14
- data/lib/lisp/tests/set-difference-examples.nydp +8 -0
- data/lib/lisp/tests/settings-examples.nydp +17 -1
- data/lib/lisp/tests/string-tests.nydp +70 -1
- data/lib/lisp/tests/syntax-tests.nydp +5 -1
- data/lib/lisp/tests/to-integer-examples.nydp +16 -0
- data/lib/lisp/tests/validation-examples.nydp +15 -0
- data/lib/nydp.rb +10 -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 +15 -1
- data/lib/nydp/builtin/error.rb +1 -1
- data/lib/nydp/builtin/hash.rb +24 -1
- data/lib/nydp/builtin/inspect.rb +1 -1
- data/lib/nydp/builtin/plus.rb +10 -2
- data/lib/nydp/builtin/random_string.rb +2 -2
- data/lib/nydp/builtin/{car.rb → regexp.rb} +2 -2
- data/lib/nydp/builtin/ruby_wrap.rb +72 -0
- data/lib/nydp/builtin/string_match.rb +2 -2
- data/lib/nydp/builtin/string_pad_left.rb +7 -0
- data/lib/nydp/builtin/string_pad_right.rb +7 -0
- data/lib/nydp/builtin/string_replace.rb +3 -3
- data/lib/nydp/builtin/string_split.rb +4 -3
- data/lib/nydp/builtin/to_integer.rb +23 -0
- data/lib/nydp/builtin/to_string.rb +2 -9
- 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 +36 -28
- data/lib/nydp/core_ext.rb +21 -5
- data/lib/nydp/date.rb +26 -18
- data/lib/nydp/function_invocation.rb +34 -26
- data/lib/nydp/helper.rb +35 -3
- data/lib/nydp/interpreted_function.rb +68 -40
- data/lib/nydp/literal.rb +1 -1
- data/lib/nydp/pair.rb +22 -5
- data/lib/nydp/parser.rb +11 -7
- data/lib/nydp/string_atom.rb +3 -4
- data/lib/nydp/symbol_lookup.rb +7 -7
- data/lib/nydp/tokeniser.rb +2 -2
- data/lib/nydp/truth.rb +10 -10
- data/lib/nydp/version.rb +1 -1
- data/lib/nydp/vm.rb +7 -0
- data/nydp.gemspec +2 -4
- data/spec/date_spec.rb +93 -0
- data/spec/embedded_spec.rb +12 -12
- data/spec/foreign_hash_spec.rb +14 -2
- data/spec/hash_non_hash_behaviour_spec.rb +7 -7
- data/spec/hash_spec.rb +24 -2
- data/spec/nydp_spec.rb +14 -2
- data/spec/pair_spec.rb +3 -1
- data/spec/parser_spec.rb +31 -20
- data/spec/rand_spec.rb +3 -3
- data/spec/spec_helper.rb +10 -1
- metadata +24 -37
- 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
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: adb6cc0345ed64c1e0e7ac99c06d9aa1328482e7d51d771cd77b844e1c5a6e14
|
|
4
|
+
data.tar.gz: 997c1f318ed518f3d2100699c1532db9a140f7109d6e4ddef6e68055466eb23a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4a80109cc7bf73c177c6f89697e386a0a12d3645512bd14db2ed036711ef2c0b11d80fef67cff8dbc6f7bfed23d103220b9bc909aa9b34590323375db699c5e3
|
|
7
|
+
data.tar.gz: 25864fdef654329baef7d494a54b926f6dd236399f131e5943505752784713b03dc9e79640407c1df6af17ac380c483d82e2fae5e35fa3f3636b1226384eaa58
|
data/README.md
CHANGED
|
@@ -55,6 +55,22 @@ answer = Nydp.apply_function ns, :question, :life, ["The Universe", and_also(eve
|
|
|
55
55
|
|
|
56
56
|
You can maintain multiple `ns` instances without mutual interference. In other words, assigning global variables while one `ns` is in scope will not affect the values of variables in any other `ns` (unless you've specifically arranged it to be so by duplicating namespaces or some such sorcery).
|
|
57
57
|
|
|
58
|
+
|
|
59
|
+
#### Facing the Truth
|
|
60
|
+
|
|
61
|
+
In conditional statements, nil is false, anything else is true
|
|
62
|
+
|
|
63
|
+
```lisp
|
|
64
|
+
(if) ;; same as (if nil)
|
|
65
|
+
(if a) ;; same as a
|
|
66
|
+
(if a b) ;; same as (if a b nil)
|
|
67
|
+
(if a b c) ;; if a is nil, return c, otherwise return b
|
|
68
|
+
(if a b c d) ;; same as (if a b (if c d))
|
|
69
|
+
(if a b c d e) ;; same as (if a b (if c d e))
|
|
70
|
+
|
|
71
|
+
;; and so on
|
|
72
|
+
```
|
|
73
|
+
|
|
58
74
|
## Different from Arc :
|
|
59
75
|
|
|
60
76
|
#### 1. Macro-expansion runs in lisp
|
|
@@ -151,8 +167,36 @@ nydp > (map &lastname german-composers) ; ampersand-syntax creates a function
|
|
|
151
167
|
|
|
152
168
|
As with all other syntax, you can of course override the `ampersand-syntax` macro to handle your special needs.
|
|
153
169
|
|
|
170
|
+
You can combine special syntaxes ("%td" comes from nydp-html gem)
|
|
171
|
+
|
|
172
|
+
```lisp
|
|
173
|
+
|
|
174
|
+
nydp > (map %td:&lastname german-composers)
|
|
175
|
+
|
|
176
|
+
"<td>Bach</td><td>Beethoven</td><td>Wagner</td><td>Mozart</td>"
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
So, @%td@ expands to @(percent-syntax || td)@, @&lastname@ to @(ampersand-syntax || lastname)@, and the whole @%td:&lastname@
|
|
181
|
+
to @(colon-syntax (percent-syntax || td) (ampersand-syntax || lastname))@. Luckily for you, there's a fine @colon-syntax@ macro
|
|
182
|
+
that knows how to build a function out of these bits and pieces.
|
|
183
|
+
|
|
184
|
+
|
|
154
185
|
Look for `SYMBOL_OPERATORS` in [parser.rb](lib/nydp/parser.rb) to see which syntax is recognised and in which order. The order of these definitions defines special-syntax-operator precedence.
|
|
155
186
|
|
|
187
|
+
Any character that is not special syntax will be recognised as part of a symbol. At time of writing, this includes the plus sign, hyphen, and slash.
|
|
188
|
+
|
|
189
|
+
```lisp
|
|
190
|
+
|
|
191
|
+
;; nonsense code illustrating the use of certain
|
|
192
|
+
;; characters as function and variable names
|
|
193
|
+
(def //-+ (x y z)
|
|
194
|
+
(let -*- (x y)
|
|
195
|
+
(if z (//-+ x y -*-) -*-)))
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
|
|
156
200
|
#### 3. Special list syntax
|
|
157
201
|
|
|
158
202
|
The parser detects alternative list delimiters
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
(assign mac-expand
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
(assign mac-expand
|
|
2
|
+
(fn (names macfn expr)
|
|
3
|
+
(cond macfn
|
|
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)))))
|
|
9
|
+
expr)))
|
|
6
10
|
|
|
7
11
|
(assign macs (hash))
|
|
8
12
|
|
|
9
|
-
(assign pre-compile-expr
|
|
10
|
-
(fn (names expr)
|
|
11
|
-
(mac-expand names
|
|
12
|
-
(hash-get names (car expr))
|
|
13
|
-
expr)))
|
|
14
|
-
|
|
15
13
|
(assign pre-compile-each
|
|
16
14
|
(fn (names args)
|
|
17
15
|
(cond args
|
|
@@ -33,7 +31,10 @@
|
|
|
33
31
|
(cond (eq? (car arg) 'quote)
|
|
34
32
|
arg
|
|
35
33
|
(pre-compile-each names
|
|
36
|
-
(
|
|
34
|
+
(mac-expand names
|
|
35
|
+
(hash-get names
|
|
36
|
+
(car arg))
|
|
37
|
+
arg)))
|
|
37
38
|
arg)))
|
|
38
39
|
|
|
39
40
|
(assign pre-compile-debug
|
|
@@ -136,7 +137,3 @@
|
|
|
136
137
|
|
|
137
138
|
(hash-set macs 'quasiquote
|
|
138
139
|
(fn (arg) (qq-quasiquote arg 0)))
|
|
139
|
-
|
|
140
|
-
(hash-set macs 'do
|
|
141
|
-
(fn args
|
|
142
|
-
`((fn nil ,@args))))
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
(car args))
|
|
9
9
|
nil)))
|
|
10
10
|
|
|
11
|
-
(def map-helper-0 (f things lc
|
|
11
|
+
(def map-helper-0 (f things lc)
|
|
12
12
|
(if (pair? things)
|
|
13
13
|
(map-helper-0 f (cdr things) (cdr-set lc (cons (f (car things)))))
|
|
14
14
|
things
|
|
@@ -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,12 @@
|
|
|
19
19
|
acc)))
|
|
20
20
|
form))
|
|
21
21
|
|
|
22
|
+
(hash-set macs 'do
|
|
23
|
+
(fn forms
|
|
24
|
+
(if (no (cdr forms))
|
|
25
|
+
(car forms)
|
|
26
|
+
`((fn nil ,@forms)))))
|
|
27
|
+
|
|
22
28
|
((fn (this-chapter-name chapters chapter-new chapter-build chapter-add-to-chapter)
|
|
23
29
|
(assign chapters (hash))
|
|
24
30
|
|
|
@@ -64,7 +70,7 @@
|
|
|
64
70
|
(assign this-script nil)
|
|
65
71
|
(assign this-plugin "Nydp Core")
|
|
66
72
|
|
|
67
|
-
((fn (dox examples chapters types dox-new dox-build)
|
|
73
|
+
((fn (dox examples chapters types types-chapters dox-new dox-build)
|
|
68
74
|
(def dox-build (hsh name what texts args src chapters)
|
|
69
75
|
(hash-set hsh 'name name )
|
|
70
76
|
(hash-set hsh 'what what )
|
|
@@ -79,16 +85,20 @@
|
|
|
79
85
|
(def dox-new (item)
|
|
80
86
|
(hash-cons dox (hash-get item 'name) item)
|
|
81
87
|
(hash-cons types (hash-get item 'what) item)
|
|
82
|
-
(dox-add-to-chapters item (hash-get item 'chapters)))
|
|
88
|
+
(dox-add-to-chapters item (hash-get item 'what) (hash-get item 'chapters) (hash)))
|
|
83
89
|
|
|
84
90
|
(def dox-add-doc (name what texts args src chapters more)
|
|
85
91
|
(cond (no (privately))
|
|
86
92
|
(dox-new (dox-build (if more more (hash)) name what texts args src chapters))))
|
|
87
93
|
|
|
88
|
-
(def dox-add-to-chapters (item chapters)
|
|
94
|
+
(def dox-add-to-chapters (item type chapters already)
|
|
89
95
|
(cond chapters
|
|
90
|
-
|
|
91
|
-
|
|
96
|
+
(cond (no (hash-get already (car chapters)))
|
|
97
|
+
(do (hash-set already (car chapters) t)
|
|
98
|
+
(chapter-add-item item (car chapters))
|
|
99
|
+
(hash-cons types-chapters (inspect (cons type (car chapters))) item)
|
|
100
|
+
(dox-add-to-chapters item type (cdr chapters) already))
|
|
101
|
+
item)
|
|
92
102
|
item))
|
|
93
103
|
|
|
94
104
|
(def dox-add-examples (name example-exprs)
|
|
@@ -102,6 +112,11 @@
|
|
|
102
112
|
(def dox-types () (hash-keys types))
|
|
103
113
|
(def dox-items-by-type (type) (hash-get types type))
|
|
104
114
|
|
|
115
|
+
(def get-types-chapters () types-chapters)
|
|
116
|
+
|
|
117
|
+
(def dox-items-by-type-and-chapter (dox-type chapter)
|
|
118
|
+
(hash-get types-chapters (inspect (cons dox-type chapter))))
|
|
119
|
+
|
|
105
120
|
(def dox-get-attr (name attr)
|
|
106
121
|
(cond (dox? name)
|
|
107
122
|
(hash-get (car (dox-lookup name)) attr)))
|
|
@@ -111,7 +126,7 @@
|
|
|
111
126
|
(def dox-examples (name) (hash-get examples name ))
|
|
112
127
|
(def dox-args (name) (dox-get-attr name 'args ))
|
|
113
128
|
(def dox-example-names () (hash-keys examples )))
|
|
114
|
-
(hash) (hash) (hash) (hash) nil)
|
|
129
|
+
(hash) (hash) (hash) (hash) (hash) nil)
|
|
115
130
|
|
|
116
131
|
(def plugin-start (name) (assign this-plugin name) (chapter-end))
|
|
117
132
|
(def plugin-end (name) (assign this-plugin nil ) (chapter-end))
|
|
@@ -128,9 +143,9 @@
|
|
|
128
143
|
(cond (eq? event 'script-end)
|
|
129
144
|
(script-end name))))))
|
|
130
145
|
|
|
146
|
+
;; if the car of 'form is a key of 'hsh, add the cdr of 'form to the value of the key in 'hsh
|
|
147
|
+
;; otherwise add the form to the list whose key is nil
|
|
131
148
|
(def filter-form (hsh form)
|
|
132
|
-
; if the car of 'form is a key of 'hsh, add the cdr of 'form to the value of the key in 'hsh
|
|
133
|
-
; otherwise add the form to the list whose key is nil
|
|
134
149
|
(cond (cond (pair? form)
|
|
135
150
|
(hash-key? hsh (car form)))
|
|
136
151
|
(hash-cons hsh (car form) (cdr form))
|
|
@@ -149,31 +164,43 @@
|
|
|
149
164
|
(def rev-values (hsh)
|
|
150
165
|
(rev-value-keys (hash-keys hsh) hsh (hash)))
|
|
151
166
|
|
|
167
|
+
;; group forms by their first element, if the first element
|
|
168
|
+
;; is already a key in hsh, collect all other elements under key nil
|
|
152
169
|
(def filter-forms (hsh forms)
|
|
153
|
-
; group forms by their first element, if the first element
|
|
154
|
-
; is already a key in hsh, collect all other elements under key nil
|
|
155
170
|
(cond forms
|
|
156
171
|
(filter-forms (filter-form hsh (car forms)) (cdr forms))
|
|
157
172
|
(rev-values hsh)))
|
|
158
173
|
|
|
159
|
-
(def
|
|
160
|
-
(
|
|
161
|
-
|
|
162
|
-
|
|
174
|
+
(def filter-remove (key forms keyforms otherforms)
|
|
175
|
+
(cond forms
|
|
176
|
+
(cond (cond (pair? forms) (cond (pair? (car forms)) (eq? key (caar forms))))
|
|
177
|
+
(filter-remove key (cdr forms) (cons (car forms) keyforms) otherforms)
|
|
178
|
+
(filter-remove key (cdr forms) keyforms (cons (car forms) otherforms)))
|
|
179
|
+
(list (rev keyforms) (rev otherforms))))
|
|
163
180
|
|
|
181
|
+
(assign DEF-FORMS '(comment chapter))
|
|
182
|
+
|
|
183
|
+
(def build-def-hash ()
|
|
184
|
+
((fn (h)
|
|
185
|
+
(map (fn (k) (hash-set h k nil)) DEF-FORMS)
|
|
186
|
+
h)
|
|
187
|
+
(hash)))
|
|
188
|
+
|
|
189
|
+
(def dox-build-def-name (name) name)
|
|
190
|
+
|
|
191
|
+
;; used internally by 'mac
|
|
164
192
|
(def define-mac-expr (name args body-forms)
|
|
165
|
-
; used internally by 'mac
|
|
166
193
|
`(do (hash-set macs ',name (fun ,args ,@(hash-get body-forms nil)))
|
|
167
|
-
(dox-add-doc ',name
|
|
194
|
+
(dox-add-doc ',(dox-build-def-name name)
|
|
168
195
|
'mac
|
|
169
|
-
',(map car (hash-get body-forms 'comment))
|
|
196
|
+
',(+ (fetch-and-clear-comments) (map car (hash-get body-forms 'comment)))
|
|
170
197
|
',args
|
|
171
198
|
'(mac ,name ,args ,@(hash-get body-forms nil))
|
|
172
199
|
',(map car (hash-get body-forms 'chapter)))))
|
|
173
200
|
|
|
174
201
|
(hash-set macs 'mac
|
|
175
202
|
(fn (name args . body)
|
|
176
|
-
(define-mac-expr name args (filter-forms (build-def-hash
|
|
203
|
+
(define-mac-expr name args (filter-forms (build-def-hash) body))))
|
|
177
204
|
|
|
178
205
|
(dox-add-doc 'mac
|
|
179
206
|
'mac
|
|
@@ -189,22 +216,26 @@
|
|
|
189
216
|
'`((fn nil ,@args))
|
|
190
217
|
'(nydp-core))
|
|
191
218
|
|
|
219
|
+
;; override later to use '= instead of 'assign, giving us hash-assignment and other goodies for free
|
|
192
220
|
(mac def-assign args `(assign ,@args))
|
|
193
221
|
|
|
222
|
+
;; used internally by 'def
|
|
194
223
|
(def define-def-expr (name args body-forms)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
224
|
+
`(do (def-assign ,name
|
|
225
|
+
((fn (self-name)
|
|
226
|
+
(fun ,args ,@(filter-comments (hash-get body-forms nil))))
|
|
227
|
+
',name))
|
|
228
|
+
(dox-add-doc ',(dox-build-def-name name)
|
|
198
229
|
'def
|
|
199
230
|
',(+ (fetch-and-clear-comments) (map car (hash-get body-forms 'comment)))
|
|
200
231
|
',args
|
|
201
232
|
'(def ,name ,args ,@(hash-get body-forms nil))
|
|
202
233
|
',(map car (hash-get body-forms 'chapter)))))
|
|
203
234
|
|
|
235
|
+
;; define a new function in the global namespace
|
|
204
236
|
(mac def (name args . body)
|
|
205
|
-
; define a new function in the global namespace
|
|
206
237
|
(chapter nydp-core)
|
|
207
|
-
(define-def-expr name args (filter-forms (build-def-hash
|
|
238
|
+
(define-def-expr name args (filter-forms (build-def-hash) body)))
|
|
208
239
|
|
|
209
240
|
(mac comment (txt)
|
|
210
241
|
(assign comments (cons txt comments))
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
(dox-add-doc 'cons 'def '("with args a and b, returns a new cons cell, (a . b)") '(a b) nil '(list-manipulation))
|
|
2
2
|
(dox-add-doc 'car 'def '("with args a, where a is a cons cell (x . y), return x." "Commonly used to get the first element of a list") '(a) nil '(list-manipulation))
|
|
3
3
|
(dox-add-doc 'cdr 'def '("with args a, where a is a cons cell (x . y), return y." "Commonly used to get contents of a list, excluding the first element") '(a) nil '(list-manipulation))
|
|
4
|
+
(dox-add-doc 'log 'def '("write arg to Nydp.logger ; be sure to assign Nydp.logger first!") '(arg) nil '(nydp-core))
|
|
4
5
|
(dox-add-doc '+ 'def '("with rest-args things, return the sum of the elements of things." "Will also increment dates and concatenate strings and lists") 'things nil '(math))
|
|
5
6
|
(dox-add-doc '- 'def '("return the result of subtracting all other args from the first arg." "(- a b c d) is equivalent to (- a (+ b c d))") 'things nil '(math))
|
|
6
7
|
(dox-add-doc '* 'def '("with rest-args things, return the product of the elements of things.") 'things nil '(math))
|
|
@@ -35,21 +36,22 @@
|
|
|
35
36
|
(dox-add-doc 'pair? 'def '("t if arg is a cons cell or (equivalently) the start of a list") '(arg) nil '(nydp-core))
|
|
36
37
|
(dox-add-doc 'hash? 'def '("t if arg is a hash") '(arg) nil '(nydp-core))
|
|
37
38
|
(dox-add-doc 'sym? 'def '("t if arg is a symbol, nil otherwise") '(arg) nil '(nydp-core))
|
|
38
|
-
(dox-add-doc 'ensuring 'def '("execute '
|
|
39
|
-
"'ensure-f will always be executed, even if there is an error in '
|
|
40
|
-
"returns the return value of '
|
|
39
|
+
(dox-add-doc 'ensuring 'def '("execute 'try-f, then 'ensure-f afterwards"
|
|
40
|
+
"'ensure-f will always be executed, even if there is an error in 'try-f"
|
|
41
|
+
"returns the return value of 'try-f. Similar to try/finally in java, or begin/ensure in ruby.") '(ensure-f try-f) nil '(flow-control))
|
|
41
42
|
(dox-add-doc 'inspect 'def '("return a string representing 'arg, potentially (but not always) in a way that can be parsed back in to get the original object") '(arg) nil '(nydp-core))
|
|
42
43
|
(dox-add-doc 'comment 'def '("does nothing at all." "Intercepted inside 'def and 'mac and used for documentation") '(arg) nil '(nydp-core))
|
|
43
44
|
(dox-add-doc 'parse-in-string 'def '("parse the given string assuming a string-open delimiter has already been encountered") '(str) nil '(nydp-core))
|
|
44
45
|
(dox-add-doc 'rand 'def '("return a random number ; with no args, between 0 and 1"
|
|
45
46
|
"with 1 arg, an integer less than arg"
|
|
46
|
-
"with two args, an integer >= arg 0 and < arg 1") 'args
|
|
47
|
-
(dox-add-doc 'random-string 'def '("return a random string of length 'len (default 10)") '(len)
|
|
48
|
-
(dox-add-doc '
|
|
49
|
-
(dox-add-doc 'string
|
|
50
|
-
(dox-add-doc 'string-
|
|
51
|
-
(dox-add-doc 'string-
|
|
52
|
-
(dox-add-doc 'string-
|
|
47
|
+
"with two args, an integer >= arg 0 and < arg 1") 'args nil '(math))
|
|
48
|
+
(dox-add-doc 'random-string 'def '("return a random string of length 'len (default 10)") '(len) nil '(string-manipulation))
|
|
49
|
+
(dox-add-doc 'regexp 'def '("return a regular expression compiled from the given string") '(str) nil '(string-manipulation))
|
|
50
|
+
(dox-add-doc 'to-string 'def '("return a human-readable string representation of 'arg") '(arg) nil '(string-manipulation))
|
|
51
|
+
(dox-add-doc 'string-length 'def '("return the length of 'arg") '(arg) nil '(string-manipulation))
|
|
52
|
+
(dox-add-doc 'string-replace 'def '("replace 'pattern with 'replacement in 'str") '(pattern replacement str) nil '(string-manipulation))
|
|
53
|
+
(dox-add-doc 'string-split 'def '("split 'str delimited by 'delim") '(str delim) nil '(string-manipulation))
|
|
54
|
+
(dox-add-doc 'string-match 'def '("if 'str matches 'pattern, return hash with keys 'match and 'captures ; otherwise nil") '(str pattern) nil '(string-manipulation))
|
|
53
55
|
(dox-add-doc 'time 'def '("with no args, return the current time."
|
|
54
56
|
"With one arg, if 'arg-0 is a number, return the current time plus 'arg-0 seconds."
|
|
55
57
|
"With one arg, if 'arg-0 is a date, return the time at the beginning of the given date."
|
|
@@ -57,9 +59,9 @@
|
|
|
57
59
|
"With two args, 'arg-0 must be a time."
|
|
58
60
|
"If 'arg-1 is a number, return 'arg-0 plus 'arg-1 seconds as a time object."
|
|
59
61
|
"If 'arg-1 is a time, return the number of seconds between the two (- 'arg-0 arg-1)."
|
|
60
|
-
"Otherwise, expect 3
|
|
62
|
+
"Otherwise, expect 3 or more args, to construct a time from"
|
|
61
63
|
"year, month, date, hours, minutes, seconds, milliseconds, reading arguments in that order,"
|
|
62
|
-
"where hours, minutes, seconds, and milliseconds are optional")
|
|
64
|
+
"where hours, minutes, seconds, and milliseconds are optional") 'args nil '(date-time))
|
|
63
65
|
(dox-add-doc 'thread-locals 'def '("return a hash bound to the current thread") nil nil '(nydp-core))
|
|
64
66
|
(dox-add-doc 'type-of 'def '("return a symbol for the type of 'arg") '(arg) nil '(nydp-core))
|
|
65
67
|
(dox-add-doc 'eq? 'def '("return 't if 'arg-0 and 'arg-1 are equal, nil otherwise") '(arg-0 arg-1) nil '(nydp-core))
|
|
@@ -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)
|
|
@@ -84,13 +94,17 @@ scoping, assignment, anonymous functions and more...")
|
|
|
84
94
|
(cons (list (car things) (cadr things))
|
|
85
95
|
(pairs (cddr things)))))
|
|
86
96
|
|
|
97
|
+
;; like 'let, but creates and assigns multiple local variables.
|
|
98
|
+
;; for example, "(with (a 1 b 2) (+ a b))" returns 3
|
|
87
99
|
(mac with (parms . body)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
100
|
+
`((fun ,(map car (pairs parms))
|
|
101
|
+
,@body)
|
|
102
|
+
,@(map cadr (pairs parms))))
|
|
91
103
|
|
|
104
|
+
;; create a lexical scope
|
|
105
|
+
;; where val is assigned to var, execute 'body in that scope
|
|
92
106
|
(mac let (var val . body)
|
|
93
|
-
|
|
107
|
+
`((fun (,var) ,@body) ,val))
|
|
94
108
|
|
|
95
109
|
(mac rfn (name parms . body)
|
|
96
110
|
; creates a named, locally-scoped function
|
|
@@ -105,17 +119,28 @@ scoping, assignment, anonymous functions and more...")
|
|
|
105
119
|
; same as 'rfn, but using the name 'self
|
|
106
120
|
`(rfn self ,parms ,@body))
|
|
107
121
|
|
|
122
|
+
;; a mix of rfn and with; creates a locally-scoped named function with
|
|
123
|
+
;; the given parameter names, and invokes it with the given parameter
|
|
124
|
+
;; values. It is possible to reference the function by its name from
|
|
125
|
+
;; within the function (to pass as an argument or for recursive
|
|
126
|
+
;; invocation)
|
|
108
127
|
(mac rfnwith (name params . body)
|
|
109
|
-
; a mix of rfn and with; creates a locally-scoped named function with
|
|
110
|
-
; the given parameter names, and invokes it with the given parameter
|
|
111
|
-
; values. It is possible to reference the function by its name from
|
|
112
|
-
; within the function (to pass as an argument or for recursive
|
|
113
|
-
; invocation)
|
|
114
128
|
(let ppairs (pairs params)
|
|
115
129
|
`(let ,name nil
|
|
116
130
|
(assign ,name (fun ,(map car ppairs) ,@body))
|
|
117
131
|
(,name ,@(map cadr ppairs)))))
|
|
118
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
|
+
|
|
119
144
|
(let uniq-counter 0
|
|
120
145
|
(def uniq (prefix)
|
|
121
146
|
(assign uniq-counter (+ uniq-counter 1))
|
|
@@ -123,9 +148,9 @@ scoping, assignment, anonymous functions and more...")
|
|
|
123
148
|
(def reset-uniq-counter ()
|
|
124
149
|
(assign uniq-counter 0)))
|
|
125
150
|
|
|
151
|
+
;; creates a lexical scope with a unique symbol assigned to
|
|
152
|
+
;; each variable in 'vars ; executes the 'body.
|
|
126
153
|
(mac w/uniq (vars . body)
|
|
127
|
-
; creates a lexical scope with a unique symbol assigned to
|
|
128
|
-
; each variable in 'vars ; executes the 'body.
|
|
129
154
|
(if (pair? vars)
|
|
130
155
|
`(with ,(apply + (map (fn (n) `(,n (uniq ',n))) vars))
|
|
131
156
|
,@body)
|
|
@@ -194,37 +219,79 @@ scoping, assignment, anonymous functions and more...")
|
|
|
194
219
|
(and (pair? name)
|
|
195
220
|
(caris 'ampersand-syntax (car name))))
|
|
196
221
|
|
|
222
|
+
;; (= (&key (expr)) (val))
|
|
223
|
+
;; (= ((ampersand-syntax key) (expr)) (val))
|
|
224
|
+
;; 'place is ((ampersand-syntax || key) (expr))
|
|
225
|
+
;; we need (hash-set (expr) 'key (val))
|
|
226
|
+
;; however,
|
|
227
|
+
;; (= (&key.subkey (expr)) (val))
|
|
228
|
+
;; 'place is ((ampersand-syntax || (dot-syntax key subkey)) (expr))
|
|
229
|
+
;; we need (hash-set (hash-get (expr) 'key) 'subkey (val))
|
|
197
230
|
(def ampersand-expression-assignment (place value)
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
(
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
(
|
|
226
|
-
|
|
227
|
-
|
|
231
|
+
(let k (cadr:cdar place)
|
|
232
|
+
(let hsh (cadr place)
|
|
233
|
+
(if (caris 'dot-syntax k)
|
|
234
|
+
(dot-syntax-assignment (cons hsh (cdr k)) value)
|
|
235
|
+
`(hash-set ,hsh ',k ,value)))))
|
|
236
|
+
|
|
237
|
+
;; used internally by 'destructuring-assign
|
|
238
|
+
(def destructuring-assigns (names values acc)
|
|
239
|
+
(if names
|
|
240
|
+
(if (pair? names)
|
|
241
|
+
(destructuring-assigns
|
|
242
|
+
(cdr names)
|
|
243
|
+
`(cdr ,values)
|
|
244
|
+
(cons `(= ,(car names) (car ,values)) acc))
|
|
245
|
+
(cons `(= ,names ,values) acc))
|
|
246
|
+
(rev acc)))
|
|
247
|
+
|
|
248
|
+
;; used internally by 'assign-expr
|
|
249
|
+
(def destructuring-assign (name value)
|
|
250
|
+
(w/uniq destructuring-assign
|
|
251
|
+
`(let ,destructuring-assign ,value
|
|
252
|
+
,@(destructuring-assigns name destructuring-assign))))
|
|
253
|
+
|
|
254
|
+
;; used internally by '= macro
|
|
255
|
+
(def assign-expr (nv)
|
|
256
|
+
(let name (car nv)
|
|
257
|
+
(let value (cadr nv)
|
|
258
|
+
(if (isa 'symbol name)
|
|
259
|
+
`(assign ,name ,value)
|
|
260
|
+
(caris 'dot-syntax name)
|
|
261
|
+
(dot-syntax-assignment (cdr name) value)
|
|
262
|
+
(caris 'hash-get name)
|
|
263
|
+
(hash-get-assignment (cdr name) value)
|
|
264
|
+
(ampersand-expression? name)
|
|
265
|
+
(ampersand-expression-assignment name value)
|
|
266
|
+
(caris 'at-syntax name)
|
|
267
|
+
`(hash-set @ ',(caddr name) ,value)
|
|
268
|
+
(pair? name)
|
|
269
|
+
(destructuring-assign name value)
|
|
270
|
+
(error "unknown assignment to place: " (inspect name))))))
|
|
271
|
+
|
|
272
|
+
;; generic assignment which unlike builtin 'assign, knows how to assign
|
|
273
|
+
;; to hash keys
|
|
274
|
+
;; (= (hash-get (expr) 'key) (val) => (hash-set (expr) 'key (val))
|
|
275
|
+
;; (= h.k (val)) => (hash-set h 'k (val))
|
|
276
|
+
;; (= h.j.k (val)) => (hash-set (hash-get h 'j) 'k (val))
|
|
277
|
+
;; (= (&key (expr)) (val)) => (hash-set (expr) 'key (val))
|
|
278
|
+
;; (= (&j.k (expr)) (val)) => (hash-set (hash-get (expr) 'j) 'k (val))
|
|
279
|
+
(mac = assignments
|
|
280
|
+
`(do ,@(map assign-expr (pairs assignments))))
|
|
281
|
+
|
|
282
|
+
;; like 'let, but creates and assigns multiple local variables.
|
|
283
|
+
;; for example, "(with (a 1 b 2) (+ a b))" returns 3
|
|
284
|
+
;;
|
|
285
|
+
;; later variables can references earlier ones:
|
|
286
|
+
;; (with (a 1 b 2 c (+ a b)) (list a b c)) ;; returns (1 2 3)
|
|
287
|
+
(mac with (assignments . body)
|
|
288
|
+
`((fun ,(map car (pairs assignments))
|
|
289
|
+
(= ,@assignments)
|
|
290
|
+
,@body) nil))
|
|
291
|
+
|
|
292
|
+
;; quiet assignment ; like =, but expression returns nil
|
|
293
|
+
(mac #= (name value)
|
|
294
|
+
`(do (= ,name ,value) nil))
|
|
228
295
|
|
|
229
296
|
; increment the value at 'place by 'inc (default 1)
|
|
230
297
|
(mac ++ (place inc) `(= ,place (+ ,place ,(or inc 1))))
|
|
@@ -283,16 +350,25 @@ scoping, assignment, anonymous functions and more...")
|
|
|
283
350
|
; (eg hash), the mutated value will be returned. See also 'returnlet
|
|
284
351
|
(mac returning (val . body) (w/uniq retval `(returnlet ,retval ,val ,@body)))
|
|
285
352
|
|
|
286
|
-
(mac
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
; source: arc.arc
|
|
290
|
-
`(let it ,expr
|
|
291
|
-
(if it
|
|
353
|
+
(mac ifv (var expr . body)
|
|
354
|
+
`(let ,var ,expr
|
|
355
|
+
(if ,var
|
|
292
356
|
,@(if (cddr body)
|
|
293
|
-
`(,(car body) (
|
|
357
|
+
`(,(car body) (ifv ,var ,@(cdr body)))
|
|
294
358
|
body))))
|
|
295
359
|
|
|
360
|
+
; like if, except the value of each condition is locally bound to the variable 'it
|
|
361
|
+
; eg (aif (find thing) (show it))
|
|
362
|
+
; source: arc.arc
|
|
363
|
+
(mac aif (expr . body)
|
|
364
|
+
`(ifv it ,expr ,@body))
|
|
365
|
+
|
|
366
|
+
;; returns the n-th item in the list 'things
|
|
367
|
+
(def nth (n things)
|
|
368
|
+
(if (eq? n 0)
|
|
369
|
+
(car things)
|
|
370
|
+
(nth (- n 1) (cdr things))))
|
|
371
|
+
|
|
296
372
|
(def destructure/with (var args n)
|
|
297
373
|
; provides the argument expression to 'with when
|
|
298
374
|
; destructuring arguments are present in a 'fun definition
|
|
@@ -301,34 +377,52 @@ scoping, assignment, anonymous functions and more...")
|
|
|
301
377
|
args
|
|
302
378
|
`(,args (nthcdr ,n ,var))))
|
|
303
379
|
|
|
304
|
-
|
|
305
|
-
|
|
380
|
+
;; issue a warning if any arg name is the name of a macro
|
|
381
|
+
(def fun/approve-arg-names (orig args body)
|
|
382
|
+
(if (pair? args)
|
|
383
|
+
(do (fun/approve-arg-names orig (car args) body)
|
|
384
|
+
(fun/approve-arg-names orig (cdr args) body))
|
|
385
|
+
args
|
|
386
|
+
(if (hash-get macs args)
|
|
387
|
+
(warnings/new 'arg-shadows-macro "arg " args " shadows macro " args " in arg list " orig " and body " body))))
|
|
388
|
+
|
|
389
|
+
;; used internally by 'fun
|
|
390
|
+
(def destructure/build (given-args new-args body next)
|
|
306
391
|
(if (pair? given-args)
|
|
307
392
|
(if (sym? (car given-args))
|
|
308
393
|
(destructure/build (cdr given-args)
|
|
309
394
|
(cons (car given-args) new-args)
|
|
310
|
-
body
|
|
395
|
+
body
|
|
396
|
+
next)
|
|
311
397
|
(w/uniq destructure
|
|
312
398
|
(destructure/build (cdr given-args)
|
|
313
399
|
(cons destructure new-args)
|
|
314
|
-
`((with ,(destructure/with destructure (car given-args) 0) ,@body))
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
(def fun/
|
|
319
|
-
(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
400
|
+
`((with ,(destructure/with destructure (car given-args) 0) ,@body))
|
|
401
|
+
next)))
|
|
402
|
+
(next (rev new-args given-args) body)))
|
|
403
|
+
|
|
404
|
+
(def fun/destructuring-args (args body next)
|
|
405
|
+
(fun/approve-arg-names args args body)
|
|
406
|
+
(destructure/build args nil body next))
|
|
407
|
+
|
|
408
|
+
(assign fun/expanders
|
|
409
|
+
(list
|
|
410
|
+
(cons 'destructuring-args fun/destructuring-args)
|
|
411
|
+
(cons 'core-builder (fn (args body next) `(fn ,args ,@body)))))
|
|
412
|
+
|
|
413
|
+
(def fun/expand (args body expanders)
|
|
414
|
+
(if expanders
|
|
415
|
+
((cdar expanders)
|
|
416
|
+
args
|
|
417
|
+
body
|
|
418
|
+
(fn (a b)
|
|
419
|
+
(fun/expand a b (cdr expanders))))))
|
|
420
|
+
|
|
421
|
+
;; build a 'fn form, changing 'args and 'body to
|
|
422
|
+
;; properly handle any destructuring args if present
|
|
326
423
|
(mac fun (args . body)
|
|
327
|
-
|
|
328
|
-
; properly handle any destructuring args if present
|
|
329
|
-
(fun/approve-arg-names args args)
|
|
330
|
-
(destructure/build args nil body))
|
|
424
|
+
(fun/expand args body fun/expanders))
|
|
331
425
|
|
|
332
|
-
|
|
426
|
+
;; assign (f place) to place
|
|
333
427
|
(mac zap (f place . args)
|
|
334
428
|
`(= ,place (,f ,place ,@args)))
|