@creationix/rex 0.1.4 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -62
- package/package.json +9 -7
- package/rex-cli.js +4077 -30
- package/rex-cli.ts +200 -0
- package/{rex-compile.js → rex-repl.js} +1679 -214
- package/rex-repl.ts +578 -0
- package/rex.js +214 -59
- package/rex.ohm +34 -3
- package/rex.ohm-bundle.cjs +1 -1
- package/rex.ohm-bundle.d.ts +8 -0
- package/rex.ohm-bundle.js +1 -1
- package/rex.ts +2579 -2422
- package/rexc-interpreter.ts +926 -848
- package/rex-compile.ts +0 -224
package/rex.js
CHANGED
|
@@ -33,38 +33,8 @@ var OPCODE_IDS = {
|
|
|
33
33
|
mod: 20,
|
|
34
34
|
neg: 21
|
|
35
35
|
};
|
|
36
|
-
var
|
|
37
|
-
|
|
38
|
-
if (!name)
|
|
39
|
-
throw new Error("Domain extension name cannot be empty");
|
|
40
|
-
if (!Number.isInteger(refId) || refId < 0)
|
|
41
|
-
throw new Error(`Invalid domain extension ref id for '${name}': ${refId}`);
|
|
42
|
-
registeredDomainRefs[name] = refId;
|
|
43
|
-
}
|
|
44
|
-
function registerDomainExtensionRefs(refs) {
|
|
45
|
-
for (const [name, refId] of Object.entries(refs)) {
|
|
46
|
-
registerDomainExtensionRef(name, refId);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
function clearDomainExtensionRefs() {
|
|
50
|
-
for (const name of Object.keys(registeredDomainRefs))
|
|
51
|
-
delete registeredDomainRefs[name];
|
|
52
|
-
}
|
|
53
|
-
function getRegisteredDomainExtensionRefs() {
|
|
54
|
-
return { ...registeredDomainRefs };
|
|
55
|
-
}
|
|
56
|
-
function resolveDomainRefMap(overrides) {
|
|
57
|
-
if (!overrides || Object.keys(overrides).length === 0) {
|
|
58
|
-
return Object.keys(registeredDomainRefs).length > 0 ? { ...registeredDomainRefs } : undefined;
|
|
59
|
-
}
|
|
60
|
-
const merged = { ...registeredDomainRefs };
|
|
61
|
-
for (const [name, refId] of Object.entries(overrides)) {
|
|
62
|
-
if (!Number.isInteger(refId) || refId < 0)
|
|
63
|
-
throw new Error(`Invalid domain extension ref id for '${name}': ${refId}`);
|
|
64
|
-
merged[name] = refId;
|
|
65
|
-
}
|
|
66
|
-
return merged;
|
|
67
|
-
}
|
|
36
|
+
var FIRST_NON_RESERVED_REF = 8;
|
|
37
|
+
var DOMAIN_DIGIT_INDEX = new Map(Array.from(DIGITS).map((char, index) => [char, index]));
|
|
68
38
|
var BINARY_TO_OPCODE = {
|
|
69
39
|
add: "add",
|
|
70
40
|
sub: "sub",
|
|
@@ -177,12 +147,33 @@ function encodeBareOrLengthString(value) {
|
|
|
177
147
|
return `${value}:`;
|
|
178
148
|
return `${encodeUint(byteLength(value))},${value}`;
|
|
179
149
|
}
|
|
150
|
+
var DEC_PARTS = /^(-?\d)(?:\.(\d+))?e([+-]\d+)$/;
|
|
151
|
+
function splitDecimal(num) {
|
|
152
|
+
const match = num.toExponential().match(DEC_PARTS);
|
|
153
|
+
if (!match)
|
|
154
|
+
throw new Error(`Failed to split decimal for ${num}`);
|
|
155
|
+
const [, b1, b2 = "", e1] = match;
|
|
156
|
+
const base = Number.parseInt(b1 + b2, 10);
|
|
157
|
+
const exp = Number.parseInt(e1, 10) - b2.length;
|
|
158
|
+
return { base, exp };
|
|
159
|
+
}
|
|
160
|
+
function encodeDecimal(significand, power) {
|
|
161
|
+
return `${encodeZigzag(power)}*${encodeInt(significand)}`;
|
|
162
|
+
}
|
|
180
163
|
function encodeNumberNode(node) {
|
|
181
164
|
const numberValue = node.value;
|
|
182
|
-
if (
|
|
183
|
-
|
|
184
|
-
if (
|
|
185
|
-
return
|
|
165
|
+
if (Number.isNaN(numberValue))
|
|
166
|
+
return "5'";
|
|
167
|
+
if (numberValue === Infinity)
|
|
168
|
+
return "6'";
|
|
169
|
+
if (numberValue === -Infinity)
|
|
170
|
+
return "7'";
|
|
171
|
+
if (Number.isInteger(numberValue)) {
|
|
172
|
+
const { base, exp } = splitDecimal(numberValue);
|
|
173
|
+
if (exp >= 0 && exp <= 4)
|
|
174
|
+
return encodeInt(numberValue);
|
|
175
|
+
return encodeDecimal(base, exp);
|
|
176
|
+
}
|
|
186
177
|
const raw = node.raw.toLowerCase();
|
|
187
178
|
const sign = raw.startsWith("-") ? -1 : 1;
|
|
188
179
|
const unsigned = sign < 0 ? raw.slice(1) : raw;
|
|
@@ -205,7 +196,7 @@ function encodeNumberNode(node) {
|
|
|
205
196
|
significand /= 10;
|
|
206
197
|
power += 1;
|
|
207
198
|
}
|
|
208
|
-
return
|
|
199
|
+
return encodeDecimal(significand, power);
|
|
209
200
|
}
|
|
210
201
|
function encodeOpcode(opcode) {
|
|
211
202
|
return `${encodeUint(OPCODE_IDS[opcode])}%`;
|
|
@@ -217,13 +208,13 @@ function needsOptionalPrefix(encoded) {
|
|
|
217
208
|
const first = encoded[0];
|
|
218
209
|
if (!first)
|
|
219
210
|
return false;
|
|
220
|
-
return first === "[" || first === "{" || first === "(" || first === "=" || first === "~" || first === "?" || first === "!" || first === "|" || first === "&" || first === ">" || first === "<";
|
|
211
|
+
return first === "[" || first === "{" || first === "(" || first === "=" || first === "~" || first === "?" || first === "!" || first === "|" || first === "&" || first === ">" || first === "<" || first === "#";
|
|
221
212
|
}
|
|
222
213
|
function addOptionalPrefix(encoded) {
|
|
223
214
|
if (!needsOptionalPrefix(encoded))
|
|
224
215
|
return encoded;
|
|
225
216
|
let payload = encoded;
|
|
226
|
-
if (encoded.startsWith("?(") || encoded.startsWith("!(") || encoded.startsWith("|(") || encoded.startsWith("&(") || encoded.startsWith(">(") || encoded.startsWith("<(")) {
|
|
217
|
+
if (encoded.startsWith("?(") || encoded.startsWith("!(") || encoded.startsWith("|(") || encoded.startsWith("&(") || encoded.startsWith(">(") || encoded.startsWith("<(") || encoded.startsWith("#(")) {
|
|
227
218
|
payload = encoded.slice(2, -1);
|
|
228
219
|
} else if (encoded.startsWith(">[") || encoded.startsWith(">{")) {
|
|
229
220
|
payload = encoded.slice(2, -1);
|
|
@@ -254,6 +245,33 @@ function encodeConditionalElse(elseBranch) {
|
|
|
254
245
|
return encodeNode(nested);
|
|
255
246
|
}
|
|
256
247
|
function encodeNavigation(node) {
|
|
248
|
+
const domainRefs = activeEncodeOptions?.domainRefs;
|
|
249
|
+
if (domainRefs && node.target.type === "identifier") {
|
|
250
|
+
const staticPath = [node.target.name];
|
|
251
|
+
for (const segment of node.segments) {
|
|
252
|
+
if (segment.type !== "static")
|
|
253
|
+
break;
|
|
254
|
+
staticPath.push(segment.key);
|
|
255
|
+
}
|
|
256
|
+
for (let pathLength = staticPath.length;pathLength >= 1; pathLength -= 1) {
|
|
257
|
+
const dottedName = staticPath.slice(0, pathLength).join(".");
|
|
258
|
+
const domainRef = domainRefs[dottedName];
|
|
259
|
+
if (domainRef === undefined)
|
|
260
|
+
continue;
|
|
261
|
+
const consumedStaticSegments = pathLength - 1;
|
|
262
|
+
if (consumedStaticSegments === node.segments.length) {
|
|
263
|
+
return `${encodeUint(domainRef)}'`;
|
|
264
|
+
}
|
|
265
|
+
const parts2 = [`${encodeUint(domainRef)}'`];
|
|
266
|
+
for (const segment of node.segments.slice(consumedStaticSegments)) {
|
|
267
|
+
if (segment.type === "static")
|
|
268
|
+
parts2.push(encodeBareOrLengthString(segment.key));
|
|
269
|
+
else
|
|
270
|
+
parts2.push(encodeNode(segment.key));
|
|
271
|
+
}
|
|
272
|
+
return encodeCallParts(parts2);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
257
275
|
const parts = [encodeNode(node.target)];
|
|
258
276
|
for (const segment of node.segments) {
|
|
259
277
|
if (segment.type === "static")
|
|
@@ -263,6 +281,11 @@ function encodeNavigation(node) {
|
|
|
263
281
|
}
|
|
264
282
|
return encodeCallParts(parts);
|
|
265
283
|
}
|
|
284
|
+
function encodeWhile(node) {
|
|
285
|
+
const cond = encodeNode(node.condition);
|
|
286
|
+
const body = addOptionalPrefix(encodeBlockExpression(node.body));
|
|
287
|
+
return `#(${cond}${body})`;
|
|
288
|
+
}
|
|
266
289
|
function encodeFor(node) {
|
|
267
290
|
const body = addOptionalPrefix(encodeBlockExpression(node.body));
|
|
268
291
|
if (node.binding.type === "binding:expr") {
|
|
@@ -399,6 +422,8 @@ function encodeNode(node) {
|
|
|
399
422
|
}
|
|
400
423
|
case "for":
|
|
401
424
|
return encodeFor(node);
|
|
425
|
+
case "while":
|
|
426
|
+
return encodeWhile(node);
|
|
402
427
|
case "break":
|
|
403
428
|
return ";";
|
|
404
429
|
case "continue":
|
|
@@ -473,6 +498,18 @@ function isPlainObject(value) {
|
|
|
473
498
|
function isBareKeyName(key) {
|
|
474
499
|
return /^[A-Za-z_][A-Za-z0-9_-]*$/.test(key);
|
|
475
500
|
}
|
|
501
|
+
function isNumericKey(key) {
|
|
502
|
+
if (key === "")
|
|
503
|
+
return false;
|
|
504
|
+
return String(Number(key)) === key && Number.isFinite(Number(key));
|
|
505
|
+
}
|
|
506
|
+
function stringifyKey(key) {
|
|
507
|
+
if (isBareKeyName(key))
|
|
508
|
+
return key;
|
|
509
|
+
if (isNumericKey(key))
|
|
510
|
+
return key;
|
|
511
|
+
return stringifyString(key);
|
|
512
|
+
}
|
|
476
513
|
function stringifyString(value) {
|
|
477
514
|
return JSON.stringify(value);
|
|
478
515
|
}
|
|
@@ -484,8 +521,12 @@ function stringifyInline(value) {
|
|
|
484
521
|
if (typeof value === "boolean")
|
|
485
522
|
return value ? "true" : "false";
|
|
486
523
|
if (typeof value === "number") {
|
|
487
|
-
if (
|
|
488
|
-
|
|
524
|
+
if (Number.isNaN(value))
|
|
525
|
+
return "nan";
|
|
526
|
+
if (value === Infinity)
|
|
527
|
+
return "inf";
|
|
528
|
+
if (value === -Infinity)
|
|
529
|
+
return "-inf";
|
|
489
530
|
return String(value);
|
|
490
531
|
}
|
|
491
532
|
if (typeof value === "string")
|
|
@@ -499,7 +540,7 @@ function stringifyInline(value) {
|
|
|
499
540
|
const entries = Object.entries(value);
|
|
500
541
|
if (entries.length === 0)
|
|
501
542
|
return "{}";
|
|
502
|
-
const body = entries.map(([key, item]) => `${
|
|
543
|
+
const body = entries.map(([key, item]) => `${stringifyKey(key)}: ${stringifyInline(item)}`).join(" ");
|
|
503
544
|
return `{${body}}`;
|
|
504
545
|
}
|
|
505
546
|
throw new Error(`Rex stringify() cannot encode value of type ${typeof value}`);
|
|
@@ -536,7 +577,7 @@ ${indent}]`;
|
|
|
536
577
|
if (entries.length === 0)
|
|
537
578
|
return "{}";
|
|
538
579
|
const lines = entries.map(([key, item]) => {
|
|
539
|
-
const keyText =
|
|
580
|
+
const keyText = stringifyKey(key);
|
|
540
581
|
const rendered = stringifyPretty(item, depth + 1, indentSize, maxWidth);
|
|
541
582
|
return `${childIndent}${keyText}: ${rendered}`;
|
|
542
583
|
});
|
|
@@ -550,6 +591,86 @@ ${indent}}`;
|
|
|
550
591
|
function parse(source) {
|
|
551
592
|
return parseDataNode(parseToIR(source));
|
|
552
593
|
}
|
|
594
|
+
function domainRefsFromConfig(config) {
|
|
595
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
596
|
+
throw new Error("Domain config must be an object");
|
|
597
|
+
}
|
|
598
|
+
const refs = {};
|
|
599
|
+
for (const section of Object.values(config)) {
|
|
600
|
+
if (!section || typeof section !== "object" || Array.isArray(section))
|
|
601
|
+
continue;
|
|
602
|
+
mapConfigEntries(section, refs);
|
|
603
|
+
}
|
|
604
|
+
return refs;
|
|
605
|
+
}
|
|
606
|
+
function decodeDomainRefKey(refText) {
|
|
607
|
+
if (!refText)
|
|
608
|
+
throw new Error("Domain ref key cannot be empty");
|
|
609
|
+
if (!/^[0-9A-Za-z_-]+$/.test(refText)) {
|
|
610
|
+
throw new Error(`Invalid domain ref key '${refText}' (must use base64 alphabet 0-9a-zA-Z-_)`);
|
|
611
|
+
}
|
|
612
|
+
if (refText.length > 1 && refText[0] === "0") {
|
|
613
|
+
throw new Error(`Invalid domain ref key '${refText}' (leading zeroes are not allowed)`);
|
|
614
|
+
}
|
|
615
|
+
if (/^[1-9]$/.test(refText)) {
|
|
616
|
+
throw new Error(`Invalid domain ref key '${refText}' (reserved by core language)`);
|
|
617
|
+
}
|
|
618
|
+
let value = 0;
|
|
619
|
+
for (const char of refText) {
|
|
620
|
+
const digit = DOMAIN_DIGIT_INDEX.get(char);
|
|
621
|
+
if (digit === undefined)
|
|
622
|
+
throw new Error(`Invalid domain ref key '${refText}'`);
|
|
623
|
+
value = value * 64 + digit;
|
|
624
|
+
if (value > Number.MAX_SAFE_INTEGER) {
|
|
625
|
+
throw new Error(`Invalid domain ref key '${refText}' (must fit in 53 bits)`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
if (value < FIRST_NON_RESERVED_REF) {
|
|
629
|
+
throw new Error(`Invalid domain ref key '${refText}' (maps to reserved id ${value})`);
|
|
630
|
+
}
|
|
631
|
+
return value;
|
|
632
|
+
}
|
|
633
|
+
function mapConfigEntries(entries, refs) {
|
|
634
|
+
const sourceKindByRoot = new Map;
|
|
635
|
+
for (const root of Object.keys(refs)) {
|
|
636
|
+
sourceKindByRoot.set(root, "explicit");
|
|
637
|
+
}
|
|
638
|
+
for (const [refText, rawEntry] of Object.entries(entries)) {
|
|
639
|
+
const entry = rawEntry;
|
|
640
|
+
if (!entry || typeof entry !== "object")
|
|
641
|
+
continue;
|
|
642
|
+
if (!Array.isArray(entry.names))
|
|
643
|
+
continue;
|
|
644
|
+
const refId = decodeDomainRefKey(refText);
|
|
645
|
+
for (const rawName of entry.names) {
|
|
646
|
+
if (typeof rawName !== "string")
|
|
647
|
+
continue;
|
|
648
|
+
const existingNameRef = refs[rawName];
|
|
649
|
+
if (existingNameRef !== undefined && existingNameRef !== refId) {
|
|
650
|
+
throw new Error(`Conflicting refs for '${rawName}': ${existingNameRef} vs ${refId}`);
|
|
651
|
+
}
|
|
652
|
+
refs[rawName] = refId;
|
|
653
|
+
const root = rawName.split(".")[0];
|
|
654
|
+
if (!root)
|
|
655
|
+
continue;
|
|
656
|
+
const currentKind = rawName.includes(".") ? "implicit" : "explicit";
|
|
657
|
+
const existing = refs[root];
|
|
658
|
+
if (existing !== undefined) {
|
|
659
|
+
if (existing === refId)
|
|
660
|
+
continue;
|
|
661
|
+
const existingKind = sourceKindByRoot.get(root) ?? "explicit";
|
|
662
|
+
if (currentKind === "explicit") {
|
|
663
|
+
throw new Error(`Conflicting refs for '${root}': ${existing} vs ${refId}`);
|
|
664
|
+
}
|
|
665
|
+
if (existingKind === "explicit")
|
|
666
|
+
continue;
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
refs[root] = refId;
|
|
670
|
+
sourceKindByRoot.set(root, currentKind);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
553
674
|
function stringify(value, options) {
|
|
554
675
|
const indent = options?.indent ?? 2;
|
|
555
676
|
const maxWidth = options?.maxWidth ?? 80;
|
|
@@ -1116,7 +1237,16 @@ function inlineAdjacentPureAssignments(block) {
|
|
|
1116
1237
|
return out;
|
|
1117
1238
|
}
|
|
1118
1239
|
function toNumberNode(value) {
|
|
1119
|
-
|
|
1240
|
+
let raw;
|
|
1241
|
+
if (Number.isNaN(value))
|
|
1242
|
+
raw = "nan";
|
|
1243
|
+
else if (value === Infinity)
|
|
1244
|
+
raw = "inf";
|
|
1245
|
+
else if (value === -Infinity)
|
|
1246
|
+
raw = "-inf";
|
|
1247
|
+
else
|
|
1248
|
+
raw = String(value);
|
|
1249
|
+
return { type: "number", raw, value };
|
|
1120
1250
|
}
|
|
1121
1251
|
function toStringNode(value) {
|
|
1122
1252
|
return { type: "string", raw: JSON.stringify(value) };
|
|
@@ -1128,7 +1258,7 @@ function toLiteralNode(value) {
|
|
|
1128
1258
|
return { type: "null" };
|
|
1129
1259
|
if (typeof value === "boolean")
|
|
1130
1260
|
return { type: "boolean", value };
|
|
1131
|
-
if (typeof value === "number"
|
|
1261
|
+
if (typeof value === "number")
|
|
1132
1262
|
return toNumberNode(value);
|
|
1133
1263
|
if (typeof value === "string")
|
|
1134
1264
|
return toStringNode(value);
|
|
@@ -1440,12 +1570,12 @@ function optimizeNode(node, env, currentDepth, asPlace = false) {
|
|
|
1440
1570
|
if (conditionValue !== undefined || condition.type === "undefined") {
|
|
1441
1571
|
const passes = node.head === "when" ? isDefinedValue(conditionValue) : !isDefinedValue(conditionValue);
|
|
1442
1572
|
if (passes) {
|
|
1443
|
-
const
|
|
1444
|
-
if (
|
|
1573
|
+
const thenBlock2 = optimizeBlock(node.thenBlock, thenEnv, currentDepth);
|
|
1574
|
+
if (thenBlock2.length === 0)
|
|
1445
1575
|
return { type: "undefined" };
|
|
1446
|
-
if (
|
|
1447
|
-
return
|
|
1448
|
-
return { type: "program", body:
|
|
1576
|
+
if (thenBlock2.length === 1)
|
|
1577
|
+
return thenBlock2[0];
|
|
1578
|
+
return { type: "program", body: thenBlock2 };
|
|
1449
1579
|
}
|
|
1450
1580
|
if (!node.elseBranch)
|
|
1451
1581
|
return { type: "undefined" };
|
|
@@ -1467,12 +1597,26 @@ function optimizeNode(node, env, currentDepth, asPlace = false) {
|
|
|
1467
1597
|
elseBranch: loweredElse.elseBranch
|
|
1468
1598
|
};
|
|
1469
1599
|
}
|
|
1600
|
+
const thenBlock = optimizeBlock(node.thenBlock, thenEnv, currentDepth);
|
|
1601
|
+
const elseBranch = optimizeElse(node.elseBranch, cloneOptimizeEnv(env), currentDepth);
|
|
1602
|
+
let finalCondition = condition;
|
|
1603
|
+
if (condition.type === "assign" && condition.op === "=" && condition.place.type === "identifier") {
|
|
1604
|
+
const name = condition.place.name;
|
|
1605
|
+
const reads = new Set;
|
|
1606
|
+
for (const part of thenBlock)
|
|
1607
|
+
collectReads(part, reads);
|
|
1608
|
+
if (elseBranch)
|
|
1609
|
+
collectReadsElse(elseBranch, reads);
|
|
1610
|
+
if (!reads.has(name)) {
|
|
1611
|
+
finalCondition = condition.value;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1470
1614
|
return {
|
|
1471
1615
|
type: "conditional",
|
|
1472
1616
|
head: node.head,
|
|
1473
|
-
condition,
|
|
1474
|
-
thenBlock
|
|
1475
|
-
elseBranch
|
|
1617
|
+
condition: finalCondition,
|
|
1618
|
+
thenBlock,
|
|
1619
|
+
elseBranch
|
|
1476
1620
|
};
|
|
1477
1621
|
}
|
|
1478
1622
|
case "for": {
|
|
@@ -1927,13 +2071,20 @@ function compile(source, options) {
|
|
|
1927
2071
|
let lowered = options?.optimize ? optimizeIR(ir) : ir;
|
|
1928
2072
|
if (options?.minifyNames)
|
|
1929
2073
|
lowered = minifyLocalNamesIR(lowered);
|
|
2074
|
+
const domainRefs = options?.domainConfig ? domainRefsFromConfig(options.domainConfig) : undefined;
|
|
1930
2075
|
return encodeIR(lowered, {
|
|
1931
|
-
domainRefs
|
|
2076
|
+
domainRefs,
|
|
1932
2077
|
dedupeValues: options?.dedupeValues,
|
|
1933
2078
|
dedupeMinBytes: options?.dedupeMinBytes
|
|
1934
2079
|
});
|
|
1935
2080
|
}
|
|
1936
2081
|
function parseNumber(raw) {
|
|
2082
|
+
if (raw === "nan")
|
|
2083
|
+
return NaN;
|
|
2084
|
+
if (raw === "inf")
|
|
2085
|
+
return Infinity;
|
|
2086
|
+
if (raw === "-inf")
|
|
2087
|
+
return -Infinity;
|
|
1937
2088
|
if (/^-?0x/i.test(raw))
|
|
1938
2089
|
return parseInt(raw, 16);
|
|
1939
2090
|
if (/^-?0b/i.test(raw)) {
|
|
@@ -2158,6 +2309,13 @@ semantics.addOperation("toIR", {
|
|
|
2158
2309
|
return body[0];
|
|
2159
2310
|
return { type: "program", body };
|
|
2160
2311
|
},
|
|
2312
|
+
WhileExpr(_while, condition, _do, block, _end) {
|
|
2313
|
+
return {
|
|
2314
|
+
type: "while",
|
|
2315
|
+
condition: condition.toIR(),
|
|
2316
|
+
body: block.toIR()
|
|
2317
|
+
};
|
|
2318
|
+
},
|
|
2161
2319
|
ForExpr(_for, binding, _do, block, _end) {
|
|
2162
2320
|
return {
|
|
2163
2321
|
type: "for",
|
|
@@ -2304,16 +2462,13 @@ var rex_default = semantics;
|
|
|
2304
2462
|
export {
|
|
2305
2463
|
stringify,
|
|
2306
2464
|
semantics,
|
|
2307
|
-
registerDomainExtensionRefs,
|
|
2308
|
-
registerDomainExtensionRef,
|
|
2309
2465
|
parseToIR,
|
|
2310
2466
|
parse,
|
|
2311
2467
|
optimizeIR,
|
|
2312
2468
|
minifyLocalNamesIR,
|
|
2313
2469
|
grammar,
|
|
2314
|
-
getRegisteredDomainExtensionRefs,
|
|
2315
2470
|
encodeIR,
|
|
2471
|
+
domainRefsFromConfig,
|
|
2316
2472
|
rex_default as default,
|
|
2317
|
-
compile
|
|
2318
|
-
clearDomainExtensionRefs
|
|
2473
|
+
compile
|
|
2319
2474
|
};
|
package/rex.ohm
CHANGED
|
@@ -38,7 +38,7 @@ Rex {
|
|
|
38
38
|
| UnaryExpr -- value
|
|
39
39
|
|
|
40
40
|
UnaryExpr
|
|
41
|
-
= "-" ~digit UnaryExpr
|
|
41
|
+
= "-" ~digit ~infTok UnaryExpr -- neg
|
|
42
42
|
| "~" UnaryExpr -- not
|
|
43
43
|
| DeleteKw Place -- delete
|
|
44
44
|
| PostfixExpr -- value
|
|
@@ -47,7 +47,7 @@ Rex {
|
|
|
47
47
|
= PrimaryExpr PostfixTail* -- chain
|
|
48
48
|
|
|
49
49
|
PostfixTail
|
|
50
|
-
= "."
|
|
50
|
+
= "." navKey -- navStatic
|
|
51
51
|
| ".(" Expr ")" -- navDynamic
|
|
52
52
|
| "(" ")" -- callEmpty
|
|
53
53
|
| "(" Elements<Expr> ")" -- call
|
|
@@ -56,6 +56,7 @@ Rex {
|
|
|
56
56
|
= ConditionalExpr
|
|
57
57
|
| DoExpr
|
|
58
58
|
| ForExpr
|
|
59
|
+
| WhileExpr
|
|
59
60
|
| BreakKw -- break
|
|
60
61
|
| ContinueKw -- continue
|
|
61
62
|
| Array
|
|
@@ -87,7 +88,7 @@ Rex {
|
|
|
87
88
|
| SelfKw
|
|
88
89
|
|
|
89
90
|
PlaceTail
|
|
90
|
-
= "."
|
|
91
|
+
= "." navKey -- navStatic
|
|
91
92
|
| ".(" Expr ")" -- navDynamic
|
|
92
93
|
|
|
93
94
|
ConditionalExpr
|
|
@@ -104,6 +105,9 @@ Rex {
|
|
|
104
105
|
ForExpr
|
|
105
106
|
= ForKw BindingExpr DoKw Block EndKw
|
|
106
107
|
|
|
108
|
+
WhileExpr
|
|
109
|
+
= WhileKw Expr DoKw Block EndKw
|
|
110
|
+
|
|
107
111
|
DoExpr
|
|
108
112
|
= DoKw Block EndKw
|
|
109
113
|
|
|
@@ -138,6 +142,10 @@ Rex {
|
|
|
138
142
|
| String -- string
|
|
139
143
|
| "(" Expr ")" -- computed
|
|
140
144
|
|
|
145
|
+
navKey
|
|
146
|
+
= keyName
|
|
147
|
+
| digit+
|
|
148
|
+
|
|
141
149
|
keyName
|
|
142
150
|
= nameHead nameTail*
|
|
143
151
|
|
|
@@ -181,10 +189,13 @@ Rex {
|
|
|
181
189
|
| falseTok
|
|
182
190
|
| nullTok
|
|
183
191
|
| undefinedTok
|
|
192
|
+
| nanTok
|
|
193
|
+
| infTok
|
|
184
194
|
| selfTok
|
|
185
195
|
| whenTok
|
|
186
196
|
| unlessTok
|
|
187
197
|
| forTok
|
|
198
|
+
| whileTok
|
|
188
199
|
| inTok
|
|
189
200
|
| ofTok
|
|
190
201
|
| doTok
|
|
@@ -222,6 +233,9 @@ Rex {
|
|
|
222
233
|
UnlessKw
|
|
223
234
|
= unlessTok
|
|
224
235
|
|
|
236
|
+
WhileKw
|
|
237
|
+
= whileTok
|
|
238
|
+
|
|
225
239
|
ForKw
|
|
226
240
|
= forTok
|
|
227
241
|
|
|
@@ -276,6 +290,12 @@ Rex {
|
|
|
276
290
|
undefinedTok
|
|
277
291
|
= "undefined" ~nameTail
|
|
278
292
|
|
|
293
|
+
nanTok
|
|
294
|
+
= "nan" ~nameTail
|
|
295
|
+
|
|
296
|
+
infTok
|
|
297
|
+
= "inf" ~nameTail
|
|
298
|
+
|
|
279
299
|
selfTok
|
|
280
300
|
= "self" ~nameTail
|
|
281
301
|
|
|
@@ -285,6 +305,9 @@ Rex {
|
|
|
285
305
|
unlessTok
|
|
286
306
|
= "unless" ~nameTail
|
|
287
307
|
|
|
308
|
+
whileTok
|
|
309
|
+
= "while" ~nameTail
|
|
310
|
+
|
|
288
311
|
forTok
|
|
289
312
|
= "for" ~nameTail
|
|
290
313
|
|
|
@@ -371,8 +394,16 @@ Rex {
|
|
|
371
394
|
Number
|
|
372
395
|
= hexNumber
|
|
373
396
|
| binaryNumber
|
|
397
|
+
| infLiteral
|
|
398
|
+
| nanLiteral
|
|
374
399
|
| decimalNumber
|
|
375
400
|
|
|
401
|
+
infLiteral
|
|
402
|
+
= "-"? infTok
|
|
403
|
+
|
|
404
|
+
nanLiteral
|
|
405
|
+
= nanTok
|
|
406
|
+
|
|
376
407
|
hexNumber
|
|
377
408
|
= "-"? "0x" hex+
|
|
378
409
|
|