@creationix/rex 0.3.0 → 0.4.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/rex.js CHANGED
@@ -10,31 +10,32 @@ function byteLength(value) {
10
10
  return Buffer.byteLength(value, "utf8");
11
11
  }
12
12
  var OPCODE_IDS = {
13
- do: 0,
14
- add: 1,
15
- sub: 2,
16
- mul: 3,
17
- div: 4,
18
- eq: 5,
19
- neq: 6,
20
- lt: 7,
21
- lte: 8,
22
- gt: 9,
23
- gte: 10,
24
- and: 11,
25
- or: 12,
26
- xor: 13,
27
- not: 14,
28
- boolean: 15,
29
- number: 16,
30
- string: 17,
31
- array: 18,
32
- object: 19,
33
- mod: 20,
34
- neg: 21
13
+ do: "",
14
+ add: "ad",
15
+ sub: "sb",
16
+ mul: "ml",
17
+ div: "dv",
18
+ eq: "eq",
19
+ neq: "nq",
20
+ lt: "lt",
21
+ lte: "le",
22
+ gt: "gt",
23
+ gte: "ge",
24
+ and: "an",
25
+ or: "or",
26
+ xor: "xr",
27
+ not: "nt",
28
+ boolean: "bt",
29
+ number: "nm",
30
+ string: "st",
31
+ array: "ar",
32
+ object: "ob",
33
+ mod: "md",
34
+ neg: "ng",
35
+ range: "rn",
36
+ size: "sz"
35
37
  };
