littlewing 2.1.1 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -66
- package/dist/index.d.ts +95 -123
- package/dist/index.js +1030 -870
- package/package.json +7 -7
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
|
|
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
|
|
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,78 +338,139 @@ function extractInputVariables(ast) {
|
|
|
341
338
|
function extractAssignedVariables(ast) {
|
|
342
339
|
const seen = new Set;
|
|
343
340
|
const names = [];
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
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
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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
|
-
|
|
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
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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(
|
|
403
|
-
if (
|
|
404
|
-
innerBound.add(
|
|
405
|
-
return recurse(
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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);
|
|
415
448
|
}
|
|
449
|
+
// src/errors.ts
|
|
450
|
+
class ParseError extends Error {
|
|
451
|
+
start;
|
|
452
|
+
end;
|
|
453
|
+
name = "ParseError";
|
|
454
|
+
constructor(message, start, end) {
|
|
455
|
+
super(message);
|
|
456
|
+
this.start = start;
|
|
457
|
+
this.end = end;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
function toLineColumn(source, offset) {
|
|
461
|
+
let line = 1;
|
|
462
|
+
let column = 1;
|
|
463
|
+
const clamped = Math.min(offset, source.length);
|
|
464
|
+
for (let i = 0;i < clamped; i++) {
|
|
465
|
+
if (source.charCodeAt(i) === 10) {
|
|
466
|
+
line++;
|
|
467
|
+
column = 1;
|
|
468
|
+
} else {
|
|
469
|
+
column++;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return { line, column };
|
|
473
|
+
}
|
|
416
474
|
// src/lexer.ts
|
|
417
475
|
var KEYWORDS = new Map([
|
|
418
476
|
["if", 28 /* If */],
|
|
@@ -594,7 +652,7 @@ function nextToken(cursor) {
|
|
|
594
652
|
}
|
|
595
653
|
return [18 /* DotDot */, start, cursor.pos];
|
|
596
654
|
}
|
|
597
|
-
throw new
|
|
655
|
+
throw new ParseError(`Unexpected character '${String.fromCharCode(ch)}'`, start, cursor.pos);
|
|
598
656
|
case 44:
|
|
599
657
|
advance(cursor);
|
|
600
658
|
return [25 /* Comma */, start, cursor.pos];
|
|
@@ -607,7 +665,7 @@ function nextToken(cursor) {
|
|
|
607
665
|
advance(cursor);
|
|
608
666
|
return [16 /* And */, start, cursor.pos];
|
|
609
667
|
}
|
|
610
|
-
throw new
|
|
668
|
+
throw new ParseError(`Unexpected character '${String.fromCharCode(ch)}'`, start, cursor.pos);
|
|
611
669
|
case 124:
|
|
612
670
|
advance(cursor);
|
|
613
671
|
if (peek(cursor) === 124) {
|
|
@@ -618,12 +676,13 @@ function nextToken(cursor) {
|
|
|
618
676
|
advance(cursor);
|
|
619
677
|
return [26 /* Pipe */, start, cursor.pos];
|
|
620
678
|
}
|
|
621
|
-
throw new
|
|
679
|
+
throw new ParseError(`Unexpected character '${String.fromCharCode(ch)}'`, start, cursor.pos);
|
|
622
680
|
case 63:
|
|
623
681
|
advance(cursor);
|
|
624
682
|
return [27 /* Question */, start, cursor.pos];
|
|
625
683
|
default:
|
|
626
|
-
|
|
684
|
+
advance(cursor);
|
|
685
|
+
throw new ParseError(`Unexpected character '${String.fromCharCode(ch)}'`, start, cursor.pos);
|
|
627
686
|
}
|
|
628
687
|
}
|
|
629
688
|
function lexString(cursor) {
|
|
@@ -640,7 +699,7 @@ function lexString(cursor) {
|
|
|
640
699
|
cursor.pos++;
|
|
641
700
|
}
|
|
642
701
|
}
|
|
643
|
-
throw new
|
|
702
|
+
throw new ParseError("Unterminated string", start, cursor.pos);
|
|
644
703
|
}
|
|
645
704
|
function lexNumber(cursor) {
|
|
646
705
|
const start = cursor.pos;
|
|
@@ -789,7 +848,17 @@ function concatenateArrays(a, b) {
|
|
|
789
848
|
function validateHomogeneousArray(elements) {
|
|
790
849
|
if (elements.length <= 1)
|
|
791
850
|
return;
|
|
792
|
-
const
|
|
851
|
+
const first = elements[0];
|
|
852
|
+
const firstPrimitive = typeof first;
|
|
853
|
+
if (firstPrimitive === "number" || firstPrimitive === "string" || firstPrimitive === "boolean") {
|
|
854
|
+
for (let i = 1;i < elements.length; i++) {
|
|
855
|
+
if (typeof elements[i] !== firstPrimitive) {
|
|
856
|
+
throw new TypeError(`Heterogeneous array: expected ${firstPrimitive}, got ${typeOf(elements[i])} at index ${i}`);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
const firstType = typeOf(first);
|
|
793
862
|
for (let i = 1;i < elements.length; i++) {
|
|
794
863
|
const elemType = typeOf(elements[i]);
|
|
795
864
|
if (elemType !== firstType) {
|
|
@@ -893,13 +962,29 @@ function resolveIndex(target, index) {
|
|
|
893
962
|
throw new TypeError(`Index must be an integer, got ${index}`);
|
|
894
963
|
}
|
|
895
964
|
if (typeof target === "string") {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
965
|
+
if (index >= 0) {
|
|
966
|
+
let i2 = 0;
|
|
967
|
+
for (const cp of target) {
|
|
968
|
+
if (i2 === index)
|
|
969
|
+
return cp;
|
|
970
|
+
i2++;
|
|
971
|
+
}
|
|
972
|
+
throw new RangeError(`Index ${index} out of bounds for length ${i2}`);
|
|
973
|
+
}
|
|
974
|
+
let len2 = 0;
|
|
975
|
+
for (const _ of target)
|
|
976
|
+
len2++;
|
|
977
|
+
const resolved2 = len2 + index;
|
|
978
|
+
if (resolved2 < 0) {
|
|
900
979
|
throw new RangeError(`Index ${index} out of bounds for length ${len2}`);
|
|
901
980
|
}
|
|
902
|
-
|
|
981
|
+
let i = 0;
|
|
982
|
+
for (const cp of target) {
|
|
983
|
+
if (i === resolved2)
|
|
984
|
+
return cp;
|
|
985
|
+
i++;
|
|
986
|
+
}
|
|
987
|
+
throw new RangeError(`Index ${index} out of bounds for length ${len2}`);
|
|
903
988
|
}
|
|
904
989
|
const len = target.length;
|
|
905
990
|
const resolved = index < 0 ? len + index : index;
|
|
@@ -919,11 +1004,7 @@ function buildRange(start, end, inclusive) {
|
|
|
919
1004
|
throw new RangeError(`Range start (${start}) must not exceed end (${end})`);
|
|
920
1005
|
}
|
|
921
1006
|
const limit = inclusive ? end + 1 : end;
|
|
922
|
-
|
|
923
|
-
for (let i = start;i < limit; i++) {
|
|
924
|
-
result.push(i);
|
|
925
|
-
}
|
|
926
|
-
return result;
|
|
1007
|
+
return Array.from({ length: limit - start }, (_, i) => start + i);
|
|
927
1008
|
}
|
|
928
1009
|
function getOperatorPrecedence(operator) {
|
|
929
1010
|
switch (operator) {
|
|
@@ -953,69 +1034,75 @@ function getOperatorPrecedence(operator) {
|
|
|
953
1034
|
}
|
|
954
1035
|
function collectAllIdentifiers(node) {
|
|
955
1036
|
const identifiers = new Set;
|
|
956
|
-
|
|
957
|
-
Program: (n, recurse) => {
|
|
958
|
-
for (const stmt of n.statements) {
|
|
959
|
-
recurse(stmt);
|
|
960
|
-
}
|
|
961
|
-
},
|
|
962
|
-
NumberLiteral: () => {},
|
|
963
|
-
StringLiteral: () => {},
|
|
964
|
-
BooleanLiteral: () => {},
|
|
965
|
-
ArrayLiteral: (n, recurse) => {
|
|
966
|
-
for (const elem of n.elements) {
|
|
967
|
-
recurse(elem);
|
|
968
|
-
}
|
|
969
|
-
},
|
|
970
|
-
Identifier: (n) => {
|
|
971
|
-
identifiers.add(n.name);
|
|
972
|
-
},
|
|
973
|
-
BinaryOp: (n, recurse) => {
|
|
974
|
-
recurse(n.left);
|
|
975
|
-
recurse(n.right);
|
|
976
|
-
},
|
|
977
|
-
UnaryOp: (n, recurse) => {
|
|
978
|
-
recurse(n.argument);
|
|
979
|
-
},
|
|
980
|
-
FunctionCall: (n, recurse) => {
|
|
981
|
-
for (const arg of n.args) {
|
|
982
|
-
recurse(arg);
|
|
983
|
-
}
|
|
984
|
-
},
|
|
985
|
-
Assignment: (n, recurse) => {
|
|
986
|
-
recurse(n.value);
|
|
987
|
-
},
|
|
988
|
-
IfExpression: (n, recurse) => {
|
|
989
|
-
recurse(n.condition);
|
|
990
|
-
recurse(n.consequent);
|
|
991
|
-
recurse(n.alternate);
|
|
992
|
-
},
|
|
993
|
-
ForExpression: (n, recurse) => {
|
|
994
|
-
recurse(n.iterable);
|
|
995
|
-
if (n.guard)
|
|
996
|
-
recurse(n.guard);
|
|
997
|
-
if (n.accumulator)
|
|
998
|
-
recurse(n.accumulator.initial);
|
|
999
|
-
recurse(n.body);
|
|
1000
|
-
},
|
|
1001
|
-
IndexAccess: (n, recurse) => {
|
|
1002
|
-
recurse(n.object);
|
|
1003
|
-
recurse(n.index);
|
|
1004
|
-
},
|
|
1005
|
-
RangeExpression: (n, recurse) => {
|
|
1006
|
-
recurse(n.start);
|
|
1007
|
-
recurse(n.end);
|
|
1008
|
-
},
|
|
1009
|
-
PipeExpression: (n, recurse) => {
|
|
1010
|
-
recurse(n.value);
|
|
1011
|
-
for (const arg of n.args) {
|
|
1012
|
-
recurse(arg);
|
|
1013
|
-
}
|
|
1014
|
-
},
|
|
1015
|
-
Placeholder: () => {}
|
|
1016
|
-
});
|
|
1037
|
+
collectIdentifiers(node, identifiers, new Set);
|
|
1017
1038
|
return identifiers;
|
|
1018
1039
|
}
|
|
1040
|
+
function collectIdentifiers(node, ids, boundVars) {
|
|
1041
|
+
switch (node.kind) {
|
|
1042
|
+
case 0 /* Program */:
|
|
1043
|
+
for (const s of node.statements)
|
|
1044
|
+
collectIdentifiers(s, ids, boundVars);
|
|
1045
|
+
break;
|
|
1046
|
+
case 2 /* Identifier */:
|
|
1047
|
+
if (!boundVars.has(node.name))
|
|
1048
|
+
ids.add(node.name);
|
|
1049
|
+
break;
|
|
1050
|
+
case 10 /* ArrayLiteral */:
|
|
1051
|
+
for (const e of node.elements)
|
|
1052
|
+
collectIdentifiers(e, ids, boundVars);
|
|
1053
|
+
break;
|
|
1054
|
+
case 3 /* BinaryOp */:
|
|
1055
|
+
collectIdentifiers(node.left, ids, boundVars);
|
|
1056
|
+
collectIdentifiers(node.right, ids, boundVars);
|
|
1057
|
+
break;
|
|
1058
|
+
case 4 /* UnaryOp */:
|
|
1059
|
+
collectIdentifiers(node.argument, ids, boundVars);
|
|
1060
|
+
break;
|
|
1061
|
+
case 5 /* FunctionCall */:
|
|
1062
|
+
for (const a of node.args)
|
|
1063
|
+
collectIdentifiers(a, ids, boundVars);
|
|
1064
|
+
break;
|
|
1065
|
+
case 6 /* Assignment */:
|
|
1066
|
+
collectIdentifiers(node.value, ids, boundVars);
|
|
1067
|
+
break;
|
|
1068
|
+
case 7 /* IfExpression */:
|
|
1069
|
+
collectIdentifiers(node.condition, ids, boundVars);
|
|
1070
|
+
collectIdentifiers(node.consequent, ids, boundVars);
|
|
1071
|
+
collectIdentifiers(node.alternate, ids, boundVars);
|
|
1072
|
+
break;
|
|
1073
|
+
case 11 /* ForExpression */: {
|
|
1074
|
+
collectIdentifiers(node.iterable, ids, boundVars);
|
|
1075
|
+
if (node.accumulator)
|
|
1076
|
+
collectIdentifiers(node.accumulator.initial, ids, boundVars);
|
|
1077
|
+
const innerBound = new Set(boundVars);
|
|
1078
|
+
innerBound.add(node.variable);
|
|
1079
|
+
if (node.accumulator)
|
|
1080
|
+
innerBound.add(node.accumulator.name);
|
|
1081
|
+
if (node.guard)
|
|
1082
|
+
collectIdentifiers(node.guard, ids, innerBound);
|
|
1083
|
+
collectIdentifiers(node.body, ids, innerBound);
|
|
1084
|
+
break;
|
|
1085
|
+
}
|
|
1086
|
+
case 12 /* IndexAccess */:
|
|
1087
|
+
collectIdentifiers(node.object, ids, boundVars);
|
|
1088
|
+
collectIdentifiers(node.index, ids, boundVars);
|
|
1089
|
+
break;
|
|
1090
|
+
case 13 /* RangeExpression */:
|
|
1091
|
+
collectIdentifiers(node.start, ids, boundVars);
|
|
1092
|
+
collectIdentifiers(node.end, ids, boundVars);
|
|
1093
|
+
break;
|
|
1094
|
+
case 14 /* PipeExpression */:
|
|
1095
|
+
collectIdentifiers(node.value, ids, boundVars);
|
|
1096
|
+
for (const a of node.args)
|
|
1097
|
+
collectIdentifiers(a, ids, boundVars);
|
|
1098
|
+
break;
|
|
1099
|
+
case 1 /* NumberLiteral */:
|
|
1100
|
+
case 8 /* StringLiteral */:
|
|
1101
|
+
case 9 /* BooleanLiteral */:
|
|
1102
|
+
case 15 /* Placeholder */:
|
|
1103
|
+
break;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1019
1106
|
function getTokenPrecedence(kind) {
|
|
1020
1107
|
switch (kind) {
|
|
1021
1108
|
case 24 /* Eq */:
|
|
@@ -1113,90 +1200,88 @@ function generate(node) {
|
|
|
1113
1200
|
return code;
|
|
1114
1201
|
}
|
|
1115
1202
|
function generateNode(node) {
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
return
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
return
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
const
|
|
1135
|
-
const right = recurse(n.right);
|
|
1136
|
-
const opPrec = getOperatorPrecedence(n.operator);
|
|
1137
|
-
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;
|
|
1203
|
+
const recurse = generateNode;
|
|
1204
|
+
switch (node.kind) {
|
|
1205
|
+
case 0 /* Program */:
|
|
1206
|
+
return generateProgram(node, recurse);
|
|
1207
|
+
case 1 /* NumberLiteral */:
|
|
1208
|
+
return String(node.value);
|
|
1209
|
+
case 8 /* StringLiteral */:
|
|
1210
|
+
return `"${escapeString(node.value)}"`;
|
|
1211
|
+
case 9 /* BooleanLiteral */:
|
|
1212
|
+
return node.value ? "true" : "false";
|
|
1213
|
+
case 10 /* ArrayLiteral */:
|
|
1214
|
+
return `[${node.elements.map(recurse).join(", ")}]`;
|
|
1215
|
+
case 2 /* Identifier */:
|
|
1216
|
+
return node.name;
|
|
1217
|
+
case 3 /* BinaryOp */: {
|
|
1218
|
+
const left = recurse(node.left);
|
|
1219
|
+
const right = recurse(node.right);
|
|
1220
|
+
const opPrec = getOperatorPrecedence(node.operator);
|
|
1221
|
+
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;
|
|
1138
1222
|
const leftCode = leftNeedsParens ? `(${left})` : left;
|
|
1139
|
-
const rightNeedsParens = needsParens(
|
|
1223
|
+
const rightNeedsParens = needsParens(node.right, node.operator, false) || isPipeExpression(node.right) || isAssignment(node.right) || isRangeExpression(node.right) && opPrec >= 6;
|
|
1140
1224
|
const rightCode = rightNeedsParens ? `(${right})` : right;
|
|
1141
|
-
return `${leftCode} ${
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
const arg = recurse(
|
|
1145
|
-
const parensNeeded = isBinaryOp(
|
|
1225
|
+
return `${leftCode} ${node.operator} ${rightCode}`;
|
|
1226
|
+
}
|
|
1227
|
+
case 4 /* UnaryOp */: {
|
|
1228
|
+
const arg = recurse(node.argument);
|
|
1229
|
+
const parensNeeded = isBinaryOp(node.argument) || isAssignment(node.argument) || isPipeExpression(node.argument) || isRangeExpression(node.argument);
|
|
1146
1230
|
const argCode = parensNeeded ? `(${arg})` : arg;
|
|
1147
|
-
return `${
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
|
-
const argsCode =
|
|
1151
|
-
return `${
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
const value = recurse(
|
|
1155
|
-
return `${
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
const condition = recurse(
|
|
1159
|
-
const consequent = recurse(
|
|
1160
|
-
const alternate = recurse(
|
|
1231
|
+
return `${node.operator}${argCode}`;
|
|
1232
|
+
}
|
|
1233
|
+
case 5 /* FunctionCall */: {
|
|
1234
|
+
const argsCode = node.args.map(recurse).join(", ");
|
|
1235
|
+
return `${node.name}(${argsCode})`;
|
|
1236
|
+
}
|
|
1237
|
+
case 6 /* Assignment */: {
|
|
1238
|
+
const value = recurse(node.value);
|
|
1239
|
+
return `${node.name} = ${value}`;
|
|
1240
|
+
}
|
|
1241
|
+
case 7 /* IfExpression */: {
|
|
1242
|
+
const condition = recurse(node.condition);
|
|
1243
|
+
const consequent = recurse(node.consequent);
|
|
1244
|
+
const alternate = recurse(node.alternate);
|
|
1161
1245
|
return `if ${condition} then ${consequent} else ${alternate}`;
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
const parts = [`for ${
|
|
1165
|
-
if (
|
|
1166
|
-
parts.push(`when ${recurse(
|
|
1246
|
+
}
|
|
1247
|
+
case 11 /* ForExpression */: {
|
|
1248
|
+
const parts = [`for ${node.variable} in ${recurse(node.iterable)}`];
|
|
1249
|
+
if (node.guard) {
|
|
1250
|
+
parts.push(`when ${recurse(node.guard)}`);
|
|
1167
1251
|
}
|
|
1168
|
-
if (
|
|
1169
|
-
parts.push(`into ${
|
|
1252
|
+
if (node.accumulator) {
|
|
1253
|
+
parts.push(`into ${node.accumulator.name} = ${recurse(node.accumulator.initial)}`);
|
|
1170
1254
|
}
|
|
1171
|
-
parts.push(`then ${recurse(
|
|
1255
|
+
parts.push(`then ${recurse(node.body)}`);
|
|
1172
1256
|
return parts.join(" ");
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
const object = recurse(
|
|
1176
|
-
const index = recurse(
|
|
1177
|
-
const
|
|
1178
|
-
const objectCode =
|
|
1257
|
+
}
|
|
1258
|
+
case 12 /* IndexAccess */: {
|
|
1259
|
+
const object = recurse(node.object);
|
|
1260
|
+
const index = recurse(node.index);
|
|
1261
|
+
const objNeedsParens = isBinaryOp(node.object) || isUnaryOp(node.object) || isAssignment(node.object) || isRangeExpression(node.object) || isPipeExpression(node.object);
|
|
1262
|
+
const objectCode = objNeedsParens ? `(${object})` : object;
|
|
1179
1263
|
return `${objectCode}[${index}]`;
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
const start = recurse(
|
|
1183
|
-
const end = recurse(
|
|
1184
|
-
const op =
|
|
1185
|
-
const startNeedsParens = isBinaryOp(
|
|
1186
|
-
const endNeedsParens = isBinaryOp(
|
|
1264
|
+
}
|
|
1265
|
+
case 13 /* RangeExpression */: {
|
|
1266
|
+
const start = recurse(node.start);
|
|
1267
|
+
const end = recurse(node.end);
|
|
1268
|
+
const op = node.inclusive ? "..=" : "..";
|
|
1269
|
+
const startNeedsParens = isBinaryOp(node.start) || isRangeExpression(node.start) || isIfExpression(node.start) || isForExpression(node.start) || isAssignment(node.start);
|
|
1270
|
+
const endNeedsParens = isBinaryOp(node.end) || isRangeExpression(node.end) || isPipeExpression(node.end) || isAssignment(node.end);
|
|
1187
1271
|
const startCode = startNeedsParens ? `(${start})` : start;
|
|
1188
1272
|
const endCode = endNeedsParens ? `(${end})` : end;
|
|
1189
1273
|
return `${startCode}${op}${endCode}`;
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
const value = recurse(
|
|
1193
|
-
const argsCode =
|
|
1194
|
-
const valueNeedsParens = isAssignment(
|
|
1274
|
+
}
|
|
1275
|
+
case 14 /* PipeExpression */: {
|
|
1276
|
+
const value = recurse(node.value);
|
|
1277
|
+
const argsCode = node.args.map(recurse).join(", ");
|
|
1278
|
+
const valueNeedsParens = isAssignment(node.value) || isIfExpression(node.value) || isForExpression(node.value);
|
|
1195
1279
|
const valueCode = valueNeedsParens ? `(${value})` : value;
|
|
1196
|
-
return `${valueCode} |> ${
|
|
1197
|
-
}
|
|
1198
|
-
|
|
1199
|
-
|
|
1280
|
+
return `${valueCode} |> ${node.name}(${argsCode})`;
|
|
1281
|
+
}
|
|
1282
|
+
case 15 /* Placeholder */:
|
|
1283
|
+
return "?";
|
|
1284
|
+
}
|
|
1200
1285
|
}
|
|
1201
1286
|
// src/parser.ts
|
|
1202
1287
|
var BINARY_OPERATOR_TOKENS = new Set([
|
|
@@ -1230,13 +1315,13 @@ function parse(source) {
|
|
|
1230
1315
|
statements.push(parseExpression(state, 0));
|
|
1231
1316
|
}
|
|
1232
1317
|
if (statements.length === 0) {
|
|
1233
|
-
throw new
|
|
1318
|
+
throw new ParseError("Empty program", 0, 0);
|
|
1234
1319
|
}
|
|
1235
1320
|
const annotated = attachComments(source, statements, statementOffsets, cursor.comments);
|
|
1236
1321
|
if (annotated.statements.length === 1 && !annotated.programTrailing) {
|
|
1237
1322
|
const stmt = annotated.statements[0];
|
|
1238
1323
|
if (stmt === undefined) {
|
|
1239
|
-
throw new
|
|
1324
|
+
throw new ParseError("Unexpected empty statements array", 0, 0);
|
|
1240
1325
|
}
|
|
1241
1326
|
return stmt;
|
|
1242
1327
|
}
|
|
@@ -1346,7 +1431,7 @@ function parseExpression(state, minPrecedence) {
|
|
|
1346
1431
|
advance2(state);
|
|
1347
1432
|
const index = parseExpression(state, 0);
|
|
1348
1433
|
if (peekKind(state) !== 23 /* RBracket */) {
|
|
1349
|
-
throw new
|
|
1434
|
+
throw new ParseError("Expected closing bracket", state.currentToken[1], state.currentToken[2]);
|
|
1350
1435
|
}
|
|
1351
1436
|
advance2(state);
|
|
1352
1437
|
left = indexAccess(left, index);
|
|
@@ -1377,7 +1462,7 @@ function parsePrefix(state) {
|
|
|
1377
1462
|
advance2(state);
|
|
1378
1463
|
const expr = parseExpression(state, 0);
|
|
1379
1464
|
if (peekKind(state) !== 21 /* RParen */) {
|
|
1380
|
-
throw new
|
|
1465
|
+
throw new ParseError("Expected closing parenthesis", state.currentToken[1], state.currentToken[2]);
|
|
1381
1466
|
}
|
|
1382
1467
|
advance2(state);
|
|
1383
1468
|
return expr;
|
|
@@ -1393,7 +1478,7 @@ function parsePrefix(state) {
|
|
|
1393
1478
|
}
|
|
1394
1479
|
}
|
|
1395
1480
|
if (peekKind(state) !== 23 /* RBracket */) {
|
|
1396
|
-
throw new
|
|
1481
|
+
throw new ParseError("Expected closing bracket", state.currentToken[1], state.currentToken[2]);
|
|
1397
1482
|
}
|
|
1398
1483
|
advance2(state);
|
|
1399
1484
|
return array(elements);
|
|
@@ -1402,12 +1487,12 @@ function parsePrefix(state) {
|
|
|
1402
1487
|
advance2(state);
|
|
1403
1488
|
const condition = parseExpression(state, 0);
|
|
1404
1489
|
if (peekKind(state) !== 29 /* Then */) {
|
|
1405
|
-
throw new
|
|
1490
|
+
throw new ParseError('Expected "then" in if expression', state.currentToken[1], state.currentToken[2]);
|
|
1406
1491
|
}
|
|
1407
1492
|
advance2(state);
|
|
1408
1493
|
const consequent = parseExpression(state, 0);
|
|
1409
1494
|
if (peekKind(state) !== 30 /* Else */) {
|
|
1410
|
-
throw new
|
|
1495
|
+
throw new ParseError('Expected "else" in if expression', state.currentToken[1], state.currentToken[2]);
|
|
1411
1496
|
}
|
|
1412
1497
|
advance2(state);
|
|
1413
1498
|
const alternate = parseExpression(state, 0);
|
|
@@ -1416,12 +1501,12 @@ function parsePrefix(state) {
|
|
|
1416
1501
|
if (tokenKind === 31 /* For */) {
|
|
1417
1502
|
advance2(state);
|
|
1418
1503
|
if (peekKind(state) !== 1 /* Identifier */) {
|
|
1419
|
-
throw new
|
|
1504
|
+
throw new ParseError('Expected identifier after "for"', state.currentToken[1], state.currentToken[2]);
|
|
1420
1505
|
}
|
|
1421
1506
|
const variableName = readText(state.cursor, state.currentToken);
|
|
1422
1507
|
advance2(state);
|
|
1423
1508
|
if (peekKind(state) !== 32 /* In */) {
|
|
1424
|
-
throw new
|
|
1509
|
+
throw new ParseError('Expected "in" in for expression', state.currentToken[1], state.currentToken[2]);
|
|
1425
1510
|
}
|
|
1426
1511
|
advance2(state);
|
|
1427
1512
|
const iterable = parseExpression(state, 0);
|
|
@@ -1434,19 +1519,19 @@ function parsePrefix(state) {
|
|
|
1434
1519
|
if (peekKind(state) === 34 /* Into */) {
|
|
1435
1520
|
advance2(state);
|
|
1436
1521
|
if (peekKind(state) !== 1 /* Identifier */) {
|
|
1437
|
-
throw new
|
|
1522
|
+
throw new ParseError('Expected identifier after "into"', state.currentToken[1], state.currentToken[2]);
|
|
1438
1523
|
}
|
|
1439
1524
|
const accName = readText(state.cursor, state.currentToken);
|
|
1440
1525
|
advance2(state);
|
|
1441
1526
|
if (peekKind(state) !== 24 /* Eq */) {
|
|
1442
|
-
throw new
|
|
1527
|
+
throw new ParseError('Expected "=" after accumulator name', state.currentToken[1], state.currentToken[2]);
|
|
1443
1528
|
}
|
|
1444
1529
|
advance2(state);
|
|
1445
1530
|
const initial = parseExpression(state, 0);
|
|
1446
1531
|
accumulator = { name: accName, initial };
|
|
1447
1532
|
}
|
|
1448
1533
|
if (peekKind(state) !== 29 /* Then */) {
|
|
1449
|
-
throw new
|
|
1534
|
+
throw new ParseError('Expected "then" in for expression', state.currentToken[1], state.currentToken[2]);
|
|
1450
1535
|
}
|
|
1451
1536
|
advance2(state);
|
|
1452
1537
|
const body = parseExpression(state, 0);
|
|
@@ -1478,7 +1563,7 @@ function parsePrefix(state) {
|
|
|
1478
1563
|
advance2(state);
|
|
1479
1564
|
const args = parseFunctionArguments(state);
|
|
1480
1565
|
if (peekKind(state) !== 21 /* RParen */) {
|
|
1481
|
-
throw new
|
|
1566
|
+
throw new ParseError("Expected closing parenthesis", state.currentToken[1], state.currentToken[2]);
|
|
1482
1567
|
}
|
|
1483
1568
|
advance2(state);
|
|
1484
1569
|
return functionCall(name, args);
|
|
@@ -1487,13 +1572,13 @@ function parsePrefix(state) {
|
|
|
1487
1572
|
}
|
|
1488
1573
|
const token = state.currentToken;
|
|
1489
1574
|
const tokenText = readText(state.cursor, token);
|
|
1490
|
-
throw new
|
|
1575
|
+
throw new ParseError(`Unexpected token: ${tokenText}`, token[1], token[2]);
|
|
1491
1576
|
}
|
|
1492
1577
|
function parseInfix(state, left, precedence) {
|
|
1493
1578
|
const tokenKind = peekKind(state);
|
|
1494
1579
|
if (tokenKind === 24 /* Eq */) {
|
|
1495
1580
|
if (left.kind !== 2 /* Identifier */) {
|
|
1496
|
-
throw new
|
|
1581
|
+
throw new ParseError("Invalid assignment target", state.currentToken[1], state.currentToken[2]);
|
|
1497
1582
|
}
|
|
1498
1583
|
const identName = left.name;
|
|
1499
1584
|
advance2(state);
|
|
@@ -1509,17 +1594,17 @@ function parseInfix(state, left, precedence) {
|
|
|
1509
1594
|
if (tokenKind === 26 /* Pipe */) {
|
|
1510
1595
|
advance2(state);
|
|
1511
1596
|
if (peekKind(state) !== 1 /* Identifier */) {
|
|
1512
|
-
throw new
|
|
1597
|
+
throw new ParseError("Expected function name after |>", state.currentToken[1], state.currentToken[2]);
|
|
1513
1598
|
}
|
|
1514
1599
|
const name = readText(state.cursor, state.currentToken);
|
|
1515
1600
|
advance2(state);
|
|
1516
1601
|
if (peekKind(state) !== 20 /* LParen */) {
|
|
1517
|
-
throw new
|
|
1602
|
+
throw new ParseError("Expected ( after function name in pipe expression", state.currentToken[1], state.currentToken[2]);
|
|
1518
1603
|
}
|
|
1519
1604
|
advance2(state);
|
|
1520
1605
|
const args = parsePipeArguments(state);
|
|
1521
1606
|
if (peekKind(state) !== 21 /* RParen */) {
|
|
1522
|
-
throw new
|
|
1607
|
+
throw new ParseError("Expected closing parenthesis", state.currentToken[1], state.currentToken[2]);
|
|
1523
1608
|
}
|
|
1524
1609
|
advance2(state);
|
|
1525
1610
|
let hasPlaceholder = false;
|
|
@@ -1530,7 +1615,7 @@ function parseInfix(state, left, precedence) {
|
|
|
1530
1615
|
}
|
|
1531
1616
|
}
|
|
1532
1617
|
if (!hasPlaceholder) {
|
|
1533
|
-
throw new
|
|
1618
|
+
throw new ParseError("Pipe expression requires at least one ? placeholder", state.currentToken[1], state.currentToken[2]);
|
|
1534
1619
|
}
|
|
1535
1620
|
return pipeExpr(left, name, args);
|
|
1536
1621
|
}
|
|
@@ -1541,7 +1626,7 @@ function parseInfix(state, left, precedence) {
|
|
|
1541
1626
|
const right = parseExpression(state, isRightAssociative ? precedence : precedence + 1);
|
|
1542
1627
|
return binaryOp(left, operator, right);
|
|
1543
1628
|
}
|
|
1544
|
-
throw new
|
|
1629
|
+
throw new ParseError("Unexpected token in infix position", state.currentToken[1], state.currentToken[2]);
|
|
1545
1630
|
}
|
|
1546
1631
|
function parseFunctionArguments(state) {
|
|
1547
1632
|
if (peekKind(state) === 21 /* RParen */) {
|
|
@@ -1586,198 +1671,224 @@ function advance2(state) {
|
|
|
1586
1671
|
}
|
|
1587
1672
|
|
|
1588
1673
|
// src/interpreter.ts
|
|
1589
|
-
function
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
}
|
|
1611
|
-
return value;
|
|
1612
|
-
},
|
|
1613
|
-
BinaryOp: (n, recurse) => {
|
|
1614
|
-
if (n.operator === "&&") {
|
|
1615
|
-
const left2 = recurse(n.left);
|
|
1616
|
-
assertBoolean(left2, "Operator '&&'", "left");
|
|
1617
|
-
if (!left2)
|
|
1618
|
-
return false;
|
|
1619
|
-
const right2 = recurse(n.right);
|
|
1620
|
-
assertBoolean(right2, "Operator '&&'", "right");
|
|
1621
|
-
return right2;
|
|
1622
|
-
}
|
|
1623
|
-
if (n.operator === "||") {
|
|
1624
|
-
const left2 = recurse(n.left);
|
|
1625
|
-
assertBoolean(left2, "Operator '||'", "left");
|
|
1626
|
-
if (left2)
|
|
1627
|
-
return true;
|
|
1628
|
-
const right2 = recurse(n.right);
|
|
1629
|
-
assertBoolean(right2, "Operator '||'", "right");
|
|
1630
|
-
return right2;
|
|
1674
|
+
function run(input, context = {}) {
|
|
1675
|
+
const node = typeof input === "string" ? parse(input) : input;
|
|
1676
|
+
const variables = new Map;
|
|
1677
|
+
const externalVariables = new Set;
|
|
1678
|
+
const vars = context.variables;
|
|
1679
|
+
if (vars) {
|
|
1680
|
+
for (const key of Object.keys(vars)) {
|
|
1681
|
+
variables.set(key, vars[key]);
|
|
1682
|
+
externalVariables.add(key);
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
const value = evalNode(node);
|
|
1686
|
+
return { value, variables };
|
|
1687
|
+
function evalNode(node2) {
|
|
1688
|
+
switch (node2.kind) {
|
|
1689
|
+
case 0 /* Program */: {
|
|
1690
|
+
let result = 0;
|
|
1691
|
+
for (const statement of node2.statements) {
|
|
1692
|
+
result = evalNode(statement);
|
|
1693
|
+
}
|
|
1694
|
+
return result;
|
|
1631
1695
|
}
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1696
|
+
case 1 /* NumberLiteral */:
|
|
1697
|
+
return node2.value;
|
|
1698
|
+
case 8 /* StringLiteral */:
|
|
1699
|
+
return node2.value;
|
|
1700
|
+
case 9 /* BooleanLiteral */:
|
|
1701
|
+
return node2.value;
|
|
1702
|
+
case 10 /* ArrayLiteral */: {
|
|
1703
|
+
const elems = node2.elements;
|
|
1704
|
+
const elements = [];
|
|
1705
|
+
for (let i = 0;i < elems.length; i++) {
|
|
1706
|
+
elements.push(evalNode(elems[i]));
|
|
1707
|
+
}
|
|
1708
|
+
validateHomogeneousArray(elements);
|
|
1709
|
+
return elements;
|
|
1641
1710
|
}
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1711
|
+
case 2 /* Identifier */: {
|
|
1712
|
+
const value2 = variables.get(node2.name);
|
|
1713
|
+
if (value2 === undefined) {
|
|
1714
|
+
throw new Error(`Undefined variable: ${node2.name}`);
|
|
1715
|
+
}
|
|
1716
|
+
return value2;
|
|
1645
1717
|
}
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1718
|
+
case 3 /* BinaryOp */: {
|
|
1719
|
+
if (node2.operator === "&&") {
|
|
1720
|
+
const left = evalNode(node2.left);
|
|
1721
|
+
assertBoolean(left, "Operator '&&'", "left");
|
|
1722
|
+
if (!left)
|
|
1723
|
+
return false;
|
|
1724
|
+
const right = evalNode(node2.right);
|
|
1725
|
+
assertBoolean(right, "Operator '&&'", "right");
|
|
1726
|
+
return right;
|
|
1727
|
+
}
|
|
1728
|
+
if (node2.operator === "||") {
|
|
1729
|
+
const left = evalNode(node2.left);
|
|
1730
|
+
assertBoolean(left, "Operator '||'", "left");
|
|
1731
|
+
if (left)
|
|
1732
|
+
return true;
|
|
1733
|
+
const right = evalNode(node2.right);
|
|
1734
|
+
assertBoolean(right, "Operator '||'", "right");
|
|
1735
|
+
return right;
|
|
1736
|
+
}
|
|
1737
|
+
return evaluateBinaryOperation(node2.operator, evalNode(node2.left), evalNode(node2.right));
|
|
1652
1738
|
}
|
|
1653
|
-
|
|
1654
|
-
|
|
1739
|
+
case 4 /* UnaryOp */: {
|
|
1740
|
+
const arg = evalNode(node2.argument);
|
|
1741
|
+
if (node2.operator === "-") {
|
|
1742
|
+
assertNumber(arg, "Operator '-' (unary)");
|
|
1743
|
+
return -arg;
|
|
1744
|
+
}
|
|
1745
|
+
if (node2.operator === "!") {
|
|
1746
|
+
assertBoolean(arg, "Operator '!'");
|
|
1747
|
+
return !arg;
|
|
1748
|
+
}
|
|
1749
|
+
throw new Error(`Unknown unary operator: ${String(node2.operator)}`);
|
|
1655
1750
|
}
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
if (externalValue !== undefined) {
|
|
1664
|
-
return externalValue;
|
|
1751
|
+
case 5 /* FunctionCall */: {
|
|
1752
|
+
const fn = context.functions?.[node2.name];
|
|
1753
|
+
if (fn === undefined) {
|
|
1754
|
+
throw new Error(`Undefined function: ${node2.name}`);
|
|
1755
|
+
}
|
|
1756
|
+
if (typeof fn !== "function") {
|
|
1757
|
+
throw new Error(`${node2.name} is not a function`);
|
|
1665
1758
|
}
|
|
1759
|
+
const nodeArgs = node2.args;
|
|
1760
|
+
const evaluatedArgs = [];
|
|
1761
|
+
for (let i = 0;i < nodeArgs.length; i++) {
|
|
1762
|
+
evaluatedArgs.push(evalNode(nodeArgs[i]));
|
|
1763
|
+
}
|
|
1764
|
+
return fn(...evaluatedArgs);
|
|
1666
1765
|
}
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
const index = recurse(n.index);
|
|
1678
|
-
if (Array.isArray(object)) {
|
|
1679
|
-
return resolveIndex(object, index);
|
|
1766
|
+
case 6 /* Assignment */: {
|
|
1767
|
+
const value2 = evalNode(node2.value);
|
|
1768
|
+
if (externalVariables.has(node2.name)) {
|
|
1769
|
+
const externalValue = variables.get(node2.name);
|
|
1770
|
+
if (externalValue !== undefined) {
|
|
1771
|
+
return externalValue;
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
variables.set(node2.name, value2);
|
|
1775
|
+
return value2;
|
|
1680
1776
|
}
|
|
1681
|
-
|
|
1682
|
-
|
|
1777
|
+
case 7 /* IfExpression */: {
|
|
1778
|
+
const condition = evalNode(node2.condition);
|
|
1779
|
+
assertBoolean(condition, "If condition");
|
|
1780
|
+
return condition ? evalNode(node2.consequent) : evalNode(node2.alternate);
|
|
1683
1781
|
}
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
const pipedValue = recurse(n.value);
|
|
1695
|
-
const fn = context.functions?.[n.name];
|
|
1696
|
-
if (fn === undefined) {
|
|
1697
|
-
throw new Error(`Undefined function: ${n.name}`);
|
|
1782
|
+
case 12 /* IndexAccess */: {
|
|
1783
|
+
const object = evalNode(node2.object);
|
|
1784
|
+
const index = evalNode(node2.index);
|
|
1785
|
+
if (Array.isArray(object)) {
|
|
1786
|
+
return resolveIndex(object, index);
|
|
1787
|
+
}
|
|
1788
|
+
if (typeof object === "string") {
|
|
1789
|
+
return resolveIndex(object, index);
|
|
1790
|
+
}
|
|
1791
|
+
throw new TypeError(`Index access expected array or string, got ${typeOf(object)}`);
|
|
1698
1792
|
}
|
|
1699
|
-
|
|
1700
|
-
|
|
1793
|
+
case 13 /* RangeExpression */: {
|
|
1794
|
+
const start = evalNode(node2.start);
|
|
1795
|
+
const end = evalNode(node2.end);
|
|
1796
|
+
assertNumber(start, "Range start");
|
|
1797
|
+
assertNumber(end, "Range end");
|
|
1798
|
+
return buildRange(start, end, node2.inclusive);
|
|
1701
1799
|
}
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1800
|
+
case 14 /* PipeExpression */: {
|
|
1801
|
+
const pipedValue = evalNode(node2.value);
|
|
1802
|
+
const fn = context.functions?.[node2.name];
|
|
1803
|
+
if (fn === undefined) {
|
|
1804
|
+
throw new Error(`Undefined function: ${node2.name}`);
|
|
1805
|
+
}
|
|
1806
|
+
if (typeof fn !== "function") {
|
|
1807
|
+
throw new Error(`${node2.name} is not a function`);
|
|
1808
|
+
}
|
|
1809
|
+
const pipeArgs = node2.args;
|
|
1810
|
+
const evaluatedArgs = [];
|
|
1811
|
+
for (let i = 0;i < pipeArgs.length; i++) {
|
|
1812
|
+
const arg = pipeArgs[i];
|
|
1813
|
+
evaluatedArgs.push(arg.kind === 15 /* Placeholder */ ? pipedValue : evalNode(arg));
|
|
1814
|
+
}
|
|
1815
|
+
return fn(...evaluatedArgs);
|
|
1717
1816
|
}
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1817
|
+
case 15 /* Placeholder */:
|
|
1818
|
+
throw new Error("Placeholder outside pipe expression");
|
|
1819
|
+
case 11 /* ForExpression */: {
|
|
1820
|
+
const iterable = evalNode(node2.iterable);
|
|
1821
|
+
let iterTarget;
|
|
1822
|
+
if (Array.isArray(iterable)) {
|
|
1823
|
+
iterTarget = iterable;
|
|
1824
|
+
} else if (typeof iterable === "string") {
|
|
1825
|
+
iterTarget = iterable;
|
|
1723
1826
|
} else {
|
|
1724
|
-
|
|
1827
|
+
throw new TypeError(`For expression expected array or string, got ${typeOf(iterable)}`);
|
|
1725
1828
|
}
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1829
|
+
const previousValue = variables.get(node2.variable);
|
|
1830
|
+
const hadPreviousValue = variables.has(node2.variable);
|
|
1831
|
+
if (node2.accumulator) {
|
|
1832
|
+
let acc = evalNode(node2.accumulator.initial);
|
|
1833
|
+
const prevAcc = variables.get(node2.accumulator.name);
|
|
1834
|
+
const hadPrevAcc = variables.has(node2.accumulator.name);
|
|
1835
|
+
for (const item of iterTarget) {
|
|
1836
|
+
variables.set(node2.variable, item);
|
|
1837
|
+
if (node2.guard) {
|
|
1838
|
+
const guardValue = evalNode(node2.guard);
|
|
1839
|
+
assertBoolean(guardValue, "For guard");
|
|
1840
|
+
if (!guardValue)
|
|
1841
|
+
continue;
|
|
1842
|
+
}
|
|
1843
|
+
variables.set(node2.accumulator.name, acc);
|
|
1844
|
+
acc = evalNode(node2.body);
|
|
1845
|
+
}
|
|
1846
|
+
if (hadPrevAcc) {
|
|
1847
|
+
variables.set(node2.accumulator.name, prevAcc);
|
|
1848
|
+
} else {
|
|
1849
|
+
variables.delete(node2.accumulator.name);
|
|
1850
|
+
}
|
|
1851
|
+
if (hadPreviousValue) {
|
|
1852
|
+
variables.set(node2.variable, previousValue);
|
|
1853
|
+
} else {
|
|
1854
|
+
variables.delete(node2.variable);
|
|
1855
|
+
}
|
|
1856
|
+
return acc;
|
|
1857
|
+
}
|
|
1858
|
+
const result = [];
|
|
1859
|
+
for (const item of iterTarget) {
|
|
1860
|
+
variables.set(node2.variable, item);
|
|
1861
|
+
if (node2.guard) {
|
|
1862
|
+
const guardValue = evalNode(node2.guard);
|
|
1735
1863
|
assertBoolean(guardValue, "For guard");
|
|
1736
1864
|
if (!guardValue)
|
|
1737
1865
|
continue;
|
|
1738
1866
|
}
|
|
1739
|
-
|
|
1740
|
-
acc = recurse(n.body);
|
|
1867
|
+
result.push(evalNode(node2.body));
|
|
1741
1868
|
}
|
|
1742
|
-
if (
|
|
1743
|
-
variables.set(
|
|
1869
|
+
if (hadPreviousValue) {
|
|
1870
|
+
variables.set(node2.variable, previousValue);
|
|
1744
1871
|
} else {
|
|
1745
|
-
variables.delete(
|
|
1746
|
-
}
|
|
1747
|
-
restoreLoopVar();
|
|
1748
|
-
return acc;
|
|
1749
|
-
}
|
|
1750
|
-
const result = [];
|
|
1751
|
-
for (const item of items) {
|
|
1752
|
-
variables.set(n.variable, item);
|
|
1753
|
-
if (n.guard) {
|
|
1754
|
-
const guardValue = recurse(n.guard);
|
|
1755
|
-
assertBoolean(guardValue, "For guard");
|
|
1756
|
-
if (!guardValue)
|
|
1757
|
-
continue;
|
|
1872
|
+
variables.delete(node2.variable);
|
|
1758
1873
|
}
|
|
1759
|
-
result
|
|
1874
|
+
validateHomogeneousArray(result);
|
|
1875
|
+
return result;
|
|
1760
1876
|
}
|
|
1761
|
-
restoreLoopVar();
|
|
1762
|
-
validateHomogeneousArray(result);
|
|
1763
|
-
return result;
|
|
1764
1877
|
}
|
|
1765
|
-
}
|
|
1766
|
-
}
|
|
1767
|
-
function run(input, context = {}) {
|
|
1768
|
-
const node = typeof input === "string" ? parse(input) : input;
|
|
1769
|
-
const entries = Object.entries(context.variables || {});
|
|
1770
|
-
const variables = new Map(entries);
|
|
1771
|
-
const externalVariables = new Set(entries.map(([key]) => key));
|
|
1772
|
-
const value = evaluateNode(node, context, variables, externalVariables);
|
|
1773
|
-
return { value, variables };
|
|
1878
|
+
}
|
|
1774
1879
|
}
|
|
1775
1880
|
function evaluate(input, context = {}) {
|
|
1776
1881
|
return run(input, context).value;
|
|
1777
1882
|
}
|
|
1778
1883
|
function evaluateScope(input, context = {}) {
|
|
1779
|
-
|
|
1780
|
-
|
|
1884
|
+
return evaluateWithScope(input, context).scope;
|
|
1885
|
+
}
|
|
1886
|
+
function evaluateWithScope(input, context = {}) {
|
|
1887
|
+
const { value, variables } = run(input, context);
|
|
1888
|
+
return {
|
|
1889
|
+
value,
|
|
1890
|
+
scope: Object.fromEntries(variables)
|
|
1891
|
+
};
|
|
1781
1892
|
}
|
|
1782
1893
|
// src/optimizer.ts
|
|
1783
1894
|
function preserveComments(original, replacement) {
|
|
@@ -1843,24 +1954,34 @@ function isLiteral(node) {
|
|
|
1843
1954
|
return isNumberLiteral(node) || isStringLiteral(node) || isBooleanLiteral(node);
|
|
1844
1955
|
}
|
|
1845
1956
|
function mightHaveSideEffects(node) {
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1957
|
+
switch (node.kind) {
|
|
1958
|
+
case 0 /* Program */:
|
|
1959
|
+
return node.statements.some(mightHaveSideEffects);
|
|
1960
|
+
case 10 /* ArrayLiteral */:
|
|
1961
|
+
return node.elements.some(mightHaveSideEffects);
|
|
1962
|
+
case 3 /* BinaryOp */:
|
|
1963
|
+
return mightHaveSideEffects(node.left) || mightHaveSideEffects(node.right);
|
|
1964
|
+
case 4 /* UnaryOp */:
|
|
1965
|
+
return mightHaveSideEffects(node.argument);
|
|
1966
|
+
case 7 /* IfExpression */:
|
|
1967
|
+
return mightHaveSideEffects(node.condition) || mightHaveSideEffects(node.consequent) || mightHaveSideEffects(node.alternate);
|
|
1968
|
+
case 11 /* ForExpression */:
|
|
1969
|
+
return mightHaveSideEffects(node.iterable) || node.guard !== null && mightHaveSideEffects(node.guard) || node.accumulator !== null && mightHaveSideEffects(node.accumulator.initial) || mightHaveSideEffects(node.body);
|
|
1970
|
+
case 12 /* IndexAccess */:
|
|
1971
|
+
return mightHaveSideEffects(node.object) || mightHaveSideEffects(node.index);
|
|
1972
|
+
case 13 /* RangeExpression */:
|
|
1973
|
+
return mightHaveSideEffects(node.start) || mightHaveSideEffects(node.end);
|
|
1974
|
+
case 5 /* FunctionCall */:
|
|
1975
|
+
case 14 /* PipeExpression */:
|
|
1976
|
+
case 6 /* Assignment */:
|
|
1977
|
+
return true;
|
|
1978
|
+
case 1 /* NumberLiteral */:
|
|
1979
|
+
case 8 /* StringLiteral */:
|
|
1980
|
+
case 9 /* BooleanLiteral */:
|
|
1981
|
+
case 2 /* Identifier */:
|
|
1982
|
+
case 15 /* Placeholder */:
|
|
1983
|
+
return false;
|
|
1984
|
+
}
|
|
1864
1985
|
}
|
|
1865
1986
|
function propagateConstants(program2, externalVariables) {
|
|
1866
1987
|
const statements = program2.statements;
|
|
@@ -1891,10 +2012,9 @@ function propagateConstants(program2, externalVariables) {
|
|
|
1891
2012
|
return null;
|
|
1892
2013
|
const referencedIds = new Set;
|
|
1893
2014
|
for (const stmt of statements) {
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
collectReferencedIdentifiers(stmt, referencedIds);
|
|
2015
|
+
const identifiers = collectAllIdentifiers(isAssignment(stmt) ? stmt.value : stmt);
|
|
2016
|
+
for (const id of identifiers) {
|
|
2017
|
+
referencedIds.add(id);
|
|
1898
2018
|
}
|
|
1899
2019
|
}
|
|
1900
2020
|
let hasSubstitution = false;
|
|
@@ -1912,221 +2032,230 @@ function propagateConstants(program2, externalVariables) {
|
|
|
1912
2032
|
}
|
|
1913
2033
|
return result;
|
|
1914
2034
|
}
|
|
1915
|
-
function collectReferencedIdentifiers(node, ids) {
|
|
1916
|
-
visit(node, {
|
|
1917
|
-
Program: (n, recurse) => {
|
|
1918
|
-
for (const s of n.statements)
|
|
1919
|
-
recurse(s);
|
|
1920
|
-
},
|
|
1921
|
-
NumberLiteral: () => {},
|
|
1922
|
-
StringLiteral: () => {},
|
|
1923
|
-
BooleanLiteral: () => {},
|
|
1924
|
-
ArrayLiteral: (n, recurse) => {
|
|
1925
|
-
for (const e of n.elements)
|
|
1926
|
-
recurse(e);
|
|
1927
|
-
},
|
|
1928
|
-
Identifier: (n) => {
|
|
1929
|
-
ids.add(n.name);
|
|
1930
|
-
},
|
|
1931
|
-
BinaryOp: (n, recurse) => {
|
|
1932
|
-
recurse(n.left);
|
|
1933
|
-
recurse(n.right);
|
|
1934
|
-
},
|
|
1935
|
-
UnaryOp: (n, recurse) => {
|
|
1936
|
-
recurse(n.argument);
|
|
1937
|
-
},
|
|
1938
|
-
FunctionCall: (n, recurse) => {
|
|
1939
|
-
for (const a of n.args)
|
|
1940
|
-
recurse(a);
|
|
1941
|
-
},
|
|
1942
|
-
Assignment: (n, recurse) => {
|
|
1943
|
-
recurse(n.value);
|
|
1944
|
-
},
|
|
1945
|
-
IfExpression: (n, recurse) => {
|
|
1946
|
-
recurse(n.condition);
|
|
1947
|
-
recurse(n.consequent);
|
|
1948
|
-
recurse(n.alternate);
|
|
1949
|
-
},
|
|
1950
|
-
ForExpression: (n, recurse) => {
|
|
1951
|
-
recurse(n.iterable);
|
|
1952
|
-
if (n.guard)
|
|
1953
|
-
recurse(n.guard);
|
|
1954
|
-
if (n.accumulator)
|
|
1955
|
-
recurse(n.accumulator.initial);
|
|
1956
|
-
recurse(n.body);
|
|
1957
|
-
},
|
|
1958
|
-
IndexAccess: (n, recurse) => {
|
|
1959
|
-
recurse(n.object);
|
|
1960
|
-
recurse(n.index);
|
|
1961
|
-
},
|
|
1962
|
-
RangeExpression: (n, recurse) => {
|
|
1963
|
-
recurse(n.start);
|
|
1964
|
-
recurse(n.end);
|
|
1965
|
-
},
|
|
1966
|
-
PipeExpression: (n, recurse) => {
|
|
1967
|
-
recurse(n.value);
|
|
1968
|
-
for (const a of n.args)
|
|
1969
|
-
recurse(a);
|
|
1970
|
-
},
|
|
1971
|
-
Placeholder: () => {}
|
|
1972
|
-
});
|
|
1973
|
-
}
|
|
1974
2035
|
function collectForLoopVars(node, vars) {
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
for (const s of
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2036
|
+
switch (node.kind) {
|
|
2037
|
+
case 0 /* Program */:
|
|
2038
|
+
for (const s of node.statements)
|
|
2039
|
+
collectForLoopVars(s, vars);
|
|
2040
|
+
break;
|
|
2041
|
+
case 10 /* ArrayLiteral */:
|
|
2042
|
+
for (const e of node.elements)
|
|
2043
|
+
collectForLoopVars(e, vars);
|
|
2044
|
+
break;
|
|
2045
|
+
case 3 /* BinaryOp */:
|
|
2046
|
+
collectForLoopVars(node.left, vars);
|
|
2047
|
+
collectForLoopVars(node.right, vars);
|
|
2048
|
+
break;
|
|
2049
|
+
case 4 /* UnaryOp */:
|
|
2050
|
+
collectForLoopVars(node.argument, vars);
|
|
2051
|
+
break;
|
|
2052
|
+
case 5 /* FunctionCall */:
|
|
2053
|
+
for (const a of node.args)
|
|
2054
|
+
collectForLoopVars(a, vars);
|
|
2055
|
+
break;
|
|
2056
|
+
case 6 /* Assignment */:
|
|
2057
|
+
collectForLoopVars(node.value, vars);
|
|
2058
|
+
break;
|
|
2059
|
+
case 7 /* IfExpression */:
|
|
2060
|
+
collectForLoopVars(node.condition, vars);
|
|
2061
|
+
collectForLoopVars(node.consequent, vars);
|
|
2062
|
+
collectForLoopVars(node.alternate, vars);
|
|
2063
|
+
break;
|
|
2064
|
+
case 11 /* ForExpression */:
|
|
2065
|
+
vars.add(node.variable);
|
|
2066
|
+
if (node.accumulator)
|
|
2067
|
+
vars.add(node.accumulator.name);
|
|
2068
|
+
collectForLoopVars(node.iterable, vars);
|
|
2069
|
+
if (node.guard)
|
|
2070
|
+
collectForLoopVars(node.guard, vars);
|
|
2071
|
+
if (node.accumulator)
|
|
2072
|
+
collectForLoopVars(node.accumulator.initial, vars);
|
|
2073
|
+
collectForLoopVars(node.body, vars);
|
|
2074
|
+
break;
|
|
2075
|
+
case 12 /* IndexAccess */:
|
|
2076
|
+
collectForLoopVars(node.object, vars);
|
|
2077
|
+
collectForLoopVars(node.index, vars);
|
|
2078
|
+
break;
|
|
2079
|
+
case 13 /* RangeExpression */:
|
|
2080
|
+
collectForLoopVars(node.start, vars);
|
|
2081
|
+
collectForLoopVars(node.end, vars);
|
|
2082
|
+
break;
|
|
2083
|
+
case 14 /* PipeExpression */:
|
|
2084
|
+
collectForLoopVars(node.value, vars);
|
|
2085
|
+
for (const a of node.args)
|
|
2086
|
+
collectForLoopVars(a, vars);
|
|
2087
|
+
break;
|
|
2088
|
+
case 1 /* NumberLiteral */:
|
|
2089
|
+
case 8 /* StringLiteral */:
|
|
2090
|
+
case 9 /* BooleanLiteral */:
|
|
2091
|
+
case 2 /* Identifier */:
|
|
2092
|
+
case 15 /* Placeholder */:
|
|
2093
|
+
break;
|
|
2094
|
+
}
|
|
2033
2095
|
}
|
|
2034
2096
|
function countAssignments(node, counts) {
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
for (const s of
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
for (const a of
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2097
|
+
switch (node.kind) {
|
|
2098
|
+
case 0 /* Program */:
|
|
2099
|
+
for (const s of node.statements)
|
|
2100
|
+
countAssignments(s, counts);
|
|
2101
|
+
break;
|
|
2102
|
+
case 6 /* Assignment */:
|
|
2103
|
+
counts.set(node.name, (counts.get(node.name) ?? 0) + 1);
|
|
2104
|
+
countAssignments(node.value, counts);
|
|
2105
|
+
break;
|
|
2106
|
+
case 10 /* ArrayLiteral */:
|
|
2107
|
+
for (const e of node.elements)
|
|
2108
|
+
countAssignments(e, counts);
|
|
2109
|
+
break;
|
|
2110
|
+
case 3 /* BinaryOp */:
|
|
2111
|
+
countAssignments(node.left, counts);
|
|
2112
|
+
countAssignments(node.right, counts);
|
|
2113
|
+
break;
|
|
2114
|
+
case 4 /* UnaryOp */:
|
|
2115
|
+
countAssignments(node.argument, counts);
|
|
2116
|
+
break;
|
|
2117
|
+
case 5 /* FunctionCall */:
|
|
2118
|
+
for (const a of node.args)
|
|
2119
|
+
countAssignments(a, counts);
|
|
2120
|
+
break;
|
|
2121
|
+
case 7 /* IfExpression */:
|
|
2122
|
+
countAssignments(node.condition, counts);
|
|
2123
|
+
countAssignments(node.consequent, counts);
|
|
2124
|
+
countAssignments(node.alternate, counts);
|
|
2125
|
+
break;
|
|
2126
|
+
case 11 /* ForExpression */:
|
|
2127
|
+
countAssignments(node.iterable, counts);
|
|
2128
|
+
if (node.guard)
|
|
2129
|
+
countAssignments(node.guard, counts);
|
|
2130
|
+
if (node.accumulator)
|
|
2131
|
+
countAssignments(node.accumulator.initial, counts);
|
|
2132
|
+
countAssignments(node.body, counts);
|
|
2133
|
+
break;
|
|
2134
|
+
case 12 /* IndexAccess */:
|
|
2135
|
+
countAssignments(node.object, counts);
|
|
2136
|
+
countAssignments(node.index, counts);
|
|
2137
|
+
break;
|
|
2138
|
+
case 13 /* RangeExpression */:
|
|
2139
|
+
countAssignments(node.start, counts);
|
|
2140
|
+
countAssignments(node.end, counts);
|
|
2141
|
+
break;
|
|
2142
|
+
case 14 /* PipeExpression */:
|
|
2143
|
+
countAssignments(node.value, counts);
|
|
2144
|
+
for (const a of node.args)
|
|
2145
|
+
countAssignments(a, counts);
|
|
2146
|
+
break;
|
|
2147
|
+
case 1 /* NumberLiteral */:
|
|
2148
|
+
case 8 /* StringLiteral */:
|
|
2149
|
+
case 9 /* BooleanLiteral */:
|
|
2150
|
+
case 2 /* Identifier */:
|
|
2151
|
+
case 15 /* Placeholder */:
|
|
2152
|
+
break;
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
function unchangedArray(original, mapped) {
|
|
2156
|
+
for (let i = 0;i < original.length; i++) {
|
|
2157
|
+
if (original[i] !== mapped[i])
|
|
2158
|
+
return false;
|
|
2159
|
+
}
|
|
2160
|
+
return true;
|
|
2091
2161
|
}
|
|
2092
2162
|
function substituteIdentifiers(node, knownValues) {
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2163
|
+
const recurse = (n) => substituteIdentifiers(n, knownValues);
|
|
2164
|
+
switch (node.kind) {
|
|
2165
|
+
case 0 /* Program */: {
|
|
2166
|
+
const stmts = node.statements.map(recurse);
|
|
2167
|
+
if (unchangedArray(node.statements, stmts))
|
|
2168
|
+
return node;
|
|
2169
|
+
const result = program(stmts);
|
|
2170
|
+
if (node.trailingComments && node.trailingComments.length > 0) {
|
|
2171
|
+
return { ...result, trailingComments: node.trailingComments };
|
|
2098
2172
|
}
|
|
2099
2173
|
return result;
|
|
2100
|
-
}
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2174
|
+
}
|
|
2175
|
+
case 1 /* NumberLiteral */:
|
|
2176
|
+
case 8 /* StringLiteral */:
|
|
2177
|
+
case 9 /* BooleanLiteral */:
|
|
2178
|
+
case 15 /* Placeholder */:
|
|
2179
|
+
return node;
|
|
2180
|
+
case 10 /* ArrayLiteral */: {
|
|
2181
|
+
const elements = node.elements.map(recurse);
|
|
2182
|
+
if (unchangedArray(node.elements, elements))
|
|
2183
|
+
return node;
|
|
2184
|
+
return preserveComments(node, array(elements));
|
|
2185
|
+
}
|
|
2186
|
+
case 2 /* Identifier */: {
|
|
2187
|
+
const replacement = knownValues.get(node.name);
|
|
2188
|
+
return replacement ? preserveComments(node, replacement) : node;
|
|
2189
|
+
}
|
|
2190
|
+
case 3 /* BinaryOp */: {
|
|
2191
|
+
const left = recurse(node.left);
|
|
2192
|
+
const right = recurse(node.right);
|
|
2193
|
+
if (left === node.left && right === node.right)
|
|
2194
|
+
return node;
|
|
2195
|
+
return preserveComments(node, binaryOp(left, node.operator, right));
|
|
2196
|
+
}
|
|
2197
|
+
case 4 /* UnaryOp */: {
|
|
2198
|
+
const argument = recurse(node.argument);
|
|
2199
|
+
if (argument === node.argument)
|
|
2200
|
+
return node;
|
|
2201
|
+
return preserveComments(node, unaryOp(node.operator, argument));
|
|
2202
|
+
}
|
|
2203
|
+
case 5 /* FunctionCall */: {
|
|
2204
|
+
const args = node.args.map(recurse);
|
|
2205
|
+
if (unchangedArray(node.args, args))
|
|
2206
|
+
return node;
|
|
2207
|
+
return preserveComments(node, functionCall(node.name, args));
|
|
2208
|
+
}
|
|
2209
|
+
case 6 /* Assignment */: {
|
|
2210
|
+
const value = recurse(node.value);
|
|
2211
|
+
if (value === node.value)
|
|
2212
|
+
return node;
|
|
2213
|
+
return preserveComments(node, assign(node.name, value));
|
|
2214
|
+
}
|
|
2215
|
+
case 7 /* IfExpression */: {
|
|
2216
|
+
const condition = recurse(node.condition);
|
|
2217
|
+
const consequent = recurse(node.consequent);
|
|
2218
|
+
const alternate = recurse(node.alternate);
|
|
2219
|
+
if (condition === node.condition && consequent === node.consequent && alternate === node.alternate)
|
|
2220
|
+
return node;
|
|
2221
|
+
return preserveComments(node, ifExpr(condition, consequent, alternate));
|
|
2222
|
+
}
|
|
2223
|
+
case 11 /* ForExpression */: {
|
|
2115
2224
|
const innerKnown = new Map(knownValues);
|
|
2116
|
-
innerKnown.delete(
|
|
2117
|
-
if (
|
|
2118
|
-
innerKnown.delete(
|
|
2119
|
-
const iterable = recurse(
|
|
2120
|
-
const guard =
|
|
2121
|
-
const
|
|
2122
|
-
const body = substituteIdentifiers(
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2225
|
+
innerKnown.delete(node.variable);
|
|
2226
|
+
if (node.accumulator)
|
|
2227
|
+
innerKnown.delete(node.accumulator.name);
|
|
2228
|
+
const iterable = recurse(node.iterable);
|
|
2229
|
+
const guard = node.guard ? substituteIdentifiers(node.guard, innerKnown) : null;
|
|
2230
|
+
const initial = node.accumulator ? recurse(node.accumulator.initial) : null;
|
|
2231
|
+
const body = substituteIdentifiers(node.body, innerKnown);
|
|
2232
|
+
if (iterable === node.iterable && guard === node.guard && (node.accumulator === null || initial === node.accumulator.initial) && body === node.body)
|
|
2233
|
+
return node;
|
|
2234
|
+
const accumulator = node.accumulator ? { name: node.accumulator.name, initial } : null;
|
|
2235
|
+
return preserveComments(node, forExpr(node.variable, iterable, guard, accumulator, body));
|
|
2236
|
+
}
|
|
2237
|
+
case 12 /* IndexAccess */: {
|
|
2238
|
+
const object = recurse(node.object);
|
|
2239
|
+
const index = recurse(node.index);
|
|
2240
|
+
if (object === node.object && index === node.index)
|
|
2241
|
+
return node;
|
|
2242
|
+
return preserveComments(node, indexAccess(object, index));
|
|
2243
|
+
}
|
|
2244
|
+
case 13 /* RangeExpression */: {
|
|
2245
|
+
const start = recurse(node.start);
|
|
2246
|
+
const end = recurse(node.end);
|
|
2247
|
+
if (start === node.start && end === node.end)
|
|
2248
|
+
return node;
|
|
2249
|
+
return preserveComments(node, rangeExpr(start, end, node.inclusive));
|
|
2250
|
+
}
|
|
2251
|
+
case 14 /* PipeExpression */: {
|
|
2252
|
+
const value = recurse(node.value);
|
|
2253
|
+
const args = node.args.map(recurse);
|
|
2254
|
+
if (value === node.value && unchangedArray(node.args, args))
|
|
2255
|
+
return node;
|
|
2256
|
+
return preserveComments(node, pipeExpr(value, node.name, args));
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2130
2259
|
}
|
|
2131
2260
|
function optimize(node, externalVariables) {
|
|
2132
2261
|
let propagated = fold(node);
|
|
@@ -2153,142 +2282,168 @@ function optimize(node, externalVariables) {
|
|
|
2153
2282
|
return propagated;
|
|
2154
2283
|
}
|
|
2155
2284
|
function fold(node) {
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2285
|
+
const recurse = fold;
|
|
2286
|
+
switch (node.kind) {
|
|
2287
|
+
case 1 /* NumberLiteral */:
|
|
2288
|
+
case 8 /* StringLiteral */:
|
|
2289
|
+
case 9 /* BooleanLiteral */:
|
|
2290
|
+
case 2 /* Identifier */:
|
|
2291
|
+
case 15 /* Placeholder */:
|
|
2292
|
+
return node;
|
|
2293
|
+
case 0 /* Program */: {
|
|
2294
|
+
const optimizedStatements = node.statements.map(recurse);
|
|
2295
|
+
if (unchangedArray(node.statements, optimizedStatements))
|
|
2296
|
+
return node;
|
|
2297
|
+
const result = program(optimizedStatements);
|
|
2298
|
+
if (node.trailingComments && node.trailingComments.length > 0) {
|
|
2299
|
+
return { ...result, trailingComments: node.trailingComments };
|
|
2300
|
+
}
|
|
2301
|
+
return result;
|
|
2302
|
+
}
|
|
2303
|
+
case 10 /* ArrayLiteral */: {
|
|
2304
|
+
const elements = node.elements.map(recurse);
|
|
2305
|
+
if (unchangedArray(node.elements, elements))
|
|
2306
|
+
return node;
|
|
2307
|
+
return preserveComments(node, array(elements));
|
|
2308
|
+
}
|
|
2309
|
+
case 3 /* BinaryOp */: {
|
|
2310
|
+
const left = recurse(node.left);
|
|
2311
|
+
const right = recurse(node.right);
|
|
2168
2312
|
if (isNumberLiteral(left) && isNumberLiteral(right)) {
|
|
2169
|
-
const result = evaluateBinaryOperation(
|
|
2313
|
+
const result = evaluateBinaryOperation(node.operator, left.value, right.value);
|
|
2170
2314
|
if (typeof result === "number")
|
|
2171
|
-
return preserveComments(
|
|
2315
|
+
return preserveComments(node, number(result));
|
|
2172
2316
|
if (typeof result === "boolean")
|
|
2173
|
-
return preserveComments(
|
|
2317
|
+
return preserveComments(node, boolean(result));
|
|
2174
2318
|
}
|
|
2175
2319
|
if (isStringLiteral(left) && isStringLiteral(right)) {
|
|
2176
|
-
if (
|
|
2177
|
-
return preserveComments(
|
|
2178
|
-
if (
|
|
2179
|
-
const result = evaluateBinaryOperation(
|
|
2180
|
-
return preserveComments(
|
|
2320
|
+
if (node.operator === "+")
|
|
2321
|
+
return preserveComments(node, string(left.value + right.value));
|
|
2322
|
+
if (node.operator === "<" || node.operator === ">" || node.operator === "<=" || node.operator === ">=") {
|
|
2323
|
+
const result = evaluateBinaryOperation(node.operator, left.value, right.value);
|
|
2324
|
+
return preserveComments(node, boolean(result));
|
|
2181
2325
|
}
|
|
2182
|
-
if (
|
|
2183
|
-
return preserveComments(
|
|
2184
|
-
if (
|
|
2185
|
-
return preserveComments(
|
|
2326
|
+
if (node.operator === "==")
|
|
2327
|
+
return preserveComments(node, boolean(left.value === right.value));
|
|
2328
|
+
if (node.operator === "!=")
|
|
2329
|
+
return preserveComments(node, boolean(left.value !== right.value));
|
|
2186
2330
|
}
|
|
2187
2331
|
if (isBooleanLiteral(left) && isBooleanLiteral(right)) {
|
|
2188
|
-
if (
|
|
2189
|
-
return preserveComments(
|
|
2190
|
-
if (
|
|
2191
|
-
return preserveComments(
|
|
2192
|
-
if (
|
|
2193
|
-
return preserveComments(
|
|
2194
|
-
if (
|
|
2195
|
-
return preserveComments(
|
|
2332
|
+
if (node.operator === "&&")
|
|
2333
|
+
return preserveComments(node, boolean(left.value && right.value));
|
|
2334
|
+
if (node.operator === "||")
|
|
2335
|
+
return preserveComments(node, boolean(left.value || right.value));
|
|
2336
|
+
if (node.operator === "==")
|
|
2337
|
+
return preserveComments(node, boolean(left.value === right.value));
|
|
2338
|
+
if (node.operator === "!=")
|
|
2339
|
+
return preserveComments(node, boolean(left.value !== right.value));
|
|
2196
2340
|
}
|
|
2197
2341
|
if (isLiteral(left) && isLiteral(right)) {
|
|
2198
2342
|
if (left.kind !== right.kind) {
|
|
2199
|
-
if (
|
|
2200
|
-
return preserveComments(
|
|
2201
|
-
if (
|
|
2202
|
-
return preserveComments(
|
|
2343
|
+
if (node.operator === "==")
|
|
2344
|
+
return preserveComments(node, boolean(false));
|
|
2345
|
+
if (node.operator === "!=")
|
|
2346
|
+
return preserveComments(node, boolean(true));
|
|
2203
2347
|
}
|
|
2204
2348
|
}
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2349
|
+
if (left === node.left && right === node.right)
|
|
2350
|
+
return node;
|
|
2351
|
+
return preserveComments(node, binaryOp(left, node.operator, right));
|
|
2352
|
+
}
|
|
2353
|
+
case 4 /* UnaryOp */: {
|
|
2354
|
+
const argument = recurse(node.argument);
|
|
2355
|
+
if (node.operator === "-" && isNumberLiteral(argument)) {
|
|
2356
|
+
return preserveComments(node, number(-argument.value));
|
|
2211
2357
|
}
|
|
2212
|
-
if (
|
|
2213
|
-
return preserveComments(
|
|
2358
|
+
if (node.operator === "!" && isBooleanLiteral(argument)) {
|
|
2359
|
+
return preserveComments(node, boolean(!argument.value));
|
|
2214
2360
|
}
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2361
|
+
if (argument === node.argument)
|
|
2362
|
+
return node;
|
|
2363
|
+
return preserveComments(node, unaryOp(node.operator, argument));
|
|
2364
|
+
}
|
|
2365
|
+
case 5 /* FunctionCall */: {
|
|
2366
|
+
const optimizedArgs = node.args.map(recurse);
|
|
2367
|
+
if (unchangedArray(node.args, optimizedArgs))
|
|
2368
|
+
return node;
|
|
2369
|
+
return preserveComments(node, functionCall(node.name, optimizedArgs));
|
|
2370
|
+
}
|
|
2371
|
+
case 6 /* Assignment */: {
|
|
2372
|
+
const value = recurse(node.value);
|
|
2373
|
+
if (value === node.value)
|
|
2374
|
+
return node;
|
|
2375
|
+
return preserveComments(node, assign(node.name, value));
|
|
2376
|
+
}
|
|
2377
|
+
case 7 /* IfExpression */: {
|
|
2378
|
+
const condition = recurse(node.condition);
|
|
2226
2379
|
if (isBooleanLiteral(condition)) {
|
|
2227
|
-
const result = condition.value ? recurse(
|
|
2228
|
-
return preserveComments(
|
|
2380
|
+
const result = condition.value ? recurse(node.consequent) : recurse(node.alternate);
|
|
2381
|
+
return preserveComments(node, result);
|
|
2229
2382
|
}
|
|
2230
|
-
const consequent = recurse(
|
|
2231
|
-
const alternate = recurse(
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
const
|
|
2238
|
-
const
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
const
|
|
2383
|
+
const consequent = recurse(node.consequent);
|
|
2384
|
+
const alternate = recurse(node.alternate);
|
|
2385
|
+
if (condition === node.condition && consequent === node.consequent && alternate === node.alternate)
|
|
2386
|
+
return node;
|
|
2387
|
+
return preserveComments(node, ifExpr(condition, consequent, alternate));
|
|
2388
|
+
}
|
|
2389
|
+
case 11 /* ForExpression */: {
|
|
2390
|
+
const iterable = recurse(node.iterable);
|
|
2391
|
+
const guard = node.guard ? recurse(node.guard) : null;
|
|
2392
|
+
const initial = node.accumulator ? recurse(node.accumulator.initial) : null;
|
|
2393
|
+
const body = recurse(node.body);
|
|
2394
|
+
if (iterable === node.iterable && guard === node.guard && (node.accumulator === null || initial === node.accumulator.initial) && body === node.body)
|
|
2395
|
+
return node;
|
|
2396
|
+
const accumulator = node.accumulator ? { name: node.accumulator.name, initial } : null;
|
|
2397
|
+
return preserveComments(node, forExpr(node.variable, iterable, guard, accumulator, body));
|
|
2398
|
+
}
|
|
2399
|
+
case 12 /* IndexAccess */: {
|
|
2400
|
+
const object = recurse(node.object);
|
|
2401
|
+
const index = recurse(node.index);
|
|
2244
2402
|
if (isArrayLiteral(object) && isNumberLiteral(index)) {
|
|
2245
2403
|
const idx = index.value;
|
|
2246
2404
|
if (Number.isInteger(idx)) {
|
|
2247
2405
|
const len = object.elements.length;
|
|
2248
2406
|
const resolved = idx < 0 ? len + idx : idx;
|
|
2249
2407
|
if (resolved >= 0 && resolved < len) {
|
|
2250
|
-
return preserveComments(
|
|
2408
|
+
return preserveComments(node, object.elements[resolved]);
|
|
2251
2409
|
}
|
|
2252
2410
|
}
|
|
2253
2411
|
}
|
|
2254
2412
|
if (isStringLiteral(object) && isNumberLiteral(index)) {
|
|
2255
2413
|
try {
|
|
2256
2414
|
const char = resolveIndex(object.value, index.value);
|
|
2257
|
-
return preserveComments(
|
|
2415
|
+
return preserveComments(node, string(char));
|
|
2258
2416
|
} catch {}
|
|
2259
2417
|
}
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2418
|
+
if (object === node.object && index === node.index)
|
|
2419
|
+
return node;
|
|
2420
|
+
return preserveComments(node, indexAccess(object, index));
|
|
2421
|
+
}
|
|
2422
|
+
case 13 /* RangeExpression */: {
|
|
2423
|
+
const start = recurse(node.start);
|
|
2424
|
+
const end = recurse(node.end);
|
|
2265
2425
|
if (isNumberLiteral(start) && isNumberLiteral(end)) {
|
|
2266
2426
|
try {
|
|
2267
|
-
const limit =
|
|
2427
|
+
const limit = node.inclusive ? end.value + 1 : end.value;
|
|
2268
2428
|
const count = limit - start.value;
|
|
2269
2429
|
if (count >= 0 && count <= 1e4) {
|
|
2270
|
-
const values = buildRange(start.value, end.value,
|
|
2271
|
-
return preserveComments(
|
|
2430
|
+
const values = buildRange(start.value, end.value, node.inclusive);
|
|
2431
|
+
return preserveComments(node, array(values.map(number)));
|
|
2272
2432
|
}
|
|
2273
2433
|
} catch {}
|
|
2274
2434
|
}
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
const value = recurse(n.value);
|
|
2279
|
-
const optimizedArgs = n.args.map(recurse);
|
|
2280
|
-
return preserveComments(n, pipeExpr(value, n.name, optimizedArgs));
|
|
2281
|
-
},
|
|
2282
|
-
Placeholder: (n) => n,
|
|
2283
|
-
Program: (n, recurse) => {
|
|
2284
|
-
const optimizedStatements = n.statements.map(recurse);
|
|
2285
|
-
const result = program(optimizedStatements);
|
|
2286
|
-
if (n.trailingComments && n.trailingComments.length > 0) {
|
|
2287
|
-
return { ...result, trailingComments: n.trailingComments };
|
|
2288
|
-
}
|
|
2289
|
-
return result;
|
|
2435
|
+
if (start === node.start && end === node.end)
|
|
2436
|
+
return node;
|
|
2437
|
+
return preserveComments(node, rangeExpr(start, end, node.inclusive));
|
|
2290
2438
|
}
|
|
2291
|
-
|
|
2439
|
+
case 14 /* PipeExpression */: {
|
|
2440
|
+
const value = recurse(node.value);
|
|
2441
|
+
const optimizedArgs = node.args.map(recurse);
|
|
2442
|
+
if (value === node.value && unchangedArray(node.args, optimizedArgs))
|
|
2443
|
+
return node;
|
|
2444
|
+
return preserveComments(node, pipeExpr(value, node.name, optimizedArgs));
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2292
2447
|
}
|
|
2293
2448
|
// src/stdlib/array.ts
|
|
2294
2449
|
var exports_array = {};
|
|
@@ -2296,52 +2451,11 @@ __export(exports_array, {
|
|
|
2296
2451
|
ARR_UNIQUE: () => ARR_UNIQUE,
|
|
2297
2452
|
ARR_SUM: () => ARR_SUM,
|
|
2298
2453
|
ARR_SORT: () => ARR_SORT,
|
|
2299
|
-
ARR_SLICE: () => ARR_SLICE,
|
|
2300
|
-
ARR_REVERSE: () => ARR_REVERSE,
|
|
2301
|
-
ARR_PUSH: () => ARR_PUSH,
|
|
2302
2454
|
ARR_MIN: () => ARR_MIN,
|
|
2303
2455
|
ARR_MAX: () => ARR_MAX,
|
|
2304
|
-
ARR_LEN: () => ARR_LEN,
|
|
2305
2456
|
ARR_JOIN: () => ARR_JOIN,
|
|
2306
|
-
ARR_FLAT: () => ARR_FLAT
|
|
2307
|
-
ARR_CONTAINS: () => ARR_CONTAINS
|
|
2457
|
+
ARR_FLAT: () => ARR_FLAT
|
|
2308
2458
|
});
|
|
2309
|
-
var ARR_LEN = (a) => {
|
|
2310
|
-
assertArray(a, "ARR_LEN");
|
|
2311
|
-
return a.length;
|
|
2312
|
-
};
|
|
2313
|
-
var ARR_PUSH = (a, value) => {
|
|
2314
|
-
assertArray(a, "ARR_PUSH");
|
|
2315
|
-
if (a.length > 0) {
|
|
2316
|
-
const elemType = typeOf(a[0]);
|
|
2317
|
-
const valType = typeOf(value);
|
|
2318
|
-
if (elemType !== valType) {
|
|
2319
|
-
throw new TypeError(`ARR_PUSH: cannot push ${valType} into array<${elemType}>`);
|
|
2320
|
-
}
|
|
2321
|
-
}
|
|
2322
|
-
return [...a, value];
|
|
2323
|
-
};
|
|
2324
|
-
var ARR_SLICE = (a, start, end) => {
|
|
2325
|
-
assertArray(a, "ARR_SLICE");
|
|
2326
|
-
assertNumber(start, "ARR_SLICE", "start");
|
|
2327
|
-
if (end !== undefined) {
|
|
2328
|
-
assertNumber(end, "ARR_SLICE", "end");
|
|
2329
|
-
return a.slice(start, end);
|
|
2330
|
-
}
|
|
2331
|
-
return a.slice(start);
|
|
2332
|
-
};
|
|
2333
|
-
var ARR_CONTAINS = (a, value) => {
|
|
2334
|
-
assertArray(a, "ARR_CONTAINS");
|
|
2335
|
-
for (const elem of a) {
|
|
2336
|
-
if (deepEquals(elem, value))
|
|
2337
|
-
return true;
|
|
2338
|
-
}
|
|
2339
|
-
return false;
|
|
2340
|
-
};
|
|
2341
|
-
var ARR_REVERSE = (a) => {
|
|
2342
|
-
assertArray(a, "ARR_REVERSE");
|
|
2343
|
-
return [...a].reverse();
|
|
2344
|
-
};
|
|
2345
2459
|
var ARR_SORT = (a) => {
|
|
2346
2460
|
assertArray(a, "ARR_SORT");
|
|
2347
2461
|
if (a.length <= 1)
|
|
@@ -2473,7 +2587,12 @@ var exports_core = {};
|
|
|
2473
2587
|
__export(exports_core, {
|
|
2474
2588
|
TYPE: () => TYPE,
|
|
2475
2589
|
STR: () => STR,
|
|
2476
|
-
|
|
2590
|
+
SLICE: () => SLICE,
|
|
2591
|
+
REVERSE: () => REVERSE,
|
|
2592
|
+
NUM: () => NUM,
|
|
2593
|
+
LEN: () => LEN,
|
|
2594
|
+
INDEX_OF: () => INDEX_OF,
|
|
2595
|
+
CONTAINS: () => CONTAINS
|
|
2477
2596
|
});
|
|
2478
2597
|
var STR = (v) => {
|
|
2479
2598
|
if (typeof v === "string")
|
|
@@ -2504,31 +2623,81 @@ var NUM = (v) => {
|
|
|
2504
2623
|
var TYPE = (v) => {
|
|
2505
2624
|
return typeOf(v);
|
|
2506
2625
|
};
|
|
2626
|
+
function assertStringOrArray(v, context) {
|
|
2627
|
+
if (typeof v !== "string" && !Array.isArray(v)) {
|
|
2628
|
+
throw new TypeError(`${context} expected string or array, got ${typeOf(v)}`);
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
var LEN = (v) => {
|
|
2632
|
+
assertStringOrArray(v, "LEN");
|
|
2633
|
+
return v.length;
|
|
2634
|
+
};
|
|
2635
|
+
var SLICE = (v, start, end) => {
|
|
2636
|
+
assertStringOrArray(v, "SLICE");
|
|
2637
|
+
assertNumber(start, "SLICE", "start");
|
|
2638
|
+
if (end !== undefined) {
|
|
2639
|
+
assertNumber(end, "SLICE", "end");
|
|
2640
|
+
return v.slice(start, end);
|
|
2641
|
+
}
|
|
2642
|
+
return v.slice(start);
|
|
2643
|
+
};
|
|
2644
|
+
var CONTAINS = (v, search) => {
|
|
2645
|
+
assertStringOrArray(v, "CONTAINS");
|
|
2646
|
+
if (typeof v === "string") {
|
|
2647
|
+
assertString(search, "CONTAINS (search)");
|
|
2648
|
+
return v.includes(search);
|
|
2649
|
+
}
|
|
2650
|
+
for (const elem of v) {
|
|
2651
|
+
if (deepEquals(elem, search))
|
|
2652
|
+
return true;
|
|
2653
|
+
}
|
|
2654
|
+
return false;
|
|
2655
|
+
};
|
|
2656
|
+
var REVERSE = (v) => {
|
|
2657
|
+
assertStringOrArray(v, "REVERSE");
|
|
2658
|
+
if (typeof v === "string") {
|
|
2659
|
+
return Array.from(v).reverse().join("");
|
|
2660
|
+
}
|
|
2661
|
+
return [...v].reverse();
|
|
2662
|
+
};
|
|
2663
|
+
var INDEX_OF = (v, search) => {
|
|
2664
|
+
assertStringOrArray(v, "INDEX_OF");
|
|
2665
|
+
if (typeof v === "string") {
|
|
2666
|
+
assertString(search, "INDEX_OF (search)");
|
|
2667
|
+
return v.indexOf(search);
|
|
2668
|
+
}
|
|
2669
|
+
for (let i = 0;i < v.length; i++) {
|
|
2670
|
+
if (deepEquals(v[i], search))
|
|
2671
|
+
return i;
|
|
2672
|
+
}
|
|
2673
|
+
return -1;
|
|
2674
|
+
};
|
|
2507
2675
|
|
|
2508
2676
|
// src/stdlib/datetime.ts
|
|
2509
2677
|
var exports_datetime = {};
|
|
2510
2678
|
__export(exports_datetime, {
|
|
2679
|
+
YEAR: () => YEAR,
|
|
2680
|
+
WEEKDAY: () => WEEKDAY,
|
|
2511
2681
|
TODAY: () => TODAY,
|
|
2512
2682
|
START_OF_YEAR: () => START_OF_YEAR,
|
|
2513
2683
|
START_OF_WEEK: () => START_OF_WEEK,
|
|
2514
2684
|
START_OF_QUARTER: () => START_OF_QUARTER,
|
|
2515
2685
|
START_OF_MONTH: () => START_OF_MONTH,
|
|
2686
|
+
QUARTER: () => QUARTER,
|
|
2687
|
+
MONTH: () => MONTH,
|
|
2516
2688
|
IS_WEEKEND: () => IS_WEEKEND,
|
|
2517
2689
|
IS_SAME_DAY: () => IS_SAME_DAY,
|
|
2518
2690
|
IS_LEAP_YEAR: () => IS_LEAP_YEAR,
|
|
2519
|
-
GET_YEAR: () => GET_YEAR,
|
|
2520
|
-
GET_WEEKDAY: () => GET_WEEKDAY,
|
|
2521
|
-
GET_QUARTER: () => GET_QUARTER,
|
|
2522
|
-
GET_MONTH: () => GET_MONTH,
|
|
2523
|
-
GET_DAY_OF_YEAR: () => GET_DAY_OF_YEAR,
|
|
2524
|
-
GET_DAY: () => GET_DAY,
|
|
2525
2691
|
END_OF_YEAR: () => END_OF_YEAR,
|
|
2526
2692
|
END_OF_MONTH: () => END_OF_MONTH,
|
|
2527
2693
|
DIFFERENCE_IN_YEARS: () => DIFFERENCE_IN_YEARS,
|
|
2528
2694
|
DIFFERENCE_IN_WEEKS: () => DIFFERENCE_IN_WEEKS,
|
|
2529
2695
|
DIFFERENCE_IN_MONTHS: () => DIFFERENCE_IN_MONTHS,
|
|
2530
2696
|
DIFFERENCE_IN_DAYS: () => DIFFERENCE_IN_DAYS,
|
|
2697
|
+
DAY_OF_YEAR: () => DAY_OF_YEAR,
|
|
2698
|
+
DAY: () => DAY,
|
|
2531
2699
|
DATE: () => DATE,
|
|
2700
|
+
AGE: () => AGE,
|
|
2532
2701
|
ADD_YEARS: () => ADD_YEARS,
|
|
2533
2702
|
ADD_MONTHS: () => ADD_MONTHS,
|
|
2534
2703
|
ADD_DAYS: () => ADD_DAYS
|
|
@@ -2540,28 +2709,28 @@ var DATE = (year, month, day) => {
|
|
|
2540
2709
|
assertNumber(day, "DATE", "day");
|
|
2541
2710
|
return new Temporal.PlainDate(year, month, day);
|
|
2542
2711
|
};
|
|
2543
|
-
var
|
|
2544
|
-
assertDateOrDateTime(date, "
|
|
2712
|
+
var YEAR = (date) => {
|
|
2713
|
+
assertDateOrDateTime(date, "YEAR");
|
|
2545
2714
|
return date.year;
|
|
2546
2715
|
};
|
|
2547
|
-
var
|
|
2548
|
-
assertDateOrDateTime(date, "
|
|
2716
|
+
var MONTH = (date) => {
|
|
2717
|
+
assertDateOrDateTime(date, "MONTH");
|
|
2549
2718
|
return date.month;
|
|
2550
2719
|
};
|
|
2551
|
-
var
|
|
2552
|
-
assertDateOrDateTime(date, "
|
|
2720
|
+
var DAY = (date) => {
|
|
2721
|
+
assertDateOrDateTime(date, "DAY");
|
|
2553
2722
|
return date.day;
|
|
2554
2723
|
};
|
|
2555
|
-
var
|
|
2556
|
-
assertDateOrDateTime(date, "
|
|
2724
|
+
var WEEKDAY = (date) => {
|
|
2725
|
+
assertDateOrDateTime(date, "WEEKDAY");
|
|
2557
2726
|
return date.dayOfWeek;
|
|
2558
2727
|
};
|
|
2559
|
-
var
|
|
2560
|
-
assertDateOrDateTime(date, "
|
|
2728
|
+
var DAY_OF_YEAR = (date) => {
|
|
2729
|
+
assertDateOrDateTime(date, "DAY_OF_YEAR");
|
|
2561
2730
|
return date.dayOfYear;
|
|
2562
2731
|
};
|
|
2563
|
-
var
|
|
2564
|
-
assertDateOrDateTime(date, "
|
|
2732
|
+
var QUARTER = (date) => {
|
|
2733
|
+
assertDateOrDateTime(date, "QUARTER");
|
|
2565
2734
|
return Math.ceil(date.month / 3);
|
|
2566
2735
|
};
|
|
2567
2736
|
var ADD_DAYS = (date, days) => {
|
|
@@ -2676,6 +2845,22 @@ var IS_LEAP_YEAR = (date) => {
|
|
|
2676
2845
|
assertDateOrDateTime(date, "IS_LEAP_YEAR");
|
|
2677
2846
|
return date.inLeapYear;
|
|
2678
2847
|
};
|
|
2848
|
+
var AGE = (birthDate, ...rest) => {
|
|
2849
|
+
assertDateOrDateTime(birthDate, "AGE");
|
|
2850
|
+
const birth = birthDate instanceof Temporal.PlainDateTime ? birthDate.toPlainDate() : birthDate;
|
|
2851
|
+
let reference;
|
|
2852
|
+
if (rest.length > 0) {
|
|
2853
|
+
const ref = rest[0];
|
|
2854
|
+
assertDateOrDateTime(ref, "AGE");
|
|
2855
|
+
reference = ref instanceof Temporal.PlainDateTime ? ref.toPlainDate() : ref;
|
|
2856
|
+
} else {
|
|
2857
|
+
reference = Temporal.Now.plainDateISO();
|
|
2858
|
+
}
|
|
2859
|
+
if (Temporal.PlainDate.compare(birth, reference) > 0) {
|
|
2860
|
+
throw new RangeError("AGE requires birth date to be on or before reference date");
|
|
2861
|
+
}
|
|
2862
|
+
return birth.until(reference, { largestUnit: "year" }).years;
|
|
2863
|
+
};
|
|
2679
2864
|
|
|
2680
2865
|
// src/stdlib/datetimefull.ts
|
|
2681
2866
|
var exports_datetimefull = {};
|
|
@@ -2822,19 +3007,11 @@ __export(exports_string, {
|
|
|
2822
3007
|
STR_TRIM: () => STR_TRIM,
|
|
2823
3008
|
STR_STARTS_WITH: () => STR_STARTS_WITH,
|
|
2824
3009
|
STR_SPLIT: () => STR_SPLIT,
|
|
2825
|
-
STR_SLICE: () => STR_SLICE,
|
|
2826
3010
|
STR_REPLACE: () => STR_REPLACE,
|
|
2827
3011
|
STR_REPEAT: () => STR_REPEAT,
|
|
2828
3012
|
STR_LOWER: () => STR_LOWER,
|
|
2829
|
-
|
|
2830
|
-
STR_INDEX_OF: () => STR_INDEX_OF,
|
|
2831
|
-
STR_ENDS_WITH: () => STR_ENDS_WITH,
|
|
2832
|
-
STR_CONTAINS: () => STR_CONTAINS
|
|
3013
|
+
STR_ENDS_WITH: () => STR_ENDS_WITH
|
|
2833
3014
|
});
|
|
2834
|
-
var STR_LEN = (s) => {
|
|
2835
|
-
assertString(s, "STR_LEN");
|
|
2836
|
-
return s.length;
|
|
2837
|
-
};
|
|
2838
3015
|
var STR_UPPER = (s) => {
|
|
2839
3016
|
assertString(s, "STR_UPPER");
|
|
2840
3017
|
return s.toUpperCase();
|
|
@@ -2847,25 +3024,6 @@ var STR_TRIM = (s) => {
|
|
|
2847
3024
|
assertString(s, "STR_TRIM");
|
|
2848
3025
|
return s.trim();
|
|
2849
3026
|
};
|
|
2850
|
-
var STR_SLICE = (s, start, end) => {
|
|
2851
|
-
assertString(s, "STR_SLICE");
|
|
2852
|
-
assertNumber(start, "STR_SLICE", "start");
|
|
2853
|
-
if (end !== undefined) {
|
|
2854
|
-
assertNumber(end, "STR_SLICE", "end");
|
|
2855
|
-
return s.slice(start, end);
|
|
2856
|
-
}
|
|
2857
|
-
return s.slice(start);
|
|
2858
|
-
};
|
|
2859
|
-
var STR_CONTAINS = (s, search) => {
|
|
2860
|
-
assertString(s, "STR_CONTAINS");
|
|
2861
|
-
assertString(search, "STR_CONTAINS");
|
|
2862
|
-
return s.includes(search);
|
|
2863
|
-
};
|
|
2864
|
-
var STR_INDEX_OF = (s, search) => {
|
|
2865
|
-
assertString(s, "STR_INDEX_OF");
|
|
2866
|
-
assertString(search, "STR_INDEX_OF");
|
|
2867
|
-
return s.indexOf(search);
|
|
2868
|
-
};
|
|
2869
3027
|
var STR_SPLIT = (s, sep) => {
|
|
2870
3028
|
assertString(s, "STR_SPLIT");
|
|
2871
3029
|
assertString(sep, "STR_SPLIT (separator)");
|
|
@@ -2900,12 +3058,12 @@ var STR_REPEAT = (s, count) => {
|
|
|
2900
3058
|
var exports_time = {};
|
|
2901
3059
|
__export(exports_time, {
|
|
2902
3060
|
TIME: () => TIME,
|
|
3061
|
+
SECOND: () => SECOND,
|
|
2903
3062
|
NOW_TIME: () => NOW_TIME,
|
|
3063
|
+
MINUTE: () => MINUTE,
|
|
3064
|
+
MILLISECOND: () => MILLISECOND,
|
|
2904
3065
|
IS_SAME_TIME: () => IS_SAME_TIME,
|
|
2905
|
-
|
|
2906
|
-
GET_MINUTE: () => GET_MINUTE,
|
|
2907
|
-
GET_MILLISECOND: () => GET_MILLISECOND,
|
|
2908
|
-
GET_HOUR: () => GET_HOUR,
|
|
3066
|
+
HOUR: () => HOUR,
|
|
2909
3067
|
DIFFERENCE_IN_SECONDS: () => DIFFERENCE_IN_SECONDS,
|
|
2910
3068
|
DIFFERENCE_IN_MINUTES: () => DIFFERENCE_IN_MINUTES,
|
|
2911
3069
|
DIFFERENCE_IN_HOURS: () => DIFFERENCE_IN_HOURS,
|
|
@@ -2920,20 +3078,20 @@ var TIME = (hour, minute, second) => {
|
|
|
2920
3078
|
return new Temporal.PlainTime(hour, minute, second);
|
|
2921
3079
|
};
|
|
2922
3080
|
var NOW_TIME = () => Temporal.Now.plainTimeISO();
|
|
2923
|
-
var
|
|
2924
|
-
assertTimeOrDateTime(t, "
|
|
3081
|
+
var HOUR = (t) => {
|
|
3082
|
+
assertTimeOrDateTime(t, "HOUR");
|
|
2925
3083
|
return t.hour;
|
|
2926
3084
|
};
|
|
2927
|
-
var
|
|
2928
|
-
assertTimeOrDateTime(t, "
|
|
3085
|
+
var MINUTE = (t) => {
|
|
3086
|
+
assertTimeOrDateTime(t, "MINUTE");
|
|
2929
3087
|
return t.minute;
|
|
2930
3088
|
};
|
|
2931
|
-
var
|
|
2932
|
-
assertTimeOrDateTime(t, "
|
|
3089
|
+
var SECOND = (t) => {
|
|
3090
|
+
assertTimeOrDateTime(t, "SECOND");
|
|
2933
3091
|
return t.second;
|
|
2934
3092
|
};
|
|
2935
|
-
var
|
|
2936
|
-
assertTimeOrDateTime(t, "
|
|
3093
|
+
var MILLISECOND = (t) => {
|
|
3094
|
+
assertTimeOrDateTime(t, "MILLISECOND");
|
|
2937
3095
|
return t.millisecond;
|
|
2938
3096
|
};
|
|
2939
3097
|
var ADD_HOURS = (t, hours) => {
|
|
@@ -3016,9 +3174,9 @@ var defaultContext = {
|
|
|
3016
3174
|
}
|
|
3017
3175
|
};
|
|
3018
3176
|
export {
|
|
3019
|
-
visitPartial,
|
|
3020
3177
|
visit,
|
|
3021
3178
|
typeOf,
|
|
3179
|
+
toLineColumn,
|
|
3022
3180
|
exports_time as time,
|
|
3023
3181
|
exports_string as string,
|
|
3024
3182
|
parse,
|
|
@@ -3043,6 +3201,7 @@ export {
|
|
|
3043
3201
|
generate,
|
|
3044
3202
|
extractInputVariables,
|
|
3045
3203
|
extractAssignedVariables,
|
|
3204
|
+
evaluateWithScope,
|
|
3046
3205
|
evaluateScope,
|
|
3047
3206
|
evaluate,
|
|
3048
3207
|
defaultContext,
|
|
@@ -3060,5 +3219,6 @@ export {
|
|
|
3060
3219
|
assertBoolean,
|
|
3061
3220
|
assertArray,
|
|
3062
3221
|
exports_array as array,
|
|
3222
|
+
ParseError,
|
|
3063
3223
|
NodeKind
|
|
3064
3224
|
};
|