@huggingface/transformers 3.6.2 → 3.6.3
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 +2 -2
- package/dist/transformers.js +709 -307
- package/dist/transformers.js.map +1 -1
- package/dist/transformers.min.js +1 -1
- package/dist/transformers.min.js.map +1 -1
- package/dist/transformers.node.cjs +709 -307
- package/dist/transformers.node.cjs.map +1 -1
- package/dist/transformers.node.min.cjs +1 -1
- package/dist/transformers.node.min.cjs.map +1 -1
- package/dist/transformers.node.min.mjs +1 -1
- package/dist/transformers.node.min.mjs.map +1 -1
- package/dist/transformers.node.mjs +709 -307
- package/dist/transformers.node.mjs.map +1 -1
- package/dist/transformers.web.js +709 -307
- package/dist/transformers.web.js.map +1 -1
- package/dist/transformers.web.min.js +1 -1
- package/dist/transformers.web.min.js.map +1 -1
- package/package.json +2 -2
- package/src/env.js +1 -1
package/dist/transformers.web.js
CHANGED
|
@@ -111,15 +111,11 @@ var TOKEN_TYPES = Object.freeze({
|
|
|
111
111
|
Text: "Text",
|
|
112
112
|
// The text between Jinja statements or expressions
|
|
113
113
|
NumericLiteral: "NumericLiteral",
|
|
114
|
-
// e.g., 123
|
|
115
|
-
BooleanLiteral: "BooleanLiteral",
|
|
116
|
-
// true or false
|
|
117
|
-
NullLiteral: "NullLiteral",
|
|
118
|
-
// none
|
|
114
|
+
// e.g., 123, 1.0
|
|
119
115
|
StringLiteral: "StringLiteral",
|
|
120
116
|
// 'string'
|
|
121
117
|
Identifier: "Identifier",
|
|
122
|
-
// Variables, functions, etc.
|
|
118
|
+
// Variables, functions, statements, booleans, etc.
|
|
123
119
|
Equals: "Equals",
|
|
124
120
|
// =
|
|
125
121
|
OpenParen: "OpenParen",
|
|
@@ -153,63 +149,15 @@ var TOKEN_TYPES = Object.freeze({
|
|
|
153
149
|
CallOperator: "CallOperator",
|
|
154
150
|
// ()
|
|
155
151
|
AdditiveBinaryOperator: "AdditiveBinaryOperator",
|
|
156
|
-
// + -
|
|
152
|
+
// + - ~
|
|
157
153
|
MultiplicativeBinaryOperator: "MultiplicativeBinaryOperator",
|
|
158
154
|
// * / %
|
|
159
155
|
ComparisonBinaryOperator: "ComparisonBinaryOperator",
|
|
160
156
|
// < > <= >= == !=
|
|
161
157
|
UnaryOperator: "UnaryOperator",
|
|
162
158
|
// ! - +
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
If: "If",
|
|
166
|
-
For: "For",
|
|
167
|
-
In: "In",
|
|
168
|
-
Is: "Is",
|
|
169
|
-
NotIn: "NotIn",
|
|
170
|
-
Else: "Else",
|
|
171
|
-
EndSet: "EndSet",
|
|
172
|
-
EndIf: "EndIf",
|
|
173
|
-
ElseIf: "ElseIf",
|
|
174
|
-
EndFor: "EndFor",
|
|
175
|
-
And: "And",
|
|
176
|
-
Or: "Or",
|
|
177
|
-
Not: "UnaryOperator",
|
|
178
|
-
Macro: "Macro",
|
|
179
|
-
EndMacro: "EndMacro",
|
|
180
|
-
Break: "Break",
|
|
181
|
-
Continue: "Continue"
|
|
182
|
-
});
|
|
183
|
-
var KEYWORDS = Object.freeze({
|
|
184
|
-
set: TOKEN_TYPES.Set,
|
|
185
|
-
for: TOKEN_TYPES.For,
|
|
186
|
-
in: TOKEN_TYPES.In,
|
|
187
|
-
is: TOKEN_TYPES.Is,
|
|
188
|
-
if: TOKEN_TYPES.If,
|
|
189
|
-
else: TOKEN_TYPES.Else,
|
|
190
|
-
endset: TOKEN_TYPES.EndSet,
|
|
191
|
-
endif: TOKEN_TYPES.EndIf,
|
|
192
|
-
elif: TOKEN_TYPES.ElseIf,
|
|
193
|
-
endfor: TOKEN_TYPES.EndFor,
|
|
194
|
-
and: TOKEN_TYPES.And,
|
|
195
|
-
or: TOKEN_TYPES.Or,
|
|
196
|
-
not: TOKEN_TYPES.Not,
|
|
197
|
-
"not in": TOKEN_TYPES.NotIn,
|
|
198
|
-
macro: TOKEN_TYPES.Macro,
|
|
199
|
-
endmacro: TOKEN_TYPES.EndMacro,
|
|
200
|
-
break: TOKEN_TYPES.Break,
|
|
201
|
-
continue: TOKEN_TYPES.Continue,
|
|
202
|
-
// Literals
|
|
203
|
-
true: TOKEN_TYPES.BooleanLiteral,
|
|
204
|
-
false: TOKEN_TYPES.BooleanLiteral,
|
|
205
|
-
none: TOKEN_TYPES.NullLiteral,
|
|
206
|
-
// NOTE: According to the Jinja docs: The special constants true, false, and none are indeed lowercase.
|
|
207
|
-
// Because that caused confusion in the past, (True used to expand to an undefined variable that was considered false),
|
|
208
|
-
// all three can now also be written in title case (True, False, and None). However, for consistency, (all Jinja identifiers are lowercase)
|
|
209
|
-
// you should use the lowercase versions.
|
|
210
|
-
True: TOKEN_TYPES.BooleanLiteral,
|
|
211
|
-
False: TOKEN_TYPES.BooleanLiteral,
|
|
212
|
-
None: TOKEN_TYPES.NullLiteral
|
|
159
|
+
Comment: "Comment"
|
|
160
|
+
// {# ... #}
|
|
213
161
|
});
|
|
214
162
|
var Token = class {
|
|
215
163
|
/**
|
|
@@ -255,6 +203,7 @@ var ORDERED_MAPPING_TABLE = [
|
|
|
255
203
|
// Arithmetic operators
|
|
256
204
|
["+", TOKEN_TYPES.AdditiveBinaryOperator],
|
|
257
205
|
["-", TOKEN_TYPES.AdditiveBinaryOperator],
|
|
206
|
+
["~", TOKEN_TYPES.AdditiveBinaryOperator],
|
|
258
207
|
["*", TOKEN_TYPES.MultiplicativeBinaryOperator],
|
|
259
208
|
["/", TOKEN_TYPES.MultiplicativeBinaryOperator],
|
|
260
209
|
["%", TOKEN_TYPES.MultiplicativeBinaryOperator],
|
|
@@ -285,19 +234,19 @@ function preprocess(template, options = {}) {
|
|
|
285
234
|
if (template.endsWith("\n")) {
|
|
286
235
|
template = template.slice(0, -1);
|
|
287
236
|
}
|
|
288
|
-
template = template.replace(/{#.*?#}/gs, "{##}");
|
|
289
237
|
if (options.lstrip_blocks) {
|
|
290
|
-
template = template.replace(/^[ \t]*({[
|
|
238
|
+
template = template.replace(/^[ \t]*({[#%-])/gm, "$1");
|
|
291
239
|
}
|
|
292
240
|
if (options.trim_blocks) {
|
|
293
|
-
template = template.replace(/([
|
|
241
|
+
template = template.replace(/([#%-]})\n/g, "$1");
|
|
294
242
|
}
|
|
295
|
-
return template.replace(
|
|
243
|
+
return template.replace(/-%}\s*/g, "%}").replace(/\s*{%-/g, "{%").replace(/-}}\s*/g, "}}").replace(/\s*{{-/g, "{{").replace(/-#}\s*/g, "#}").replace(/\s*{#-/g, "{#").replace(/{%\s*(end)?generation\s*%}/gs, "");
|
|
296
244
|
}
|
|
297
245
|
function tokenize(source, options = {}) {
|
|
298
246
|
const tokens = [];
|
|
299
247
|
const src = preprocess(source, options);
|
|
300
248
|
let cursorPosition = 0;
|
|
249
|
+
let curlyBracketDepth = 0;
|
|
301
250
|
const consumeWhile = (predicate) => {
|
|
302
251
|
let str = "";
|
|
303
252
|
while (predicate(src[cursorPosition])) {
|
|
@@ -322,10 +271,10 @@ function tokenize(source, options = {}) {
|
|
|
322
271
|
main:
|
|
323
272
|
while (cursorPosition < src.length) {
|
|
324
273
|
const lastTokenType = tokens.at(-1)?.type;
|
|
325
|
-
if (lastTokenType === void 0 || lastTokenType === TOKEN_TYPES.CloseStatement || lastTokenType === TOKEN_TYPES.CloseExpression) {
|
|
274
|
+
if (lastTokenType === void 0 || lastTokenType === TOKEN_TYPES.CloseStatement || lastTokenType === TOKEN_TYPES.CloseExpression || lastTokenType === TOKEN_TYPES.Comment) {
|
|
326
275
|
let text = "";
|
|
327
276
|
while (cursorPosition < src.length && // Keep going until we hit the next Jinja statement or expression
|
|
328
|
-
!(src[cursorPosition] === "{" && (src[cursorPosition + 1] === "%" || src[cursorPosition + 1] === "{"))) {
|
|
277
|
+
!(src[cursorPosition] === "{" && (src[cursorPosition + 1] === "%" || src[cursorPosition + 1] === "{" || src[cursorPosition + 1] === "#"))) {
|
|
329
278
|
text += src[cursorPosition++];
|
|
330
279
|
}
|
|
331
280
|
if (text.length > 0) {
|
|
@@ -333,6 +282,19 @@ function tokenize(source, options = {}) {
|
|
|
333
282
|
continue;
|
|
334
283
|
}
|
|
335
284
|
}
|
|
285
|
+
if (src[cursorPosition] === "{" && src[cursorPosition + 1] === "#") {
|
|
286
|
+
cursorPosition += 2;
|
|
287
|
+
let comment = "";
|
|
288
|
+
while (src[cursorPosition] !== "#" || src[cursorPosition + 1] !== "}") {
|
|
289
|
+
if (cursorPosition + 2 >= src.length) {
|
|
290
|
+
throw new SyntaxError("Missing end of comment tag");
|
|
291
|
+
}
|
|
292
|
+
comment += src[cursorPosition++];
|
|
293
|
+
}
|
|
294
|
+
tokens.push(new Token(comment, TOKEN_TYPES.Comment));
|
|
295
|
+
cursorPosition += 2;
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
336
298
|
consumeWhile((char2) => /\s/.test(char2));
|
|
337
299
|
const char = src[cursorPosition];
|
|
338
300
|
if (char === "-" || char === "+") {
|
|
@@ -343,8 +305,6 @@ function tokenize(source, options = {}) {
|
|
|
343
305
|
switch (lastTokenType2) {
|
|
344
306
|
case TOKEN_TYPES.Identifier:
|
|
345
307
|
case TOKEN_TYPES.NumericLiteral:
|
|
346
|
-
case TOKEN_TYPES.BooleanLiteral:
|
|
347
|
-
case TOKEN_TYPES.NullLiteral:
|
|
348
308
|
case TOKEN_TYPES.StringLiteral:
|
|
349
309
|
case TOKEN_TYPES.CloseParen:
|
|
350
310
|
case TOKEN_TYPES.CloseSquareBracket:
|
|
@@ -359,11 +319,21 @@ function tokenize(source, options = {}) {
|
|
|
359
319
|
}
|
|
360
320
|
}
|
|
361
321
|
}
|
|
362
|
-
for (const [
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
322
|
+
for (const [seq, type] of ORDERED_MAPPING_TABLE) {
|
|
323
|
+
if (seq === "}}" && curlyBracketDepth > 0) {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const slice2 = src.slice(cursorPosition, cursorPosition + seq.length);
|
|
327
|
+
if (slice2 === seq) {
|
|
328
|
+
tokens.push(new Token(seq, type));
|
|
329
|
+
if (type === TOKEN_TYPES.OpenExpression) {
|
|
330
|
+
curlyBracketDepth = 0;
|
|
331
|
+
} else if (type === TOKEN_TYPES.OpenCurlyBracket) {
|
|
332
|
+
++curlyBracketDepth;
|
|
333
|
+
} else if (type === TOKEN_TYPES.CloseCurlyBracket) {
|
|
334
|
+
--curlyBracketDepth;
|
|
335
|
+
}
|
|
336
|
+
cursorPosition += seq.length;
|
|
367
337
|
continue main;
|
|
368
338
|
}
|
|
369
339
|
}
|
|
@@ -375,19 +345,18 @@ function tokenize(source, options = {}) {
|
|
|
375
345
|
continue;
|
|
376
346
|
}
|
|
377
347
|
if (isInteger(char)) {
|
|
378
|
-
|
|
348
|
+
let num = consumeWhile(isInteger);
|
|
349
|
+
if (src[cursorPosition] === "." && isInteger(src[cursorPosition + 1])) {
|
|
350
|
+
++cursorPosition;
|
|
351
|
+
const frac = consumeWhile(isInteger);
|
|
352
|
+
num = `${num}.${frac}`;
|
|
353
|
+
}
|
|
379
354
|
tokens.push(new Token(num, TOKEN_TYPES.NumericLiteral));
|
|
380
355
|
continue;
|
|
381
356
|
}
|
|
382
357
|
if (isWord(char)) {
|
|
383
358
|
const word = consumeWhile(isWord);
|
|
384
|
-
|
|
385
|
-
if (type === TOKEN_TYPES.In && tokens.at(-1)?.type === TOKEN_TYPES.Not) {
|
|
386
|
-
tokens.pop();
|
|
387
|
-
tokens.push(new Token("not in", TOKEN_TYPES.NotIn));
|
|
388
|
-
} else {
|
|
389
|
-
tokens.push(new Token(word, type));
|
|
390
|
-
}
|
|
359
|
+
tokens.push(new Token(word, TOKEN_TYPES.Identifier));
|
|
391
360
|
continue;
|
|
392
361
|
}
|
|
393
362
|
throw new SyntaxError(`Unexpected character: ${char}`);
|
|
@@ -449,6 +418,13 @@ var Macro = class extends Statement {
|
|
|
449
418
|
}
|
|
450
419
|
type = "Macro";
|
|
451
420
|
};
|
|
421
|
+
var Comment = class extends Statement {
|
|
422
|
+
constructor(value) {
|
|
423
|
+
super();
|
|
424
|
+
this.value = value;
|
|
425
|
+
}
|
|
426
|
+
type = "Comment";
|
|
427
|
+
};
|
|
452
428
|
var Expression = class extends Statement {
|
|
453
429
|
type = "Expression";
|
|
454
430
|
};
|
|
@@ -486,18 +462,15 @@ var Literal = class extends Expression {
|
|
|
486
462
|
}
|
|
487
463
|
type = "Literal";
|
|
488
464
|
};
|
|
489
|
-
var
|
|
490
|
-
type = "
|
|
465
|
+
var IntegerLiteral = class extends Literal {
|
|
466
|
+
type = "IntegerLiteral";
|
|
467
|
+
};
|
|
468
|
+
var FloatLiteral = class extends Literal {
|
|
469
|
+
type = "FloatLiteral";
|
|
491
470
|
};
|
|
492
471
|
var StringLiteral = class extends Literal {
|
|
493
472
|
type = "StringLiteral";
|
|
494
473
|
};
|
|
495
|
-
var BooleanLiteral = class extends Literal {
|
|
496
|
-
type = "BooleanLiteral";
|
|
497
|
-
};
|
|
498
|
-
var NullLiteral = class extends Literal {
|
|
499
|
-
type = "NullLiteral";
|
|
500
|
-
};
|
|
501
474
|
var ArrayLiteral = class extends Literal {
|
|
502
475
|
type = "ArrayLiteral";
|
|
503
476
|
};
|
|
@@ -524,10 +497,18 @@ var FilterExpression = class extends Expression {
|
|
|
524
497
|
}
|
|
525
498
|
type = "FilterExpression";
|
|
526
499
|
};
|
|
500
|
+
var FilterStatement = class extends Statement {
|
|
501
|
+
constructor(filter, body) {
|
|
502
|
+
super();
|
|
503
|
+
this.filter = filter;
|
|
504
|
+
this.body = body;
|
|
505
|
+
}
|
|
506
|
+
type = "FilterStatement";
|
|
507
|
+
};
|
|
527
508
|
var SelectExpression = class extends Expression {
|
|
528
|
-
constructor(
|
|
509
|
+
constructor(lhs, test) {
|
|
529
510
|
super();
|
|
530
|
-
this.
|
|
511
|
+
this.lhs = lhs;
|
|
531
512
|
this.test = test;
|
|
532
513
|
}
|
|
533
514
|
type = "SelectExpression";
|
|
@@ -566,6 +547,31 @@ var KeywordArgumentExpression = class extends Expression {
|
|
|
566
547
|
}
|
|
567
548
|
type = "KeywordArgumentExpression";
|
|
568
549
|
};
|
|
550
|
+
var SpreadExpression = class extends Expression {
|
|
551
|
+
constructor(argument) {
|
|
552
|
+
super();
|
|
553
|
+
this.argument = argument;
|
|
554
|
+
}
|
|
555
|
+
type = "SpreadExpression";
|
|
556
|
+
};
|
|
557
|
+
var CallStatement = class extends Statement {
|
|
558
|
+
constructor(call, callerArgs, body) {
|
|
559
|
+
super();
|
|
560
|
+
this.call = call;
|
|
561
|
+
this.callerArgs = callerArgs;
|
|
562
|
+
this.body = body;
|
|
563
|
+
}
|
|
564
|
+
type = "CallStatement";
|
|
565
|
+
};
|
|
566
|
+
var Ternary = class extends Expression {
|
|
567
|
+
constructor(condition, trueExpr, falseExpr) {
|
|
568
|
+
super();
|
|
569
|
+
this.condition = condition;
|
|
570
|
+
this.trueExpr = trueExpr;
|
|
571
|
+
this.falseExpr = falseExpr;
|
|
572
|
+
}
|
|
573
|
+
type = "Ternary";
|
|
574
|
+
};
|
|
569
575
|
|
|
570
576
|
// src/parser.ts
|
|
571
577
|
function parse(tokens) {
|
|
@@ -578,8 +584,16 @@ function parse(tokens) {
|
|
|
578
584
|
}
|
|
579
585
|
return prev;
|
|
580
586
|
}
|
|
587
|
+
function expectIdentifier(name) {
|
|
588
|
+
if (!isIdentifier(name)) {
|
|
589
|
+
throw new SyntaxError(`Expected ${name}`);
|
|
590
|
+
}
|
|
591
|
+
++current;
|
|
592
|
+
}
|
|
581
593
|
function parseAny() {
|
|
582
594
|
switch (tokens[current].type) {
|
|
595
|
+
case TOKEN_TYPES.Comment:
|
|
596
|
+
return new Comment(tokens[current++].value);
|
|
583
597
|
case TOKEN_TYPES.Text:
|
|
584
598
|
return parseText();
|
|
585
599
|
case TOKEN_TYPES.OpenStatement:
|
|
@@ -590,57 +604,103 @@ function parse(tokens) {
|
|
|
590
604
|
throw new SyntaxError(`Unexpected token type: ${tokens[current].type}`);
|
|
591
605
|
}
|
|
592
606
|
}
|
|
593
|
-
function not(...types) {
|
|
594
|
-
return current + types.length <= tokens.length && types.some((type, i) => type !== tokens[current + i].type);
|
|
595
|
-
}
|
|
596
607
|
function is(...types) {
|
|
597
608
|
return current + types.length <= tokens.length && types.every((type, i) => type === tokens[current + i].type);
|
|
598
609
|
}
|
|
610
|
+
function isStatement(...names) {
|
|
611
|
+
return tokens[current]?.type === TOKEN_TYPES.OpenStatement && tokens[current + 1]?.type === TOKEN_TYPES.Identifier && names.includes(tokens[current + 1]?.value);
|
|
612
|
+
}
|
|
613
|
+
function isIdentifier(...names) {
|
|
614
|
+
return current + names.length <= tokens.length && names.every((name, i) => tokens[current + i].type === "Identifier" && name === tokens[current + i].value);
|
|
615
|
+
}
|
|
599
616
|
function parseText() {
|
|
600
617
|
return new StringLiteral(expect(TOKEN_TYPES.Text, "Expected text token").value);
|
|
601
618
|
}
|
|
602
619
|
function parseJinjaStatement() {
|
|
603
620
|
expect(TOKEN_TYPES.OpenStatement, "Expected opening statement token");
|
|
621
|
+
if (tokens[current].type !== TOKEN_TYPES.Identifier) {
|
|
622
|
+
throw new SyntaxError(`Unknown statement, got ${tokens[current].type}`);
|
|
623
|
+
}
|
|
624
|
+
const name = tokens[current].value;
|
|
604
625
|
let result;
|
|
605
|
-
switch (
|
|
606
|
-
case
|
|
626
|
+
switch (name) {
|
|
627
|
+
case "set":
|
|
607
628
|
++current;
|
|
608
629
|
result = parseSetStatement();
|
|
609
|
-
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
610
630
|
break;
|
|
611
|
-
case
|
|
631
|
+
case "if":
|
|
612
632
|
++current;
|
|
613
633
|
result = parseIfStatement();
|
|
614
634
|
expect(TOKEN_TYPES.OpenStatement, "Expected {% token");
|
|
615
|
-
|
|
635
|
+
expectIdentifier("endif");
|
|
616
636
|
expect(TOKEN_TYPES.CloseStatement, "Expected %} token");
|
|
617
637
|
break;
|
|
618
|
-
case
|
|
638
|
+
case "macro":
|
|
619
639
|
++current;
|
|
620
640
|
result = parseMacroStatement();
|
|
621
641
|
expect(TOKEN_TYPES.OpenStatement, "Expected {% token");
|
|
622
|
-
|
|
642
|
+
expectIdentifier("endmacro");
|
|
623
643
|
expect(TOKEN_TYPES.CloseStatement, "Expected %} token");
|
|
624
644
|
break;
|
|
625
|
-
case
|
|
645
|
+
case "for":
|
|
626
646
|
++current;
|
|
627
647
|
result = parseForStatement();
|
|
628
648
|
expect(TOKEN_TYPES.OpenStatement, "Expected {% token");
|
|
629
|
-
|
|
649
|
+
expectIdentifier("endfor");
|
|
630
650
|
expect(TOKEN_TYPES.CloseStatement, "Expected %} token");
|
|
631
651
|
break;
|
|
632
|
-
case
|
|
652
|
+
case "call": {
|
|
653
|
+
++current;
|
|
654
|
+
let callerArgs = null;
|
|
655
|
+
if (is(TOKEN_TYPES.OpenParen)) {
|
|
656
|
+
callerArgs = parseArgs();
|
|
657
|
+
}
|
|
658
|
+
const callee = parsePrimaryExpression();
|
|
659
|
+
if (callee.type !== "Identifier") {
|
|
660
|
+
throw new SyntaxError(`Expected identifier following call statement`);
|
|
661
|
+
}
|
|
662
|
+
const callArgs = parseArgs();
|
|
663
|
+
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
664
|
+
const body = [];
|
|
665
|
+
while (!isStatement("endcall")) {
|
|
666
|
+
body.push(parseAny());
|
|
667
|
+
}
|
|
668
|
+
expect(TOKEN_TYPES.OpenStatement, "Expected '{%'");
|
|
669
|
+
expectIdentifier("endcall");
|
|
670
|
+
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
671
|
+
const callExpr = new CallExpression(callee, callArgs);
|
|
672
|
+
result = new CallStatement(callExpr, callerArgs, body);
|
|
673
|
+
break;
|
|
674
|
+
}
|
|
675
|
+
case "break":
|
|
633
676
|
++current;
|
|
634
677
|
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
635
678
|
result = new Break();
|
|
636
679
|
break;
|
|
637
|
-
case
|
|
680
|
+
case "continue":
|
|
638
681
|
++current;
|
|
639
682
|
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
640
683
|
result = new Continue();
|
|
641
684
|
break;
|
|
685
|
+
case "filter": {
|
|
686
|
+
++current;
|
|
687
|
+
let filterNode = parsePrimaryExpression();
|
|
688
|
+
if (filterNode instanceof Identifier && is(TOKEN_TYPES.OpenParen)) {
|
|
689
|
+
filterNode = parseCallExpression(filterNode);
|
|
690
|
+
}
|
|
691
|
+
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
692
|
+
const filterBody = [];
|
|
693
|
+
while (!isStatement("endfilter")) {
|
|
694
|
+
filterBody.push(parseAny());
|
|
695
|
+
}
|
|
696
|
+
expect(TOKEN_TYPES.OpenStatement, "Expected '{%'");
|
|
697
|
+
expectIdentifier("endfilter");
|
|
698
|
+
expect(TOKEN_TYPES.CloseStatement, "Expected '%}'");
|
|
699
|
+
result = new FilterStatement(filterNode, filterBody);
|
|
700
|
+
break;
|
|
701
|
+
}
|
|
642
702
|
default:
|
|
643
|
-
throw new SyntaxError(`Unknown statement type: ${
|
|
703
|
+
throw new SyntaxError(`Unknown statement type: ${name}`);
|
|
644
704
|
}
|
|
645
705
|
return result;
|
|
646
706
|
}
|
|
@@ -651,42 +711,42 @@ function parse(tokens) {
|
|
|
651
711
|
return result;
|
|
652
712
|
}
|
|
653
713
|
function parseSetStatement() {
|
|
654
|
-
const left =
|
|
714
|
+
const left = parseExpressionSequence();
|
|
715
|
+
let value = null;
|
|
716
|
+
const body = [];
|
|
655
717
|
if (is(TOKEN_TYPES.Equals)) {
|
|
656
718
|
++current;
|
|
657
|
-
|
|
658
|
-
return new SetStatement(left, value, []);
|
|
719
|
+
value = parseExpressionSequence();
|
|
659
720
|
} else {
|
|
660
|
-
const body = [];
|
|
661
721
|
expect(TOKEN_TYPES.CloseStatement, "Expected %} token");
|
|
662
|
-
while (!(
|
|
663
|
-
|
|
664
|
-
body.push(another);
|
|
722
|
+
while (!isStatement("endset")) {
|
|
723
|
+
body.push(parseAny());
|
|
665
724
|
}
|
|
666
725
|
expect(TOKEN_TYPES.OpenStatement, "Expected {% token");
|
|
667
|
-
|
|
668
|
-
return new SetStatement(left, null, body);
|
|
726
|
+
expectIdentifier("endset");
|
|
669
727
|
}
|
|
728
|
+
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
729
|
+
return new SetStatement(left, value, body);
|
|
670
730
|
}
|
|
671
731
|
function parseIfStatement() {
|
|
672
732
|
const test = parseExpression();
|
|
673
733
|
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
674
734
|
const body = [];
|
|
675
735
|
const alternate = [];
|
|
676
|
-
while (!(
|
|
736
|
+
while (!isStatement("elif", "else", "endif")) {
|
|
677
737
|
body.push(parseAny());
|
|
678
738
|
}
|
|
679
|
-
if (
|
|
739
|
+
if (isStatement("elif")) {
|
|
680
740
|
++current;
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
741
|
+
++current;
|
|
742
|
+
const result = parseIfStatement();
|
|
743
|
+
alternate.push(result);
|
|
744
|
+
} else if (isStatement("else")) {
|
|
745
|
+
++current;
|
|
746
|
+
++current;
|
|
747
|
+
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
748
|
+
while (!isStatement("endif")) {
|
|
749
|
+
alternate.push(parseAny());
|
|
690
750
|
}
|
|
691
751
|
}
|
|
692
752
|
return new If(test, body, alternate);
|
|
@@ -699,7 +759,7 @@ function parse(tokens) {
|
|
|
699
759
|
const args = parseArgs();
|
|
700
760
|
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
701
761
|
const body = [];
|
|
702
|
-
while (
|
|
762
|
+
while (!isStatement("endmacro")) {
|
|
703
763
|
body.push(parseAny());
|
|
704
764
|
}
|
|
705
765
|
return new Macro(name, args, body);
|
|
@@ -722,19 +782,22 @@ function parse(tokens) {
|
|
|
722
782
|
if (!(loopVariable instanceof Identifier || loopVariable instanceof TupleLiteral)) {
|
|
723
783
|
throw new SyntaxError(`Expected identifier/tuple for the loop variable, got ${loopVariable.type} instead`);
|
|
724
784
|
}
|
|
725
|
-
|
|
785
|
+
if (!isIdentifier("in")) {
|
|
786
|
+
throw new SyntaxError("Expected `in` keyword following loop variable");
|
|
787
|
+
}
|
|
788
|
+
++current;
|
|
726
789
|
const iterable = parseExpression();
|
|
727
790
|
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
728
791
|
const body = [];
|
|
729
|
-
while (
|
|
792
|
+
while (!isStatement("endfor", "else")) {
|
|
730
793
|
body.push(parseAny());
|
|
731
794
|
}
|
|
732
795
|
const alternative = [];
|
|
733
|
-
if (
|
|
796
|
+
if (isStatement("else")) {
|
|
734
797
|
++current;
|
|
735
798
|
++current;
|
|
736
799
|
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
737
|
-
while (
|
|
800
|
+
while (!isStatement("endfor")) {
|
|
738
801
|
alternative.push(parseAny());
|
|
739
802
|
}
|
|
740
803
|
}
|
|
@@ -745,22 +808,22 @@ function parse(tokens) {
|
|
|
745
808
|
}
|
|
746
809
|
function parseIfExpression() {
|
|
747
810
|
const a = parseLogicalOrExpression();
|
|
748
|
-
if (
|
|
811
|
+
if (isIdentifier("if")) {
|
|
749
812
|
++current;
|
|
750
|
-
const
|
|
751
|
-
if (
|
|
813
|
+
const test = parseLogicalOrExpression();
|
|
814
|
+
if (isIdentifier("else")) {
|
|
752
815
|
++current;
|
|
753
|
-
const
|
|
754
|
-
return new
|
|
816
|
+
const falseExpr = parseIfExpression();
|
|
817
|
+
return new Ternary(test, a, falseExpr);
|
|
755
818
|
} else {
|
|
756
|
-
return new SelectExpression(a,
|
|
819
|
+
return new SelectExpression(a, test);
|
|
757
820
|
}
|
|
758
821
|
}
|
|
759
822
|
return a;
|
|
760
823
|
}
|
|
761
824
|
function parseLogicalOrExpression() {
|
|
762
825
|
let left = parseLogicalAndExpression();
|
|
763
|
-
while (
|
|
826
|
+
while (isIdentifier("or")) {
|
|
764
827
|
const operator = tokens[current];
|
|
765
828
|
++current;
|
|
766
829
|
const right = parseLogicalAndExpression();
|
|
@@ -770,7 +833,7 @@ function parse(tokens) {
|
|
|
770
833
|
}
|
|
771
834
|
function parseLogicalAndExpression() {
|
|
772
835
|
let left = parseLogicalNegationExpression();
|
|
773
|
-
while (
|
|
836
|
+
while (isIdentifier("and")) {
|
|
774
837
|
const operator = tokens[current];
|
|
775
838
|
++current;
|
|
776
839
|
const right = parseLogicalNegationExpression();
|
|
@@ -780,7 +843,7 @@ function parse(tokens) {
|
|
|
780
843
|
}
|
|
781
844
|
function parseLogicalNegationExpression() {
|
|
782
845
|
let right;
|
|
783
|
-
while (
|
|
846
|
+
while (isIdentifier("not")) {
|
|
784
847
|
const operator = tokens[current];
|
|
785
848
|
++current;
|
|
786
849
|
const arg = parseLogicalNegationExpression();
|
|
@@ -790,9 +853,18 @@ function parse(tokens) {
|
|
|
790
853
|
}
|
|
791
854
|
function parseComparisonExpression() {
|
|
792
855
|
let left = parseAdditiveExpression();
|
|
793
|
-
while (
|
|
794
|
-
|
|
795
|
-
|
|
856
|
+
while (true) {
|
|
857
|
+
let operator;
|
|
858
|
+
if (isIdentifier("not", "in")) {
|
|
859
|
+
operator = new Token("not in", TOKEN_TYPES.Identifier);
|
|
860
|
+
current += 2;
|
|
861
|
+
} else if (isIdentifier("in")) {
|
|
862
|
+
operator = tokens[current++];
|
|
863
|
+
} else if (is(TOKEN_TYPES.ComparisonBinaryOperator)) {
|
|
864
|
+
operator = tokens[current++];
|
|
865
|
+
} else {
|
|
866
|
+
break;
|
|
867
|
+
}
|
|
796
868
|
const right = parseAdditiveExpression();
|
|
797
869
|
left = new BinaryExpression(operator, left, right);
|
|
798
870
|
}
|
|
@@ -832,14 +904,21 @@ function parse(tokens) {
|
|
|
832
904
|
function parseArgumentsList() {
|
|
833
905
|
const args = [];
|
|
834
906
|
while (!is(TOKEN_TYPES.CloseParen)) {
|
|
835
|
-
let argument
|
|
836
|
-
if (
|
|
907
|
+
let argument;
|
|
908
|
+
if (tokens[current].type === TOKEN_TYPES.MultiplicativeBinaryOperator && tokens[current].value === "*") {
|
|
837
909
|
++current;
|
|
838
|
-
|
|
839
|
-
|
|
910
|
+
const expr = parseExpression();
|
|
911
|
+
argument = new SpreadExpression(expr);
|
|
912
|
+
} else {
|
|
913
|
+
argument = parseExpression();
|
|
914
|
+
if (is(TOKEN_TYPES.Equals)) {
|
|
915
|
+
++current;
|
|
916
|
+
if (!(argument instanceof Identifier)) {
|
|
917
|
+
throw new SyntaxError(`Expected identifier for keyword argument`);
|
|
918
|
+
}
|
|
919
|
+
const value = parseExpression();
|
|
920
|
+
argument = new KeywordArgumentExpression(argument, value);
|
|
840
921
|
}
|
|
841
|
-
const value = parseExpression();
|
|
842
|
-
argument = new KeywordArgumentExpression(argument, value);
|
|
843
922
|
}
|
|
844
923
|
args.push(argument);
|
|
845
924
|
if (is(TOKEN_TYPES.Comma)) {
|
|
@@ -880,7 +959,7 @@ function parse(tokens) {
|
|
|
880
959
|
const operator = tokens[current];
|
|
881
960
|
++current;
|
|
882
961
|
let property;
|
|
883
|
-
const computed = operator.type
|
|
962
|
+
const computed = operator.type === TOKEN_TYPES.OpenSquareBracket;
|
|
884
963
|
if (computed) {
|
|
885
964
|
property = parseMemberExpressionArgumentsList();
|
|
886
965
|
expect(TOKEN_TYPES.CloseSquareBracket, "Expected closing square bracket");
|
|
@@ -897,8 +976,7 @@ function parse(tokens) {
|
|
|
897
976
|
function parseMultiplicativeExpression() {
|
|
898
977
|
let left = parseTestExpression();
|
|
899
978
|
while (is(TOKEN_TYPES.MultiplicativeBinaryOperator)) {
|
|
900
|
-
const operator = tokens[current];
|
|
901
|
-
++current;
|
|
979
|
+
const operator = tokens[current++];
|
|
902
980
|
const right = parseTestExpression();
|
|
903
981
|
left = new BinaryExpression(operator, left, right);
|
|
904
982
|
}
|
|
@@ -906,18 +984,13 @@ function parse(tokens) {
|
|
|
906
984
|
}
|
|
907
985
|
function parseTestExpression() {
|
|
908
986
|
let operand = parseFilterExpression();
|
|
909
|
-
while (is
|
|
987
|
+
while (isIdentifier("is")) {
|
|
910
988
|
++current;
|
|
911
|
-
const negate =
|
|
989
|
+
const negate = isIdentifier("not");
|
|
912
990
|
if (negate) {
|
|
913
991
|
++current;
|
|
914
992
|
}
|
|
915
|
-
|
|
916
|
-
if (filter instanceof BooleanLiteral) {
|
|
917
|
-
filter = new Identifier(filter.value.toString());
|
|
918
|
-
} else if (filter instanceof NullLiteral) {
|
|
919
|
-
filter = new Identifier("none");
|
|
920
|
-
}
|
|
993
|
+
const filter = parsePrimaryExpression();
|
|
921
994
|
if (!(filter instanceof Identifier)) {
|
|
922
995
|
throw new SyntaxError(`Expected identifier for the test`);
|
|
923
996
|
}
|
|
@@ -941,34 +1014,27 @@ function parse(tokens) {
|
|
|
941
1014
|
return operand;
|
|
942
1015
|
}
|
|
943
1016
|
function parsePrimaryExpression() {
|
|
944
|
-
const token = tokens[current];
|
|
1017
|
+
const token = tokens[current++];
|
|
945
1018
|
switch (token.type) {
|
|
946
|
-
case TOKEN_TYPES.NumericLiteral:
|
|
947
|
-
|
|
948
|
-
return new
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
return new NullLiteral(null);
|
|
1019
|
+
case TOKEN_TYPES.NumericLiteral: {
|
|
1020
|
+
const num = token.value;
|
|
1021
|
+
return num.includes(".") ? new FloatLiteral(Number(num)) : new IntegerLiteral(Number(num));
|
|
1022
|
+
}
|
|
1023
|
+
case TOKEN_TYPES.StringLiteral: {
|
|
1024
|
+
let value = token.value;
|
|
1025
|
+
while (is(TOKEN_TYPES.StringLiteral)) {
|
|
1026
|
+
value += tokens[current++].value;
|
|
1027
|
+
}
|
|
1028
|
+
return new StringLiteral(value);
|
|
1029
|
+
}
|
|
958
1030
|
case TOKEN_TYPES.Identifier:
|
|
959
|
-
++current;
|
|
960
1031
|
return new Identifier(token.value);
|
|
961
1032
|
case TOKEN_TYPES.OpenParen: {
|
|
962
|
-
++current;
|
|
963
1033
|
const expression = parseExpressionSequence();
|
|
964
|
-
|
|
965
|
-
throw new SyntaxError(`Expected closing parenthesis, got ${tokens[current].type} instead`);
|
|
966
|
-
}
|
|
967
|
-
++current;
|
|
1034
|
+
expect(TOKEN_TYPES.CloseParen, "Expected closing parenthesis, got ${tokens[current].type} instead.");
|
|
968
1035
|
return expression;
|
|
969
1036
|
}
|
|
970
1037
|
case TOKEN_TYPES.OpenSquareBracket: {
|
|
971
|
-
++current;
|
|
972
1038
|
const values = [];
|
|
973
1039
|
while (!is(TOKEN_TYPES.CloseSquareBracket)) {
|
|
974
1040
|
values.push(parseExpression());
|
|
@@ -980,7 +1046,6 @@ function parse(tokens) {
|
|
|
980
1046
|
return new ArrayLiteral(values);
|
|
981
1047
|
}
|
|
982
1048
|
case TOKEN_TYPES.OpenCurlyBracket: {
|
|
983
|
-
++current;
|
|
984
1049
|
const values = /* @__PURE__ */ new Map();
|
|
985
1050
|
while (!is(TOKEN_TYPES.CloseCurlyBracket)) {
|
|
986
1051
|
const key = parseExpression();
|
|
@@ -1034,6 +1099,52 @@ function slice(array, start, stop, step = 1) {
|
|
|
1034
1099
|
function titleCase(value) {
|
|
1035
1100
|
return value.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
1036
1101
|
}
|
|
1102
|
+
function strftime_now(format2) {
|
|
1103
|
+
return strftime(/* @__PURE__ */ new Date(), format2);
|
|
1104
|
+
}
|
|
1105
|
+
function strftime(date, format2) {
|
|
1106
|
+
const monthFormatterLong = new Intl.DateTimeFormat(void 0, { month: "long" });
|
|
1107
|
+
const monthFormatterShort = new Intl.DateTimeFormat(void 0, { month: "short" });
|
|
1108
|
+
const pad2 = (n) => n < 10 ? "0" + n : n.toString();
|
|
1109
|
+
return format2.replace(/%[YmdbBHM%]/g, (token) => {
|
|
1110
|
+
switch (token) {
|
|
1111
|
+
case "%Y":
|
|
1112
|
+
return date.getFullYear().toString();
|
|
1113
|
+
case "%m":
|
|
1114
|
+
return pad2(date.getMonth() + 1);
|
|
1115
|
+
case "%d":
|
|
1116
|
+
return pad2(date.getDate());
|
|
1117
|
+
case "%b":
|
|
1118
|
+
return monthFormatterShort.format(date);
|
|
1119
|
+
case "%B":
|
|
1120
|
+
return monthFormatterLong.format(date);
|
|
1121
|
+
case "%H":
|
|
1122
|
+
return pad2(date.getHours());
|
|
1123
|
+
case "%M":
|
|
1124
|
+
return pad2(date.getMinutes());
|
|
1125
|
+
case "%%":
|
|
1126
|
+
return "%";
|
|
1127
|
+
default:
|
|
1128
|
+
return token;
|
|
1129
|
+
}
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
function escapeRegExp(s) {
|
|
1133
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1134
|
+
}
|
|
1135
|
+
function replace(str, oldvalue, newvalue, count) {
|
|
1136
|
+
if (count === 0)
|
|
1137
|
+
return str;
|
|
1138
|
+
let remaining = count == null || count < 0 ? Infinity : count;
|
|
1139
|
+
const pattern = oldvalue.length === 0 ? new RegExp("(?=)", "gu") : new RegExp(escapeRegExp(oldvalue), "gu");
|
|
1140
|
+
return str.replaceAll(pattern, (match) => {
|
|
1141
|
+
if (remaining > 0) {
|
|
1142
|
+
--remaining;
|
|
1143
|
+
return newvalue;
|
|
1144
|
+
}
|
|
1145
|
+
return match;
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1037
1148
|
|
|
1038
1149
|
// src/runtime.ts
|
|
1039
1150
|
var BreakControl = class extends Error {
|
|
@@ -1061,9 +1172,18 @@ var RuntimeValue = class {
|
|
|
1061
1172
|
__bool__() {
|
|
1062
1173
|
return new BooleanValue(!!this.value);
|
|
1063
1174
|
}
|
|
1175
|
+
toString() {
|
|
1176
|
+
return String(this.value);
|
|
1177
|
+
}
|
|
1178
|
+
};
|
|
1179
|
+
var IntegerValue = class extends RuntimeValue {
|
|
1180
|
+
type = "IntegerValue";
|
|
1064
1181
|
};
|
|
1065
|
-
var
|
|
1066
|
-
type = "
|
|
1182
|
+
var FloatValue = class extends RuntimeValue {
|
|
1183
|
+
type = "FloatValue";
|
|
1184
|
+
toString() {
|
|
1185
|
+
return this.value % 1 === 0 ? this.value.toFixed(1) : this.value.toString();
|
|
1186
|
+
}
|
|
1067
1187
|
};
|
|
1068
1188
|
var StringValue = class extends RuntimeValue {
|
|
1069
1189
|
type = "StringValue";
|
|
@@ -1092,7 +1212,13 @@ var StringValue = class extends RuntimeValue {
|
|
|
1092
1212
|
return new StringValue(titleCase(this.value));
|
|
1093
1213
|
})
|
|
1094
1214
|
],
|
|
1095
|
-
[
|
|
1215
|
+
[
|
|
1216
|
+
"capitalize",
|
|
1217
|
+
new FunctionValue(() => {
|
|
1218
|
+
return new StringValue(this.value.charAt(0).toUpperCase() + this.value.slice(1));
|
|
1219
|
+
})
|
|
1220
|
+
],
|
|
1221
|
+
["length", new IntegerValue(this.value.length)],
|
|
1096
1222
|
[
|
|
1097
1223
|
"rstrip",
|
|
1098
1224
|
new FunctionValue(() => {
|
|
@@ -1111,11 +1237,21 @@ var StringValue = class extends RuntimeValue {
|
|
|
1111
1237
|
if (args.length === 0) {
|
|
1112
1238
|
throw new Error("startswith() requires at least one argument");
|
|
1113
1239
|
}
|
|
1114
|
-
const
|
|
1115
|
-
if (
|
|
1116
|
-
|
|
1240
|
+
const pattern = args[0];
|
|
1241
|
+
if (pattern instanceof StringValue) {
|
|
1242
|
+
return new BooleanValue(this.value.startsWith(pattern.value));
|
|
1243
|
+
} else if (pattern instanceof ArrayValue) {
|
|
1244
|
+
for (const item of pattern.value) {
|
|
1245
|
+
if (!(item instanceof StringValue)) {
|
|
1246
|
+
throw new Error("startswith() tuple elements must be strings");
|
|
1247
|
+
}
|
|
1248
|
+
if (this.value.startsWith(item.value)) {
|
|
1249
|
+
return new BooleanValue(true);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
return new BooleanValue(false);
|
|
1117
1253
|
}
|
|
1118
|
-
|
|
1254
|
+
throw new Error("startswith() argument must be a string or tuple of strings");
|
|
1119
1255
|
})
|
|
1120
1256
|
],
|
|
1121
1257
|
[
|
|
@@ -1124,11 +1260,21 @@ var StringValue = class extends RuntimeValue {
|
|
|
1124
1260
|
if (args.length === 0) {
|
|
1125
1261
|
throw new Error("endswith() requires at least one argument");
|
|
1126
1262
|
}
|
|
1127
|
-
const
|
|
1128
|
-
if (
|
|
1129
|
-
|
|
1263
|
+
const pattern = args[0];
|
|
1264
|
+
if (pattern instanceof StringValue) {
|
|
1265
|
+
return new BooleanValue(this.value.endsWith(pattern.value));
|
|
1266
|
+
} else if (pattern instanceof ArrayValue) {
|
|
1267
|
+
for (const item of pattern.value) {
|
|
1268
|
+
if (!(item instanceof StringValue)) {
|
|
1269
|
+
throw new Error("endswith() tuple elements must be strings");
|
|
1270
|
+
}
|
|
1271
|
+
if (this.value.endsWith(item.value)) {
|
|
1272
|
+
return new BooleanValue(true);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
return new BooleanValue(false);
|
|
1130
1276
|
}
|
|
1131
|
-
|
|
1277
|
+
throw new Error("endswith() argument must be a string or tuple of strings");
|
|
1132
1278
|
})
|
|
1133
1279
|
],
|
|
1134
1280
|
[
|
|
@@ -1140,8 +1286,8 @@ var StringValue = class extends RuntimeValue {
|
|
|
1140
1286
|
if (!(sep instanceof StringValue || sep instanceof NullValue)) {
|
|
1141
1287
|
throw new Error("sep argument must be a string or null");
|
|
1142
1288
|
}
|
|
1143
|
-
const maxsplit = args[1] ?? new
|
|
1144
|
-
if (!(maxsplit instanceof
|
|
1289
|
+
const maxsplit = args[1] ?? new IntegerValue(-1);
|
|
1290
|
+
if (!(maxsplit instanceof IntegerValue)) {
|
|
1145
1291
|
throw new Error("maxsplit argument must be a number");
|
|
1146
1292
|
}
|
|
1147
1293
|
let result = [];
|
|
@@ -1165,6 +1311,33 @@ var StringValue = class extends RuntimeValue {
|
|
|
1165
1311
|
}
|
|
1166
1312
|
return new ArrayValue(result.map((part) => new StringValue(part)));
|
|
1167
1313
|
})
|
|
1314
|
+
],
|
|
1315
|
+
[
|
|
1316
|
+
"replace",
|
|
1317
|
+
new FunctionValue((args) => {
|
|
1318
|
+
if (args.length < 2) {
|
|
1319
|
+
throw new Error("replace() requires at least two arguments");
|
|
1320
|
+
}
|
|
1321
|
+
const oldValue = args[0];
|
|
1322
|
+
const newValue = args[1];
|
|
1323
|
+
if (!(oldValue instanceof StringValue && newValue instanceof StringValue)) {
|
|
1324
|
+
throw new Error("replace() arguments must be strings");
|
|
1325
|
+
}
|
|
1326
|
+
let count;
|
|
1327
|
+
if (args.length > 2) {
|
|
1328
|
+
if (args[2].type === "KeywordArgumentsValue") {
|
|
1329
|
+
count = args[2].value.get("count") ?? new NullValue();
|
|
1330
|
+
} else {
|
|
1331
|
+
count = args[2];
|
|
1332
|
+
}
|
|
1333
|
+
} else {
|
|
1334
|
+
count = new NullValue();
|
|
1335
|
+
}
|
|
1336
|
+
if (!(count instanceof IntegerValue || count instanceof NullValue)) {
|
|
1337
|
+
throw new Error("replace() count argument must be a number or null");
|
|
1338
|
+
}
|
|
1339
|
+
return new StringValue(replace(this.value, oldValue.value, newValue.value, count.value));
|
|
1340
|
+
})
|
|
1168
1341
|
]
|
|
1169
1342
|
]);
|
|
1170
1343
|
};
|
|
@@ -1194,22 +1367,28 @@ var ObjectValue = class extends RuntimeValue {
|
|
|
1194
1367
|
return this.value.get(key.value) ?? defaultValue ?? new NullValue();
|
|
1195
1368
|
})
|
|
1196
1369
|
],
|
|
1197
|
-
[
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
return new ArrayValue(
|
|
1201
|
-
Array.from(this.value.entries()).map(([key, value]) => new ArrayValue([new StringValue(key), value]))
|
|
1202
|
-
);
|
|
1203
|
-
})
|
|
1204
|
-
]
|
|
1370
|
+
["items", new FunctionValue(() => this.items())],
|
|
1371
|
+
["keys", new FunctionValue(() => this.keys())],
|
|
1372
|
+
["values", new FunctionValue(() => this.values())]
|
|
1205
1373
|
]);
|
|
1374
|
+
items() {
|
|
1375
|
+
return new ArrayValue(
|
|
1376
|
+
Array.from(this.value.entries()).map(([key, value]) => new ArrayValue([new StringValue(key), value]))
|
|
1377
|
+
);
|
|
1378
|
+
}
|
|
1379
|
+
keys() {
|
|
1380
|
+
return new ArrayValue(Array.from(this.value.keys()).map((key) => new StringValue(key)));
|
|
1381
|
+
}
|
|
1382
|
+
values() {
|
|
1383
|
+
return new ArrayValue(Array.from(this.value.values()));
|
|
1384
|
+
}
|
|
1206
1385
|
};
|
|
1207
1386
|
var KeywordArgumentsValue = class extends ObjectValue {
|
|
1208
1387
|
type = "KeywordArgumentsValue";
|
|
1209
1388
|
};
|
|
1210
1389
|
var ArrayValue = class extends RuntimeValue {
|
|
1211
1390
|
type = "ArrayValue";
|
|
1212
|
-
builtins = /* @__PURE__ */ new Map([["length", new
|
|
1391
|
+
builtins = /* @__PURE__ */ new Map([["length", new IntegerValue(this.value.length)]]);
|
|
1213
1392
|
/**
|
|
1214
1393
|
* NOTE: necessary to override since all JavaScript arrays are considered truthy,
|
|
1215
1394
|
* while only non-empty Python arrays are consider truthy.
|
|
@@ -1264,8 +1443,8 @@ var Environment = class {
|
|
|
1264
1443
|
[
|
|
1265
1444
|
"odd",
|
|
1266
1445
|
(operand) => {
|
|
1267
|
-
if (operand
|
|
1268
|
-
throw new Error(`
|
|
1446
|
+
if (!(operand instanceof IntegerValue)) {
|
|
1447
|
+
throw new Error(`cannot odd on ${operand.type}`);
|
|
1269
1448
|
}
|
|
1270
1449
|
return operand.value % 2 !== 0;
|
|
1271
1450
|
}
|
|
@@ -1273,8 +1452,8 @@ var Environment = class {
|
|
|
1273
1452
|
[
|
|
1274
1453
|
"even",
|
|
1275
1454
|
(operand) => {
|
|
1276
|
-
if (operand
|
|
1277
|
-
throw new Error(`
|
|
1455
|
+
if (!(operand instanceof IntegerValue)) {
|
|
1456
|
+
throw new Error(`cannot even on ${operand.type}`);
|
|
1278
1457
|
}
|
|
1279
1458
|
return operand.value % 2 === 0;
|
|
1280
1459
|
}
|
|
@@ -1283,8 +1462,8 @@ var Environment = class {
|
|
|
1283
1462
|
["true", (operand) => operand.type === "BooleanValue" && operand.value],
|
|
1284
1463
|
["none", (operand) => operand.type === "NullValue"],
|
|
1285
1464
|
["string", (operand) => operand.type === "StringValue"],
|
|
1286
|
-
["number", (operand) => operand
|
|
1287
|
-
["integer", (operand) => operand
|
|
1465
|
+
["number", (operand) => operand instanceof IntegerValue || operand instanceof FloatValue],
|
|
1466
|
+
["integer", (operand) => operand instanceof IntegerValue],
|
|
1288
1467
|
["iterable", (operand) => operand.type === "ArrayValue" || operand.type === "StringValue"],
|
|
1289
1468
|
["mapping", (operand) => operand.type === "ObjectValue"],
|
|
1290
1469
|
[
|
|
@@ -1355,6 +1534,19 @@ var Environment = class {
|
|
|
1355
1534
|
}
|
|
1356
1535
|
}
|
|
1357
1536
|
};
|
|
1537
|
+
function setupGlobals(env) {
|
|
1538
|
+
env.set("false", false);
|
|
1539
|
+
env.set("true", true);
|
|
1540
|
+
env.set("none", null);
|
|
1541
|
+
env.set("raise_exception", (args) => {
|
|
1542
|
+
throw new Error(args);
|
|
1543
|
+
});
|
|
1544
|
+
env.set("range", range);
|
|
1545
|
+
env.set("strftime_now", strftime_now);
|
|
1546
|
+
env.set("True", true);
|
|
1547
|
+
env.set("False", false);
|
|
1548
|
+
env.set("None", null);
|
|
1549
|
+
}
|
|
1358
1550
|
var Interpreter = class {
|
|
1359
1551
|
global;
|
|
1360
1552
|
constructor(env) {
|
|
@@ -1385,29 +1577,39 @@ var Interpreter = class {
|
|
|
1385
1577
|
return new BooleanValue(left.value != right.value);
|
|
1386
1578
|
}
|
|
1387
1579
|
if (left instanceof UndefinedValue || right instanceof UndefinedValue) {
|
|
1388
|
-
|
|
1580
|
+
if (right instanceof UndefinedValue && ["in", "not in"].includes(node.operator.value)) {
|
|
1581
|
+
return new BooleanValue(node.operator.value === "not in");
|
|
1582
|
+
}
|
|
1583
|
+
throw new Error(`Cannot perform operation ${node.operator.value} on undefined values`);
|
|
1389
1584
|
} else if (left instanceof NullValue || right instanceof NullValue) {
|
|
1390
1585
|
throw new Error("Cannot perform operation on null values");
|
|
1391
|
-
} else if (
|
|
1586
|
+
} else if (node.operator.value === "~") {
|
|
1587
|
+
return new StringValue(left.value.toString() + right.value.toString());
|
|
1588
|
+
} else if ((left instanceof IntegerValue || left instanceof FloatValue) && (right instanceof IntegerValue || right instanceof FloatValue)) {
|
|
1589
|
+
const a = left.value, b = right.value;
|
|
1392
1590
|
switch (node.operator.value) {
|
|
1393
1591
|
case "+":
|
|
1394
|
-
return new NumericValue(left.value + right.value);
|
|
1395
1592
|
case "-":
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1593
|
+
case "*": {
|
|
1594
|
+
const res = node.operator.value === "+" ? a + b : node.operator.value === "-" ? a - b : a * b;
|
|
1595
|
+
const isFloat = left instanceof FloatValue || right instanceof FloatValue;
|
|
1596
|
+
return isFloat ? new FloatValue(res) : new IntegerValue(res);
|
|
1597
|
+
}
|
|
1399
1598
|
case "/":
|
|
1400
|
-
return new
|
|
1401
|
-
case "%":
|
|
1402
|
-
|
|
1599
|
+
return new FloatValue(a / b);
|
|
1600
|
+
case "%": {
|
|
1601
|
+
const rem = a % b;
|
|
1602
|
+
const isFloat = left instanceof FloatValue || right instanceof FloatValue;
|
|
1603
|
+
return isFloat ? new FloatValue(rem) : new IntegerValue(rem);
|
|
1604
|
+
}
|
|
1403
1605
|
case "<":
|
|
1404
|
-
return new BooleanValue(
|
|
1606
|
+
return new BooleanValue(a < b);
|
|
1405
1607
|
case ">":
|
|
1406
|
-
return new BooleanValue(
|
|
1608
|
+
return new BooleanValue(a > b);
|
|
1407
1609
|
case ">=":
|
|
1408
|
-
return new BooleanValue(
|
|
1610
|
+
return new BooleanValue(a >= b);
|
|
1409
1611
|
case "<=":
|
|
1410
|
-
return new BooleanValue(
|
|
1612
|
+
return new BooleanValue(a <= b);
|
|
1411
1613
|
}
|
|
1412
1614
|
} else if (left instanceof ArrayValue && right instanceof ArrayValue) {
|
|
1413
1615
|
switch (node.operator.value) {
|
|
@@ -1451,7 +1653,16 @@ var Interpreter = class {
|
|
|
1451
1653
|
const positionalArguments = [];
|
|
1452
1654
|
const keywordArguments = /* @__PURE__ */ new Map();
|
|
1453
1655
|
for (const argument of args) {
|
|
1454
|
-
if (argument.type === "
|
|
1656
|
+
if (argument.type === "SpreadExpression") {
|
|
1657
|
+
const spreadNode = argument;
|
|
1658
|
+
const val = this.evaluate(spreadNode.argument, environment);
|
|
1659
|
+
if (!(val instanceof ArrayValue)) {
|
|
1660
|
+
throw new Error(`Cannot unpack non-iterable type: ${val.type}`);
|
|
1661
|
+
}
|
|
1662
|
+
for (const item of val.value) {
|
|
1663
|
+
positionalArguments.push(item);
|
|
1664
|
+
}
|
|
1665
|
+
} else if (argument.type === "KeywordArgumentExpression") {
|
|
1455
1666
|
const kwarg = argument;
|
|
1456
1667
|
keywordArguments.set(kwarg.key.value, this.evaluate(kwarg.value, environment));
|
|
1457
1668
|
} else {
|
|
@@ -1463,13 +1674,9 @@ var Interpreter = class {
|
|
|
1463
1674
|
}
|
|
1464
1675
|
return [positionalArguments, keywordArguments];
|
|
1465
1676
|
}
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
evaluateFilterExpression(node, environment) {
|
|
1470
|
-
const operand = this.evaluate(node.operand, environment);
|
|
1471
|
-
if (node.filter.type === "Identifier") {
|
|
1472
|
-
const filter = node.filter;
|
|
1677
|
+
applyFilter(operand, filterNode, environment) {
|
|
1678
|
+
if (filterNode.type === "Identifier") {
|
|
1679
|
+
const filter = filterNode;
|
|
1473
1680
|
if (filter.value === "tojson") {
|
|
1474
1681
|
return new StringValue(toJSON(operand));
|
|
1475
1682
|
}
|
|
@@ -1482,7 +1689,7 @@ var Interpreter = class {
|
|
|
1482
1689
|
case "last":
|
|
1483
1690
|
return operand.value[operand.value.length - 1];
|
|
1484
1691
|
case "length":
|
|
1485
|
-
return new
|
|
1692
|
+
return new IntegerValue(operand.value.length);
|
|
1486
1693
|
case "reverse":
|
|
1487
1694
|
return new ArrayValue(operand.value.reverse());
|
|
1488
1695
|
case "sort":
|
|
@@ -1492,7 +1699,8 @@ var Interpreter = class {
|
|
|
1492
1699
|
throw new Error(`Cannot compare different types: ${a.type} and ${b.type}`);
|
|
1493
1700
|
}
|
|
1494
1701
|
switch (a.type) {
|
|
1495
|
-
case "
|
|
1702
|
+
case "IntegerValue":
|
|
1703
|
+
case "FloatValue":
|
|
1496
1704
|
return a.value - b.value;
|
|
1497
1705
|
case "StringValue":
|
|
1498
1706
|
return a.value.localeCompare(b.value);
|
|
@@ -1505,21 +1713,40 @@ var Interpreter = class {
|
|
|
1505
1713
|
return new StringValue(operand.value.map((x) => x.value).join(""));
|
|
1506
1714
|
case "string":
|
|
1507
1715
|
return new StringValue(toJSON(operand));
|
|
1716
|
+
case "unique": {
|
|
1717
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1718
|
+
const output = [];
|
|
1719
|
+
for (const item of operand.value) {
|
|
1720
|
+
if (!seen.has(item.value)) {
|
|
1721
|
+
seen.add(item.value);
|
|
1722
|
+
output.push(item);
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
return new ArrayValue(output);
|
|
1726
|
+
}
|
|
1508
1727
|
default:
|
|
1509
1728
|
throw new Error(`Unknown ArrayValue filter: ${filter.value}`);
|
|
1510
1729
|
}
|
|
1511
1730
|
} else if (operand instanceof StringValue) {
|
|
1512
1731
|
switch (filter.value) {
|
|
1513
1732
|
case "length":
|
|
1514
|
-
return new NumericValue(operand.value.length);
|
|
1515
1733
|
case "upper":
|
|
1516
|
-
return new StringValue(operand.value.toUpperCase());
|
|
1517
1734
|
case "lower":
|
|
1518
|
-
return new StringValue(operand.value.toLowerCase());
|
|
1519
1735
|
case "title":
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1736
|
+
case "capitalize": {
|
|
1737
|
+
const builtin = operand.builtins.get(filter.value);
|
|
1738
|
+
if (builtin instanceof FunctionValue) {
|
|
1739
|
+
return builtin.value(
|
|
1740
|
+
/* no arguments */
|
|
1741
|
+
[],
|
|
1742
|
+
environment
|
|
1743
|
+
);
|
|
1744
|
+
} else if (builtin instanceof IntegerValue) {
|
|
1745
|
+
return builtin;
|
|
1746
|
+
} else {
|
|
1747
|
+
throw new Error(`Unknown StringValue filter: ${filter.value}`);
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1523
1750
|
case "trim":
|
|
1524
1751
|
return new StringValue(operand.value.trim());
|
|
1525
1752
|
case "indent":
|
|
@@ -1534,13 +1761,25 @@ var Interpreter = class {
|
|
|
1534
1761
|
case "join":
|
|
1535
1762
|
case "string":
|
|
1536
1763
|
return operand;
|
|
1764
|
+
case "int": {
|
|
1765
|
+
const val = parseInt(operand.value, 10);
|
|
1766
|
+
return new IntegerValue(isNaN(val) ? 0 : val);
|
|
1767
|
+
}
|
|
1768
|
+
case "float": {
|
|
1769
|
+
const val = parseFloat(operand.value);
|
|
1770
|
+
return new FloatValue(isNaN(val) ? 0 : val);
|
|
1771
|
+
}
|
|
1537
1772
|
default:
|
|
1538
1773
|
throw new Error(`Unknown StringValue filter: ${filter.value}`);
|
|
1539
1774
|
}
|
|
1540
|
-
} else if (operand instanceof
|
|
1775
|
+
} else if (operand instanceof IntegerValue || operand instanceof FloatValue) {
|
|
1541
1776
|
switch (filter.value) {
|
|
1542
1777
|
case "abs":
|
|
1543
|
-
return new
|
|
1778
|
+
return operand instanceof IntegerValue ? new IntegerValue(Math.abs(operand.value)) : new FloatValue(Math.abs(operand.value));
|
|
1779
|
+
case "int":
|
|
1780
|
+
return new IntegerValue(Math.floor(operand.value));
|
|
1781
|
+
case "float":
|
|
1782
|
+
return new FloatValue(operand.value);
|
|
1544
1783
|
default:
|
|
1545
1784
|
throw new Error(`Unknown NumericValue filter: ${filter.value}`);
|
|
1546
1785
|
}
|
|
@@ -1551,14 +1790,27 @@ var Interpreter = class {
|
|
|
1551
1790
|
Array.from(operand.value.entries()).map(([key, value]) => new ArrayValue([new StringValue(key), value]))
|
|
1552
1791
|
);
|
|
1553
1792
|
case "length":
|
|
1554
|
-
return new
|
|
1793
|
+
return new IntegerValue(operand.value.size);
|
|
1555
1794
|
default:
|
|
1556
1795
|
throw new Error(`Unknown ObjectValue filter: ${filter.value}`);
|
|
1557
1796
|
}
|
|
1797
|
+
} else if (operand instanceof BooleanValue) {
|
|
1798
|
+
switch (filter.value) {
|
|
1799
|
+
case "bool":
|
|
1800
|
+
return new BooleanValue(operand.value);
|
|
1801
|
+
case "int":
|
|
1802
|
+
return new IntegerValue(operand.value ? 1 : 0);
|
|
1803
|
+
case "float":
|
|
1804
|
+
return new FloatValue(operand.value ? 1 : 0);
|
|
1805
|
+
case "string":
|
|
1806
|
+
return new StringValue(operand.value ? "true" : "false");
|
|
1807
|
+
default:
|
|
1808
|
+
throw new Error(`Unknown BooleanValue filter: ${filter.value}`);
|
|
1809
|
+
}
|
|
1558
1810
|
}
|
|
1559
1811
|
throw new Error(`Cannot apply filter "${filter.value}" to type: ${operand.type}`);
|
|
1560
|
-
} else if (
|
|
1561
|
-
const filter =
|
|
1812
|
+
} else if (filterNode.type === "CallExpression") {
|
|
1813
|
+
const filter = filterNode;
|
|
1562
1814
|
if (filter.callee.type !== "Identifier") {
|
|
1563
1815
|
throw new Error(`Unknown filter: ${filter.callee.type}`);
|
|
1564
1816
|
}
|
|
@@ -1566,7 +1818,7 @@ var Interpreter = class {
|
|
|
1566
1818
|
if (filterName === "tojson") {
|
|
1567
1819
|
const [, kwargs] = this.evaluateArguments(filter.args, environment);
|
|
1568
1820
|
const indent = kwargs.get("indent") ?? new NullValue();
|
|
1569
|
-
if (!(indent instanceof
|
|
1821
|
+
if (!(indent instanceof IntegerValue || indent instanceof NullValue)) {
|
|
1570
1822
|
throw new Error("If set, indent must be a number");
|
|
1571
1823
|
}
|
|
1572
1824
|
return new StringValue(toJSON(operand, indent.value));
|
|
@@ -1585,6 +1837,30 @@ var Interpreter = class {
|
|
|
1585
1837
|
throw new Error("separator must be a string");
|
|
1586
1838
|
}
|
|
1587
1839
|
return new StringValue(value.join(separator.value));
|
|
1840
|
+
} else if (filterName === "int" || filterName === "float") {
|
|
1841
|
+
const [args, kwargs] = this.evaluateArguments(filter.args, environment);
|
|
1842
|
+
const defaultValue = args.at(0) ?? kwargs.get("default") ?? (filterName === "int" ? new IntegerValue(0) : new FloatValue(0));
|
|
1843
|
+
if (operand instanceof StringValue) {
|
|
1844
|
+
const val = filterName === "int" ? parseInt(operand.value, 10) : parseFloat(operand.value);
|
|
1845
|
+
return isNaN(val) ? defaultValue : filterName === "int" ? new IntegerValue(val) : new FloatValue(val);
|
|
1846
|
+
} else if (operand instanceof IntegerValue || operand instanceof FloatValue) {
|
|
1847
|
+
return operand;
|
|
1848
|
+
} else if (operand instanceof BooleanValue) {
|
|
1849
|
+
return filterName === "int" ? new IntegerValue(operand.value ? 1 : 0) : new FloatValue(operand.value ? 1 : 0);
|
|
1850
|
+
} else {
|
|
1851
|
+
throw new Error(`Cannot apply filter "${filterName}" to type: ${operand.type}`);
|
|
1852
|
+
}
|
|
1853
|
+
} else if (filterName === "default") {
|
|
1854
|
+
const [args, kwargs] = this.evaluateArguments(filter.args, environment);
|
|
1855
|
+
const defaultValue = args[0] ?? new StringValue("");
|
|
1856
|
+
const booleanValue = args[1] ?? kwargs.get("boolean") ?? new BooleanValue(false);
|
|
1857
|
+
if (!(booleanValue instanceof BooleanValue)) {
|
|
1858
|
+
throw new Error("`default` filter flag must be a boolean");
|
|
1859
|
+
}
|
|
1860
|
+
if (operand instanceof UndefinedValue || booleanValue.value && !operand.__bool__().value) {
|
|
1861
|
+
return defaultValue;
|
|
1862
|
+
}
|
|
1863
|
+
return operand;
|
|
1588
1864
|
}
|
|
1589
1865
|
if (operand instanceof ArrayValue) {
|
|
1590
1866
|
switch (filterName) {
|
|
@@ -1640,8 +1916,8 @@ var Interpreter = class {
|
|
|
1640
1916
|
switch (filterName) {
|
|
1641
1917
|
case "indent": {
|
|
1642
1918
|
const [args, kwargs] = this.evaluateArguments(filter.args, environment);
|
|
1643
|
-
const width = args.at(0) ?? kwargs.get("width") ?? new
|
|
1644
|
-
if (!(width instanceof
|
|
1919
|
+
const width = args.at(0) ?? kwargs.get("width") ?? new IntegerValue(4);
|
|
1920
|
+
if (!(width instanceof IntegerValue)) {
|
|
1645
1921
|
throw new Error("width must be a number");
|
|
1646
1922
|
}
|
|
1647
1923
|
const first = args.at(1) ?? kwargs.get("first") ?? new BooleanValue(false);
|
|
@@ -1653,13 +1929,28 @@ var Interpreter = class {
|
|
|
1653
1929
|
);
|
|
1654
1930
|
return new StringValue(indented.join("\n"));
|
|
1655
1931
|
}
|
|
1932
|
+
case "replace": {
|
|
1933
|
+
const replaceFn = operand.builtins.get("replace");
|
|
1934
|
+
if (!(replaceFn instanceof FunctionValue)) {
|
|
1935
|
+
throw new Error("replace filter not available");
|
|
1936
|
+
}
|
|
1937
|
+
const [args, kwargs] = this.evaluateArguments(filter.args, environment);
|
|
1938
|
+
return replaceFn.value([...args, new KeywordArgumentsValue(kwargs)], environment);
|
|
1939
|
+
}
|
|
1656
1940
|
}
|
|
1657
1941
|
throw new Error(`Unknown StringValue filter: ${filterName}`);
|
|
1658
1942
|
} else {
|
|
1659
1943
|
throw new Error(`Cannot apply filter "${filterName}" to type: ${operand.type}`);
|
|
1660
1944
|
}
|
|
1661
1945
|
}
|
|
1662
|
-
throw new Error(`Unknown filter: ${
|
|
1946
|
+
throw new Error(`Unknown filter: ${filterNode.type}`);
|
|
1947
|
+
}
|
|
1948
|
+
/**
|
|
1949
|
+
* Evaluates expressions following the filter operation type.
|
|
1950
|
+
*/
|
|
1951
|
+
evaluateFilterExpression(node, environment) {
|
|
1952
|
+
const operand = this.evaluate(node.operand, environment);
|
|
1953
|
+
return this.applyFilter(operand, node.filter, environment);
|
|
1663
1954
|
}
|
|
1664
1955
|
/**
|
|
1665
1956
|
* Evaluates expressions following the test operation type.
|
|
@@ -1673,6 +1964,16 @@ var Interpreter = class {
|
|
|
1673
1964
|
const result = test(operand);
|
|
1674
1965
|
return new BooleanValue(node.negate ? !result : result);
|
|
1675
1966
|
}
|
|
1967
|
+
/**
|
|
1968
|
+
* Evaluates expressions following the select operation type.
|
|
1969
|
+
*/
|
|
1970
|
+
evaluateSelectExpression(node, environment) {
|
|
1971
|
+
const predicate = this.evaluate(node.test, environment);
|
|
1972
|
+
if (!predicate.__bool__().value) {
|
|
1973
|
+
return new UndefinedValue();
|
|
1974
|
+
}
|
|
1975
|
+
return this.evaluate(node.lhs, environment);
|
|
1976
|
+
}
|
|
1676
1977
|
/**
|
|
1677
1978
|
* Evaluates expressions following the unary operation type.
|
|
1678
1979
|
*/
|
|
@@ -1685,6 +1986,10 @@ var Interpreter = class {
|
|
|
1685
1986
|
throw new SyntaxError(`Unknown operator: ${node.operator.value}`);
|
|
1686
1987
|
}
|
|
1687
1988
|
}
|
|
1989
|
+
evaluateTernaryExpression(node, environment) {
|
|
1990
|
+
const cond = this.evaluate(node.condition, environment);
|
|
1991
|
+
return cond.__bool__().value ? this.evaluate(node.trueExpr, environment) : this.evaluate(node.falseExpr, environment);
|
|
1992
|
+
}
|
|
1688
1993
|
evalProgram(program, environment) {
|
|
1689
1994
|
return this.evaluateBlock(program.body, environment);
|
|
1690
1995
|
}
|
|
@@ -1693,7 +1998,7 @@ var Interpreter = class {
|
|
|
1693
1998
|
for (const statement of statements) {
|
|
1694
1999
|
const lastEvaluated = this.evaluate(statement, environment);
|
|
1695
2000
|
if (lastEvaluated.type !== "NullValue" && lastEvaluated.type !== "UndefinedValue") {
|
|
1696
|
-
result += lastEvaluated.
|
|
2001
|
+
result += lastEvaluated.toString();
|
|
1697
2002
|
}
|
|
1698
2003
|
}
|
|
1699
2004
|
return new StringValue(result);
|
|
@@ -1719,13 +2024,13 @@ var Interpreter = class {
|
|
|
1719
2024
|
const start = this.evaluate(expr.start, environment);
|
|
1720
2025
|
const stop = this.evaluate(expr.stop, environment);
|
|
1721
2026
|
const step = this.evaluate(expr.step, environment);
|
|
1722
|
-
if (!(start instanceof
|
|
2027
|
+
if (!(start instanceof IntegerValue || start instanceof UndefinedValue)) {
|
|
1723
2028
|
throw new Error("Slice start must be numeric or undefined");
|
|
1724
2029
|
}
|
|
1725
|
-
if (!(stop instanceof
|
|
2030
|
+
if (!(stop instanceof IntegerValue || stop instanceof UndefinedValue)) {
|
|
1726
2031
|
throw new Error("Slice stop must be numeric or undefined");
|
|
1727
2032
|
}
|
|
1728
|
-
if (!(step instanceof
|
|
2033
|
+
if (!(step instanceof IntegerValue || step instanceof UndefinedValue)) {
|
|
1729
2034
|
throw new Error("Slice step must be numeric or undefined");
|
|
1730
2035
|
}
|
|
1731
2036
|
if (object instanceof ArrayValue) {
|
|
@@ -1753,7 +2058,7 @@ var Interpreter = class {
|
|
|
1753
2058
|
}
|
|
1754
2059
|
value = object.value.get(property.value) ?? object.builtins.get(property.value);
|
|
1755
2060
|
} else if (object instanceof ArrayValue || object instanceof StringValue) {
|
|
1756
|
-
if (property instanceof
|
|
2061
|
+
if (property instanceof IntegerValue) {
|
|
1757
2062
|
value = object.value.at(property.value);
|
|
1758
2063
|
if (object instanceof StringValue) {
|
|
1759
2064
|
value = new StringValue(object.value.at(property.value));
|
|
@@ -1776,6 +2081,22 @@ var Interpreter = class {
|
|
|
1776
2081
|
if (node.assignee.type === "Identifier") {
|
|
1777
2082
|
const variableName = node.assignee.value;
|
|
1778
2083
|
environment.setVariable(variableName, rhs);
|
|
2084
|
+
} else if (node.assignee.type === "TupleLiteral") {
|
|
2085
|
+
const tuple = node.assignee;
|
|
2086
|
+
if (!(rhs instanceof ArrayValue)) {
|
|
2087
|
+
throw new Error(`Cannot unpack non-iterable type in set: ${rhs.type}`);
|
|
2088
|
+
}
|
|
2089
|
+
const arr = rhs.value;
|
|
2090
|
+
if (arr.length !== tuple.value.length) {
|
|
2091
|
+
throw new Error(`Too ${tuple.value.length > arr.length ? "few" : "many"} items to unpack in set`);
|
|
2092
|
+
}
|
|
2093
|
+
for (let i = 0; i < tuple.value.length; ++i) {
|
|
2094
|
+
const elem = tuple.value[i];
|
|
2095
|
+
if (elem.type !== "Identifier") {
|
|
2096
|
+
throw new Error(`Cannot unpack to non-identifier in set: ${elem.type}`);
|
|
2097
|
+
}
|
|
2098
|
+
environment.setVariable(elem.value, arr[i]);
|
|
2099
|
+
}
|
|
1779
2100
|
} else if (node.assignee.type === "MemberExpression") {
|
|
1780
2101
|
const member = node.assignee;
|
|
1781
2102
|
const object = this.evaluate(member.object, environment);
|
|
@@ -1800,13 +2121,16 @@ var Interpreter = class {
|
|
|
1800
2121
|
let test, iterable;
|
|
1801
2122
|
if (node.iterable.type === "SelectExpression") {
|
|
1802
2123
|
const select = node.iterable;
|
|
1803
|
-
iterable = this.evaluate(select.
|
|
2124
|
+
iterable = this.evaluate(select.lhs, scope);
|
|
1804
2125
|
test = select.test;
|
|
1805
2126
|
} else {
|
|
1806
2127
|
iterable = this.evaluate(node.iterable, scope);
|
|
1807
2128
|
}
|
|
1808
|
-
if (!(iterable instanceof ArrayValue)) {
|
|
1809
|
-
throw new Error(`Expected iterable type in for loop: got ${iterable.type}`);
|
|
2129
|
+
if (!(iterable instanceof ArrayValue || iterable instanceof ObjectValue)) {
|
|
2130
|
+
throw new Error(`Expected iterable or object type in for loop: got ${iterable.type}`);
|
|
2131
|
+
}
|
|
2132
|
+
if (iterable instanceof ObjectValue) {
|
|
2133
|
+
iterable = iterable.keys();
|
|
1810
2134
|
}
|
|
1811
2135
|
const items = [];
|
|
1812
2136
|
const scopeUpdateFunctions = [];
|
|
@@ -1850,13 +2174,13 @@ var Interpreter = class {
|
|
|
1850
2174
|
let noIteration = true;
|
|
1851
2175
|
for (let i = 0; i < items.length; ++i) {
|
|
1852
2176
|
const loop = /* @__PURE__ */ new Map([
|
|
1853
|
-
["index", new
|
|
1854
|
-
["index0", new
|
|
1855
|
-
["revindex", new
|
|
1856
|
-
["revindex0", new
|
|
2177
|
+
["index", new IntegerValue(i + 1)],
|
|
2178
|
+
["index0", new IntegerValue(i)],
|
|
2179
|
+
["revindex", new IntegerValue(items.length - i)],
|
|
2180
|
+
["revindex0", new IntegerValue(items.length - i - 1)],
|
|
1857
2181
|
["first", new BooleanValue(i === 0)],
|
|
1858
2182
|
["last", new BooleanValue(i === items.length - 1)],
|
|
1859
|
-
["length", new
|
|
2183
|
+
["length", new IntegerValue(items.length)],
|
|
1860
2184
|
["previtem", i > 0 ? items[i - 1] : new UndefinedValue()],
|
|
1861
2185
|
["nextitem", i < items.length - 1 ? items[i + 1] : new UndefinedValue()]
|
|
1862
2186
|
]);
|
|
@@ -1919,8 +2243,36 @@ var Interpreter = class {
|
|
|
1919
2243
|
);
|
|
1920
2244
|
return new NullValue();
|
|
1921
2245
|
}
|
|
2246
|
+
evaluateCallStatement(node, environment) {
|
|
2247
|
+
const callerFn = new FunctionValue((callerArgs, callerEnv) => {
|
|
2248
|
+
const callBlockEnv = new Environment(callerEnv);
|
|
2249
|
+
if (node.callerArgs) {
|
|
2250
|
+
for (let i = 0; i < node.callerArgs.length; ++i) {
|
|
2251
|
+
const param = node.callerArgs[i];
|
|
2252
|
+
if (param.type !== "Identifier") {
|
|
2253
|
+
throw new Error(`Caller parameter must be an identifier, got ${param.type}`);
|
|
2254
|
+
}
|
|
2255
|
+
callBlockEnv.setVariable(param.value, callerArgs[i] ?? new UndefinedValue());
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
return this.evaluateBlock(node.body, callBlockEnv);
|
|
2259
|
+
});
|
|
2260
|
+
const [macroArgs, macroKwargs] = this.evaluateArguments(node.call.args, environment);
|
|
2261
|
+
macroArgs.push(new KeywordArgumentsValue(macroKwargs));
|
|
2262
|
+
const fn = this.evaluate(node.call.callee, environment);
|
|
2263
|
+
if (fn.type !== "FunctionValue") {
|
|
2264
|
+
throw new Error(`Cannot call something that is not a function: got ${fn.type}`);
|
|
2265
|
+
}
|
|
2266
|
+
const newEnv = new Environment(environment);
|
|
2267
|
+
newEnv.setVariable("caller", callerFn);
|
|
2268
|
+
return fn.value(macroArgs, newEnv);
|
|
2269
|
+
}
|
|
2270
|
+
evaluateFilterStatement(node, environment) {
|
|
2271
|
+
const rendered = this.evaluateBlock(node.body, environment);
|
|
2272
|
+
return this.applyFilter(rendered, node.filter, environment);
|
|
2273
|
+
}
|
|
1922
2274
|
evaluate(statement, environment) {
|
|
1923
|
-
if (statement
|
|
2275
|
+
if (!statement)
|
|
1924
2276
|
return new UndefinedValue();
|
|
1925
2277
|
switch (statement.type) {
|
|
1926
2278
|
case "Program":
|
|
@@ -1933,18 +2285,18 @@ var Interpreter = class {
|
|
|
1933
2285
|
return this.evaluateFor(statement, environment);
|
|
1934
2286
|
case "Macro":
|
|
1935
2287
|
return this.evaluateMacro(statement, environment);
|
|
2288
|
+
case "CallStatement":
|
|
2289
|
+
return this.evaluateCallStatement(statement, environment);
|
|
1936
2290
|
case "Break":
|
|
1937
2291
|
throw new BreakControl();
|
|
1938
2292
|
case "Continue":
|
|
1939
2293
|
throw new ContinueControl();
|
|
1940
|
-
case "
|
|
1941
|
-
return new
|
|
2294
|
+
case "IntegerLiteral":
|
|
2295
|
+
return new IntegerValue(statement.value);
|
|
2296
|
+
case "FloatLiteral":
|
|
2297
|
+
return new FloatValue(statement.value);
|
|
1942
2298
|
case "StringLiteral":
|
|
1943
2299
|
return new StringValue(statement.value);
|
|
1944
|
-
case "BooleanLiteral":
|
|
1945
|
-
return new BooleanValue(statement.value);
|
|
1946
|
-
case "NullLiteral":
|
|
1947
|
-
return new NullValue(statement.value);
|
|
1948
2300
|
case "ArrayLiteral":
|
|
1949
2301
|
return new ArrayValue(statement.value.map((x) => this.evaluate(x, environment)));
|
|
1950
2302
|
case "TupleLiteral":
|
|
@@ -1972,8 +2324,16 @@ var Interpreter = class {
|
|
|
1972
2324
|
return this.evaluateBinaryExpression(statement, environment);
|
|
1973
2325
|
case "FilterExpression":
|
|
1974
2326
|
return this.evaluateFilterExpression(statement, environment);
|
|
2327
|
+
case "FilterStatement":
|
|
2328
|
+
return this.evaluateFilterStatement(statement, environment);
|
|
1975
2329
|
case "TestExpression":
|
|
1976
2330
|
return this.evaluateTestExpression(statement, environment);
|
|
2331
|
+
case "SelectExpression":
|
|
2332
|
+
return this.evaluateSelectExpression(statement, environment);
|
|
2333
|
+
case "Ternary":
|
|
2334
|
+
return this.evaluateTernaryExpression(statement, environment);
|
|
2335
|
+
case "Comment":
|
|
2336
|
+
return new NullValue();
|
|
1977
2337
|
default:
|
|
1978
2338
|
throw new SyntaxError(`Unknown node type: ${statement.type}`);
|
|
1979
2339
|
}
|
|
@@ -1982,7 +2342,7 @@ var Interpreter = class {
|
|
|
1982
2342
|
function convertToRuntimeValues(input) {
|
|
1983
2343
|
switch (typeof input) {
|
|
1984
2344
|
case "number":
|
|
1985
|
-
return new
|
|
2345
|
+
return Number.isInteger(input) ? new IntegerValue(input) : new FloatValue(input);
|
|
1986
2346
|
case "string":
|
|
1987
2347
|
return new StringValue(input);
|
|
1988
2348
|
case "boolean":
|
|
@@ -2014,7 +2374,8 @@ function toJSON(input, indent, depth) {
|
|
|
2014
2374
|
case "NullValue":
|
|
2015
2375
|
case "UndefinedValue":
|
|
2016
2376
|
return "null";
|
|
2017
|
-
case "
|
|
2377
|
+
case "IntegerValue":
|
|
2378
|
+
case "FloatValue":
|
|
2018
2379
|
case "StringValue":
|
|
2019
2380
|
case "BooleanValue":
|
|
2020
2381
|
return JSON.stringify(input.value);
|
|
@@ -2043,11 +2404,23 @@ function toJSON(input, indent, depth) {
|
|
|
2043
2404
|
var NEWLINE = "\n";
|
|
2044
2405
|
var OPEN_STATEMENT = "{%- ";
|
|
2045
2406
|
var CLOSE_STATEMENT = " -%}";
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2407
|
+
function getBinaryOperatorPrecedence(expr) {
|
|
2408
|
+
switch (expr.operator.type) {
|
|
2409
|
+
case "MultiplicativeBinaryOperator":
|
|
2410
|
+
return 4;
|
|
2411
|
+
case "AdditiveBinaryOperator":
|
|
2412
|
+
return 3;
|
|
2413
|
+
case "ComparisonBinaryOperator":
|
|
2414
|
+
return 2;
|
|
2415
|
+
case "Identifier":
|
|
2416
|
+
if (expr.operator.value === "and")
|
|
2417
|
+
return 1;
|
|
2418
|
+
if (expr.operator.value === "in" || expr.operator.value === "not in")
|
|
2419
|
+
return 2;
|
|
2420
|
+
return 0;
|
|
2421
|
+
}
|
|
2422
|
+
return 0;
|
|
2423
|
+
}
|
|
2051
2424
|
function format(program, indent = " ") {
|
|
2052
2425
|
const indentStr = typeof indent === "number" ? " ".repeat(indent) : indent;
|
|
2053
2426
|
const body = formatStatements(program.body, 0, indentStr);
|
|
@@ -2076,6 +2449,12 @@ function formatStatement(node, depth, indentStr) {
|
|
|
2076
2449
|
return pad + createStatement("break");
|
|
2077
2450
|
case "Continue":
|
|
2078
2451
|
return pad + createStatement("continue");
|
|
2452
|
+
case "CallStatement":
|
|
2453
|
+
return formatCallStatement(node, depth, indentStr);
|
|
2454
|
+
case "FilterStatement":
|
|
2455
|
+
return formatFilterStatement(node, depth, indentStr);
|
|
2456
|
+
case "Comment":
|
|
2457
|
+
return pad + "{# " + node.value + " #}";
|
|
2079
2458
|
default:
|
|
2080
2459
|
return pad + "{{- " + formatExpression(node) + " -}}";
|
|
2081
2460
|
}
|
|
@@ -2093,7 +2472,7 @@ function formatIf(node, depth, indentStr) {
|
|
|
2093
2472
|
}
|
|
2094
2473
|
}
|
|
2095
2474
|
let out = pad + createStatement("if", formatExpression(clauses[0].test)) + NEWLINE + formatStatements(clauses[0].body, depth + 1, indentStr);
|
|
2096
|
-
for (let i = 1; i < clauses.length; i
|
|
2475
|
+
for (let i = 1; i < clauses.length; ++i) {
|
|
2097
2476
|
out += NEWLINE + pad + createStatement("elif", formatExpression(clauses[i].test)) + NEWLINE + formatStatements(clauses[i].body, depth + 1, indentStr);
|
|
2098
2477
|
}
|
|
2099
2478
|
if (current && current.alternate.length > 0) {
|
|
@@ -2107,7 +2486,7 @@ function formatFor(node, depth, indentStr) {
|
|
|
2107
2486
|
let formattedIterable = "";
|
|
2108
2487
|
if (node.iterable.type === "SelectExpression") {
|
|
2109
2488
|
const n = node.iterable;
|
|
2110
|
-
formattedIterable = `${formatExpression(n.
|
|
2489
|
+
formattedIterable = `${formatExpression(n.lhs)} if ${formatExpression(n.test)}`;
|
|
2111
2490
|
} else {
|
|
2112
2491
|
formattedIterable = formatExpression(node.iterable);
|
|
2113
2492
|
}
|
|
@@ -2133,20 +2512,40 @@ function formatMacro(node, depth, indentStr) {
|
|
|
2133
2512
|
const args = node.args.map(formatExpression).join(", ");
|
|
2134
2513
|
return pad + createStatement("macro", `${node.name.value}(${args})`) + NEWLINE + formatStatements(node.body, depth + 1, indentStr) + NEWLINE + pad + createStatement("endmacro");
|
|
2135
2514
|
}
|
|
2515
|
+
function formatCallStatement(node, depth, indentStr) {
|
|
2516
|
+
const pad = indentStr.repeat(depth);
|
|
2517
|
+
const params = node.callerArgs && node.callerArgs.length > 0 ? `(${node.callerArgs.map(formatExpression).join(", ")})` : "";
|
|
2518
|
+
const callExpr = formatExpression(node.call);
|
|
2519
|
+
let out = pad + createStatement(`call${params}`, callExpr) + NEWLINE;
|
|
2520
|
+
out += formatStatements(node.body, depth + 1, indentStr) + NEWLINE;
|
|
2521
|
+
out += pad + createStatement("endcall");
|
|
2522
|
+
return out;
|
|
2523
|
+
}
|
|
2524
|
+
function formatFilterStatement(node, depth, indentStr) {
|
|
2525
|
+
const pad = indentStr.repeat(depth);
|
|
2526
|
+
const spec = node.filter.type === "Identifier" ? node.filter.value : formatExpression(node.filter);
|
|
2527
|
+
let out = pad + createStatement("filter", spec) + NEWLINE;
|
|
2528
|
+
out += formatStatements(node.body, depth + 1, indentStr) + NEWLINE;
|
|
2529
|
+
out += pad + createStatement("endfilter");
|
|
2530
|
+
return out;
|
|
2531
|
+
}
|
|
2136
2532
|
function formatExpression(node, parentPrec = -1) {
|
|
2137
2533
|
switch (node.type) {
|
|
2534
|
+
case "SpreadExpression": {
|
|
2535
|
+
const n = node;
|
|
2536
|
+
return `*${formatExpression(n.argument)}`;
|
|
2537
|
+
}
|
|
2138
2538
|
case "Identifier":
|
|
2139
2539
|
return node.value;
|
|
2140
|
-
case "
|
|
2141
|
-
return
|
|
2142
|
-
case "
|
|
2143
|
-
case "BooleanLiteral":
|
|
2540
|
+
case "IntegerLiteral":
|
|
2541
|
+
return `${node.value}`;
|
|
2542
|
+
case "FloatLiteral":
|
|
2144
2543
|
return `${node.value}`;
|
|
2145
2544
|
case "StringLiteral":
|
|
2146
2545
|
return JSON.stringify(node.value);
|
|
2147
2546
|
case "BinaryExpression": {
|
|
2148
2547
|
const n = node;
|
|
2149
|
-
const thisPrecedence =
|
|
2548
|
+
const thisPrecedence = getBinaryOperatorPrecedence(n);
|
|
2150
2549
|
const left = formatExpression(n.left, thisPrecedence);
|
|
2151
2550
|
const right = formatExpression(n.right, thisPrecedence + 1);
|
|
2152
2551
|
const expr = `${left} ${n.operator.value} ${right}`;
|
|
@@ -2157,20 +2556,28 @@ function formatExpression(node, parentPrec = -1) {
|
|
|
2157
2556
|
const val = n.operator.value + (n.operator.value === "not" ? " " : "") + formatExpression(n.argument, Infinity);
|
|
2158
2557
|
return val;
|
|
2159
2558
|
}
|
|
2160
|
-
case "LogicalNegationExpression":
|
|
2161
|
-
return `not ${formatExpression(node.argument, Infinity)}`;
|
|
2162
2559
|
case "CallExpression": {
|
|
2163
2560
|
const n = node;
|
|
2164
|
-
const args = n.args.map(
|
|
2165
|
-
return `${formatExpression(n.callee
|
|
2561
|
+
const args = n.args.map(formatExpression).join(", ");
|
|
2562
|
+
return `${formatExpression(n.callee)}(${args})`;
|
|
2166
2563
|
}
|
|
2167
2564
|
case "MemberExpression": {
|
|
2168
2565
|
const n = node;
|
|
2169
|
-
let obj = formatExpression(n.object
|
|
2170
|
-
if (
|
|
2566
|
+
let obj = formatExpression(n.object);
|
|
2567
|
+
if (![
|
|
2568
|
+
"Identifier",
|
|
2569
|
+
"MemberExpression",
|
|
2570
|
+
"CallExpression",
|
|
2571
|
+
"StringLiteral",
|
|
2572
|
+
"IntegerLiteral",
|
|
2573
|
+
"FloatLiteral",
|
|
2574
|
+
"ArrayLiteral",
|
|
2575
|
+
"TupleLiteral",
|
|
2576
|
+
"ObjectLiteral"
|
|
2577
|
+
].includes(n.object.type)) {
|
|
2171
2578
|
obj = `(${obj})`;
|
|
2172
2579
|
}
|
|
2173
|
-
let prop = formatExpression(n.property
|
|
2580
|
+
let prop = formatExpression(n.property);
|
|
2174
2581
|
if (!n.computed && n.property.type !== "Identifier") {
|
|
2175
2582
|
prop = `(${prop})`;
|
|
2176
2583
|
}
|
|
@@ -2180,47 +2587,47 @@ function formatExpression(node, parentPrec = -1) {
|
|
|
2180
2587
|
const n = node;
|
|
2181
2588
|
const operand = formatExpression(n.operand, Infinity);
|
|
2182
2589
|
if (n.filter.type === "CallExpression") {
|
|
2183
|
-
return `${operand} | ${formatExpression(n.filter
|
|
2590
|
+
return `${operand} | ${formatExpression(n.filter)}`;
|
|
2184
2591
|
}
|
|
2185
2592
|
return `${operand} | ${n.filter.value}`;
|
|
2186
2593
|
}
|
|
2187
2594
|
case "SelectExpression": {
|
|
2188
2595
|
const n = node;
|
|
2189
|
-
return `${formatExpression(n.
|
|
2596
|
+
return `${formatExpression(n.lhs)} if ${formatExpression(n.test)}`;
|
|
2190
2597
|
}
|
|
2191
2598
|
case "TestExpression": {
|
|
2192
2599
|
const n = node;
|
|
2193
|
-
return `${formatExpression(n.operand
|
|
2600
|
+
return `${formatExpression(n.operand)} is${n.negate ? " not" : ""} ${n.test.value}`;
|
|
2194
2601
|
}
|
|
2195
2602
|
case "ArrayLiteral":
|
|
2196
2603
|
case "TupleLiteral": {
|
|
2197
|
-
const elems = node.value.map(
|
|
2604
|
+
const elems = node.value.map(formatExpression);
|
|
2198
2605
|
const brackets = node.type === "ArrayLiteral" ? "[]" : "()";
|
|
2199
2606
|
return `${brackets[0]}${elems.join(", ")}${brackets[1]}`;
|
|
2200
2607
|
}
|
|
2201
2608
|
case "ObjectLiteral": {
|
|
2202
2609
|
const entries = Array.from(node.value.entries()).map(
|
|
2203
|
-
([k, v]) => `${formatExpression(k
|
|
2610
|
+
([k, v]) => `${formatExpression(k)}: ${formatExpression(v)}`
|
|
2204
2611
|
);
|
|
2205
|
-
return `{
|
|
2612
|
+
return `{${entries.join(", ")}}`;
|
|
2206
2613
|
}
|
|
2207
2614
|
case "SliceExpression": {
|
|
2208
2615
|
const n = node;
|
|
2209
|
-
const s = n.start ? formatExpression(n.start
|
|
2210
|
-
const t = n.stop ? formatExpression(n.stop
|
|
2211
|
-
const st = n.step ? `:${formatExpression(n.step
|
|
2616
|
+
const s = n.start ? formatExpression(n.start) : "";
|
|
2617
|
+
const t = n.stop ? formatExpression(n.stop) : "";
|
|
2618
|
+
const st = n.step ? `:${formatExpression(n.step)}` : "";
|
|
2212
2619
|
return `${s}:${t}${st}`;
|
|
2213
2620
|
}
|
|
2214
2621
|
case "KeywordArgumentExpression": {
|
|
2215
2622
|
const n = node;
|
|
2216
|
-
return `${n.key.value}=${formatExpression(n.value
|
|
2623
|
+
return `${n.key.value}=${formatExpression(n.value)}`;
|
|
2217
2624
|
}
|
|
2218
|
-
case "
|
|
2625
|
+
case "Ternary": {
|
|
2219
2626
|
const n = node;
|
|
2220
|
-
const
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
return
|
|
2627
|
+
const expr = `${formatExpression(n.trueExpr)} if ${formatExpression(n.condition, 0)} else ${formatExpression(
|
|
2628
|
+
n.falseExpr
|
|
2629
|
+
)}`;
|
|
2630
|
+
return parentPrec > -1 ? `(${expr})` : expr;
|
|
2224
2631
|
}
|
|
2225
2632
|
default:
|
|
2226
2633
|
throw new Error(`Unknown expression type: ${node.type}`);
|
|
@@ -2242,12 +2649,7 @@ var Template = class {
|
|
|
2242
2649
|
}
|
|
2243
2650
|
render(items) {
|
|
2244
2651
|
const env = new Environment();
|
|
2245
|
-
env
|
|
2246
|
-
env.set("true", true);
|
|
2247
|
-
env.set("raise_exception", (args) => {
|
|
2248
|
-
throw new Error(args);
|
|
2249
|
-
});
|
|
2250
|
-
env.set("range", range);
|
|
2652
|
+
setupGlobals(env);
|
|
2251
2653
|
if (items) {
|
|
2252
2654
|
for (const [key, value] of Object.entries(items)) {
|
|
2253
2655
|
env.set(key, value);
|
|
@@ -4374,7 +4776,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
4374
4776
|
|
|
4375
4777
|
|
|
4376
4778
|
|
|
4377
|
-
const VERSION = '3.6.
|
|
4779
|
+
const VERSION = '3.6.3';
|
|
4378
4780
|
|
|
4379
4781
|
// Check if various APIs are available (depends on environment)
|
|
4380
4782
|
const IS_BROWSER_ENV = typeof window !== "undefined" && typeof window.document !== "undefined";
|