littlewing 2.2.0 → 2.3.2

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/index.js CHANGED
@@ -16,6 +16,7 @@ var __export = (target, all) => {
16
16
  // src/ast.ts
17
17
  var exports_ast = {};
18
18
  __export(exports_ast, {
19
+ visit: () => visit,
19
20
  unaryOp: () => unaryOp,
20
21
  subtract: () => subtract,
21
22
  string: () => string,
@@ -86,6 +87,43 @@ var NodeKind;
86
87
  NodeKind2[NodeKind2["PipeExpression"] = 14] = "PipeExpression";
87
88
  NodeKind2[NodeKind2["Placeholder"] = 15] = "Placeholder";
88
89
  })(NodeKind ||= {});
90
+ function visit(node, visitor) {
91
+ const recurse = (child) => visit(child, visitor);
92
+ switch (node.kind) {
93
+ case 0 /* Program */:
94
+ return visitor.Program(node, recurse);
95
+ case 1 /* NumberLiteral */:
96
+ return visitor.NumberLiteral(node, recurse);
97
+ case 8 /* StringLiteral */:
98
+ return visitor.StringLiteral(node, recurse);
99
+ case 9 /* BooleanLiteral */:
100
+ return visitor.BooleanLiteral(node, recurse);
101
+ case 10 /* ArrayLiteral */:
102
+ return visitor.ArrayLiteral(node, recurse);
103
+ case 2 /* Identifier */:
104
+ return visitor.Identifier(node, recurse);
105
+ case 3 /* BinaryOp */:
106
+ return visitor.BinaryOp(node, recurse);
107
+ case 4 /* UnaryOp */:
108
+ return visitor.UnaryOp(node, recurse);
109
+ case 5 /* FunctionCall */:
110
+ return visitor.FunctionCall(node, recurse);
111
+ case 6 /* Assignment */:
112
+ return visitor.Assignment(node, recurse);
113
+ case 7 /* IfExpression */:
114
+ return visitor.IfExpression(node, recurse);
115
+ case 11 /* ForExpression */:
116
+ return visitor.ForExpression(node, recurse);
117
+ case 12 /* IndexAccess */:
118
+ return visitor.IndexAccess(node, recurse);
119
+ case 13 /* RangeExpression */:
120
+ return visitor.RangeExpression(node, recurse);
121
+ case 14 /* PipeExpression */:
122
+ return visitor.PipeExpression(node, recurse);
123
+ case 15 /* Placeholder */:
124
+ return visitor.Placeholder(node, recurse);
125
+ }
126
+ }
89
127
  function isProgram(node) {
90
128
  return node.kind === 0 /* Program */;
91
129
  }
@@ -143,8 +181,10 @@ function number(value) {
143
181
  function string(value) {
144
182
  return { kind: 8 /* StringLiteral */, value };
145
183
  }
184
+ var TRUE_LITERAL = { kind: 9 /* BooleanLiteral */, value: true };
185
+ var FALSE_LITERAL = { kind: 9 /* BooleanLiteral */, value: false };
146
186
  function boolean(value) {
147
- return { kind: 9 /* BooleanLiteral */, value };
187
+ return value ? TRUE_LITERAL : FALSE_LITERAL;
148
188
  }
149
189
  function array(elements) {
150
190
  return { kind: 10 /* ArrayLiteral */, elements };
@@ -191,8 +231,9 @@ function rangeExpr(start, end, inclusive) {
191
231
  function pipeExpr(value, name, args) {
192
232
  return { kind: 14 /* PipeExpression */, value, name, args };
193
233
  }
234
+ var PLACEHOLDER_SINGLETON = { kind: 15 /* Placeholder */ };
194
235
  function placeholder() {
195
- return { kind: 15 /* Placeholder */ };
236
+ return PLACEHOLDER_SINGLETON;
196
237
  }
197
238
  function add(left, right) {
198
239
  return binaryOp(left, "+", right);
@@ -281,50 +322,6 @@ function getNodeName(node) {
281
322
  }
282
323
  }
283
324
 
284
- // src/visitor.ts
285
- function visit(node, visitor) {
286
- return visitPartial(node, visitor, (node2) => {
287
- throw new Error(`No handler for node type: ${getNodeName(node2)}`);
288
- });
289
- }
290
- function visitPartial(node, visitor, defaultHandler) {
291
- const recurse = (n) => visitPartial(n, visitor, defaultHandler);
292
- switch (node.kind) {
293
- case 0 /* Program */:
294
- return visitor.Program ? visitor.Program(node, recurse) : defaultHandler(node, recurse);
295
- case 1 /* NumberLiteral */:
296
- return visitor.NumberLiteral ? visitor.NumberLiteral(node, recurse) : defaultHandler(node, recurse);
297
- case 8 /* StringLiteral */:
298
- return visitor.StringLiteral ? visitor.StringLiteral(node, recurse) : defaultHandler(node, recurse);
299
- case 9 /* BooleanLiteral */:
300
- return visitor.BooleanLiteral ? visitor.BooleanLiteral(node, recurse) : defaultHandler(node, recurse);
301
- case 10 /* ArrayLiteral */:
302
- return visitor.ArrayLiteral ? visitor.ArrayLiteral(node, recurse) : defaultHandler(node, recurse);
303
- case 2 /* Identifier */:
304
- return visitor.Identifier ? visitor.Identifier(node, recurse) : defaultHandler(node, recurse);
305
- case 3 /* BinaryOp */:
306
- return visitor.BinaryOp ? visitor.BinaryOp(node, recurse) : defaultHandler(node, recurse);
307
- case 4 /* UnaryOp */:
308
- return visitor.UnaryOp ? visitor.UnaryOp(node, recurse) : defaultHandler(node, recurse);
309
- case 5 /* FunctionCall */:
310
- return visitor.FunctionCall ? visitor.FunctionCall(node, recurse) : defaultHandler(node, recurse);
311
- case 6 /* Assignment */:
312
- return visitor.Assignment ? visitor.Assignment(node, recurse) : defaultHandler(node, recurse);
313
- case 7 /* IfExpression */:
314
- return visitor.IfExpression ? visitor.IfExpression(node, recurse) : defaultHandler(node, recurse);
315
- case 11 /* ForExpression */:
316
- return visitor.ForExpression ? visitor.ForExpression(node, recurse) : defaultHandler(node, recurse);
317
- case 12 /* IndexAccess */:
318
- return visitor.IndexAccess ? visitor.IndexAccess(node, recurse) : defaultHandler(node, recurse);
319
- case 13 /* RangeExpression */:
320
- return visitor.RangeExpression ? visitor.RangeExpression(node, recurse) : defaultHandler(node, recurse);
321
- case 14 /* PipeExpression */:
322
- return visitor.PipeExpression ? visitor.PipeExpression(node, recurse) : defaultHandler(node, recurse);
323
- case 15 /* Placeholder */:
324
- return visitor.Placeholder ? visitor.Placeholder(node, recurse) : defaultHandler(node, recurse);
325
- }
326
- }
327
-
328
325
  // src/analyzer.ts
329
326
  function extractInputVariables(ast) {
330
327
  const inputVars = new Set;
@@ -341,74 +338,110 @@ function extractInputVariables(ast) {
341
338
  function extractAssignedVariables(ast) {
342
339
  const seen = new Set;
343
340
  const names = [];
344
- visitPartial(ast, {
345
- Program: (n, recurse) => {
346
- for (const statement of n.statements) {
347
- recurse(statement);
348
- }
349
- },
350
- Assignment: (n, recurse) => {
351
- if (!seen.has(n.name)) {
352
- seen.add(n.name);
353
- names.push(n.name);
341
+ collectAssignedVariables(ast, seen, names);
342
+ return names;
343
+ }
344
+ function collectAssignedVariables(node, seen, names) {
345
+ switch (node.kind) {
346
+ case 0 /* Program */:
347
+ for (const statement of node.statements) {
348
+ collectAssignedVariables(statement, seen, names);
354
349
  }
355
- recurse(n.value);
356
- },
357
- IfExpression: (n, recurse) => {
358
- recurse(n.condition);
359
- recurse(n.consequent);
360
- recurse(n.alternate);
361
- },
362
- ForExpression: (n, recurse) => {
363
- recurse(n.iterable);
364
- if (n.guard)
365
- recurse(n.guard);
366
- if (n.accumulator)
367
- recurse(n.accumulator.initial);
368
- recurse(n.body);
369
- },
370
- IndexAccess: (n, recurse) => {
371
- recurse(n.object);
372
- recurse(n.index);
373
- },
374
- RangeExpression: (n, recurse) => {
375
- recurse(n.start);
376
- recurse(n.end);
377
- },
378
- PipeExpression: (n, recurse) => {
379
- recurse(n.value);
380
- for (const arg of n.args) {
381
- recurse(arg);
350
+ break;
351
+ case 6 /* Assignment */:
352
+ if (!seen.has(node.name)) {
353
+ seen.add(node.name);
354
+ names.push(node.name);
382
355
  }
383
- }
384
- }, () => {});
385
- return names;
356
+ collectAssignedVariables(node.value, seen, names);
357
+ break;
358
+ case 3 /* BinaryOp */:
359
+ collectAssignedVariables(node.left, seen, names);
360
+ collectAssignedVariables(node.right, seen, names);
361
+ break;
362
+ case 4 /* UnaryOp */:
363
+ collectAssignedVariables(node.argument, seen, names);
364
+ break;
365
+ case 10 /* ArrayLiteral */:
366
+ for (const e of node.elements)
367
+ collectAssignedVariables(e, seen, names);
368
+ break;
369
+ case 5 /* FunctionCall */:
370
+ for (const a of node.args)
371
+ collectAssignedVariables(a, seen, names);
372
+ break;
373
+ case 7 /* IfExpression */:
374
+ collectAssignedVariables(node.condition, seen, names);
375
+ collectAssignedVariables(node.consequent, seen, names);
376
+ collectAssignedVariables(node.alternate, seen, names);
377
+ break;
378
+ case 11 /* ForExpression */:
379
+ collectAssignedVariables(node.iterable, seen, names);
380
+ if (node.guard)
381
+ collectAssignedVariables(node.guard, seen, names);
382
+ if (node.accumulator)
383
+ collectAssignedVariables(node.accumulator.initial, seen, names);
384
+ collectAssignedVariables(node.body, seen, names);
385
+ break;
386
+ case 12 /* IndexAccess */:
387
+ collectAssignedVariables(node.object, seen, names);
388
+ collectAssignedVariables(node.index, seen, names);
389
+ break;
390
+ case 13 /* RangeExpression */:
391
+ collectAssignedVariables(node.start, seen, names);
392
+ collectAssignedVariables(node.end, seen, names);
393
+ break;
394
+ case 14 /* PipeExpression */:
395
+ collectAssignedVariables(node.value, seen, names);
396
+ for (const arg of node.args)
397
+ collectAssignedVariables(arg, seen, names);
398
+ break;
399
+ case 1 /* NumberLiteral */:
400
+ case 8 /* StringLiteral */:
401
+ case 9 /* BooleanLiteral */:
402
+ case 2 /* Identifier */:
403
+ case 15 /* Placeholder */:
404
+ break;
405
+ }
386
406
  }
387
407
  function containsExternalReference(node, boundVars) {
388
- return visit(node, {
389
- Program: (n, recurse) => n.statements.some(recurse),
390
- NumberLiteral: () => false,
391
- StringLiteral: () => false,
392
- BooleanLiteral: () => false,
393
- Identifier: (n) => !boundVars.has(n.name),
394
- ArrayLiteral: (n, recurse) => n.elements.some(recurse),
395
- BinaryOp: (n, recurse) => recurse(n.left) || recurse(n.right),
396
- UnaryOp: (n, recurse) => recurse(n.argument),
397
- FunctionCall: (n, recurse) => n.args.some(recurse),
398
- Assignment: (n, recurse) => recurse(n.value),
399
- IfExpression: (n, recurse) => recurse(n.condition) || recurse(n.consequent) || recurse(n.alternate),
400
- ForExpression: (n, recurse) => {
408
+ const recurse = (n) => containsExternalReference(n, boundVars);
409
+ switch (node.kind) {
410
+ case 0 /* Program */:
411
+ return node.statements.some(recurse);
412
+ case 2 /* Identifier */:
413
+ return !boundVars.has(node.name);
414
+ case 10 /* ArrayLiteral */:
415
+ return node.elements.some(recurse);
416
+ case 3 /* BinaryOp */:
417
+ return recurse(node.left) || recurse(node.right);
418
+ case 4 /* UnaryOp */:
419
+ return recurse(node.argument);
420
+ case 5 /* FunctionCall */:
421
+ return node.args.some(recurse);
422
+ case 6 /* Assignment */:
423
+ return recurse(node.value);
424
+ case 7 /* IfExpression */:
425
+ return recurse(node.condition) || recurse(node.consequent) || recurse(node.alternate);
426
+ case 11 /* ForExpression */: {
401
427
  const innerBound = new Set(boundVars);
402
- innerBound.add(n.variable);
403
- if (n.accumulator)
404
- innerBound.add(n.accumulator.name);
405
- return recurse(n.iterable) || (n.guard ? containsExternalReference(n.guard, innerBound) : false) || (n.accumulator ? recurse(n.accumulator.initial) : false) || containsExternalReference(n.body, innerBound);
406
- },
407
- IndexAccess: (n, recurse) => recurse(n.object) || recurse(n.index),
408
- RangeExpression: (n, recurse) => recurse(n.start) || recurse(n.end),
409
- PipeExpression: (n, recurse) => recurse(n.value) || n.args.some(recurse),
410
- Placeholder: () => false
411
- });
428
+ innerBound.add(node.variable);
429
+ if (node.accumulator)
430
+ innerBound.add(node.accumulator.name);
431
+ return recurse(node.iterable) || (node.guard ? containsExternalReference(node.guard, innerBound) : false) || (node.accumulator ? recurse(node.accumulator.initial) : false) || containsExternalReference(node.body, innerBound);
432
+ }
433
+ case 12 /* IndexAccess */:
434
+ return recurse(node.object) || recurse(node.index);
435
+ case 13 /* RangeExpression */:
436
+ return recurse(node.start) || recurse(node.end);
437
+ case 14 /* PipeExpression */:
438
+ return recurse(node.value) || node.args.some(recurse);
439
+ case 1 /* NumberLiteral */:
440
+ case 8 /* StringLiteral */:
441
+ case 9 /* BooleanLiteral */:
442
+ case 15 /* Placeholder */:
443
+ return false;
444
+ }
412
445
  }
413
446
  function containsVariableReference(node) {
414
447
  return containsExternalReference(node, new Set);
@@ -707,21 +740,25 @@ function lexIdentifier(cursor) {
707
740
 
708
741
  // src/utils.ts
709
742
  function typeOf(value) {
743
+ if (value === undefined)
744
+ return "undefined";
745
+ if (value === null)
746
+ return "null";
710
747
  if (typeof value === "number")
711
748
  return "number";
712
749
  if (typeof value === "string")
713
750
  return "string";
714
751
  if (typeof value === "boolean")
715
752
  return "boolean";
753
+ if (Array.isArray(value))
754
+ return "array";
716
755
  if (value instanceof Temporal.PlainDateTime)
717
756
  return "datetime";
718
757
  if (value instanceof Temporal.PlainDate)
719
758
  return "date";
720
759
  if (value instanceof Temporal.PlainTime)
721
760
  return "time";
722
- if (Array.isArray(value))
723
- return "array";
724
- throw new Error(`Unknown runtime value type`);
761
+ return typeof value;
725
762
  }
726
763
  function deepEquals(a, b) {
727
764
  if (typeof a === "number" && typeof b === "number")
@@ -758,6 +795,13 @@ function assertNumber(v, context, side) {
758
795
  throw new TypeError(`${context}${where} expected number, got ${typeOf(v)}`);
759
796
  }
760
797
  }
798
+ function assertInteger(v, context, side) {
799
+ assertNumber(v, context, side);
800
+ if (!Number.isInteger(v)) {
801
+ const where = side ? ` (${side})` : "";
802
+ throw new TypeError(`${context}${where} expected integer, got ${v}`);
803
+ }
804
+ }
761
805
  function assertBoolean(v, context, side) {
762
806
  if (typeof v !== "boolean") {
763
807
  const where = side ? ` (${side})` : "";
@@ -815,7 +859,17 @@ function concatenateArrays(a, b) {
815
859
  function validateHomogeneousArray(elements) {
816
860
  if (elements.length <= 1)
817
861
  return;
818
- const firstType = typeOf(elements[0]);
862
+ const first = elements[0];
863
+ const firstPrimitive = typeof first;
864
+ if (firstPrimitive === "number" || firstPrimitive === "string" || firstPrimitive === "boolean") {
865
+ for (let i = 1;i < elements.length; i++) {
866
+ if (typeof elements[i] !== firstPrimitive) {
867
+ throw new TypeError(`Heterogeneous array: expected ${firstPrimitive}, got ${typeOf(elements[i])} at index ${i}`);
868
+ }
869
+ }
870
+ return;
871
+ }
872
+ const firstType = typeOf(first);
819
873
  for (let i = 1;i < elements.length; i++) {
820
874
  const elemType = typeOf(elements[i]);
821
875
  if (elemType !== firstType) {
@@ -919,13 +973,29 @@ function resolveIndex(target, index) {
919
973
  throw new TypeError(`Index must be an integer, got ${index}`);
920
974
  }
921
975
  if (typeof target === "string") {
922
- const codePoints = Array.from(target);
923
- const len2 = codePoints.length;
924
- const resolved2 = index < 0 ? len2 + index : index;
925
- if (resolved2 < 0 || resolved2 >= len2) {
976
+ if (index >= 0) {
977
+ let i2 = 0;
978
+ for (const cp of target) {
979
+ if (i2 === index)
980
+ return cp;
981
+ i2++;
982
+ }
983
+ throw new RangeError(`Index ${index} out of bounds for length ${i2}`);
984
+ }
985
+ let len2 = 0;
986
+ for (const _ of target)
987
+ len2++;
988
+ const resolved2 = len2 + index;
989
+ if (resolved2 < 0) {
926
990
  throw new RangeError(`Index ${index} out of bounds for length ${len2}`);
927
991
  }
928
- return codePoints[resolved2];
992
+ let i = 0;
993
+ for (const cp of target) {
994
+ if (i === resolved2)
995
+ return cp;
996
+ i++;
997
+ }
998
+ throw new RangeError(`Index ${index} out of bounds for length ${len2}`);
929
999
  }
930
1000
  const len = target.length;
931
1001
  const resolved = index < 0 ? len + index : index;
@@ -945,11 +1015,7 @@ function buildRange(start, end, inclusive) {
945
1015
  throw new RangeError(`Range start (${start}) must not exceed end (${end})`);
946
1016
  }
947
1017
  const limit = inclusive ? end + 1 : end;
948
- const result = [];
949
- for (let i = start;i < limit; i++) {
950
- result.push(i);
951
- }
952
- return result;
1018
+ return Array.from({ length: limit - start }, (_, i) => start + i);
953
1019
  }
954
1020
  function getOperatorPrecedence(operator) {
955
1021
  switch (operator) {
@@ -979,69 +1045,75 @@ function getOperatorPrecedence(operator) {
979
1045
  }
980
1046
  function collectAllIdentifiers(node) {
981
1047
  const identifiers = new Set;
982
- visit(node, {
983
- Program: (n, recurse) => {
984
- for (const stmt of n.statements) {
985
- recurse(stmt);
986
- }
987
- },
988
- NumberLiteral: () => {},
989
- StringLiteral: () => {},
990
- BooleanLiteral: () => {},
991
- ArrayLiteral: (n, recurse) => {
992
- for (const elem of n.elements) {
993
- recurse(elem);
994
- }
995
- },
996
- Identifier: (n) => {
997
- identifiers.add(n.name);
998
- },
999
- BinaryOp: (n, recurse) => {
1000
- recurse(n.left);
1001
- recurse(n.right);
1002
- },
1003
- UnaryOp: (n, recurse) => {
1004
- recurse(n.argument);
1005
- },
1006
- FunctionCall: (n, recurse) => {
1007
- for (const arg of n.args) {
1008
- recurse(arg);
1009
- }
1010
- },
1011
- Assignment: (n, recurse) => {
1012
- recurse(n.value);
1013
- },
1014
- IfExpression: (n, recurse) => {
1015
- recurse(n.condition);
1016
- recurse(n.consequent);
1017
- recurse(n.alternate);
1018
- },
1019
- ForExpression: (n, recurse) => {
1020
- recurse(n.iterable);
1021
- if (n.guard)
1022
- recurse(n.guard);
1023
- if (n.accumulator)
1024
- recurse(n.accumulator.initial);
1025
- recurse(n.body);
1026
- },
1027
- IndexAccess: (n, recurse) => {
1028
- recurse(n.object);
1029
- recurse(n.index);
1030
- },
1031
- RangeExpression: (n, recurse) => {
1032
- recurse(n.start);
1033
- recurse(n.end);
1034
- },
1035
- PipeExpression: (n, recurse) => {
1036
- recurse(n.value);
1037
- for (const arg of n.args) {
1038
- recurse(arg);
1039
- }
1040
- },
1041
- Placeholder: () => {}
1042
- });
1048
+ collectIdentifiers(node, identifiers, new Set);
1043
1049
  return identifiers;
1044
1050
  }
1051
+ function collectIdentifiers(node, ids, boundVars) {
1052
+ switch (node.kind) {
1053
+ case 0 /* Program */:
1054
+ for (const s of node.statements)
1055
+ collectIdentifiers(s, ids, boundVars);
1056
+ break;
1057
+ case 2 /* Identifier */:
1058
+ if (!boundVars.has(node.name))
1059
+ ids.add(node.name);
1060
+ break;
1061
+ case 10 /* ArrayLiteral */:
1062
+ for (const e of node.elements)
1063
+ collectIdentifiers(e, ids, boundVars);
1064
+ break;
1065
+ case 3 /* BinaryOp */:
1066
+ collectIdentifiers(node.left, ids, boundVars);
1067
+ collectIdentifiers(node.right, ids, boundVars);
1068
+ break;
1069
+ case 4 /* UnaryOp */:
1070
+ collectIdentifiers(node.argument, ids, boundVars);
1071
+ break;
1072
+ case 5 /* FunctionCall */:
1073
+ for (const a of node.args)
1074
+ collectIdentifiers(a, ids, boundVars);
1075
+ break;
1076
+ case 6 /* Assignment */:
1077
+ collectIdentifiers(node.value, ids, boundVars);
1078
+ break;
1079
+ case 7 /* IfExpression */:
1080
+ collectIdentifiers(node.condition, ids, boundVars);
1081
+ collectIdentifiers(node.consequent, ids, boundVars);
1082
+ collectIdentifiers(node.alternate, ids, boundVars);
1083
+ break;
1084
+ case 11 /* ForExpression */: {
1085
+ collectIdentifiers(node.iterable, ids, boundVars);
1086
+ if (node.accumulator)
1087
+ collectIdentifiers(node.accumulator.initial, ids, boundVars);
1088
+ const innerBound = new Set(boundVars);
1089
+ innerBound.add(node.variable);
1090
+ if (node.accumulator)
1091
+ innerBound.add(node.accumulator.name);
1092
+ if (node.guard)
1093
+ collectIdentifiers(node.guard, ids, innerBound);
1094
+ collectIdentifiers(node.body, ids, innerBound);
1095
+ break;
1096
+ }
1097
+ case 12 /* IndexAccess */:
1098
+ collectIdentifiers(node.object, ids, boundVars);
1099
+ collectIdentifiers(node.index, ids, boundVars);
1100
+ break;
1101
+ case 13 /* RangeExpression */:
1102
+ collectIdentifiers(node.start, ids, boundVars);
1103
+ collectIdentifiers(node.end, ids, boundVars);
1104
+ break;
1105
+ case 14 /* PipeExpression */:
1106
+ collectIdentifiers(node.value, ids, boundVars);
1107
+ for (const a of node.args)
1108
+ collectIdentifiers(a, ids, boundVars);
1109
+ break;
1110
+ case 1 /* NumberLiteral */:
1111
+ case 8 /* StringLiteral */:
1112
+ case 9 /* BooleanLiteral */:
1113
+ case 15 /* Placeholder */:
1114
+ break;
1115
+ }
1116
+ }
1045
1117
  function getTokenPrecedence(kind) {
1046
1118
  switch (kind) {
1047
1119
  case 24 /* Eq */:
@@ -1139,90 +1211,88 @@ function generate(node) {
1139
1211
  return code;
1140
1212
  }
1141
1213
  function generateNode(node) {
1142
- return visit(node, {
1143
- Program: generateProgram,
1144
- NumberLiteral: (n) => {
1145
- return String(n.value);
1146
- },
1147
- StringLiteral: (n) => {
1148
- return `"${escapeString(n.value)}"`;
1149
- },
1150
- BooleanLiteral: (n) => {
1151
- return n.value ? "true" : "false";
1152
- },
1153
- ArrayLiteral: (n, recurse) => {
1154
- return `[${n.elements.map(recurse).join(", ")}]`;
1155
- },
1156
- Identifier: (n) => {
1157
- return n.name;
1158
- },
1159
- BinaryOp: (n, recurse) => {
1160
- const left = recurse(n.left);
1161
- const right = recurse(n.right);
1162
- const opPrec = getOperatorPrecedence(n.operator);
1163
- const leftNeedsParens = needsParens(n.left, n.operator, true) || n.operator === "^" && isUnaryOp(n.left) || isIfExpression(n.left) || isForExpression(n.left) || isAssignment(n.left) || isRangeExpression(n.left) && opPrec >= 7;
1214
+ const recurse = generateNode;
1215
+ switch (node.kind) {
1216
+ case 0 /* Program */:
1217
+ return generateProgram(node, recurse);
1218
+ case 1 /* NumberLiteral */:
1219
+ return String(node.value);
1220
+ case 8 /* StringLiteral */:
1221
+ return `"${escapeString(node.value)}"`;
1222
+ case 9 /* BooleanLiteral */:
1223
+ return node.value ? "true" : "false";
1224
+ case 10 /* ArrayLiteral */:
1225
+ return `[${node.elements.map(recurse).join(", ")}]`;
1226
+ case 2 /* Identifier */:
1227
+ return node.name;
1228
+ case 3 /* BinaryOp */: {
1229
+ const left = recurse(node.left);
1230
+ const right = recurse(node.right);
1231
+ const opPrec = getOperatorPrecedence(node.operator);
1232
+ const leftNeedsParens = needsParens(node.left, node.operator, true) || node.operator === "^" && isUnaryOp(node.left) || isIfExpression(node.left) || isForExpression(node.left) || isAssignment(node.left) || isRangeExpression(node.left) && opPrec >= 7;
1164
1233
  const leftCode = leftNeedsParens ? `(${left})` : left;
1165
- const rightNeedsParens = needsParens(n.right, n.operator, false) || isPipeExpression(n.right) || isAssignment(n.right) || isRangeExpression(n.right) && opPrec >= 6;
1234
+ const rightNeedsParens = needsParens(node.right, node.operator, false) || isPipeExpression(node.right) || isAssignment(node.right) || isRangeExpression(node.right) && opPrec >= 6;
1166
1235
  const rightCode = rightNeedsParens ? `(${right})` : right;
1167
- return `${leftCode} ${n.operator} ${rightCode}`;
1168
- },
1169
- UnaryOp: (n, recurse) => {
1170
- const arg = recurse(n.argument);
1171
- const parensNeeded = isBinaryOp(n.argument) || isAssignment(n.argument) || isPipeExpression(n.argument) || isRangeExpression(n.argument);
1236
+ return `${leftCode} ${node.operator} ${rightCode}`;
1237
+ }
1238
+ case 4 /* UnaryOp */: {
1239
+ const arg = recurse(node.argument);
1240
+ const parensNeeded = isBinaryOp(node.argument) || isAssignment(node.argument) || isPipeExpression(node.argument) || isRangeExpression(node.argument);
1172
1241
  const argCode = parensNeeded ? `(${arg})` : arg;
1173
- return `${n.operator}${argCode}`;
1174
- },
1175
- FunctionCall: (n, recurse) => {
1176
- const argsCode = n.args.map(recurse).join(", ");
1177
- return `${n.name}(${argsCode})`;
1178
- },
1179
- Assignment: (n, recurse) => {
1180
- const value = recurse(n.value);
1181
- return `${n.name} = ${value}`;
1182
- },
1183
- IfExpression: (n, recurse) => {
1184
- const condition = recurse(n.condition);
1185
- const consequent = recurse(n.consequent);
1186
- const alternate = recurse(n.alternate);
1242
+ return `${node.operator}${argCode}`;
1243
+ }
1244
+ case 5 /* FunctionCall */: {
1245
+ const argsCode = node.args.map(recurse).join(", ");
1246
+ return `${node.name}(${argsCode})`;
1247
+ }
1248
+ case 6 /* Assignment */: {
1249
+ const value = recurse(node.value);
1250
+ return `${node.name} = ${value}`;
1251
+ }
1252
+ case 7 /* IfExpression */: {
1253
+ const condition = recurse(node.condition);
1254
+ const consequent = recurse(node.consequent);
1255
+ const alternate = recurse(node.alternate);
1187
1256
  return `if ${condition} then ${consequent} else ${alternate}`;
1188
- },
1189
- ForExpression: (n, recurse) => {
1190
- const parts = [`for ${n.variable} in ${recurse(n.iterable)}`];
1191
- if (n.guard) {
1192
- parts.push(`when ${recurse(n.guard)}`);
1257
+ }
1258
+ case 11 /* ForExpression */: {
1259
+ const parts = [`for ${node.variable} in ${recurse(node.iterable)}`];
1260
+ if (node.guard) {
1261
+ parts.push(`when ${recurse(node.guard)}`);
1193
1262
  }
1194
- if (n.accumulator) {
1195
- parts.push(`into ${n.accumulator.name} = ${recurse(n.accumulator.initial)}`);
1263
+ if (node.accumulator) {
1264
+ parts.push(`into ${node.accumulator.name} = ${recurse(node.accumulator.initial)}`);
1196
1265
  }
1197
- parts.push(`then ${recurse(n.body)}`);
1266
+ parts.push(`then ${recurse(node.body)}`);
1198
1267
  return parts.join(" ");
1199
- },
1200
- IndexAccess: (n, recurse) => {
1201
- const object = recurse(n.object);
1202
- const index = recurse(n.index);
1203
- const needsParens2 = isBinaryOp(n.object) || isUnaryOp(n.object) || isAssignment(n.object) || isRangeExpression(n.object) || isPipeExpression(n.object);
1204
- const objectCode = needsParens2 ? `(${object})` : object;
1268
+ }
1269
+ case 12 /* IndexAccess */: {
1270
+ const object = recurse(node.object);
1271
+ const index = recurse(node.index);
1272
+ const objNeedsParens = isBinaryOp(node.object) || isUnaryOp(node.object) || isAssignment(node.object) || isRangeExpression(node.object) || isPipeExpression(node.object);
1273
+ const objectCode = objNeedsParens ? `(${object})` : object;
1205
1274
  return `${objectCode}[${index}]`;
1206
- },
1207
- RangeExpression: (n, recurse) => {
1208
- const start = recurse(n.start);
1209
- const end = recurse(n.end);
1210
- const op = n.inclusive ? "..=" : "..";
1211
- const startNeedsParens = isBinaryOp(n.start) || isRangeExpression(n.start) || isIfExpression(n.start) || isForExpression(n.start) || isAssignment(n.start);
1212
- const endNeedsParens = isBinaryOp(n.end) || isRangeExpression(n.end) || isPipeExpression(n.end) || isAssignment(n.end);
1275
+ }
1276
+ case 13 /* RangeExpression */: {
1277
+ const start = recurse(node.start);
1278
+ const end = recurse(node.end);
1279
+ const op = node.inclusive ? "..=" : "..";
1280
+ const startNeedsParens = isBinaryOp(node.start) || isRangeExpression(node.start) || isIfExpression(node.start) || isForExpression(node.start) || isAssignment(node.start);
1281
+ const endNeedsParens = isBinaryOp(node.end) || isRangeExpression(node.end) || isPipeExpression(node.end) || isAssignment(node.end);
1213
1282
  const startCode = startNeedsParens ? `(${start})` : start;
1214
1283
  const endCode = endNeedsParens ? `(${end})` : end;
1215
1284
  return `${startCode}${op}${endCode}`;
1216
- },
1217
- PipeExpression: (n, recurse) => {
1218
- const value = recurse(n.value);
1219
- const argsCode = n.args.map(recurse).join(", ");
1220
- const valueNeedsParens = isAssignment(n.value) || isIfExpression(n.value) || isForExpression(n.value);
1285
+ }
1286
+ case 14 /* PipeExpression */: {
1287
+ const value = recurse(node.value);
1288
+ const argsCode = node.args.map(recurse).join(", ");
1289
+ const valueNeedsParens = isAssignment(node.value) || isIfExpression(node.value) || isForExpression(node.value);
1221
1290
  const valueCode = valueNeedsParens ? `(${value})` : value;
1222
- return `${valueCode} |> ${n.name}(${argsCode})`;
1223
- },
1224
- Placeholder: () => "?"
1225
- });
1291
+ return `${valueCode} |> ${node.name}(${argsCode})`;
1292
+ }
1293
+ case 15 /* Placeholder */:
1294
+ return "?";
1295
+ }
1226
1296
  }
1227
1297
  // src/parser.ts
1228
1298
  var BINARY_OPERATOR_TOKENS = new Set([
@@ -1612,198 +1682,224 @@ function advance2(state) {
1612
1682
  }
1613
1683
 
1614
1684
  // src/interpreter.ts
1615
- function evaluateNode(node, context, variables, externalVariables) {
1616
- return visit(node, {
1617
- Program: (n, recurse) => {
1618
- let result = 0;
1619
- for (const statement of n.statements) {
1620
- result = recurse(statement);
1621
- }
1622
- return result;
1623
- },
1624
- NumberLiteral: (n) => n.value,
1625
- StringLiteral: (n) => n.value,
1626
- BooleanLiteral: (n) => n.value,
1627
- ArrayLiteral: (n, recurse) => {
1628
- const elements = n.elements.map(recurse);
1629
- validateHomogeneousArray(elements);
1630
- return elements;
1631
- },
1632
- Identifier: (n) => {
1633
- const value = variables.get(n.name);
1634
- if (value === undefined) {
1635
- throw new Error(`Undefined variable: ${n.name}`);
1636
- }
1637
- return value;
1638
- },
1639
- BinaryOp: (n, recurse) => {
1640
- if (n.operator === "&&") {
1641
- const left2 = recurse(n.left);
1642
- assertBoolean(left2, "Operator '&&'", "left");
1643
- if (!left2)
1644
- return false;
1645
- const right2 = recurse(n.right);
1646
- assertBoolean(right2, "Operator '&&'", "right");
1647
- return right2;
1648
- }
1649
- if (n.operator === "||") {
1650
- const left2 = recurse(n.left);
1651
- assertBoolean(left2, "Operator '||'", "left");
1652
- if (left2)
1653
- return true;
1654
- const right2 = recurse(n.right);
1655
- assertBoolean(right2, "Operator '||'", "right");
1656
- return right2;
1685
+ function run(input, context = {}) {
1686
+ const node = typeof input === "string" ? parse(input) : input;
1687
+ const variables = new Map;
1688
+ const externalVariables = new Set;
1689
+ const vars = context.variables;
1690
+ if (vars) {
1691
+ for (const key of Object.keys(vars)) {
1692
+ variables.set(key, vars[key]);
1693
+ externalVariables.add(key);
1694
+ }
1695
+ }
1696
+ const value = evalNode(node);
1697
+ return { value, variables };
1698
+ function evalNode(node2) {
1699
+ switch (node2.kind) {
1700
+ case 0 /* Program */: {
1701
+ let result = 0;
1702
+ for (const statement of node2.statements) {
1703
+ result = evalNode(statement);
1704
+ }
1705
+ return result;
1657
1706
  }
1658
- const left = recurse(n.left);
1659
- const right = recurse(n.right);
1660
- return evaluateBinaryOperation(n.operator, left, right);
1661
- },
1662
- UnaryOp: (n, recurse) => {
1663
- const arg = recurse(n.argument);
1664
- if (n.operator === "-") {
1665
- assertNumber(arg, "Operator '-' (unary)");
1666
- return -arg;
1707
+ case 1 /* NumberLiteral */:
1708
+ return node2.value;
1709
+ case 8 /* StringLiteral */:
1710
+ return node2.value;
1711
+ case 9 /* BooleanLiteral */:
1712
+ return node2.value;
1713
+ case 10 /* ArrayLiteral */: {
1714
+ const elems = node2.elements;
1715
+ const elements = [];
1716
+ for (let i = 0;i < elems.length; i++) {
1717
+ elements.push(evalNode(elems[i]));
1718
+ }
1719
+ validateHomogeneousArray(elements);
1720
+ return elements;
1667
1721
  }
1668
- if (n.operator === "!") {
1669
- assertBoolean(arg, "Operator '!'");
1670
- return !arg;
1722
+ case 2 /* Identifier */: {
1723
+ const value2 = variables.get(node2.name);
1724
+ if (value2 === undefined) {
1725
+ throw new Error(`Undefined variable: ${node2.name}`);
1726
+ }
1727
+ return value2;
1671
1728
  }
1672
- throw new Error(`Unknown unary operator: ${String(n.operator)}`);
1673
- },
1674
- FunctionCall: (n, recurse) => {
1675
- const fn = context.functions?.[n.name];
1676
- if (fn === undefined) {
1677
- throw new Error(`Undefined function: ${n.name}`);
1729
+ case 3 /* BinaryOp */: {
1730
+ if (node2.operator === "&&") {
1731
+ const left = evalNode(node2.left);
1732
+ assertBoolean(left, "Operator '&&'", "left");
1733
+ if (!left)
1734
+ return false;
1735
+ const right = evalNode(node2.right);
1736
+ assertBoolean(right, "Operator '&&'", "right");
1737
+ return right;
1738
+ }
1739
+ if (node2.operator === "||") {
1740
+ const left = evalNode(node2.left);
1741
+ assertBoolean(left, "Operator '||'", "left");
1742
+ if (left)
1743
+ return true;
1744
+ const right = evalNode(node2.right);
1745
+ assertBoolean(right, "Operator '||'", "right");
1746
+ return right;
1747
+ }
1748
+ return evaluateBinaryOperation(node2.operator, evalNode(node2.left), evalNode(node2.right));
1678
1749
  }
1679
- if (typeof fn !== "function") {
1680
- throw new Error(`${n.name} is not a function`);
1750
+ case 4 /* UnaryOp */: {
1751
+ const arg = evalNode(node2.argument);
1752
+ if (node2.operator === "-") {
1753
+ assertNumber(arg, "Operator '-' (unary)");
1754
+ return -arg;
1755
+ }
1756
+ if (node2.operator === "!") {
1757
+ assertBoolean(arg, "Operator '!'");
1758
+ return !arg;
1759
+ }
1760
+ throw new Error(`Unknown unary operator: ${String(node2.operator)}`);
1681
1761
  }
1682
- const evaluatedArgs = n.args.map(recurse);
1683
- return fn(...evaluatedArgs);
1684
- },
1685
- Assignment: (n, recurse) => {
1686
- const value = recurse(n.value);
1687
- if (externalVariables.has(n.name)) {
1688
- const externalValue = variables.get(n.name);
1689
- if (externalValue !== undefined) {
1690
- return externalValue;
1762
+ case 5 /* FunctionCall */: {
1763
+ const fn = context.functions?.[node2.name];
1764
+ if (fn === undefined) {
1765
+ throw new Error(`Undefined function: ${node2.name}`);
1766
+ }
1767
+ if (typeof fn !== "function") {
1768
+ throw new Error(`${node2.name} is not a function`);
1769
+ }
1770
+ const nodeArgs = node2.args;
1771
+ const evaluatedArgs = [];
1772
+ for (let i = 0;i < nodeArgs.length; i++) {
1773
+ evaluatedArgs.push(evalNode(nodeArgs[i]));
1691
1774
  }
1775
+ return fn(...evaluatedArgs);
1692
1776
  }
1693
- variables.set(n.name, value);
1694
- return value;
1695
- },
1696
- IfExpression: (n, recurse) => {
1697
- const condition = recurse(n.condition);
1698
- assertBoolean(condition, "If condition");
1699
- return condition ? recurse(n.consequent) : recurse(n.alternate);
1700
- },
1701
- IndexAccess: (n, recurse) => {
1702
- const object = recurse(n.object);
1703
- const index = recurse(n.index);
1704
- if (Array.isArray(object)) {
1705
- return resolveIndex(object, index);
1777
+ case 6 /* Assignment */: {
1778
+ const value2 = evalNode(node2.value);
1779
+ if (externalVariables.has(node2.name)) {
1780
+ const externalValue = variables.get(node2.name);
1781
+ if (externalValue !== undefined) {
1782
+ return externalValue;
1783
+ }
1784
+ }
1785
+ variables.set(node2.name, value2);
1786
+ return value2;
1706
1787
  }
1707
- if (typeof object === "string") {
1708
- return resolveIndex(object, index);
1788
+ case 7 /* IfExpression */: {
1789
+ const condition = evalNode(node2.condition);
1790
+ assertBoolean(condition, "If condition");
1791
+ return condition ? evalNode(node2.consequent) : evalNode(node2.alternate);
1709
1792
  }
1710
- throw new TypeError(`Index access expected array or string, got ${typeOf(object)}`);
1711
- },
1712
- RangeExpression: (n, recurse) => {
1713
- const start = recurse(n.start);
1714
- const end = recurse(n.end);
1715
- assertNumber(start, "Range start");
1716
- assertNumber(end, "Range end");
1717
- return buildRange(start, end, n.inclusive);
1718
- },
1719
- PipeExpression: (n, recurse) => {
1720
- const pipedValue = recurse(n.value);
1721
- const fn = context.functions?.[n.name];
1722
- if (fn === undefined) {
1723
- throw new Error(`Undefined function: ${n.name}`);
1793
+ case 12 /* IndexAccess */: {
1794
+ const object = evalNode(node2.object);
1795
+ const index = evalNode(node2.index);
1796
+ if (Array.isArray(object)) {
1797
+ return resolveIndex(object, index);
1798
+ }
1799
+ if (typeof object === "string") {
1800
+ return resolveIndex(object, index);
1801
+ }
1802
+ throw new TypeError(`Index access expected array or string, got ${typeOf(object)}`);
1724
1803
  }
1725
- if (typeof fn !== "function") {
1726
- throw new Error(`${n.name} is not a function`);
1804
+ case 13 /* RangeExpression */: {
1805
+ const start = evalNode(node2.start);
1806
+ const end = evalNode(node2.end);
1807
+ assertNumber(start, "Range start");
1808
+ assertNumber(end, "Range end");
1809
+ return buildRange(start, end, node2.inclusive);
1727
1810
  }
1728
- const evaluatedArgs = n.args.map((arg) => arg.kind === 15 /* Placeholder */ ? pipedValue : recurse(arg));
1729
- return fn(...evaluatedArgs);
1730
- },
1731
- Placeholder: () => {
1732
- throw new Error("Placeholder outside pipe expression");
1733
- },
1734
- ForExpression: (n, recurse) => {
1735
- const iterable = recurse(n.iterable);
1736
- let items;
1737
- if (Array.isArray(iterable)) {
1738
- items = iterable;
1739
- } else if (typeof iterable === "string") {
1740
- items = Array.from(iterable);
1741
- } else {
1742
- throw new TypeError(`For expression expected array or string, got ${typeOf(iterable)}`);
1811
+ case 14 /* PipeExpression */: {
1812
+ const pipedValue = evalNode(node2.value);
1813
+ const fn = context.functions?.[node2.name];
1814
+ if (fn === undefined) {
1815
+ throw new Error(`Undefined function: ${node2.name}`);
1816
+ }
1817
+ if (typeof fn !== "function") {
1818
+ throw new Error(`${node2.name} is not a function`);
1819
+ }
1820
+ const pipeArgs = node2.args;
1821
+ const evaluatedArgs = [];
1822
+ for (let i = 0;i < pipeArgs.length; i++) {
1823
+ const arg = pipeArgs[i];
1824
+ evaluatedArgs.push(arg.kind === 15 /* Placeholder */ ? pipedValue : evalNode(arg));
1825
+ }
1826
+ return fn(...evaluatedArgs);
1743
1827
  }
1744
- const previousValue = variables.get(n.variable);
1745
- const hadPreviousValue = variables.has(n.variable);
1746
- const restoreLoopVar = () => {
1747
- if (hadPreviousValue) {
1748
- variables.set(n.variable, previousValue);
1828
+ case 15 /* Placeholder */:
1829
+ throw new Error("Placeholder outside pipe expression");
1830
+ case 11 /* ForExpression */: {
1831
+ const iterable = evalNode(node2.iterable);
1832
+ let iterTarget;
1833
+ if (Array.isArray(iterable)) {
1834
+ iterTarget = iterable;
1835
+ } else if (typeof iterable === "string") {
1836
+ iterTarget = iterable;
1749
1837
  } else {
1750
- variables.delete(n.variable);
1838
+ throw new TypeError(`For expression expected array or string, got ${typeOf(iterable)}`);
1751
1839
  }
1752
- };
1753
- if (n.accumulator) {
1754
- let acc = recurse(n.accumulator.initial);
1755
- const prevAcc = variables.get(n.accumulator.name);
1756
- const hadPrevAcc = variables.has(n.accumulator.name);
1757
- for (const item of items) {
1758
- variables.set(n.variable, item);
1759
- if (n.guard) {
1760
- const guardValue = recurse(n.guard);
1840
+ const previousValue = variables.get(node2.variable);
1841
+ const hadPreviousValue = variables.has(node2.variable);
1842
+ if (node2.accumulator) {
1843
+ let acc = evalNode(node2.accumulator.initial);
1844
+ const prevAcc = variables.get(node2.accumulator.name);
1845
+ const hadPrevAcc = variables.has(node2.accumulator.name);
1846
+ for (const item of iterTarget) {
1847
+ variables.set(node2.variable, item);
1848
+ if (node2.guard) {
1849
+ const guardValue = evalNode(node2.guard);
1850
+ assertBoolean(guardValue, "For guard");
1851
+ if (!guardValue)
1852
+ continue;
1853
+ }
1854
+ variables.set(node2.accumulator.name, acc);
1855
+ acc = evalNode(node2.body);
1856
+ }
1857
+ if (hadPrevAcc) {
1858
+ variables.set(node2.accumulator.name, prevAcc);
1859
+ } else {
1860
+ variables.delete(node2.accumulator.name);
1861
+ }
1862
+ if (hadPreviousValue) {
1863
+ variables.set(node2.variable, previousValue);
1864
+ } else {
1865
+ variables.delete(node2.variable);
1866
+ }
1867
+ return acc;
1868
+ }
1869
+ const result = [];
1870
+ for (const item of iterTarget) {
1871
+ variables.set(node2.variable, item);
1872
+ if (node2.guard) {
1873
+ const guardValue = evalNode(node2.guard);
1761
1874
  assertBoolean(guardValue, "For guard");
1762
1875
  if (!guardValue)
1763
1876
  continue;
1764
1877
  }
1765
- variables.set(n.accumulator.name, acc);
1766
- acc = recurse(n.body);
1878
+ result.push(evalNode(node2.body));
1767
1879
  }
1768
- if (hadPrevAcc) {
1769
- variables.set(n.accumulator.name, prevAcc);
1880
+ if (hadPreviousValue) {
1881
+ variables.set(node2.variable, previousValue);
1770
1882
  } else {
1771
- variables.delete(n.accumulator.name);
1883
+ variables.delete(node2.variable);
1772
1884
  }
1773
- restoreLoopVar();
1774
- return acc;
1885
+ validateHomogeneousArray(result);
1886
+ return result;
1775
1887
  }
1776
- const result = [];
1777
- for (const item of items) {
1778
- variables.set(n.variable, item);
1779
- if (n.guard) {
1780
- const guardValue = recurse(n.guard);
1781
- assertBoolean(guardValue, "For guard");
1782
- if (!guardValue)
1783
- continue;
1784
- }
1785
- result.push(recurse(n.body));
1786
- }
1787
- restoreLoopVar();
1788
- validateHomogeneousArray(result);
1789
- return result;
1790
1888
  }
1791
- });
1792
- }
1793
- function run(input, context = {}) {
1794
- const node = typeof input === "string" ? parse(input) : input;
1795
- const entries = Object.entries(context.variables || {});
1796
- const variables = new Map(entries);
1797
- const externalVariables = new Set(entries.map(([key]) => key));
1798
- const value = evaluateNode(node, context, variables, externalVariables);
1799
- return { value, variables };
1889
+ }
1800
1890
  }
1801
1891
  function evaluate(input, context = {}) {
1802
1892
  return run(input, context).value;
1803
1893
  }
1804
1894
  function evaluateScope(input, context = {}) {
1805
- const { variables } = run(input, context);
1806
- return Object.fromEntries(variables);
1895
+ return evaluateWithScope(input, context).scope;
1896
+ }
1897
+ function evaluateWithScope(input, context = {}) {
1898
+ const { value, variables } = run(input, context);
1899
+ return {
1900
+ value,
1901
+ scope: Object.fromEntries(variables)
1902
+ };
1807
1903
  }
1808
1904
  // src/optimizer.ts
1809
1905
  function preserveComments(original, replacement) {
@@ -1869,24 +1965,34 @@ function isLiteral(node) {
1869
1965
  return isNumberLiteral(node) || isStringLiteral(node) || isBooleanLiteral(node);
1870
1966
  }
1871
1967
  function mightHaveSideEffects(node) {
1872
- return visit(node, {
1873
- Program: (n, recurse) => n.statements.some(recurse),
1874
- NumberLiteral: () => false,
1875
- StringLiteral: () => false,
1876
- BooleanLiteral: () => false,
1877
- Identifier: () => false,
1878
- ArrayLiteral: (n, recurse) => n.elements.some(recurse),
1879
- BinaryOp: (n, recurse) => recurse(n.left) || recurse(n.right),
1880
- UnaryOp: (n, recurse) => recurse(n.argument),
1881
- FunctionCall: () => true,
1882
- PipeExpression: () => true,
1883
- Placeholder: () => false,
1884
- Assignment: () => true,
1885
- IfExpression: (n, recurse) => recurse(n.condition) || recurse(n.consequent) || recurse(n.alternate),
1886
- ForExpression: (n, recurse) => recurse(n.iterable) || (n.guard ? recurse(n.guard) : false) || (n.accumulator ? recurse(n.accumulator.initial) : false) || recurse(n.body),
1887
- IndexAccess: (n, recurse) => recurse(n.object) || recurse(n.index),
1888
- RangeExpression: (n, recurse) => recurse(n.start) || recurse(n.end)
1889
- });
1968
+ switch (node.kind) {
1969
+ case 0 /* Program */:
1970
+ return node.statements.some(mightHaveSideEffects);
1971
+ case 10 /* ArrayLiteral */:
1972
+ return node.elements.some(mightHaveSideEffects);
1973
+ case 3 /* BinaryOp */:
1974
+ return mightHaveSideEffects(node.left) || mightHaveSideEffects(node.right);
1975
+ case 4 /* UnaryOp */:
1976
+ return mightHaveSideEffects(node.argument);
1977
+ case 7 /* IfExpression */:
1978
+ return mightHaveSideEffects(node.condition) || mightHaveSideEffects(node.consequent) || mightHaveSideEffects(node.alternate);
1979
+ case 11 /* ForExpression */:
1980
+ return mightHaveSideEffects(node.iterable) || node.guard !== null && mightHaveSideEffects(node.guard) || node.accumulator !== null && mightHaveSideEffects(node.accumulator.initial) || mightHaveSideEffects(node.body);
1981
+ case 12 /* IndexAccess */:
1982
+ return mightHaveSideEffects(node.object) || mightHaveSideEffects(node.index);
1983
+ case 13 /* RangeExpression */:
1984
+ return mightHaveSideEffects(node.start) || mightHaveSideEffects(node.end);
1985
+ case 5 /* FunctionCall */:
1986
+ case 14 /* PipeExpression */:
1987
+ case 6 /* Assignment */:
1988
+ return true;
1989
+ case 1 /* NumberLiteral */:
1990
+ case 8 /* StringLiteral */:
1991
+ case 9 /* BooleanLiteral */:
1992
+ case 2 /* Identifier */:
1993
+ case 15 /* Placeholder */:
1994
+ return false;
1995
+ }
1890
1996
  }
1891
1997
  function propagateConstants(program2, externalVariables) {
1892
1998
  const statements = program2.statements;
@@ -1917,10 +2023,9 @@ function propagateConstants(program2, externalVariables) {
1917
2023
  return null;
1918
2024
  const referencedIds = new Set;
1919
2025
  for (const stmt of statements) {
1920
- if (isAssignment(stmt)) {
1921
- collectReferencedIdentifiers(stmt.value, referencedIds);
1922
- } else {
1923
- collectReferencedIdentifiers(stmt, referencedIds);
2026
+ const identifiers = collectAllIdentifiers(isAssignment(stmt) ? stmt.value : stmt);
2027
+ for (const id of identifiers) {
2028
+ referencedIds.add(id);
1924
2029
  }
1925
2030
  }
1926
2031
  let hasSubstitution = false;
@@ -1938,221 +2043,230 @@ function propagateConstants(program2, externalVariables) {
1938
2043
  }
1939
2044
  return result;
1940
2045
  }
1941
- function collectReferencedIdentifiers(node, ids) {
1942
- visit(node, {
1943
- Program: (n, recurse) => {
1944
- for (const s of n.statements)
1945
- recurse(s);
1946
- },
1947
- NumberLiteral: () => {},
1948
- StringLiteral: () => {},
1949
- BooleanLiteral: () => {},
1950
- ArrayLiteral: (n, recurse) => {
1951
- for (const e of n.elements)
1952
- recurse(e);
1953
- },
1954
- Identifier: (n) => {
1955
- ids.add(n.name);
1956
- },
1957
- BinaryOp: (n, recurse) => {
1958
- recurse(n.left);
1959
- recurse(n.right);
1960
- },
1961
- UnaryOp: (n, recurse) => {
1962
- recurse(n.argument);
1963
- },
1964
- FunctionCall: (n, recurse) => {
1965
- for (const a of n.args)
1966
- recurse(a);
1967
- },
1968
- Assignment: (n, recurse) => {
1969
- recurse(n.value);
1970
- },
1971
- IfExpression: (n, recurse) => {
1972
- recurse(n.condition);
1973
- recurse(n.consequent);
1974
- recurse(n.alternate);
1975
- },
1976
- ForExpression: (n, recurse) => {
1977
- recurse(n.iterable);
1978
- if (n.guard)
1979
- recurse(n.guard);
1980
- if (n.accumulator)
1981
- recurse(n.accumulator.initial);
1982
- recurse(n.body);
1983
- },
1984
- IndexAccess: (n, recurse) => {
1985
- recurse(n.object);
1986
- recurse(n.index);
1987
- },
1988
- RangeExpression: (n, recurse) => {
1989
- recurse(n.start);
1990
- recurse(n.end);
1991
- },
1992
- PipeExpression: (n, recurse) => {
1993
- recurse(n.value);
1994
- for (const a of n.args)
1995
- recurse(a);
1996
- },
1997
- Placeholder: () => {}
1998
- });
1999
- }
2000
2046
  function collectForLoopVars(node, vars) {
2001
- visit(node, {
2002
- Program: (n, recurse) => {
2003
- for (const s of n.statements)
2004
- recurse(s);
2005
- },
2006
- NumberLiteral: () => {},
2007
- StringLiteral: () => {},
2008
- BooleanLiteral: () => {},
2009
- ArrayLiteral: (n, recurse) => {
2010
- for (const e of n.elements)
2011
- recurse(e);
2012
- },
2013
- Identifier: () => {},
2014
- BinaryOp: (n, recurse) => {
2015
- recurse(n.left);
2016
- recurse(n.right);
2017
- },
2018
- UnaryOp: (n, recurse) => {
2019
- recurse(n.argument);
2020
- },
2021
- FunctionCall: (n, recurse) => {
2022
- for (const a of n.args)
2023
- recurse(a);
2024
- },
2025
- Assignment: (n, recurse) => {
2026
- recurse(n.value);
2027
- },
2028
- IfExpression: (n, recurse) => {
2029
- recurse(n.condition);
2030
- recurse(n.consequent);
2031
- recurse(n.alternate);
2032
- },
2033
- ForExpression: (n, recurse) => {
2034
- vars.add(n.variable);
2035
- if (n.accumulator)
2036
- vars.add(n.accumulator.name);
2037
- recurse(n.iterable);
2038
- if (n.guard)
2039
- recurse(n.guard);
2040
- if (n.accumulator)
2041
- recurse(n.accumulator.initial);
2042
- recurse(n.body);
2043
- },
2044
- IndexAccess: (n, recurse) => {
2045
- recurse(n.object);
2046
- recurse(n.index);
2047
- },
2048
- RangeExpression: (n, recurse) => {
2049
- recurse(n.start);
2050
- recurse(n.end);
2051
- },
2052
- PipeExpression: (n, recurse) => {
2053
- recurse(n.value);
2054
- for (const a of n.args)
2055
- recurse(a);
2056
- },
2057
- Placeholder: () => {}
2058
- });
2047
+ switch (node.kind) {
2048
+ case 0 /* Program */:
2049
+ for (const s of node.statements)
2050
+ collectForLoopVars(s, vars);
2051
+ break;
2052
+ case 10 /* ArrayLiteral */:
2053
+ for (const e of node.elements)
2054
+ collectForLoopVars(e, vars);
2055
+ break;
2056
+ case 3 /* BinaryOp */:
2057
+ collectForLoopVars(node.left, vars);
2058
+ collectForLoopVars(node.right, vars);
2059
+ break;
2060
+ case 4 /* UnaryOp */:
2061
+ collectForLoopVars(node.argument, vars);
2062
+ break;
2063
+ case 5 /* FunctionCall */:
2064
+ for (const a of node.args)
2065
+ collectForLoopVars(a, vars);
2066
+ break;
2067
+ case 6 /* Assignment */:
2068
+ collectForLoopVars(node.value, vars);
2069
+ break;
2070
+ case 7 /* IfExpression */:
2071
+ collectForLoopVars(node.condition, vars);
2072
+ collectForLoopVars(node.consequent, vars);
2073
+ collectForLoopVars(node.alternate, vars);
2074
+ break;
2075
+ case 11 /* ForExpression */:
2076
+ vars.add(node.variable);
2077
+ if (node.accumulator)
2078
+ vars.add(node.accumulator.name);
2079
+ collectForLoopVars(node.iterable, vars);
2080
+ if (node.guard)
2081
+ collectForLoopVars(node.guard, vars);
2082
+ if (node.accumulator)
2083
+ collectForLoopVars(node.accumulator.initial, vars);
2084
+ collectForLoopVars(node.body, vars);
2085
+ break;
2086
+ case 12 /* IndexAccess */:
2087
+ collectForLoopVars(node.object, vars);
2088
+ collectForLoopVars(node.index, vars);
2089
+ break;
2090
+ case 13 /* RangeExpression */:
2091
+ collectForLoopVars(node.start, vars);
2092
+ collectForLoopVars(node.end, vars);
2093
+ break;
2094
+ case 14 /* PipeExpression */:
2095
+ collectForLoopVars(node.value, vars);
2096
+ for (const a of node.args)
2097
+ collectForLoopVars(a, vars);
2098
+ break;
2099
+ case 1 /* NumberLiteral */:
2100
+ case 8 /* StringLiteral */:
2101
+ case 9 /* BooleanLiteral */:
2102
+ case 2 /* Identifier */:
2103
+ case 15 /* Placeholder */:
2104
+ break;
2105
+ }
2059
2106
  }
2060
2107
  function countAssignments(node, counts) {
2061
- visit(node, {
2062
- Program: (n, recurse) => {
2063
- for (const s of n.statements)
2064
- recurse(s);
2065
- },
2066
- NumberLiteral: () => {},
2067
- StringLiteral: () => {},
2068
- BooleanLiteral: () => {},
2069
- ArrayLiteral: (n, recurse) => {
2070
- for (const e of n.elements)
2071
- recurse(e);
2072
- },
2073
- Identifier: () => {},
2074
- BinaryOp: (n, recurse) => {
2075
- recurse(n.left);
2076
- recurse(n.right);
2077
- },
2078
- UnaryOp: (n, recurse) => {
2079
- recurse(n.argument);
2080
- },
2081
- FunctionCall: (n, recurse) => {
2082
- for (const a of n.args)
2083
- recurse(a);
2084
- },
2085
- Assignment: (n, recurse) => {
2086
- counts.set(n.name, (counts.get(n.name) ?? 0) + 1);
2087
- recurse(n.value);
2088
- },
2089
- IfExpression: (n, recurse) => {
2090
- recurse(n.condition);
2091
- recurse(n.consequent);
2092
- recurse(n.alternate);
2093
- },
2094
- ForExpression: (n, recurse) => {
2095
- recurse(n.iterable);
2096
- if (n.guard)
2097
- recurse(n.guard);
2098
- if (n.accumulator)
2099
- recurse(n.accumulator.initial);
2100
- recurse(n.body);
2101
- },
2102
- IndexAccess: (n, recurse) => {
2103
- recurse(n.object);
2104
- recurse(n.index);
2105
- },
2106
- RangeExpression: (n, recurse) => {
2107
- recurse(n.start);
2108
- recurse(n.end);
2109
- },
2110
- PipeExpression: (n, recurse) => {
2111
- recurse(n.value);
2112
- for (const a of n.args)
2113
- recurse(a);
2114
- },
2115
- Placeholder: () => {}
2116
- });
2108
+ switch (node.kind) {
2109
+ case 0 /* Program */:
2110
+ for (const s of node.statements)
2111
+ countAssignments(s, counts);
2112
+ break;
2113
+ case 6 /* Assignment */:
2114
+ counts.set(node.name, (counts.get(node.name) ?? 0) + 1);
2115
+ countAssignments(node.value, counts);
2116
+ break;
2117
+ case 10 /* ArrayLiteral */:
2118
+ for (const e of node.elements)
2119
+ countAssignments(e, counts);
2120
+ break;
2121
+ case 3 /* BinaryOp */:
2122
+ countAssignments(node.left, counts);
2123
+ countAssignments(node.right, counts);
2124
+ break;
2125
+ case 4 /* UnaryOp */:
2126
+ countAssignments(node.argument, counts);
2127
+ break;
2128
+ case 5 /* FunctionCall */:
2129
+ for (const a of node.args)
2130
+ countAssignments(a, counts);
2131
+ break;
2132
+ case 7 /* IfExpression */:
2133
+ countAssignments(node.condition, counts);
2134
+ countAssignments(node.consequent, counts);
2135
+ countAssignments(node.alternate, counts);
2136
+ break;
2137
+ case 11 /* ForExpression */:
2138
+ countAssignments(node.iterable, counts);
2139
+ if (node.guard)
2140
+ countAssignments(node.guard, counts);
2141
+ if (node.accumulator)
2142
+ countAssignments(node.accumulator.initial, counts);
2143
+ countAssignments(node.body, counts);
2144
+ break;
2145
+ case 12 /* IndexAccess */:
2146
+ countAssignments(node.object, counts);
2147
+ countAssignments(node.index, counts);
2148
+ break;
2149
+ case 13 /* RangeExpression */:
2150
+ countAssignments(node.start, counts);
2151
+ countAssignments(node.end, counts);
2152
+ break;
2153
+ case 14 /* PipeExpression */:
2154
+ countAssignments(node.value, counts);
2155
+ for (const a of node.args)
2156
+ countAssignments(a, counts);
2157
+ break;
2158
+ case 1 /* NumberLiteral */:
2159
+ case 8 /* StringLiteral */:
2160
+ case 9 /* BooleanLiteral */:
2161
+ case 2 /* Identifier */:
2162
+ case 15 /* Placeholder */:
2163
+ break;
2164
+ }
2165
+ }
2166
+ function unchangedArray(original, mapped) {
2167
+ for (let i = 0;i < original.length; i++) {
2168
+ if (original[i] !== mapped[i])
2169
+ return false;
2170
+ }
2171
+ return true;
2117
2172
  }
2118
2173
  function substituteIdentifiers(node, knownValues) {
2119
- return visit(node, {
2120
- Program: (n, recurse) => {
2121
- const result = program(n.statements.map(recurse));
2122
- if (n.trailingComments && n.trailingComments.length > 0) {
2123
- return { ...result, trailingComments: n.trailingComments };
2174
+ const recurse = (n) => substituteIdentifiers(n, knownValues);
2175
+ switch (node.kind) {
2176
+ case 0 /* Program */: {
2177
+ const stmts = node.statements.map(recurse);
2178
+ if (unchangedArray(node.statements, stmts))
2179
+ return node;
2180
+ const result = program(stmts);
2181
+ if (node.trailingComments && node.trailingComments.length > 0) {
2182
+ return { ...result, trailingComments: node.trailingComments };
2124
2183
  }
2125
2184
  return result;
2126
- },
2127
- NumberLiteral: (n) => n,
2128
- StringLiteral: (n) => n,
2129
- BooleanLiteral: (n) => n,
2130
- ArrayLiteral: (n, recurse) => preserveComments(n, array(n.elements.map(recurse))),
2131
- Identifier: (n) => {
2132
- const replacement = knownValues.get(n.name);
2133
- return replacement ? preserveComments(n, replacement) : n;
2134
- },
2135
- BinaryOp: (n, recurse) => preserveComments(n, binaryOp(recurse(n.left), n.operator, recurse(n.right))),
2136
- UnaryOp: (n, recurse) => preserveComments(n, unaryOp(n.operator, recurse(n.argument))),
2137
- FunctionCall: (n, recurse) => preserveComments(n, functionCall(n.name, n.args.map(recurse))),
2138
- Assignment: (n, recurse) => preserveComments(n, assign(n.name, recurse(n.value))),
2139
- IfExpression: (n, recurse) => preserveComments(n, ifExpr(recurse(n.condition), recurse(n.consequent), recurse(n.alternate))),
2140
- ForExpression: (n, recurse) => {
2185
+ }
2186
+ case 1 /* NumberLiteral */:
2187
+ case 8 /* StringLiteral */:
2188
+ case 9 /* BooleanLiteral */:
2189
+ case 15 /* Placeholder */:
2190
+ return node;
2191
+ case 10 /* ArrayLiteral */: {
2192
+ const elements = node.elements.map(recurse);
2193
+ if (unchangedArray(node.elements, elements))
2194
+ return node;
2195
+ return preserveComments(node, array(elements));
2196
+ }
2197
+ case 2 /* Identifier */: {
2198
+ const replacement = knownValues.get(node.name);
2199
+ return replacement ? preserveComments(node, replacement) : node;
2200
+ }
2201
+ case 3 /* BinaryOp */: {
2202
+ const left = recurse(node.left);
2203
+ const right = recurse(node.right);
2204
+ if (left === node.left && right === node.right)
2205
+ return node;
2206
+ return preserveComments(node, binaryOp(left, node.operator, right));
2207
+ }
2208
+ case 4 /* UnaryOp */: {
2209
+ const argument = recurse(node.argument);
2210
+ if (argument === node.argument)
2211
+ return node;
2212
+ return preserveComments(node, unaryOp(node.operator, argument));
2213
+ }
2214
+ case 5 /* FunctionCall */: {
2215
+ const args = node.args.map(recurse);
2216
+ if (unchangedArray(node.args, args))
2217
+ return node;
2218
+ return preserveComments(node, functionCall(node.name, args));
2219
+ }
2220
+ case 6 /* Assignment */: {
2221
+ const value = recurse(node.value);
2222
+ if (value === node.value)
2223
+ return node;
2224
+ return preserveComments(node, assign(node.name, value));
2225
+ }
2226
+ case 7 /* IfExpression */: {
2227
+ const condition = recurse(node.condition);
2228
+ const consequent = recurse(node.consequent);
2229
+ const alternate = recurse(node.alternate);
2230
+ if (condition === node.condition && consequent === node.consequent && alternate === node.alternate)
2231
+ return node;
2232
+ return preserveComments(node, ifExpr(condition, consequent, alternate));
2233
+ }
2234
+ case 11 /* ForExpression */: {
2141
2235
  const innerKnown = new Map(knownValues);
2142
- innerKnown.delete(n.variable);
2143
- if (n.accumulator)
2144
- innerKnown.delete(n.accumulator.name);
2145
- const iterable = recurse(n.iterable);
2146
- const guard = n.guard ? substituteIdentifiers(n.guard, innerKnown) : null;
2147
- const accumulator = n.accumulator ? { name: n.accumulator.name, initial: recurse(n.accumulator.initial) } : null;
2148
- const body = substituteIdentifiers(n.body, innerKnown);
2149
- return preserveComments(n, forExpr(n.variable, iterable, guard, accumulator, body));
2150
- },
2151
- IndexAccess: (n, recurse) => preserveComments(n, indexAccess(recurse(n.object), recurse(n.index))),
2152
- RangeExpression: (n, recurse) => preserveComments(n, rangeExpr(recurse(n.start), recurse(n.end), n.inclusive)),
2153
- PipeExpression: (n, recurse) => preserveComments(n, pipeExpr(recurse(n.value), n.name, n.args.map(recurse))),
2154
- Placeholder: (n) => n
2155
- });
2236
+ innerKnown.delete(node.variable);
2237
+ if (node.accumulator)
2238
+ innerKnown.delete(node.accumulator.name);
2239
+ const iterable = recurse(node.iterable);
2240
+ const guard = node.guard ? substituteIdentifiers(node.guard, innerKnown) : null;
2241
+ const initial = node.accumulator ? recurse(node.accumulator.initial) : null;
2242
+ const body = substituteIdentifiers(node.body, innerKnown);
2243
+ if (iterable === node.iterable && guard === node.guard && (node.accumulator === null || initial === node.accumulator.initial) && body === node.body)
2244
+ return node;
2245
+ const accumulator = node.accumulator ? { name: node.accumulator.name, initial } : null;
2246
+ return preserveComments(node, forExpr(node.variable, iterable, guard, accumulator, body));
2247
+ }
2248
+ case 12 /* IndexAccess */: {
2249
+ const object = recurse(node.object);
2250
+ const index = recurse(node.index);
2251
+ if (object === node.object && index === node.index)
2252
+ return node;
2253
+ return preserveComments(node, indexAccess(object, index));
2254
+ }
2255
+ case 13 /* RangeExpression */: {
2256
+ const start = recurse(node.start);
2257
+ const end = recurse(node.end);
2258
+ if (start === node.start && end === node.end)
2259
+ return node;
2260
+ return preserveComments(node, rangeExpr(start, end, node.inclusive));
2261
+ }
2262
+ case 14 /* PipeExpression */: {
2263
+ const value = recurse(node.value);
2264
+ const args = node.args.map(recurse);
2265
+ if (value === node.value && unchangedArray(node.args, args))
2266
+ return node;
2267
+ return preserveComments(node, pipeExpr(value, node.name, args));
2268
+ }
2269
+ }
2156
2270
  }
2157
2271
  function optimize(node, externalVariables) {
2158
2272
  let propagated = fold(node);
@@ -2179,142 +2293,188 @@ function optimize(node, externalVariables) {
2179
2293
  return propagated;
2180
2294
  }
2181
2295
  function fold(node) {
2182
- return visit(node, {
2183
- NumberLiteral: (n) => n,
2184
- StringLiteral: (n) => n,
2185
- BooleanLiteral: (n) => n,
2186
- ArrayLiteral: (n, recurse) => {
2187
- const elements = n.elements.map(recurse);
2188
- return preserveComments(n, array(elements));
2189
- },
2190
- Identifier: (n) => n,
2191
- BinaryOp: (n, recurse) => {
2192
- const left = recurse(n.left);
2193
- const right = recurse(n.right);
2296
+ const recurse = fold;
2297
+ switch (node.kind) {
2298
+ case 1 /* NumberLiteral */:
2299
+ case 8 /* StringLiteral */:
2300
+ case 9 /* BooleanLiteral */:
2301
+ case 2 /* Identifier */:
2302
+ case 15 /* Placeholder */:
2303
+ return node;
2304
+ case 0 /* Program */: {
2305
+ const optimizedStatements = node.statements.map(recurse);
2306
+ if (unchangedArray(node.statements, optimizedStatements))
2307
+ return node;
2308
+ const result = program(optimizedStatements);
2309
+ if (node.trailingComments && node.trailingComments.length > 0) {
2310
+ return { ...result, trailingComments: node.trailingComments };
2311
+ }
2312
+ return result;
2313
+ }
2314
+ case 10 /* ArrayLiteral */: {
2315
+ const elements = node.elements.map(recurse);
2316
+ if (unchangedArray(node.elements, elements))
2317
+ return node;
2318
+ return preserveComments(node, array(elements));
2319
+ }
2320
+ case 3 /* BinaryOp */: {
2321
+ const left = recurse(node.left);
2322
+ if (node.operator === "&&") {
2323
+ if (isBooleanLiteral(left) && !left.value) {
2324
+ return preserveComments(node, boolean(false));
2325
+ }
2326
+ const right2 = recurse(node.right);
2327
+ if (isBooleanLiteral(left) && isBooleanLiteral(right2)) {
2328
+ return preserveComments(node, boolean(right2.value));
2329
+ }
2330
+ if (left === node.left && right2 === node.right)
2331
+ return node;
2332
+ return preserveComments(node, binaryOp(left, node.operator, right2));
2333
+ }
2334
+ if (node.operator === "||") {
2335
+ if (isBooleanLiteral(left) && left.value) {
2336
+ return preserveComments(node, boolean(true));
2337
+ }
2338
+ const right2 = recurse(node.right);
2339
+ if (isBooleanLiteral(left) && isBooleanLiteral(right2)) {
2340
+ return preserveComments(node, boolean(right2.value));
2341
+ }
2342
+ if (left === node.left && right2 === node.right)
2343
+ return node;
2344
+ return preserveComments(node, binaryOp(left, node.operator, right2));
2345
+ }
2346
+ const right = recurse(node.right);
2194
2347
  if (isNumberLiteral(left) && isNumberLiteral(right)) {
2195
- const result = evaluateBinaryOperation(n.operator, left.value, right.value);
2348
+ const result = evaluateBinaryOperation(node.operator, left.value, right.value);
2196
2349
  if (typeof result === "number")
2197
- return preserveComments(n, number(result));
2350
+ return preserveComments(node, number(result));
2198
2351
  if (typeof result === "boolean")
2199
- return preserveComments(n, boolean(result));
2352
+ return preserveComments(node, boolean(result));
2200
2353
  }
2201
2354
  if (isStringLiteral(left) && isStringLiteral(right)) {
2202
- if (n.operator === "+")
2203
- return preserveComments(n, string(left.value + right.value));
2204
- if (n.operator === "<" || n.operator === ">" || n.operator === "<=" || n.operator === ">=") {
2205
- const result = evaluateBinaryOperation(n.operator, left.value, right.value);
2206
- return preserveComments(n, boolean(result));
2355
+ if (node.operator === "+")
2356
+ return preserveComments(node, string(left.value + right.value));
2357
+ if (node.operator === "<" || node.operator === ">" || node.operator === "<=" || node.operator === ">=") {
2358
+ const result = evaluateBinaryOperation(node.operator, left.value, right.value);
2359
+ return preserveComments(node, boolean(result));
2207
2360
  }
2208
- if (n.operator === "==")
2209
- return preserveComments(n, boolean(left.value === right.value));
2210
- if (n.operator === "!=")
2211
- return preserveComments(n, boolean(left.value !== right.value));
2361
+ if (node.operator === "==")
2362
+ return preserveComments(node, boolean(left.value === right.value));
2363
+ if (node.operator === "!=")
2364
+ return preserveComments(node, boolean(left.value !== right.value));
2212
2365
  }
2213
2366
  if (isBooleanLiteral(left) && isBooleanLiteral(right)) {
2214
- if (n.operator === "&&")
2215
- return preserveComments(n, boolean(left.value && right.value));
2216
- if (n.operator === "||")
2217
- return preserveComments(n, boolean(left.value || right.value));
2218
- if (n.operator === "==")
2219
- return preserveComments(n, boolean(left.value === right.value));
2220
- if (n.operator === "!=")
2221
- return preserveComments(n, boolean(left.value !== right.value));
2367
+ if (node.operator === "==")
2368
+ return preserveComments(node, boolean(left.value === right.value));
2369
+ if (node.operator === "!=")
2370
+ return preserveComments(node, boolean(left.value !== right.value));
2222
2371
  }
2223
2372
  if (isLiteral(left) && isLiteral(right)) {
2224
2373
  if (left.kind !== right.kind) {
2225
- if (n.operator === "==")
2226
- return preserveComments(n, boolean(false));
2227
- if (n.operator === "!=")
2228
- return preserveComments(n, boolean(true));
2374
+ if (node.operator === "==")
2375
+ return preserveComments(node, boolean(false));
2376
+ if (node.operator === "!=")
2377
+ return preserveComments(node, boolean(true));
2229
2378
  }
2230
2379
  }
2231
- return preserveComments(n, binaryOp(left, n.operator, right));
2232
- },
2233
- UnaryOp: (n, recurse) => {
2234
- const argument = recurse(n.argument);
2235
- if (n.operator === "-" && isNumberLiteral(argument)) {
2236
- return preserveComments(n, number(-argument.value));
2380
+ if (left === node.left && right === node.right)
2381
+ return node;
2382
+ return preserveComments(node, binaryOp(left, node.operator, right));
2383
+ }
2384
+ case 4 /* UnaryOp */: {
2385
+ const argument = recurse(node.argument);
2386
+ if (node.operator === "-" && isNumberLiteral(argument)) {
2387
+ return preserveComments(node, number(-argument.value));
2237
2388
  }
2238
- if (n.operator === "!" && isBooleanLiteral(argument)) {
2239
- return preserveComments(n, boolean(!argument.value));
2389
+ if (node.operator === "!" && isBooleanLiteral(argument)) {
2390
+ return preserveComments(node, boolean(!argument.value));
2240
2391
  }
2241
- return preserveComments(n, unaryOp(n.operator, argument));
2242
- },
2243
- FunctionCall: (n, recurse) => {
2244
- const optimizedArgs = n.args.map(recurse);
2245
- return preserveComments(n, functionCall(n.name, optimizedArgs));
2246
- },
2247
- Assignment: (n, recurse) => {
2248
- return preserveComments(n, assign(n.name, recurse(n.value)));
2249
- },
2250
- IfExpression: (n, recurse) => {
2251
- const condition = recurse(n.condition);
2392
+ if (argument === node.argument)
2393
+ return node;
2394
+ return preserveComments(node, unaryOp(node.operator, argument));
2395
+ }
2396
+ case 5 /* FunctionCall */: {
2397
+ const optimizedArgs = node.args.map(recurse);
2398
+ if (unchangedArray(node.args, optimizedArgs))
2399
+ return node;
2400
+ return preserveComments(node, functionCall(node.name, optimizedArgs));
2401
+ }
2402
+ case 6 /* Assignment */: {
2403
+ const value = recurse(node.value);
2404
+ if (value === node.value)
2405
+ return node;
2406
+ return preserveComments(node, assign(node.name, value));
2407
+ }
2408
+ case 7 /* IfExpression */: {
2409
+ const condition = recurse(node.condition);
2252
2410
  if (isBooleanLiteral(condition)) {
2253
- const result = condition.value ? recurse(n.consequent) : recurse(n.alternate);
2254
- return preserveComments(n, result);
2411
+ const result = condition.value ? recurse(node.consequent) : recurse(node.alternate);
2412
+ return preserveComments(node, result);
2255
2413
  }
2256
- const consequent = recurse(n.consequent);
2257
- const alternate = recurse(n.alternate);
2258
- return preserveComments(n, ifExpr(condition, consequent, alternate));
2259
- },
2260
- ForExpression: (n, recurse) => {
2261
- const iterable = recurse(n.iterable);
2262
- const guard = n.guard ? recurse(n.guard) : null;
2263
- const accumulator = n.accumulator ? { name: n.accumulator.name, initial: recurse(n.accumulator.initial) } : null;
2264
- const body = recurse(n.body);
2265
- return preserveComments(n, forExpr(n.variable, iterable, guard, accumulator, body));
2266
- },
2267
- IndexAccess: (n, recurse) => {
2268
- const object = recurse(n.object);
2269
- const index = recurse(n.index);
2414
+ const consequent = recurse(node.consequent);
2415
+ const alternate = recurse(node.alternate);
2416
+ if (condition === node.condition && consequent === node.consequent && alternate === node.alternate)
2417
+ return node;
2418
+ return preserveComments(node, ifExpr(condition, consequent, alternate));
2419
+ }
2420
+ case 11 /* ForExpression */: {
2421
+ const iterable = recurse(node.iterable);
2422
+ const guard = node.guard ? recurse(node.guard) : null;
2423
+ const initial = node.accumulator ? recurse(node.accumulator.initial) : null;
2424
+ const body = recurse(node.body);
2425
+ if (iterable === node.iterable && guard === node.guard && (node.accumulator === null || initial === node.accumulator.initial) && body === node.body)
2426
+ return node;
2427
+ const accumulator = node.accumulator ? { name: node.accumulator.name, initial } : null;
2428
+ return preserveComments(node, forExpr(node.variable, iterable, guard, accumulator, body));
2429
+ }
2430
+ case 12 /* IndexAccess */: {
2431
+ const object = recurse(node.object);
2432
+ const index = recurse(node.index);
2270
2433
  if (isArrayLiteral(object) && isNumberLiteral(index)) {
2271
2434
  const idx = index.value;
2272
2435
  if (Number.isInteger(idx)) {
2273
2436
  const len = object.elements.length;
2274
2437
  const resolved = idx < 0 ? len + idx : idx;
2275
2438
  if (resolved >= 0 && resolved < len) {
2276
- return preserveComments(n, object.elements[resolved]);
2439
+ return preserveComments(node, object.elements[resolved]);
2277
2440
  }
2278
2441
  }
2279
2442
  }
2280
2443
  if (isStringLiteral(object) && isNumberLiteral(index)) {
2281
2444
  try {
2282
2445
  const char = resolveIndex(object.value, index.value);
2283
- return preserveComments(n, string(char));
2446
+ return preserveComments(node, string(char));
2284
2447
  } catch {}
2285
2448
  }
2286
- return preserveComments(n, indexAccess(object, index));
2287
- },
2288
- RangeExpression: (n, recurse) => {
2289
- const start = recurse(n.start);
2290
- const end = recurse(n.end);
2449
+ if (object === node.object && index === node.index)
2450
+ return node;
2451
+ return preserveComments(node, indexAccess(object, index));
2452
+ }
2453
+ case 13 /* RangeExpression */: {
2454
+ const start = recurse(node.start);
2455
+ const end = recurse(node.end);
2291
2456
  if (isNumberLiteral(start) && isNumberLiteral(end)) {
2292
2457
  try {
2293
- const limit = n.inclusive ? end.value + 1 : end.value;
2458
+ const limit = node.inclusive ? end.value + 1 : end.value;
2294
2459
  const count = limit - start.value;
2295
2460
  if (count >= 0 && count <= 1e4) {
2296
- const values = buildRange(start.value, end.value, n.inclusive);
2297
- return preserveComments(n, array(values.map(number)));
2461
+ const values = buildRange(start.value, end.value, node.inclusive);
2462
+ return preserveComments(node, array(values.map(number)));
2298
2463
  }
2299
2464
  } catch {}
2300
2465
  }
2301
- return preserveComments(n, rangeExpr(start, end, n.inclusive));
2302
- },
2303
- PipeExpression: (n, recurse) => {
2304
- const value = recurse(n.value);
2305
- const optimizedArgs = n.args.map(recurse);
2306
- return preserveComments(n, pipeExpr(value, n.name, optimizedArgs));
2307
- },
2308
- Placeholder: (n) => n,
2309
- Program: (n, recurse) => {
2310
- const optimizedStatements = n.statements.map(recurse);
2311
- const result = program(optimizedStatements);
2312
- if (n.trailingComments && n.trailingComments.length > 0) {
2313
- return { ...result, trailingComments: n.trailingComments };
2314
- }
2315
- return result;
2466
+ if (start === node.start && end === node.end)
2467
+ return node;
2468
+ return preserveComments(node, rangeExpr(start, end, node.inclusive));
2316
2469
  }
2317
- });
2470
+ case 14 /* PipeExpression */: {
2471
+ const value = recurse(node.value);
2472
+ const optimizedArgs = node.args.map(recurse);
2473
+ if (value === node.value && unchangedArray(node.args, optimizedArgs))
2474
+ return node;
2475
+ return preserveComments(node, pipeExpr(value, node.name, optimizedArgs));
2476
+ }
2477
+ }
2318
2478
  }
2319
2479
  // src/stdlib/array.ts
2320
2480
  var exports_array = {};
@@ -2330,7 +2490,7 @@ __export(exports_array, {
2330
2490
  var ARR_SORT = (a) => {
2331
2491
  assertArray(a, "ARR_SORT");
2332
2492
  if (a.length <= 1)
2333
- return a;
2493
+ return [...a];
2334
2494
  const sorted = [...a];
2335
2495
  const elemType = typeOf(sorted[0]);
2336
2496
  sorted.sort((x, y) => {
@@ -2499,8 +2659,63 @@ function assertStringOrArray(v, context) {
2499
2659
  throw new TypeError(`${context} expected string or array, got ${typeOf(v)}`);
2500
2660
  }
2501
2661
  }
2662
+ function hasSurrogateCodeUnit(value) {
2663
+ for (let i = 0;i < value.length; i++) {
2664
+ const code = value.charCodeAt(i);
2665
+ if (code >= 55296 && code <= 57343)
2666
+ return true;
2667
+ }
2668
+ return false;
2669
+ }
2670
+ function codePointLength(value) {
2671
+ let length = 0;
2672
+ for (let i = 0;i < value.length; i++) {
2673
+ const code = value.charCodeAt(i);
2674
+ if (code >= 55296 && code <= 56319 && i + 1 < value.length) {
2675
+ const next = value.charCodeAt(i + 1);
2676
+ if (next >= 56320 && next <= 57343)
2677
+ i++;
2678
+ }
2679
+ length++;
2680
+ }
2681
+ return length;
2682
+ }
2683
+ function stringLength(value) {
2684
+ return hasSurrogateCodeUnit(value) ? codePointLength(value) : value.length;
2685
+ }
2686
+ function sliceString(value, start, end) {
2687
+ if (!hasSurrogateCodeUnit(value))
2688
+ return value.slice(start, end);
2689
+ return Array.from(value).slice(start, end).join("");
2690
+ }
2691
+ function indexOfString(value, search) {
2692
+ if (search === "")
2693
+ return 0;
2694
+ if (!hasSurrogateCodeUnit(value) && !hasSurrogateCodeUnit(search)) {
2695
+ return value.indexOf(search);
2696
+ }
2697
+ const haystack = Array.from(value);
2698
+ const needle = Array.from(search);
2699
+ if (needle.length > haystack.length)
2700
+ return -1;
2701
+ const limit = haystack.length - needle.length;
2702
+ for (let i = 0;i <= limit; i++) {
2703
+ let found = true;
2704
+ for (let j = 0;j < needle.length; j++) {
2705
+ if (haystack[i + j] !== needle[j]) {
2706
+ found = false;
2707
+ break;
2708
+ }
2709
+ }
2710
+ if (found)
2711
+ return i;
2712
+ }
2713
+ return -1;
2714
+ }
2502
2715
  var LEN = (v) => {
2503
2716
  assertStringOrArray(v, "LEN");
2717
+ if (typeof v === "string")
2718
+ return stringLength(v);
2504
2719
  return v.length;
2505
2720
  };
2506
2721
  var SLICE = (v, start, end) => {
@@ -2508,8 +2723,12 @@ var SLICE = (v, start, end) => {
2508
2723
  assertNumber(start, "SLICE", "start");
2509
2724
  if (end !== undefined) {
2510
2725
  assertNumber(end, "SLICE", "end");
2726
+ if (typeof v === "string")
2727
+ return sliceString(v, start, end);
2511
2728
  return v.slice(start, end);
2512
2729
  }
2730
+ if (typeof v === "string")
2731
+ return sliceString(v, start);
2513
2732
  return v.slice(start);
2514
2733
  };
2515
2734
  var CONTAINS = (v, search) => {
@@ -2535,7 +2754,7 @@ var INDEX_OF = (v, search) => {
2535
2754
  assertStringOrArray(v, "INDEX_OF");
2536
2755
  if (typeof v === "string") {
2537
2756
  assertString(search, "INDEX_OF (search)");
2538
- return v.indexOf(search);
2757
+ return indexOfString(v, search);
2539
2758
  }
2540
2759
  for (let i = 0;i < v.length; i++) {
2541
2760
  if (deepEquals(v[i], search))
@@ -2575,9 +2794,9 @@ __export(exports_datetime, {
2575
2794
  });
2576
2795
  var TODAY = () => Temporal.Now.plainDateISO();
2577
2796
  var DATE = (year, month, day) => {
2578
- assertNumber(year, "DATE", "year");
2579
- assertNumber(month, "DATE", "month");
2580
- assertNumber(day, "DATE", "day");
2797
+ assertInteger(year, "DATE", "year");
2798
+ assertInteger(month, "DATE", "month");
2799
+ assertInteger(day, "DATE", "day");
2581
2800
  return new Temporal.PlainDate(year, month, day);
2582
2801
  };
2583
2802
  var YEAR = (date) => {
@@ -2745,12 +2964,12 @@ __export(exports_datetimefull, {
2745
2964
  COMBINE: () => COMBINE
2746
2965
  });
2747
2966
  var DATETIME = (year, month, day, hour, minute, second) => {
2748
- assertNumber(year, "DATETIME", "year");
2749
- assertNumber(month, "DATETIME", "month");
2750
- assertNumber(day, "DATETIME", "day");
2751
- assertNumber(hour, "DATETIME", "hour");
2752
- assertNumber(minute, "DATETIME", "minute");
2753
- assertNumber(second, "DATETIME", "second");
2967
+ assertInteger(year, "DATETIME", "year");
2968
+ assertInteger(month, "DATETIME", "month");
2969
+ assertInteger(day, "DATETIME", "day");
2970
+ assertInteger(hour, "DATETIME", "hour");
2971
+ assertInteger(minute, "DATETIME", "minute");
2972
+ assertInteger(second, "DATETIME", "second");
2754
2973
  return new Temporal.PlainDateTime(year, month, day, hour, minute, second);
2755
2974
  };
2756
2975
  var NOW = () => Temporal.Now.plainDateTimeISO();
@@ -2829,12 +3048,18 @@ var SQRT = (x) => {
2829
3048
  return Math.sqrt(x);
2830
3049
  };
2831
3050
  var MIN = (...values) => {
3051
+ if (values.length === 0) {
3052
+ throw new RangeError("MIN requires at least one argument");
3053
+ }
2832
3054
  for (const value of values) {
2833
3055
  assertNumber(value, "MIN");
2834
3056
  }
2835
3057
  return Math.min(...values);
2836
3058
  };
2837
3059
  var MAX = (...values) => {
3060
+ if (values.length === 0) {
3061
+ throw new RangeError("MAX requires at least one argument");
3062
+ }
2838
3063
  for (const value of values) {
2839
3064
  assertNumber(value, "MAX");
2840
3065
  }
@@ -2868,6 +3093,9 @@ var CLAMP = (value, min, max) => {
2868
3093
  assertNumber(value, "CLAMP", "value");
2869
3094
  assertNumber(min, "CLAMP", "min");
2870
3095
  assertNumber(max, "CLAMP", "max");
3096
+ if (min > max) {
3097
+ throw new RangeError(`CLAMP: min (${min}) must not exceed max (${max})`);
3098
+ }
2871
3099
  return value < min ? min : value > max ? max : value;
2872
3100
  };
2873
3101
 
@@ -2943,9 +3171,9 @@ __export(exports_time, {
2943
3171
  ADD_HOURS: () => ADD_HOURS
2944
3172
  });
2945
3173
  var TIME = (hour, minute, second) => {
2946
- assertNumber(hour, "TIME", "hour");
2947
- assertNumber(minute, "TIME", "minute");
2948
- assertNumber(second, "TIME", "second");
3174
+ assertInteger(hour, "TIME", "hour");
3175
+ assertInteger(minute, "TIME", "minute");
3176
+ assertInteger(second, "TIME", "second");
2949
3177
  return new Temporal.PlainTime(hour, minute, second);
2950
3178
  };
2951
3179
  var NOW_TIME = () => Temporal.Now.plainTimeISO();
@@ -3045,7 +3273,6 @@ var defaultContext = {
3045
3273
  }
3046
3274
  };
3047
3275
  export {
3048
- visitPartial,
3049
3276
  visit,
3050
3277
  typeOf,
3051
3278
  toLineColumn,
@@ -3073,6 +3300,7 @@ export {
3073
3300
  generate,
3074
3301
  extractInputVariables,
3075
3302
  extractAssignedVariables,
3303
+ evaluateWithScope,
3076
3304
  evaluateScope,
3077
3305
  evaluate,
3078
3306
  defaultContext,