36
- var FIRST_NON_RESERVED_REF = 5;
37
- var DOMAIN_DIGIT_INDEX = new Map(Array.from(DIGITS).map((char, index) => [char, index]));
38
+ var KEYWORD_OPCODES = new Set(["boolean", "number", "string", "array", "object", "size"]);
38
39
  var BINARY_TO_OPCODE = {
39
40
  add: "add",
40
41
  sub: "sub",
@@ -147,12 +148,33 @@ function encodeBareOrLengthString(value) {
147
148
  return `${value}:`;
148
149
  return `${encodeUint(byteLength(value))},${value}`;
149
150
  }
151
+ var DEC_PARTS = /^(-?\d)(?:\.(\d+))?e([+-]\d+)$/;
152
+ function splitDecimal(num) {
153
+ const match = num.toExponential().match(DEC_PARTS);
154
+ if (!match)
155
+ throw new Error(`Failed to split decimal for ${num}`);
156
+ const [, b1, b2 = "", e1] = match;
157
+ const base = Number.parseInt(b1 + b2, 10);
158
+ const exp = Number.parseInt(e1, 10) - b2.length;
159
+ return { base, exp };
160
+ }
161
+ function encodeDecimal(significand, power) {
162
+ return `${encodeZigzag(power)}*${encodeInt(significand)}`;
163
+ }
150
164
  function encodeNumberNode(node) {
151
165
  const numberValue = node.value;
152
- if (!Number.isFinite(numberValue))
153
- throw new Error(`Cannot encode non-finite number: ${node.raw}`);
154
- if (Number.isInteger(numberValue))
155
- return encodeInt(numberValue);
166
+ if (Number.isNaN(numberValue))
167
+ return "nan'";
168
+ if (numberValue === Infinity)
169
+ return "inf'";
170
+ if (numberValue === -Infinity)
171
+ return "nif'";
172
+ if (Number.isInteger(numberValue)) {
173
+ const { base, exp } = splitDecimal(numberValue);
174
+ if (exp >= 0 && exp <= 4)
175
+ return encodeInt(numberValue);
176
+ return encodeDecimal(base, exp);
177
+ }
156
178
  const raw = node.raw.toLowerCase();
157
179
  const sign = raw.startsWith("-") ? -1 : 1;
158
180
  const unsigned = sign < 0 ? raw.slice(1) : raw;
@@ -175,10 +197,10 @@ function encodeNumberNode(node) {
175
197
  significand /= 10;
176
198
  power += 1;
177
199
  }
178
- return `${encodeZigzag(power)}*${encodeInt(significand)}`;
200
+ return encodeDecimal(significand, power);
179
201
  }
180
202
  function encodeOpcode(opcode) {
181
- return `${encodeUint(OPCODE_IDS[opcode])}%`;
203
+ return `${OPCODE_IDS[opcode]}%`;
182
204
  }
183
205
  function encodeCallParts(parts) {
184
206
  return `(${parts.join("")})`;
@@ -195,7 +217,7 @@ function addOptionalPrefix(encoded) {
195
217
  let payload = encoded;
196
218
  if (encoded.startsWith("?(") || encoded.startsWith("!(") || encoded.startsWith("|(") || encoded.startsWith("&(") || encoded.startsWith(">(") || encoded.startsWith("<(") || encoded.startsWith("#(")) {
197
219
  payload = encoded.slice(2, -1);
198
- } else if (encoded.startsWith(">[") || encoded.startsWith(">{")) {
220
+ } else if (encoded.startsWith(">[") || encoded.startsWith(">{") || encoded.startsWith("<[") || encoded.startsWith("<{") || encoded.startsWith("#[") || encoded.startsWith("#{")) {
199
221
  payload = encoded.slice(2, -1);
200
222
  } else if (encoded.startsWith("[") || encoded.startsWith("{") || encoded.startsWith("(")) {
201
223
  payload = encoded.slice(1, -1);
@@ -206,7 +228,7 @@ function addOptionalPrefix(encoded) {
206
228
  }
207
229
  function encodeBlockExpression(block) {
208
230
  if (block.length === 0)
209
- return "4'";
231
+ return "un'";
210
232
  if (block.length === 1)
211
233
  return encodeNode(block[0]);
212
234
  return encodeCallParts([encodeOpcode("do"), ...block.map((node) => encodeNode(node))]);
@@ -223,9 +245,13 @@ function encodeConditionalElse(elseBranch) {
223
245
  };
224
246
  return encodeNode(nested);
225
247
  }
248
+ function encodeDomainLookup(shortCode, tag) {
249
+ return `${shortCode}${tag}`;
250
+ }
226
251
  function encodeNavigation(node) {
227
252
  const domainRefs = activeEncodeOptions?.domainRefs;
228
- if (domainRefs && node.target.type === "identifier") {
253
+ const domainOpcodes = activeEncodeOptions?.domainOpcodes;
254
+ if ((domainRefs || domainOpcodes) && node.target.type === "identifier") {
229
255
  const staticPath = [node.target.name];
230
256
  for (const segment of node.segments) {
231
257
  if (segment.type !== "static")
@@ -234,14 +260,17 @@ function encodeNavigation(node) {
234
260
  }
235
261
  for (let pathLength = staticPath.length;pathLength >= 1; pathLength -= 1) {
236
262
  const dottedName = staticPath.slice(0, pathLength).join(".");
237
- const domainRef = domainRefs[dottedName];
238
- if (domainRef === undefined)
263
+ const refCode = domainRefs?.[dottedName];
264
+ const opcodeCode = domainOpcodes?.[dottedName];
265
+ const shortCode = refCode ?? opcodeCode;
266
+ if (shortCode === undefined)
239
267
  continue;
268
+ const tag = refCode !== undefined ? "'" : "%";
240
269
  const consumedStaticSegments = pathLength - 1;
241
270
  if (consumedStaticSegments === node.segments.length) {
242
- return `${encodeUint(domainRef)}'`;
271
+ return encodeDomainLookup(shortCode, tag);
243
272
  }
244
- const parts2 = [`${encodeUint(domainRef)}'`];
273
+ const parts2 = [encodeDomainLookup(shortCode, tag)];
245
274
  for (const segment of node.segments.slice(consumedStaticSegments)) {
246
275
  if (segment.type === "static")
247
276
  parts2.push(encodeBareOrLengthString(segment.key));
@@ -267,9 +296,12 @@ function encodeWhile(node) {
267
296
  }
268
297
  function encodeFor(node) {
269
298
  const body = addOptionalPrefix(encodeBlockExpression(node.body));
270
- if (node.binding.type === "binding:expr") {
299
+ if (node.binding.type === "binding:bareIn") {
271
300
  return `>(${encodeNode(node.binding.source)}${body})`;
272
301
  }
302
+ if (node.binding.type === "binding:bareOf") {
303
+ return `<(${encodeNode(node.binding.source)}${body})`;
304
+ }
273
305
  if (node.binding.type === "binding:valueIn") {
274
306
  return `>(${encodeNode(node.binding.source)}${node.binding.value}$${body})`;
275
307
  }
@@ -280,30 +312,47 @@ function encodeFor(node) {
280
312
  }
281
313
  function encodeArrayComprehension(node) {
282
314
  const body = addOptionalPrefix(encodeNode(node.body));
283
- if (node.binding.type === "binding:expr") {
315
+ if (node.binding.type === "binding:bareIn") {
284
316
  return `>[${encodeNode(node.binding.source)}${body}]`;
285
317
  }
318
+ if (node.binding.type === "binding:bareOf") {
319
+ return `<[${encodeNode(node.binding.source)}${body}]`;
320
+ }
286
321
  if (node.binding.type === "binding:valueIn") {
287
322
  return `>[${encodeNode(node.binding.source)}${node.binding.value}$${body}]`;
288
323
  }
289
324
  if (node.binding.type === "binding:keyValueIn") {
290
325
  return `>[${encodeNode(node.binding.source)}${node.binding.key}$${node.binding.value}$${body}]`;
291
326
  }
292
- return `>[${encodeNode(node.binding.source)}${node.binding.key}$${body}]`;
327
+ return `<[${encodeNode(node.binding.source)}${node.binding.key}$${body}]`;
293
328
  }
294
329
  function encodeObjectComprehension(node) {
295
330
  const key = addOptionalPrefix(encodeNode(node.key));
296
331
  const value = addOptionalPrefix(encodeNode(node.value));
297
- if (node.binding.type === "binding:expr") {
332
+ if (node.binding.type === "binding:bareIn") {
298
333
  return `>{${encodeNode(node.binding.source)}${key}${value}}`;
299
334
  }
335
+ if (node.binding.type === "binding:bareOf") {
336
+ return `<{${encodeNode(node.binding.source)}${key}${value}}`;
337
+ }
300
338
  if (node.binding.type === "binding:valueIn") {
301
339
  return `>{${encodeNode(node.binding.source)}${node.binding.value}$${key}${value}}`;
302
340
  }
303
341
  if (node.binding.type === "binding:keyValueIn") {
304
342
  return `>{${encodeNode(node.binding.source)}${node.binding.key}$${node.binding.value}$${key}${value}}`;
305
343
  }
306
- return `>{${encodeNode(node.binding.source)}${node.binding.key}$${key}${value}}`;
344
+ return `<{${encodeNode(node.binding.source)}${node.binding.key}$${key}${value}}`;
345
+ }
346
+ function encodeWhileArrayComprehension(node) {
347
+ const cond = encodeNode(node.condition);
348
+ const body = addOptionalPrefix(encodeNode(node.body));
349
+ return `#[${cond}${body}]`;
350
+ }
351
+ function encodeWhileObjectComprehension(node) {
352
+ const cond = encodeNode(node.condition);
353
+ const key = addOptionalPrefix(encodeNode(node.key));
354
+ const value = addOptionalPrefix(encodeNode(node.value));
355
+ return `#{${cond}${key}${value}}`;
307
356
  }
308
357
  var activeEncodeOptions;
309
358
  function encodeNode(node) {
@@ -313,7 +362,10 @@ function encodeNode(node) {
313
362
  case "identifier": {
314
363
  const domainRef = activeEncodeOptions?.domainRefs?.[node.name];
315
364
  if (domainRef !== undefined)
316
- return `${encodeUint(domainRef)}'`;
365
+ return `${domainRef}'`;
366
+ const domainOpcode = activeEncodeOptions?.domainOpcodes?.[node.name];
367
+ if (domainOpcode !== undefined)
368
+ return `${domainOpcode}%`;
317
369
  return `${node.name}$`;
318
370
  }
319
371
  case "self":
@@ -326,11 +378,11 @@ function encodeNode(node) {
326
378
  return `${encodeUint(node.depth - 1)}@`;
327
379
  }
328
380
  case "boolean":
329
- return node.value ? "1'" : "2'";
381
+ return node.value ? "tr'" : "fl'";
330
382
  case "null":
331
- return "3'";
383
+ return "nl'";
332
384
  case "undefined":
333
- return "4'";
385
+ return "un'";
334
386
  case "number":
335
387
  return encodeNumberNode(node);
336
388
  case "string":
@@ -341,12 +393,16 @@ function encodeNode(node) {
341
393
  }
342
394
  case "arrayComprehension":
343
395
  return encodeArrayComprehension(node);
396
+ case "whileArrayComprehension":
397
+ return encodeWhileArrayComprehension(node);
344
398
  case "object": {
345
399
  const body = node.entries.map(({ key, value }) => `${encodeNode(key)}${addOptionalPrefix(encodeNode(value))}`).join("");
346
400
  return `{${body}}`;
347
401
  }
348
402
  case "objectComprehension":
349
403
  return encodeObjectComprehension(node);
404
+ case "whileObjectComprehension":
405
+ return encodeWhileObjectComprehension(node);
350
406
  case "key":
351
407
  return encodeBareOrLengthString(node.name);
352
408
  case "group":
@@ -356,6 +412,10 @@ function encodeNode(node) {
356
412
  return `~${encodeNode(node.value)}`;
357
413
  if (node.op === "neg")
358
414
  return encodeCallParts([encodeOpcode("neg"), encodeNode(node.value)]);
415
+ if (node.op === "logicalNot") {
416
+ const val = encodeNode(node.value);
417
+ return `!(${val}tr')`;
418
+ }
359
419
  return encodeCallParts([encodeOpcode("not"), encodeNode(node.value)]);
360
420
  case "binary":
361
421
  if (node.op === "and") {
@@ -374,12 +434,19 @@ function encodeNode(node) {
374
434
  }).join("");
375
435
  return `|(${body})`;
376
436
  }
437
+ if (node.op === "nor") {
438
+ const left = encodeNode(node.left);
439
+ const right = addOptionalPrefix(encodeNode(node.right));
440
+ return `!(${left}${right})`;
441
+ }
377
442
  return encodeCallParts([
378
443
  encodeOpcode(BINARY_TO_OPCODE[node.op]),
379
444
  encodeNode(node.left),
380
445
  encodeNode(node.right)
381
446
  ]);
382
447
  case "assign": {
448
+ if (node.op === ":=")
449
+ return `/${encodeNode(node.place)}${addOptionalPrefix(encodeNode(node.value))}`;
383
450
  if (node.op === "=")
384
451
  return `=${encodeNode(node.place)}${addOptionalPrefix(encodeNode(node.value))}`;
385
452
  const opcode = ASSIGN_COMPOUND_TO_OPCODE[node.op];
@@ -390,8 +457,12 @@ function encodeNode(node) {
390
457
  }
391
458
  case "navigation":
392
459
  return encodeNavigation(node);
393
- case "call":
460
+ case "call": {
461
+ if (node.callee.type === "identifier" && KEYWORD_OPCODES.has(node.callee.name)) {
462
+ return encodeCallParts([encodeOpcode(node.callee.name), ...node.args.map((arg) => encodeNode(arg))]);
463
+ }
394
464
  return encodeCallParts([encodeNode(node.callee), ...node.args.map((arg) => encodeNode(arg))]);
465
+ }
395
466
  case "conditional": {
396
467
  const opener = node.head === "when" ? "?(" : "!(";
397
468
  const cond = encodeNode(node.condition);
@@ -399,6 +470,8 @@ function encodeNode(node) {
399
470
  const elseExpr = node.elseBranch ? addOptionalPrefix(encodeConditionalElse(node.elseBranch)) : "";
400
471
  return `${opener}${cond}${thenExpr}${elseExpr})`;
401
472
  }
473
+ case "range":
474
+ return encodeCallParts([encodeOpcode("range"), encodeNode(node.from), encodeNode(node.to)]);
402
475
  case "for":
403
476
  return encodeFor(node);
404
477
  case "while":
@@ -477,6 +550,18 @@ function isPlainObject(value) {
477
550
  function isBareKeyName(key) {
478
551
  return /^[A-Za-z_][A-Za-z0-9_-]*$/.test(key);
479
552
  }
553
+ function isNumericKey(key) {
554
+ if (key === "")
555
+ return false;
556
+ return String(Number(key)) === key && Number.isFinite(Number(key));
557
+ }
558
+ function stringifyKey(key) {
559
+ if (isBareKeyName(key))
560
+ return key;
561
+ if (isNumericKey(key))
562
+ return key;
563
+ return stringifyString(key);
564
+ }
480
565
  function stringifyString(value) {
481
566
  return JSON.stringify(value);
482
567
  }
@@ -488,8 +573,12 @@ function stringifyInline(value) {
488
573
  if (typeof value === "boolean")
489
574
  return value ? "true" : "false";
490
575
  if (typeof value === "number") {
491
- if (!Number.isFinite(value))
492
- throw new Error("Rex stringify() cannot encode non-finite numbers");
576
+ if (Number.isNaN(value))
577
+ return "nan";
578
+ if (value === Infinity)
579
+ return "inf";
580
+ if (value === -Infinity)
581
+ return "-inf";
493
582
  return String(value);
494
583
  }
495
584
  if (typeof value === "string")
@@ -503,7 +592,7 @@ function stringifyInline(value) {
503
592
  const entries = Object.entries(value);
504
593
  if (entries.length === 0)
505
594
  return "{}";
506
- const body = entries.map(([key, item]) => `${isBareKeyName(key) ? key : stringifyString(key)}: ${stringifyInline(item)}`).join(" ");
595
+ const body = entries.map(([key, item]) => `${stringifyKey(key)}: ${stringifyInline(item)}`).join(" ");
507
596
  return `{${body}}`;
508
597
  }
509
598
  throw new Error(`Rex stringify() cannot encode value of type ${typeof value}`);
@@ -540,7 +629,7 @@ ${indent}]`;
540
629
  if (entries.length === 0)
541
630
  return "{}";
542
631
  const lines = entries.map(([key, item]) => {
543
- const keyText = isBareKeyName(key) ? key : stringifyString(key);
632
+ const keyText = stringifyKey(key);
544
633
  const rendered = stringifyPretty(item, depth + 1, indentSize, maxWidth);
545
634
  return `${childIndent}${keyText}: ${rendered}`;
546
635
  });
@@ -558,78 +647,55 @@ function domainRefsFromConfig(config) {
558
647
  if (!config || typeof config !== "object" || Array.isArray(config)) {
559
648
  throw new Error("Domain config must be an object");
560
649
  }
561
- const refs = {};
562
- for (const section of Object.values(config)) {
563
- if (!section || typeof section !== "object" || Array.isArray(section))
564
- continue;
565
- mapConfigEntries(section, refs);
566
- }
567
- return refs;
568
- }
569
- function decodeDomainRefKey(refText) {
570
- if (!refText)
571
- throw new Error("Domain ref key cannot be empty");
572
- if (!/^[0-9A-Za-z_-]+$/.test(refText)) {
573
- throw new Error(`Invalid domain ref key '${refText}' (must use base64 alphabet 0-9a-zA-Z-_)`);
574
- }
575
- if (refText.length > 1 && refText[0] === "0") {
576
- throw new Error(`Invalid domain ref key '${refText}' (leading zeroes are not allowed)`);
577
- }
578
- if (/^[1-9]$/.test(refText)) {
579
- throw new Error(`Invalid domain ref key '${refText}' (reserved by core language)`);
580
- }
581
- let value = 0;
582
- for (const char of refText) {
583
- const digit = DOMAIN_DIGIT_INDEX.get(char);
584
- if (digit === undefined)
585
- throw new Error(`Invalid domain ref key '${refText}'`);
586
- value = value * 64 + digit;
587
- if (value > Number.MAX_SAFE_INTEGER) {
588
- throw new Error(`Invalid domain ref key '${refText}' (must fit in 53 bits)`);
589
- }
650
+ const configObj = config;
651
+ const domainRefs = {};
652
+ const domainOpcodes = {};
653
+ const dataSection = configObj.data;
654
+ if (dataSection && typeof dataSection === "object" && !Array.isArray(dataSection)) {
655
+ mapConfigEntries(dataSection, domainRefs);
590
656
  }
591
- if (value < FIRST_NON_RESERVED_REF) {
592
- throw new Error(`Invalid domain ref key '${refText}' (maps to reserved id ${value})`);
657
+ const functionsSection = configObj.functions;
658
+ if (functionsSection && typeof functionsSection === "object" && !Array.isArray(functionsSection)) {
659
+ mapConfigEntries(functionsSection, domainOpcodes);
593
660
  }
594
- return value;
661
+ return { domainRefs, domainOpcodes };
595
662
  }
596
663
  function mapConfigEntries(entries, refs) {
597
664
  const sourceKindByRoot = new Map;
598
665
  for (const root of Object.keys(refs)) {
599
666
  sourceKindByRoot.set(root, "explicit");
600
667
  }
601
- for (const [refText, rawEntry] of Object.entries(entries)) {
668
+ for (const [shortCode, rawEntry] of Object.entries(entries)) {
602
669
  const entry = rawEntry;
603
670
  if (!entry || typeof entry !== "object")
604
671
  continue;
605
672
  if (!Array.isArray(entry.names))
606
673
  continue;
607
- const refId = decodeDomainRefKey(refText);
608
674
  for (const rawName of entry.names) {
609
675
  if (typeof rawName !== "string")
610
676
  continue;
611
- const existingNameRef = refs[rawName];
612
- if (existingNameRef !== undefined && existingNameRef !== refId) {
613
- throw new Error(`Conflicting refs for '${rawName}': ${existingNameRef} vs ${refId}`);
677
+ const existingRef = refs[rawName];
678
+ if (existingRef !== undefined && existingRef !== shortCode) {
679
+ throw new Error(`Conflicting refs for '${rawName}': ${existingRef} vs ${shortCode}`);
614
680
  }
615
- refs[rawName] = refId;
681
+ refs[rawName] = shortCode;
616
682
  const root = rawName.split(".")[0];
617
683
  if (!root)
618
684
  continue;
619
685
  const currentKind = rawName.includes(".") ? "implicit" : "explicit";
620
686
  const existing = refs[root];
621
687
  if (existing !== undefined) {
622
- if (existing === refId)
688
+ if (existing === shortCode)
623
689
  continue;
624
690
  const existingKind = sourceKindByRoot.get(root) ?? "explicit";
625
691
  if (currentKind === "explicit") {
626
- throw new Error(`Conflicting refs for '${root}': ${existing} vs ${refId}`);
692
+ throw new Error(`Conflicting refs for '${root}': ${existing} vs ${shortCode}`);
627
693
  }
628
694
  if (existingKind === "explicit")
629
695
  continue;
630
696
  continue;
631
697
  }
632
- refs[root] = refId;
698
+ refs[root] = shortCode;
633
699
  sourceKindByRoot.set(root, currentKind);
634
700
  }
635
701
  }
@@ -913,6 +979,21 @@ function dropBindingNames(env, binding) {
913
979
  clearBinding(env, binding.key);
914
980
  }
915
981
  }
982
+ function optimizeBinding(binding, sourceEnv, currentDepth) {
983
+ const source = optimizeNode(binding.source, sourceEnv, currentDepth);
984
+ switch (binding.type) {
985
+ case "binding:bareIn":
986
+ return { type: "binding:bareIn", source };
987
+ case "binding:bareOf":
988
+ return { type: "binding:bareOf", source };
989
+ case "binding:valueIn":
990
+ return { type: "binding:valueIn", value: binding.value, source };
991
+ case "binding:keyValueIn":
992
+ return { type: "binding:keyValueIn", key: binding.key, value: binding.value, source };
993
+ case "binding:keyOf":
994
+ return { type: "binding:keyOf", key: binding.key, source };
995
+ }
996
+ }
916
997
  function collectReads(node, out) {
917
998
  switch (node.type) {
918
999
  case "identifier":
@@ -935,11 +1016,20 @@ function collectReads(node, out) {
935
1016
  collectReads(node.binding.source, out);
936
1017
  collectReads(node.body, out);
937
1018
  return;
1019
+ case "whileArrayComprehension":
1020
+ collectReads(node.condition, out);
1021
+ collectReads(node.body, out);
1022
+ return;
938
1023
  case "objectComprehension":
939
1024
  collectReads(node.binding.source, out);
940
1025
  collectReads(node.key, out);
941
1026
  collectReads(node.value, out);
942
1027
  return;
1028
+ case "whileObjectComprehension":
1029
+ collectReads(node.condition, out);
1030
+ collectReads(node.key, out);
1031
+ collectReads(node.value, out);
1032
+ return;
943
1033
  case "unary":
944
1034
  collectReads(node.value, out);
945
1035
  return;
@@ -976,6 +1066,10 @@ function collectReads(node, out) {
976
1066
  for (const part of node.body)
977
1067
  collectReads(part, out);
978
1068
  return;
1069
+ case "range":
1070
+ collectReads(node.from, out);
1071
+ collectReads(node.to, out);
1072
+ return;
979
1073
  case "program":
980
1074
  for (const part of node.body)
981
1075
  collectReads(part, out);
@@ -1020,6 +1114,8 @@ function isPureNode(node) {
1020
1114
  return node.op !== "delete" && isPureNode(node.value);
1021
1115
  case "binary":
1022
1116
  return isPureNode(node.left) && isPureNode(node.right);
1117
+ case "range":
1118
+ return isPureNode(node.from) && isPureNode(node.to);
1023
1119
  default:
1024
1120
  return false;
1025
1121
  }
@@ -1084,6 +1180,8 @@ function hasIdentifierRead(node, name, asPlace = false) {
1084
1180
  return hasIdentifierRead(node.value, name, node.op === "delete");
1085
1181
  case "binary":
1086
1182
  return hasIdentifierRead(node.left, name) || hasIdentifierRead(node.right, name);
1183
+ case "range":
1184
+ return hasIdentifierRead(node.from, name) || hasIdentifierRead(node.to, name);
1087
1185
  case "assign":
1088
1186
  return hasIdentifierRead(node.place, name, true) || hasIdentifierRead(node.value, name);
1089
1187
  default:
@@ -1106,6 +1204,8 @@ function countIdentifierReads(node, name, asPlace = false) {
1106
1204
  return countIdentifierReads(node.value, name, node.op === "delete");
1107
1205
  case "binary":
1108
1206
  return countIdentifierReads(node.left, name) + countIdentifierReads(node.right, name);
1207
+ case "range":
1208
+ return countIdentifierReads(node.from, name) + countIdentifierReads(node.to, name);
1109
1209
  case "assign":
1110
1210
  return countIdentifierReads(node.place, name, true) + countIdentifierReads(node.value, name);
1111
1211
  default:
@@ -1160,6 +1260,12 @@ function replaceIdentifier(node, name, replacement, asPlace = false) {
1160
1260
  place: replaceIdentifier(node.place, name, replacement, true),
1161
1261
  value: replaceIdentifier(node.value, name, replacement)
1162
1262
  };
1263
+ case "range":
1264
+ return {
1265
+ type: "range",
1266
+ from: replaceIdentifier(node.from, name, replacement),
1267
+ to: replaceIdentifier(node.to, name, replacement)
1268
+ };
1163
1269
  default:
1164
1270
  return node;
1165
1271
  }
@@ -1200,7 +1306,16 @@ function inlineAdjacentPureAssignments(block) {
1200
1306
  return out;
1201
1307
  }
1202
1308
  function toNumberNode(value) {
1203
- return { type: "number", raw: String(value), value };
1309
+ let raw;
1310
+ if (Number.isNaN(value))
1311
+ raw = "nan";
1312
+ else if (value === Infinity)
1313
+ raw = "inf";
1314
+ else if (value === -Infinity)
1315
+ raw = "-inf";
1316
+ else
1317
+ raw = String(value);
1318
+ return { type: "number", raw, value };
1204
1319
  }
1205
1320
  function toStringNode(value) {
1206
1321
  return { type: "string", raw: JSON.stringify(value) };
@@ -1212,7 +1327,7 @@ function toLiteralNode(value) {
1212
1327
  return { type: "null" };
1213
1328
  if (typeof value === "boolean")
1214
1329
  return { type: "boolean", value };
1215
- if (typeof value === "number" && Number.isFinite(value))
1330
+ if (typeof value === "number")
1216
1331
  return toNumberNode(value);
1217
1332
  if (typeof value === "string")
1218
1333
  return toStringNode(value);
@@ -1295,6 +1410,9 @@ function foldUnary(op, value) {
1295
1410
  return ~value;
1296
1411
  return;
1297
1412
  }
1413
+ if (op === "logicalNot") {
1414
+ return value === undefined ? true : undefined;
1415
+ }
1298
1416
  return;
1299
1417
  }
1300
1418
  function foldBinary(op, left, right) {
@@ -1465,6 +1583,12 @@ function optimizeNode(node, env, currentDepth, asPlace = false) {
1465
1583
  }
1466
1584
  return { type: "binary", op: node.op, left, right };
1467
1585
  }
1586
+ case "range":
1587
+ return {
1588
+ type: "range",
1589
+ from: optimizeNode(node.from, env, currentDepth),
1590
+ to: optimizeNode(node.to, env, currentDepth)
1591
+ };
1468
1592
  case "navigation": {
1469
1593
  const target = optimizeNode(node.target, env, currentDepth);
1470
1594
  const segments = node.segments.map((segment) => segment.type === "static" ? segment : { type: "dynamic", key: optimizeNode(segment.key, env, currentDepth) });
@@ -1575,31 +1699,7 @@ function optimizeNode(node, env, currentDepth, asPlace = false) {
1575
1699
  }
1576
1700
  case "for": {
1577
1701
  const sourceEnv = cloneOptimizeEnv(env);
1578
- const binding = (() => {
1579
- if (node.binding.type === "binding:expr") {
1580
- return { type: "binding:expr", source: optimizeNode(node.binding.source, sourceEnv, currentDepth) };
1581
- }
1582
- if (node.binding.type === "binding:valueIn") {
1583
- return {
1584
- type: "binding:valueIn",
1585
- value: node.binding.value,
1586
- source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
1587
- };
1588
- }
1589
- if (node.binding.type === "binding:keyValueIn") {
1590
- return {
1591
- type: "binding:keyValueIn",
1592
- key: node.binding.key,
1593
- value: node.binding.value,
1594
- source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
1595
- };
1596
- }
1597
- return {
1598
- type: "binding:keyOf",
1599
- key: node.binding.key,
1600
- source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
1601
- };
1602
- })();
1702
+ const binding = optimizeBinding(node.binding, sourceEnv, currentDepth);
1603
1703
  const bodyEnv = cloneOptimizeEnv(env);
1604
1704
  dropBindingNames(bodyEnv, binding);
1605
1705
  return {
@@ -1610,20 +1710,7 @@ function optimizeNode(node, env, currentDepth, asPlace = false) {
1610
1710
  }
1611
1711
  case "arrayComprehension": {
1612
1712
  const sourceEnv = cloneOptimizeEnv(env);
1613
- const binding = node.binding.type === "binding:expr" ? { type: "binding:expr", source: optimizeNode(node.binding.source, sourceEnv, currentDepth) } : node.binding.type === "binding:valueIn" ? {
1614
- type: "binding:valueIn",
1615
- value: node.binding.value,
1616
- source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
1617
- } : node.binding.type === "binding:keyValueIn" ? {
1618
- type: "binding:keyValueIn",
1619
- key: node.binding.key,
1620
- value: node.binding.value,
1621
- source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
1622
- } : {
1623
- type: "binding:keyOf",
1624
- key: node.binding.key,
1625
- source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
1626
- };
1713
+ const binding = optimizeBinding(node.binding, sourceEnv, currentDepth);
1627
1714
  const bodyEnv = cloneOptimizeEnv(env);
1628
1715
  dropBindingNames(bodyEnv, binding);
1629
1716
  return {
@@ -1632,22 +1719,15 @@ function optimizeNode(node, env, currentDepth, asPlace = false) {
1632
1719
  body: optimizeNode(node.body, bodyEnv, currentDepth + 1)
1633
1720
  };
1634
1721
  }
1722
+ case "whileArrayComprehension":
1723
+ return {
1724
+ type: "whileArrayComprehension",
1725
+ condition: optimizeNode(node.condition, env, currentDepth),
1726
+ body: optimizeNode(node.body, env, currentDepth + 1)
1727
+ };
1635
1728
  case "objectComprehension": {
1636
1729
  const sourceEnv = cloneOptimizeEnv(env);
1637
- const binding = node.binding.type === "binding:expr" ? { type: "binding:expr", source: optimizeNode(node.binding.source, sourceEnv, currentDepth) } : node.binding.type === "binding:valueIn" ? {
1638
- type: "binding:valueIn",
1639
- value: node.binding.value,
1640
- source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
1641
- } : node.binding.type === "binding:keyValueIn" ? {
1642
- type: "binding:keyValueIn",
1643
- key: node.binding.key,
1644
- value: node.binding.value,
1645
- source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
1646
- } : {
1647
- type: "binding:keyOf",
1648
- key: node.binding.key,
1649
- source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
1650
- };
1730
+ const binding = optimizeBinding(node.binding, sourceEnv, currentDepth);
1651
1731
  const bodyEnv = cloneOptimizeEnv(env);
1652
1732
  dropBindingNames(bodyEnv, binding);
1653
1733
  return {
@@ -1657,6 +1737,13 @@ function optimizeNode(node, env, currentDepth, asPlace = false) {
1657
1737
  value: optimizeNode(node.value, bodyEnv, currentDepth + 1)
1658
1738
  };
1659
1739
  }
1740
+ case "whileObjectComprehension":
1741
+ return {
1742
+ type: "whileObjectComprehension",
1743
+ condition: optimizeNode(node.condition, env, currentDepth),
1744
+ key: optimizeNode(node.key, env, currentDepth + 1),
1745
+ value: optimizeNode(node.value, env, currentDepth + 1)
1746
+ };
1660
1747
  default:
1661
1748
  return node;
1662
1749
  }
@@ -1708,6 +1795,10 @@ function collectLocalBindings(node, locals) {
1708
1795
  collectLocalBindings(node.left, locals);
1709
1796
  collectLocalBindings(node.right, locals);
1710
1797
  return;
1798
+ case "range":
1799
+ collectLocalBindings(node.from, locals);
1800
+ collectLocalBindings(node.to, locals);
1801
+ return;
1711
1802
  case "conditional":
1712
1803
  collectLocalBindings(node.condition, locals);
1713
1804
  for (const part of node.thenBlock)
@@ -1724,11 +1815,20 @@ function collectLocalBindings(node, locals) {
1724
1815
  collectLocalBindingFromBinding(node.binding, locals);
1725
1816
  collectLocalBindings(node.body, locals);
1726
1817
  return;
1818
+ case "whileArrayComprehension":
1819
+ collectLocalBindings(node.condition, locals);
1820
+ collectLocalBindings(node.body, locals);
1821
+ return;
1727
1822
  case "objectComprehension":
1728
1823
  collectLocalBindingFromBinding(node.binding, locals);
1729
1824
  collectLocalBindings(node.key, locals);
1730
1825
  collectLocalBindings(node.value, locals);
1731
1826
  return;
1827
+ case "whileObjectComprehension":
1828
+ collectLocalBindings(node.condition, locals);
1829
+ collectLocalBindings(node.key, locals);
1830
+ collectLocalBindings(node.value, locals);
1831
+ return;
1732
1832
  default:
1733
1833
  return;
1734
1834
  }
@@ -1820,6 +1920,10 @@ function collectNameFrequencies(node, locals, frequencies, order, nextOrder) {
1820
1920
  collectNameFrequencies(node.left, locals, frequencies, order, nextOrder);
1821
1921
  collectNameFrequencies(node.right, locals, frequencies, order, nextOrder);
1822
1922
  return;
1923
+ case "range":
1924
+ collectNameFrequencies(node.from, locals, frequencies, order, nextOrder);
1925
+ collectNameFrequencies(node.to, locals, frequencies, order, nextOrder);
1926
+ return;
1823
1927
  case "conditional":
1824
1928
  collectNameFrequencies(node.condition, locals, frequencies, order, nextOrder);
1825
1929
  for (const part of node.thenBlock)
@@ -1836,11 +1940,20 @@ function collectNameFrequencies(node, locals, frequencies, order, nextOrder) {
1836
1940
  collectNameFrequenciesBinding(node.binding, locals, frequencies, order, nextOrder);
1837
1941
  collectNameFrequencies(node.body, locals, frequencies, order, nextOrder);
1838
1942
  return;
1943
+ case "whileArrayComprehension":
1944
+ collectNameFrequencies(node.condition, locals, frequencies, order, nextOrder);
1945
+ collectNameFrequencies(node.body, locals, frequencies, order, nextOrder);
1946
+ return;
1839
1947
  case "objectComprehension":
1840
1948
  collectNameFrequenciesBinding(node.binding, locals, frequencies, order, nextOrder);
1841
1949
  collectNameFrequencies(node.key, locals, frequencies, order, nextOrder);
1842
1950
  collectNameFrequencies(node.value, locals, frequencies, order, nextOrder);
1843
1951
  return;
1952
+ case "whileObjectComprehension":
1953
+ collectNameFrequencies(node.condition, locals, frequencies, order, nextOrder);
1954
+ collectNameFrequencies(node.key, locals, frequencies, order, nextOrder);
1955
+ collectNameFrequencies(node.value, locals, frequencies, order, nextOrder);
1956
+ return;
1844
1957
  default:
1845
1958
  return;
1846
1959
  }
@@ -1915,6 +2028,12 @@ function renameLocalNames(node, map) {
1915
2028
  left: renameLocalNames(node.left, map),
1916
2029
  right: renameLocalNames(node.right, map)
1917
2030
  };
2031
+ case "range":
2032
+ return {
2033
+ type: "range",
2034
+ from: renameLocalNames(node.from, map),
2035
+ to: renameLocalNames(node.to, map)
2036
+ };
1918
2037
  case "assign": {
1919
2038
  const place = node.place.type === "identifier" && map.has(node.place.name) ? { type: "identifier", name: map.get(node.place.name) } : renameLocalNames(node.place, map);
1920
2039
  return {
@@ -1944,6 +2063,12 @@ function renameLocalNames(node, map) {
1944
2063
  binding: renameLocalNamesBinding(node.binding, map),
1945
2064
  body: renameLocalNames(node.body, map)
1946
2065
  };
2066
+ case "whileArrayComprehension":
2067
+ return {
2068
+ type: "whileArrayComprehension",
2069
+ condition: renameLocalNames(node.condition, map),
2070
+ body: renameLocalNames(node.body, map)
2071
+ };
1947
2072
  case "objectComprehension":
1948
2073
  return {
1949
2074
  type: "objectComprehension",
@@ -1951,34 +2076,31 @@ function renameLocalNames(node, map) {
1951
2076
  key: renameLocalNames(node.key, map),
1952
2077
  value: renameLocalNames(node.value, map)
1953
2078
  };
2079
+ case "whileObjectComprehension":
2080
+ return {
2081
+ type: "whileObjectComprehension",
2082
+ condition: renameLocalNames(node.condition, map),
2083
+ key: renameLocalNames(node.key, map),
2084
+ value: renameLocalNames(node.value, map)
2085
+ };
1954
2086
  default:
1955
2087
  return node;
1956
2088
  }
1957
2089
  }
1958
2090
  function renameLocalNamesBinding(binding, map) {
1959
- if (binding.type === "binding:expr") {
1960
- return { type: "binding:expr", source: renameLocalNames(binding.source, map) };
1961
- }
1962
- if (binding.type === "binding:valueIn") {
1963
- return {
1964
- type: "binding:valueIn",
1965
- value: map.get(binding.value) ?? binding.value,
1966
- source: renameLocalNames(binding.source, map)
1967
- };
2091
+ const source = renameLocalNames(binding.source, map);
2092
+ switch (binding.type) {
2093
+ case "binding:bareIn":
2094
+ return { type: "binding:bareIn", source };
2095
+ case "binding:bareOf":
2096
+ return { type: "binding:bareOf", source };
2097
+ case "binding:valueIn":
2098
+ return { type: "binding:valueIn", value: map.get(binding.value) ?? binding.value, source };
2099
+ case "binding:keyValueIn":
2100
+ return { type: "binding:keyValueIn", key: map.get(binding.key) ?? binding.key, value: map.get(binding.value) ?? binding.value, source };
2101
+ case "binding:keyOf":
2102
+ return { type: "binding:keyOf", key: map.get(binding.key) ?? binding.key, source };
1968
2103
  }
1969
- if (binding.type === "binding:keyValueIn") {
1970
- return {
1971
- type: "binding:keyValueIn",
1972
- key: map.get(binding.key) ?? binding.key,
1973
- value: map.get(binding.value) ?? binding.value,
1974
- source: renameLocalNames(binding.source, map)
1975
- };
1976
- }
1977
- return {
1978
- type: "binding:keyOf",
1979
- key: map.get(binding.key) ?? binding.key,
1980
- source: renameLocalNames(binding.source, map)
1981
- };
1982
2104
  }
1983
2105
  function renameLocalNamesElse(elseBranch, map) {
1984
2106
  if (elseBranch.type === "else") {
@@ -2025,14 +2147,20 @@ function compile(source, options) {
2025
2147
  let lowered = options?.optimize ? optimizeIR(ir) : ir;
2026
2148
  if (options?.minifyNames)
2027
2149
  lowered = minifyLocalNamesIR(lowered);
2028
- const domainRefs = options?.domainConfig ? domainRefsFromConfig(options.domainConfig) : undefined;
2150
+ const domainMaps = options?.domainConfig ? domainRefsFromConfig(options.domainConfig) : undefined;
2029
2151
  return encodeIR(lowered, {
2030
- domainRefs,
2152
+ ...domainMaps,
2031
2153
  dedupeValues: options?.dedupeValues,
2032
2154
  dedupeMinBytes: options?.dedupeMinBytes
2033
2155
  });
2034
2156
  }
2035
2157
  function parseNumber(raw) {
2158
+ if (raw === "nan")
2159
+ return NaN;
2160
+ if (raw === "inf")
2161
+ return Infinity;
2162
+ if (raw === "-inf")
2163
+ return -Infinity;
2036
2164
  if (/^-?0x/i.test(raw))
2037
2165
  return parseInt(raw, 16);
2038
2166
  if (/^-?0b/i.test(raw)) {
@@ -2147,6 +2275,9 @@ semantics.addOperation("toIR", {
2147
2275
  ExistenceExpr_or(left, _or, right) {
2148
2276
  return { type: "binary", op: "or", left: left.toIR(), right: right.toIR() };
2149
2277
  },
2278
+ ExistenceExpr_nor(left, _nor, right) {
2279
+ return { type: "binary", op: "nor", left: left.toIR(), right: right.toIR() };
2280
+ },
2150
2281
  BitExpr_and(left, _op, right) {
2151
2282
  return { type: "binary", op: "bitAnd", left: left.toIR(), right: right.toIR() };
2152
2283
  },
@@ -2156,6 +2287,9 @@ semantics.addOperation("toIR", {
2156
2287
  BitExpr_or(left, _op, right) {
2157
2288
  return { type: "binary", op: "bitOr", left: left.toIR(), right: right.toIR() };
2158
2289
  },
2290
+ RangeExpr_range(left, _op, right) {
2291
+ return { type: "range", from: left.toIR(), to: right.toIR() };
2292
+ },
2159
2293
  CompareExpr_binary(left, op, right) {
2160
2294
  const map = {
2161
2295
  "==": "eq",
@@ -2196,6 +2330,9 @@ semantics.addOperation("toIR", {
2196
2330
  UnaryExpr_not(_op, value) {
2197
2331
  return { type: "unary", op: "not", value: value.toIR() };
2198
2332
  },
2333
+ UnaryExpr_logicalNot(_not, value) {
2334
+ return { type: "unary", op: "logicalNot", value: value.toIR() };
2335
+ },
2199
2336
  UnaryExpr_delete(_del, place) {
2200
2337
  return { type: "unary", op: "delete", value: place.toIR() };
2201
2338
  },
@@ -2249,14 +2386,6 @@ semantics.addOperation("toIR", {
2249
2386
  ConditionalElse_else(_else, block) {
2250
2387
  return { type: "else", block: block.toIR() };
2251
2388
  },
2252
- DoExpr(_do, block, _end) {
2253
- const body = block.toIR();
2254
- if (body.length === 0)
2255
- return { type: "undefined" };
2256
- if (body.length === 1)
2257
- return body[0];
2258
- return { type: "program", body };
2259
- },
2260
2389
  WhileExpr(_while, condition, _do, block, _end) {
2261
2390
  return {
2262
2391
  type: "while",
@@ -2271,30 +2400,44 @@ semantics.addOperation("toIR", {
2271
2400
  body: block.toIR()
2272
2401
  };
2273
2402
  },
2274
- BindingExpr(iterOrExpr) {
2275
- const node = iterOrExpr.toIR();
2276
- if (typeof node === "object" && node && "type" in node && String(node.type).startsWith("binding:")) {
2277
- return node;
2278
- }
2279
- return { type: "binding:expr", source: node };
2280
- },
2281
2403
  Array_empty(_open, _close) {
2282
2404
  return { type: "array", items: [] };
2283
2405
  },
2284
- Array_comprehension(_open, binding, _semi, body, _close) {
2406
+ Array_forComprehension(_open, body, _for, binding, _close) {
2285
2407
  return {
2286
2408
  type: "arrayComprehension",
2287
2409
  binding: binding.toIR(),
2288
2410
  body: body.toIR()
2289
2411
  };
2290
2412
  },
2413
+ Array_whileComprehension(_open, body, _while, condition, _close) {
2414
+ return {
2415
+ type: "whileArrayComprehension",
2416
+ condition: condition.toIR(),
2417
+ body: body.toIR()
2418
+ };
2419
+ },
2420
+ Array_inComprehension(_open, body, _in, source, _close) {
2421
+ return {
2422
+ type: "arrayComprehension",
2423
+ binding: { type: "binding:bareIn", source: source.toIR() },
2424
+ body: body.toIR()
2425
+ };
2426
+ },
2427
+ Array_ofComprehension(_open, body, _of, source, _close) {
2428
+ return {
2429
+ type: "arrayComprehension",
2430
+ binding: { type: "binding:bareOf", source: source.toIR() },
2431
+ body: body.toIR()
2432
+ };
2433
+ },
2291
2434
  Array_values(_open, items, _close) {
2292
2435
  return { type: "array", items: normalizeList(items.toIR()) };
2293
2436
  },
2294
2437
  Object_empty(_open, _close) {
2295
2438
  return { type: "object", entries: [] };
2296
2439
  },
2297
- Object_comprehension(_open, binding, _semi, key, _colon, value, _close) {
2440
+ Object_forComprehension(_open, key, _colon, value, _for, binding, _close) {
2298
2441
  return {
2299
2442
  type: "objectComprehension",
2300
2443
  binding: binding.toIR(),
@@ -2302,6 +2445,30 @@ semantics.addOperation("toIR", {
2302
2445
  value: value.toIR()
2303
2446
  };
2304
2447
  },
2448
+ Object_whileComprehension(_open, key, _colon, value, _while, condition, _close) {
2449
+ return {
2450
+ type: "whileObjectComprehension",
2451
+ condition: condition.toIR(),
2452
+ key: key.toIR(),
2453
+ value: value.toIR()
2454
+ };
2455
+ },
2456
+ Object_inComprehension(_open, key, _colon, value, _in, source, _close) {
2457
+ return {
2458
+ type: "objectComprehension",
2459
+ binding: { type: "binding:bareIn", source: source.toIR() },
2460
+ key: key.toIR(),
2461
+ value: value.toIR()
2462
+ };
2463
+ },
2464
+ Object_ofComprehension(_open, key, _colon, value, _of, source, _close) {
2465
+ return {
2466
+ type: "objectComprehension",
2467
+ binding: { type: "binding:bareOf", source: source.toIR() },
2468
+ key: key.toIR(),
2469
+ value: value.toIR()
2470
+ };
2471
+ },
2305
2472
  Object_pairs(_open, pairs, _close) {
2306
2473
  return {
2307
2474
  type: "object",
@@ -2330,6 +2497,18 @@ semantics.addOperation("toIR", {
2330
2497
  source: source.toIR()
2331
2498
  };
2332
2499
  },
2500
+ IterBinding_bareIn(_in, source) {
2501
+ return {
2502
+ type: "binding:bareIn",
2503
+ source: source.toIR()
2504
+ };
2505
+ },
2506
+ IterBinding_bareOf(_of, source) {
2507
+ return {
2508
+ type: "binding:bareOf",
2509
+ source: source.toIR()
2510
+ };
2511
+ },
2333
2512
  Pair(key, _colon, value) {
2334
2513
  return { key: key.toIR(), value: value.toIR() };
2335
2514
  },
@@ -2393,6 +2572,9 @@ semantics.addOperation("toIR", {
2393
2572
  BooleanKw(_kw) {
2394
2573
  return { type: "identifier", name: "boolean" };
2395
2574
  },
2575
+ SizeKw(_kw) {
2576
+ return { type: "identifier", name: "size" };
2577
+ },
2396
2578
  identifier(_a, _b) {
2397
2579
  return { type: "identifier", name: this.sourceString };
2398
2580
  },