zuzu-js 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +5 -0
- package/README.md +113 -0
- package/bin/zuzu +17 -0
- package/bin/zuzu-build-browser-bundle +57 -0
- package/bin/zuzu-generate-browser-stdlib +584 -0
- package/bin/zuzu-js +23 -0
- package/bin/zuzu-js-compile +152 -0
- package/bin/zuzu-js-electron +19 -0
- package/dist/zuzu-browser-worker.js +45574 -0
- package/dist/zuzu-browser.js +45362 -0
- package/lib/browser-bundle-entry.js +160 -0
- package/lib/browser-gui-renderer.js +387 -0
- package/lib/browser-runtime.js +167 -0
- package/lib/browser-worker-entry.js +413 -0
- package/lib/browser-ztests/runner.html +103 -0
- package/lib/browser-ztests/runner.js +369 -0
- package/lib/cli.js +350 -0
- package/lib/collections.js +367 -0
- package/lib/compiler.js +303 -0
- package/lib/electron/launcher.js +70 -0
- package/lib/electron/main.js +956 -0
- package/lib/electron/preload.js +80 -0
- package/lib/electron/renderer.html +122 -0
- package/lib/electron/renderer.js +24 -0
- package/lib/execution-metadata.js +18 -0
- package/lib/gui/dom-renderer.js +778 -0
- package/lib/host/browser-host.js +278 -0
- package/lib/host/capabilities.js +47 -0
- package/lib/host/electron-host.js +15 -0
- package/lib/host/node-host.js +74 -0
- package/lib/paths.js +150 -0
- package/lib/runtime-entrypoints.js +60 -0
- package/lib/runtime-helpers.js +886 -0
- package/lib/runtime.js +3529 -0
- package/lib/tap.js +37 -0
- package/lib/transpiler-new/ast.js +23 -0
- package/lib/transpiler-new/codegen.js +2455 -0
- package/lib/transpiler-new/errors.js +28 -0
- package/lib/transpiler-new/index.js +26 -0
- package/lib/transpiler-new/lexer.js +834 -0
- package/lib/transpiler-new/parser.js +2332 -0
- package/lib/transpiler-new/validate-bindings.js +326 -0
- package/lib/transpiler-utils.js +95 -0
- package/lib/transpiler.js +33 -0
- package/lib/zuzu.js +53 -0
- package/modules/javascript.js +193 -0
- package/modules/std/archive.js +603 -0
- package/modules/std/clib.js +338 -0
- package/modules/std/data/csv.js +1331 -0
- package/modules/std/data/json.js +531 -0
- package/modules/std/data/xml.js +441 -0
- package/modules/std/data/yaml.js +256 -0
- package/modules/std/db-worker.js +250 -0
- package/modules/std/db.js +664 -0
- package/modules/std/digest/_hash.js +443 -0
- package/modules/std/digest/md5.js +26 -0
- package/modules/std/digest/sha.js +72 -0
- package/modules/std/eval.js +10 -0
- package/modules/std/gui/objects.js +1519 -0
- package/modules/std/internals.js +571 -0
- package/modules/std/io/socks-worker.js +318 -0
- package/modules/std/io/socks.js +186 -0
- package/modules/std/io.js +475 -0
- package/modules/std/marshal/cbor.js +463 -0
- package/modules/std/marshal/graph.js +1624 -0
- package/modules/std/marshal.js +87 -0
- package/modules/std/math/bignum.js +91 -0
- package/modules/std/math.js +79 -0
- package/modules/std/net/dns.js +306 -0
- package/modules/std/net/http.js +820 -0
- package/modules/std/net/smtp.js +943 -0
- package/modules/std/net/url.js +109 -0
- package/modules/std/proc.js +602 -0
- package/modules/std/secure.js +3724 -0
- package/modules/std/string/base64.js +138 -0
- package/modules/std/string.js +299 -0
- package/modules/std/task.js +914 -0
- package/modules/std/time.js +579 -0
- package/modules/std/tui.js +188 -0
- package/modules/std/worker-thread.js +246 -0
- package/modules/std/worker.js +790 -0
- package/package.json +67 -0
- package/stdlib/modules/javascript.zzm +99 -0
- package/stdlib/modules/perl.zzm +105 -0
- package/stdlib/modules/std/archive.zzm +132 -0
- package/stdlib/modules/std/cache/lru.zzm +174 -0
- package/stdlib/modules/std/clib.zzm +112 -0
- package/stdlib/modules/std/colour.zzm +220 -0
- package/stdlib/modules/std/config.zzm +818 -0
- package/stdlib/modules/std/data/cbor.zzm +497 -0
- package/stdlib/modules/std/data/csv.zzm +285 -0
- package/stdlib/modules/std/data/ini.zzm +472 -0
- package/stdlib/modules/std/data/json/schema/core.zzm +573 -0
- package/stdlib/modules/std/data/json/schema/format.zzm +581 -0
- package/stdlib/modules/std/data/json/schema/model.zzm +255 -0
- package/stdlib/modules/std/data/json/schema/output.zzm +272 -0
- package/stdlib/modules/std/data/json/schema/relative_pointer.zzm +299 -0
- package/stdlib/modules/std/data/json/schema/validation.zzm +1503 -0
- package/stdlib/modules/std/data/json/schema.zzm +306 -0
- package/stdlib/modules/std/data/json.zzm +102 -0
- package/stdlib/modules/std/data/kdl/json.zzm +460 -0
- package/stdlib/modules/std/data/kdl/xml.zzm +387 -0
- package/stdlib/modules/std/data/kdl.zzm +1631 -0
- package/stdlib/modules/std/data/toml.zzm +756 -0
- package/stdlib/modules/std/data/toon.zzm +1017 -0
- package/stdlib/modules/std/data/xml/escape.zzm +156 -0
- package/stdlib/modules/std/data/xml.zzm +276 -0
- package/stdlib/modules/std/data/yaml.zzm +94 -0
- package/stdlib/modules/std/db.zzm +173 -0
- package/stdlib/modules/std/defer.zzm +75 -0
- package/stdlib/modules/std/digest/crc32.zzm +196 -0
- package/stdlib/modules/std/digest/md5.zzm +54 -0
- package/stdlib/modules/std/digest/sha.zzm +83 -0
- package/stdlib/modules/std/dump.zzm +317 -0
- package/stdlib/modules/std/eval.zzm +63 -0
- package/stdlib/modules/std/getopt.zzm +432 -0
- package/stdlib/modules/std/gui/dialogue.zzm +592 -0
- package/stdlib/modules/std/gui/objects.zzm +123 -0
- package/stdlib/modules/std/gui.zzm +1914 -0
- package/stdlib/modules/std/internals.zzm +139 -0
- package/stdlib/modules/std/io/socks.zzm +139 -0
- package/stdlib/modules/std/io.zzm +157 -0
- package/stdlib/modules/std/lingua/en.zzm +347 -0
- package/stdlib/modules/std/log.zzm +169 -0
- package/stdlib/modules/std/mail.zzm +2726 -0
- package/stdlib/modules/std/marshal.zzm +138 -0
- package/stdlib/modules/std/math/bignum.zzm +98 -0
- package/stdlib/modules/std/math/range.zzm +116 -0
- package/stdlib/modules/std/math/roman.zzm +156 -0
- package/stdlib/modules/std/math.zzm +141 -0
- package/stdlib/modules/std/net/dns.zzm +93 -0
- package/stdlib/modules/std/net/http.zzm +278 -0
- package/stdlib/modules/std/net/smtp.zzm +257 -0
- package/stdlib/modules/std/net/url.zzm +69 -0
- package/stdlib/modules/std/path/jsonpointer.zzm +526 -0
- package/stdlib/modules/std/path/kdl.zzm +1003 -0
- package/stdlib/modules/std/path/simple.zzm +520 -0
- package/stdlib/modules/std/path/z/context.zzm +147 -0
- package/stdlib/modules/std/path/z/evaluate.zzm +549 -0
- package/stdlib/modules/std/path/z/functions.zzm +874 -0
- package/stdlib/modules/std/path/z/lexer.zzm +490 -0
- package/stdlib/modules/std/path/z/node.zzm +1455 -0
- package/stdlib/modules/std/path/z/operators.zzm +445 -0
- package/stdlib/modules/std/path/z/parser.zzm +359 -0
- package/stdlib/modules/std/path/z.zzm +403 -0
- package/stdlib/modules/std/path/zz/functions.zzm +828 -0
- package/stdlib/modules/std/path/zz/operators.zzm +1036 -0
- package/stdlib/modules/std/path/zz.zzm +100 -0
- package/stdlib/modules/std/proc.zzm +155 -0
- package/stdlib/modules/std/result.zzm +149 -0
- package/stdlib/modules/std/secure.zzm +606 -0
- package/stdlib/modules/std/string/base64.zzm +66 -0
- package/stdlib/modules/std/string/quoted_printable.zzm +485 -0
- package/stdlib/modules/std/string.zzm +179 -0
- package/stdlib/modules/std/task.zzm +221 -0
- package/stdlib/modules/std/template/z.zzm +531 -0
- package/stdlib/modules/std/template/zz.zzm +62 -0
- package/stdlib/modules/std/time.zzm +188 -0
- package/stdlib/modules/std/tui.zzm +89 -0
- package/stdlib/modules/std/uuid.zzm +223 -0
- package/stdlib/modules/std/web/session.zzm +388 -0
- package/stdlib/modules/std/web/static.zzm +329 -0
- package/stdlib/modules/std/web.zzm +1942 -0
- package/stdlib/modules/std/worker.zzm +202 -0
- package/stdlib/modules/std/zuzuzoo.zzm +3960 -0
- package/stdlib/modules/test/more.zzm +528 -0
- package/stdlib/modules/test/parser.zzm +209 -0
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
=encoding utf8
|
|
2
|
+
|
|
3
|
+
=head1 NAME
|
|
4
|
+
|
|
5
|
+
std/path/simple - Tiny JSONPath/XPath-like traversal helper.
|
|
6
|
+
|
|
7
|
+
=head1 SYNOPSIS
|
|
8
|
+
|
|
9
|
+
from std/path/simple import SimplePath;
|
|
10
|
+
|
|
11
|
+
let data := {
|
|
12
|
+
store: {
|
|
13
|
+
books: [
|
|
14
|
+
{ author: "Nigel Rees" },
|
|
15
|
+
{ author: "J. R. R. Tolkien" },
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
let p := new SimplePath( path: "store.books[*].author" );
|
|
21
|
+
for ( let name in p.query(data) ) {
|
|
22
|
+
say name;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
=head1 IMPLEMENTATION SUPPORT
|
|
26
|
+
|
|
27
|
+
This module is supported by all implementations of ZuzuScript.
|
|
28
|
+
|
|
29
|
+
=head1 DESCRIPTION
|
|
30
|
+
|
|
31
|
+
C<SimplePath> implements only a tiny subset of path traversal:
|
|
32
|
+
|
|
33
|
+
=over
|
|
34
|
+
|
|
35
|
+
=item * C<.something>
|
|
36
|
+
|
|
37
|
+
Dict/PairList lookup by key.
|
|
38
|
+
|
|
39
|
+
=item * C<.*>
|
|
40
|
+
|
|
41
|
+
Dict/PairList wildcard that yields all values.
|
|
42
|
+
|
|
43
|
+
=item * C<[1]>
|
|
44
|
+
|
|
45
|
+
Array lookup by numeric index.
|
|
46
|
+
|
|
47
|
+
=item * C<[-1]>
|
|
48
|
+
|
|
49
|
+
Negative indexes count from the end of arrays.
|
|
50
|
+
|
|
51
|
+
=item * C<[*]>
|
|
52
|
+
|
|
53
|
+
Array/Bag/Set wildcard that yields all items.
|
|
54
|
+
|
|
55
|
+
=back
|
|
56
|
+
|
|
57
|
+
No other syntax is supported.
|
|
58
|
+
|
|
59
|
+
The public API intentionally mirrors key C<std/path/z> methods:
|
|
60
|
+
C<get>, C<select>, C<query>, C<first>, C<exists>,
|
|
61
|
+
C<expression>, C<assign_first>, C<assign_all>, C<assign_maybe>,
|
|
62
|
+
C<ref_first>, C<ref_all>, and C<ref_maybe>.
|
|
63
|
+
|
|
64
|
+
The path operators C<@>, C<@@>, and C<@?> can be set to use this module
|
|
65
|
+
in a lexical scope:
|
|
66
|
+
|
|
67
|
+
from std/path/simple import SimplePath;
|
|
68
|
+
SimplePath.use();
|
|
69
|
+
|
|
70
|
+
=head1 EXPORTS
|
|
71
|
+
|
|
72
|
+
=head2 Classes
|
|
73
|
+
|
|
74
|
+
=over
|
|
75
|
+
|
|
76
|
+
=item C<< SimplePath({ path: String }) >>
|
|
77
|
+
|
|
78
|
+
Constructs a simple path selector. Returns: C<SimplePath>.
|
|
79
|
+
|
|
80
|
+
=over
|
|
81
|
+
|
|
82
|
+
=item C<< SimplePath.use() >>
|
|
83
|
+
|
|
84
|
+
Parameters: none. Returns: C<null>. Makes this path class the lexical
|
|
85
|
+
implementation for C<@>, C<@@>, and C<@?>.
|
|
86
|
+
|
|
87
|
+
=item C<< path.expression() >>
|
|
88
|
+
|
|
89
|
+
Parameters: none. Returns: C<String>. Returns the original path
|
|
90
|
+
expression.
|
|
91
|
+
|
|
92
|
+
=item C<< path.get(value) >>, C<< path.select(value) >>, C<< path.query(value) >>
|
|
93
|
+
|
|
94
|
+
Parameters: C<value> is the query root. Returns: C<Array>. Evaluates the
|
|
95
|
+
path and returns selected values.
|
|
96
|
+
|
|
97
|
+
=item C<< path.first(value, fallback) >>
|
|
98
|
+
|
|
99
|
+
Parameters: C<value> is the query root and C<fallback> is returned when
|
|
100
|
+
there is no match. Returns: value. Returns the first selected value.
|
|
101
|
+
|
|
102
|
+
=item C<< path.exists(value) >>
|
|
103
|
+
|
|
104
|
+
Parameters: C<value> is the query root. Returns: C<Boolean>. Returns
|
|
105
|
+
true when the path selects at least one value.
|
|
106
|
+
|
|
107
|
+
=item C<< path.assign_first(target, value, op := ":=", weak := false) >>
|
|
108
|
+
|
|
109
|
+
Parameters: C<target> is the query root, C<value> is the assignment
|
|
110
|
+
value, C<op> is an assignment operator, and C<weak> is accepted for path
|
|
111
|
+
API compatibility. Returns: value. Updates the first selected location.
|
|
112
|
+
|
|
113
|
+
=item C<< path.assign_all(target, value, op := ":=", weak := false) >>
|
|
114
|
+
|
|
115
|
+
Parameters: same as C<assign_first>. Returns: value. Updates every
|
|
116
|
+
selected location.
|
|
117
|
+
|
|
118
|
+
=item C<< path.assign_maybe(target, value, op := ":=", weak := false) >>
|
|
119
|
+
|
|
120
|
+
Parameters: same as C<assign_first>. Returns: C<Boolean>. Updates the
|
|
121
|
+
first selected location when one exists.
|
|
122
|
+
|
|
123
|
+
=item C<< path.ref_first(target) >>
|
|
124
|
+
|
|
125
|
+
Parameters: C<target> is the query root. Returns: C<Function>. Returns a
|
|
126
|
+
reference-like getter/setter for the first selected location.
|
|
127
|
+
|
|
128
|
+
=item C<< path.ref_all(target) >>
|
|
129
|
+
|
|
130
|
+
Parameters: C<target> is the query root. Returns: C<Array>. Returns
|
|
131
|
+
reference-like getter/setters for all selected locations.
|
|
132
|
+
|
|
133
|
+
=item C<< path.ref_maybe(target) >>
|
|
134
|
+
|
|
135
|
+
Parameters: C<target> is the query root. Returns: C<Function> or
|
|
136
|
+
C<null>. Returns a reference-like getter/setter for the first selected
|
|
137
|
+
location when one exists.
|
|
138
|
+
|
|
139
|
+
=back
|
|
140
|
+
|
|
141
|
+
=back
|
|
142
|
+
|
|
143
|
+
=cut
|
|
144
|
+
|
|
145
|
+
from std/string import substr;
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class SimplePath {
|
|
149
|
+
let String path;
|
|
150
|
+
let Array _steps := [];
|
|
151
|
+
|
|
152
|
+
static method use () {
|
|
153
|
+
from std/internals import setupperprop;
|
|
154
|
+
setupperprop( 1, "paths", self );
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
method __build__ () {
|
|
158
|
+
_steps := self._parse(path);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
method expression () {
|
|
162
|
+
return path;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
method _parse ( String raw ) {
|
|
166
|
+
let text := raw;
|
|
167
|
+
let steps := [];
|
|
168
|
+
let i := 0;
|
|
169
|
+
|
|
170
|
+
while ( i < length text ) {
|
|
171
|
+
let ch := substr( text, i, 1 );
|
|
172
|
+
if ( ch ≡ "." ) {
|
|
173
|
+
i++;
|
|
174
|
+
die "SimplePath parse error: expected name or * after '.'"
|
|
175
|
+
if i >= length text;
|
|
176
|
+
let after_dot := substr( text, i, 1 );
|
|
177
|
+
if ( after_dot ≡ "*" ) {
|
|
178
|
+
steps.push( { kind: "dict_wildcard" } );
|
|
179
|
+
i++;
|
|
180
|
+
next;
|
|
181
|
+
}
|
|
182
|
+
let start := i;
|
|
183
|
+
while ( i < length text ) {
|
|
184
|
+
let c := substr( text, i, 1 );
|
|
185
|
+
last if c ≡ "." or c ≡ "[" or c ≡ "]";
|
|
186
|
+
i++;
|
|
187
|
+
}
|
|
188
|
+
let key := substr( text, start, i - start );
|
|
189
|
+
die "SimplePath parse error: empty key"
|
|
190
|
+
if key ≡ "";
|
|
191
|
+
steps.push( { kind: "key", value: key } );
|
|
192
|
+
next;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if ( ch ≡ "[" ) {
|
|
196
|
+
let close := i + 1;
|
|
197
|
+
while ( close < length text and substr( text, close, 1 ) ≢ "]" ) {
|
|
198
|
+
close++;
|
|
199
|
+
}
|
|
200
|
+
die "SimplePath parse error: missing closing ']'"
|
|
201
|
+
if close >= length text;
|
|
202
|
+
let inner := substr( text, i + 1, close - i - 1 );
|
|
203
|
+
if ( inner ≡ "*" ) {
|
|
204
|
+
steps.push( { kind: "list_wildcard" } );
|
|
205
|
+
}
|
|
206
|
+
else if ( inner ~ /^-?[0-9]+$/ ) {
|
|
207
|
+
steps.push( { kind: "index", value: int(inner) } );
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
die `SimplePath parse error: unsupported bracket token '[${inner}]'`;
|
|
211
|
+
}
|
|
212
|
+
i := close + 1;
|
|
213
|
+
next;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
let start := i;
|
|
217
|
+
while ( i < length text ) {
|
|
218
|
+
let c := substr( text, i, 1 );
|
|
219
|
+
last if c ≡ "." or c ≡ "[" or c ≡ "]";
|
|
220
|
+
i++;
|
|
221
|
+
}
|
|
222
|
+
let key := substr( text, start, i - start );
|
|
223
|
+
die `SimplePath parse error: unexpected token '${ch}'`
|
|
224
|
+
if key ≡ "";
|
|
225
|
+
steps.push( { kind: "key", value: key } );
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return steps;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
method _node ( value, parent, key ) {
|
|
232
|
+
return {
|
|
233
|
+
value: value,
|
|
234
|
+
parent: parent,
|
|
235
|
+
key: key,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
method _evaluate_nodes ( value ) {
|
|
240
|
+
let current := [ self._node( value, null, null ) ];
|
|
241
|
+
|
|
242
|
+
for ( let step in _steps ) {
|
|
243
|
+
let next_nodes := [];
|
|
244
|
+
|
|
245
|
+
for ( let node in current ) {
|
|
246
|
+
let v := node{value};
|
|
247
|
+
|
|
248
|
+
if ( step{kind} ≡ "key" ) {
|
|
249
|
+
if ( v instanceof Dict and v.exists( step{value} ) ) {
|
|
250
|
+
next_nodes.push( self._node( v.get( step{value} ), node, step{value} ) );
|
|
251
|
+
}
|
|
252
|
+
else if ( v instanceof PairList ) {
|
|
253
|
+
for ( let item in v.get_all( step{value} ) ) {
|
|
254
|
+
next_nodes.push( self._node( item, node, step{value} ) );
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
next;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if ( step{kind} ≡ "dict_wildcard" ) {
|
|
261
|
+
if ( v instanceof Dict ) {
|
|
262
|
+
for ( let k in v.keys() ) {
|
|
263
|
+
next_nodes.push( self._node( v.get(k), node, k ) );
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
else if ( v instanceof PairList ) {
|
|
267
|
+
for ( let pair in v.to_Array() ) {
|
|
268
|
+
next_nodes.push( self._node( pair.value, node, pair.key ) );
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
next;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if ( step{kind} ≡ "index" ) {
|
|
275
|
+
if ( v instanceof Array ) {
|
|
276
|
+
let idx := step{value};
|
|
277
|
+
if ( idx < 0 ) {
|
|
278
|
+
idx := v.length() + idx;
|
|
279
|
+
}
|
|
280
|
+
if ( idx >= 0 and idx < v.length() ) {
|
|
281
|
+
next_nodes.push( self._node( v[idx], node, idx ) );
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
next;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if ( step{kind} ≡ "list_wildcard" ) {
|
|
288
|
+
if ( v instanceof Array ) {
|
|
289
|
+
let i := 0;
|
|
290
|
+
while ( i < v.length() ) {
|
|
291
|
+
next_nodes.push( self._node( v[i], node, i ) );
|
|
292
|
+
i++;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
else if ( v instanceof Bag or v instanceof Set ) {
|
|
296
|
+
for ( let item in v.to_Array() ) {
|
|
297
|
+
next_nodes.push( self._node( item, node, "*" ) );
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
next;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
current := next_nodes;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return current;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
method _evaluate ( value ) {
|
|
311
|
+
return self._evaluate_nodes(value).map( fn n -> n{value} );
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
method get ( value ) {
|
|
315
|
+
return self._evaluate(value);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
method select ( value ) {
|
|
319
|
+
return self._evaluate(value);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
method query ( value ) {
|
|
323
|
+
return self._evaluate(value);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
method first ( value, fallback ) {
|
|
327
|
+
let out := self._evaluate(value);
|
|
328
|
+
return out.length() = 0 ? fallback : out[0];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
method exists ( value ) {
|
|
332
|
+
return self._evaluate(value).length() > 0;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
method _assign_node ( Dict node, value ) {
|
|
336
|
+
let parent := node{parent};
|
|
337
|
+
die "SimplePath assignment target has no parent node"
|
|
338
|
+
if parent ≡ null;
|
|
339
|
+
|
|
340
|
+
let container := parent{value};
|
|
341
|
+
let key := node{key};
|
|
342
|
+
|
|
343
|
+
if ( container instanceof Array ) {
|
|
344
|
+
die "SimplePath assignment expects numeric array index"
|
|
345
|
+
if not( key instanceof Number );
|
|
346
|
+
container[key] := value;
|
|
347
|
+
return value;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if ( container instanceof Dict ) {
|
|
351
|
+
die "SimplePath assignment expects string dict key"
|
|
352
|
+
if not( key instanceof String );
|
|
353
|
+
container{(key)} := value;
|
|
354
|
+
return value;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if ( container instanceof PairList ) {
|
|
358
|
+
die "SimplePath assignment expects string pairlist key"
|
|
359
|
+
if not( key instanceof String );
|
|
360
|
+
container.set( key, value );
|
|
361
|
+
return value;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
die `SimplePath assignment target container '${typeof container}' is not assignable`;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
method _ref_for_node ( Dict node ) {
|
|
368
|
+
let parent := node{parent};
|
|
369
|
+
die "SimplePath assignment target has no parent node"
|
|
370
|
+
if parent ≡ null;
|
|
371
|
+
|
|
372
|
+
let container := parent{value};
|
|
373
|
+
let key := node{key};
|
|
374
|
+
|
|
375
|
+
if ( container instanceof Array ) {
|
|
376
|
+
die "SimplePath assignment expects numeric array index"
|
|
377
|
+
if not( key instanceof Number );
|
|
378
|
+
return \ container[key];
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if ( container instanceof Dict ) {
|
|
382
|
+
die "SimplePath assignment expects string dict key"
|
|
383
|
+
if not( key instanceof String );
|
|
384
|
+
return \ container{(key)};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if ( container instanceof PairList ) {
|
|
388
|
+
die "SimplePath assignment expects string pairlist key"
|
|
389
|
+
if not( key instanceof String );
|
|
390
|
+
return \ container{(key)};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
die `SimplePath assignment target container '${typeof container}' is not assignable`;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
method _apply_assignment_ref ( ref, value, op := ":=", weak := false ) {
|
|
397
|
+
die "SimplePath weak assignment is not supported"
|
|
398
|
+
if weak;
|
|
399
|
+
|
|
400
|
+
if ( op ≡ ":=" ) {
|
|
401
|
+
return ref(value);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
let current := ref();
|
|
405
|
+
|
|
406
|
+
if ( op ≡ "+=" ) {
|
|
407
|
+
current += value;
|
|
408
|
+
}
|
|
409
|
+
else if ( op ≡ "-=" ) {
|
|
410
|
+
current -= value;
|
|
411
|
+
}
|
|
412
|
+
else if ( op ≡ "*=" or op ≡ "×=" ) {
|
|
413
|
+
current *= value;
|
|
414
|
+
}
|
|
415
|
+
else if ( op ≡ "/=" or op ≡ "÷=" ) {
|
|
416
|
+
current /= value;
|
|
417
|
+
}
|
|
418
|
+
else if ( op ≡ "**=" ) {
|
|
419
|
+
current **= value;
|
|
420
|
+
}
|
|
421
|
+
else if ( op ≡ "_=" ) {
|
|
422
|
+
current _= value;
|
|
423
|
+
}
|
|
424
|
+
else if ( op ≡ "?:=" ) {
|
|
425
|
+
current ?:= value;
|
|
426
|
+
}
|
|
427
|
+
else if ( op ≡ "~=" ) {
|
|
428
|
+
current ~= value[0] -> value[1](m);
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
die `Unsupported path assignment operator '${op}'`;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
ref(current);
|
|
435
|
+
return current;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
method _assign_all_result ( value, op, last_result ) {
|
|
439
|
+
return op ≡ "~=" ? last_result : value;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
method assign_first ( target, value, op := ":=", weak := false ) {
|
|
443
|
+
let nodes := self._evaluate_nodes(target);
|
|
444
|
+
die "SimplePath assignment found no matches"
|
|
445
|
+
if nodes.length() ≡ 0;
|
|
446
|
+
return self._apply_assignment_ref(
|
|
447
|
+
self._ref_for_node( nodes[0] ),
|
|
448
|
+
value,
|
|
449
|
+
op,
|
|
450
|
+
weak,
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
method assign_all ( target, value, op := ":=", weak := false ) {
|
|
455
|
+
let nodes := self._evaluate_nodes(target);
|
|
456
|
+
if ( nodes.length() ≡ 0 ) {
|
|
457
|
+
return self._assign_all_result( value, op, value );
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
let i := 0;
|
|
461
|
+
let last_result := value;
|
|
462
|
+
while ( i < nodes.length() ) {
|
|
463
|
+
last_result := self._apply_assignment_ref(
|
|
464
|
+
self._ref_for_node( nodes[i] ),
|
|
465
|
+
value,
|
|
466
|
+
op,
|
|
467
|
+
weak,
|
|
468
|
+
);
|
|
469
|
+
i++;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return self._assign_all_result( value, op, last_result );
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
method assign_maybe ( target, value, op := ":=", weak := false ) {
|
|
476
|
+
let nodes := self._evaluate_nodes(target);
|
|
477
|
+
if ( nodes.length() ≡ 0 ) {
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
self._apply_assignment_ref(
|
|
482
|
+
self._ref_for_node( nodes[0] ),
|
|
483
|
+
value,
|
|
484
|
+
op,
|
|
485
|
+
weak,
|
|
486
|
+
);
|
|
487
|
+
return true;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
method ref_first ( target ) {
|
|
491
|
+
let nodes := self._evaluate_nodes(target);
|
|
492
|
+
die "SimplePath assignment found no matches"
|
|
493
|
+
if nodes.length() ≡ 0;
|
|
494
|
+
return self._ref_for_node( nodes[0] );
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
method ref_all ( target ) {
|
|
498
|
+
let nodes := self._evaluate_nodes(target);
|
|
499
|
+
let out := [];
|
|
500
|
+
for ( let node in nodes ) {
|
|
501
|
+
out.push( self._ref_for_node(node) );
|
|
502
|
+
}
|
|
503
|
+
return out;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
method ref_maybe ( target ) {
|
|
507
|
+
let nodes := self._evaluate_nodes(target);
|
|
508
|
+
return nodes.length() ≡ 0 ? null : self._ref_for_node( nodes[0] );
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
=head1 COPYRIGHT AND LICENCE
|
|
513
|
+
|
|
514
|
+
B<< std/path/simple >> is copyright Toby Inkster.
|
|
515
|
+
|
|
516
|
+
It is free software; you may redistribute it and/or modify it under
|
|
517
|
+
the terms of either the Artistic License 1.0 or the GNU General Public
|
|
518
|
+
License version 2.
|
|
519
|
+
|
|
520
|
+
=cut
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
=encoding utf8
|
|
2
|
+
|
|
3
|
+
=head1 NAME
|
|
4
|
+
|
|
5
|
+
std/path/z/context - Evaluation context used by std/path/z.
|
|
6
|
+
|
|
7
|
+
=head1 IMPLEMENTATION SUPPORT
|
|
8
|
+
|
|
9
|
+
This module is supported by all implementations of ZuzuScript.
|
|
10
|
+
|
|
11
|
+
=head1 DESCRIPTION
|
|
12
|
+
|
|
13
|
+
This module provides the pure-Zuzu evaluation context used by ZPath.
|
|
14
|
+
|
|
15
|
+
=head1 EXPORTS
|
|
16
|
+
|
|
17
|
+
=head2 Classes
|
|
18
|
+
|
|
19
|
+
=over
|
|
20
|
+
|
|
21
|
+
=item C<< Ctx({ root, nodeset?, parentset?, meta? }) >>
|
|
22
|
+
|
|
23
|
+
Constructs a ZPath evaluation context. Returns: C<Ctx>. Wraps C<root>
|
|
24
|
+
as a C<std/path/z/node> C<Node> and stores the active node sets.
|
|
25
|
+
|
|
26
|
+
=over
|
|
27
|
+
|
|
28
|
+
=item C<< ctx.with_nodeset(ns, ps) >>
|
|
29
|
+
|
|
30
|
+
Parameters: C<ns> is the next node set and C<ps> is the parent set.
|
|
31
|
+
Returns: C<Ctx>. Returns a copy of the context with different node
|
|
32
|
+
sets.
|
|
33
|
+
|
|
34
|
+
=item C<< ctx.nested(extras?) >>
|
|
35
|
+
|
|
36
|
+
Parameters: C<extras> is optional metadata. Returns: C<Ctx>. Returns a
|
|
37
|
+
nested context with incremented metadata level.
|
|
38
|
+
|
|
39
|
+
=item C<< ctx.root() >>
|
|
40
|
+
|
|
41
|
+
Parameters: none. Returns: C<Node>. Returns the root node.
|
|
42
|
+
|
|
43
|
+
=item C<< ctx.nodeset() >>
|
|
44
|
+
|
|
45
|
+
Parameters: none. Returns: C<Array>. Returns the current node set.
|
|
46
|
+
|
|
47
|
+
=item C<< ctx.parentset() >>
|
|
48
|
+
|
|
49
|
+
Parameters: none. Returns: C<Array> or C<null>. Returns the parent node
|
|
50
|
+
set.
|
|
51
|
+
|
|
52
|
+
=item C<< ctx.meta() >>
|
|
53
|
+
|
|
54
|
+
Parameters: none. Returns: C<Dict>. Returns context metadata.
|
|
55
|
+
|
|
56
|
+
=back
|
|
57
|
+
|
|
58
|
+
=back
|
|
59
|
+
|
|
60
|
+
=head1 COPYRIGHT AND LICENCE
|
|
61
|
+
|
|
62
|
+
B<< std/path/z/context >> is copyright Toby Inkster.
|
|
63
|
+
|
|
64
|
+
It is free software; you may redistribute it and/or modify it under
|
|
65
|
+
the terms of either the Artistic License 1.0 or the GNU General Public
|
|
66
|
+
License version 2.
|
|
67
|
+
|
|
68
|
+
=cut
|
|
69
|
+
|
|
70
|
+
from std/path/z/node import Node;
|
|
71
|
+
|
|
72
|
+
class Ctx {
|
|
73
|
+
let root := null;
|
|
74
|
+
let nodeset := null;
|
|
75
|
+
let parentset := null;
|
|
76
|
+
let meta := null;
|
|
77
|
+
|
|
78
|
+
method __build__ () {
|
|
79
|
+
if ( not ( root instanceof Node ) ) {
|
|
80
|
+
let root_obj := root;
|
|
81
|
+
let node_type := null;
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
node_type := int( "" _ root_obj.nodeType() );
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let xml_document := node_type = 9;
|
|
90
|
+
if ( not xml_document and root_obj can documentElement ) {
|
|
91
|
+
try {
|
|
92
|
+
root_obj.documentElement();
|
|
93
|
+
xml_document := true;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if ( xml_document ) {
|
|
100
|
+
try {
|
|
101
|
+
let de := root_obj.documentElement();
|
|
102
|
+
root_obj := de if de ≢ null;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
root := Node.wrap( root_obj );
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
nodeset ?:= [ root ];
|
|
112
|
+
meta ?:= { level: 0 };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
method with_nodeset ( ns, ps ) {
|
|
116
|
+
return new Ctx(
|
|
117
|
+
root: root,
|
|
118
|
+
nodeset: ns,
|
|
119
|
+
parentset: ps,
|
|
120
|
+
meta: meta,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
method nested ( extras? ) {
|
|
125
|
+
let extra_meta := extras ?: {};
|
|
126
|
+
|
|
127
|
+
let next_meta := {
|
|
128
|
+
level: meta.get( "level", 0 ) + 1,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
for ( let pair in extra_meta.enumerate ) {
|
|
132
|
+
next_meta.add( pair );
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return new Ctx(
|
|
136
|
+
root: root,
|
|
137
|
+
nodeset: nodeset,
|
|
138
|
+
parentset: parentset,
|
|
139
|
+
meta: next_meta,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
method root () { return root; }
|
|
144
|
+
method nodeset () { return nodeset; }
|
|
145
|
+
method parentset () { return parentset; }
|
|
146
|
+
method meta () { return meta; }
|
|
147
|
+
}
|