zuzu-js 0.4.0 → 0.5.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/dist/zuzu-browser-worker.js +1012 -68
- package/dist/zuzu-browser.js +1018 -72
- package/lib/browser-bundle-entry.js +2 -0
- package/lib/cli.js +1 -1
- package/lib/collections.js +49 -2
- package/lib/host/browser-host.js +124 -0
- package/lib/runtime-helpers.js +14 -1
- package/lib/runtime.js +562 -30
- package/lib/tap.js +8 -1
- package/lib/transpiler-new/codegen.js +115 -22
- package/lib/transpiler-new/lexer.js +49 -3
- package/lib/transpiler-new/parser.js +121 -11
- package/lib/zuzu.js +5 -1
- package/modules/std/marshal/graph.js +3 -1
- package/package.json +1 -1
- package/stdlib/modules/std/path/zz/operators.zzm +438 -75
- package/stdlib/modules/std/uuid.zzm +1 -1
|
@@ -228,6 +228,9 @@
|
|
|
228
228
|
function makeSet(values) {
|
|
229
229
|
return runtimeHelpers().makeSet(values);
|
|
230
230
|
}
|
|
231
|
+
function operatorString(value) {
|
|
232
|
+
return runtimeHelpers().operatorString(value);
|
|
233
|
+
}
|
|
231
234
|
function stringSortComparator(a, b) {
|
|
232
235
|
return runtimeHelpers().stringSortComparator(a, b);
|
|
233
236
|
}
|
|
@@ -278,7 +281,13 @@
|
|
|
278
281
|
return this.add(...values);
|
|
279
282
|
}
|
|
280
283
|
remove(value) {
|
|
281
|
-
|
|
284
|
+
for (let idx = this.items.length - 1; idx >= 0; idx--) {
|
|
285
|
+
if (this.items[idx] === value) {
|
|
286
|
+
releaseCollectionValue(this, this.items[idx]);
|
|
287
|
+
this.items.splice(idx, 1);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return this;
|
|
282
291
|
}
|
|
283
292
|
remove_first(value) {
|
|
284
293
|
const idx = this.items.indexOf(value);
|
|
@@ -298,9 +307,6 @@
|
|
|
298
307
|
});
|
|
299
308
|
return this;
|
|
300
309
|
}
|
|
301
|
-
get(idx, fallback = null) {
|
|
302
|
-
return idx >= 0 && idx < this.items.length ? this.items[idx] : fallback;
|
|
303
|
-
}
|
|
304
310
|
map(fn2) {
|
|
305
311
|
return new _ZuzuBag(this.items.map(fn2));
|
|
306
312
|
}
|
|
@@ -437,6 +443,9 @@
|
|
|
437
443
|
empty() {
|
|
438
444
|
return this.list.length === 0 ? 1 : 0;
|
|
439
445
|
}
|
|
446
|
+
is_empty() {
|
|
447
|
+
return this.empty();
|
|
448
|
+
}
|
|
440
449
|
keys() {
|
|
441
450
|
return this.list.map((pair) => pair[0]);
|
|
442
451
|
}
|
|
@@ -543,6 +552,7 @@
|
|
|
543
552
|
configurable: true
|
|
544
553
|
});
|
|
545
554
|
function withArrayMethods() {
|
|
555
|
+
const nativeJoin = Array.prototype.join;
|
|
546
556
|
const define = (name2, fn2) => {
|
|
547
557
|
if (!Object.prototype.hasOwnProperty.call(Array.prototype, name2)) {
|
|
548
558
|
const desc = /* @__PURE__ */ Object.create(null);
|
|
@@ -551,6 +561,38 @@
|
|
|
551
561
|
Object.defineProperty(Array.prototype, name2, desc);
|
|
552
562
|
}
|
|
553
563
|
};
|
|
564
|
+
if (Array.prototype.join.__zuzu_array_join !== true) {
|
|
565
|
+
const desc = /* @__PURE__ */ Object.create(null);
|
|
566
|
+
desc.value = function _join(separator, fallback) {
|
|
567
|
+
const hasFallback = arguments.length > 1;
|
|
568
|
+
let fallbackString;
|
|
569
|
+
const sep = operatorString(separator);
|
|
570
|
+
const out = [];
|
|
571
|
+
for (const value of this) {
|
|
572
|
+
try {
|
|
573
|
+
out.push(operatorString(value));
|
|
574
|
+
} catch (err) {
|
|
575
|
+
if (!hasFallback) {
|
|
576
|
+
throw err;
|
|
577
|
+
}
|
|
578
|
+
if (typeof fallback === "function") {
|
|
579
|
+
out.push(operatorString(fallback(value)));
|
|
580
|
+
} else {
|
|
581
|
+
if (fallbackString === void 0) {
|
|
582
|
+
fallbackString = operatorString(fallback);
|
|
583
|
+
}
|
|
584
|
+
out.push(fallbackString);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return nativeJoin.call(out, sep);
|
|
589
|
+
};
|
|
590
|
+
desc.value.__zuzu_array_join = true;
|
|
591
|
+
desc.enumerable = false;
|
|
592
|
+
desc.configurable = true;
|
|
593
|
+
desc.writable = true;
|
|
594
|
+
Object.defineProperty(Array.prototype, "join", desc);
|
|
595
|
+
}
|
|
554
596
|
define("count", function _count() {
|
|
555
597
|
return this.length;
|
|
556
598
|
});
|
|
@@ -1197,6 +1239,9 @@
|
|
|
1197
1239
|
if (name2 === "eq") {
|
|
1198
1240
|
return (left, right) => String(left) === String(right);
|
|
1199
1241
|
}
|
|
1242
|
+
if (name2 === "eqi") {
|
|
1243
|
+
return (left, right) => String(left).toLowerCase() === String(right).toLowerCase();
|
|
1244
|
+
}
|
|
1200
1245
|
if (name2 === "~") {
|
|
1201
1246
|
return (left, right) => {
|
|
1202
1247
|
if (right && typeof right.test === "function") {
|
|
@@ -1207,11 +1252,19 @@
|
|
|
1207
1252
|
}
|
|
1208
1253
|
return (left, right) => left == right;
|
|
1209
1254
|
}
|
|
1255
|
+
function switchTruthy(value) {
|
|
1256
|
+
return !!value;
|
|
1257
|
+
}
|
|
1210
1258
|
function runSwitch(value, cmpName, cases, defaultBody) {
|
|
1211
1259
|
const cmp = buildComparator(cmpName);
|
|
1212
1260
|
let runNext = false;
|
|
1213
1261
|
for (const section of cases) {
|
|
1214
|
-
|
|
1262
|
+
let matched = false;
|
|
1263
|
+
if (Array.isArray(section.tests)) {
|
|
1264
|
+
matched = section.tests.some((test) => switchTruthy(test(value)));
|
|
1265
|
+
} else {
|
|
1266
|
+
matched = section.values.some((item) => cmp(value, item));
|
|
1267
|
+
}
|
|
1215
1268
|
if (matched || runNext) {
|
|
1216
1269
|
const result = section.body();
|
|
1217
1270
|
runNext = result === true;
|
|
@@ -4432,6 +4485,33 @@
|
|
|
4432
4485
|
return `
|
|
4433
4486
|
//# sourceURL=${filename.replace(/[\r\n]/gu, "_")}`;
|
|
4434
4487
|
}
|
|
4488
|
+
var browserModuleUrls = /* @__PURE__ */ new Map();
|
|
4489
|
+
function _normalizeModuleName(value) {
|
|
4490
|
+
const name2 = String(value ?? "").trim().replace(/\\/gu, "/");
|
|
4491
|
+
if (name2 === "" || name2.startsWith("/") || name2.endsWith("/") || /(^|\/)\.\.?(\/|$)/u.test(name2)) {
|
|
4492
|
+
throw new Error(`Invalid browser module name: ${value}`);
|
|
4493
|
+
}
|
|
4494
|
+
return name2.replace(/\.zzm$/u, "");
|
|
4495
|
+
}
|
|
4496
|
+
function _moduleNameFromPath(filename) {
|
|
4497
|
+
const path = _resolvePath(filename);
|
|
4498
|
+
if (!path.startsWith("/modules/") || !path.endsWith(".zzm")) {
|
|
4499
|
+
return null;
|
|
4500
|
+
}
|
|
4501
|
+
return path.slice("/modules/".length, -".zzm".length);
|
|
4502
|
+
}
|
|
4503
|
+
function addBrowserModule(moduleName, url) {
|
|
4504
|
+
const logicalName = _normalizeModuleName(moduleName);
|
|
4505
|
+
const moduleUrl = String(url ?? "").trim();
|
|
4506
|
+
if (moduleUrl === "") {
|
|
4507
|
+
throw new Error(`Invalid URL for browser module '${logicalName}'`);
|
|
4508
|
+
}
|
|
4509
|
+
browserModuleUrls.set(logicalName, moduleUrl);
|
|
4510
|
+
return logicalName;
|
|
4511
|
+
}
|
|
4512
|
+
function hasBrowserModules() {
|
|
4513
|
+
return browserModuleUrls.size > 0;
|
|
4514
|
+
}
|
|
4435
4515
|
function _browserEval(source, context, runOptions = {}) {
|
|
4436
4516
|
context.globalThis = context;
|
|
4437
4517
|
const sourceUrl = _sourceUrlComment(runOptions);
|
|
@@ -4530,6 +4610,11 @@
|
|
|
4530
4610
|
const virtualFiles = new Map(Object.entries(options.virtualFiles || {}).map(([filename, source]) => [_resolvePath(filename), String(source)]));
|
|
4531
4611
|
const jsModules = new Map(Object.entries(options.jsModules || {}).map(([filename, loaded]) => [_resolvePath(filename), loaded]));
|
|
4532
4612
|
const fetchedFiles = /* @__PURE__ */ new Map();
|
|
4613
|
+
const fetchingFiles = /* @__PURE__ */ new Map();
|
|
4614
|
+
const optionModuleUrls = new Map(
|
|
4615
|
+
Object.entries(options.remoteModules || {}).map(([name2, url]) => [_normalizeModuleName(name2), String(url)])
|
|
4616
|
+
);
|
|
4617
|
+
const fetchText = typeof options.fetch === "function" ? options.fetch : typeof fetch === "function" ? fetch : null;
|
|
4533
4618
|
const fetchModule = typeof options.fetchModule === "function" ? options.fetchModule : null;
|
|
4534
4619
|
const runInContext = typeof options.evaluate === "function" ? options.evaluate : _browserEval;
|
|
4535
4620
|
const capabilities2 = /* @__PURE__ */ new Set([
|
|
@@ -4549,6 +4634,56 @@
|
|
|
4549
4634
|
capabilities2.add("worker");
|
|
4550
4635
|
}
|
|
4551
4636
|
const gui = _defaultGuiBridge(options);
|
|
4637
|
+
function browserModuleUrlForPath(filename) {
|
|
4638
|
+
const logicalName = _moduleNameFromPath(filename);
|
|
4639
|
+
if (!logicalName) {
|
|
4640
|
+
return null;
|
|
4641
|
+
}
|
|
4642
|
+
if (optionModuleUrls.has(logicalName)) {
|
|
4643
|
+
return optionModuleUrls.get(logicalName);
|
|
4644
|
+
}
|
|
4645
|
+
return browserModuleUrls.get(logicalName) || null;
|
|
4646
|
+
}
|
|
4647
|
+
function hasAsyncModules() {
|
|
4648
|
+
return optionModuleUrls.size > 0 || browserModuleUrls.size > 0;
|
|
4649
|
+
}
|
|
4650
|
+
async function fetchBrowserModule(key, url) {
|
|
4651
|
+
if (fetchedFiles.has(key)) {
|
|
4652
|
+
return fetchedFiles.get(key);
|
|
4653
|
+
}
|
|
4654
|
+
if (fetchingFiles.has(key)) {
|
|
4655
|
+
return fetchingFiles.get(key);
|
|
4656
|
+
}
|
|
4657
|
+
if (!fetchText) {
|
|
4658
|
+
throw new Error(`Exception: Browser host cannot fetch module '${key}'`);
|
|
4659
|
+
}
|
|
4660
|
+
const pending = Promise.resolve(fetchText(url)).then(async (response) => {
|
|
4661
|
+
if (typeof response === "string") {
|
|
4662
|
+
return response;
|
|
4663
|
+
}
|
|
4664
|
+
if (response && response.ok === false) {
|
|
4665
|
+
throw new Error(
|
|
4666
|
+
`Exception: Fetch failed for browser module '${key}' (${response.status})`
|
|
4667
|
+
);
|
|
4668
|
+
}
|
|
4669
|
+
if (!response || typeof response.text !== "function") {
|
|
4670
|
+
throw new Error(
|
|
4671
|
+
`Exception: Fetch did not return text for browser module '${key}'`
|
|
4672
|
+
);
|
|
4673
|
+
}
|
|
4674
|
+
return response.text();
|
|
4675
|
+
}).then((source) => {
|
|
4676
|
+
const text = String(source);
|
|
4677
|
+
fetchedFiles.set(key, text);
|
|
4678
|
+
fetchingFiles.delete(key);
|
|
4679
|
+
return text;
|
|
4680
|
+
}, (err) => {
|
|
4681
|
+
fetchingFiles.delete(key);
|
|
4682
|
+
throw err;
|
|
4683
|
+
});
|
|
4684
|
+
fetchingFiles.set(key, pending);
|
|
4685
|
+
return pending;
|
|
4686
|
+
}
|
|
4552
4687
|
return {
|
|
4553
4688
|
name: "browser",
|
|
4554
4689
|
repoRoot,
|
|
@@ -4585,13 +4720,33 @@
|
|
|
4585
4720
|
return fetched;
|
|
4586
4721
|
}
|
|
4587
4722
|
}
|
|
4723
|
+
if (browserModuleUrlForPath(key)) {
|
|
4724
|
+
throw new Error(`Exception: Browser module '${filename}' requires asynchronous loading`);
|
|
4725
|
+
}
|
|
4588
4726
|
throw new Error(`Exception: Browser host cannot read file '${filename}'`);
|
|
4589
4727
|
},
|
|
4728
|
+
async readFileTextAsync(filename) {
|
|
4729
|
+
const key = _resolvePath(filename);
|
|
4730
|
+
if (virtualFiles.has(key)) {
|
|
4731
|
+
return virtualFiles.get(key);
|
|
4732
|
+
}
|
|
4733
|
+
if (fetchedFiles.has(key)) {
|
|
4734
|
+
return fetchedFiles.get(key);
|
|
4735
|
+
}
|
|
4736
|
+
const browserModuleUrl = browserModuleUrlForPath(key);
|
|
4737
|
+
if (browserModuleUrl) {
|
|
4738
|
+
return fetchBrowserModule(key, browserModuleUrl);
|
|
4739
|
+
}
|
|
4740
|
+
return this.readFileText(key);
|
|
4741
|
+
},
|
|
4590
4742
|
fileExists(filename) {
|
|
4591
4743
|
const key = _resolvePath(filename);
|
|
4592
4744
|
if (virtualFiles.has(key) || jsModules.has(key) || fetchedFiles.has(key)) {
|
|
4593
4745
|
return true;
|
|
4594
4746
|
}
|
|
4747
|
+
if (browserModuleUrlForPath(key)) {
|
|
4748
|
+
return true;
|
|
4749
|
+
}
|
|
4595
4750
|
if (fetchModule) {
|
|
4596
4751
|
const fetched = fetchModule(key);
|
|
4597
4752
|
if (typeof fetched === "string") {
|
|
@@ -4625,11 +4780,14 @@
|
|
|
4625
4780
|
throw new Error(`Exception: Browser host has no JS module for '${filename}'`);
|
|
4626
4781
|
}
|
|
4627
4782
|
return jsModules.get(key);
|
|
4628
|
-
}
|
|
4783
|
+
},
|
|
4784
|
+
hasAsyncModules
|
|
4629
4785
|
};
|
|
4630
4786
|
}
|
|
4631
4787
|
module2.exports = {
|
|
4632
|
-
|
|
4788
|
+
addBrowserModule,
|
|
4789
|
+
createBrowserHost,
|
|
4790
|
+
hasBrowserModules
|
|
4633
4791
|
};
|
|
4634
4792
|
}
|
|
4635
4793
|
});
|
|
@@ -4782,6 +4940,10 @@
|
|
|
4782
4940
|
"or",
|
|
4783
4941
|
"xor",
|
|
4784
4942
|
"nand",
|
|
4943
|
+
"nor",
|
|
4944
|
+
"xnor",
|
|
4945
|
+
"onlyif",
|
|
4946
|
+
"butnot",
|
|
4785
4947
|
"not",
|
|
4786
4948
|
// TODO: Remove stale legacy JS-only words that are not current
|
|
4787
4949
|
// ZuzuScript keywords: contains, difference, elsif, export, foreach,
|
|
@@ -4866,6 +5028,31 @@
|
|
|
4866
5028
|
"contains"
|
|
4867
5029
|
]);
|
|
4868
5030
|
var SIMPLE_PUNCTUATION = /* @__PURE__ */ new Set(["(", ")", "{", "}", "[", "]", ",", ";", "."]);
|
|
5031
|
+
var VALUE_PRESERVING_LOGICAL_OPERATORS = /* @__PURE__ */ new Set([
|
|
5032
|
+
"and",
|
|
5033
|
+
"\u22C0",
|
|
5034
|
+
"or",
|
|
5035
|
+
"\u22C1",
|
|
5036
|
+
"xor",
|
|
5037
|
+
"\u22BB",
|
|
5038
|
+
"xnor",
|
|
5039
|
+
"\u2194",
|
|
5040
|
+
"nand",
|
|
5041
|
+
"\u22BC",
|
|
5042
|
+
"nor",
|
|
5043
|
+
"\u22BD",
|
|
5044
|
+
"onlyif",
|
|
5045
|
+
"\u22A8",
|
|
5046
|
+
"butnot",
|
|
5047
|
+
"\u22AD"
|
|
5048
|
+
]);
|
|
5049
|
+
function maybeValuePreservingOperator(value, peek, advance) {
|
|
5050
|
+
if (VALUE_PRESERVING_LOGICAL_OPERATORS.has(value) && peek() === "?") {
|
|
5051
|
+
advance();
|
|
5052
|
+
return `${value}?`;
|
|
5053
|
+
}
|
|
5054
|
+
return value;
|
|
5055
|
+
}
|
|
4869
5056
|
function decodeSimpleEscape(esc) {
|
|
4870
5057
|
switch (esc) {
|
|
4871
5058
|
case "n":
|
|
@@ -5137,7 +5324,30 @@
|
|
|
5137
5324
|
if (lastToken.type === "operator") {
|
|
5138
5325
|
return true;
|
|
5139
5326
|
}
|
|
5140
|
-
if (lastToken.type === "keyword" && [
|
|
5327
|
+
if (lastToken.type === "keyword" && [
|
|
5328
|
+
"return",
|
|
5329
|
+
"case",
|
|
5330
|
+
"if",
|
|
5331
|
+
"while",
|
|
5332
|
+
"throw",
|
|
5333
|
+
"and",
|
|
5334
|
+
"and?",
|
|
5335
|
+
"or",
|
|
5336
|
+
"or?",
|
|
5337
|
+
"xor",
|
|
5338
|
+
"xor?",
|
|
5339
|
+
"xnor",
|
|
5340
|
+
"xnor?",
|
|
5341
|
+
"nand",
|
|
5342
|
+
"nand?",
|
|
5343
|
+
"nor",
|
|
5344
|
+
"nor?",
|
|
5345
|
+
"onlyif",
|
|
5346
|
+
"onlyif?",
|
|
5347
|
+
"butnot",
|
|
5348
|
+
"butnot?",
|
|
5349
|
+
"not"
|
|
5350
|
+
].includes(lastToken.value)) {
|
|
5141
5351
|
return true;
|
|
5142
5352
|
}
|
|
5143
5353
|
return false;
|
|
@@ -5507,12 +5717,18 @@
|
|
|
5507
5717
|
addToken("number", value, start, cursor());
|
|
5508
5718
|
continue;
|
|
5509
5719
|
}
|
|
5720
|
+
if (ch === "\u22A4" || ch === "\u22A5") {
|
|
5721
|
+
advance();
|
|
5722
|
+
addToken("keyword", ch === "\u22A4" ? "true" : "false", start, cursor());
|
|
5723
|
+
continue;
|
|
5724
|
+
}
|
|
5510
5725
|
if (isIdentifierStart(ch)) {
|
|
5511
5726
|
let value = "";
|
|
5512
5727
|
while (isIdentifierPart(peek())) {
|
|
5513
5728
|
value += advance();
|
|
5514
5729
|
}
|
|
5515
5730
|
if (KEYWORDS.has(value)) {
|
|
5731
|
+
value = maybeValuePreservingOperator(value, peek, advance);
|
|
5516
5732
|
addToken("keyword", value, start, cursor());
|
|
5517
5733
|
} else {
|
|
5518
5734
|
addToken("identifier", value, start, cursor());
|
|
@@ -5524,9 +5740,10 @@
|
|
|
5524
5740
|
addToken("punctuation", ch, start, cursor());
|
|
5525
5741
|
continue;
|
|
5526
5742
|
}
|
|
5527
|
-
if (["+", "-", "*", "/", "%", "<", ">", "=", "_", "?", ":", "~", "!", "\\", "&", "|", "^", "@", "\xD7", "\xF7", "\xAC", "\u22C0", "\u22C1", "\u22BB", "\u22BC"].includes(ch)) {
|
|
5743
|
+
if (["+", "-", "*", "/", "%", "<", ">", "=", "_", "?", ":", "~", "!", "\\", "&", "|", "^", "@", "\xD7", "\xF7", "\xAC", "\u22C0", "\u22C1", "\u22BB", "\u22BC", "\u22BD", "\u2194", "\u22A8", "\u22AD"].includes(ch)) {
|
|
5528
5744
|
advance();
|
|
5529
|
-
|
|
5745
|
+
const value = maybeValuePreservingOperator(ch, peek, advance);
|
|
5746
|
+
addToken("operator", value, start, cursor());
|
|
5530
5747
|
continue;
|
|
5531
5748
|
}
|
|
5532
5749
|
if (["\u2261", "\u2262", "\u2260", "\u2264", "\u2265", "\u2192", "\u221A", "\u230A", "\u230B", "\u2308", "\u2309", "\u2208", "\u2209", "\u22C3", "\u22C2", "\u2216", "\u2282", "\u2283", "\xAB", "\xBB", "\u2276", "\u2277", "\u25B7", "\u25C1", "\u2223", "\u2224"].includes(ch)) {
|
|
@@ -6517,11 +6734,11 @@
|
|
|
6517
6734
|
let comparator = "==";
|
|
6518
6735
|
if (match("operator", ":")) {
|
|
6519
6736
|
const token = current();
|
|
6520
|
-
|
|
6737
|
+
const operator = parseSwitchComparator();
|
|
6738
|
+
if (!operator) {
|
|
6521
6739
|
throw new TranspilerSyntaxError("Expected switch comparator after :", token);
|
|
6522
6740
|
}
|
|
6523
|
-
|
|
6524
|
-
comparator = token.value;
|
|
6741
|
+
comparator = operator;
|
|
6525
6742
|
}
|
|
6526
6743
|
expect("punctuation", ")", "Expected ) after switch header");
|
|
6527
6744
|
expect("punctuation", "{", "Expected { to start switch body");
|
|
@@ -6555,18 +6772,97 @@
|
|
|
6555
6772
|
}
|
|
6556
6773
|
function parseSwitchCase() {
|
|
6557
6774
|
const start = expect("keyword", "case");
|
|
6558
|
-
const
|
|
6775
|
+
const first = parseSwitchCaseValue();
|
|
6776
|
+
const values = [first.value];
|
|
6777
|
+
const operators = [first.operator];
|
|
6559
6778
|
while (match("punctuation", ",")) {
|
|
6560
|
-
|
|
6779
|
+
const item = parseSwitchCaseValue();
|
|
6780
|
+
values.push(item.value);
|
|
6781
|
+
operators.push(item.operator);
|
|
6561
6782
|
}
|
|
6562
6783
|
expect("operator", ":", "Expected : after switch case");
|
|
6563
6784
|
const consequent = parseSwitchConsequent(start);
|
|
6564
6785
|
return withLoc({
|
|
6565
6786
|
type: "SwitchCase",
|
|
6566
6787
|
values,
|
|
6788
|
+
operators,
|
|
6567
6789
|
consequent
|
|
6568
6790
|
}, start, endLocFromNode(consequent));
|
|
6569
6791
|
}
|
|
6792
|
+
function parseSwitchCaseValue() {
|
|
6793
|
+
const operator = parseSwitchComparator();
|
|
6794
|
+
return {
|
|
6795
|
+
operator,
|
|
6796
|
+
value: parseExpression()
|
|
6797
|
+
};
|
|
6798
|
+
}
|
|
6799
|
+
function parseSwitchComparator() {
|
|
6800
|
+
if (!isSwitchComparatorToken(current())) {
|
|
6801
|
+
return null;
|
|
6802
|
+
}
|
|
6803
|
+
const operator = current().value;
|
|
6804
|
+
index++;
|
|
6805
|
+
return operator;
|
|
6806
|
+
}
|
|
6807
|
+
function isSwitchComparatorToken(token) {
|
|
6808
|
+
if (!token) {
|
|
6809
|
+
return false;
|
|
6810
|
+
}
|
|
6811
|
+
if (token.type === "identifier" && token.value === "instanceof") {
|
|
6812
|
+
return true;
|
|
6813
|
+
}
|
|
6814
|
+
if (token.type !== "operator" && token.type !== "keyword") {
|
|
6815
|
+
return false;
|
|
6816
|
+
}
|
|
6817
|
+
return [
|
|
6818
|
+
">",
|
|
6819
|
+
"<",
|
|
6820
|
+
">=",
|
|
6821
|
+
"\u2264",
|
|
6822
|
+
"<=",
|
|
6823
|
+
"\u2265",
|
|
6824
|
+
"=",
|
|
6825
|
+
"!=",
|
|
6826
|
+
"\u2260",
|
|
6827
|
+
"==",
|
|
6828
|
+
"\u2261",
|
|
6829
|
+
"\u2262",
|
|
6830
|
+
"<=>",
|
|
6831
|
+
"\u2276",
|
|
6832
|
+
"\u2277",
|
|
6833
|
+
"eq",
|
|
6834
|
+
"ne",
|
|
6835
|
+
"gt",
|
|
6836
|
+
"ge",
|
|
6837
|
+
"lt",
|
|
6838
|
+
"le",
|
|
6839
|
+
"cmp",
|
|
6840
|
+
"eqi",
|
|
6841
|
+
"nei",
|
|
6842
|
+
"gti",
|
|
6843
|
+
"gei",
|
|
6844
|
+
"lti",
|
|
6845
|
+
"lei",
|
|
6846
|
+
"cmpi",
|
|
6847
|
+
"in",
|
|
6848
|
+
"\u2208",
|
|
6849
|
+
"not_in",
|
|
6850
|
+
"\u2209",
|
|
6851
|
+
"subsetof",
|
|
6852
|
+
"\u2282",
|
|
6853
|
+
"supersetof",
|
|
6854
|
+
"\u2283",
|
|
6855
|
+
"equivalentof",
|
|
6856
|
+
"\u2282\u2283",
|
|
6857
|
+
"does",
|
|
6858
|
+
"can",
|
|
6859
|
+
"~",
|
|
6860
|
+
"@?",
|
|
6861
|
+
"\u2223",
|
|
6862
|
+
"divides",
|
|
6863
|
+
"\u2224"
|
|
6864
|
+
].includes(token.value);
|
|
6865
|
+
}
|
|
6570
6866
|
function parseSwitchDefaultCase() {
|
|
6571
6867
|
const start = expect("keyword", "default");
|
|
6572
6868
|
expect("operator", ":", "Expected : after default");
|
|
@@ -6953,15 +7249,27 @@
|
|
|
6953
7249
|
}, startLocFromNode(left), endLocFromNode(right));
|
|
6954
7250
|
}
|
|
6955
7251
|
function parseLogicalOr() {
|
|
7252
|
+
return parseLeftAssociative(
|
|
7253
|
+
parseOnlyif,
|
|
7254
|
+
(token) => token.type === "keyword" && ["or", "or?"].includes(token.value) || token.type === "operator" && ["\u22C1", "\u22C1?"].includes(token.value)
|
|
7255
|
+
);
|
|
7256
|
+
}
|
|
7257
|
+
function parseOnlyif() {
|
|
7258
|
+
return parseRightAssociative(
|
|
7259
|
+
parseLogicalXor,
|
|
7260
|
+
(token) => token.type === "keyword" && ["onlyif", "onlyif?"].includes(token.value) || token.type === "operator" && ["\u22A8", "\u22A8?"].includes(token.value)
|
|
7261
|
+
);
|
|
7262
|
+
}
|
|
7263
|
+
function parseLogicalXor() {
|
|
6956
7264
|
return parseLeftAssociative(
|
|
6957
7265
|
parseLogicalAnd,
|
|
6958
|
-
(token) => token.type === "keyword" && ["
|
|
7266
|
+
(token) => token.type === "keyword" && ["xor", "xor?", "nor", "nor?", "xnor", "xnor?"].includes(token.value) || token.type === "operator" && ["\u22BB", "\u22BB?", "\u22BD", "\u22BD?", "\u2194", "\u2194?"].includes(token.value)
|
|
6959
7267
|
);
|
|
6960
7268
|
}
|
|
6961
7269
|
function parseLogicalAnd() {
|
|
6962
7270
|
return parseLeftAssociative(
|
|
6963
7271
|
parseEquality,
|
|
6964
|
-
(token) => token.type === "keyword" &&
|
|
7272
|
+
(token) => token.type === "keyword" && ["and", "and?", "nand", "nand?", "butnot", "butnot?"].includes(token.value) || token.type === "operator" && ["\u22C0", "\u22C0?", "\u22BC", "\u22BC?", "\u22AD", "\u22AD?"].includes(token.value)
|
|
6965
7273
|
);
|
|
6966
7274
|
}
|
|
6967
7275
|
function parseEquality() {
|
|
@@ -7021,6 +7329,21 @@
|
|
|
7021
7329
|
}
|
|
7022
7330
|
return expr;
|
|
7023
7331
|
}
|
|
7332
|
+
function parseRightAssociative(nextFn, predicate) {
|
|
7333
|
+
const left = nextFn();
|
|
7334
|
+
if (!predicate(current())) {
|
|
7335
|
+
return left;
|
|
7336
|
+
}
|
|
7337
|
+
const op = current();
|
|
7338
|
+
index++;
|
|
7339
|
+
const right = parseRightAssociative(nextFn, predicate);
|
|
7340
|
+
return withLoc({
|
|
7341
|
+
type: "BinaryExpression",
|
|
7342
|
+
operator: op.value,
|
|
7343
|
+
left,
|
|
7344
|
+
right
|
|
7345
|
+
}, startLocFromNode(left), endLocFromNode(right));
|
|
7346
|
+
}
|
|
7024
7347
|
function parseUnary() {
|
|
7025
7348
|
if (current().type === "operator" && ["-", "+", "++", "--", "!", "~", "\\", "\u221A", "\xAC"].includes(current().value) || current().type === "keyword" && ["not", "typeof", "abs", "sqrt", "floor", "ceil", "round", "int", "length", "uc", "lc"].includes(current().value)) {
|
|
7026
7349
|
const op = current();
|
|
@@ -7204,6 +7527,17 @@
|
|
|
7204
7527
|
argument
|
|
7205
7528
|
}, start, endLocFromNode(argument));
|
|
7206
7529
|
}
|
|
7530
|
+
if (startsNamedKeyBeforeColon()) {
|
|
7531
|
+
const normalized = parseNamedKeyBeforeColon();
|
|
7532
|
+
expect("operator", ":", "Expected : in named argument");
|
|
7533
|
+
const value = parseExpression();
|
|
7534
|
+
return withLoc({
|
|
7535
|
+
type: "NamedArgument",
|
|
7536
|
+
key: normalized.key,
|
|
7537
|
+
keyExpr: normalized.keyExpr,
|
|
7538
|
+
value
|
|
7539
|
+
}, startLocFromNode(normalized.keyExpr), previous());
|
|
7540
|
+
}
|
|
7207
7541
|
const expr = parseExpression();
|
|
7208
7542
|
if (current().type === "keyword" && current().value === "but") {
|
|
7209
7543
|
throw new TranspilerSyntaxError(
|
|
@@ -7224,6 +7558,20 @@
|
|
|
7224
7558
|
}
|
|
7225
7559
|
return expr;
|
|
7226
7560
|
}
|
|
7561
|
+
function startsNamedKeyBeforeColon() {
|
|
7562
|
+
return ["identifier", "keyword", "string"].includes(current().type) && peekToken().type === "operator" && peekToken().value === ":";
|
|
7563
|
+
}
|
|
7564
|
+
function parseNamedKeyBeforeColon() {
|
|
7565
|
+
const token = current();
|
|
7566
|
+
index++;
|
|
7567
|
+
return {
|
|
7568
|
+
key: token.value,
|
|
7569
|
+
keyExpr: withLoc({
|
|
7570
|
+
type: "StringLiteral",
|
|
7571
|
+
value: token.value
|
|
7572
|
+
}, token, token)
|
|
7573
|
+
};
|
|
7574
|
+
}
|
|
7227
7575
|
function normalizeNamedArgumentKey(expr) {
|
|
7228
7576
|
if (expr.type === "Identifier") {
|
|
7229
7577
|
return {
|
|
@@ -7492,9 +7840,10 @@
|
|
|
7492
7840
|
break;
|
|
7493
7841
|
}
|
|
7494
7842
|
const start = current();
|
|
7495
|
-
const
|
|
7843
|
+
const literalKey = startsNamedKeyBeforeColon() ? parseNamedKeyBeforeColon() : null;
|
|
7844
|
+
const keyExpr = literalKey ? literalKey.keyExpr : parseExpression();
|
|
7496
7845
|
if (current().type === "operator" && current().value === ":") {
|
|
7497
|
-
const normalized = normalizeNamedArgumentKey(keyExpr);
|
|
7846
|
+
const normalized = literalKey || normalizeNamedArgumentKey(keyExpr);
|
|
7498
7847
|
expect("operator", ":", "Expected : in pairlist literal");
|
|
7499
7848
|
const value = parseExpression();
|
|
7500
7849
|
entries.push(withLoc({
|
|
@@ -7725,8 +8074,8 @@
|
|
|
7725
8074
|
function emitProgram(ast, options = {}) {
|
|
7726
8075
|
loopCounter = 0;
|
|
7727
8076
|
chainCounter = 0;
|
|
7728
|
-
const needsAsyncWrapper = programNeedsAsyncWrapper(ast);
|
|
7729
8077
|
const syncEval = options.syncEval === true;
|
|
8078
|
+
const needsAsyncWrapper = programNeedsAsyncWrapper(ast) || options.asyncImports === true && !syncEval && programContainsImport(ast);
|
|
7730
8079
|
const expressionDeclaredNames = collectExpressionDeclaredNames(ast.body);
|
|
7731
8080
|
const sharedOptions = {
|
|
7732
8081
|
...options,
|
|
@@ -7752,7 +8101,7 @@ ${emitExpressionBlock({ body: ast.body }, sharedOptions)}
|
|
|
7752
8101
|
})).join("\n");
|
|
7753
8102
|
const prelude = emitPredeclaredNames(expressionDeclaredNames);
|
|
7754
8103
|
const source = [prelude, body].filter(Boolean).join("\n");
|
|
7755
|
-
if (needsAsyncWrapper && !syncEval) {
|
|
8104
|
+
if (needsAsyncWrapper && !syncEval && options.deferAsyncWrapper !== true) {
|
|
7756
8105
|
return `( async () => {
|
|
7757
8106
|
${source}
|
|
7758
8107
|
} )()`;
|
|
@@ -8509,14 +8858,19 @@ globalThis[${JSON.stringify(node.id.name)}] = ${name2};` : declaration;
|
|
|
8509
8858
|
return `try ${emitBlock(node.block, options)} catch ( __zuzu_err ) { ${catchBody} }`;
|
|
8510
8859
|
}
|
|
8511
8860
|
function emitImportDeclaration(node, options = {}) {
|
|
8861
|
+
const asyncImport = options.asyncImports === true && options.syncEval !== true;
|
|
8862
|
+
const importModule = () => {
|
|
8863
|
+
const call = `__zuzu_import( ${JSON.stringify(node.source)} )`;
|
|
8864
|
+
return asyncImport ? `await ${call}` : call;
|
|
8865
|
+
};
|
|
8512
8866
|
if (node.importAll) {
|
|
8513
8867
|
if (options.syncEval) {
|
|
8514
8868
|
return `{ const __zuzu_star = __zuzu_import( ${JSON.stringify(node.source)} ); }`;
|
|
8515
8869
|
}
|
|
8516
8870
|
if (node.source === "std/eval") {
|
|
8517
|
-
return `{ const __zuzu_star =
|
|
8871
|
+
return `{ const __zuzu_star = ${importModule()}; for ( const __zuzu_key of Object.keys( __zuzu_star ) ) { if ( __zuzu_key === "eval" ) { continue; } const __zuzu_desc = Object.create( null ); __zuzu_desc.configurable = true; __zuzu_desc.enumerable = true; __zuzu_desc.get = function() { return __zuzu_star[ __zuzu_key ] ?? null; }; __zuzu_desc.set = function( value ) { __zuzu_star[ __zuzu_key ] = value; }; Object.defineProperty( globalThis, __zuzu_key, __zuzu_desc ); } }`;
|
|
8518
8872
|
}
|
|
8519
|
-
return `{ const __zuzu_star =
|
|
8873
|
+
return `{ const __zuzu_star = ${importModule()}; if ( Object.prototype.hasOwnProperty.call( __zuzu_star, "done_testing" ) ) { var done_testing = __zuzu_star.done_testing ?? null; } for ( const __zuzu_key of Object.keys( __zuzu_star ) ) { if ( __zuzu_key === "done_testing" ) { continue; } const __zuzu_desc = Object.create( null ); __zuzu_desc.configurable = true; __zuzu_desc.enumerable = true; __zuzu_desc.get = function() { return __zuzu_star[ __zuzu_key ] ?? null; }; __zuzu_desc.set = function( value ) { __zuzu_star[ __zuzu_key ] = value; }; Object.defineProperty( globalThis, __zuzu_key, __zuzu_desc ); } }`;
|
|
8520
8874
|
}
|
|
8521
8875
|
const moduleName = `__zuzu_imported_${Math.abs(hashString(node.source))}_${node.specifiers.length}_${options.syncEval ? loopCounter++ : 0}`;
|
|
8522
8876
|
const defineImports = node.specifiers.map((specifier) => {
|
|
@@ -8565,6 +8919,22 @@ globalThis[${JSON.stringify(node.id.name)}] = ${name2};` : declaration;
|
|
|
8565
8919
|
return `const ${moduleName} = __zuzu_import( ${JSON.stringify(node.source)} ); ${defineImports.join(" ")}`;
|
|
8566
8920
|
}
|
|
8567
8921
|
if (node.tryMode) {
|
|
8922
|
+
if (asyncImport) {
|
|
8923
|
+
return [
|
|
8924
|
+
`{ ${legacyShape} const ${moduleName} = await ( async () => {`,
|
|
8925
|
+
"try {",
|
|
8926
|
+
importCondition ? `if ( !( ${importCondition} ) ) { return {}; }` : "",
|
|
8927
|
+
`return ${importModule()};`,
|
|
8928
|
+
"}",
|
|
8929
|
+
"catch ( __zuzu_err ) {",
|
|
8930
|
+
"if ( __zuzu_err && __zuzu_err.__zuzu_nonlocal_return ) { throw __zuzu_err; }",
|
|
8931
|
+
"return {};",
|
|
8932
|
+
"}",
|
|
8933
|
+
"} )();",
|
|
8934
|
+
...defineImports,
|
|
8935
|
+
"}"
|
|
8936
|
+
].filter(Boolean).join(" ");
|
|
8937
|
+
}
|
|
8568
8938
|
return [
|
|
8569
8939
|
`{ ${legacyShape} const ${moduleName} = ( () => {`,
|
|
8570
8940
|
"try {",
|
|
@@ -8581,6 +8951,16 @@ globalThis[${JSON.stringify(node.id.name)}] = ${name2};` : declaration;
|
|
|
8581
8951
|
].filter(Boolean).join(" ");
|
|
8582
8952
|
}
|
|
8583
8953
|
if (importCondition) {
|
|
8954
|
+
if (asyncImport) {
|
|
8955
|
+
return [
|
|
8956
|
+
`{ ${legacyShape} const ${moduleName} = await ( async () => {`,
|
|
8957
|
+
`if ( !( ${importCondition} ) ) { return ${disabledImports}; }`,
|
|
8958
|
+
`return ${importModule()};`,
|
|
8959
|
+
"} )();",
|
|
8960
|
+
...defineImports,
|
|
8961
|
+
"}"
|
|
8962
|
+
].join(" ");
|
|
8963
|
+
}
|
|
8584
8964
|
return [
|
|
8585
8965
|
`{ ${legacyShape} const ${moduleName} = ( () => {`,
|
|
8586
8966
|
`if ( !( ${importCondition} ) ) { return ${disabledImports}; }`,
|
|
@@ -8590,7 +8970,7 @@ globalThis[${JSON.stringify(node.id.name)}] = ${name2};` : declaration;
|
|
|
8590
8970
|
"}"
|
|
8591
8971
|
].join(" ");
|
|
8592
8972
|
}
|
|
8593
|
-
return `{ ${legacyShape} const ${moduleName} =
|
|
8973
|
+
return `{ ${legacyShape} const ${moduleName} = ${importModule()}; ${defineImports.join(" ")} }`;
|
|
8594
8974
|
}
|
|
8595
8975
|
function normalizeImportedName(source, imported) {
|
|
8596
8976
|
return source === "std/math" && imported === "pi" ? "\u03C0" : imported;
|
|
@@ -8889,7 +9269,7 @@ ${cleanup}
|
|
|
8889
9269
|
}
|
|
8890
9270
|
function emitSwitchStatement(node, options = {}) {
|
|
8891
9271
|
if (options.asyncContext && !options.syncEval) {
|
|
8892
|
-
const cases2 = node.cases.map((section) => `{
|
|
9272
|
+
const cases2 = node.cases.map((section) => `{ tests: [ ${section.values.map((value, index) => `async function( __zuzu_switch_value ) { return __zuzu_truthy( ${emitSwitchTestExpression(section, index, node.comparator)} ); }`).join(", ")} ], body: async function() ${emitBlock(section.consequent, {
|
|
8893
9273
|
...options,
|
|
8894
9274
|
inSwitchSection: true,
|
|
8895
9275
|
loopDepth: 0
|
|
@@ -8902,7 +9282,7 @@ ${cleanup}
|
|
|
8902
9282
|
const tail2 = switchStatementContainsReturn(node) ? options.inSwitchSection ? "if ( __zuzu_switch_result && __zuzu_switch_result.__zuzu_return ) { return __zuzu_switch_result; }" : "if ( __zuzu_switch_result && __zuzu_switch_result.__zuzu_return ) { return __zuzu_switch_result.value; }" : "";
|
|
8903
9283
|
return `{ let __zuzu_switch_result = await __zuzu_switch_async( ${emitExpression(node.discriminant)}, ${JSON.stringify(node.comparator)}, [ ${cases2.join(", ")} ], ${defaultBody2} ); ${tail2} }`;
|
|
8904
9284
|
}
|
|
8905
|
-
const cases = node.cases.map((section) => `{
|
|
9285
|
+
const cases = node.cases.map((section) => `{ tests: [ ${section.values.map((value, index) => `function( __zuzu_switch_value ) { return __zuzu_truthy( ${emitSwitchTestExpression(section, index, node.comparator)} ); }`).join(", ")} ], body: function() ${emitBlock(section.consequent, {
|
|
8906
9286
|
...options,
|
|
8907
9287
|
inSwitchSection: true,
|
|
8908
9288
|
loopDepth: 0
|
|
@@ -8915,6 +9295,19 @@ ${cleanup}
|
|
|
8915
9295
|
const tail = switchStatementContainsReturn(node) ? options.inSwitchSection ? "if ( __zuzu_switch_result && __zuzu_switch_result.__zuzu_return ) { return __zuzu_switch_result; }" : "if ( __zuzu_switch_result && __zuzu_switch_result.__zuzu_return ) { return __zuzu_switch_result.value; }" : "";
|
|
8916
9296
|
return `{ let __zuzu_switch_result = __zuzu_switch( ${emitExpression(node.discriminant)}, ${JSON.stringify(node.comparator)}, [ ${cases.join(", ")} ], ${defaultBody} ); ${tail} }`;
|
|
8917
9297
|
}
|
|
9298
|
+
function emitSwitchTestExpression(section, index, defaultComparator) {
|
|
9299
|
+
const right = section.values[index];
|
|
9300
|
+
const operator = section.operators && section.operators[index] || defaultComparator || "==";
|
|
9301
|
+
return emitBinaryExpression({
|
|
9302
|
+
type: "BinaryExpression",
|
|
9303
|
+
operator,
|
|
9304
|
+
left: {
|
|
9305
|
+
type: "Identifier",
|
|
9306
|
+
name: "__zuzu_switch_value"
|
|
9307
|
+
},
|
|
9308
|
+
right
|
|
9309
|
+
});
|
|
9310
|
+
}
|
|
8918
9311
|
function emitTraitDeclaration(node, options = {}) {
|
|
8919
9312
|
const methods = completeMethodDeclarations(node.body || []).map((method) => {
|
|
8920
9313
|
const value = emitMethodFunction(method, {
|
|
@@ -9216,13 +9609,17 @@ ${cleanup}
|
|
|
9216
9609
|
source = `await __zuzu_collection_${method}_async( ${object}, ${args} )`;
|
|
9217
9610
|
} else if (node.arguments.length === 0) {
|
|
9218
9611
|
const object = emitExpression(node.callee.object);
|
|
9219
|
-
|
|
9220
|
-
|
|
9612
|
+
if (node.callee.computed) {
|
|
9613
|
+
const property = node.callee.property.type === "BraceIdentifier" ? `__zuzu_resolve_brace_key( __zuzu_receiver, ${JSON.stringify(node.callee.property.name)}, () => ${node.callee.property.name} )` : emitExpression(node.callee.property);
|
|
9614
|
+
source = `( () => { const __zuzu_receiver = ${object}; return __zuzu_call_member( __zuzu_receiver, ${property} ); } )()`;
|
|
9615
|
+
} else {
|
|
9616
|
+
source = `__zuzu_call_member( ${object}, ${JSON.stringify(node.callee.property.name)} )`;
|
|
9617
|
+
}
|
|
9221
9618
|
} else {
|
|
9222
9619
|
const object = emitExpression(node.callee.object);
|
|
9223
9620
|
if (node.callee.computed) {
|
|
9224
|
-
const property = node.callee.property.type === "BraceIdentifier" ? `__zuzu_resolve_brace_key(
|
|
9225
|
-
source = `
|
|
9621
|
+
const property = node.callee.property.type === "BraceIdentifier" ? `__zuzu_resolve_brace_key( __zuzu_receiver, ${JSON.stringify(node.callee.property.name)}, () => ${node.callee.property.name} )` : emitExpression(node.callee.property);
|
|
9622
|
+
source = `( () => { const __zuzu_receiver = ${object}; return __zuzu_call_member( __zuzu_receiver, ${property}, ${args} ); } )()`;
|
|
9226
9623
|
} else {
|
|
9227
9624
|
source = `__zuzu_call_member( ${object}, ${JSON.stringify(node.callee.property.name)}, ${args} )`;
|
|
9228
9625
|
}
|
|
@@ -9405,16 +9802,52 @@ ${cleanup}
|
|
|
9405
9802
|
switch (node.operator) {
|
|
9406
9803
|
case "and":
|
|
9407
9804
|
case "\u22C0":
|
|
9408
|
-
return `( () => { const __zuzu_left = ${left}; return __zuzu_truthy( __zuzu_left ) ?
|
|
9805
|
+
return `( () => { const __zuzu_left = ${left}; return __zuzu_truthy( __zuzu_left ) ? __zuzu_truthy( ${right} ) : false; } )()`;
|
|
9806
|
+
case "and?":
|
|
9807
|
+
case "\u22C0?":
|
|
9808
|
+
return `( () => { const __zuzu_left = ${left}; return __zuzu_truthy( __zuzu_left ) ? ${right} : __zuzu_left; } )()`;
|
|
9409
9809
|
case "or":
|
|
9410
9810
|
case "\u22C1":
|
|
9411
|
-
return `( () => { const __zuzu_left = ${left}; return __zuzu_truthy( __zuzu_left ) ?
|
|
9811
|
+
return `( () => { const __zuzu_left = ${left}; return __zuzu_truthy( __zuzu_left ) ? true : __zuzu_truthy( ${right} ); } )()`;
|
|
9812
|
+
case "or?":
|
|
9813
|
+
case "\u22C1?":
|
|
9814
|
+
return `( () => { const __zuzu_left = ${left}; return __zuzu_truthy( __zuzu_left ) ? __zuzu_left : ${right}; } )()`;
|
|
9815
|
+
case "nor":
|
|
9816
|
+
case "\u22BD":
|
|
9817
|
+
return `( () => { const __zuzu_left = ${left}; return __zuzu_truthy( __zuzu_left ) ? false : !__zuzu_truthy( ${right} ); } )()`;
|
|
9818
|
+
case "nor?":
|
|
9819
|
+
case "\u22BD?":
|
|
9820
|
+
return `( () => { const __zuzu_left = ${left}; const __zuzu_right = ${right}; return __zuzu_truthy( __zuzu_left ) ? ( __zuzu_truthy( __zuzu_right ) ? false : __zuzu_right ) : ( __zuzu_truthy( __zuzu_right ) ? __zuzu_left : true ); } )()`;
|
|
9412
9821
|
case "xor":
|
|
9413
9822
|
case "\u22BB":
|
|
9414
9823
|
return `__zuzu_xor( ${left}, ${right} )`;
|
|
9824
|
+
case "xor?":
|
|
9825
|
+
case "\u22BB?":
|
|
9826
|
+
return `( () => { const __zuzu_left = ${left}; const __zuzu_right = ${right}; return __zuzu_truthy( __zuzu_left ) ? ( __zuzu_truthy( __zuzu_right ) ? false : __zuzu_left ) : ( __zuzu_truthy( __zuzu_right ) ? __zuzu_right : false ); } )()`;
|
|
9827
|
+
case "xnor":
|
|
9828
|
+
case "\u2194":
|
|
9829
|
+
return `( __zuzu_truthy( ${left} ) === __zuzu_truthy( ${right} ) )`;
|
|
9830
|
+
case "xnor?":
|
|
9831
|
+
case "\u2194?":
|
|
9832
|
+
return `( () => { const __zuzu_left = ${left}; const __zuzu_right = ${right}; return __zuzu_truthy( __zuzu_left ) ? __zuzu_right : ( __zuzu_truthy( __zuzu_right ) ? __zuzu_left : true ); } )()`;
|
|
9415
9833
|
case "nand":
|
|
9416
9834
|
case "\u22BC":
|
|
9417
9835
|
return `__zuzu_nand( ${left}, ${right} )`;
|
|
9836
|
+
case "nand?":
|
|
9837
|
+
case "\u22BC?":
|
|
9838
|
+
return `( () => { const __zuzu_left = ${left}; const __zuzu_right = ${right}; return __zuzu_truthy( __zuzu_left ) ? ( __zuzu_truthy( __zuzu_right ) ? false : true ) : ( __zuzu_truthy( __zuzu_right ) ? __zuzu_right : true ); } )()`;
|
|
9839
|
+
case "onlyif":
|
|
9840
|
+
case "\u22A8":
|
|
9841
|
+
return `( () => { const __zuzu_left = ${left}; return __zuzu_truthy( __zuzu_left ) ? __zuzu_truthy( ${right} ) : true; } )()`;
|
|
9842
|
+
case "onlyif?":
|
|
9843
|
+
case "\u22A8?":
|
|
9844
|
+
return `( () => { const __zuzu_left = ${left}; return __zuzu_truthy( __zuzu_left ) ? ${right} : true; } )()`;
|
|
9845
|
+
case "butnot":
|
|
9846
|
+
case "\u22AD":
|
|
9847
|
+
return `( () => { const __zuzu_left = ${left}; return __zuzu_truthy( __zuzu_left ) ? !__zuzu_truthy( ${right} ) : false; } )()`;
|
|
9848
|
+
case "butnot?":
|
|
9849
|
+
case "\u22AD?":
|
|
9850
|
+
return `( () => { const __zuzu_left = ${left}; return __zuzu_truthy( __zuzu_left ) ? ( __zuzu_truthy( ${right} ) ? false : __zuzu_left ) : __zuzu_left; } )()`;
|
|
9418
9851
|
case "eq":
|
|
9419
9852
|
return `__zuzu_str_eq( ${left}, ${right} )`;
|
|
9420
9853
|
case "ne":
|
|
@@ -9817,6 +10250,9 @@ ${cleanup}
|
|
|
9817
10250
|
function programNeedsAsyncWrapper(ast) {
|
|
9818
10251
|
return ast.body.some((stmt) => nodeContainsAsyncControl(stmt));
|
|
9819
10252
|
}
|
|
10253
|
+
function programContainsImport(ast) {
|
|
10254
|
+
return ast.body.some((stmt) => stmt && stmt.type === "ImportDeclaration");
|
|
10255
|
+
}
|
|
9820
10256
|
function nodeContainsAsyncControl(node) {
|
|
9821
10257
|
if (!node || typeof node !== "object") {
|
|
9822
10258
|
return false;
|
|
@@ -11104,7 +11540,7 @@ ${cleanup}
|
|
|
11104
11540
|
"package.json"(exports2, module2) {
|
|
11105
11541
|
module2.exports = {
|
|
11106
11542
|
name: "zuzu-js",
|
|
11107
|
-
version: "0.
|
|
11543
|
+
version: "0.5.0",
|
|
11108
11544
|
description: "JavaScript runtime, compiler, and browser bundle for ZuzuScript.",
|
|
11109
11545
|
main: "lib/zuzu.js",
|
|
11110
11546
|
bin: {
|
|
@@ -11758,6 +12194,12 @@ ${cleanup}
|
|
|
11758
12194
|
this.add(makeWeakValue(value));
|
|
11759
12195
|
return this;
|
|
11760
12196
|
});
|
|
12197
|
+
define(Set.prototype, "push_weak", function _pushWeak(...values) {
|
|
12198
|
+
for (const value of values) {
|
|
12199
|
+
this.add(makeWeakValue(value));
|
|
12200
|
+
}
|
|
12201
|
+
return this;
|
|
12202
|
+
});
|
|
11761
12203
|
define(Set.prototype, "copy", function _copy() {
|
|
11762
12204
|
return makeSet(this);
|
|
11763
12205
|
});
|
|
@@ -12064,8 +12506,12 @@ ${cleanup}
|
|
|
12064
12506
|
switch (comparator) {
|
|
12065
12507
|
case "eq":
|
|
12066
12508
|
return stringCompare(left, right) === 0;
|
|
12509
|
+
case "eqi":
|
|
12510
|
+
return stringCompare(left, right, { insensitive: true }) === 0;
|
|
12067
12511
|
case "ne":
|
|
12068
12512
|
return stringCompare(left, right) !== 0;
|
|
12513
|
+
case "nei":
|
|
12514
|
+
return stringCompare(left, right, { insensitive: true }) !== 0;
|
|
12069
12515
|
case "=":
|
|
12070
12516
|
return numericEqual(zuzuToNumber(left), zuzuToNumber(right));
|
|
12071
12517
|
case "==":
|
|
@@ -12075,7 +12521,17 @@ ${cleanup}
|
|
|
12075
12521
|
};
|
|
12076
12522
|
let runNext = false;
|
|
12077
12523
|
for (const section of cases) {
|
|
12078
|
-
|
|
12524
|
+
let matched = false;
|
|
12525
|
+
if (Array.isArray(section.tests)) {
|
|
12526
|
+
for (const test of section.tests) {
|
|
12527
|
+
if (zuzuTruthy(await taskRuntime2.awaitValue(test(value)))) {
|
|
12528
|
+
matched = true;
|
|
12529
|
+
break;
|
|
12530
|
+
}
|
|
12531
|
+
}
|
|
12532
|
+
} else {
|
|
12533
|
+
matched = section.values.some((item) => cmp(value, item));
|
|
12534
|
+
}
|
|
12079
12535
|
if (matched || runNext) {
|
|
12080
12536
|
const result = await taskRuntime2.awaitValue(section.body());
|
|
12081
12537
|
runNext = result === true;
|
|
@@ -12310,7 +12766,7 @@ ${cleanup}
|
|
|
12310
12766
|
return Object.prototype.toString.call(value) === "[object Object]" && !(value.constructor && value.constructor.__zuzu_class_name);
|
|
12311
12767
|
}
|
|
12312
12768
|
function isDictMethodReceiver(value) {
|
|
12313
|
-
return
|
|
12769
|
+
return isPlainObjectLike(value) && !isPairListLike(value) && !isSetLike(value) && !isBagLike(value);
|
|
12314
12770
|
}
|
|
12315
12771
|
function normalizeDictKey(key) {
|
|
12316
12772
|
key = resolveWeakValue(key);
|
|
@@ -12328,18 +12784,350 @@ ${cleanup}
|
|
|
12328
12784
|
}
|
|
12329
12785
|
return String(key);
|
|
12330
12786
|
}
|
|
12787
|
+
function arraySliceBounds(length, start, end = length) {
|
|
12788
|
+
let from = Number(start ?? 0);
|
|
12789
|
+
let to = Number(end ?? length);
|
|
12790
|
+
from = Number.isFinite(from) ? Math.trunc(from) : 0;
|
|
12791
|
+
to = Number.isFinite(to) ? Math.trunc(to) : length;
|
|
12792
|
+
if (from < 0) {
|
|
12793
|
+
from += length;
|
|
12794
|
+
}
|
|
12795
|
+
if (to < 0) {
|
|
12796
|
+
to += length;
|
|
12797
|
+
}
|
|
12798
|
+
from = Math.max(0, Math.min(length, from));
|
|
12799
|
+
to = Math.max(0, Math.min(length, to));
|
|
12800
|
+
return [Math.min(from, to), Math.max(from, to)];
|
|
12801
|
+
}
|
|
12802
|
+
function arrayMethodArity(name2, actual, min, max = min) {
|
|
12803
|
+
const count = actual - 1;
|
|
12804
|
+
if (count < min || count > max) {
|
|
12805
|
+
throw new Error(
|
|
12806
|
+
min === max ? `${name2} expects ${min} argument${min === 1 ? "" : "s"}` : `${name2} expects between ${min} and ${max} arguments`
|
|
12807
|
+
);
|
|
12808
|
+
}
|
|
12809
|
+
}
|
|
12810
|
+
function arrayIndex(length, idx) {
|
|
12811
|
+
let index = Number(idx);
|
|
12812
|
+
index = Number.isFinite(index) ? Math.trunc(index) : 0;
|
|
12813
|
+
if (index < 0) {
|
|
12814
|
+
index += length;
|
|
12815
|
+
}
|
|
12816
|
+
return index;
|
|
12817
|
+
}
|
|
12818
|
+
function shuffledArrayValues(self) {
|
|
12819
|
+
const out = self.slice();
|
|
12820
|
+
for (let idx = out.length - 1; idx > 0; idx--) {
|
|
12821
|
+
const swapIdx = Math.floor(Math.random() * (idx + 1));
|
|
12822
|
+
[out[idx], out[swapIdx]] = [out[swapIdx], out[idx]];
|
|
12823
|
+
}
|
|
12824
|
+
return out;
|
|
12825
|
+
}
|
|
12826
|
+
function arrayJoin(self, separator, fallback, hasFallback) {
|
|
12827
|
+
const sep = operatorString(separator);
|
|
12828
|
+
let fallbackString;
|
|
12829
|
+
const out = [];
|
|
12830
|
+
for (const value of self) {
|
|
12831
|
+
try {
|
|
12832
|
+
out.push(operatorString(value));
|
|
12833
|
+
} catch (err) {
|
|
12834
|
+
if (!hasFallback) {
|
|
12835
|
+
throw err;
|
|
12836
|
+
}
|
|
12837
|
+
if (typeof fallback === "function") {
|
|
12838
|
+
out.push(operatorString(fallback(value)));
|
|
12839
|
+
} else {
|
|
12840
|
+
if (fallbackString === void 0) {
|
|
12841
|
+
fallbackString = operatorString(fallback);
|
|
12842
|
+
}
|
|
12843
|
+
out.push(fallbackString);
|
|
12844
|
+
}
|
|
12845
|
+
}
|
|
12846
|
+
}
|
|
12847
|
+
return out.join(sep);
|
|
12848
|
+
}
|
|
12849
|
+
var ARRAY_METHODS = Object.freeze({
|
|
12850
|
+
append(self, ...values) {
|
|
12851
|
+
self.push(...values.map((value) => retainCollectionValue(self, value)));
|
|
12852
|
+
return self;
|
|
12853
|
+
},
|
|
12854
|
+
push(self, ...values) {
|
|
12855
|
+
return ARRAY_METHODS.append(self, ...values);
|
|
12856
|
+
},
|
|
12857
|
+
add(self, ...values) {
|
|
12858
|
+
return ARRAY_METHODS.append(self, ...values);
|
|
12859
|
+
},
|
|
12860
|
+
push_weak(self, ...values) {
|
|
12861
|
+
self.push(...values.map(makeWeakValue));
|
|
12862
|
+
return self;
|
|
12863
|
+
},
|
|
12864
|
+
pop(self) {
|
|
12865
|
+
return self.length ? self.pop() : null;
|
|
12866
|
+
},
|
|
12867
|
+
prepend(self, ...values) {
|
|
12868
|
+
self.unshift(...values.map((value) => retainCollectionValue(self, value)));
|
|
12869
|
+
return self;
|
|
12870
|
+
},
|
|
12871
|
+
unshift(self, ...values) {
|
|
12872
|
+
return ARRAY_METHODS.prepend(self, ...values);
|
|
12873
|
+
},
|
|
12874
|
+
unshift_weak(self, ...values) {
|
|
12875
|
+
self.unshift(...values.map(makeWeakValue));
|
|
12876
|
+
return self;
|
|
12877
|
+
},
|
|
12878
|
+
shift(self) {
|
|
12879
|
+
return self.length ? self.shift() : null;
|
|
12880
|
+
},
|
|
12881
|
+
length(self) {
|
|
12882
|
+
return self.length;
|
|
12883
|
+
},
|
|
12884
|
+
count(self) {
|
|
12885
|
+
return self.length;
|
|
12886
|
+
},
|
|
12887
|
+
empty(self) {
|
|
12888
|
+
return self.length === 0 ? 1 : 0;
|
|
12889
|
+
},
|
|
12890
|
+
is_empty(self) {
|
|
12891
|
+
return ARRAY_METHODS.empty(self);
|
|
12892
|
+
},
|
|
12893
|
+
copy(self) {
|
|
12894
|
+
return makeArray(self);
|
|
12895
|
+
},
|
|
12896
|
+
to_Array(self) {
|
|
12897
|
+
return makeArray(self);
|
|
12898
|
+
},
|
|
12899
|
+
get(self, idx, fallback = null) {
|
|
12900
|
+
arrayMethodArity("Array.get", arguments.length, 1, 2);
|
|
12901
|
+
const index = arrayIndex(self.length, idx);
|
|
12902
|
+
return index >= 0 && index < self.length ? self[index] : fallback;
|
|
12903
|
+
},
|
|
12904
|
+
set(self, idx, value) {
|
|
12905
|
+
arrayMethodArity("Array.set", arguments.length, 2);
|
|
12906
|
+
const index = arrayIndex(self.length, idx);
|
|
12907
|
+
if (index < 0) {
|
|
12908
|
+
throw new Error("Array index is out of range");
|
|
12909
|
+
}
|
|
12910
|
+
releaseCollectionValue(self, self[index]);
|
|
12911
|
+
self[index] = retainCollectionValue(self, value);
|
|
12912
|
+
return self;
|
|
12913
|
+
},
|
|
12914
|
+
set_weak(self, idx, value) {
|
|
12915
|
+
arrayMethodArity("Array.set_weak", arguments.length, 2);
|
|
12916
|
+
const index = arrayIndex(self.length, idx);
|
|
12917
|
+
if (index < 0) {
|
|
12918
|
+
throw new Error("Array index is out of range");
|
|
12919
|
+
}
|
|
12920
|
+
releaseCollectionValue(self, self[index]);
|
|
12921
|
+
self[index] = makeWeakValue(value);
|
|
12922
|
+
return self;
|
|
12923
|
+
},
|
|
12924
|
+
clear(self) {
|
|
12925
|
+
releaseCollectionValues(self);
|
|
12926
|
+
self.splice(0, self.length);
|
|
12927
|
+
return self;
|
|
12928
|
+
},
|
|
12929
|
+
join(self, separator, fallback) {
|
|
12930
|
+
return arrayJoin(self, separator, fallback, arguments.length > 2);
|
|
12931
|
+
},
|
|
12932
|
+
slice(self, start, end) {
|
|
12933
|
+
const [from, to] = arraySliceBounds(self.length, start, end);
|
|
12934
|
+
return makeArray(self.slice(from, to));
|
|
12935
|
+
},
|
|
12936
|
+
head(self, n = 1) {
|
|
12937
|
+
arrayMethodArity("Array.head", arguments.length, 0, 1);
|
|
12938
|
+
return makeArray(self.slice(0, Math.max(0, Number(n) || 0)));
|
|
12939
|
+
},
|
|
12940
|
+
tail(self, n = 1) {
|
|
12941
|
+
arrayMethodArity("Array.tail", arguments.length, 0, 1);
|
|
12942
|
+
const count = Math.max(0, Number(n) || 0);
|
|
12943
|
+
return makeArray(count === 0 ? [] : self.slice(-count));
|
|
12944
|
+
},
|
|
12945
|
+
to_Set(self) {
|
|
12946
|
+
return makeSet(self);
|
|
12947
|
+
},
|
|
12948
|
+
to_Bag(self) {
|
|
12949
|
+
return makeBag(self);
|
|
12950
|
+
},
|
|
12951
|
+
to_Iterator(self) {
|
|
12952
|
+
return self[Symbol.iterator]();
|
|
12953
|
+
},
|
|
12954
|
+
sort(self, fn2) {
|
|
12955
|
+
const out = self.slice();
|
|
12956
|
+
out.sort((left, right) => Number(fn2(left, right)) || 0);
|
|
12957
|
+
return makeArray(out);
|
|
12958
|
+
},
|
|
12959
|
+
sortstr(self) {
|
|
12960
|
+
return makeArray(self.slice().sort(stringSortComparator));
|
|
12961
|
+
},
|
|
12962
|
+
sortnum(self) {
|
|
12963
|
+
return makeArray(
|
|
12964
|
+
self.map((item) => Number(item)).sort((a, b) => a - b)
|
|
12965
|
+
);
|
|
12966
|
+
},
|
|
12967
|
+
reverse(self) {
|
|
12968
|
+
return makeArray(self.slice().reverse());
|
|
12969
|
+
},
|
|
12970
|
+
sum(self) {
|
|
12971
|
+
return self.reduce((a, b) => Number(a) + Number(b), 0);
|
|
12972
|
+
},
|
|
12973
|
+
product(self) {
|
|
12974
|
+
return self.reduce((a, b) => Number(a) * Number(b), 1);
|
|
12975
|
+
},
|
|
12976
|
+
shuffle(self) {
|
|
12977
|
+
arrayMethodArity("Array.shuffle", arguments.length, 0);
|
|
12978
|
+
return makeArray(shuffledArrayValues(self));
|
|
12979
|
+
},
|
|
12980
|
+
sample(self, n = 1) {
|
|
12981
|
+
arrayMethodArity("Array.sample", arguments.length, 0, 1);
|
|
12982
|
+
return makeArray(
|
|
12983
|
+
shuffledArrayValues(self).slice(0, Math.max(0, Number(n) || 0))
|
|
12984
|
+
);
|
|
12985
|
+
},
|
|
12986
|
+
contains(self, value) {
|
|
12987
|
+
return self.includes(value) ? 1 : 0;
|
|
12988
|
+
},
|
|
12989
|
+
map(self, fn2) {
|
|
12990
|
+
arrayMethodArity("Array.map", arguments.length, 1);
|
|
12991
|
+
return makeArray(self.map((value) => fn2(value)));
|
|
12992
|
+
},
|
|
12993
|
+
grep(self, fn2) {
|
|
12994
|
+
arrayMethodArity("Array.grep", arguments.length, 1);
|
|
12995
|
+
return makeArray(self.filter((value) => fn2(value)));
|
|
12996
|
+
},
|
|
12997
|
+
any(self, fn2) {
|
|
12998
|
+
arrayMethodArity("Array.any", arguments.length, 1);
|
|
12999
|
+
return self.some((value) => fn2(value)) ? 1 : 0;
|
|
13000
|
+
},
|
|
13001
|
+
all(self, fn2) {
|
|
13002
|
+
arrayMethodArity("Array.all", arguments.length, 1);
|
|
13003
|
+
return self.every((value) => fn2(value)) ? 1 : 0;
|
|
13004
|
+
},
|
|
13005
|
+
first(self, fn2) {
|
|
13006
|
+
arrayMethodArity("Array.first", arguments.length, 1);
|
|
13007
|
+
for (const value of self) {
|
|
13008
|
+
if (fn2(value)) {
|
|
13009
|
+
return value;
|
|
13010
|
+
}
|
|
13011
|
+
}
|
|
13012
|
+
return null;
|
|
13013
|
+
},
|
|
13014
|
+
remove(self, fn2) {
|
|
13015
|
+
for (let idx = self.length - 1; idx >= 0; idx--) {
|
|
13016
|
+
if (fn2(self[idx])) {
|
|
13017
|
+
releaseCollectionValue(self, self[idx]);
|
|
13018
|
+
self.splice(idx, 1);
|
|
13019
|
+
}
|
|
13020
|
+
}
|
|
13021
|
+
return self;
|
|
13022
|
+
},
|
|
13023
|
+
first_index(self, fn2) {
|
|
13024
|
+
for (let idx = 0; idx < self.length; idx++) {
|
|
13025
|
+
if (fn2(self[idx])) {
|
|
13026
|
+
return idx;
|
|
13027
|
+
}
|
|
13028
|
+
}
|
|
13029
|
+
return -1;
|
|
13030
|
+
},
|
|
13031
|
+
for_each_value(self, fn2) {
|
|
13032
|
+
for (const value of self) {
|
|
13033
|
+
fn2(value);
|
|
13034
|
+
}
|
|
13035
|
+
return self;
|
|
13036
|
+
},
|
|
13037
|
+
reduce(self, fn2) {
|
|
13038
|
+
if (self.length === 0) {
|
|
13039
|
+
return null;
|
|
13040
|
+
}
|
|
13041
|
+
let acc = self[0];
|
|
13042
|
+
for (let idx = 1; idx < self.length; idx++) {
|
|
13043
|
+
acc = fn2(acc, self[idx]);
|
|
13044
|
+
}
|
|
13045
|
+
return acc;
|
|
13046
|
+
},
|
|
13047
|
+
reductions(self, fn2) {
|
|
13048
|
+
if (self.length === 0) {
|
|
13049
|
+
return makeArray([]);
|
|
13050
|
+
}
|
|
13051
|
+
const out = [self[0]];
|
|
13052
|
+
for (let idx = 1; idx < self.length; idx++) {
|
|
13053
|
+
out.push(fn2(out[out.length - 1], self[idx]));
|
|
13054
|
+
}
|
|
13055
|
+
return makeArray(out);
|
|
13056
|
+
}
|
|
13057
|
+
});
|
|
13058
|
+
var ARRAY_ZERO_ARG_METHODS = /* @__PURE__ */ new Set([
|
|
13059
|
+
"copy",
|
|
13060
|
+
"count",
|
|
13061
|
+
"empty",
|
|
13062
|
+
"is_empty",
|
|
13063
|
+
"length",
|
|
13064
|
+
"pop",
|
|
13065
|
+
"reverse",
|
|
13066
|
+
"shift",
|
|
13067
|
+
"shuffle",
|
|
13068
|
+
"sortnum",
|
|
13069
|
+
"sortstr",
|
|
13070
|
+
"to_Array",
|
|
13071
|
+
"to_Bag",
|
|
13072
|
+
"to_Iterator",
|
|
13073
|
+
"to_Set"
|
|
13074
|
+
]);
|
|
13075
|
+
function getArrayMethod(object, property) {
|
|
13076
|
+
if (typeof property === "symbol") {
|
|
13077
|
+
return null;
|
|
13078
|
+
}
|
|
13079
|
+
const name2 = String(property);
|
|
13080
|
+
if (!Array.isArray(object) || !Object.prototype.hasOwnProperty.call(ARRAY_METHODS, name2)) {
|
|
13081
|
+
return null;
|
|
13082
|
+
}
|
|
13083
|
+
return function zuzuArrayMethod(...args) {
|
|
13084
|
+
return ARRAY_METHODS[name2](object, ...args);
|
|
13085
|
+
};
|
|
13086
|
+
}
|
|
13087
|
+
var SET_METHODS = Object.freeze({
|
|
13088
|
+
add_weak(self, ...values) {
|
|
13089
|
+
for (const value of values) {
|
|
13090
|
+
self.add(makeWeakValue(value));
|
|
13091
|
+
}
|
|
13092
|
+
return self;
|
|
13093
|
+
},
|
|
13094
|
+
push_weak(self, ...values) {
|
|
13095
|
+
return SET_METHODS.add_weak(self, ...values);
|
|
13096
|
+
},
|
|
13097
|
+
clear(self) {
|
|
13098
|
+
releaseCollectionValues(self);
|
|
13099
|
+
Set.prototype.clear.call(self);
|
|
13100
|
+
return self;
|
|
13101
|
+
}
|
|
13102
|
+
});
|
|
13103
|
+
var SET_ZERO_ARG_METHODS = /* @__PURE__ */ new Set(["clear"]);
|
|
13104
|
+
function getSetMethod(object, property) {
|
|
13105
|
+
if (typeof property === "symbol") {
|
|
13106
|
+
return null;
|
|
13107
|
+
}
|
|
13108
|
+
const name2 = String(property);
|
|
13109
|
+
if (!isSetLike(object) || !Object.prototype.hasOwnProperty.call(SET_METHODS, name2)) {
|
|
13110
|
+
return null;
|
|
13111
|
+
}
|
|
13112
|
+
return function zuzuSetMethod(...args) {
|
|
13113
|
+
return SET_METHODS[name2](object, ...args);
|
|
13114
|
+
};
|
|
13115
|
+
}
|
|
13116
|
+
function dictSortedKeys(self) {
|
|
13117
|
+
return isDictMethodReceiver(self) ? Object.keys(self).sort() : [];
|
|
13118
|
+
}
|
|
12331
13119
|
var DICT_METHODS = Object.freeze({
|
|
12332
13120
|
length(self) {
|
|
12333
13121
|
return isDictMethodReceiver(self) ? Object.keys(self).length : 0;
|
|
12334
13122
|
},
|
|
12335
13123
|
keys(self) {
|
|
12336
|
-
return
|
|
13124
|
+
return makeSet(dictSortedKeys(self));
|
|
12337
13125
|
},
|
|
12338
13126
|
values(self) {
|
|
12339
13127
|
if (!isDictMethodReceiver(self)) {
|
|
12340
|
-
return [];
|
|
13128
|
+
return makeBag([]);
|
|
12341
13129
|
}
|
|
12342
|
-
return
|
|
13130
|
+
return makeBag(dictSortedKeys(self).map((key) => resolveWeakValue(self[key])));
|
|
12343
13131
|
},
|
|
12344
13132
|
copy(self) {
|
|
12345
13133
|
if (!isDictMethodReceiver(self)) {
|
|
@@ -12353,11 +13141,11 @@ ${cleanup}
|
|
|
12353
13141
|
},
|
|
12354
13142
|
enumerate(self) {
|
|
12355
13143
|
if (!isDictMethodReceiver(self)) {
|
|
12356
|
-
return [];
|
|
13144
|
+
return makeBag([]);
|
|
12357
13145
|
}
|
|
12358
|
-
return
|
|
13146
|
+
return makeBag(dictSortedKeys(self).map(
|
|
12359
13147
|
(key) => new Pair({ pair: [key, resolveWeakValue(self[key])] })
|
|
12360
|
-
);
|
|
13148
|
+
));
|
|
12361
13149
|
},
|
|
12362
13150
|
has(self, key) {
|
|
12363
13151
|
return isDictMethodReceiver(self) && Object.prototype.hasOwnProperty.call(self, normalizeDictKey(key)) ? 1 : 0;
|
|
@@ -12405,13 +13193,13 @@ ${cleanup}
|
|
|
12405
13193
|
return [];
|
|
12406
13194
|
}
|
|
12407
13195
|
const out = [];
|
|
12408
|
-
for (const key of
|
|
13196
|
+
for (const key of dictSortedKeys(self)) {
|
|
12409
13197
|
out.push(key, resolveWeakValue(self[key]));
|
|
12410
13198
|
}
|
|
12411
13199
|
return out;
|
|
12412
13200
|
},
|
|
12413
13201
|
sorted_keys(self) {
|
|
12414
|
-
return
|
|
13202
|
+
return dictSortedKeys(self);
|
|
12415
13203
|
},
|
|
12416
13204
|
remove(self, key) {
|
|
12417
13205
|
if (!isDictMethodReceiver(self)) {
|
|
@@ -12444,26 +13232,31 @@ ${cleanup}
|
|
|
12444
13232
|
return DICT_METHODS.empty(self);
|
|
12445
13233
|
},
|
|
12446
13234
|
to_Array(self) {
|
|
12447
|
-
|
|
13235
|
+
if (!isDictMethodReceiver(self)) {
|
|
13236
|
+
return [];
|
|
13237
|
+
}
|
|
13238
|
+
return makeArray(dictSortedKeys(self).map(
|
|
13239
|
+
(key) => new Pair({ pair: [key, resolveWeakValue(self[key])] })
|
|
13240
|
+
));
|
|
12448
13241
|
},
|
|
12449
13242
|
to_Iterator(self) {
|
|
12450
|
-
return
|
|
13243
|
+
return dictSortedKeys(self)[Symbol.iterator]();
|
|
12451
13244
|
},
|
|
12452
13245
|
for_each_key(self, fn2) {
|
|
12453
|
-
for (const key of
|
|
13246
|
+
for (const key of dictSortedKeys(self)) {
|
|
12454
13247
|
fn2(key);
|
|
12455
13248
|
}
|
|
12456
13249
|
return self;
|
|
12457
13250
|
},
|
|
12458
13251
|
for_each_value(self, fn2) {
|
|
12459
|
-
for (const
|
|
12460
|
-
fn2(
|
|
13252
|
+
for (const key of dictSortedKeys(self)) {
|
|
13253
|
+
fn2(resolveWeakValue(self[key]));
|
|
12461
13254
|
}
|
|
12462
13255
|
return self;
|
|
12463
13256
|
},
|
|
12464
13257
|
for_each_pair(self, fn2) {
|
|
12465
|
-
for (const
|
|
12466
|
-
fn2(pair);
|
|
13258
|
+
for (const key of dictSortedKeys(self)) {
|
|
13259
|
+
fn2(new Pair({ pair: [key, resolveWeakValue(self[key])] }));
|
|
12467
13260
|
}
|
|
12468
13261
|
return self;
|
|
12469
13262
|
},
|
|
@@ -12497,6 +13290,12 @@ ${cleanup}
|
|
|
12497
13290
|
return null;
|
|
12498
13291
|
}
|
|
12499
13292
|
const name2 = String(property);
|
|
13293
|
+
for (let proto = Object.getPrototypeOf(object); proto; proto = Object.getPrototypeOf(proto)) {
|
|
13294
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, name2);
|
|
13295
|
+
if (descriptor && typeof descriptor.value === "function") {
|
|
13296
|
+
return null;
|
|
13297
|
+
}
|
|
13298
|
+
}
|
|
12500
13299
|
if (!isDictMethodReceiver(object) || Object.prototype.hasOwnProperty.call(object, name2) || !Object.prototype.hasOwnProperty.call(DICT_METHODS, name2)) {
|
|
12501
13300
|
return null;
|
|
12502
13301
|
}
|
|
@@ -12536,8 +13335,8 @@ ${cleanup}
|
|
|
12536
13335
|
enumerable: false,
|
|
12537
13336
|
configurable: true
|
|
12538
13337
|
});
|
|
12539
|
-
bound.invoke = function invoke(
|
|
12540
|
-
return fn2.apply(
|
|
13338
|
+
bound.invoke = function invoke(self, args = []) {
|
|
13339
|
+
return fn2.apply(self, args);
|
|
12541
13340
|
};
|
|
12542
13341
|
bound.to_String = function to_String() {
|
|
12543
13342
|
return methodName;
|
|
@@ -12988,6 +13787,22 @@ ${cleanup}
|
|
|
12988
13787
|
if (object == null) {
|
|
12989
13788
|
return null;
|
|
12990
13789
|
}
|
|
13790
|
+
if (property !== "length") {
|
|
13791
|
+
const arrayMethod = getArrayMethod(object, property);
|
|
13792
|
+
if (arrayMethod && ARRAY_ZERO_ARG_METHODS.has(String(property))) {
|
|
13793
|
+
return arrayMethod();
|
|
13794
|
+
}
|
|
13795
|
+
if (arrayMethod) {
|
|
13796
|
+
return arrayMethod;
|
|
13797
|
+
}
|
|
13798
|
+
}
|
|
13799
|
+
const setMethod = getSetMethod(object, property);
|
|
13800
|
+
if (setMethod && SET_ZERO_ARG_METHODS.has(String(property))) {
|
|
13801
|
+
return setMethod();
|
|
13802
|
+
}
|
|
13803
|
+
if (setMethod) {
|
|
13804
|
+
return setMethod;
|
|
13805
|
+
}
|
|
12991
13806
|
const value = resolveWeakValue(object[property]);
|
|
12992
13807
|
if (typeof value === "function" && value.length === 0 && !value.__zuzu_marshal_meta) {
|
|
12993
13808
|
return value.call(object);
|
|
@@ -13020,6 +13835,18 @@ ${cleanup}
|
|
|
13020
13835
|
if (property instanceof ZuzuMethod || property && property.__zuzu_method) {
|
|
13021
13836
|
return property.invoke(object, args);
|
|
13022
13837
|
}
|
|
13838
|
+
const arrayMethod = getArrayMethod(object, property);
|
|
13839
|
+
if (arrayMethod) {
|
|
13840
|
+
return arrayMethod(...args);
|
|
13841
|
+
}
|
|
13842
|
+
const setMethod = getSetMethod(object, property);
|
|
13843
|
+
if (setMethod) {
|
|
13844
|
+
return setMethod(...args);
|
|
13845
|
+
}
|
|
13846
|
+
const dictMethod = getDictMethod(object, property);
|
|
13847
|
+
if (dictMethod) {
|
|
13848
|
+
return dictMethod(...args);
|
|
13849
|
+
}
|
|
13023
13850
|
const value = resolveWeakValue(object[property]);
|
|
13024
13851
|
if (typeof value === "function") {
|
|
13025
13852
|
return value.apply(object, args);
|
|
@@ -13032,10 +13859,6 @@ ${cleanup}
|
|
|
13032
13859
|
}
|
|
13033
13860
|
proto = Object.getPrototypeOf(proto);
|
|
13034
13861
|
}
|
|
13035
|
-
const dictMethod = getDictMethod(object, property);
|
|
13036
|
-
if (dictMethod) {
|
|
13037
|
-
return dictMethod(...args);
|
|
13038
|
-
}
|
|
13039
13862
|
throw new TypeError(`${String(property)} is not a function`);
|
|
13040
13863
|
}
|
|
13041
13864
|
function zuzuMaybeDemolish(value) {
|
|
@@ -13054,6 +13877,12 @@ ${cleanup}
|
|
|
13054
13877
|
return 0;
|
|
13055
13878
|
}
|
|
13056
13879
|
const key = String(methodName || "");
|
|
13880
|
+
if (getArrayMethod(value, key)) {
|
|
13881
|
+
return 1;
|
|
13882
|
+
}
|
|
13883
|
+
if (getSetMethod(value, key)) {
|
|
13884
|
+
return 1;
|
|
13885
|
+
}
|
|
13057
13886
|
if (getDictMethod(value, key)) {
|
|
13058
13887
|
return 1;
|
|
13059
13888
|
}
|
|
@@ -13488,14 +14317,19 @@ ${cleanup}
|
|
|
13488
14317
|
this.transpiler = normalizeTranspilerName(
|
|
13489
14318
|
options.transpiler || DEFAULT_TRANSPILER
|
|
13490
14319
|
);
|
|
14320
|
+
this.asyncImports = options.asyncImports === true;
|
|
13491
14321
|
if (typeof this.host.loadJsModule !== "function") {
|
|
13492
14322
|
this.host.loadJsModule = (filename) => __require(filename);
|
|
13493
14323
|
}
|
|
13494
14324
|
}
|
|
14325
|
+
usesAsyncImports() {
|
|
14326
|
+
return this.asyncImports || typeof this.host.hasAsyncModules === "function" && this.host.hasAsyncModules();
|
|
14327
|
+
}
|
|
13495
14328
|
transpile(source, options = {}) {
|
|
13496
14329
|
return transpile(source, {
|
|
13497
14330
|
...options,
|
|
13498
|
-
transpiler: options.transpiler || this.transpiler
|
|
14331
|
+
transpiler: options.transpiler || this.transpiler,
|
|
14332
|
+
asyncImports: options.asyncImports ?? this.usesAsyncImports()
|
|
13499
14333
|
});
|
|
13500
14334
|
}
|
|
13501
14335
|
getModuleSearchRoots() {
|
|
@@ -13834,6 +14668,12 @@ ${cleanup}
|
|
|
13834
14668
|
}
|
|
13835
14669
|
return this;
|
|
13836
14670
|
});
|
|
14671
|
+
defineRuntimeMethod(Set.prototype, "push_weak", function _pushWeakSet(...values) {
|
|
14672
|
+
for (const v of values) {
|
|
14673
|
+
this.add(makeWeakValue(v));
|
|
14674
|
+
}
|
|
14675
|
+
return this;
|
|
14676
|
+
});
|
|
13837
14677
|
defineRuntimeMethod(Set.prototype, "contains", function _containsSet(value) {
|
|
13838
14678
|
return contains(this, value);
|
|
13839
14679
|
});
|
|
@@ -13983,6 +14823,7 @@ ${cleanup}
|
|
|
13983
14823
|
__file__: this.fileValueForFilename(filename),
|
|
13984
14824
|
__zuzu_system_seed: systemGlobalSeed,
|
|
13985
14825
|
__zuzu_current_system: currentSystem,
|
|
14826
|
+
__zuzu_operator_string: zuzuOperatorString,
|
|
13986
14827
|
DEBUG: this.debugLevel,
|
|
13987
14828
|
__zuzu_host_capabilities: capabilityFlags,
|
|
13988
14829
|
has_capability(name2) {
|
|
@@ -14343,13 +15184,13 @@ ${cleanup}
|
|
|
14343
15184
|
return zuzuTruthy(value);
|
|
14344
15185
|
},
|
|
14345
15186
|
__zuzu_not(value) {
|
|
14346
|
-
return zuzuTruthy(value)
|
|
15187
|
+
return !zuzuTruthy(value);
|
|
14347
15188
|
},
|
|
14348
15189
|
__zuzu_and(left, right) {
|
|
14349
|
-
return zuzuTruthy(left) && zuzuTruthy(right)
|
|
15190
|
+
return zuzuTruthy(left) && zuzuTruthy(right);
|
|
14350
15191
|
},
|
|
14351
15192
|
__zuzu_or(left, right) {
|
|
14352
|
-
return zuzuTruthy(left) || zuzuTruthy(right)
|
|
15193
|
+
return zuzuTruthy(left) || zuzuTruthy(right);
|
|
14353
15194
|
},
|
|
14354
15195
|
__zuzu_typeof(value) {
|
|
14355
15196
|
return zuzuTypeof(value);
|
|
@@ -14599,10 +15440,10 @@ ${cleanup}
|
|
|
14599
15440
|
return zuzuMaybeDemolish(value);
|
|
14600
15441
|
},
|
|
14601
15442
|
__zuzu_xor(left, right) {
|
|
14602
|
-
return zuzuTruthy(left) !== zuzuTruthy(right)
|
|
15443
|
+
return zuzuTruthy(left) !== zuzuTruthy(right);
|
|
14603
15444
|
},
|
|
14604
15445
|
__zuzu_nand(left, right) {
|
|
14605
|
-
return zuzuTruthy(left) && zuzuTruthy(right)
|
|
15446
|
+
return !(zuzuTruthy(left) && zuzuTruthy(right));
|
|
14606
15447
|
},
|
|
14607
15448
|
__zuzu_num_eq(left, right) {
|
|
14608
15449
|
if (!isNumericComparable(left) || !isNumericComparable(right)) {
|
|
@@ -14708,6 +15549,9 @@ ${cleanup}
|
|
|
14708
15549
|
if (name2 === "std/eval") {
|
|
14709
15550
|
return { eval: context.__zuzu_native_eval };
|
|
14710
15551
|
}
|
|
15552
|
+
if (this.usesAsyncImports()) {
|
|
15553
|
+
return this.loadModuleAsync(name2, filename, context);
|
|
15554
|
+
}
|
|
14711
15555
|
return this.loadModule(name2, filename, context);
|
|
14712
15556
|
};
|
|
14713
15557
|
return context;
|
|
@@ -14784,6 +15628,41 @@ ${cleanup}
|
|
|
14784
15628
|
Object.defineProperty( proto, name, desc );
|
|
14785
15629
|
}
|
|
14786
15630
|
};
|
|
15631
|
+
if ( Array.prototype.join.__zuzu_array_join !== true ) {
|
|
15632
|
+
const __zuzu_native_array_join = Array.prototype.join;
|
|
15633
|
+
const joinDesc = Object.create( null );
|
|
15634
|
+
joinDesc.value = function _join( separator, fallback ) {
|
|
15635
|
+
const hasFallback = arguments.length > 1;
|
|
15636
|
+
let fallbackString;
|
|
15637
|
+
const sep = __zuzu_operator_string( separator );
|
|
15638
|
+
const out = [];
|
|
15639
|
+
for ( const value of this ) {
|
|
15640
|
+
try {
|
|
15641
|
+
out.push( __zuzu_operator_string( value ) );
|
|
15642
|
+
}
|
|
15643
|
+
catch ( err ) {
|
|
15644
|
+
if ( !hasFallback ) {
|
|
15645
|
+
throw err;
|
|
15646
|
+
}
|
|
15647
|
+
if ( typeof fallback === 'function' ) {
|
|
15648
|
+
out.push( __zuzu_operator_string( fallback( value ) ) );
|
|
15649
|
+
}
|
|
15650
|
+
else {
|
|
15651
|
+
if ( fallbackString === undefined ) {
|
|
15652
|
+
fallbackString = __zuzu_operator_string( fallback );
|
|
15653
|
+
}
|
|
15654
|
+
out.push( fallbackString );
|
|
15655
|
+
}
|
|
15656
|
+
}
|
|
15657
|
+
}
|
|
15658
|
+
return __zuzu_native_array_join.call( out, sep );
|
|
15659
|
+
};
|
|
15660
|
+
joinDesc.value.__zuzu_array_join = true;
|
|
15661
|
+
joinDesc.enumerable = false;
|
|
15662
|
+
joinDesc.configurable = true;
|
|
15663
|
+
joinDesc.writable = true;
|
|
15664
|
+
Object.defineProperty( Array.prototype, 'join', joinDesc );
|
|
15665
|
+
}
|
|
14787
15666
|
define( Array.prototype, 'length', function _length() { return this.length; } );
|
|
14788
15667
|
define( Array.prototype, 'count', function _count() { return this.length; } );
|
|
14789
15668
|
define( Array.prototype, 'empty', function _empty() { return this.length === 0 ? 1 : 0; } );
|
|
@@ -14826,6 +15705,7 @@ ${cleanup}
|
|
|
14826
15705
|
define( Set.prototype, 'is_empty', function _is_empty() { return this.empty(); } );
|
|
14827
15706
|
define( Set.prototype, 'push', function _push( ...values ) { for ( const v of values ) { __zuzu_add_set_value( this, v ); } return this; } );
|
|
14828
15707
|
define( Set.prototype, 'add_weak', function _add_weak( value ) { this.add( __zuzu_make_weak_value( value ) ); return this; } );
|
|
15708
|
+
define( Set.prototype, 'push_weak', function _push_weak( ...values ) { for ( const v of values ) { this.add( __zuzu_make_weak_value( v ) ); } return this; } );
|
|
14829
15709
|
define( Set.prototype, 'contains', function _contains( value ) { return __zuzu_contains( this, value ); } );
|
|
14830
15710
|
define( Set.prototype, 'remove', function _remove( value ) { const resolved = __zuzu_resolve_weak_value( value ); if ( this.delete( resolved ) ) { __zuzu_release_collection_value( this, resolved ); } return this; } );
|
|
14831
15711
|
define( Set.prototype, 'to_Array', function _to_array() { return __zuzu_array( this ); } );
|
|
@@ -15057,6 +15937,68 @@ ${exportBridge}
|
|
|
15057
15937
|
}
|
|
15058
15938
|
return moduleObj.exports;
|
|
15059
15939
|
}
|
|
15940
|
+
async loadModuleAsync(moduleName, fromFile, contextForPolicy = null) {
|
|
15941
|
+
if (/(^|\/)\.\.(\/|$)/.test(moduleName)) {
|
|
15942
|
+
throw new Error("Import module path cannot contain '..' segments");
|
|
15943
|
+
}
|
|
15944
|
+
this.enforceModulePolicy(moduleName);
|
|
15945
|
+
const resolved = this.resolveModulePath(moduleName, fromFile);
|
|
15946
|
+
const cacheable = moduleName !== "test/more" && this.evalCapabilityOverrides == null;
|
|
15947
|
+
if (cacheable && this.moduleCache.has(resolved)) {
|
|
15948
|
+
return this.moduleCache.get(resolved);
|
|
15949
|
+
}
|
|
15950
|
+
if (resolved.endsWith(".js")) {
|
|
15951
|
+
return this.loadModule(moduleName, fromFile, contextForPolicy);
|
|
15952
|
+
}
|
|
15953
|
+
if (this.moduleLoading.has(resolved)) {
|
|
15954
|
+
throw new Error("Circular module loading detected");
|
|
15955
|
+
}
|
|
15956
|
+
this.moduleLoading.add(resolved);
|
|
15957
|
+
try {
|
|
15958
|
+
const source = typeof this.host.readFileTextAsync === "function" ? await this.host.readFileTextAsync(resolved) : this.host.readFileText(resolved);
|
|
15959
|
+
let js = this.transpile(source, {
|
|
15960
|
+
asyncImports: true,
|
|
15961
|
+
deferAsyncWrapper: true
|
|
15962
|
+
});
|
|
15963
|
+
const exportNames = resolved.endsWith(".zzm") ? collectTopLevelDeclarations(source, stripPod) : [];
|
|
15964
|
+
let exportBridge = "";
|
|
15965
|
+
if (exportNames.length > 0) {
|
|
15966
|
+
exportBridge = exportNames.map((name2) => {
|
|
15967
|
+
if (name2.startsWith("_")) {
|
|
15968
|
+
return `if ( typeof ${name2} !== "undefined" ) { const __zuzu_desc = Object.create( null ); __zuzu_desc.get = function() { return ${name2}; }; __zuzu_desc.set = function( value ) { ${name2} = value; }; __zuzu_desc.enumerable = false; __zuzu_desc.configurable = true; Object.defineProperty( module.exports, ${JSON.stringify(name2)}, __zuzu_desc ); }`;
|
|
15969
|
+
}
|
|
15970
|
+
return `if ( typeof ${name2} !== "undefined" ) { const __zuzu_desc = Object.create( null ); __zuzu_desc.get = function() { return ${name2}; }; __zuzu_desc.set = function( value ) { ${name2} = value; }; __zuzu_desc.enumerable = true; __zuzu_desc.configurable = true; Object.defineProperty( module.exports, ${JSON.stringify(name2)}, __zuzu_desc ); }`;
|
|
15971
|
+
}).join("\n");
|
|
15972
|
+
}
|
|
15973
|
+
js = `( async () => {
|
|
15974
|
+
${js}
|
|
15975
|
+
${exportBridge}
|
|
15976
|
+
} )()`;
|
|
15977
|
+
setCompiledSource(resolved, js);
|
|
15978
|
+
const moduleObj = { exports: {} };
|
|
15979
|
+
const context = this.buildContext({
|
|
15980
|
+
exports: moduleObj.exports,
|
|
15981
|
+
module: moduleObj,
|
|
15982
|
+
filename: resolved
|
|
15983
|
+
});
|
|
15984
|
+
context.__global__ = /* @__PURE__ */ Object.create(null);
|
|
15985
|
+
this.installCollectionMethods(context);
|
|
15986
|
+
const moduleRunOptions = { filename: resolved };
|
|
15987
|
+
if (this.executionTimeoutMs != null) {
|
|
15988
|
+
moduleRunOptions.timeout = this.executionTimeoutMs;
|
|
15989
|
+
}
|
|
15990
|
+
const result = this.host.runInContext(js, context, moduleRunOptions);
|
|
15991
|
+
if (result && typeof result.then === "function") {
|
|
15992
|
+
await result;
|
|
15993
|
+
}
|
|
15994
|
+
if (cacheable) {
|
|
15995
|
+
this.moduleCache.set(resolved, moduleObj.exports);
|
|
15996
|
+
}
|
|
15997
|
+
return moduleObj.exports;
|
|
15998
|
+
} finally {
|
|
15999
|
+
this.moduleLoading.delete(resolved);
|
|
16000
|
+
}
|
|
16001
|
+
}
|
|
15060
16002
|
runSource(source, options = {}) {
|
|
15061
16003
|
const filename = options.filename || this.host.join(this.repoRoot, "<inline>.zzs");
|
|
15062
16004
|
let js;
|
|
@@ -15694,7 +16636,9 @@ ${" ".repeat(Math.max(0, caretColumn - 1))}^`;
|
|
|
15694
16636
|
const bindingName = marshalBindingName(preferredName || meta.name, id);
|
|
15695
16637
|
const captures = [];
|
|
15696
16638
|
const dependencies = [];
|
|
15697
|
-
for (const [name2, captured] of Object.entries(meta.captures || {}).sort(
|
|
16639
|
+
for (const [name2, captured] of Object.entries(meta.captures || {}).sort(
|
|
16640
|
+
(left, right) => left[0].localeCompare(right[0])
|
|
16641
|
+
)) {
|
|
15698
16642
|
if (isFunctionValue(captured)) {
|
|
15699
16643
|
dependencies.push([0, encodeFunctionCode(captured, state, name2)]);
|
|
15700
16644
|
} else if (isUserClassValue(captured)) {
|
|
@@ -40602,9 +41546,9 @@ ${lines.join("\n")}
|
|
|
40602
41546
|
}
|
|
40603
41547
|
});
|
|
40604
41548
|
|
|
40605
|
-
// ../../../../../tmp/zuzu-browser-build.
|
|
41549
|
+
// ../../../../../tmp/zuzu-browser-build.gMJDcc/browser-stdlib.generated.js
|
|
40606
41550
|
var require_browser_stdlib_generated = __commonJS({
|
|
40607
|
-
"../../../../../tmp/zuzu-browser-build.
|
|
41551
|
+
"../../../../../tmp/zuzu-browser-build.gMJDcc/browser-stdlib.generated.js"(exports2, module2) {
|
|
40608
41552
|
"use strict";
|
|
40609
41553
|
function createBrowserStdlib2() {
|
|
40610
41554
|
const jsModules = /* @__PURE__ */ Object.create(null);
|
|
@@ -40637,7 +41581,7 @@ ${lines.join("\n")}
|
|
|
40637
41581
|
virtualFiles["/modules/std/string/quoted_printable.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/string/quoted_printable - Quoted-printable encoders and decoders.\n\n=head1 SYNOPSIS\n\n from std/string/quoted_printable import encode, decode;\n\n let raw := to_binary( "Hello, world!\\r\\n" );\n\n let text := encode(raw);\n let bytes := decode(text);\n\n let binary_text := encode(raw, binary: true);\n let short_lines := encode(raw, line_length: 40, newline: "\\n");\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by all implementations of ZuzuScript.\n\n=head1 DESCRIPTION\n\nThis module provides quoted-printable encoding and decoding helpers for\nRFC 2045-style byte transport. Encoding returns ASCII C<String> text.\nDecoding returns a C<BinaryString>, because quoted-printable is a byte\ntransfer encoding rather than a Unicode text format.\n\nThe C<binary> option controls how input line break bytes are encoded.\nIn the default non-binary mode, CRLF, CR, and LF bytes are normalized to\nthe configured C<newline> string. In binary mode, CR and LF bytes are\nencoded as C<=0D> and C<=0A>.\n\n=head1 EXPORTS\n\n=head2 Functions\n\n=over\n\n=item * C<encode(BinaryString bytes, ... PairList options)>\n\nParameters: C<bytes> is binary input data and C<options> controls\nencoding. Returns: C<String>. Encodes C<bytes> as quoted-printable ASCII\ntext.\n\n=item * C<decode(String text, ... PairList options)>\n\nParameters: C<text> is quoted-printable text and C<options> controls\nstrictness. Returns: C<BinaryString>. Decodes quoted-printable text into\nbytes.\n\n=back\n\n=head1 OPTIONS\n\n=over\n\n=item * C<line_length>\n\nMaximum encoded line length. Defaults to C<76> and must be at least\nC<4>.\n\n=item * C<newline>\n\nOutput newline for hard line breaks and encoded soft breaks. Defaults\nto CRLF.\n\n=item * C<binary>\n\nWhen true, encode CR and LF bytes as C<=0D> and C<=0A>. Defaults to\nfalse.\n\n=item * C<strict>\n\nWhen true, malformed quoted-printable escape sequences throw during\ndecoding. Non-strict decoding preserves malformed escape text\nliterally.\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/string/quoted_printable >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\n\nlet encode := null;\nlet decode := null;\n\n{\n from std/string import chr, index, ord, substr;\n from std/string/base64 import\n encode as _base64_encode,\n decode as _base64_decode;\n\n let _B64_ALPHABET := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"\n _ "abcdefghijklmnopqrstuvwxyz0123456789+/";\n let _HEX := "0123456789ABCDEF";\n\n function _div_floor ( Number n, Number d ) {\n return floor( n / d );\n }\n\n function _mod ( Number n, Number d ) {\n return n - _div_floor( n, d ) * d;\n }\n\n function _bytes_to_binary ( Array bytes ) {\n let out := "";\n let i := 0;\n let n := bytes.length();\n\n while ( i < n ) {\n let b0 := bytes[i];\n let b1 := null;\n let b2 := null;\n if ( i + 1 < n ) {\n b1 := bytes[i + 1];\n }\n if ( i + 2 < n ) {\n b2 := bytes[i + 2];\n }\n\n let c0 := _div_floor( b0, 4 );\n let c1 := _mod( b0, 4 ) * 16;\n let c2 := 64;\n let c3 := 64;\n\n if ( not( b1 == null ) ) {\n c1 += _div_floor( b1, 16 );\n c2 := _mod( b1, 16 ) * 4;\n if ( not( b2 == null ) ) {\n c2 += _div_floor( b2, 64 );\n c3 := _mod( b2, 64 );\n }\n }\n\n out _= substr( _B64_ALPHABET, c0, 1 );\n out _= substr( _B64_ALPHABET, c1, 1 );\n out _= c2 == 64 ? "=" : substr( _B64_ALPHABET, c2, 1 );\n out _= c3 == 64 ? "=" : substr( _B64_ALPHABET, c3, 1 );\n i += 3;\n }\n\n return _base64_decode(out);\n }\n\n function _binary_to_bytes ( BinaryString raw ) {\n let b64 := _base64_encode(raw);\n let out := [];\n let i := 0;\n let n := length b64;\n\n while ( i < n ) {\n let c0 := index( _B64_ALPHABET, substr( b64, i, 1 ) );\n let c1 := index( _B64_ALPHABET, substr( b64, i + 1, 1 ) );\n let ch2 := substr( b64, i + 2, 1 );\n let ch3 := substr( b64, i + 3, 1 );\n let c2 := -1;\n let c3 := -1;\n if ( ch2 ne "=" ) {\n c2 := index( _B64_ALPHABET, ch2 );\n }\n if ( ch3 ne "=" ) {\n c3 := index( _B64_ALPHABET, ch3 );\n }\n\n out.push( c0 * 4 + _div_floor( c1, 16 ) );\n if ( c2 >= 0 ) {\n out.push( _mod( c1, 16 ) * 16 + _div_floor( c2, 4 ) );\n }\n if ( c3 >= 0 ) {\n out.push( _mod( c2, 4 ) * 64 + c3 );\n }\n\n i += 4;\n }\n\n return out;\n }\n\n function _parse_options ( PairList options ) {\n let line_length := 76;\n let newline := "\\r\\n";\n let binary := false;\n let strict := false;\n\n for ( let option in options.enumerate() ) {\n let key := option.key;\n let value := option.value;\n\n if ( key eq "line_length" ) {\n line_length := value;\n }\n else if ( key eq "newline" ) {\n newline := value;\n }\n else if ( key eq "binary" ) {\n binary := value;\n }\n else if ( key eq "strict" ) {\n strict := value;\n }\n else {\n die `quoted_printable option \'${key}\' is not supported`;\n }\n }\n\n if ( not( line_length instanceof Number ) ) {\n die "quoted_printable line_length option expects Number";\n }\n if ( line_length < 4 ) {\n die "quoted_printable line_length option must be at least 4";\n }\n if ( not( newline instanceof String ) ) {\n die "quoted_printable newline option expects String";\n }\n if ( not( binary instanceof Boolean ) ) {\n die "quoted_printable binary option expects Boolean";\n }\n if ( not( strict instanceof Boolean ) ) {\n die "quoted_printable strict option expects Boolean";\n }\n\n return {\n line_length: int(line_length),\n newline: newline,\n binary: binary,\n strict: strict,\n };\n }\n\n function _is_safe_literal ( Number b ) {\n return ( b >= 33 and b <= 60 ) or ( b >= 62 and b <= 126 );\n }\n\n function _byte_to_hex_token ( Number b ) {\n return "="\n _ substr( _HEX, _div_floor( b, 16 ), 1 )\n _ substr( _HEX, _mod( b, 16 ), 1 );\n }\n\n function _simple_token_length ( Number b, Boolean final_byte ) {\n if ( ( b == 9 or b == 32 ) and not final_byte ) {\n return 1;\n }\n if ( _is_safe_literal(b) ) {\n return 1;\n }\n return 3;\n }\n\n function _space_tab_needs_escape (\n Array bytes,\n Number i,\n Number column,\n Number line_length,\n ) {\n let n := bytes.length();\n if ( i + 1 >= n ) {\n return true;\n }\n\n let j := i + 1;\n while ( j < n and ( bytes[j] == 9 or bytes[j] == 32 ) ) {\n j++;\n }\n if ( j >= n ) {\n return true;\n }\n\n let next_is_final := i + 2 >= n;\n let next_len := _simple_token_length( bytes[i + 1], next_is_final );\n let max := next_is_final ? line_length : line_length - 1;\n return column + 1 + next_len > max;\n }\n\n function _token_for_byte (\n Array bytes,\n Number i,\n Number column,\n Number line_length,\n ) {\n let b := bytes[i];\n\n if ( b == 9 or b == 32 ) {\n if ( _space_tab_needs_escape( bytes, i, column, line_length ) ) {\n return _byte_to_hex_token(b);\n }\n return chr(b);\n }\n\n if ( _is_safe_literal(b) ) {\n return chr(b);\n }\n\n return _byte_to_hex_token(b);\n }\n\n function _emit_token (\n String out,\n Number column,\n String token,\n Boolean more_after,\n Number line_length,\n String newline,\n ) {\n let max := more_after ? line_length - 1 : line_length;\n let updated_out := out;\n let updated_column := column;\n\n if ( updated_column > 0 and updated_column + ( length token ) > max ) {\n updated_out _= "=" _ newline;\n updated_column := 0;\n }\n\n updated_out _= token;\n updated_column += length token;\n\n return [ updated_out, updated_column ];\n }\n\n function _encode_segment (\n Array bytes,\n Number line_length,\n String newline,\n ) {\n let out := "";\n let column := 0;\n let i := 0;\n let n := bytes.length();\n\n while ( i < n ) {\n let token := _token_for_byte( bytes, i, column, line_length );\n let emitted := _emit_token(\n out,\n column,\n token,\n i + 1 < n,\n line_length,\n newline,\n );\n out := emitted[0];\n column := emitted[1];\n i++;\n }\n\n return out;\n }\n\n function _encode_text_bytes (\n Array bytes,\n Number line_length,\n String newline,\n ) {\n let out := "";\n let line := [];\n let i := 0;\n let n := bytes.length();\n\n while ( i < n ) {\n let b := bytes[i];\n if ( b == 13 or b == 10 ) {\n out _= _encode_segment( line, line_length, newline );\n out _= newline;\n line := [];\n\n if ( b == 13 and i + 1 < n and bytes[i + 1] == 10 ) {\n i++;\n }\n }\n else {\n line.push(b);\n }\n\n i++;\n }\n\n out _= _encode_segment( line, line_length, newline );\n return out;\n }\n\n function _hex_value ( String ch ) {\n let cp := ord(ch);\n if ( cp >= 48 and cp <= 57 ) {\n return cp - 48;\n }\n if ( cp >= 65 and cp <= 70 ) {\n return cp - 55;\n }\n if ( cp >= 97 and cp <= 102 ) {\n return cp - 87;\n }\n return -1;\n }\n\n function _decode_text_bytes ( String text, Boolean strict ) {\n let out := [];\n let i := 0;\n let n := length text;\n\n while ( i < n ) {\n let ch := substr( text, i, 1 );\n let cp := ord( text, i );\n\n if ( cp > 127 ) {\n die "quoted_printable.decode rejects non-ASCII input";\n }\n\n if ( ch eq "=" ) {\n if ( i + 1 >= n ) {\n die "malformed quoted-printable escape" if strict;\n out.push(61);\n i++;\n next;\n }\n\n let ch1 := substr( text, i + 1, 1 );\n if ( ch1 eq "\\r" ) {\n if ( i + 2 < n and substr( text, i + 2, 1 ) eq "\\n" ) {\n i += 3;\n }\n else {\n i += 2;\n }\n next;\n }\n if ( ch1 eq "\\n" ) {\n i += 2;\n next;\n }\n\n if ( i + 2 < n ) {\n let hi := _hex_value(ch1);\n let lo := _hex_value( substr( text, i + 2, 1 ) );\n if ( hi >= 0 and lo >= 0 ) {\n out.push( hi * 16 + lo );\n i += 3;\n next;\n }\n }\n\n die "malformed quoted-printable escape" if strict;\n out.push(61);\n i++;\n next;\n }\n\n out.push(cp);\n i++;\n }\n\n return out;\n }\n\n encode := function ( BinaryString bytes, ... PairList options ) {\n let opts := _parse_options(options);\n let raw := _binary_to_bytes(bytes);\n\n if ( opts{binary} ) {\n return _encode_segment(\n raw,\n opts{line_length},\n opts{newline},\n );\n }\n\n return _encode_text_bytes(\n raw,\n opts{line_length},\n opts{newline},\n );\n };\n\n decode := function ( String text, ... PairList options ) {\n let opts := _parse_options(options);\n return _bytes_to_binary( _decode_text_bytes( text, opts{strict} ) );\n };\n}\n';
|
|
40638
41582
|
virtualFiles["/modules/std/gui.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/gui - User-facing GUI constructor helpers.\n\n=head1 SYNOPSIS\n\n from std/gui import *;\n\n let w := Window(\n title: "Demo",\n VBox(\n Label( text: "Name:" ),\n Input( id: "name" ),\n Button( text: "OK", id: "submit" ),\n ),\n );\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by zuzu.pl, zuzu-rust, and zuzu-js on Electron.\nIt is not supported by zuzu-js on Node. It is partially supported by\nzuzu-js in the browser: core GUI and widget lifecycle coverage passes,\nbut filesystem-backed file and directory dialogue coverage is unsupported.\n\n=head1 DESCRIPTION\n\nThis module provides thin constructor helpers over C<std/gui/objects>.\nHost runtimes expose the shared widget, object tree, event, and window\nlifecycle APIs when GUI support is available. It also re-exports\nbackend-native file and directory dialogue hooks for C<std/gui/dialogue>.\n\nThe module exports C<EM>, the standard UI font height in logical\npixels, derived from C<std/gui/objects> metadata.\n\n=head1 EXPORTS\n\n=head2 Constants\n\n=over\n\n=item C<EM>\n\nType: C<Number>. Standard UI font height in logical pixels.\n\n=item C<GUI_XML_NS>\n\nType: C<String>. XML namespace URI used by GUI XML serialization and\nparsing.\n\n=back\n\n=head2 Functions\n\n=over\n\n=item C<< Window(... PairList p, Array c) >>, C<< VBox(... PairList p, Array c) >>, C<< HBox(... PairList p, Array c) >>, C<< Frame(... PairList p, Array c) >>\n\nParameters: C<p> are widget properties and C<c> contains child widgets.\nReturns: widget object. Constructs window and layout widgets.\n\n=item C<< Label(... PairList p, Array c) >>, C<< Text(... PairList p, Array c) >>, C<< RichText(... PairList p, Array c) >>, C<< Image(... PairList p, Array c) >>\n\nParameters: C<p> are widget properties and C<c> contains child widgets.\nReturns: widget object. Constructs content widgets.\n\n=item C<< Input(... PairList p, Array c) >>, C<< DatePicker(... PairList p, Array c) >>, C<< Checkbox(... PairList p, Array c) >>, C<< Radio(... PairList p, Array c) >>, C<< RadioGroup(... PairList p, Array c) >>, C<< Select(... PairList p, Array c) >>\n\nParameters: C<p> are widget properties and C<c> contains child widgets.\nReturns: widget object. Constructs input widgets.\n\n=item C<< Menu(... PairList p, Array c) >>, C<< MenuItem(... PairList p, Array c) >>, C<< Button(... PairList p, Array c) >>, C<< Separator(... PairList p, Array c) >>, C<< Slider(... PairList p, Array c) >>, C<< Progress(... PairList p, Array c) >>\n\nParameters: C<p> are widget properties and C<c> contains child widgets.\nReturns: widget object. Constructs command and control widgets.\n\n=item C<< Tabs(... PairList p, Array c) >>, C<< Tab(... PairList p, Array c) >>, C<< ListView(... PairList p, Array c) >>, C<< TreeView(... PairList p, Array c) >>\n\nParameters: C<p> are widget properties and C<c> contains child widgets.\nReturns: widget object. Constructs tabular and collection widgets.\n\n=item C<< unbind(BindingToken token) >>\n\nParameters: C<token> is a binding token. Returns: C<null>. Removes a GUI\nbinding.\n\n=item C<< gui_from_xml(String xml) >>, C<< gui_from_xml_file(path) >>\n\nParameters: C<xml> is GUI XML text and C<path> is a file path. Returns:\nwidget object. Builds a GUI object tree from XML.\n\n=item C<< gui_to_xml(Widget root) >>\n\nParameters: C<root> is a GUI widget. Returns: C<String>. Serializes a\nGUI object tree to XML.\n\n=back\n\n=head2 Classes\n\n=over\n\n=item C<BindingToken>\n\nRepresents a model/widget binding.\n\n=over\n\n=item C<< token.is_active() >>\n\nParameters: none. Returns: C<Boolean>. Returns true while the binding is\nactive.\n\n=item C<< token.set_listener(token) >>\n\nParameters: C<token> is a listener token. Returns: C<BindingToken>.\nStores the listener token associated with the binding.\n\n=item C<< token.sync_model_to_widget() >>, C<< token.sync_widget_to_model() >>\n\nParameters: none. Returns: C<null>. Synchronizes the bound values.\n\n=item C<< token.unbind() >>\n\nParameters: none. Returns: C<null>. Removes the binding.\n\n=back\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/gui >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nfrom std/gui/objects import\n Window as _WindowClass,\n VBox as _VBoxClass,\n HBox as _HBoxClass,\n Frame as _FrameClass,\n Label as _LabelClass,\n Text as _TextClass,\n RichText as _RichTextClass,\n Image as _ImageClass,\n Input as _InputClass,\n DatePicker as _DatePickerClass,\n Checkbox as _CheckboxClass,\n Radio as _RadioClass,\n RadioGroup as _RadioGroupClass,\n Select as _SelectClass,\n Menu as _MenuClass,\n MenuItem as _MenuItemClass,\n Button as _ButtonClass,\n Separator as _SeparatorClass,\n Slider as _SliderClass,\n Progress as _ProgressClass,\n Tabs as _TabsClass,\n Tab as _TabClass,\n ListView as _ListViewClass,\n TreeView as _TreeViewClass,\n Widget,\n Event,\n ListenerToken,\n native_file_open,\n native_file_save,\n native_directory_open,\n native_directory_save,\n native_colour_picker,\n meta as _gui_meta;\n\nfrom std/gui/objects try import\n native_alert,\n native_confirm,\n native_prompt;\n\nfrom std/data/xml import XML;\nfrom std/data/xml/escape import escape_xml;\nfrom std/internals import getupperprop;\nfrom std/path/zz import ZZPath;\nfrom std/string import join, split, substr, trim;\n\n\nconst Number EM := _gui_meta{font_size_pixels};\n\nfunction _assert_known_props ( String ctor, PairList props, Array allowed ) {\n let geometry := [\n "width",\n "height",\n "minwidth",\n "minheight",\n "maxwidth",\n "maxheight",\n ];\n for ( let key in props.keys() ) {\n if ( key \u2209 allowed and key \u2209 geometry ) {\n die `GUI_PROP_UNKNOWN: ${ctor} does not accept property \'${key}\'`;\n }\n }\n}\n\nfunction _assert_prop_value ( String ctor, String prop, value, Array allowed ) {\n if ( value \u2209 allowed ) {\n die `GUI_PROP_TYPE: ${ctor} property \'${prop}\' has invalid value`;\n }\n}\n\nfunction _assert_prop_array ( String ctor, String prop, value ) {\n if ( not( value instanceof Array ) ) {\n die `GUI_PROP_TYPE: ${ctor} property \'${prop}\' expects Array`;\n }\n}\n\nfunction _with_geometry_props ( Array allowed ) {\n for ( let key in [\n "width",\n "height",\n "minwidth",\n "minheight",\n "maxwidth",\n "maxheight",\n ] ) {\n allowed.push(key) unless key \u2208 allowed;\n }\n return allowed;\n}\n\nfunction _apply_geometry ( Widget widget, PairList p ) {\n for ( let key in [\n "width",\n "height",\n "minwidth",\n "minheight",\n "maxwidth",\n "maxheight",\n ] ) {\n if ( p.has(key) ) {\n widget.(key)( p.get(key) );\n }\n }\n return widget;\n}\n\nfunction Window ( ... PairList p, Array c ) {\n _assert_known_props(\n "Window",\n p,\n _with_geometry_props( [\n "id",\n "title",\n "width",\n "height",\n "resizable",\n "modal",\n "visible",\n "enabled",\n "disabled",\n ] ),\n );\n\n return new _WindowClass(\n id: p.get( "id", null ),\n title: p.get( "title", "" ),\n width: p.get( "width", 800 ),\n height: p.get( "height", 600 ),\n minwidth: p.get( "minwidth", null ),\n minheight: p.get( "minheight", null ),\n maxwidth: p.get( "maxwidth", null ),\n maxheight: p.get( "maxheight", null ),\n resizable: p.get( "resizable", true ),\n modal: p.get( "modal", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n );\n}\n\nfunction VBox ( ... PairList p, Array c ) {\n _assert_known_props(\n "VBox",\n p,\n [\n "id",\n "align",\n "gap",\n "padding",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n _assert_prop_value(\n "VBox",\n "align",\n p.get( "align", "top" ),\n [ "top", "centre", "bottom", "stretch" ],\n );\n\n return _apply_geometry( new _VBoxClass(\n id: p.get( "id", null ),\n align: p.get( "align", "top" ),\n gap: p.get( "gap", 0 ),\n padding: p.get( "padding", 0 ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction HBox ( ... PairList p, Array c ) {\n _assert_known_props(\n "HBox",\n p,\n _with_geometry_props( [\n "id",\n "align",\n "gap",\n "padding",\n "visible",\n "enabled",\n "disabled",\n ] ),\n );\n\n _assert_prop_value(\n "HBox",\n "align",\n p.get( "align", "left" ),\n [ "left", "centre", "right", "stretch" ],\n );\n\n return new _HBoxClass(\n id: p.get( "id", null ),\n align: p.get( "align", "left" ),\n gap: p.get( "gap", 0 ),\n padding: p.get( "padding", 0 ),\n width: p.get( "width", null ),\n height: p.get( "height", null ),\n minwidth: p.get( "minwidth", null ),\n minheight: p.get( "minheight", null ),\n maxwidth: p.get( "maxwidth", null ),\n maxheight: p.get( "maxheight", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n );\n}\n\nfunction Frame ( ... PairList p, Array c ) {\n _assert_known_props(\n "Frame",\n p,\n [\n "id",\n "label",\n "collapsible",\n "collapsed",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _FrameClass(\n id: p.get( "id", null ),\n label: p.get( "label", "" ),\n collapsible: p.get( "collapsible", false ),\n collapsed: p.get( "collapsed", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Label ( ... PairList p, Array c ) {\n _assert_known_props(\n "Label",\n p,\n [ "id", "text", "for", "visible", "enabled", "disabled" ],\n );\n\n let label := new _LabelClass(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n );\n if ( p.has("for") ) {\n label.set_for_id( p.get( "for", null ) );\n }\n\n return _apply_geometry( label, p );\n}\n\nfunction Text ( ... PairList p, Array c ) {\n _assert_known_props(\n "Text",\n p,\n [\n "id",\n "value",\n "multiline",\n "readonly",\n "wrap",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _TextClass(\n id: p.get( "id", null ),\n value: p.get( "value", "" ),\n multiline: p.get( "multiline", false ),\n readonly: p.get( "readonly", false ),\n wrap: p.get( "wrap", true ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction RichText ( ... PairList p, Array c ) {\n _assert_known_props(\n "RichText",\n p,\n [\n "id",\n "value",\n "multiline",\n "readonly",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _RichTextClass(\n id: p.get( "id", null ),\n value: p.get( "value", "" ),\n multiline: p.get( "multiline", true ),\n readonly: p.get( "readonly", true ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Image ( ... PairList p, Array c ) {\n _assert_known_props(\n "Image",\n p,\n [ "id", "src", "alt", "fit", "visible", "enabled", "disabled" ],\n );\n\n _assert_prop_value(\n "Image",\n "fit",\n p.get( "fit", "none" ),\n [ "none", "contain", "cover", "stretch" ],\n );\n\n return _apply_geometry( new _ImageClass(\n id: p.get( "id", null ),\n src: p.get( "src", "" ),\n alt: p.get( "alt", "" ),\n fit: p.get( "fit", "none" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Input ( ... PairList p, Array c ) {\n _assert_known_props(\n "Input",\n p,\n [\n "id",\n "value",\n "placeholder",\n "multiline",\n "readonly",\n "password",\n "required",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _InputClass(\n id: p.get( "id", null ),\n value: p.get( "value", "" ),\n placeholder: p.get( "placeholder", "" ),\n multiline: p.get( "multiline", false ),\n readonly: p.get( "readonly", false ),\n password: p.get( "password", false ),\n required: p.get( "required", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction DatePicker ( ... PairList p, Array c ) {\n _assert_known_props(\n "DatePicker",\n p,\n [\n "id",\n "value",\n "min",\n "max",\n "first_day_of_week",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _DatePickerClass(\n id: p.get( "id", null ),\n value: p.get( "value", null ),\n min: p.get( "min", null ),\n max: p.get( "max", null ),\n first_day_of_week: p.get( "first_day_of_week", 0 ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Checkbox ( ... PairList p, Array c ) {\n _assert_known_props(\n "Checkbox",\n p,\n [\n "id",\n "label",\n "checked",\n "indeterminate",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _CheckboxClass(\n id: p.get( "id", null ),\n label: p.get( "label", "" ),\n checked: p.get( "checked", false ),\n indeterminate: p.get( "indeterminate", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Radio ( ... PairList p, Array c ) {\n _assert_known_props(\n "Radio",\n p,\n [\n "id",\n "label",\n "value",\n "group",\n "checked",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _RadioClass(\n id: p.get( "id", null ),\n label: p.get( "label", "" ),\n value: p.get( "value", "" ),\n group: p.get( "group", null ),\n checked: p.get( "checked", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction RadioGroup ( ... PairList p, Array c ) {\n _assert_known_props(\n "RadioGroup",\n p,\n [\n "id",\n "name",\n "value",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _RadioGroupClass(\n id: p.get( "id", null ),\n name: p.get( "name", "" ),\n value: p.get( "value", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Select ( ... PairList p, Array c ) {\n _assert_known_props(\n "Select",\n p,\n [\n "id",\n "value",\n "options",\n "multiple",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n if ( p.has("options") ) {\n _assert_prop_array( "Select", "options", p.get("options") );\n }\n\n return _apply_geometry( new _SelectClass(\n id: p.get( "id", null ),\n value: p.get( "value", null ),\n options: p.get( "options", [] ),\n multiple: p.get( "multiple", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Menu ( ... PairList p, Array c ) {\n _assert_known_props(\n "Menu",\n p,\n [ "id", "text", "visible", "enabled", "disabled" ],\n );\n\n return _apply_geometry( new _MenuClass(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction MenuItem ( ... PairList p, Array c ) {\n _assert_known_props(\n "MenuItem",\n p,\n [ "id", "text", "disabled", "visible", "enabled" ],\n );\n\n return _apply_geometry( new _MenuItemClass(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Button ( ... PairList p, Array c ) {\n _assert_known_props(\n "Button",\n p,\n _with_geometry_props( [\n "id",\n "text",\n "variant",\n "visible",\n "enabled",\n "disabled",\n ] ),\n );\n\n _assert_prop_value(\n "Button",\n "variant",\n p.get( "variant", "default" ),\n [ "default", "primary", "danger" ],\n );\n\n return new _ButtonClass(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n variant: p.get( "variant", "default" ),\n width: p.get( "width", null ),\n height: p.get( "height", null ),\n minwidth: p.get( "minwidth", null ),\n minheight: p.get( "minheight", null ),\n maxwidth: p.get( "maxwidth", null ),\n maxheight: p.get( "maxheight", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n );\n}\n\nfunction Separator ( ... PairList p, Array c ) {\n _assert_known_props(\n "Separator",\n p,\n [ "id", "orientation", "visible", "enabled", "disabled" ],\n );\n\n _assert_prop_value(\n "Separator",\n "orientation",\n p.get( "orientation", "horizontal" ),\n [ "horizontal", "vertical" ],\n );\n\n return _apply_geometry( new _SeparatorClass(\n id: p.get( "id", null ),\n orientation: p.get( "orientation", "horizontal" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Slider ( ... PairList p, Array c ) {\n _assert_known_props(\n "Slider",\n p,\n [\n "id",\n "value",\n "min",\n "max",\n "step",\n "orientation",\n "readonly",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n _assert_prop_value(\n "Slider",\n "orientation",\n p.get( "orientation", "horizontal" ),\n [ "horizontal", "vertical" ],\n );\n\n return _apply_geometry( new _SliderClass(\n id: p.get( "id", null ),\n value: p.get( "value", 0 ),\n min: p.get( "min", 0 ),\n max: p.get( "max", 100 ),\n step: p.get( "step", 1 ),\n orientation: p.get( "orientation", "horizontal" ),\n readonly: p.get( "readonly", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Progress ( ... PairList p, Array c ) {\n _assert_known_props(\n "Progress",\n p,\n [\n "id",\n "value",\n "min",\n "max",\n "indeterminate",\n "show_text",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _ProgressClass(\n id: p.get( "id", null ),\n value: p.get( "value", 0 ),\n min: p.get( "min", 0 ),\n max: p.get( "max", 100 ),\n indeterminate: p.get( "indeterminate", false ),\n show_text: p.get( "show_text", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Tabs ( ... PairList p, Array c ) {\n _assert_known_props(\n "Tabs",\n p,\n [\n "id",\n "selected",\n "placement",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n _assert_prop_value(\n "Tabs",\n "placement",\n p.get( "placement", "top" ),\n [ "top", "bottom", "left", "right" ],\n );\n\n return _apply_geometry( new _TabsClass(\n id: p.get( "id", null ),\n selected: p.get( "selected", null ),\n placement: p.get( "placement", "top" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Tab ( ... PairList p, Array c ) {\n _assert_known_props(\n "Tab",\n p,\n [\n "id",\n "title",\n "value",\n "selected",\n "closable",\n "icon",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _TabClass(\n id: p.get( "id", null ),\n title: p.get( "title", "" ),\n value: p.get( "value", "" ),\n selected: p.get( "selected", false ),\n closable: p.get( "closable", false ),\n icon: p.get( "icon", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction ListView ( ... PairList p, Array c ) {\n _assert_known_props(\n "ListView",\n p,\n [\n "id",\n "items",\n "selected_index",\n "multiple",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n if ( p.has("items") ) {\n _assert_prop_array( "ListView", "items", p.get("items") );\n }\n\n return _apply_geometry( new _ListViewClass(\n id: p.get( "id", null ),\n items: p.get( "items", [] ),\n selected_index: p.get( "selected_index", null ),\n multiple: p.get( "multiple", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction TreeView ( ... PairList p, Array c ) {\n _assert_known_props(\n "TreeView",\n p,\n [\n "id",\n "items",\n "selected_path",\n "multiple",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n if ( p.has("items") ) {\n _assert_prop_array( "TreeView", "items", p.get("items") );\n }\n if ( p.has("selected_path") ) {\n _assert_prop_array( "TreeView", "selected_path", p.get("selected_path") );\n }\n\n return _apply_geometry( new _TreeViewClass(\n id: p.get( "id", null ),\n items: p.get( "items", [] ),\n selected_path: p.get( "selected_path", [] ),\n multiple: p.get( "multiple", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction _binding_path_class ( path_class ) {\n if ( path_class \u2261 null ) {\n return ZZPath;\n }\n if ( not( path_class instanceof Class ) ) {\n die "GUI_BIND_PATH: paths special property must be Class or null";\n }\n return path_class;\n}\n\nfunction _binding_compile_path ( String path_text, path_class ) {\n if ( path_class \u2261 null ) {\n try {\n return new ZZPath( path: path_text );\n }\n catch ( Exception e ) {\n die `GUI_BIND_PATH: ${e{message}}`;\n }\n }\n\n let path_type := _binding_path_class(path_class);\n try {\n return new path_type( path: path_text );\n }\n catch ( Exception e ) {\n die `GUI_BIND_PATH: ${e{message}}`;\n }\n}\n\nfunction _binding_path ( pathish, path_class ) {\n if ( pathish instanceof String ) {\n return _binding_compile_path( pathish, path_class );\n }\n if (\n pathish can first\n and ( pathish can assign_first or pathish can ref_first )\n ) {\n return pathish;\n }\n\n die "GUI_BIND_PATH: binding path must be String or path-like Object";\n}\n\nfunction _binding_get ( model, path ) {\n return path.first( model, null );\n}\n\nfunction _binding_set ( model, path, value ) {\n if ( path can assign_first ) {\n return path.assign_first( model, value );\n }\n\n let ref := path.ref_first(model);\n return ref(value);\n}\n\nclass BindingToken {\n let Widget widget but weak;\n let String widget_prop;\n let model;\n let model_path;\n let String event := "change";\n let listener := null;\n let Boolean _active := true;\n\n method is_active () {\n return _active;\n }\n\n method set_listener ( token ) {\n listener := token;\n return self;\n }\n\n method sync_model_to_widget () {\n widget.(widget_prop)( _binding_get( model, model_path ) );\n return self;\n }\n\n method sync_widget_to_model () {\n _binding_set( model, model_path, widget.(widget_prop)() );\n return self;\n }\n\n method unbind () {\n if ( _active and listener \u2262 null ) {\n widget.off(listener);\n }\n _active := false;\n return self;\n }\n}\n\nfunction bind (\n Widget widget,\n String widget_prop,\n model,\n model_path,\n ... PairList p\n) {\n let path := _binding_path( model_path, getupperprop( 1, "paths" ) );\n\n let token := new BindingToken(\n widget: widget,\n widget_prop: widget_prop,\n model: model,\n model_path: path,\n event: p.get( "event", "change" ),\n );\n let event_name := p.get( "event", "change" );\n\n switch ( p.get( "initial", "model" ): eq ) {\n case "model":\n token.sync_model_to_widget();\n case "widget":\n token.sync_widget_to_model();\n case "none":\n // No initial sync.\n default:\n die "GUI_BIND_INITIAL: initial must be model, widget, or none";\n }\n\n token.set_listener(\n widget.on( event_name, function () {\n if ( token.is_active() ) {\n token.sync_widget_to_model();\n }\n } ),\n );\n return token;\n}\n\nfunction unbind ( BindingToken token ) {\n return token.unbind();\n}\n\nlet GUI_XML_NS := "https://zuzulang.org/ns/std/gui";\n\nfunction _xml_error ( String code, String message ) {\n die `${code}: ${message}`;\n}\n\nfunction _xml_tag_name ( node ) {\n return node.localName() ?: node.nodeName();\n}\n\nfunction _xml_assert_namespace ( node ) {\n let ns := node.namespaceURI();\n if ( ns \u2262 null and ns \u2262 "" and ns \u2262 GUI_XML_NS ) {\n _xml_error(\n "GUI_XML_STRUCTURE",\n `unsupported GUI XML namespace \'${ns}\'`,\n );\n }\n}\n\nfunction _xml_common_allowed ( Array extra ) {\n let out := [\n "id",\n "visible",\n "enabled",\n "disabled",\n "width",\n "height",\n "minwidth",\n "minheight",\n "maxwidth",\n "maxheight",\n ];\n for ( let attr in extra ) {\n out.push(attr);\n }\n return out;\n}\n\nfunction _xml_allowed_attrs ( String tag ) {\n switch ( tag: eq ) {\n case "Window":\n return _xml_common_allowed(\n [ "title", "width", "height", "resizable", "modal" ],\n );\n case "VBox", "HBox":\n return _xml_common_allowed( [ "align", "gap", "padding" ] );\n case "Frame":\n return _xml_common_allowed( [ "label", "collapsible", "collapsed" ] );\n case "Label":\n return _xml_common_allowed( [ "text", "for" ] );\n case "Text":\n return _xml_common_allowed(\n [ "value", "multiline", "readonly", "wrap" ],\n );\n case "RichText":\n return _xml_common_allowed(\n [ "value", "multiline", "readonly" ],\n );\n case "Image":\n return _xml_common_allowed( [ "src", "alt", "fit" ] );\n case "Input":\n return _xml_common_allowed( [\n "value",\n "placeholder",\n "multiline",\n "readonly",\n "password",\n "required",\n ] );\n case "DatePicker":\n return _xml_common_allowed(\n [ "value", "min", "max", "first_day_of_week" ],\n );\n case "Checkbox":\n return _xml_common_allowed( [ "label", "checked", "indeterminate" ] );\n case "Radio":\n return _xml_common_allowed( [ "label", "value", "group", "checked" ] );\n case "RadioGroup":\n return _xml_common_allowed( [ "name", "value" ] );\n case "Select":\n return _xml_common_allowed( [ "value", "multiple" ] );\n case "Menu":\n return _xml_common_allowed( [ "text" ] );\n case "MenuItem":\n return _xml_common_allowed( [ "text" ] );\n case "Button":\n return _xml_common_allowed( [ "text", "variant" ] );\n case "Separator":\n return _xml_common_allowed( [ "orientation" ] );\n case "Slider":\n return _xml_common_allowed( [\n "value",\n "min",\n "max",\n "step",\n "orientation",\n "readonly",\n ] );\n case "Progress":\n return _xml_common_allowed( [\n "value",\n "min",\n "max",\n "indeterminate",\n "show_text",\n ] );\n case "Tabs":\n return _xml_common_allowed( [ "selected", "placement" ] );\n case "Tab":\n return _xml_common_allowed(\n [ "title", "value", "selected", "closable", "icon" ],\n );\n case "ListView":\n return _xml_common_allowed( [ "selected_index", "multiple" ] );\n case "TreeView":\n return _xml_common_allowed( [ "selected_path", "multiple" ] );\n }\n\n _xml_error( "GUI_XML_STRUCTURE", `unsupported GUI XML element \'${tag}\'` );\n}\n\nfunction _xml_bool_attrs ( String tag ) {\n return [\n "visible",\n "enabled",\n "disabled",\n "resizable",\n "modal",\n "collapsible",\n "collapsed",\n "multiline",\n "readonly",\n "wrap",\n "password",\n "required",\n "checked",\n "indeterminate",\n "multiple",\n "show_text",\n "selected",\n "closable",\n ];\n}\n\nfunction _xml_number_attrs ( String tag ) {\n return [\n "width",\n "height",\n "minwidth",\n "minheight",\n "maxwidth",\n "maxheight",\n "gap",\n "padding",\n "first_day_of_week",\n "selected_index",\n "value",\n "min",\n "max",\n "step",\n ];\n}\n\nfunction _xml_bool ( String tag, String attr, String raw ) {\n switch ( lc(raw): eq ) {\n case "true", "1", "yes", "on": return true;\n case "false", "0", "no", "off": return false;\n }\n _xml_error(\n "GUI_XML_ATTR_TYPE",\n `${tag}.${attr} expects a boolean XML attribute`,\n );\n}\n\nfunction _xml_number ( String tag, String attr, String raw ) {\n if ( not ( raw ~ /^-?[0-9]+(\\.[0-9]+)?$/ ) ) {\n _xml_error(\n "GUI_XML_ATTR_TYPE",\n `${tag}.${attr} expects a numeric XML attribute`,\n );\n }\n return 0 + raw;\n}\n\nfunction _xml_int_list ( String tag, String attr, String raw ) {\n let out := [];\n return out if raw eq "";\n for ( let part in split( raw, "," ) ) {\n let item := trim(part);\n if ( not ( item ~ /^-?[0-9]+$/ ) ) {\n _xml_error(\n "GUI_XML_ATTR_TYPE",\n `${tag}.${attr} expects comma-separated integers`,\n );\n }\n out.push( 0 + item );\n }\n return out;\n}\n\nfunction _xml_coerce_attr ( String tag, String attr, String raw ) {\n if ( attr eq "selected" and tag eq "Tabs" ) {\n return raw;\n }\n if ( attr eq "value" and tag \u2209 [ "Slider", "Progress" ] ) {\n return raw;\n }\n if ( attr eq "min" and tag eq "DatePicker" ) {\n return raw;\n }\n if ( attr eq "max" and tag eq "DatePicker" ) {\n return raw;\n }\n if ( attr eq "selected_path" ) {\n return _xml_int_list( tag, attr, raw );\n }\n if ( attr \u2208 _xml_bool_attrs(tag) ) {\n return _xml_bool( tag, attr, raw );\n }\n if ( attr \u2208 _xml_number_attrs(tag) ) {\n return _xml_number( tag, attr, raw );\n }\n return raw;\n}\n\nfunction _xml_attrs ( node ) {\n let tag := _xml_tag_name(node);\n let props := {};\n let meta := {};\n let meta_keys := [];\n let style := {};\n let style_keys := [];\n let allowed := _xml_allowed_attrs(tag);\n\n for ( let attr in node.attributeNames() ) {\n next if attr eq "xmlns";\n next if substr( attr, 0, 6 ) eq "xmlns:";\n let value := node.getAttribute(attr);\n if ( substr( attr, 0, 5 ) eq "meta." ) {\n let key := substr( attr, 5 );\n _xml_error( "GUI_XML_ATTR_UNKNOWN", "empty meta attribute name" )\n if key eq "";\n meta{(key)} := value;\n meta_keys.push(key);\n next;\n }\n if ( substr( attr, 0, 6 ) eq "style." ) {\n let key := substr( attr, 6 );\n _xml_error( "GUI_XML_ATTR_UNKNOWN", "empty style attribute name" )\n if key eq "";\n style{(key)} := value;\n style_keys.push(key);\n next;\n }\n if ( attr \u2209 allowed ) {\n _xml_error(\n "GUI_XML_ATTR_UNKNOWN",\n `${tag} does not accept XML attribute \'${attr}\'`,\n );\n }\n props{(attr)} := _xml_coerce_attr( tag, attr, value );\n }\n\n return {\n props: props,\n meta: meta,\n meta_keys: meta_keys,\n style: style,\n style_keys: style_keys,\n };\n}\n\nfunction _xml_apply_meta ( Widget widget, Dict meta, Array keys ) {\n for ( let key in keys ) {\n widget.meta( key, meta{(key)} );\n }\n if ( keys.length() > 0 ) {\n widget.meta( "__xml_meta_keys", keys );\n }\n return widget;\n}\n\nfunction _xml_apply_style ( Widget widget, Dict style, Array keys ) {\n for ( let key in keys ) {\n widget.style( key, style{(key)} );\n }\n if ( keys.length() > 0 ) {\n widget.meta( "__xml_style_keys", keys );\n }\n return widget;\n}\n\nfunction _xml_widget_from_node ( node ) {\n _xml_assert_namespace(node);\n\n let tag := _xml_tag_name(node);\n let child_widgets := [];\n for ( let child in node.children() ) {\n child_widgets.push( _xml_widget_from_node(child) );\n }\n let parsed := _xml_attrs(node);\n let p := parsed{props};\n let widget;\n\n switch ( tag: eq ) {\n case "Window":\n widget := new _WindowClass(\n id: p.get( "id", null ),\n title: p.get( "title", "" ),\n width: p.get( "width", 800 ),\n height: p.get( "height", 600 ),\n resizable: p.get( "resizable", true ),\n modal: p.get( "modal", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "VBox":\n widget := new _VBoxClass(\n id: p.get( "id", null ),\n align: p.get( "align", "top" ),\n gap: p.get( "gap", 0 ),\n padding: p.get( "padding", 0 ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "HBox":\n widget := new _HBoxClass(\n id: p.get( "id", null ),\n align: p.get( "align", "left" ),\n gap: p.get( "gap", 0 ),\n padding: p.get( "padding", 0 ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "Frame":\n widget := new _FrameClass(\n id: p.get( "id", null ),\n label: p.get( "label", "" ),\n collapsible: p.get( "collapsible", false ),\n collapsed: p.get( "collapsed", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "Label":\n widget := Label(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n ("for"): p.get( "for", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Text":\n widget := Text(\n id: p.get( "id", null ),\n value: p.get( "value", "" ),\n multiline: p.get( "multiline", false ),\n readonly: p.get( "readonly", false ),\n wrap: p.get( "wrap", true ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "RichText":\n widget := RichText(\n id: p.get( "id", null ),\n value: p.get( "value", "" ),\n multiline: p.get( "multiline", true ),\n readonly: p.get( "readonly", true ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Image":\n widget := Image(\n id: p.get( "id", null ),\n src: p.get( "src", "" ),\n alt: p.get( "alt", "" ),\n fit: p.get( "fit", "none" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Input":\n widget := Input(\n id: p.get( "id", null ),\n value: p.get( "value", "" ),\n placeholder: p.get( "placeholder", "" ),\n multiline: p.get( "multiline", false ),\n readonly: p.get( "readonly", false ),\n password: p.get( "password", false ),\n required: p.get( "required", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "DatePicker":\n widget := DatePicker(\n id: p.get( "id", null ),\n value: p.get( "value", null ),\n min: p.get( "min", null ),\n max: p.get( "max", null ),\n first_day_of_week: p.get( "first_day_of_week", 0 ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Checkbox":\n widget := Checkbox(\n id: p.get( "id", null ),\n label: p.get( "label", "" ),\n checked: p.get( "checked", false ),\n indeterminate: p.get( "indeterminate", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Radio":\n widget := Radio(\n id: p.get( "id", null ),\n label: p.get( "label", "" ),\n value: p.get( "value", "" ),\n group: p.get( "group", null ),\n checked: p.get( "checked", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "RadioGroup":\n widget := new _RadioGroupClass(\n id: p.get( "id", null ),\n name: p.get( "name", "" ),\n value: p.get( "value", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "Select":\n widget := Select(\n id: p.get( "id", null ),\n value: p.get( "value", null ),\n multiple: p.get( "multiple", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Menu":\n widget := new _MenuClass(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "MenuItem":\n widget := MenuItem(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Button":\n widget := Button(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n variant: p.get( "variant", "default" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Separator":\n widget := Separator(\n id: p.get( "id", null ),\n orientation: p.get( "orientation", "horizontal" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Slider":\n widget := Slider(\n id: p.get( "id", null ),\n value: p.get( "value", 0 ),\n min: p.get( "min", 0 ),\n max: p.get( "max", 100 ),\n step: p.get( "step", 1 ),\n orientation: p.get( "orientation", "horizontal" ),\n readonly: p.get( "readonly", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Progress":\n widget := Progress(\n id: p.get( "id", null ),\n value: p.get( "value", 0 ),\n min: p.get( "min", 0 ),\n max: p.get( "max", 100 ),\n indeterminate: p.get( "indeterminate", false ),\n show_text: p.get( "show_text", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Tabs":\n widget := new _TabsClass(\n id: p.get( "id", null ),\n selected: p.get( "selected", null ),\n placement: p.get( "placement", "top" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "Tab":\n widget := new _TabClass(\n id: p.get( "id", null ),\n title: p.get( "title", "" ),\n value: p.get( "value", "" ),\n selected: p.get( "selected", false ),\n closable: p.get( "closable", false ),\n icon: p.get( "icon", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "ListView":\n widget := ListView(\n id: p.get( "id", null ),\n selected_index: p.get( "selected_index", null ),\n multiple: p.get( "multiple", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "TreeView":\n widget := TreeView(\n id: p.get( "id", null ),\n selected_path: p.get( "selected_path", [] ),\n multiple: p.get( "multiple", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n default:\n _xml_error(\n "GUI_XML_STRUCTURE",\n `unsupported GUI XML element \'${tag}\'`,\n );\n }\n\n _xml_apply_meta( widget, parsed{meta}, parsed{meta_keys} );\n return _xml_apply_style( widget, parsed{style}, parsed{style_keys} );\n}\n\nfunction gui_from_xml ( String xml ) {\n return _xml_widget_from_node( XML.parse(xml).documentElement() );\n}\n\nfunction gui_from_xml_file ( path ) {\n die "XML.load is denied by runtime policy" if __system__{deny_fs};\n from std/io import Path;\n let file := path instanceof Path ? path : new Path(path);\n return _xml_widget_from_node( XML.load(file).documentElement() );\n}\n\nfunction _xml_tag_for_widget ( Widget widget ) {\n if ( widget instanceof _WindowClass ) { return "Window"; }\n if ( widget instanceof _VBoxClass ) { return "VBox"; }\n if ( widget instanceof _HBoxClass ) { return "HBox"; }\n if ( widget instanceof _FrameClass ) { return "Frame"; }\n if ( widget instanceof _LabelClass ) { return "Label"; }\n if ( widget instanceof _TextClass ) { return "Text"; }\n if ( widget instanceof _RichTextClass ) { return "RichText"; }\n if ( widget instanceof _ImageClass ) { return "Image"; }\n if ( widget instanceof _InputClass ) { return "Input"; }\n if ( widget instanceof _DatePickerClass ) { return "DatePicker"; }\n if ( widget instanceof _CheckboxClass ) { return "Checkbox"; }\n if ( widget instanceof _RadioClass ) { return "Radio"; }\n if ( widget instanceof _RadioGroupClass ) { return "RadioGroup"; }\n if ( widget instanceof _SelectClass ) { return "Select"; }\n if ( widget instanceof _MenuClass ) { return "Menu"; }\n if ( widget instanceof _MenuItemClass ) { return "MenuItem"; }\n if ( widget instanceof _ButtonClass ) { return "Button"; }\n if ( widget instanceof _SeparatorClass ) { return "Separator"; }\n if ( widget instanceof _SliderClass ) { return "Slider"; }\n if ( widget instanceof _ProgressClass ) { return "Progress"; }\n if ( widget instanceof _TabsClass ) { return "Tabs"; }\n if ( widget instanceof _TabClass ) { return "Tab"; }\n if ( widget instanceof _ListViewClass ) { return "ListView"; }\n if ( widget instanceof _TreeViewClass ) { return "TreeView"; }\n _xml_error( "GUI_XML_STRUCTURE", "unsupported widget for gui_to_xml" );\n}\n\nfunction _xml_attr ( String name, value ) {\n return "" if value \u2261 null;\n return ` ${name}="${escape_xml(value)}"`;\n}\n\nfunction _xml_attr_if ( String name, value, fallback ) {\n return "" if value \u2261 fallback;\n return _xml_attr( name, value );\n}\n\nfunction _xml_bool_attr_if ( String name, value, fallback ) {\n let normalized := value ? true : false;\n let normalized_fallback := fallback ? true : false;\n return "" if normalized \u2261 normalized_fallback;\n return _xml_attr( name, normalized ? "true" : "false" );\n}\n\nfunction _xml_attr_nonempty ( String name, value ) {\n return "" if value \u2261 null or value eq "";\n return _xml_attr( name, value );\n}\n\nfunction _xml_join_ints ( Array values ) {\n let out := [];\n for ( let value in values ) {\n out.push( "" _ value );\n }\n return join( ",", out );\n}\n\nfunction _xml_meta_attrs ( Widget widget ) {\n let keys := widget.meta( "__xml_meta_keys" ) ?: [];\n let out := "";\n for ( let key in keys ) {\n out _= _xml_attr( "meta." _ key, widget.meta(key) );\n }\n return out;\n}\n\nfunction _xml_style_attrs ( Widget widget ) {\n let keys := widget.meta( "__xml_style_keys" ) ?: [];\n let out := "";\n for ( let key in keys ) {\n out _= _xml_attr( "style." _ key, widget.style(key) );\n }\n return out;\n}\n\nfunction _xml_common_attrs ( Widget widget ) {\n let out := "";\n out _= _xml_attr( "id", widget.id() ) if widget.id() \u2262 null;\n out _= _xml_bool_attr_if( "visible", widget.visible(), true );\n out _= _xml_bool_attr_if( "disabled", not widget.enabled(), false );\n out _= _xml_meta_attrs(widget);\n out _= _xml_style_attrs(widget);\n return out;\n}\n\nfunction _xml_widget_attrs ( Widget widget ) {\n let out := _xml_common_attrs(widget);\n if ( widget instanceof _WindowClass ) {\n out _= _xml_attr_if( "title", widget.title(), "" );\n }\n else if ( widget instanceof _VBoxClass or widget instanceof _HBoxClass ) {\n let default_align := widget instanceof _VBoxClass ? "top" : "left";\n out _= _xml_attr_if( "align", widget.align(), default_align );\n out _= _xml_attr_if( "gap", widget.gap(), 0 );\n out _= _xml_attr_if( "padding", widget.padding(), 0 )\n unless widget.padding() instanceof Array;\n }\n else if ( widget instanceof _FrameClass ) {\n out _= _xml_attr_if( "label", widget.label(), "" );\n out _= _xml_bool_attr_if( "collapsible", widget.collapsible(), false );\n out _= _xml_bool_attr_if( "collapsed", widget.collapsed(), false );\n }\n else if ( widget instanceof _LabelClass ) {\n out _= _xml_attr_if( "text", widget.text(), "" );\n out _= _xml_attr_nonempty( "for", widget.for_id() );\n }\n else if ( widget instanceof _TextClass ) {\n out _= _xml_attr_if( "value", widget.value(), "" );\n out _= _xml_bool_attr_if( "multiline", widget.multiline(), false );\n out _= _xml_bool_attr_if( "readonly", widget.readonly(), false );\n out _= _xml_bool_attr_if( "wrap", widget.wrap(), true );\n }\n else if ( widget instanceof _RichTextClass ) {\n out _= _xml_attr_if( "value", widget.value(), "" );\n out _= _xml_bool_attr_if( "multiline", widget.multiline(), true );\n out _= _xml_bool_attr_if( "readonly", widget.readonly(), true );\n }\n else if ( widget instanceof _ImageClass ) {\n out _= _xml_attr_if( "src", widget.src(), "" );\n out _= _xml_attr_if( "alt", widget.alt(), "" );\n out _= _xml_attr_if( "fit", widget.fit(), "none" );\n }\n else if ( widget instanceof _InputClass ) {\n out _= _xml_attr_if( "value", widget.value(), "" );\n out _= _xml_attr_if( "placeholder", widget.placeholder(), "" );\n out _= _xml_bool_attr_if( "multiline", widget.multiline(), false );\n out _= _xml_bool_attr_if( "readonly", widget.readonly(), false );\n out _= _xml_bool_attr_if( "password", widget.password(), false );\n out _= _xml_bool_attr_if( "required", widget.required(), false );\n }\n else if ( widget instanceof _DatePickerClass ) {\n out _= _xml_attr( "value", widget.value() );\n out _= _xml_attr( "min", widget.min() ) if widget.min() \u2262 null;\n out _= _xml_attr( "max", widget.max() ) if widget.max() \u2262 null;\n out _= _xml_attr_if(\n "first_day_of_week",\n widget.first_day_of_week(),\n 0,\n );\n }\n else if ( widget instanceof _CheckboxClass ) {\n out _= _xml_attr_if( "label", widget.label(), "" );\n out _= _xml_bool_attr_if( "checked", widget.checked(), false );\n out _= _xml_bool_attr_if( "indeterminate", widget.indeterminate(), false );\n }\n else if ( widget instanceof _RadioClass ) {\n out _= _xml_attr_if( "label", widget.label(), "" );\n out _= _xml_attr_if( "value", widget.value(), "" );\n out _= _xml_attr_nonempty( "group", widget.group() );\n out _= _xml_bool_attr_if( "checked", widget.checked(), false );\n }\n else if ( widget instanceof _RadioGroupClass ) {\n out _= _xml_attr_if( "name", widget.name(), "" );\n out _= _xml_attr( "value", widget.value() ) if widget.value() \u2262 null;\n }\n else if ( widget instanceof _SelectClass ) {\n out _= _xml_attr( "value", widget.value() ) if widget.value() \u2262 null;\n out _= _xml_bool_attr_if( "multiple", widget.multiple(), false );\n }\n else if ( widget instanceof _MenuClass ) {\n out _= _xml_attr_if( "text", widget.text(), "" );\n }\n else if ( widget instanceof _MenuItemClass ) {\n out _= _xml_attr_if( "text", widget.text(), "" );\n }\n else if ( widget instanceof _ButtonClass ) {\n out _= _xml_attr_if( "text", widget.text(), "" );\n out _= _xml_attr_if( "variant", widget.variant(), "default" );\n }\n else if ( widget instanceof _SeparatorClass ) {\n out _= _xml_attr_if( "orientation", widget.orientation(), "horizontal" );\n }\n else if ( widget instanceof _SliderClass ) {\n out _= _xml_attr_if( "value", widget.value(), 0 );\n out _= _xml_attr_if( "min", widget.min(), 0 );\n out _= _xml_attr_if( "max", widget.max(), 100 );\n out _= _xml_attr_if( "step", widget.step(), 1 );\n out _= _xml_attr_if( "orientation", widget.orientation(), "horizontal" );\n out _= _xml_bool_attr_if( "readonly", widget.readonly(), false );\n }\n else if ( widget instanceof _ProgressClass ) {\n out _= _xml_attr_if( "value", widget.value(), 0 );\n out _= _xml_attr_if( "min", widget.min(), 0 );\n out _= _xml_attr_if( "max", widget.max(), 100 );\n out _= _xml_bool_attr_if( "indeterminate", widget.indeterminate(), false );\n out _= _xml_bool_attr_if( "show_text", widget.show_text(), false );\n }\n else if ( widget instanceof _TabsClass ) {\n out _= _xml_attr( "selected", widget.selected() )\n if widget.selected() \u2262 null;\n out _= _xml_attr_if( "placement", widget.placement(), "top" );\n }\n else if ( widget instanceof _TabClass ) {\n out _= _xml_attr_if( "title", widget.title(), "" );\n out _= _xml_attr_if( "value", widget.value(), "" );\n out _= _xml_attr( "icon", widget.icon() ) if widget.icon() \u2262 null;\n out _= _xml_bool_attr_if( "selected", widget.selected(), false );\n out _= _xml_bool_attr_if( "closable", widget.closable(), false );\n }\n else if ( widget instanceof _ListViewClass ) {\n out _= _xml_attr( "selected_index", widget.selected_index() )\n if widget.selected_index() \u2262 null;\n out _= _xml_bool_attr_if( "multiple", widget.multiple(), false );\n }\n else if ( widget instanceof _TreeViewClass ) {\n let selected_path := widget.selected_path();\n out _= _xml_attr( "selected_path", _xml_join_ints(selected_path) )\n if selected_path.length() > 0;\n out _= _xml_bool_attr_if( "multiple", widget.multiple(), false );\n }\n return out;\n}\n\nfunction _xml_serialize_widget ( Widget widget, Number depth ) {\n let indent := "";\n let i := 0;\n while ( i < depth ) {\n indent _= "\\t";\n i++;\n }\n\n let tag := _xml_tag_for_widget(widget);\n let attrs := _xml_widget_attrs(widget);\n attrs _= _xml_attr( "xmlns", GUI_XML_NS ) if depth = 0;\n let children := widget.children();\n if ( children.length() = 0 ) {\n return indent _ "<" _ tag _ attrs _ " />";\n }\n\n let parts := [];\n for ( let child in children ) {\n parts.push( _xml_serialize_widget( child, depth + 1 ) );\n }\n\n return indent _ "<" _ tag _ attrs _ ">\\n"\n _ join( "\\n", parts )\n _ "\\n" _ indent _ "</" _ tag _ ">";\n}\n\nfunction gui_to_xml ( Widget root ) {\n return _xml_serialize_widget( root, 0 ) _ "\\n";\n}\n';
|
|
40639
41583
|
virtualFiles["/modules/std/gui/dialogue.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/gui/dialogue - Dialogue helpers.\n\n=head1 SYNOPSIS\n\n from std/gui/dialogue import *;\n\n alert("Saved");\n let ok := confirm("Continue?");\n let name := prompt("Name:", value: "Ada");\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by zuzu.pl, zuzu-rust, and zuzu-js on Electron\nand Browser. It is not supported by zuzu-js on Node.\n\n=head1 DESCRIPTION\n\nThis module provides convenience dialogue helpers layered on top of the\nregular C<std/gui> widgets.\n\n=head1 EXPORTS\n\n=head2 Functions\n\n=over\n\n=item C<< alert(String message, ... PairList p) >>, C<< alert_window(String message, ... PairList p) >>\n\nParameters: C<message> is display text and C<p> contains options.\nReturns: C<null> for C<alert> or C<Window> for C<alert_window>. Shows or\nbuilds an alert dialogue.\n\n=item C<< confirm(String message, ... PairList p) >>, C<< confirm_window(String message, ... PairList p) >>\n\nParameters: C<message> is display text and C<p> contains options.\nReturns: C<Boolean> for C<confirm> or C<Window> for\nC<confirm_window>. Shows or builds a confirmation dialogue.\n\n=item C<< prompt(String message, ... PairList p) >>, C<< prompt_window(String message, ... PairList p) >>\n\nParameters: C<message> is prompt text and C<p> contains options such as\nC<value>. Returns: C<String> or C<null> for C<prompt>, or C<Window> for\nC<prompt_window>. Shows or builds a text prompt.\n\n=item C<< file_open(... PairList p) >>, C<< file_save(... PairList p) >>\n\nParameters: C<p> contains dialogue options. Returns: path value or\nC<null>. Opens a file selection dialogue.\n\n=item C<< directory_open(... PairList p) >>, C<< directory_save(... PairList p) >>\n\nParameters: C<p> contains dialogue options. Returns: path value or\nC<null>. Opens a directory selection dialogue.\n\n=item C<< colour_picker(... PairList p) >>\n\nParameters: C<p> contains dialogue options. Returns: C<String> or\nC<null>. Opens a colour picker and returns a normalized colour string.\n\n=item C<< file_open_window(... PairList p) >>, C<< file_save_window(... PairList p) >>, C<< directory_open_window(... PairList p) >>, C<< directory_save_window(... PairList p) >>, C<< colour_picker_window(... PairList p) >>\n\nParameters: C<p> contains dialogue options. Returns: C<Window>. Builds\nthe corresponding GUI dialogue window.\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/gui/dialogue >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nfrom std/gui try import\n EM,\n Window,\n VBox,\n HBox,\n Label,\n Text,\n Input,\n Button,\n Widget,\n native_file_open,\n native_file_save,\n native_directory_open,\n native_directory_save,\n native_colour_picker;\nfrom std/gui/objects try import\n meta as _objects_meta,\n native_alert,\n native_confirm,\n native_prompt;\nfrom std/colour import parse_colour;\nfrom std/string import split;\nfrom std/tui import\n colour_text,\n directory_completions,\n filename_completions,\n readline;\n\nfunction _tui_string ( value ) {\n return value \u2261 null ? "" : "" _ value;\n}\n\nfunction _gui_backend () {\n if ( _objects_meta \u2262 null ) {\n return _objects_meta{backend};\n }\n return "";\n}\n\nfunction _path_dialogue_unsupported () {\n if ( __system__{deny_fs} ) {\n die "GUI_DIALOGUE_FS_DENIED: file and directory dialogues require filesystem capability";\n }\n if ( _gui_backend() eq "browser-dom" ) {\n die "GUI_DIALOGUE_UNSUPPORTED: file and directory dialogues are unsupported in JS/Browser";\n }\n}\n\nfunction _tui_prompt ( String message, PairList p, String default_value ) {\n return readline(\n colour_text( message _ " ", "cyan" ),\n default_value,\n null,\n );\n}\n\nfunction _tui_path_dialog (\n String label,\n String default_value,\n completion,\n PairList p\n) {\n let answer := readline(\n colour_text( p.get( "label", label ) _ " ", "cyan" ),\n _tui_string( p.get( "value", default_value ) ),\n completion,\n );\n if ( p.get( "multiple", false ) ) {\n return split( answer, p.get( "separator", "\\n" ) );\n }\n return answer;\n}\n\nfunction _parse_colour_or_null ( value ) {\n return try {\n parse_colour( _tui_string(value) );\n }\n catch {\n null;\n };\n}\n\nfunction _colour_initial_value ( PairList p ) {\n let raw := _tui_string( p.get( "value", "#000000" ) );\n let parsed := _parse_colour_or_null(raw);\n return parsed \u2262 null ? parsed : raw;\n}\n\nfunction _colour_default_value ( PairList p ) {\n return _parse_colour_or_null( p.get( "value", "#000000" ) ) ?: "#000000";\n}\n\nfunction _tui_colour_dialog ( PairList p ) {\n let default_value := _colour_default_value(p);\n while ( true ) {\n let answer := readline(\n colour_text( p.get( "label", "Colour:" ) _ " ", "cyan" ),\n default_value,\n null,\n );\n let parsed := _parse_colour_or_null(answer);\n if ( parsed \u2262 null ) {\n return parsed;\n }\n say( colour_text( "Invalid colour; try #336699 or red.", "yellow" ) );\n }\n}\n\nfunction _dialogue_window (\n String kind,\n String title,\n Widget body,\n Array buttons,\n PairList p\n) {\n let button_row := HBox(\n id: "buttons",\n align: "right",\n gap: 6,\n height: p.get( "button_row_height", 2.125 \xD7 EM ),\n maxheight: p.get( "button_row_height", 2.125 \xD7 EM ),\n );\n for ( let button in buttons ) {\n button_row.add_child(button);\n }\n let w := Window(\n title: title,\n width: p.get( "width", 360 ),\n height: p.get( "height", 180 ),\n resizable: p.get( "resizable", false ),\n modal: true,\n VBox(\n id: p.get( "id", null ),\n gap: p.get( "gap", 8 ),\n padding: p.get( "padding", 12 ),\n body,\n button_row,\n ),\n );\n w.meta( "dialogue.kind", kind );\n return w;\n}\n\nfunction _message_body ( String message, PairList p ) {\n return Text(\n id: p.get( "message_id", "message" ),\n value: message,\n readonly: true,\n wrap: true,\n );\n}\n\nfunction _primary_button ( PairList p, String fallback ) {\n return Button(\n id: p.get( "ok_id", "ok" ),\n text: p.get( "ok_text", fallback ),\n variant: "primary",\n width: p.get( "button_width", 5.5 \xD7 EM ),\n height: p.get( "button_height", 1.75 \xD7 EM ),\n maxheight: p.get( "button_height", 1.75 \xD7 EM ),\n );\n}\n\nfunction _cancel_button ( PairList p ) {\n return Button(\n id: p.get( "cancel_id", "cancel" ),\n text: p.get( "cancel_text", "Cancel" ),\n width: p.get( "button_width", 5.5 \xD7 EM ),\n height: p.get( "button_height", 1.75 \xD7 EM ),\n maxheight: p.get( "button_height", 1.75 \xD7 EM ),\n );\n}\n\nfunction _alert_window ( String message, PairList p ) {\n let ok := _primary_button( p, "OK" );\n let w := _dialogue_window(\n "alert",\n p.get( "title", "Alert" ),\n _message_body( message, p ),\n [ ok ],\n p,\n );\n ok.click( function () {\n w.close(null);\n } );\n return w;\n}\n\nfunction alert_window ( String message, ... PairList p ) {\n return _alert_window( message, p );\n}\n\nfunction alert ( String message, ... PairList p ) {\n if ( p.has("auto_result") ) {\n return null;\n }\n if ( __system__{deny_gui} ) {\n say( colour_text( message, "yellow" ) );\n return null;\n }\n if ( native_alert \u2262 null ) {\n let native_result := native_alert( message, p );\n if ( native_result ) {\n return null;\n }\n }\n return _alert_window( message, p ).call();\n}\n\nfunction _confirm_window ( String message, PairList p ) {\n let ok := _primary_button( p, p.get( "ok_text", "OK" ) );\n let cancel := _cancel_button(p);\n let w := _dialogue_window(\n "confirm",\n p.get( "title", "Confirm" ),\n _message_body( message, p ),\n [ cancel, ok ],\n p,\n );\n ok.click( function () {\n w.close(true);\n } );\n cancel.click( function () {\n w.close(false);\n } );\n return w;\n}\n\nfunction confirm_window ( String message, ... PairList p ) {\n return _confirm_window( message, p );\n}\n\nfunction confirm ( String message, ... PairList p ) {\n if ( p.has("auto_result") ) {\n return p.get("auto_result") ? true : false;\n }\n if ( __system__{deny_gui} ) {\n let yes_default := p.get( "value", p.get( "default", false ) );\n let suffix := yes_default ? " [Y/n] " : " [y/N] ";\n let answer := readline(\n colour_text( message _ suffix, "cyan" ),\n yes_default ? "y" : "n",\n null,\n );\n return ( answer ~ /^(?:y|yes|1|true)$/i ) ? true : false;\n }\n if ( native_confirm \u2262 null ) {\n let native_result := native_confirm( message, p );\n if ( native_result \u2262 null ) {\n return native_result ? true : false;\n }\n }\n return _confirm_window( message, p ).call() ? true : false;\n}\n\nfunction _prompt_window ( String message, PairList p ) {\n let input := Input(\n id: p.get( "input_id", "value" ),\n value: p.get( "value", "" ),\n placeholder: p.get( "placeholder", "" ),\n );\n let ok := _primary_button( p, p.get( "ok_text", "OK" ) );\n let cancel := _cancel_button(p);\n let w := _dialogue_window(\n "prompt",\n p.get( "title", "Prompt" ),\n VBox(\n gap: 6,\n _message_body( message, p ),\n input,\n ),\n [ cancel, ok ],\n p,\n );\n ok.click( function () {\n w.close( input.value() );\n } );\n cancel.click( function () {\n w.close(null);\n } );\n return w;\n}\n\nfunction prompt_window ( String message, ... PairList p ) {\n return _prompt_window( message, p );\n}\n\nfunction prompt ( String message, ... PairList p ) {\n if ( p.has("auto_result") ) {\n return p.get("auto_result");\n }\n if ( __system__{deny_gui} ) {\n return _tui_prompt(\n message,\n p,\n _tui_string( p.get( "value", "" ) ),\n );\n }\n if ( native_prompt \u2262 null ) {\n let native_result := native_prompt( message, p );\n if ( _gui_backend() eq "browser-dom" ) {\n return native_result;\n }\n if ( native_result \u2262 null ) {\n return native_result;\n }\n }\n return _prompt_window( message, p ).call();\n}\n\nfunction _path_dialog_window (\n String kind,\n String title,\n String label,\n String default_value,\n PairList p\n) {\n let input := Input(\n id: p.get( "input_id", "path" ),\n value: p.get( "value", default_value ),\n placeholder: p.get( "placeholder", "" ),\n multiline: p.get( "multiple", false ),\n );\n let ok := _primary_button( p, p.get( "ok_text", "OK" ) );\n let cancel := _cancel_button(p);\n let w := _dialogue_window(\n kind,\n p.get( "title", title ),\n VBox(\n gap: 6,\n Label( text: p.get( "label", label ), ("for"): input.id() ),\n input,\n ),\n [ cancel, ok ],\n p,\n );\n ok.click( function () {\n if ( p.get( "multiple", false ) ) {\n w.close( split( input.value(), p.get( "separator", "\\n" ) ) );\n }\n else {\n w.close( input.value() );\n }\n } );\n cancel.click( function () {\n w.close(null);\n } );\n return w;\n}\n\nfunction file_open_window ( ... PairList p ) {\n return _path_dialog_window( "file_open", "Open File", "File:", "", p );\n}\n\nfunction file_save_window ( ... PairList p ) {\n return _path_dialog_window( "file_save", "Save File", "File:", "", p );\n}\n\nfunction directory_open_window ( ... PairList p ) {\n return _path_dialog_window(\n "directory_open",\n "Open Directory",\n "Directory:",\n "",\n p,\n );\n}\n\nfunction directory_save_window ( ... PairList p ) {\n return _path_dialog_window(\n "directory_save",\n "Save Directory",\n "Directory:",\n "",\n p,\n );\n}\n\nfunction _colour_picker_window ( PairList p ) {\n let input := Input(\n id: p.get( "input_id", "path" ),\n value: _colour_initial_value(p),\n placeholder: p.get( "placeholder", "#336699" ),\n );\n let ok := _primary_button( p, p.get( "ok_text", "OK" ) );\n let cancel := _cancel_button(p);\n let default_value := _colour_default_value(p);\n let sync_ok := function () {\n ok.set_enabled( _parse_colour_or_null( input.value() ) \u2262 null );\n };\n let w := _dialogue_window(\n "colour_picker",\n p.get( "title", "Choose Colour" ),\n VBox(\n gap: 6,\n Label(\n text: p.get( "label", "Colour:" ),\n ("for"): input.id(),\n ),\n input,\n ),\n [ cancel, ok ],\n p,\n );\n sync_ok();\n input.on( "change", sync_ok );\n ok.click( function () {\n let parsed := _parse_colour_or_null( input.value() );\n if ( parsed \u2262 null ) {\n w.close(parsed);\n }\n } );\n cancel.click( function () {\n w.close(default_value);\n } );\n return w;\n}\n\nfunction colour_picker_window ( ... PairList p ) {\n return _colour_picker_window(p);\n}\n\nfunction file_open ( ... PairList p ) {\n _path_dialogue_unsupported();\n if ( p.has("auto_result") ) {\n return p.get("auto_result");\n }\n if ( __system__{deny_gui} ) {\n return _tui_path_dialog( "File:", "", filename_completions, p );\n }\n return native_file_open(p);\n}\n\nfunction file_save ( ... PairList p ) {\n _path_dialogue_unsupported();\n if ( p.has("auto_result") ) {\n return p.get("auto_result");\n }\n if ( __system__{deny_gui} ) {\n return _tui_path_dialog( "File:", "", filename_completions, p );\n }\n return native_file_save(p);\n}\n\nfunction directory_open ( ... PairList p ) {\n _path_dialogue_unsupported();\n if ( p.has("auto_result") ) {\n return p.get("auto_result");\n }\n if ( __system__{deny_gui} ) {\n return _tui_path_dialog(\n "Directory:",\n "",\n directory_completions,\n p,\n );\n }\n return native_directory_open(p);\n}\n\nfunction directory_save ( ... PairList p ) {\n _path_dialogue_unsupported();\n if ( p.has("auto_result") ) {\n return p.get("auto_result");\n }\n if ( __system__{deny_gui} ) {\n return _tui_path_dialog(\n "Directory:",\n "",\n directory_completions,\n p,\n );\n }\n if ( native_directory_save \u2262 null ) {\n let native_result := native_directory_save(p);\n if ( native_result \u2262 null ) {\n return native_result;\n }\n if ( _gui_backend() eq "electron-dom" ) {\n return null;\n }\n }\n return _path_dialog_window(\n "directory_save",\n "Save Directory",\n "Directory:",\n "",\n p,\n ).call();\n}\n\nfunction colour_picker ( ... PairList p ) {\n if ( p.has("auto_result") ) {\n return parse_colour( _tui_string( p.get("auto_result") ) );\n }\n if ( __system__{deny_gui} ) {\n return _tui_colour_dialog(p);\n }\n if ( native_colour_picker \u2262 null ) {\n let native_result := native_colour_picker(p);\n if ( native_result \u2262 null ) {\n return parse_colour(native_result);\n }\n if ( _gui_backend() eq "browser-dom" ) {\n return null;\n }\n }\n if ( _gui_backend() eq "electron-dom" ) {\n return _colour_picker_window(p).call();\n }\n return parse_colour( _colour_picker_window(p).call() );\n}\n';
|
|
40640
|
-
virtualFiles["/modules/std/uuid.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/uuid - Pure ZuzuScript UUID v1 generator.\n\n=head1 SYNOPSIS\n\n from std/uuid import create_uuid, create_uuid_binary;\n\n let text := create_uuid();\n let raw := create_uuid_binary();\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by all implementations of ZuzuScript.\n\n=head1 DESCRIPTION\n\nThis module implements UUID version 1 generation using only\nZuzuScript code.\n\n=head1 EXPORTS\n\n=head2 Functions\n\n=over\n\n=item * C<create_uuid_binary()>\n\nParameters: none. Returns: C<BinaryString>. Returns a single UUID as 16\nraw bytes.\n\n=item * C<create_uuid()>\n\nParameters: none. Returns: C<String>. Returns a single UUID as\nlowercase hexadecimal text with hyphens in the usual C<8-4-4-4-12>\nlayout.\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/uuid >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nfrom std/math import Math;\nfrom std/string import substr;\nfrom std/string/base64 import decode;\nfrom std/time import Time;\n\nlet _B64_ALPHABET := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";\nlet _HEX_ALPHABET := "0123456789abcdef";\n\nfunction _div_floor ( Number n, Number d ) {\n return floor( n / d );\n}\n\nfunction _mod ( Number n, Number d ) {\n return n - _div_floor( n, d ) * d;\n}\n\nfunction _rand_int ( Number max ) {\n return floor( Math.rand(max) );\n}\n\nfunction _bytes_to_binary ( Array bytes ) {\n let out := "";\n let i := 0;\n let n := bytes.length();\n\n while ( i < n ) {\n let b0 := bytes[i];\n let b1 := null;\n let b2 := null;\n if ( i + 1 < n ) {\n b1 := bytes[i + 1];\n }\n if ( i + 2 < n ) {\n b2 := bytes[i + 2];\n }\n\n let c0 := _div_floor( b0, 4 );\n let c1 := _mod( b0, 4 ) * 16;\n let c2 := 64;\n let c3 := 64;\n\n if ( b1 \u2262 null ) {\n c1 += _div_floor( b1, 16 );\n c2 := _mod( b1, 16 ) * 4;\n if ( b2 \u2262 null ) {\n c2 += _div_floor( b2, 64 );\n c3 := _mod( b2, 64 );\n }\n }\n\n out _= substr( _B64_ALPHABET, c0, 1 );\n out _= substr( _B64_ALPHABET, c1, 1 );\n if ( c2 \u2261 64 ) {\n out _= "=";\n }\n else {\n out _= substr( _B64_ALPHABET, c2, 1 );\n }\n if ( c3 \u2261 64 ) {\n out _= "=";\n }\n else {\n out _= substr( _B64_ALPHABET, c3, 1 );\n }\n\n i += 3;\n }\n\n return decode(out);\n}\n\nfunction _timestamp_words () {\n // Seconds between 1582-10-15 and 1970-01-01.\n let epoch_offset := 12219292800;\n let seconds := new Time().epoch() + epoch_offset;\n let ticks := _rand_int(10000000);\n\n let words := [\n _mod( seconds, 65536 ),\n _mod( _div_floor( seconds, 65536 ), 65536 ),\n _mod( _div_floor( seconds, 4294967296 ), 65536 ),\n 0,\n 0,\n ];\n\n let scale := 10000000;\n let i := 0;\n let carry := 0;\n while ( i < words.length() ) {\n let product := words[i] * scale + carry;\n words[i] := _mod( product, 65536 );\n carry := _div_floor( product, 65536 );\n i++;\n }\n\n let add_i := 0;\n let add_carry := ticks;\n while ( add_carry > 0 and add_i < words.length() ) {\n let sum := words[add_i] + _mod( add_carry, 65536 );\n words[add_i] := _mod( sum, 65536 );\n add_carry := _div_floor( add_carry, 65536 ) + _div_floor( sum, 65536 );\n add_i++;\n }\n\n return words;\n}\n\nfunction _create_uuid_bytes () {\n let words := _timestamp_words();\n let time_low := words[0] + words[1] * 65536;\n let time_mid := words[2];\n let time_hi_and_version := _mod( words[3], 4096 ) + 4096;\n\n let clock_seq := _rand_int(16384);\n let clock_seq_hi_and_reserved := _mod( _div_floor( clock_seq, 256 ), 64 ) + 128;\n let clock_seq_low := _mod( clock_seq, 256 );\n\n let node := [];\n let j := 0;\n while ( j < 6 ) {\n node.push( _rand_int(256) );\n j++;\n }\n // Multicast bit set means this is not an IEEE MAC address.\n node[0] := node[0] | 1;\n\n return [\n _mod( _div_floor( time_low, 16777216 ), 256 ),\n _mod( _div_floor( time_low, 65536 ), 256 ),\n _mod( _div_floor( time_low, 256 ), 256 ),\n _mod( time_low, 256 ),\n _mod( _div_floor( time_mid, 256 ), 256 ),\n _mod( time_mid, 256 ),\n _mod( _div_floor( time_hi_and_version, 256 ), 256 ),\n _mod( time_hi_and_version, 256 ),\n clock_seq_hi_and_reserved,\n clock_seq_low,\n node[0],\n node[1],\n node[2],\n node[3],\n node[4],\n node[5],\n ];\n}\n\nfunction _byte_to_hex ( Number b ) {\n let hi := _div_floor( b, 16 );\n let lo := _mod( b, 16 );\n return substr( _HEX_ALPHABET, hi, 1 ) _ substr( _HEX_ALPHABET, lo, 1 );\n}\n\nfunction _bytes_to_uuid_text ( Array bytes ) {\n let out := "";\n let i := 0;\n while ( i < 16 ) {\n out _= _byte_to_hex( bytes[i] );\n if ( i \u2261 3 or i \u2261 5 or i \u2261 7 or i \u2261 9 ) {\n out _= "-";\n }\n i++;\n }\n return out;\n}\n\nfunction create_uuid_binary () {\n return _bytes_to_binary( _create_uuid_bytes() );\n}\n\nfunction create_uuid () {\n return _bytes_to_uuid_text( _create_uuid_bytes() );\n}\n';
|
|
41584
|
+
virtualFiles["/modules/std/uuid.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/uuid - Pure ZuzuScript UUID v1 generator.\n\n=head1 SYNOPSIS\n\n from std/uuid import create_uuid, create_uuid_binary;\n\n let text := create_uuid();\n let raw := create_uuid_binary();\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by all implementations of ZuzuScript.\n\n=head1 DESCRIPTION\n\nThis module implements UUID version 1 generation using only\nZuzuScript code.\n\n=head1 EXPORTS\n\n=head2 Functions\n\n=over\n\n=item * C<create_uuid_binary()>\n\nParameters: none. Returns: C<BinaryString>. Returns a single UUID as 16\nraw bytes.\n\n=item * C<create_uuid()>\n\nParameters: none. Returns: C<String>. Returns a single UUID as\nlowercase hexadecimal text with hyphens in the usual C<8-4-4-4-12>\nlayout.\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/uuid >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nfrom std/math import Math;\nfrom std/string import substr;\nfrom std/string/base64 import decode;\nfrom std/time import Time;\n\nlet _B64_ALPHABET := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";\nlet _HEX_ALPHABET := "0123456789abcdef";\n\nfunction _div_floor ( Number n, Number d ) {\n return floor( n / d );\n}\n\nfunction _mod ( Number n, Number d ) {\n return n - _div_floor( n, d ) * d;\n}\n\nfunction _rand_int ( Number max ) {\n return floor( Math.rand(max) );\n}\n\nfunction _bytes_to_binary ( Array bytes ) {\n let out := "";\n let i := 0;\n let n := bytes.length();\n\n while ( i < n ) {\n let b0 := bytes[i];\n let b1 := null;\n let b2 := null;\n if ( i + 1 < n ) {\n b1 := bytes[i + 1];\n }\n if ( i + 2 < n ) {\n b2 := bytes[i + 2];\n }\n\n let c0 := _div_floor( b0, 4 );\n let c1 := _mod( b0, 4 ) * 16;\n let c2 := 64;\n let c3 := 64;\n\n if ( b1 \u2262 null ) {\n c1 += _div_floor( b1, 16 );\n c2 := _mod( b1, 16 ) * 4;\n if ( b2 \u2262 null ) {\n c2 += _div_floor( b2, 64 );\n c3 := _mod( b2, 64 );\n }\n }\n\n out _= substr( _B64_ALPHABET, c0, 1 );\n out _= substr( _B64_ALPHABET, c1, 1 );\n if ( c2 \u2261 64 ) {\n out _= "=";\n }\n else {\n out _= substr( _B64_ALPHABET, c2, 1 );\n }\n if ( c3 \u2261 64 ) {\n out _= "=";\n }\n else {\n out _= substr( _B64_ALPHABET, c3, 1 );\n }\n\n i += 3;\n }\n\n return decode(out);\n}\n\nfunction _timestamp_words () {\n // Seconds between 1582-10-15 and 1970-01-01.\n let epoch_offset := 12219292800;\n let seconds := floor( new Time().epoch() ) + epoch_offset;\n let ticks := _rand_int(10000000);\n\n let words := [\n _mod( seconds, 65536 ),\n _mod( _div_floor( seconds, 65536 ), 65536 ),\n _mod( _div_floor( seconds, 4294967296 ), 65536 ),\n 0,\n 0,\n ];\n\n let scale := 10000000;\n let i := 0;\n let carry := 0;\n while ( i < words.length() ) {\n let product := words[i] * scale + carry;\n words[i] := _mod( product, 65536 );\n carry := _div_floor( product, 65536 );\n i++;\n }\n\n let add_i := 0;\n let add_carry := ticks;\n while ( add_carry > 0 and add_i < words.length() ) {\n let sum := words[add_i] + _mod( add_carry, 65536 );\n words[add_i] := _mod( sum, 65536 );\n add_carry := _div_floor( add_carry, 65536 ) + _div_floor( sum, 65536 );\n add_i++;\n }\n\n return words;\n}\n\nfunction _create_uuid_bytes () {\n let words := _timestamp_words();\n let time_low := words[0] + words[1] * 65536;\n let time_mid := words[2];\n let time_hi_and_version := _mod( words[3], 4096 ) + 4096;\n\n let clock_seq := _rand_int(16384);\n let clock_seq_hi_and_reserved := _mod( _div_floor( clock_seq, 256 ), 64 ) + 128;\n let clock_seq_low := _mod( clock_seq, 256 );\n\n let node := [];\n let j := 0;\n while ( j < 6 ) {\n node.push( _rand_int(256) );\n j++;\n }\n // Multicast bit set means this is not an IEEE MAC address.\n node[0] := node[0] | 1;\n\n return [\n _mod( _div_floor( time_low, 16777216 ), 256 ),\n _mod( _div_floor( time_low, 65536 ), 256 ),\n _mod( _div_floor( time_low, 256 ), 256 ),\n _mod( time_low, 256 ),\n _mod( _div_floor( time_mid, 256 ), 256 ),\n _mod( time_mid, 256 ),\n _mod( _div_floor( time_hi_and_version, 256 ), 256 ),\n _mod( time_hi_and_version, 256 ),\n clock_seq_hi_and_reserved,\n clock_seq_low,\n node[0],\n node[1],\n node[2],\n node[3],\n node[4],\n node[5],\n ];\n}\n\nfunction _byte_to_hex ( Number b ) {\n let hi := _div_floor( b, 16 );\n let lo := _mod( b, 16 );\n return substr( _HEX_ALPHABET, hi, 1 ) _ substr( _HEX_ALPHABET, lo, 1 );\n}\n\nfunction _bytes_to_uuid_text ( Array bytes ) {\n let out := "";\n let i := 0;\n while ( i < 16 ) {\n out _= _byte_to_hex( bytes[i] );\n if ( i \u2261 3 or i \u2261 5 or i \u2261 7 or i \u2261 9 ) {\n out _= "-";\n }\n i++;\n }\n return out;\n}\n\nfunction create_uuid_binary () {\n return _bytes_to_binary( _create_uuid_bytes() );\n}\n\nfunction create_uuid () {\n return _bytes_to_uuid_text( _create_uuid_bytes() );\n}\n';
|
|
40641
41585
|
virtualFiles["/modules/std/dump.zzm"] = `=encoding utf8
|
|
40642
41586
|
|
|
40643
41587
|
=head1 NAME
|
|
@@ -46398,7 +47342,7 @@ const STANDARD_FUNCTIONS := [
|
|
|
46398
47342
|
virtualFiles["/modules/std/path/z/parser.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/path/z/parser - Pure Zuzu parser for ZPath expressions.\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by all implementations of ZuzuScript.\n\n=head1 DESCRIPTION\n\nThis module provides the pure-Zuzu parser used by ZPath.\n\n=head1 EXPORTS\n\n=head2 Classes\n\n=over\n\n=item C<< Parser({ lexer_class?, allowed_operators }) >>\n\nConstructs a ZPath parser. Returns: C<Parser>.\n\n=over\n\n=item C<< parser.parse_top_level_terms(src) >>\n\nParameters: C<src> is a ZPath expression string. Returns: C<Array>.\nParses comma-separated top-level expression terms.\n\n=item C<< parser.parse_expression(lx) >>\n\nParameters: C<lx> is a C<Lexer>. Returns: C<Dict>. Parses an expression.\n\n=item C<< parser.parse_ternary(lx) >>\n\nParameters: C<lx> is a C<Lexer>. Returns: C<Dict>. Parses ternary and\nElvis expressions.\n\n=item C<< parser.parse_subexpression(lx, min_prec) >>\n\nParameters: C<lx> is a C<Lexer> and C<min_prec> is a precedence floor.\nReturns: C<Dict>. Parses a precedence-climbing subexpression.\n\n=item C<< parser.parse_primary(lx) >>\n\nParameters: C<lx> is a C<Lexer>. Returns: C<Dict>. Parses a primary\nexpression.\n\n=back\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/path/z/parser >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nfrom std/string import trim;\nfrom std/path/z/lexer import Lexer;\n\nclass Parser {\n let lexer_class;\n let allowed_operators;\n let _binop_prec := {};\n let _unop_prec := {};\n let _need_ws := {};\n let _right_assoc := {};\n let _path_terminators := {};\n let _allow_elvis := false;\n\n method __build__ () {\n lexer_class ?:= Lexer;\n self._init_path_terminators();\n for ( let op in allowed_operators ) {\n let spell := op.get_spelling();\n if ( op.is_unary() ) {\n _unop_prec.set( spell, op.get_precedence() );\n }\n else {\n if ( op.get_kind() \u2261 "ELVIS" ) {\n _allow_elvis := true;\n _path_terminators.set( op.get_kind(), true );\n next;\n }\n _binop_prec.set( spell, op.get_precedence() );\n _path_terminators.set( op.get_kind(), true );\n if ( op.has_alias() ) {\n _path_terminators.set( op.get_alias(), true );\n }\n if ( op.requires_whitespace() ) {\n _need_ws.set( spell, true );\n }\n if ( op.is_right_associative() ) {\n _right_assoc.set( spell, true );\n }\n }\n }\n }\n\n method _init_path_terminators () {\n for ( let k in [\n "EOF",\n "COMMA",\n "RPAREN",\n "RBRACK",\n "QMARK",\n "COLON",\n ] ) {\n _path_terminators.set( k, true );\n }\n }\n\n method parse_top_level_terms ( src ) {\n let terms := [];\n let lexer := new lexer_class(\n src: src,\n allowed_operators: allowed_operators,\n );\n\n while ( true ) {\n let expr := self.parse_expression(lexer);\n terms.push(expr);\n if ( lexer.peek_kind() \u2261 "COMMA" ) {\n lexer.next_tok();\n next;\n }\n lexer.expect("EOF");\n last;\n }\n\n return terms;\n }\n\n method _trim ( s ) {\n return trim(s);\n }\n\n method parse_expression ( lx ) {\n return self.parse_ternary(lx);\n }\n\n method parse_ternary ( lx ) {\n let cond := self.parse_subexpression( lx, 1 );\n\n if ( lx.peek_kind() \u2261 "QMARK" ) {\n lx.next_tok();\n let then := self.parse_expression(lx); // ZZPath should use: self.parse_subexpression( lx, 1 )\n lx.expect("COLON");\n let els := self.parse_expression(lx);\n return { t: "ternary", c: cond, a: then, b: els };\n }\n if ( _allow_elvis and lx.peek_kind() \u2261 "ELVIS" ) {\n lx.next_tok();\n let fallback := self.parse_expression(lx);\n return { t: "elvis", c: cond, b: fallback };\n }\n\n return cond;\n }\n\n method parse_subexpression ( lx, min_prec ) {\n let left := self._parse_maybe_unary( lx, min_prec );\n\n while ( true ) {\n let spell := lx.peek{v};\n let op_prec := _binop_prec.get( spell, null );\n last if op_prec \u2261 null or op_prec < min_prec;\n\n let op := lx.next_tok;\n if ( _need_ws.exists( spell ) ) {\n if ( not ( op{ws_before} and op{ws_after} ) ) {\n die `Binary operator \'${spell}\' requires whitespace around it`;\n }\n }\n\n let next_min := _right_assoc.exists(spell) ? op_prec : op_prec + 1;\n let right := self.parse_subexpression( lx, next_min );\n left := { t: "bin", op: spell, l: left, r: right };\n }\n\n return left;\n }\n\n method _parse_maybe_unary ( lx, min_prec ) {\n let spell := lx.peek{v};\n let op_prec := _unop_prec.get( spell, null );\n if ( op_prec \u2262 null and op_prec >= min_prec ) {\n let op := lx.next_tok{v};\n let e := self._parse_maybe_unary( lx, op_prec );\n return { t: "un", op: op, e: e };\n }\n return self.parse_primary( lx );\n }\n\n method parse_primary ( lx ) {\n let k := lx.peek_kind;\n\n if ( k \u2261 "NUMBER" ) {\n return { t: "num", v: lx.next_tok(){v} };\n }\n if ( k \u2261 "STRING" ) {\n return { t: "str", v: lx.next_tok(){v} };\n }\n if ( k \u2261 "LPAREN" ) {\n lx.next_tok();\n let e := self.parse_expression(lx);\n lx.expect("RPAREN");\n return e;\n }\n\n if ( k \u2261 "NAME" and lx.peek_kind_n(1) \u2261 "LPAREN" ) {\n let name := lx.next_tok(){v};\n lx.expect("LPAREN");\n let args := [];\n if ( lx.peek_kind() \u2262 "RPAREN" ) {\n args.push( self.parse_expression(lx) );\n while ( lx.peek_kind() \u2261 "COMMA" ) {\n lx.next_tok();\n args.push( self.parse_expression(lx) );\n }\n }\n lx.expect("RPAREN");\n return { t: "fn", n: name, a: args };\n }\n\n return self._parse_path_expr(lx);\n }\n\n method _is_path_terminator ( k ) {\n return _path_terminators.exists(k);\n }\n\n method _parse_path_expr ( lx ) {\n let segs := [];\n\n if ( lx.peek_kind() \u2261 "SLASH_PATH" ) {\n lx.next_tok();\n let root := { k: "root", q: [] };\n segs.push(root);\n\n if ( lx.peek_kind() \u2261 "LBRACK" ) {\n root{q} := self._parse_qualifiers(lx);\n }\n\n if ( self._is_path_terminator( lx.peek_kind() ) ) {\n return { t: "path", s: segs };\n }\n }\n else if ( lx.peek_kind() \u2261 "LBRACK" ) {\n let seg := { k: "dot", q: self._parse_qualifiers(lx) };\n segs.push(seg);\n if ( self._is_path_terminator( lx.peek_kind() ) ) {\n return { t: "path", s: segs };\n }\n }\n\n if (\n lx.peek_kind() \u2262 "SLASH_PATH"\n and not self._is_path_terminator( lx.peek_kind() )\n ) {\n segs.push( self._parse_path_segment(lx) );\n }\n\n while ( lx.peek_kind() \u2261 "SLASH_PATH" ) {\n lx.next_tok();\n if ( lx.peek_kind() \u2261 "LBRACK" ) {\n let seg := { k: "star", q: [] };\n seg{q} := self._parse_qualifiers(lx);\n segs.push(seg);\n next;\n }\n segs.push( self._parse_path_segment(lx) );\n }\n\n return { t: "path", s: segs };\n }\n\n method _parse_path_segment ( lx ) {\n let k := lx.peek_kind();\n let seg := null;\n\n if ( k \u2261 "DOT" ) {\n lx.next_tok();\n seg := { k: "dot" };\n }\n else if ( k \u2261 "DOTDOT" ) {\n lx.next_tok();\n seg := { k: "parent" };\n }\n else if ( k \u2261 "DOTDOTSTAR" ) {\n lx.next_tok();\n seg := { k: "ancestors" };\n }\n else if ( k \u2261 "STAR_PATH" ) {\n lx.next_tok();\n seg := { k: "star" };\n }\n else if ( k \u2261 "STARSTAR" ) {\n lx.next_tok();\n seg := { k: "desc" };\n }\n else if ( k \u2261 "INDEX" ) {\n let i := lx.next_tok(){v};\n seg := { k: "index", i: i };\n }\n else if ( k \u2261 "NUMBER" ) {\n let i := lx.next_tok(){v};\n seg := { k: "index", i: i };\n }\n else if ( k \u2261 "NAME" and lx.peek_kind_n(1) \u2261 "LPAREN" ) {\n let name := lx.next_tok(){v};\n lx.expect("LPAREN");\n let args := [];\n if ( lx.peek_kind() \u2262 "RPAREN" ) {\n args.push( self.parse_expression(lx) );\n while ( lx.peek_kind() \u2261 "COMMA" ) {\n lx.next_tok();\n args.push( self.parse_expression(lx) );\n }\n }\n lx.expect("RPAREN");\n seg := { k: "fnseg", n: name, a: args };\n }\n else if ( k \u2261 "NAME" ) {\n let n := lx.next_tok(){v};\n seg := { k: "name", n: n };\n }\n else {\n die `Unexpected token in path segment: ${k}`;\n }\n\n if ( seg{k} \u2261 "name" and lx.peek_kind() \u2261 "INDEX" ) {\n seg{i} := lx.next_tok(){v};\n }\n\n seg{q} := self._parse_qualifiers(lx);\n return seg;\n }\n\n method _parse_qualifiers ( lx ) {\n let q := [];\n\n while ( lx.peek_kind() \u2261 "LBRACK" ) {\n lx.next_tok();\n let e := self.parse_expression(lx);\n lx.expect("RBRACK");\n q.push(e);\n }\n\n return q;\n }\n}\n';
|
|
46399
47343
|
virtualFiles["/modules/std/path/zz.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/path/zz - ZuzuScript-flavoured path selectors.\n\n=head1 SYNOPSIS\n\n from std/path/zz import ZZPath;\n\n let data := { users: [ { name: "Ada" } ] };\n say( ( new ZZPath( path: "/users/#0/name" ) ).first(data) );\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by all implementations of ZuzuScript.\n\n=head1 DESCRIPTION\n\nThis module provides the public C<ZZPath> class. It currently reuses the\nZPath traversal, parser, lexer, assignment, and reference\nmachinery while routing expression operators through\nC<std/path/zz/operators> and expression functions through\nC<std/path/zz/functions>.\n\n=head1 EXPORTS\n\n=head2 Classes\n\n=over\n\n=item C<ZZEvaluator>\n\nEvaluator class that supplies ZZPath operators and functions.\n\n=over\n\n=item C<< evaluator.operator_definitions() >>\n\nParameters: none. Returns: C<Array>. Returns ZZPath operator\ndefinitions.\n\n=item C<< evaluator.function_definitions() >>\n\nParameters: none. Returns: C<Array>. Returns ZZPath function\ndefinitions.\n\n=back\n\n=item C<< ZZPath({ path: String }) >>\n\nConstructs a ZZPath query object. Returns: C<ZZPath>. Inherits the\npublic query, assignment, and reference methods from C<ZPath>.\n\n=over\n\n=item C<< path.get_evaluator() >>\n\nParameters: none. Returns: C<ZZEvaluator>. Returns the evaluator used\nfor this path.\n\n=item C<< node.find(path) >>\n\nC<ZZPath> inherits from C<ZPath>, so a C<ZZPath> object can be passed to\nC<std/path/z/node> C<Node.find()>.\n\n=back\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/path/zz >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nfrom std/path/z import ZPath;\nfrom std/path/z/evaluate import Evaluator as ZEvaluator;\n\nclass ZZEvaluator extends ZEvaluator {\n method operator_definitions () {\n from std/path/zz/operators import STANDARD_OPERATORS;\n return STANDARD_OPERATORS;\n }\n\n method function_definitions () {\n from std/path/zz/functions import STANDARD_FUNCTIONS;\n return STANDARD_FUNCTIONS;\n }\n}\n\nclass ZZPath extends ZPath {\n method get_evaluator () {\n return new ZZEvaluator();\n }\n}\n';
|
|
46400
47344
|
virtualFiles["/modules/std/path/zz/functions.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/path/zz/functions - Function definitions for ZZPath expressions.\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by all implementations of ZuzuScript.\n\n=head1 DESCRIPTION\n\nThis module extends the base ZPath function table with\nZuzuScript-flavoured path expression helpers.\n\n=head1 EXPORTS\n\n=head2 Constants\n\n=over\n\n=item C<STANDARD_FUNCTION_NAMES>\n\nType: C<Array>. Names of inherited ZPath functions available to ZZPath.\n\n=item C<STANDARD_FUNCTIONS>\n\nType: C<Array>. Complete ZZPath function definition table.\n\n=back\n\n=head2 Functions\n\n=over\n\n=item C<< first_arg_node(name, ev, ctx, args) >>\n\nParameters: function name, evaluator, context, and argument AST nodes.\nReturns: C<Node> or C<null>. Resolves the first argument or current\ncontext node.\n\n=item C<< first_number_arg(name, ev, ctx, args) >>, C<< nth_number_arg(name, ev, ctx, args, i) >>\n\nParameters: function name, evaluator, context, arguments, and optional\nindex. Returns: C<Number>. Resolves an argument as a number.\n\n=item C<< first_string_arg(name, ev, ctx, args) >>, C<< nth_string_arg(name, ev, ctx, args, i) >>\n\nParameters: function name, evaluator, context, arguments, and optional\nindex. Returns: C<String>. Resolves an argument as a string.\n\n=item C<< nth_value_arg(name, ev, ctx, args, i) >>\n\nParameters: function name, evaluator, context, arguments, and index.\nReturns: value. Resolves an argument as a primitive value.\n\n=item C<< nth_array_arg(name, ev, ctx, args, i) >>\n\nParameters: function name, evaluator, context, arguments, and index.\nReturns: C<Array>. Resolves an argument as an array value.\n\n=item C<< number_args(ev, ctx, args) >>\n\nParameters: evaluator, context, and argument AST nodes. Returns:\nC<Array>. Resolves all arguments as numbers.\n\n=item C<< first_arg_value(name, ev, ctx, args) >>\n\nParameters: function name, evaluator, context, and arguments. Returns:\nvalue. Resolves the first argument as a primitive value.\n\n=item C<< z_function(spelling) >>\n\nParameters: C<spelling> is a base ZPath function name. Returns:\nC<Function>. Returns the inherited function implementation.\n\n=item C<< string_index_of(funk, ev, ast, ctx, args) >>\n\nParameters: standard ZPath function callback arguments. Returns:\nC<Array>. Implements string C<index-of>.\n\n=item C<< string_rindex(funk, ev, ast, ctx, args) >>\n\nParameters: standard ZPath function callback arguments. Returns:\nC<Array>. Implements string reverse-index lookup.\n\n=item C<< defined_function(funk, ev, ast, ctx, args) >>\n\nParameters: standard ZPath function callback arguments. Returns:\nC<Array>. Implements defined-value testing.\n\n=item C<< empty_function(funk, ev, ast, ctx, args) >>\n\nParameters: standard ZPath function callback arguments. Returns:\nC<Array>. Implements empty-value testing.\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/path/zz/functions >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nfrom std/path/z/functions import Func, STANDARD_FUNCTIONS as Z_STANDARD_FUNCTIONS;\n\n\nconst STANDARD_FUNCTION_NAMES := [\n "true",\n "false",\n "null",\n "tag",\n "url",\n "local-name",\n "key",\n "value",\n "index",\n "count",\n "is-first",\n "is-last",\n "next",\n "prev",\n];\n\nfunction first_arg_node ( name, ev, ctx, args ) {\n if ( args.length() = 0 ) {\n return ctx.nodeset.get( 0, null );\n }\n if ( args.length() = 1 ) {\n const got := ev.eval_expr( args[0], ev.nested_ctx( ctx ) );\n return got.get( 0, null );\n }\n die `Too many arguments for ${name}()`;\n}\n\nfunction first_number_arg ( name, ev, ctx, args ) {\n const node := first_arg_node( name, ev, ctx, args );\n return ev.to_number(node) ?: 0;\n}\n\nfunction nth_number_arg ( name, ev, ctx, args, i ) {\n die `Not enough arguments for ${name}()` if args.length() <= i;\n const got := ev.eval_expr( args[i], ev.nested_ctx( ctx ) );\n return ev.to_number( got.get( 0, null ) ) ?: 0;\n}\n\nfunction nth_string_arg ( name, ev, ctx, args, i ) {\n die `Not enough arguments for ${name}()` if args.length() <= i;\n const got := ev.eval_expr( args[i], ev.nested_ctx( ctx ) );\n const value := ev.to_string( got.get( 0, null ) );\n return value \u2261 null ? "" : "" _ value;\n}\n\nfunction nth_value_arg ( name, ev, ctx, args, i ) {\n die `Not enough arguments for ${name}()` if args.length() <= i;\n const got := ev.eval_expr( args[i], ev.nested_ctx( ctx ) );\n const node := got.get( 0, null );\n return node \u2261 null ? null : node.primitive_value();\n}\n\nfunction nth_array_arg ( name, ev, ctx, args, i ) {\n die `Not enough arguments for ${name}()` if args.length() <= i;\n const got := ev.eval_expr( args[i], ev.nested_ctx( ctx ) );\n if ( got.length() = 1 ) {\n const one := got[0].primitive_value();\n return one if one instanceof Array;\n }\n return got.map( fn node \u2192 node.primitive_value() );\n}\n\nfunction number_args ( ev, ctx, args ) {\n let nums := [];\n if ( args.length() = 0 ) {\n for ( let node in ctx.nodeset ) {\n const value := ev.to_number(node);\n nums.push(value) if value instanceof Number;\n }\n return nums;\n }\n for ( let arg in args ) {\n const got := ev.eval_expr( arg, ev.nested_ctx( ctx ) );\n for ( let node in got ) {\n const value := ev.to_number(node);\n nums.push(value) if value instanceof Number;\n }\n }\n return nums;\n}\n\nfunction first_string_arg ( name, ev, ctx, args ) {\n const node := first_arg_node( name, ev, ctx, args );\n const value := ev.to_string(node);\n return value \u2261 null ? "" : "" _ value;\n}\n\nfunction first_arg_value ( name, ev, ctx, args ) {\n const node := first_arg_node( name, ev, ctx, args );\n return node \u2261 null ? null : node.primitive_value();\n}\n\nfunction z_function ( spelling ) {\n const func := Z_STANDARD_FUNCTIONS.first( fn f \u2192 f.has_name(spelling) );\n die `std/path/z/functions is missing ${spelling}()` if func \u2261 null;\n return func;\n}\n\nfunction string_index_of ( funk, ev, ast, ctx, args ) {\n from std/string import index;\n die "Too many arguments for index-of()" if args.length() > 3;\n if ( args.length() = 2 ) {\n return funk.wrap( index(\n nth_string_arg( "index-of", ev, ctx, args, 0 ),\n nth_string_arg( "index-of", ev, ctx, args, 1 ),\n ) );\n }\n return funk.wrap( index(\n nth_string_arg( "index-of", ev, ctx, args, 0 ),\n nth_string_arg( "index-of", ev, ctx, args, 1 ),\n nth_number_arg( "index-of", ev, ctx, args, 2 ),\n ) );\n}\n\nfunction string_rindex ( funk, ev, ast, ctx, args ) {\n from std/string import rindex;\n const name := funk.get_spelling;\n die `Too many arguments for ${name}()` if args.length() > 3;\n if ( args.length() = 2 ) {\n return funk.wrap( rindex(\n nth_string_arg( name, ev, ctx, args, 0 ),\n nth_string_arg( name, ev, ctx, args, 1 ),\n ) );\n }\n return funk.wrap( rindex(\n nth_string_arg( name, ev, ctx, args, 0 ),\n nth_string_arg( name, ev, ctx, args, 1 ),\n nth_number_arg( name, ev, ctx, args, 2 ),\n ) );\n}\n\nfunction defined_function ( funk, ev, ast, ctx, args ) {\n const node := first_arg_node( "defined", ev, ctx, args );\n return funk.wrap( node \u2262 null and node.primitive_value() \u2262 null );\n}\n\nfunction empty_function ( funk, ev, ast, ctx, args ) {\n const value := first_arg_value( "empty", ev, ctx, args );\n return funk.wrap( true ) if value \u2261 null;\n\n if (\n value instanceof Array or\n value instanceof Bag or\n value instanceof Set or\n value instanceof Dict or\n value instanceof PairList\n ) {\n return funk.wrap( value.length() = 0 );\n }\n\n die `empty() expects a Collection or null, got ${typeof value}`;\n}\n\n// Start with a base of functions inherited from ZPath:\nconst STANDARD_FUNCTIONS := STANDARD_FUNCTION_NAMES.map( fn n \u2192 z_function(n) );\n\n// Add equivalents for ZuzuScript word-like unary operators:\nSTANDARD_FUNCTIONS.push(\n new Func(\n spelling: "abs",\n f: function ( funk, ev, ast, ctx, args ) {\n return funk.wrap( abs first_number_arg( "abs", ev, ctx, args ) );\n },\n ),\n new Func(\n spelling: "floor",\n f: function ( funk, ev, ast, ctx, args ) {\n return funk.wrap( floor first_number_arg( "floor", ev, ctx, args ) );\n },\n ),\n new Func(\n spelling: "ceil",\n f: function ( funk, ev, ast, ctx, args ) {\n return funk.wrap( ceil first_number_arg( "ceil", ev, ctx, args ) );\n },\n ),\n new Func(\n spelling: "round",\n f: function ( funk, ev, ast, ctx, args ) {\n return funk.wrap( round first_number_arg( "round", ev, ctx, args ) );\n },\n ),\n new Func(\n spelling: "int",\n f: function ( funk, ev, ast, ctx, args ) {\n return funk.wrap( int first_number_arg( "int", ev, ctx, args ) );\n },\n ),\n new Func(\n spelling: "sqrt",\n f: function ( funk, ev, ast, ctx, args ) {\n return funk.wrap( sqrt first_number_arg( "sqrt", ev, ctx, args ) );\n },\n ),\n new Func(\n spelling: "uc",\n f: function ( funk, ev, ast, ctx, args ) {\n return funk.wrap( uc first_string_arg( "uc", ev, ctx, args ) );\n },\n ),\n new Func(\n spelling: "lc",\n f: function ( funk, ev, ast, ctx, args ) {\n return funk.wrap( lc first_string_arg( "lc", ev, ctx, args ) );\n },\n ),\n new Func(\n spelling: "length",\n f: function ( funk, ev, ast, ctx, args ) {\n return funk.wrap( length first_string_arg( "length", ev, ctx, args ) );\n },\n ),\n new Func(\n spelling: "not",\n f: function ( funk, ev, ast, ctx, args ) {\n const node := first_arg_node( "not", ev, ctx, args );\n return funk.wrap( not ev.truthy(node) );\n },\n ),\n new Func(\n spelling: "typeof",\n f: function ( funk, ev, ast, ctx, args ) {\n const node := first_arg_node( "typeof", ev, ctx, args );\n const value := node \u2261 null ? null : node.primitive_value();\n return funk.wrap( typeof value );\n },\n ),\n new Func(\n spelling: "defined",\n f: defined_function,\n ),\n new Func(\n spelling: "empty",\n f: empty_function,\n ),\n);\n\n// Functions from std/internals:\nSTANDARD_FUNCTIONS.push(\n new Func(\n spelling: "string",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/internals import to_String;\n return funk.wrap( to_String( first_arg_value(\n "string",\n ev,\n ctx,\n args,\n ) ) );\n },\n ),\n new Func(\n spelling: "number",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/internals import to_Number;\n return funk.wrap( to_Number( first_arg_value(\n "number",\n ev,\n ctx,\n args,\n ) ) );\n },\n ),\n new Func(\n spelling: "boolean",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/internals import to_Boolean;\n return funk.wrap( to_Boolean( first_arg_value(\n "boolean",\n ev,\n ctx,\n args,\n ) ) );\n },\n ),\n new Func(\n spelling: "regexp",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/internals import to_Regexp;\n return funk.wrap( to_Regexp( first_arg_value(\n "regexp",\n ev,\n ctx,\n args,\n ) ) );\n },\n ),\n);\n\n// Functions from std/math:\nSTANDARD_FUNCTIONS.push(\n new Func(\n spelling: "sum",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/math import Math;\n return funk.wrap( Math.sum( number_args( ev, ctx, args ) ) );\n },\n ),\n new Func(\n spelling: "min",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/math import Math;\n return funk.wrap( Math.min( number_args( ev, ctx, args ) ) );\n },\n ),\n new Func(\n spelling: "max",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/math import Math;\n return funk.wrap( Math.max( number_args( ev, ctx, args ) ) );\n },\n ),\n new Func(\n spelling: "clamp",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/math import Math;\n die "Too many arguments for clamp()" if args.length() > 3;\n return funk.wrap( Math.clamp(\n nth_number_arg( "clamp", ev, ctx, args, 0 ),\n nth_number_arg( "clamp", ev, ctx, args, 1 ),\n nth_number_arg( "clamp", ev, ctx, args, 2 ),\n ) );\n },\n ),\n);\n\n// Functions from std/string:\nSTANDARD_FUNCTIONS.push(\n new Func(\n spelling: "substr",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import substr;\n die "Too many arguments for substr()" if args.length() > 3;\n if ( args.length() = 2 ) {\n return funk.wrap( substr(\n nth_string_arg( "substr", ev, ctx, args, 0 ),\n nth_number_arg( "substr", ev, ctx, args, 1 ),\n ) );\n }\n return funk.wrap( substr(\n nth_string_arg( "substr", ev, ctx, args, 0 ),\n nth_number_arg( "substr", ev, ctx, args, 1 ),\n nth_number_arg( "substr", ev, ctx, args, 2 ),\n ) );\n },\n ),\n new Func(\n spelling: "index-of",\n f: string_index_of,\n ),\n new Func(\n spelling: "rindex",\n f: string_rindex,\n ),\n new Func(\n spelling: "last-index-of",\n f: string_rindex,\n ),\n new Func(\n spelling: "contains",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import contains;\n die "Too many arguments for contains()" if args.length() > 2;\n return funk.wrap( contains(\n nth_string_arg( "contains", ev, ctx, args, 0 ),\n nth_string_arg( "contains", ev, ctx, args, 1 ),\n ) );\n },\n ),\n new Func(\n spelling: "chr",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import chr;\n die "Too many arguments for chr()" if args.length() > 1;\n return funk.wrap( chr( nth_number_arg(\n "chr",\n ev,\n ctx,\n args,\n 0,\n ) ) );\n },\n ),\n new Func(\n spelling: "ord",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import ord;\n die "Too many arguments for ord()" if args.length() > 2;\n if ( args.length() = 1 ) {\n return funk.wrap( ord( nth_string_arg(\n "ord",\n ev,\n ctx,\n args,\n 0,\n ) ) );\n }\n return funk.wrap( ord(\n nth_string_arg( "ord", ev, ctx, args, 0 ),\n nth_number_arg( "ord", ev, ctx, args, 1 ),\n ) );\n },\n ),\n new Func(\n spelling: "replace",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import replace;\n die "Too many arguments for replace()" if args.length() > 4;\n if ( args.length() = 3 ) {\n return funk.wrap( replace(\n nth_string_arg( "replace", ev, ctx, args, 0 ),\n nth_value_arg( "replace", ev, ctx, args, 1 ),\n nth_string_arg( "replace", ev, ctx, args, 2 ),\n ) );\n }\n return funk.wrap( replace(\n nth_string_arg( "replace", ev, ctx, args, 0 ),\n nth_value_arg( "replace", ev, ctx, args, 1 ),\n nth_string_arg( "replace", ev, ctx, args, 2 ),\n nth_string_arg( "replace", ev, ctx, args, 3 ),\n ) );\n },\n ),\n new Func(\n spelling: "search",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import search;\n die "Too many arguments for search()" if args.length() > 3;\n if ( args.length() = 2 ) {\n return funk.wrap( search(\n nth_string_arg( "search", ev, ctx, args, 0 ),\n nth_value_arg( "search", ev, ctx, args, 1 ),\n ) );\n }\n return funk.wrap( search(\n nth_string_arg( "search", ev, ctx, args, 0 ),\n nth_value_arg( "search", ev, ctx, args, 1 ),\n nth_string_arg( "search", ev, ctx, args, 2 ),\n ) );\n },\n ),\n new Func(\n spelling: "starts_with",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import starts_with;\n die "Too many arguments for starts_with()" if args.length() > 2;\n return funk.wrap( starts_with(\n nth_string_arg( "starts_with", ev, ctx, args, 0 ),\n nth_string_arg( "starts_with", ev, ctx, args, 1 ),\n ) );\n },\n ),\n new Func(\n spelling: "ends_with",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import ends_with;\n die "Too many arguments for ends_with()" if args.length() > 2;\n return funk.wrap( ends_with(\n nth_string_arg( "ends_with", ev, ctx, args, 0 ),\n nth_string_arg( "ends_with", ev, ctx, args, 1 ),\n ) );\n },\n ),\n new Func(\n spelling: "matches",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import matches;\n die "Too many arguments for matches()" if args.length() > 3;\n if ( args.length() = 2 ) {\n return funk.wrap( matches(\n nth_string_arg( "matches", ev, ctx, args, 0 ),\n nth_value_arg( "matches", ev, ctx, args, 1 ),\n ) );\n }\n return funk.wrap( matches(\n nth_string_arg( "matches", ev, ctx, args, 0 ),\n nth_value_arg( "matches", ev, ctx, args, 1 ),\n nth_string_arg( "matches", ev, ctx, args, 2 ),\n ) );\n },\n ),\n new Func(\n spelling: "pattern_to_regexp",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import pattern_to_regexp;\n die "Too many arguments for pattern_to_regexp()"\n if args.length() > 2;\n if ( args.length() = 1 ) {\n return funk.wrap( pattern_to_regexp(\n nth_string_arg( "pattern_to_regexp", ev, ctx, args, 0 ),\n ) );\n }\n return funk.wrap( pattern_to_regexp(\n nth_string_arg( "pattern_to_regexp", ev, ctx, args, 0 ),\n nth_value_arg( "pattern_to_regexp", ev, ctx, args, 1 ),\n ) );\n },\n ),\n new Func(\n spelling: "quotemeta",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import quotemeta;\n die "Too many arguments for quotemeta()" if args.length() > 1;\n return funk.wrap( quotemeta(\n nth_string_arg( "quotemeta", ev, ctx, args, 0 ),\n ) );\n },\n ),\n new Func(\n spelling: "sprint",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import sprint;\n die "Not enough arguments for sprint()" if args.length() = 0;\n die "Too many arguments for sprint()" if args.length() > 8;\n\n const fmt := nth_string_arg( "sprint", ev, ctx, args, 0 );\n if ( args.length() = 1 ) {\n return funk.wrap( sprint(fmt) );\n }\n if ( args.length() = 2 ) {\n return funk.wrap( sprint(\n fmt,\n nth_value_arg( "sprint", ev, ctx, args, 1 ),\n ) );\n }\n if ( args.length() = 3 ) {\n return funk.wrap( sprint(\n fmt,\n nth_value_arg( "sprint", ev, ctx, args, 1 ),\n nth_value_arg( "sprint", ev, ctx, args, 2 ),\n ) );\n }\n if ( args.length() = 4 ) {\n return funk.wrap( sprint(\n fmt,\n nth_value_arg( "sprint", ev, ctx, args, 1 ),\n nth_value_arg( "sprint", ev, ctx, args, 2 ),\n nth_value_arg( "sprint", ev, ctx, args, 3 ),\n ) );\n }\n if ( args.length() = 5 ) {\n return funk.wrap( sprint(\n fmt,\n nth_value_arg( "sprint", ev, ctx, args, 1 ),\n nth_value_arg( "sprint", ev, ctx, args, 2 ),\n nth_value_arg( "sprint", ev, ctx, args, 3 ),\n nth_value_arg( "sprint", ev, ctx, args, 4 ),\n ) );\n }\n if ( args.length() = 6 ) {\n return funk.wrap( sprint(\n fmt,\n nth_value_arg( "sprint", ev, ctx, args, 1 ),\n nth_value_arg( "sprint", ev, ctx, args, 2 ),\n nth_value_arg( "sprint", ev, ctx, args, 3 ),\n nth_value_arg( "sprint", ev, ctx, args, 4 ),\n nth_value_arg( "sprint", ev, ctx, args, 5 ),\n ) );\n }\n if ( args.length() = 7 ) {\n return funk.wrap( sprint(\n fmt,\n nth_value_arg( "sprint", ev, ctx, args, 1 ),\n nth_value_arg( "sprint", ev, ctx, args, 2 ),\n nth_value_arg( "sprint", ev, ctx, args, 3 ),\n nth_value_arg( "sprint", ev, ctx, args, 4 ),\n nth_value_arg( "sprint", ev, ctx, args, 5 ),\n nth_value_arg( "sprint", ev, ctx, args, 6 ),\n ) );\n }\n return funk.wrap( sprint(\n fmt,\n nth_value_arg( "sprint", ev, ctx, args, 1 ),\n nth_value_arg( "sprint", ev, ctx, args, 2 ),\n nth_value_arg( "sprint", ev, ctx, args, 3 ),\n nth_value_arg( "sprint", ev, ctx, args, 4 ),\n nth_value_arg( "sprint", ev, ctx, args, 5 ),\n nth_value_arg( "sprint", ev, ctx, args, 6 ),\n nth_value_arg( "sprint", ev, ctx, args, 7 ),\n ) );\n },\n ),\n new Func(\n spelling: "split",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import split;\n die "Too many arguments for split()" if args.length() > 3;\n if ( args.length() = 2 ) {\n return funk.wrap( split(\n nth_string_arg( "split", ev, ctx, args, 0 ),\n nth_value_arg( "split", ev, ctx, args, 1 ),\n ) );\n }\n return funk.wrap( split(\n nth_string_arg( "split", ev, ctx, args, 0 ),\n nth_value_arg( "split", ev, ctx, args, 1 ),\n nth_number_arg( "split", ev, ctx, args, 2 ),\n ) );\n },\n ),\n new Func(\n spelling: "join",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import join;\n die "Too many arguments for join()" if args.length() > 2;\n return funk.wrap( join(\n nth_string_arg( "join", ev, ctx, args, 0 ),\n nth_array_arg( "join", ev, ctx, args, 1 ),\n ) );\n },\n ),\n new Func(\n spelling: "trim",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import trim;\n die "Too many arguments for trim()" if args.length() > 1;\n return funk.wrap( trim( first_string_arg(\n "trim",\n ev,\n ctx,\n args,\n ) ) );\n },\n ),\n new Func(\n spelling: "pad",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import pad;\n die "Too many arguments for pad()" if args.length() > 4;\n if ( args.length() = 2 ) {\n return funk.wrap( pad(\n nth_string_arg( "pad", ev, ctx, args, 0 ),\n nth_number_arg( "pad", ev, ctx, args, 1 ),\n ) );\n }\n if ( args.length() = 3 ) {\n return funk.wrap( pad(\n nth_string_arg( "pad", ev, ctx, args, 0 ),\n nth_number_arg( "pad", ev, ctx, args, 1 ),\n nth_string_arg( "pad", ev, ctx, args, 2 ),\n ) );\n }\n return funk.wrap( pad(\n nth_string_arg( "pad", ev, ctx, args, 0 ),\n nth_number_arg( "pad", ev, ctx, args, 1 ),\n nth_string_arg( "pad", ev, ctx, args, 2 ),\n nth_string_arg( "pad", ev, ctx, args, 3 ),\n ) );\n },\n ),\n new Func(\n spelling: "chomp",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import chomp;\n die "Too many arguments for chomp()" if args.length() > 1;\n return funk.wrap( chomp( first_string_arg(\n "chomp",\n ev,\n ctx,\n args,\n ) ) );\n },\n ),\n new Func(\n spelling: "title",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import title;\n die "Too many arguments for title()" if args.length() > 1;\n return funk.wrap( title( first_string_arg(\n "title",\n ev,\n ctx,\n args,\n ) ) );\n },\n ),\n new Func(\n spelling: "snake",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import snake;\n die "Too many arguments for snake()" if args.length() > 1;\n return funk.wrap( snake( first_string_arg(\n "snake",\n ev,\n ctx,\n args,\n ) ) );\n },\n ),\n new Func(\n spelling: "kebab",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import kebab;\n die "Too many arguments for kebab()" if args.length() > 1;\n return funk.wrap( kebab( first_string_arg(\n "kebab",\n ev,\n ctx,\n args,\n ) ) );\n },\n ),\n new Func(\n spelling: "camel",\n f: function ( funk, ev, ast, ctx, args ) {\n from std/string import camel;\n die "Too many arguments for camel()" if args.length() > 1;\n return funk.wrap( camel( first_string_arg(\n "camel",\n ev,\n ctx,\n args,\n ) ) );\n },\n ),\n);\n';
|
|
46401
|
-
virtualFiles["/modules/std/path/zz/operators.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/path/zz/operators - Operator definitions for ZZPath expressions.\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by all implementations of ZuzuScript.\n\n=head1 DESCRIPTION\n\nThis module extends the base ZPath operator model with\nZuzuScript-flavoured expression operators.\n\n=head1 EXPORTS\n\n=head2 Classes\n\n=over\n\n=item C<Operator>\n\nZZPath operator class extending C<std/path/z/operators> C<Operator>.\n\n=back\n\n=head2 Functions\n\n=over\n\n=item C<< string_operand(ev, ctx, expr) >>, C<< string_operands(ev, ctx, left, right) >>\n\nParameters: evaluator, context, and expression AST nodes. Returns:\nC<String> or C<Array>. Evaluates one or two operands as strings.\n\n=item C<< first_eval_value(values) >>, C<< primitive_eval_value(values) >>\n\nParameters: C<values> is an evaluated node array. Returns: value.\nExtracts the first or primitive value used by ZZPath operators.\n\n=item C<< collection_operand(ev, ctx, expr) >>\n\nParameters: evaluator, context, and expression AST node. Returns:\ncollection value. Evaluates an operand for collection operators.\n\n=item C<< builtin_can(value, method_name) >>\n\nParameters: C<value> is any value and C<method_name> is a method name.\nReturns: C<Boolean>. Tests whether built-in values support a method.\n\n=back\n\n=head2 Constants\n\n=over\n\n=item C<STANDARD_OPERATORS>\n\nType: C<Array>. Complete ZZPath operator definition table.\n\n=item C<logical_negation>, C<logical_and>, C<logical_nand>, C<logical_xor>, C<logical_or>\n\nType: C<Function>. Logical operator implementations.\n\n=item C<numeric_power>, C<numeric_multiplication>, C<numeric_division>, C<numeric_modulus>, C<numeric_addition>, C<numeric_subtraction>, C<numeric_equality>, C<numeric_inequality>, C<numeric_less_than>, C<numeric_greater_than>, C<numeric_less_than_or_equal>, C<numeric_greater_than_or_equal>, C<numeric_compare>\n\nType: C<Function>. Numeric operator implementations.\n\n=item C<string_concatenation>, C<string_equality>, C<string_inequality>, C<string_greater_than>, C<string_greater_than_or_equal>, C<string_less_than>, C<string_less_than_or_equal>, C<string_compare>, C<string_equality_insensitive>, C<string_inequality_insensitive>, C<string_greater_than_insensitive>, C<string_greater_than_or_equal_insensitive>, C<string_less_than_insensitive>, C<string_less_than_or_equal_insensitive>, C<string_compare_insensitive>\n\nType: C<Function>. String operator implementations.\n\n=item C<regexp_match>, C<bitwise_and>, C<bitwise_xor>, C<bitwise_or>, C<set_union>, C<set_intersection>, C<set_difference>, C<collection_membership>, C<collection_non_membership>, C<set_subsetof>, C<set_supersetof>, C<set_equivalentof>, C<type_aware_equality>, C<type_aware_inequality>, C<object_can>\n\nType: C<Function>. Regular expression, bitwise, collection, type-aware,\nand object capability operator implementations.\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/path/zz/operators >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nfrom std/path/z/operators import Operator as ZOperator;\n\n\nclass Operator extends ZOperator;\n\nconst logical_negation := function ( op, ev, ast, ctx, expr ) {\n const got := ev.eval_expr( expr, ev.nested_ctx( ctx ) );\n const value := got.length() > 0 ? got[0] : null;\n return op.wrap( not ev.truthy(value) );\n};\n\nconst numeric_power := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val ** right_val );\n};\n\nconst numeric_multiplication := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val \xD7 right_val );\n};\n\nconst numeric_division := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val \xF7 right_val );\n};\n\nconst numeric_modulus := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val mod right_val );\n};\n\nconst numeric_addition := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val + right_val );\n};\n\nconst numeric_subtraction := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val - right_val );\n};\n\nconst numeric_equality := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val = right_val );\n};\n\nconst numeric_inequality := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val \u2260 right_val );\n};\n\nconst numeric_less_than := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val < right_val );\n};\n\nconst numeric_greater_than := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val > right_val );\n};\n\nconst numeric_less_than_or_equal := function (\n op,\n ev,\n ast,\n ctx,\n left,\n right,\n) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val \u2264 right_val );\n};\n\nconst numeric_greater_than_or_equal := function (\n op,\n ev,\n ast,\n ctx,\n left,\n right,\n) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val \u2265 right_val );\n};\n\nconst numeric_compare := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val <=> right_val );\n};\n\nfunction string_operand ( ev, ctx, expr ) {\n const result := ev.eval_expr( expr, ev.nested_ctx( ctx ) );\n return "" unless result.length;\n const value := ev.to_string( result[0] );\n return value \u2261 null ? "" : "" _ value;\n}\n\nfunction string_operands ( ev, ctx, left, right ) {\n return [\n string_operand( ev, ctx, left ),\n string_operand( ev, ctx, right ),\n ];\n}\n\nconst string_concatenation := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] _ values[1] );\n};\n\nconst string_equality := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] eq values[1] );\n};\n\nconst string_inequality := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] ne values[1] );\n};\n\nconst string_greater_than := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] gt values[1] );\n};\n\nconst string_greater_than_or_equal := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] ge values[1] );\n};\n\nconst string_less_than := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] lt values[1] );\n};\n\nconst string_less_than_or_equal := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] le values[1] );\n};\n\nconst string_compare := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] cmp values[1] );\n};\n\nconst string_equality_insensitive := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val eq right_val );\n};\n\nconst string_inequality_insensitive := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val ne right_val );\n};\n\nconst string_greater_than_insensitive := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val gt right_val );\n};\n\nconst string_greater_than_or_equal_insensitive := function (\n op,\n ev,\n ast,\n ctx,\n left,\n right,\n) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val ge right_val );\n};\n\nconst string_less_than_insensitive := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val lt right_val );\n};\n\nconst string_less_than_or_equal_insensitive := function (\n op,\n ev,\n ast,\n ctx,\n left,\n right,\n) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val le right_val );\n};\n\nconst string_compare_insensitive := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val cmp right_val );\n};\n\nconst regexp_match := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] ~ values[1] );\n};\n\nconst bitwise_and := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val & right_val );\n};\n\nconst bitwise_xor := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val ^ right_val );\n};\n\nconst bitwise_or := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val | right_val );\n};\n\nfunction first_eval_value ( values ) {\n return values.length() > 0 ? values[0] : null;\n}\n\nfunction primitive_eval_value ( values ) {\n const first := first_eval_value(values);\n return first \u2261 null ? null : first.primitive_value();\n}\n\nfunction collection_operand ( ev, ctx, expr ) {\n const values := ev.eval_expr( expr, ev.nested_ctx( ctx ) );\n if ( values.length() = 1 ) {\n return values[0].primitive_value();\n }\n return values.map( fn value \u2192 value.primitive_value() );\n}\n\nconst logical_and := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n if ( ev.truthy( first_eval_value(left_vals) ) ) {\n return ev.eval_expr( right, ev.nested_ctx( ctx ) );\n }\n return op.wrap(false);\n};\n\nconst logical_nand := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n if ( not ev.truthy( first_eval_value(left_vals) ) ) {\n return op.wrap(true);\n }\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n return op.wrap( ev.truthy( first_eval_value(right_vals) ) ? false : true );\n};\n\nconst logical_xor := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n const left_truth := ev.truthy( first_eval_value(left_vals) );\n const right_truth := ev.truthy( first_eval_value(right_vals) );\n return op.wrap( ( left_truth xor right_truth ) ? true : false );\n};\n\nconst logical_or := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n if ( ev.truthy( first_eval_value(left_vals) ) ) {\n return op.wrap(true);\n }\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n return op.wrap( ev.truthy( first_eval_value(right_vals) ) ? true : false );\n};\n\nconst set_union := function ( op, ev, ast, ctx, left, right ) {\n const left_val := collection_operand( ev, ctx, left );\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val union right_val );\n};\n\nconst set_intersection := function ( op, ev, ast, ctx, left, right ) {\n const left_val := collection_operand( ev, ctx, left );\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val intersection right_val );\n};\n\nconst set_difference := function ( op, ev, ast, ctx, left, right ) {\n const left_val := collection_operand( ev, ctx, left );\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val \u2216 right_val );\n};\n\nconst collection_membership := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const left_val := primitive_eval_value(left_vals);\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val in right_val );\n};\n\nconst collection_non_membership := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const left_val := primitive_eval_value(left_vals);\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val \u2209 right_val );\n};\n\nconst set_subsetof := function ( op, ev, ast, ctx, left, right ) {\n const left_val := collection_operand( ev, ctx, left );\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val subsetof right_val );\n};\n\nconst set_supersetof := function ( op, ev, ast, ctx, left, right ) {\n const left_val := collection_operand( ev, ctx, left );\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val supersetof right_val );\n};\n\nconst set_equivalentof := function ( op, ev, ast, ctx, left, right ) {\n const left_val := collection_operand( ev, ctx, left );\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val equivalentof right_val );\n};\n\nconst type_aware_equality := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n return op.wrap( ev.equals(\n first_eval_value(left_vals),\n first_eval_value(right_vals),\n ) );\n};\n\nconst type_aware_inequality := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n return op.wrap( not ev.equals(\n first_eval_value(left_vals),\n first_eval_value(right_vals),\n ) );\n};\n\nfunction builtin_can ( value, method_name ) {\n return false if value \u2261 null\n or method_name \u2261 null\n or method_name eq "";\n\n if ( value instanceof Array or value instanceof Bag or value instanceof Set ) {\n return method_name in [\n "length",\n "empty",\n "contains",\n "push",\n "to_Array",\n "to_Bag",\n "to_Set",\n ];\n }\n if ( value instanceof Dict or value instanceof PairList ) {\n return method_name in [\n "length",\n "empty",\n "exists",\n "keys",\n "values",\n "to_Array",\n ];\n }\n if ( value instanceof String or value instanceof BinaryString ) {\n return method_name in [ "length" ];\n }\n return false;\n}\n\nconst object_can := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n const left_val := primitive_eval_value(left_vals);\n const right_val := primitive_eval_value(right_vals);\n return op.wrap(\n ( left_val can (right_val) ) or builtin_can( left_val, right_val )\n );\n};\n\nconst STANDARD_OPERATORS := [\n new Operator(\n spelling: "?:",\n kind: "ELVIS",\n precedence: 1,\n lex_ignore: true,\n ),\n\n new Operator(\n spelling: "+",\n kind: "UPLUS",\n unary: true,\n precedence: 20,\n f: function ( op, ev, ast, ctx, expr ) {\n const value := op._handle_numeric_operand( ev, ctx, expr );\n return op.wrap( +value );\n },\n ),\n\n new Operator(\n spelling: "-",\n kind: "UMINUS",\n unary: true,\n precedence: 20,\n f: function ( op, ev, ast, ctx, expr ) {\n const value := op._handle_numeric_operand( ev, ctx, expr );\n return op.wrap( -value );\n },\n ),\n\n new Operator(\n spelling: "\u221A",\n kind: "SQRT",\n unary: true,\n precedence: 20,\n f: function ( op, ev, ast, ctx, expr ) {\n const value := op._handle_numeric_operand( ev, ctx, expr );\n return op.wrap( sqrt value );\n },\n ),\n\n new Operator(\n spelling: "!",\n kind: "NOT",\n unary: true,\n precedence: 20,\n f: logical_negation,\n ),\n\n new Operator(\n spelling: "\xAC",\n kind: "NOTSYM",\n unary: true,\n precedence: 20,\n f: logical_negation,\n ),\n\n new Operator(\n spelling: "**",\n kind: "POW",\n require_ws: true,\n right_assoc: true,\n precedence: 13,\n f: numeric_power,\n ),\n\n new Operator(\n spelling: "\xD7",\n kind: "TIMES_SIGN",\n precedence: 12,\n f: numeric_multiplication,\n ),\n\n new Operator(\n spelling: "*",\n kind: "TIMES",\n require_ws: true,\n precedence: 12,\n lex_ignore: true,\n alias: "STAR",\n f: numeric_multiplication,\n ),\n\n new Operator(\n spelling: "\xF7",\n kind: "DIVIDE_SIGN",\n precedence: 12,\n f: numeric_division,\n ),\n\n new Operator(\n spelling: "/",\n kind: "DIVIDE",\n require_ws: true,\n precedence: 12,\n lex_ignore: true,\n alias: "SLASH",\n f: numeric_division,\n ),\n\n new Operator(\n spelling: "mod",\n kind: "MOD",\n precedence: 12,\n f: numeric_modulus,\n ),\n\n new Operator(\n spelling: "+",\n kind: "PLUS",\n require_ws: true,\n precedence: 11,\n f: numeric_addition,\n ),\n\n new Operator(\n spelling: "-",\n kind: "MINUS",\n require_ws: true,\n precedence: 11,\n f: numeric_subtraction,\n ),\n\n new Operator(\n spelling: "=",\n kind: "EQ",\n precedence: 5,\n f: numeric_equality,\n ),\n\n new Operator(\n spelling: "\u2260",\n kind: "NE",\n precedence: 5,\n f: numeric_inequality,\n ),\n\n new Operator(\n spelling: "<",\n kind: "LT",\n precedence: 5,\n f: numeric_less_than,\n ),\n\n new Operator(\n spelling: ">",\n kind: "GT",\n precedence: 5,\n f: numeric_greater_than,\n ),\n\n new Operator(\n spelling: "\u2264",\n kind: "LE_SIGN",\n precedence: 5,\n f: numeric_less_than_or_equal,\n ),\n\n new Operator(\n spelling: "<=",\n kind: "LE",\n precedence: 5,\n f: numeric_less_than_or_equal,\n ),\n\n new Operator(\n spelling: "\u2265",\n kind: "GE_SIGN",\n precedence: 5,\n f: numeric_greater_than_or_equal,\n ),\n\n new Operator(\n spelling: ">=",\n kind: "GE",\n precedence: 5,\n f: numeric_greater_than_or_equal,\n ),\n\n new Operator(\n spelling: "\u2276",\n kind: "CMP_SIGN",\n precedence: 5,\n f: numeric_compare,\n ),\n\n new Operator(\n spelling: "<=>",\n kind: "CMP",\n precedence: 5,\n f: numeric_compare,\n ),\n\n new Operator(\n spelling: "\u2277",\n kind: "CMP_REV_SIGN",\n precedence: 5,\n f: numeric_compare,\n ),\n\n new Operator(\n spelling: "_",\n kind: "CONCAT",\n require_ws: true,\n precedence: 10,\n f: string_concatenation,\n ),\n\n new Operator(\n spelling: "eq",\n kind: "STR_EQ",\n precedence: 5,\n f: string_equality,\n ),\n\n new Operator(\n spelling: "ne",\n kind: "STR_NE",\n precedence: 5,\n f: string_inequality,\n ),\n\n new Operator(\n spelling: "gt",\n kind: "STR_GT",\n precedence: 5,\n f: string_greater_than,\n ),\n\n new Operator(\n spelling: "ge",\n kind: "STR_GE",\n precedence: 5,\n f: string_greater_than_or_equal,\n ),\n\n new Operator(\n spelling: "lt",\n kind: "STR_LT",\n precedence: 5,\n f: string_less_than,\n ),\n\n new Operator(\n spelling: "le",\n kind: "STR_LE",\n precedence: 5,\n f: string_less_than_or_equal,\n ),\n\n new Operator(\n spelling: "cmp",\n kind: "STR_CMP",\n precedence: 5,\n f: string_compare,\n ),\n\n new Operator(\n spelling: "eqi",\n kind: "STR_EQI",\n precedence: 5,\n f: string_equality_insensitive,\n ),\n\n new Operator(\n spelling: "nei",\n kind: "STR_NEI",\n precedence: 5,\n f: string_inequality_insensitive,\n ),\n\n new Operator(\n spelling: "gti",\n kind: "STR_GTI",\n precedence: 5,\n f: string_greater_than_insensitive,\n ),\n\n new Operator(\n spelling: "gei",\n kind: "STR_GEI",\n precedence: 5,\n f: string_greater_than_or_equal_insensitive,\n ),\n\n new Operator(\n spelling: "lti",\n kind: "STR_LTI",\n precedence: 5,\n f: string_less_than_insensitive,\n ),\n\n new Operator(\n spelling: "lei",\n kind: "STR_LEI",\n precedence: 5,\n f: string_less_than_or_equal_insensitive,\n ),\n\n new Operator(\n spelling: "cmpi",\n kind: "STR_CMPI",\n precedence: 5,\n f: string_compare_insensitive,\n ),\n\n new Operator(\n spelling: "~",\n kind: "REGEXP_MATCH",\n precedence: 5,\n f: regexp_match,\n ),\n\n new Operator(\n spelling: "&",\n kind: "BAND",\n precedence: 8,\n f: bitwise_and,\n ),\n\n new Operator(\n spelling: "^",\n kind: "BXOR",\n precedence: 7,\n f: bitwise_xor,\n ),\n\n new Operator(\n spelling: "|",\n kind: "BOR",\n precedence: 6,\n f: bitwise_or,\n ),\n\n new Operator(\n spelling: "\u22C0",\n kind: "LAND_SIGN",\n precedence: 3,\n f: logical_and,\n ),\n\n new Operator(\n spelling: "and",\n kind: "LAND",\n precedence: 3,\n f: logical_and,\n ),\n\n new Operator(\n spelling: "\u22BC",\n kind: "LNAND_SIGN",\n precedence: 3,\n f: logical_nand,\n ),\n\n new Operator(\n spelling: "nand",\n kind: "LNAND",\n precedence: 3,\n f: logical_nand,\n ),\n\n new Operator(\n spelling: "\u22BB",\n kind: "LXOR_SIGN",\n precedence: 2,\n f: logical_xor,\n ),\n\n new Operator(\n spelling: "xor",\n kind: "LXOR",\n precedence: 2,\n f: logical_xor,\n ),\n\n new Operator(\n spelling: "\u22C1",\n kind: "LOR_SIGN",\n precedence: 1,\n f: logical_or,\n ),\n\n new Operator(\n spelling: "or",\n kind: "LOR",\n precedence: 1,\n f: logical_or,\n ),\n\n new Operator(\n spelling: "\u22C3",\n kind: "SET_UNION_SIGN",\n precedence: 9,\n f: set_union,\n ),\n\n new Operator(\n spelling: "union",\n kind: "SET_UNION",\n precedence: 9,\n f: set_union,\n ),\n\n new Operator(\n spelling: "\u22C2",\n kind: "SET_INTERSECTION_SIGN",\n precedence: 9,\n f: set_intersection,\n ),\n\n new Operator(\n spelling: "intersection",\n kind: "SET_INTERSECTION",\n precedence: 9,\n f: set_intersection,\n ),\n\n new Operator(\n spelling: "\u2216",\n kind: "SET_DIFFERENCE_SIGN",\n precedence: 9,\n f: set_difference,\n ),\n\n new Operator(\n spelling: "\\\\",\n kind: "SET_DIFFERENCE",\n precedence: 9,\n require_ws: true,\n f: set_difference,\n ),\n\n new Operator(\n spelling: "\u2208",\n kind: "MEMBER_SIGN",\n precedence: 5,\n f: collection_membership,\n ),\n\n new Operator(\n spelling: "in",\n kind: "MEMBER",\n precedence: 5,\n f: collection_membership,\n ),\n\n new Operator(\n spelling: "\u2209",\n kind: "NOT_MEMBER_SIGN",\n precedence: 5,\n f: collection_non_membership,\n ),\n\n new Operator(\n spelling: "\u2282",\n kind: "SUBSETOF_SIGN",\n precedence: 5,\n f: set_subsetof,\n ),\n\n new Operator(\n spelling: "subsetof",\n kind: "SUBSETOF",\n precedence: 5,\n f: set_subsetof,\n ),\n\n new Operator(\n spelling: "\u2283",\n kind: "SUPERSETOF_SIGN",\n precedence: 5,\n f: set_supersetof,\n ),\n\n new Operator(\n spelling: "supersetof",\n kind: "SUPERSETOF",\n precedence: 5,\n f: set_supersetof,\n ),\n\n new Operator(\n spelling: "\u2282\u2283",\n kind: "EQUIVALENTOF_SIGN",\n precedence: 5,\n f: set_equivalentof,\n ),\n\n new Operator(\n spelling: "equivalentof",\n kind: "EQUIVALENTOF",\n precedence: 5,\n f: set_equivalentof,\n ),\n\n new Operator(\n spelling: "\u2261",\n kind: "TYPE_EQ_SIGN",\n precedence: 4,\n f: type_aware_equality,\n ),\n\n new Operator(\n spelling: "==",\n kind: "TYPE_EQ",\n precedence: 4,\n f: type_aware_equality,\n ),\n\n new Operator(\n spelling: "\u2262",\n kind: "TYPE_NE_SIGN",\n precedence: 4,\n f: type_aware_inequality,\n ),\n\n new Operator(\n spelling: "!=",\n kind: "TYPE_NE",\n precedence: 4,\n f: type_aware_inequality,\n ),\n\n new Operator(\n spelling: "can",\n kind: "CAN",\n precedence: 5,\n f: object_can,\n ),\n\n new Operator(\n spelling: "~",\n kind: "BNOT",\n unary: true,\n precedence: 20,\n f: function ( op, ev, ast, ctx, expr ) {\n const value := op._handle_numeric_operand( ev, ctx, expr );\n return op.wrap( ~value );\n },\n ),\n];\n';
|
|
47345
|
+
virtualFiles["/modules/std/path/zz/operators.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/path/zz/operators - Operator definitions for ZZPath expressions.\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by all implementations of ZuzuScript.\n\n=head1 DESCRIPTION\n\nThis module extends the base ZPath operator model with\nZuzuScript-flavoured expression operators.\n\n=head1 EXPORTS\n\n=head2 Classes\n\n=over\n\n=item C<Operator>\n\nZZPath operator class extending C<std/path/z/operators> C<Operator>.\n\n=back\n\n=head2 Functions\n\n=over\n\n=item C<< string_operand(ev, ctx, expr) >>, C<< string_operands(ev, ctx, left, right) >>\n\nParameters: evaluator, context, and expression AST nodes. Returns:\nC<String> or C<Array>. Evaluates one or two operands as strings.\n\n=item C<< first_eval_value(values) >>, C<< primitive_eval_value(values) >>\n\nParameters: C<values> is an evaluated node array. Returns: value.\nExtracts the first or primitive value used by ZZPath operators.\n\n=item C<< collection_operand(ev, ctx, expr) >>\n\nParameters: evaluator, context, and expression AST node. Returns:\ncollection value. Evaluates an operand for collection operators.\n\n=item C<< builtin_can(value, method_name) >>\n\nParameters: C<value> is any value and C<method_name> is a method name.\nReturns: C<Boolean>. Tests whether built-in values support a method.\n\n=back\n\n=head2 Constants\n\n=over\n\n=item C<STANDARD_OPERATORS>\n\nType: C<Array>. Complete ZZPath operator definition table.\n\n=item C<logical_negation>, C<logical_and>, C<logical_nand>, C<logical_butnot>, C<logical_xor>, C<logical_nor>, C<logical_xnor>, C<logical_onlyif>, C<logical_or>, C<logical_and_value>, C<logical_nand_value>, C<logical_butnot_value>, C<logical_xor_value>, C<logical_nor_value>, C<logical_xnor_value>, C<logical_onlyif_value>, C<logical_or_value>\n\nType: C<Function>. Logical operator implementations.\n\n=item C<numeric_power>, C<numeric_multiplication>, C<numeric_division>, C<numeric_modulus>, C<numeric_addition>, C<numeric_subtraction>, C<numeric_left_shift>, C<numeric_right_shift>, C<numeric_equality>, C<numeric_inequality>, C<numeric_less_than>, C<numeric_greater_than>, C<numeric_less_than_or_equal>, C<numeric_greater_than_or_equal>, C<numeric_compare>, C<numeric_divides>, C<numeric_not_divides>\n\nType: C<Function>. Numeric operator implementations.\n\n=item C<string_concatenation>, C<string_equality>, C<string_inequality>, C<string_greater_than>, C<string_greater_than_or_equal>, C<string_less_than>, C<string_less_than_or_equal>, C<string_compare>, C<string_equality_insensitive>, C<string_inequality_insensitive>, C<string_greater_than_insensitive>, C<string_greater_than_or_equal_insensitive>, C<string_less_than_insensitive>, C<string_less_than_or_equal_insensitive>, C<string_compare_insensitive>\n\nType: C<Function>. String operator implementations.\n\n=item C<regexp_match>, C<bitwise_and>, C<bitwise_xor>, C<bitwise_or>, C<set_union>, C<set_intersection>, C<set_difference>, C<collection_membership>, C<collection_non_membership>, C<set_subsetof>, C<set_supersetof>, C<set_equivalentof>, C<type_aware_equality>, C<type_aware_inequality>, C<object_can>\n\nType: C<Function>. Regular expression, bitwise, collection, type-aware,\nand object capability operator implementations.\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/path/zz/operators >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nfrom std/path/z/operators import Operator as ZOperator;\n\n\nclass Operator extends ZOperator;\n\nconst logical_negation := function ( op, ev, ast, ctx, expr ) {\n const got := ev.eval_expr( expr, ev.nested_ctx( ctx ) );\n const value := got.length() > 0 ? got[0] : null;\n return op.wrap( not ev.truthy(value) );\n};\n\nconst numeric_power := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val ** right_val );\n};\n\nconst numeric_multiplication := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val \xD7 right_val );\n};\n\nconst numeric_division := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val \xF7 right_val );\n};\n\nconst numeric_modulus := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val mod right_val );\n};\n\nconst numeric_left_shift := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const first := left_vals.length() > 0 ? left_vals[0] : null;\n const left_val := first \u2261 null ? null : first.primitive_value();\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val \xAB right_val );\n};\n\nconst numeric_right_shift := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const first := left_vals.length() > 0 ? left_vals[0] : null;\n const left_val := first \u2261 null ? null : first.primitive_value();\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val \xBB right_val );\n};\n\nconst numeric_addition := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val + right_val );\n};\n\nconst numeric_subtraction := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val - right_val );\n};\n\nconst numeric_equality := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val = right_val );\n};\n\nconst numeric_inequality := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val \u2260 right_val );\n};\n\nconst numeric_less_than := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val < right_val );\n};\n\nconst numeric_greater_than := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val > right_val );\n};\n\nconst numeric_less_than_or_equal := function (\n op,\n ev,\n ast,\n ctx,\n left,\n right,\n) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val \u2264 right_val );\n};\n\nconst numeric_greater_than_or_equal := function (\n op,\n ev,\n ast,\n ctx,\n left,\n right,\n) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val \u2265 right_val );\n};\n\nconst numeric_compare := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val <=> right_val );\n};\n\nconst numeric_divides := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( right_val mod left_val = 0 );\n};\n\nconst numeric_not_divides := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( right_val mod left_val );\n};\n\nfunction string_operand ( ev, ctx, expr ) {\n const result := ev.eval_expr( expr, ev.nested_ctx( ctx ) );\n return "" unless result.length;\n const value := ev.to_string( result[0] );\n return value \u2261 null ? "" : "" _ value;\n}\n\nfunction string_operands ( ev, ctx, left, right ) {\n return [\n string_operand( ev, ctx, left ),\n string_operand( ev, ctx, right ),\n ];\n}\n\nconst string_concatenation := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] _ values[1] );\n};\n\nconst string_equality := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] eq values[1] );\n};\n\nconst string_inequality := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] ne values[1] );\n};\n\nconst string_greater_than := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] gt values[1] );\n};\n\nconst string_greater_than_or_equal := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] ge values[1] );\n};\n\nconst string_less_than := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] lt values[1] );\n};\n\nconst string_less_than_or_equal := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] le values[1] );\n};\n\nconst string_compare := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] cmp values[1] );\n};\n\nconst string_equality_insensitive := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val eq right_val );\n};\n\nconst string_inequality_insensitive := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val ne right_val );\n};\n\nconst string_greater_than_insensitive := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val gt right_val );\n};\n\nconst string_greater_than_or_equal_insensitive := function (\n op,\n ev,\n ast,\n ctx,\n left,\n right,\n) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val ge right_val );\n};\n\nconst string_less_than_insensitive := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val lt right_val );\n};\n\nconst string_less_than_or_equal_insensitive := function (\n op,\n ev,\n ast,\n ctx,\n left,\n right,\n) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val le right_val );\n};\n\nconst string_compare_insensitive := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n const left_val := lc values[0];\n const right_val := lc values[1];\n return op.wrap( left_val cmp right_val );\n};\n\nconst regexp_match := function ( op, ev, ast, ctx, left, right ) {\n const values := string_operands( ev, ctx, left, right );\n return op.wrap( values[0] ~ values[1] );\n};\n\nconst bitwise_and := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val & right_val );\n};\n\nconst bitwise_xor := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val ^ right_val );\n};\n\nconst bitwise_or := function ( op, ev, ast, ctx, left, right ) {\n const left_val := op._handle_numeric_operand( ev, ctx, left );\n const right_val := op._handle_numeric_operand( ev, ctx, right );\n return op.wrap( left_val | right_val );\n};\n\nfunction first_eval_value ( values ) {\n return values.length() > 0 ? values[0] : null;\n}\n\nfunction primitive_eval_value ( values ) {\n const first := first_eval_value(values);\n return first \u2261 null ? null : first.primitive_value();\n}\n\nfunction collection_operand ( ev, ctx, expr ) {\n const values := ev.eval_expr( expr, ev.nested_ctx( ctx ) );\n if ( values.length() = 1 ) {\n return values[0].primitive_value();\n }\n return values.map( fn value \u2192 value.primitive_value() );\n}\n\nconst logical_and := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n if ( ev.truthy( first_eval_value(left_vals) ) ) {\n return ev.eval_expr( right, ev.nested_ctx( ctx ) );\n }\n return op.wrap(false);\n};\n\nconst logical_nand := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n if ( not ev.truthy( first_eval_value(left_vals) ) ) {\n return op.wrap(true);\n }\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n return op.wrap( ev.truthy( first_eval_value(right_vals) ) ? false : true );\n};\n\nconst logical_butnot := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n if ( not ev.truthy( first_eval_value(left_vals) ) ) {\n return op.wrap(false);\n }\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n return op.wrap( ev.truthy( first_eval_value(right_vals) ) ? false : true );\n};\n\nconst logical_xor := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n const left_truth := ev.truthy( first_eval_value(left_vals) );\n const right_truth := ev.truthy( first_eval_value(right_vals) );\n return op.wrap( ( left_truth xor right_truth ) ? true : false );\n};\n\nconst logical_nor := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n if ( ev.truthy( first_eval_value(left_vals) ) ) {\n return op.wrap(false);\n }\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n return op.wrap( ev.truthy( first_eval_value(right_vals) ) ? false : true );\n};\n\nconst logical_xnor := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n const left_truth := ev.truthy( first_eval_value(left_vals) );\n const right_truth := ev.truthy( first_eval_value(right_vals) );\n return op.wrap( left_truth \u2261 right_truth );\n};\n\nconst logical_onlyif := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n if ( not ev.truthy( first_eval_value(left_vals) ) ) {\n return op.wrap(true);\n }\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n return op.wrap( ev.truthy( first_eval_value(right_vals) ) ? true : false );\n};\n\nconst logical_or := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n if ( ev.truthy( first_eval_value(left_vals) ) ) {\n return op.wrap(true);\n }\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n return op.wrap( ev.truthy( first_eval_value(right_vals) ) ? true : false );\n};\n\nconst logical_and_value := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n if ( ev.truthy( first_eval_value(left_vals) ) ) {\n return ev.eval_expr( right, ev.nested_ctx( ctx ) );\n }\n return left_vals;\n};\n\nconst logical_nand_value := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const left_truth := ev.truthy( first_eval_value(left_vals) );\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n const right_truth := ev.truthy( first_eval_value(right_vals) );\n if ( left_truth and right_truth ) {\n return op.wrap(false);\n }\n return right_vals if not left_truth and right_truth;\n return op.wrap(true);\n};\n\nconst logical_butnot_value := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const left_truth := ev.truthy( first_eval_value(left_vals) );\n return left_vals unless left_truth;\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n return ev.truthy( first_eval_value(right_vals) )\n ? op.wrap(false)\n : left_vals;\n};\n\nconst logical_xor_value := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n const left_truth := ev.truthy( first_eval_value(left_vals) );\n const right_truth := ev.truthy( first_eval_value(right_vals) );\n if ( left_truth xor right_truth ) {\n return left_truth ? left_vals : right_vals;\n }\n return op.wrap(false);\n};\n\nconst logical_nor_value := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n const left_truth := ev.truthy( first_eval_value(left_vals) );\n const right_truth := ev.truthy( first_eval_value(right_vals) );\n return op.wrap(false) if left_truth and right_truth;\n return right_vals if left_truth and not right_truth;\n return left_vals if not left_truth and right_truth;\n return op.wrap(true);\n};\n\nconst logical_xnor_value := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n const left_truth := ev.truthy( first_eval_value(left_vals) );\n const right_truth := ev.truthy( first_eval_value(right_vals) );\n if ( left_truth \u2261 right_truth ) {\n return left_truth ? right_vals : op.wrap(true);\n }\n return left_truth ? right_vals : left_vals;\n};\n\nconst logical_onlyif_value := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n if ( not ev.truthy( first_eval_value(left_vals) ) ) {\n return op.wrap(true);\n }\n return ev.eval_expr( right, ev.nested_ctx( ctx ) );\n};\n\nconst logical_or_value := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n if ( ev.truthy( first_eval_value(left_vals) ) ) {\n return left_vals;\n }\n return ev.eval_expr( right, ev.nested_ctx( ctx ) );\n};\n\nconst set_union := function ( op, ev, ast, ctx, left, right ) {\n const left_val := collection_operand( ev, ctx, left );\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val union right_val );\n};\n\nconst set_intersection := function ( op, ev, ast, ctx, left, right ) {\n const left_val := collection_operand( ev, ctx, left );\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val intersection right_val );\n};\n\nconst set_difference := function ( op, ev, ast, ctx, left, right ) {\n const left_val := collection_operand( ev, ctx, left );\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val \u2216 right_val );\n};\n\nconst collection_membership := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const left_val := primitive_eval_value(left_vals);\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val in right_val );\n};\n\nconst collection_non_membership := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const left_val := primitive_eval_value(left_vals);\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val \u2209 right_val );\n};\n\nconst set_subsetof := function ( op, ev, ast, ctx, left, right ) {\n const left_val := collection_operand( ev, ctx, left );\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val subsetof right_val );\n};\n\nconst set_supersetof := function ( op, ev, ast, ctx, left, right ) {\n const left_val := collection_operand( ev, ctx, left );\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val supersetof right_val );\n};\n\nconst set_equivalentof := function ( op, ev, ast, ctx, left, right ) {\n const left_val := collection_operand( ev, ctx, left );\n const right_val := collection_operand( ev, ctx, right );\n return op.wrap( left_val equivalentof right_val );\n};\n\nconst type_aware_equality := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n return op.wrap( ev.equals(\n first_eval_value(left_vals),\n first_eval_value(right_vals),\n ) );\n};\n\nconst type_aware_inequality := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n return op.wrap( not ev.equals(\n first_eval_value(left_vals),\n first_eval_value(right_vals),\n ) );\n};\n\nfunction builtin_can ( value, method_name ) {\n return false if value \u2261 null\n or method_name \u2261 null\n or method_name eq "";\n\n if ( value instanceof Array or value instanceof Bag or value instanceof Set ) {\n return method_name in [\n "length",\n "empty",\n "contains",\n "push",\n "to_Array",\n "to_Bag",\n "to_Set",\n ];\n }\n if ( value instanceof Dict or value instanceof PairList ) {\n return method_name in [\n "length",\n "empty",\n "exists",\n "keys",\n "values",\n "to_Array",\n ];\n }\n if ( value instanceof String or value instanceof BinaryString ) {\n return method_name in [ "length" ];\n }\n return false;\n}\n\nconst object_can := function ( op, ev, ast, ctx, left, right ) {\n const left_vals := ev.eval_expr( left, ev.nested_ctx( ctx ) );\n const right_vals := ev.eval_expr( right, ev.nested_ctx( ctx ) );\n const left_val := primitive_eval_value(left_vals);\n const right_val := primitive_eval_value(right_vals);\n return op.wrap(\n ( left_val can (right_val) ) or builtin_can( left_val, right_val )\n );\n};\n\nconst STANDARD_OPERATORS := [\n new Operator(\n spelling: "?:",\n kind: "ELVIS",\n precedence: 2,\n lex_ignore: true,\n ),\n\n new Operator(\n spelling: "+",\n kind: "UPLUS",\n unary: true,\n precedence: 40,\n f: function ( op, ev, ast, ctx, expr ) {\n const value := op._handle_numeric_operand( ev, ctx, expr );\n return op.wrap( +value );\n },\n ),\n\n new Operator(\n spelling: "-",\n kind: "UMINUS",\n unary: true,\n precedence: 40,\n f: function ( op, ev, ast, ctx, expr ) {\n const value := op._handle_numeric_operand( ev, ctx, expr );\n return op.wrap( -value );\n },\n ),\n\n new Operator(\n spelling: "\u221A",\n kind: "SQRT",\n unary: true,\n precedence: 40,\n f: function ( op, ev, ast, ctx, expr ) {\n const value := op._handle_numeric_operand( ev, ctx, expr );\n return op.wrap( sqrt value );\n },\n ),\n\n new Operator(\n spelling: "!",\n kind: "NOT",\n unary: true,\n precedence: 40,\n f: logical_negation,\n ),\n\n new Operator(\n spelling: "\xAC",\n kind: "NOTSYM",\n unary: true,\n precedence: 40,\n f: logical_negation,\n ),\n\n new Operator(\n spelling: "**",\n kind: "POW",\n require_ws: true,\n right_assoc: true,\n precedence: 26,\n f: numeric_power,\n ),\n\n new Operator(\n spelling: "\xD7",\n kind: "TIMES_SIGN",\n precedence: 24,\n f: numeric_multiplication,\n ),\n\n new Operator(\n spelling: "*",\n kind: "TIMES",\n require_ws: true,\n precedence: 24,\n lex_ignore: true,\n alias: "STAR",\n f: numeric_multiplication,\n ),\n\n new Operator(\n spelling: "\xF7",\n kind: "DIVIDE_SIGN",\n precedence: 24,\n f: numeric_division,\n ),\n\n new Operator(\n spelling: "/",\n kind: "DIVIDE",\n require_ws: true,\n precedence: 24,\n lex_ignore: true,\n alias: "SLASH",\n f: numeric_division,\n ),\n\n new Operator(\n spelling: "mod",\n kind: "MOD",\n precedence: 24,\n f: numeric_modulus,\n ),\n\n new Operator(\n spelling: "+",\n kind: "PLUS",\n require_ws: true,\n precedence: 22,\n f: numeric_addition,\n ),\n\n new Operator(\n spelling: "-",\n kind: "MINUS",\n require_ws: true,\n precedence: 22,\n f: numeric_subtraction,\n ),\n\n new Operator(\n spelling: "=",\n kind: "EQ",\n precedence: 10,\n f: numeric_equality,\n ),\n\n new Operator(\n spelling: "\u2260",\n kind: "NE",\n precedence: 10,\n f: numeric_inequality,\n ),\n\n new Operator(\n spelling: "<",\n kind: "LT",\n precedence: 10,\n f: numeric_less_than,\n ),\n\n new Operator(\n spelling: ">",\n kind: "GT",\n precedence: 10,\n f: numeric_greater_than,\n ),\n\n new Operator(\n spelling: "\u2264",\n kind: "LE_SIGN",\n precedence: 10,\n f: numeric_less_than_or_equal,\n ),\n\n new Operator(\n spelling: "<=",\n kind: "LE",\n precedence: 10,\n f: numeric_less_than_or_equal,\n ),\n\n new Operator(\n spelling: "\u2265",\n kind: "GE_SIGN",\n precedence: 10,\n f: numeric_greater_than_or_equal,\n ),\n\n new Operator(\n spelling: ">=",\n kind: "GE",\n precedence: 10,\n f: numeric_greater_than_or_equal,\n ),\n\n new Operator(\n spelling: "\u2276",\n kind: "CMP_SIGN",\n precedence: 10,\n f: numeric_compare,\n ),\n\n new Operator(\n spelling: "<=>",\n kind: "CMP",\n precedence: 10,\n f: numeric_compare,\n ),\n\n new Operator(\n spelling: "\u2277",\n kind: "CMP_REV_SIGN",\n precedence: 10,\n f: numeric_compare,\n ),\n\n new Operator(\n spelling: "\u2223",\n kind: "DIVIDES_SIGN",\n precedence: 10,\n f: numeric_divides,\n ),\n\n new Operator(\n spelling: "divides",\n kind: "DIVIDES",\n precedence: 10,\n f: numeric_divides,\n ),\n\n new Operator(\n spelling: "\u2224",\n kind: "NOT_DIVIDES_SIGN",\n precedence: 10,\n f: numeric_not_divides,\n ),\n\n new Operator(\n spelling: "_",\n kind: "CONCAT",\n require_ws: true,\n precedence: 21,\n f: string_concatenation,\n ),\n\n new Operator(\n spelling: "eq",\n kind: "STR_EQ",\n precedence: 10,\n f: string_equality,\n ),\n\n new Operator(\n spelling: "ne",\n kind: "STR_NE",\n precedence: 10,\n f: string_inequality,\n ),\n\n new Operator(\n spelling: "gt",\n kind: "STR_GT",\n precedence: 10,\n f: string_greater_than,\n ),\n\n new Operator(\n spelling: "ge",\n kind: "STR_GE",\n precedence: 10,\n f: string_greater_than_or_equal,\n ),\n\n new Operator(\n spelling: "lt",\n kind: "STR_LT",\n precedence: 10,\n f: string_less_than,\n ),\n\n new Operator(\n spelling: "le",\n kind: "STR_LE",\n precedence: 10,\n f: string_less_than_or_equal,\n ),\n\n new Operator(\n spelling: "cmp",\n kind: "STR_CMP",\n precedence: 10,\n f: string_compare,\n ),\n\n new Operator(\n spelling: "eqi",\n kind: "STR_EQI",\n precedence: 10,\n f: string_equality_insensitive,\n ),\n\n new Operator(\n spelling: "nei",\n kind: "STR_NEI",\n precedence: 10,\n f: string_inequality_insensitive,\n ),\n\n new Operator(\n spelling: "gti",\n kind: "STR_GTI",\n precedence: 10,\n f: string_greater_than_insensitive,\n ),\n\n new Operator(\n spelling: "gei",\n kind: "STR_GEI",\n precedence: 10,\n f: string_greater_than_or_equal_insensitive,\n ),\n\n new Operator(\n spelling: "lti",\n kind: "STR_LTI",\n precedence: 10,\n f: string_less_than_insensitive,\n ),\n\n new Operator(\n spelling: "lei",\n kind: "STR_LEI",\n precedence: 10,\n f: string_less_than_or_equal_insensitive,\n ),\n\n new Operator(\n spelling: "cmpi",\n kind: "STR_CMPI",\n precedence: 10,\n f: string_compare_insensitive,\n ),\n\n new Operator(\n spelling: "~",\n kind: "REGEXP_MATCH",\n precedence: 10,\n f: regexp_match,\n ),\n\n new Operator(\n spelling: "\xAB",\n kind: "LSHIFT_SIGN",\n precedence: 18,\n f: numeric_left_shift,\n ),\n\n new Operator(\n spelling: "<<",\n kind: "LSHIFT",\n precedence: 18,\n f: numeric_left_shift,\n ),\n\n new Operator(\n spelling: "\xBB",\n kind: "RSHIFT_SIGN",\n precedence: 18,\n f: numeric_right_shift,\n ),\n\n new Operator(\n spelling: ">>",\n kind: "RSHIFT",\n precedence: 18,\n f: numeric_right_shift,\n ),\n\n new Operator(\n spelling: "&",\n kind: "BAND",\n precedence: 16,\n f: bitwise_and,\n ),\n\n new Operator(\n spelling: "^",\n kind: "BXOR",\n precedence: 14,\n f: bitwise_xor,\n ),\n\n new Operator(\n spelling: "|",\n kind: "BOR",\n precedence: 12,\n f: bitwise_or,\n ),\n\n new Operator(\n spelling: "\u22C0",\n kind: "LAND_SIGN",\n precedence: 7,\n f: logical_and,\n ),\n\n new Operator(\n spelling: "and",\n kind: "LAND",\n precedence: 7,\n f: logical_and,\n ),\n\n new Operator(\n spelling: "\u22C0?",\n kind: "LAND_VALUE_SIGN",\n precedence: 7,\n f: logical_and_value,\n ),\n\n new Operator(\n spelling: "and?",\n kind: "LAND_VALUE",\n precedence: 7,\n f: logical_and_value,\n ),\n\n new Operator(\n spelling: "\u22BC",\n kind: "LNAND_SIGN",\n precedence: 7,\n f: logical_nand,\n ),\n\n new Operator(\n spelling: "nand",\n kind: "LNAND",\n precedence: 7,\n f: logical_nand,\n ),\n\n new Operator(\n spelling: "\u22BC?",\n kind: "LNAND_VALUE_SIGN",\n precedence: 7,\n f: logical_nand_value,\n ),\n\n new Operator(\n spelling: "nand?",\n kind: "LNAND_VALUE",\n precedence: 7,\n f: logical_nand_value,\n ),\n\n new Operator(\n spelling: "\u22AD",\n kind: "LBUTNOT_SIGN",\n precedence: 7,\n f: logical_butnot,\n ),\n\n new Operator(\n spelling: "butnot",\n kind: "LBUTNOT",\n precedence: 7,\n f: logical_butnot,\n ),\n\n new Operator(\n spelling: "\u22AD?",\n kind: "LBUTNOT_VALUE_SIGN",\n precedence: 7,\n f: logical_butnot_value,\n ),\n\n new Operator(\n spelling: "butnot?",\n kind: "LBUTNOT_VALUE",\n precedence: 7,\n f: logical_butnot_value,\n ),\n\n new Operator(\n spelling: "\u22BB",\n kind: "LXOR_SIGN",\n precedence: 5,\n f: logical_xor,\n ),\n\n new Operator(\n spelling: "xor",\n kind: "LXOR",\n precedence: 5,\n f: logical_xor,\n ),\n\n new Operator(\n spelling: "\u22BB?",\n kind: "LXOR_VALUE_SIGN",\n precedence: 5,\n f: logical_xor_value,\n ),\n\n new Operator(\n spelling: "xor?",\n kind: "LXOR_VALUE",\n precedence: 5,\n f: logical_xor_value,\n ),\n\n new Operator(\n spelling: "\u22BD",\n kind: "LNOR_SIGN",\n precedence: 5,\n f: logical_nor,\n ),\n\n new Operator(\n spelling: "nor",\n kind: "LNOR",\n precedence: 5,\n f: logical_nor,\n ),\n\n new Operator(\n spelling: "\u22BD?",\n kind: "LNOR_VALUE_SIGN",\n precedence: 5,\n f: logical_nor_value,\n ),\n\n new Operator(\n spelling: "nor?",\n kind: "LNOR_VALUE",\n precedence: 5,\n f: logical_nor_value,\n ),\n\n new Operator(\n spelling: "\u2194",\n kind: "LXNOR_SIGN",\n precedence: 5,\n f: logical_xnor,\n ),\n\n new Operator(\n spelling: "xnor",\n kind: "LXNOR",\n precedence: 5,\n f: logical_xnor,\n ),\n\n new Operator(\n spelling: "\u2194?",\n kind: "LXNOR_VALUE_SIGN",\n precedence: 5,\n f: logical_xnor_value,\n ),\n\n new Operator(\n spelling: "xnor?",\n kind: "LXNOR_VALUE",\n precedence: 5,\n f: logical_xnor_value,\n ),\n\n new Operator(\n spelling: "\u22A8",\n kind: "LONLYIF_SIGN",\n precedence: 4,\n right_assoc: true,\n f: logical_onlyif,\n ),\n\n new Operator(\n spelling: "onlyif",\n kind: "LONLYIF",\n precedence: 4,\n right_assoc: true,\n f: logical_onlyif,\n ),\n\n new Operator(\n spelling: "\u22A8?",\n kind: "LONLYIF_VALUE_SIGN",\n precedence: 4,\n right_assoc: true,\n f: logical_onlyif_value,\n ),\n\n new Operator(\n spelling: "onlyif?",\n kind: "LONLYIF_VALUE",\n precedence: 4,\n right_assoc: true,\n f: logical_onlyif_value,\n ),\n\n new Operator(\n spelling: "\u22C1",\n kind: "LOR_SIGN",\n precedence: 2,\n f: logical_or,\n ),\n\n new Operator(\n spelling: "or",\n kind: "LOR",\n precedence: 2,\n f: logical_or,\n ),\n\n new Operator(\n spelling: "\u22C1?",\n kind: "LOR_VALUE_SIGN",\n precedence: 2,\n f: logical_or_value,\n ),\n\n new Operator(\n spelling: "or?",\n kind: "LOR_VALUE",\n precedence: 2,\n f: logical_or_value,\n ),\n\n new Operator(\n spelling: "\u22C3",\n kind: "SET_UNION_SIGN",\n precedence: 20,\n f: set_union,\n ),\n\n new Operator(\n spelling: "union",\n kind: "SET_UNION",\n precedence: 20,\n f: set_union,\n ),\n\n new Operator(\n spelling: "\u22C2",\n kind: "SET_INTERSECTION_SIGN",\n precedence: 20,\n f: set_intersection,\n ),\n\n new Operator(\n spelling: "intersection",\n kind: "SET_INTERSECTION",\n precedence: 20,\n f: set_intersection,\n ),\n\n new Operator(\n spelling: "\u2216",\n kind: "SET_DIFFERENCE_SIGN",\n precedence: 20,\n f: set_difference,\n ),\n\n new Operator(\n spelling: "\\\\",\n kind: "SET_DIFFERENCE",\n precedence: 20,\n require_ws: true,\n f: set_difference,\n ),\n\n new Operator(\n spelling: "\u2208",\n kind: "MEMBER_SIGN",\n precedence: 10,\n f: collection_membership,\n ),\n\n new Operator(\n spelling: "in",\n kind: "MEMBER",\n precedence: 10,\n f: collection_membership,\n ),\n\n new Operator(\n spelling: "\u2209",\n kind: "NOT_MEMBER_SIGN",\n precedence: 10,\n f: collection_non_membership,\n ),\n\n new Operator(\n spelling: "\u2282",\n kind: "SUBSETOF_SIGN",\n precedence: 10,\n f: set_subsetof,\n ),\n\n new Operator(\n spelling: "subsetof",\n kind: "SUBSETOF",\n precedence: 10,\n f: set_subsetof,\n ),\n\n new Operator(\n spelling: "\u2283",\n kind: "SUPERSETOF_SIGN",\n precedence: 10,\n f: set_supersetof,\n ),\n\n new Operator(\n spelling: "supersetof",\n kind: "SUPERSETOF",\n precedence: 10,\n f: set_supersetof,\n ),\n\n new Operator(\n spelling: "\u2282\u2283",\n kind: "EQUIVALENTOF_SIGN",\n precedence: 10,\n f: set_equivalentof,\n ),\n\n new Operator(\n spelling: "equivalentof",\n kind: "EQUIVALENTOF",\n precedence: 10,\n f: set_equivalentof,\n ),\n\n new Operator(\n spelling: "\u2261",\n kind: "TYPE_EQ_SIGN",\n precedence: 8,\n f: type_aware_equality,\n ),\n\n new Operator(\n spelling: "==",\n kind: "TYPE_EQ",\n precedence: 8,\n f: type_aware_equality,\n ),\n\n new Operator(\n spelling: "\u2262",\n kind: "TYPE_NE_SIGN",\n precedence: 8,\n f: type_aware_inequality,\n ),\n\n new Operator(\n spelling: "!=",\n kind: "TYPE_NE",\n precedence: 8,\n f: type_aware_inequality,\n ),\n\n new Operator(\n spelling: "can",\n kind: "CAN",\n precedence: 10,\n f: object_can,\n ),\n\n new Operator(\n spelling: "~",\n kind: "BNOT",\n unary: true,\n precedence: 40,\n f: function ( op, ev, ast, ctx, expr ) {\n const value := op._handle_numeric_operand( ev, ctx, expr );\n return op.wrap( ~value );\n },\n ),\n];\n';
|
|
46402
47346
|
virtualFiles["/modules/std/template/z.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/template/z - Pure ZuzuScript template engine.\n\n=head1 SYNOPSIS\n\n from std/template/z import ZTemplate;\n\n let inline := new ZTemplate(\n string: "Hello {{ user/name }}!",\n );\n say( inline.process( { user: { name: "Ada" } } ) );\n\n let file_tmpl := new ZTemplate(\n file: "templates/page.zt",\n escape: "html",\n );\n say( file_tmpl.process( data ) );\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by zuzu.pl, zuzu-rust, and zuzu-js on Node and\nElectron. It is partially supported by zuzu-js in the browser: complex,\nHTTP/JSON/ZPath pipeline, self-contained, and trait-object rendering\ncoverage passes, but filesystem-backed template loading and database row\nrendering coverage are unsupported.\n\n=head1 DESCRIPTION\n\nC<std/template/z> is a pure ZuzuScript template renderer.\n\nThe module compiles template text into a cached parse tree and renders\nit against data using C<std/path/z> expressions.\n\n=head1 EXPORTS\n\n=head2 Classes\n\n=over\n\n=item C<< ZTemplate({ string?: String, file?, escape?: String, includes?: Boolean }) >>\n\nConstructs a template from inline text or a file path. Returns:\nC<ZTemplate>.\n\n=over\n\n=item C<< template.process(data) >>\n\nParameters: C<data> is the model used for path lookups. Returns:\nC<String>. Renders the template.\n\n=back\n\n=back\n\n=head1 TAG FORMS\n\n=over 4\n\n=item * C<{{ expr }}>\n\nRender expression output using template default escaping.\n\n=item * C<{{ expr :: raw }}>, C<{{ expr :: html }}>\n\nRender expression output using per-tag escape override.\n\n=item * C<{{# expr }}> ... C<{{/expr}}>\n\nBlock form. Each truthy match renders child nodes.\n\n=item * C<{{> include.zt }}>\n\nInclude another template file. Relative include paths resolve from the\ncurrent template\'s file directory.\n\n=back\n\n=head1 ESCAPING\n\nDefault escape mode is C<html>. Supported escape modes are C<html> and\nC<raw>.\n\nC<html> escapes C<&>, C<< < >>, C<E<gt>>, double quotes, and single\nquotes.\n\n=head1 INCLUDE RULES\n\n=over 4\n\n=item * Include processing is enabled by default.\n\n=item * Pass C<includes: false> to disable include tags.\n\n=item * Relative includes require a file-backed template source.\n\n=item * Circular include chains throw a deterministic error.\n\n=back\n\n=head1 KNOWN DIFFERENCES\n\nThis module is implemented on top of C<std/path/z>. Parser/rendering\ndeltas across runtimes are covered in ztests and should be treated as\nimplementation bugs unless explicitly documented.\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/template/z >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nfrom std/string import index, substr, trim;\nfrom std/path/z import ZPath;\n\nclass ZTemplate {\n let string;\n let file;\n let String escape := "html";\n let includes := true;\n let source_file := null;\n let Array tree := [];\n let compiled_paths := {};\n\n method __build__ () {\n let has_string := string \u2262 null;\n let has_file := file \u2262 null;\n\n if ( has_string and has_file ) {\n die "Specify only one of \\"string\\" or \\"file\\"";\n }\n if ( not has_string and not has_file ) {\n die "Missing template source: provide \\"string\\" or \\"file\\"";\n }\n\n escape := lc( "" _ escape );\n if ( escape \u2262 "html" and escape \u2262 "raw" ) {\n die `Invalid escape mode "${escape}"`;\n }\n\n if ( has_file ) {\n let loaded := self._read_template_file(file);\n string := loaded{text};\n source_file := loaded{file};\n }\n\n tree := self._parse_template(\n template: string \u2261 null ? "": string,\n current_file: source_file,\n seen_files: {},\n includes: includes,\n );\n }\n\n method process ( data ) {\n die "process() requires a data model" if data \u2261 null;\n\n return self._render_nodes(\n nodes: tree,\n context: data,\n eval_meta: {},\n default_escape: escape,\n );\n }\n\n method _parse_template ( ... PairList args ) {\n let template := args.get( "template", "" );\n let current_file := args.get( "current_file", null );\n let seen_files := args.get( "seen_files", {} );\n let includes_enabled := args.get( "includes", true );\n let root := [];\n\n let stack := [\n {\n expr: null,\n nodes: root,\n },\n ];\n\n let pos := 0;\n while ( true ) {\n let tag_open := index( template, "{{", pos );\n last if tag_open < 0;\n\n let text := substr( template, pos, tag_open - pos );\n self._push_text( stack[ stack.length() - 1 ]{nodes}, text );\n\n let tag_close := index( template, "}}", tag_open + 2 );\n if ( tag_close < 0 ) {\n die `Unterminated tag at character ${tag_open}`;\n }\n\n let raw := substr( template, tag_open + 2, tag_close - tag_open - 2 );\n let tagged := trim(raw);\n\n if ( substr( tagged, 0, 1 ) \u2261 "#" ) {\n let inner := trim( substr( tagged, 1 ) );\n let parsed := self._parse_expression_spec(inner);\n let block := {\n type: "block",\n expr_src: parsed{expr},\n nodes: [],\n };\n stack[ stack.length() - 1 ]{nodes}.push(block);\n stack.push( {\n expr: parsed{expr},\n nodes: block{nodes},\n } );\n }\n else if ( substr( tagged, 0, 1 ) \u2261 "/" ) {\n let inner := trim( substr( tagged, 1 ) );\n let current := stack.pop();\n if ( current \u2261 null or current{expr} \u2261 null ) {\n die `Mismatched close tag {{/${inner}}}`;\n }\n if ( inner \u2262 "" ) {\n let parsed := self._parse_expression_spec(inner);\n if ( current{expr} \u2262 parsed{expr} ) {\n die `Mismatched close tag {{/${inner}}} for {{${current{expr}}}}`;\n }\n }\n }\n else if ( tagged \u2262 "" ) {\n if ( substr( tagged, 0, 1 ) \u2261 ">" ) {\n die "Template includes are disabled"\n if not includes_enabled;\n\n let include_path := trim( substr( tagged, 1 ) );\n die "Empty include path in template tag"\n if include_path \u2261 "";\n\n let resolved := self._resolve_include_path(\n include_path: include_path,\n current_file: current_file,\n );\n\n let key := self._canonical_path(resolved);\n if ( seen_files.exists(key) and seen_files.get(key) ) {\n die `Circular include detected for "${resolved}"`;\n }\n\n seen_files.set( key, true );\n let loaded := self._read_template_file(resolved);\n let include_nodes := self._parse_template(\n template: loaded{text},\n current_file: loaded{file},\n seen_files: seen_files,\n includes: includes_enabled,\n );\n seen_files.remove(key);\n\n for ( let node in include_nodes ) {\n stack[ stack.length() - 1 ]{nodes}.push(node);\n }\n }\n else {\n let parsed := self._parse_expression_spec(tagged);\n stack[ stack.length() - 1 ]{nodes}.push( {\n type: "expr",\n expr_src: parsed{expr},\n escape: parsed{escape},\n } );\n }\n }\n\n pos := tag_close + 2;\n }\n\n let tail := substr( template, pos );\n self._push_text( stack[ stack.length() - 1 ]{nodes}, tail );\n\n if ( stack.length() > 1 ) {\n let missing := stack[ stack.length() - 1 ]{expr};\n die `Missing close tag for {{${missing}}}`;\n }\n\n return root;\n }\n\n method _push_text ( nodes, text ) {\n if ( text \u2262 "" ) {\n nodes.push( {\n type: "text",\n text: text,\n } );\n }\n }\n\n method _read_template_file ( raw_file ) {\n let path_obj := self._to_path(raw_file);\n let text := path_obj.slurp_utf8();\n let canonical := self._canonical_path(path_obj);\n\n return {\n text: text,\n file: canonical,\n };\n }\n\n method _to_path ( raw_file ) {\n from std/io import Path;\n if ( raw_file instanceof Path ) {\n return raw_file;\n }\n return new Path( "" _ raw_file );\n }\n\n method _canonical_path ( path_obj ) {\n let obj := self._to_path(path_obj);\n let canonical := obj.realpath();\n if ( canonical \u2261 null ) {\n canonical := obj.absolute();\n }\n if ( canonical \u2261 null ) {\n return obj.to_String;\n }\n from std/io import Path;\n if ( canonical instanceof Path ) {\n return canonical.to_String;\n }\n return "" _ canonical;\n }\n\n method _resolve_include_path ( ... PairList args ) {\n let include_path := args.get( "include_path" );\n let current_file := args.get( "current_file" );\n\n let include_obj := self._to_path(include_path);\n if ( include_obj.is_absolute() ) {\n return include_obj.to_String;\n }\n\n if ( current_file \u2261 null ) {\n die `Relative include path "${include_path}" requires file-based template source`;\n }\n\n let base := self._to_path(current_file).parent();\n return base.child( include_obj.to_String ).to_String;\n }\n\n method _parse_expression_spec ( raw ) {\n let expr := raw;\n let escape_mode := null;\n\n let split := self._find_escape_separator(raw);\n if ( split \u2262 null ) {\n let lhs := split[0];\n let rhs := split[1];\n if ( rhs \u2261 "html" or rhs \u2261 "raw" ) {\n expr := lhs;\n escape_mode := rhs;\n }\n }\n\n expr := trim(expr);\n if ( expr \u2261 "" ) {\n die "Empty expression in template tag";\n }\n\n return {\n expr: expr,\n escape: escape_mode,\n };\n }\n\n method _find_escape_separator ( text ) {\n let quote := "";\n let i := 0;\n while ( i < length text ) {\n let ch := substr( text, i, 1 );\n if ( quote \u2262 "" ) {\n if ( ch \u2261 "\\\\" ) {\n i += 2;\n next;\n }\n if ( ch \u2261 quote ) {\n quote := "";\n }\n i++;\n next;\n }\n\n if ( ch \u2261 "\\"" or ch \u2261 "\'" ) {\n quote := ch;\n i++;\n next;\n }\n\n if ( ch \u2261 ":" and substr( text, i, 2 ) \u2261 "::" ) {\n let lhs := trim( substr( text, 0, i ) );\n let rhs := lc( trim( substr( text, i + 2 ) ) );\n return [ lhs, rhs ];\n }\n\n i++;\n }\n\n return null;\n }\n\n method _render_nodes ( ... PairList args ) {\n let nodes := args.get( "nodes", [] );\n let context := args.get( "context", null );\n let eval_meta := args.get( "eval_meta", {} );\n let default_escape := args.get( "default_escape", "html" );\n let out := "";\n\n for ( let node in nodes ) {\n if ( node{type} \u2261 "text" ) {\n out _= node{text};\n }\n else if ( node{type} \u2261 "expr" ) {\n let results := self._evaluate_expression(\n expr_src: node{expr_src},\n context: context,\n eval_meta: eval_meta,\n );\n let value := "";\n for ( let matched in results ) {\n let sv := matched.string_value();\n value _= sv \u2261 null ? "" : sv;\n }\n\n let escape_mode := node{escape};\n if ( escape_mode \u2261 null ) {\n escape_mode := default_escape;\n }\n\n if ( escape_mode \u2261 "html" ) {\n out _= self._escape_html(value);\n }\n else {\n out _= value;\n }\n }\n else if ( node{type} \u2261 "block" ) {\n let results := self._evaluate_expression(\n expr_src: node{expr_src},\n context: context,\n eval_meta: eval_meta,\n );\n for ( let matched in results ) {\n let primitive := matched.primitive_value();\n next if not self._truthy(primitive);\n\n let inner_context := context;\n let inner_meta := eval_meta;\n if ( self._node_has_identity(matched) ) {\n inner_context := matched;\n inner_meta := { parentset: results };\n }\n\n out _= self._render_nodes(\n nodes: node{nodes},\n context: inner_context,\n eval_meta: inner_meta,\n default_escape: default_escape,\n );\n }\n }\n }\n\n return out;\n }\n\n method _evaluate_expression ( ... PairList args ) {\n let expr_src := args.get( "expr_src" );\n let context := args.get( "context" );\n let eval_meta := args.get( "eval_meta", {} );\n if ( not compiled_paths.exists(expr_src) ) {\n compiled_paths.set(\n expr_src,\n self._compile_path(expr_src),\n );\n }\n let zpath := compiled_paths.get(expr_src);\n return zpath.evaluate( context, eval_meta );\n }\n\n method _compile_path ( expr_src ) {\n return new ZPath( path: expr_src );\n }\n\n method _node_has_identity ( node ) {\n let parent := node.parent();\n if ( parent \u2261 null ) {\n return false;\n }\n\n return true;\n }\n\n method _truthy ( value ) {\n return value ? true : false;\n }\n\n method _escape_html ( text ) {\n let out := "";\n let i := 0;\n while ( i < length text ) {\n let ch := substr( text, i, 1 );\n if ( ch \u2261 "&" ) {\n out _= "&";\n }\n else if ( ch \u2261 "<" ) {\n out _= "<";\n }\n else if ( ch \u2261 ">" ) {\n out _= ">";\n }\n else if ( ch \u2261 "\\"" ) {\n out _= """;\n }\n else if ( ch \u2261 "\'" ) {\n out _= "'";\n }\n else {\n out _= ch;\n }\n i++;\n }\n return out;\n }\n}\n';
|
|
46403
47347
|
virtualFiles["/modules/std/template/zz.zzm"] = `=encoding utf8
|
|
46404
47348
|
|
|
@@ -46841,7 +47785,7 @@ class ZZTemplate extends ZTemplate {
|
|
|
46841
47785
|
}
|
|
46842
47786
|
});
|
|
46843
47787
|
|
|
46844
|
-
// ../../../../../tmp/zuzu-browser-build.
|
|
47788
|
+
// ../../../../../tmp/zuzu-browser-build.gMJDcc/browser-worker-entry.generated.js
|
|
46845
47789
|
var { createBrowserStdlib } = require_browser_stdlib_generated();
|
|
46846
47790
|
globalThis.__ZUZU_BROWSER_DEFAULT_RUNTIME_OPTIONS__ = createBrowserStdlib();
|
|
46847
47791
|
var { installBrowserWorker } = require_browser_worker_entry();
|