@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
|
@@ -95,15 +95,11 @@ var TOKEN_TYPES = Object.freeze({
|
|
|
95
95
|
Text: "Text",
|
|
96
96
|
// The text between Jinja statements or expressions
|
|
97
97
|
NumericLiteral: "NumericLiteral",
|
|
98
|
-
// e.g., 123
|
|
99
|
-
BooleanLiteral: "BooleanLiteral",
|
|
100
|
-
// true or false
|
|
101
|
-
NullLiteral: "NullLiteral",
|
|
102
|
-
// none
|
|
98
|
+
// e.g., 123, 1.0
|
|
103
99
|
StringLiteral: "StringLiteral",
|
|
104
100
|
// 'string'
|
|
105
101
|
Identifier: "Identifier",
|
|
106
|
-
// Variables, functions, etc.
|
|
102
|
+
// Variables, functions, statements, booleans, etc.
|
|
107
103
|
Equals: "Equals",
|
|
108
104
|
// =
|
|
109
105
|
OpenParen: "OpenParen",
|
|
@@ -137,63 +133,15 @@ var TOKEN_TYPES = Object.freeze({
|
|
|
137
133
|
CallOperator: "CallOperator",
|
|
138
134
|
// ()
|
|
139
135
|
AdditiveBinaryOperator: "AdditiveBinaryOperator",
|
|
140
|
-
// + -
|
|
136
|
+
// + - ~
|
|
141
137
|
MultiplicativeBinaryOperator: "MultiplicativeBinaryOperator",
|
|
142
138
|
// * / %
|
|
143
139
|
ComparisonBinaryOperator: "ComparisonBinaryOperator",
|
|
144
140
|
// < > <= >= == !=
|
|
145
141
|
UnaryOperator: "UnaryOperator",
|
|
146
142
|
// ! - +
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
If: "If",
|
|
150
|
-
For: "For",
|
|
151
|
-
In: "In",
|
|
152
|
-
Is: "Is",
|
|
153
|
-
NotIn: "NotIn",
|
|
154
|
-
Else: "Else",
|
|
155
|
-
EndSet: "EndSet",
|
|
156
|
-
EndIf: "EndIf",
|
|
157
|
-
ElseIf: "ElseIf",
|
|
158
|
-
EndFor: "EndFor",
|
|
159
|
-
And: "And",
|
|
160
|
-
Or: "Or",
|
|
161
|
-
Not: "UnaryOperator",
|
|
162
|
-
Macro: "Macro",
|
|
163
|
-
EndMacro: "EndMacro",
|
|
164
|
-
Break: "Break",
|
|
165
|
-
Continue: "Continue"
|
|
166
|
-
});
|
|
167
|
-
var KEYWORDS = Object.freeze({
|
|
168
|
-
set: TOKEN_TYPES.Set,
|
|
169
|
-
for: TOKEN_TYPES.For,
|
|
170
|
-
in: TOKEN_TYPES.In,
|
|
171
|
-
is: TOKEN_TYPES.Is,
|
|
172
|
-
if: TOKEN_TYPES.If,
|
|
173
|
-
else: TOKEN_TYPES.Else,
|
|
174
|
-
endset: TOKEN_TYPES.EndSet,
|
|
175
|
-
endif: TOKEN_TYPES.EndIf,
|
|
176
|
-
elif: TOKEN_TYPES.ElseIf,
|
|
177
|
-
endfor: TOKEN_TYPES.EndFor,
|
|
178
|
-
and: TOKEN_TYPES.And,
|
|
179
|
-
or: TOKEN_TYPES.Or,
|
|
180
|
-
not: TOKEN_TYPES.Not,
|
|
181
|
-
"not in": TOKEN_TYPES.NotIn,
|
|
182
|
-
macro: TOKEN_TYPES.Macro,
|
|
183
|
-
endmacro: TOKEN_TYPES.EndMacro,
|
|
184
|
-
break: TOKEN_TYPES.Break,
|
|
185
|
-
continue: TOKEN_TYPES.Continue,
|
|
186
|
-
// Literals
|
|
187
|
-
true: TOKEN_TYPES.BooleanLiteral,
|
|
188
|
-
false: TOKEN_TYPES.BooleanLiteral,
|
|
189
|
-
none: TOKEN_TYPES.NullLiteral,
|
|
190
|
-
// NOTE: According to the Jinja docs: The special constants true, false, and none are indeed lowercase.
|
|
191
|
-
// Because that caused confusion in the past, (True used to expand to an undefined variable that was considered false),
|
|
192
|
-
// all three can now also be written in title case (True, False, and None). However, for consistency, (all Jinja identifiers are lowercase)
|
|
193
|
-
// you should use the lowercase versions.
|
|
194
|
-
True: TOKEN_TYPES.BooleanLiteral,
|
|
195
|
-
False: TOKEN_TYPES.BooleanLiteral,
|
|
196
|
-
None: TOKEN_TYPES.NullLiteral
|
|
143
|
+
Comment: "Comment"
|
|
144
|
+
// {# ... #}
|
|
197
145
|
});
|
|
198
146
|
var Token = class {
|
|
199
147
|
/**
|
|
@@ -239,6 +187,7 @@ var ORDERED_MAPPING_TABLE = [
|
|
|
239
187
|
// Arithmetic operators
|
|
240
188
|
["+", TOKEN_TYPES.AdditiveBinaryOperator],
|
|
241
189
|
["-", TOKEN_TYPES.AdditiveBinaryOperator],
|
|
190
|
+
["~", TOKEN_TYPES.AdditiveBinaryOperator],
|
|
242
191
|
["*", TOKEN_TYPES.MultiplicativeBinaryOperator],
|
|
243
192
|
["/", TOKEN_TYPES.MultiplicativeBinaryOperator],
|
|
244
193
|
["%", TOKEN_TYPES.MultiplicativeBinaryOperator],
|
|
@@ -269,19 +218,19 @@ function preprocess(template, options = {}) {
|
|
|
269
218
|
if (template.endsWith("\n")) {
|
|
270
219
|
template = template.slice(0, -1);
|
|
271
220
|
}
|
|
272
|
-
template = template.replace(/{#.*?#}/gs, "{##}");
|
|
273
221
|
if (options.lstrip_blocks) {
|
|
274
|
-
template = template.replace(/^[ \t]*({[
|
|
222
|
+
template = template.replace(/^[ \t]*({[#%-])/gm, "$1");
|
|
275
223
|
}
|
|
276
224
|
if (options.trim_blocks) {
|
|
277
|
-
template = template.replace(/([
|
|
225
|
+
template = template.replace(/([#%-]})\n/g, "$1");
|
|
278
226
|
}
|
|
279
|
-
return template.replace(
|
|
227
|
+
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, "");
|
|
280
228
|
}
|
|
281
229
|
function tokenize(source, options = {}) {
|
|
282
230
|
const tokens = [];
|
|
283
231
|
const src = preprocess(source, options);
|
|
284
232
|
let cursorPosition = 0;
|
|
233
|
+
let curlyBracketDepth = 0;
|
|
285
234
|
const consumeWhile = (predicate) => {
|
|
286
235
|
let str = "";
|
|
287
236
|
while (predicate(src[cursorPosition])) {
|
|
@@ -306,10 +255,10 @@ function tokenize(source, options = {}) {
|
|
|
306
255
|
main:
|
|
307
256
|
while (cursorPosition < src.length) {
|
|
308
257
|
const lastTokenType = tokens.at(-1)?.type;
|
|
309
|
-
if (lastTokenType === void 0 || lastTokenType === TOKEN_TYPES.CloseStatement || lastTokenType === TOKEN_TYPES.CloseExpression) {
|
|
258
|
+
if (lastTokenType === void 0 || lastTokenType === TOKEN_TYPES.CloseStatement || lastTokenType === TOKEN_TYPES.CloseExpression || lastTokenType === TOKEN_TYPES.Comment) {
|
|
310
259
|
let text = "";
|
|
311
260
|
while (cursorPosition < src.length && // Keep going until we hit the next Jinja statement or expression
|
|
312
|
-
!(src[cursorPosition] === "{" && (src[cursorPosition + 1] === "%" || src[cursorPosition + 1] === "{"))) {
|
|
261
|
+
!(src[cursorPosition] === "{" && (src[cursorPosition + 1] === "%" || src[cursorPosition + 1] === "{" || src[cursorPosition + 1] === "#"))) {
|
|
313
262
|
text += src[cursorPosition++];
|
|
314
263
|
}
|
|
315
264
|
if (text.length > 0) {
|
|
@@ -317,6 +266,19 @@ function tokenize(source, options = {}) {
|
|
|
317
266
|
continue;
|
|
318
267
|
}
|
|
319
268
|
}
|
|
269
|
+
if (src[cursorPosition] === "{" && src[cursorPosition + 1] === "#") {
|
|
270
|
+
cursorPosition += 2;
|
|
271
|
+
let comment = "";
|
|
272
|
+
while (src[cursorPosition] !== "#" || src[cursorPosition + 1] !== "}") {
|
|
273
|
+
if (cursorPosition + 2 >= src.length) {
|
|
274
|
+
throw new SyntaxError("Missing end of comment tag");
|
|
275
|
+
}
|
|
276
|
+
comment += src[cursorPosition++];
|
|
277
|
+
}
|
|
278
|
+
tokens.push(new Token(comment, TOKEN_TYPES.Comment));
|
|
279
|
+
cursorPosition += 2;
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
320
282
|
consumeWhile((char2) => /\s/.test(char2));
|
|
321
283
|
const char = src[cursorPosition];
|
|
322
284
|
if (char === "-" || char === "+") {
|
|
@@ -327,8 +289,6 @@ function tokenize(source, options = {}) {
|
|
|
327
289
|
switch (lastTokenType2) {
|
|
328
290
|
case TOKEN_TYPES.Identifier:
|
|
329
291
|
case TOKEN_TYPES.NumericLiteral:
|
|
330
|
-
case TOKEN_TYPES.BooleanLiteral:
|
|
331
|
-
case TOKEN_TYPES.NullLiteral:
|
|
332
292
|
case TOKEN_TYPES.StringLiteral:
|
|
333
293
|
case TOKEN_TYPES.CloseParen:
|
|
334
294
|
case TOKEN_TYPES.CloseSquareBracket:
|
|
@@ -343,11 +303,21 @@ function tokenize(source, options = {}) {
|
|
|
343
303
|
}
|
|
344
304
|
}
|
|
345
305
|
}
|
|
346
|
-
for (const [
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
306
|
+
for (const [seq, type] of ORDERED_MAPPING_TABLE) {
|
|
307
|
+
if (seq === "}}" && curlyBracketDepth > 0) {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
const slice2 = src.slice(cursorPosition, cursorPosition + seq.length);
|
|
311
|
+
if (slice2 === seq) {
|
|
312
|
+
tokens.push(new Token(seq, type));
|
|
313
|
+
if (type === TOKEN_TYPES.OpenExpression) {
|
|
314
|
+
curlyBracketDepth = 0;
|
|
315
|
+
} else if (type === TOKEN_TYPES.OpenCurlyBracket) {
|
|
316
|
+
++curlyBracketDepth;
|
|
317
|
+
} else if (type === TOKEN_TYPES.CloseCurlyBracket) {
|
|
318
|
+
--curlyBracketDepth;
|
|
319
|
+
}
|
|
320
|
+
cursorPosition += seq.length;
|
|
351
321
|
continue main;
|
|
352
322
|
}
|
|
353
323
|
}
|
|
@@ -359,19 +329,18 @@ function tokenize(source, options = {}) {
|
|
|
359
329
|
continue;
|
|
360
330
|
}
|
|
361
331
|
if (isInteger(char)) {
|
|
362
|
-
|
|
332
|
+
let num = consumeWhile(isInteger);
|
|
333
|
+
if (src[cursorPosition] === "." && isInteger(src[cursorPosition + 1])) {
|
|
334
|
+
++cursorPosition;
|
|
335
|
+
const frac = consumeWhile(isInteger);
|
|
336
|
+
num = `${num}.${frac}`;
|
|
337
|
+
}
|
|
363
338
|
tokens.push(new Token(num, TOKEN_TYPES.NumericLiteral));
|
|
364
339
|
continue;
|
|
365
340
|
}
|
|
366
341
|
if (isWord(char)) {
|
|
367
342
|
const word = consumeWhile(isWord);
|
|
368
|
-
|
|
369
|
-
if (type === TOKEN_TYPES.In && tokens.at(-1)?.type === TOKEN_TYPES.Not) {
|
|
370
|
-
tokens.pop();
|
|
371
|
-
tokens.push(new Token("not in", TOKEN_TYPES.NotIn));
|
|
372
|
-
} else {
|
|
373
|
-
tokens.push(new Token(word, type));
|
|
374
|
-
}
|
|
343
|
+
tokens.push(new Token(word, TOKEN_TYPES.Identifier));
|
|
375
344
|
continue;
|
|
376
345
|
}
|
|
377
346
|
throw new SyntaxError(`Unexpected character: ${char}`);
|
|
@@ -433,6 +402,13 @@ var Macro = class extends Statement {
|
|
|
433
402
|
}
|
|
434
403
|
type = "Macro";
|
|
435
404
|
};
|
|
405
|
+
var Comment = class extends Statement {
|
|
406
|
+
constructor(value) {
|
|
407
|
+
super();
|
|
408
|
+
this.value = value;
|
|
409
|
+
}
|
|
410
|
+
type = "Comment";
|
|
411
|
+
};
|
|
436
412
|
var Expression = class extends Statement {
|
|
437
413
|
type = "Expression";
|
|
438
414
|
};
|
|
@@ -470,18 +446,15 @@ var Literal = class extends Expression {
|
|
|
470
446
|
}
|
|
471
447
|
type = "Literal";
|
|
472
448
|
};
|
|
473
|
-
var
|
|
474
|
-
type = "
|
|
449
|
+
var IntegerLiteral = class extends Literal {
|
|
450
|
+
type = "IntegerLiteral";
|
|
451
|
+
};
|
|
452
|
+
var FloatLiteral = class extends Literal {
|
|
453
|
+
type = "FloatLiteral";
|
|
475
454
|
};
|
|
476
455
|
var StringLiteral = class extends Literal {
|
|
477
456
|
type = "StringLiteral";
|
|
478
457
|
};
|
|
479
|
-
var BooleanLiteral = class extends Literal {
|
|
480
|
-
type = "BooleanLiteral";
|
|
481
|
-
};
|
|
482
|
-
var NullLiteral = class extends Literal {
|
|
483
|
-
type = "NullLiteral";
|
|
484
|
-
};
|
|
485
458
|
var ArrayLiteral = class extends Literal {
|
|
486
459
|
type = "ArrayLiteral";
|
|
487
460
|
};
|
|
@@ -508,10 +481,18 @@ var FilterExpression = class extends Expression {
|
|
|
508
481
|
}
|
|
509
482
|
type = "FilterExpression";
|
|
510
483
|
};
|
|
484
|
+
var FilterStatement = class extends Statement {
|
|
485
|
+
constructor(filter, body) {
|
|
486
|
+
super();
|
|
487
|
+
this.filter = filter;
|
|
488
|
+
this.body = body;
|
|
489
|
+
}
|
|
490
|
+
type = "FilterStatement";
|
|
491
|
+
};
|
|
511
492
|
var SelectExpression = class extends Expression {
|
|
512
|
-
constructor(
|
|
493
|
+
constructor(lhs, test) {
|
|
513
494
|
super();
|
|
514
|
-
this.
|
|
495
|
+
this.lhs = lhs;
|
|
515
496
|
this.test = test;
|
|
516
497
|
}
|
|
517
498
|
type = "SelectExpression";
|
|
@@ -550,6 +531,31 @@ var KeywordArgumentExpression = class extends Expression {
|
|
|
550
531
|
}
|
|
551
532
|
type = "KeywordArgumentExpression";
|
|
552
533
|
};
|
|
534
|
+
var SpreadExpression = class extends Expression {
|
|
535
|
+
constructor(argument) {
|
|
536
|
+
super();
|
|
537
|
+
this.argument = argument;
|
|
538
|
+
}
|
|
539
|
+
type = "SpreadExpression";
|
|
540
|
+
};
|
|
541
|
+
var CallStatement = class extends Statement {
|
|
542
|
+
constructor(call, callerArgs, body) {
|
|
543
|
+
super();
|
|
544
|
+
this.call = call;
|
|
545
|
+
this.callerArgs = callerArgs;
|
|
546
|
+
this.body = body;
|
|
547
|
+
}
|
|
548
|
+
type = "CallStatement";
|
|
549
|
+
};
|
|
550
|
+
var Ternary = class extends Expression {
|
|
551
|
+
constructor(condition, trueExpr, falseExpr) {
|
|
552
|
+
super();
|
|
553
|
+
this.condition = condition;
|
|
554
|
+
this.trueExpr = trueExpr;
|
|
555
|
+
this.falseExpr = falseExpr;
|
|
556
|
+
}
|
|
557
|
+
type = "Ternary";
|
|
558
|
+
};
|
|
553
559
|
|
|
554
560
|
// src/parser.ts
|
|
555
561
|
function parse(tokens) {
|
|
@@ -562,8 +568,16 @@ function parse(tokens) {
|
|
|
562
568
|
}
|
|
563
569
|
return prev;
|
|
564
570
|
}
|
|
571
|
+
function expectIdentifier(name) {
|
|
572
|
+
if (!isIdentifier(name)) {
|
|
573
|
+
throw new SyntaxError(`Expected ${name}`);
|
|
574
|
+
}
|
|
575
|
+
++current;
|
|
576
|
+
}
|
|
565
577
|
function parseAny() {
|
|
566
578
|
switch (tokens[current].type) {
|
|
579
|
+
case TOKEN_TYPES.Comment:
|
|
580
|
+
return new Comment(tokens[current++].value);
|
|
567
581
|
case TOKEN_TYPES.Text:
|
|
568
582
|
return parseText();
|
|
569
583
|
case TOKEN_TYPES.OpenStatement:
|
|
@@ -574,57 +588,103 @@ function parse(tokens) {
|
|
|
574
588
|
throw new SyntaxError(`Unexpected token type: ${tokens[current].type}`);
|
|
575
589
|
}
|
|
576
590
|
}
|
|
577
|
-
function not(...types) {
|
|
578
|
-
return current + types.length <= tokens.length && types.some((type, i) => type !== tokens[current + i].type);
|
|
579
|
-
}
|
|
580
591
|
function is(...types) {
|
|
581
592
|
return current + types.length <= tokens.length && types.every((type, i) => type === tokens[current + i].type);
|
|
582
593
|
}
|
|
594
|
+
function isStatement(...names) {
|
|
595
|
+
return tokens[current]?.type === TOKEN_TYPES.OpenStatement && tokens[current + 1]?.type === TOKEN_TYPES.Identifier && names.includes(tokens[current + 1]?.value);
|
|
596
|
+
}
|
|
597
|
+
function isIdentifier(...names) {
|
|
598
|
+
return current + names.length <= tokens.length && names.every((name, i) => tokens[current + i].type === "Identifier" && name === tokens[current + i].value);
|
|
599
|
+
}
|
|
583
600
|
function parseText() {
|
|
584
601
|
return new StringLiteral(expect(TOKEN_TYPES.Text, "Expected text token").value);
|
|
585
602
|
}
|
|
586
603
|
function parseJinjaStatement() {
|
|
587
604
|
expect(TOKEN_TYPES.OpenStatement, "Expected opening statement token");
|
|
605
|
+
if (tokens[current].type !== TOKEN_TYPES.Identifier) {
|
|
606
|
+
throw new SyntaxError(`Unknown statement, got ${tokens[current].type}`);
|
|
607
|
+
}
|
|
608
|
+
const name = tokens[current].value;
|
|
588
609
|
let result;
|
|
589
|
-
switch (
|
|
590
|
-
case
|
|
610
|
+
switch (name) {
|
|
611
|
+
case "set":
|
|
591
612
|
++current;
|
|
592
613
|
result = parseSetStatement();
|
|
593
|
-
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
594
614
|
break;
|
|
595
|
-
case
|
|
615
|
+
case "if":
|
|
596
616
|
++current;
|
|
597
617
|
result = parseIfStatement();
|
|
598
618
|
expect(TOKEN_TYPES.OpenStatement, "Expected {% token");
|
|
599
|
-
|
|
619
|
+
expectIdentifier("endif");
|
|
600
620
|
expect(TOKEN_TYPES.CloseStatement, "Expected %} token");
|
|
601
621
|
break;
|
|
602
|
-
case
|
|
622
|
+
case "macro":
|
|
603
623
|
++current;
|
|
604
624
|
result = parseMacroStatement();
|
|
605
625
|
expect(TOKEN_TYPES.OpenStatement, "Expected {% token");
|
|
606
|
-
|
|
626
|
+
expectIdentifier("endmacro");
|
|
607
627
|
expect(TOKEN_TYPES.CloseStatement, "Expected %} token");
|
|
608
628
|
break;
|
|
609
|
-
case
|
|
629
|
+
case "for":
|
|
610
630
|
++current;
|
|
611
631
|
result = parseForStatement();
|
|
612
632
|
expect(TOKEN_TYPES.OpenStatement, "Expected {% token");
|
|
613
|
-
|
|
633
|
+
expectIdentifier("endfor");
|
|
614
634
|
expect(TOKEN_TYPES.CloseStatement, "Expected %} token");
|
|
615
635
|
break;
|
|
616
|
-
case
|
|
636
|
+
case "call": {
|
|
637
|
+
++current;
|
|
638
|
+
let callerArgs = null;
|
|
639
|
+
if (is(TOKEN_TYPES.OpenParen)) {
|
|
640
|
+
callerArgs = parseArgs();
|
|
641
|
+
}
|
|
642
|
+
const callee = parsePrimaryExpression();
|
|
643
|
+
if (callee.type !== "Identifier") {
|
|
644
|
+
throw new SyntaxError(`Expected identifier following call statement`);
|
|
645
|
+
}
|
|
646
|
+
const callArgs = parseArgs();
|
|
647
|
+
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
648
|
+
const body = [];
|
|
649
|
+
while (!isStatement("endcall")) {
|
|
650
|
+
body.push(parseAny());
|
|
651
|
+
}
|
|
652
|
+
expect(TOKEN_TYPES.OpenStatement, "Expected '{%'");
|
|
653
|
+
expectIdentifier("endcall");
|
|
654
|
+
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
655
|
+
const callExpr = new CallExpression(callee, callArgs);
|
|
656
|
+
result = new CallStatement(callExpr, callerArgs, body);
|
|
657
|
+
break;
|
|
658
|
+
}
|
|
659
|
+
case "break":
|
|
617
660
|
++current;
|
|
618
661
|
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
619
662
|
result = new Break();
|
|
620
663
|
break;
|
|
621
|
-
case
|
|
664
|
+
case "continue":
|
|
622
665
|
++current;
|
|
623
666
|
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
624
667
|
result = new Continue();
|
|
625
668
|
break;
|
|
669
|
+
case "filter": {
|
|
670
|
+
++current;
|
|
671
|
+
let filterNode = parsePrimaryExpression();
|
|
672
|
+
if (filterNode instanceof Identifier && is(TOKEN_TYPES.OpenParen)) {
|
|
673
|
+
filterNode = parseCallExpression(filterNode);
|
|
674
|
+
}
|
|
675
|
+
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
676
|
+
const filterBody = [];
|
|
677
|
+
while (!isStatement("endfilter")) {
|
|
678
|
+
filterBody.push(parseAny());
|
|
679
|
+
}
|
|
680
|
+
expect(TOKEN_TYPES.OpenStatement, "Expected '{%'");
|
|
681
|
+
expectIdentifier("endfilter");
|
|
682
|
+
expect(TOKEN_TYPES.CloseStatement, "Expected '%}'");
|
|
683
|
+
result = new FilterStatement(filterNode, filterBody);
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
626
686
|
default:
|
|
627
|
-
throw new SyntaxError(`Unknown statement type: ${
|
|
687
|
+
throw new SyntaxError(`Unknown statement type: ${name}`);
|
|
628
688
|
}
|
|
629
689
|
return result;
|
|
630
690
|
}
|
|
@@ -635,42 +695,42 @@ function parse(tokens) {
|
|
|
635
695
|
return result;
|
|
636
696
|
}
|
|
637
697
|
function parseSetStatement() {
|
|
638
|
-
const left =
|
|
698
|
+
const left = parseExpressionSequence();
|
|
699
|
+
let value = null;
|
|
700
|
+
const body = [];
|
|
639
701
|
if (is(TOKEN_TYPES.Equals)) {
|
|
640
702
|
++current;
|
|
641
|
-
|
|
642
|
-
return new SetStatement(left, value, []);
|
|
703
|
+
value = parseExpressionSequence();
|
|
643
704
|
} else {
|
|
644
|
-
const body = [];
|
|
645
705
|
expect(TOKEN_TYPES.CloseStatement, "Expected %} token");
|
|
646
|
-
while (!(
|
|
647
|
-
|
|
648
|
-
body.push(another);
|
|
706
|
+
while (!isStatement("endset")) {
|
|
707
|
+
body.push(parseAny());
|
|
649
708
|
}
|
|
650
709
|
expect(TOKEN_TYPES.OpenStatement, "Expected {% token");
|
|
651
|
-
|
|
652
|
-
return new SetStatement(left, null, body);
|
|
710
|
+
expectIdentifier("endset");
|
|
653
711
|
}
|
|
712
|
+
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
713
|
+
return new SetStatement(left, value, body);
|
|
654
714
|
}
|
|
655
715
|
function parseIfStatement() {
|
|
656
716
|
const test = parseExpression();
|
|
657
717
|
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
658
718
|
const body = [];
|
|
659
719
|
const alternate = [];
|
|
660
|
-
while (!(
|
|
720
|
+
while (!isStatement("elif", "else", "endif")) {
|
|
661
721
|
body.push(parseAny());
|
|
662
722
|
}
|
|
663
|
-
if (
|
|
723
|
+
if (isStatement("elif")) {
|
|
664
724
|
++current;
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
725
|
+
++current;
|
|
726
|
+
const result = parseIfStatement();
|
|
727
|
+
alternate.push(result);
|
|
728
|
+
} else if (isStatement("else")) {
|
|
729
|
+
++current;
|
|
730
|
+
++current;
|
|
731
|
+
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
732
|
+
while (!isStatement("endif")) {
|
|
733
|
+
alternate.push(parseAny());
|
|
674
734
|
}
|
|
675
735
|
}
|
|
676
736
|
return new If(test, body, alternate);
|
|
@@ -683,7 +743,7 @@ function parse(tokens) {
|
|
|
683
743
|
const args = parseArgs();
|
|
684
744
|
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
685
745
|
const body = [];
|
|
686
|
-
while (
|
|
746
|
+
while (!isStatement("endmacro")) {
|
|
687
747
|
body.push(parseAny());
|
|
688
748
|
}
|
|
689
749
|
return new Macro(name, args, body);
|
|
@@ -706,19 +766,22 @@ function parse(tokens) {
|
|
|
706
766
|
if (!(loopVariable instanceof Identifier || loopVariable instanceof TupleLiteral)) {
|
|
707
767
|
throw new SyntaxError(`Expected identifier/tuple for the loop variable, got ${loopVariable.type} instead`);
|
|
708
768
|
}
|
|
709
|
-
|
|
769
|
+
if (!isIdentifier("in")) {
|
|
770
|
+
throw new SyntaxError("Expected `in` keyword following loop variable");
|
|
771
|
+
}
|
|
772
|
+
++current;
|
|
710
773
|
const iterable = parseExpression();
|
|
711
774
|
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
712
775
|
const body = [];
|
|
713
|
-
while (
|
|
776
|
+
while (!isStatement("endfor", "else")) {
|
|
714
777
|
body.push(parseAny());
|
|
715
778
|
}
|
|
716
779
|
const alternative = [];
|
|
717
|
-
if (
|
|
780
|
+
if (isStatement("else")) {
|
|
718
781
|
++current;
|
|
719
782
|
++current;
|
|
720
783
|
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
|
|
721
|
-
while (
|
|
784
|
+
while (!isStatement("endfor")) {
|
|
722
785
|
alternative.push(parseAny());
|
|
723
786
|
}
|
|
724
787
|
}
|
|
@@ -729,22 +792,22 @@ function parse(tokens) {
|
|
|
729
792
|
}
|
|
730
793
|
function parseIfExpression() {
|
|
731
794
|
const a = parseLogicalOrExpression();
|
|
732
|
-
if (
|
|
795
|
+
if (isIdentifier("if")) {
|
|
733
796
|
++current;
|
|
734
|
-
const
|
|
735
|
-
if (
|
|
797
|
+
const test = parseLogicalOrExpression();
|
|
798
|
+
if (isIdentifier("else")) {
|
|
736
799
|
++current;
|
|
737
|
-
const
|
|
738
|
-
return new
|
|
800
|
+
const falseExpr = parseIfExpression();
|
|
801
|
+
return new Ternary(test, a, falseExpr);
|
|
739
802
|
} else {
|
|
740
|
-
return new SelectExpression(a,
|
|
803
|
+
return new SelectExpression(a, test);
|
|
741
804
|
}
|
|
742
805
|
}
|
|
743
806
|
return a;
|
|
744
807
|
}
|
|
745
808
|
function parseLogicalOrExpression() {
|
|
746
809
|
let left = parseLogicalAndExpression();
|
|
747
|
-
while (
|
|
810
|
+
while (isIdentifier("or")) {
|
|
748
811
|
const operator = tokens[current];
|
|
749
812
|
++current;
|
|
750
813
|
const right = parseLogicalAndExpression();
|
|
@@ -754,7 +817,7 @@ function parse(tokens) {
|
|
|
754
817
|
}
|
|
755
818
|
function parseLogicalAndExpression() {
|
|
756
819
|
let left = parseLogicalNegationExpression();
|
|
757
|
-
while (
|
|
820
|
+
while (isIdentifier("and")) {
|
|
758
821
|
const operator = tokens[current];
|
|
759
822
|
++current;
|
|
760
823
|
const right = parseLogicalNegationExpression();
|
|
@@ -764,7 +827,7 @@ function parse(tokens) {
|
|
|
764
827
|
}
|
|
765
828
|
function parseLogicalNegationExpression() {
|
|
766
829
|
let right;
|
|
767
|
-
while (
|
|
830
|
+
while (isIdentifier("not")) {
|
|
768
831
|
const operator = tokens[current];
|
|
769
832
|
++current;
|
|
770
833
|
const arg = parseLogicalNegationExpression();
|
|
@@ -774,9 +837,18 @@ function parse(tokens) {
|
|
|
774
837
|
}
|
|
775
838
|
function parseComparisonExpression() {
|
|
776
839
|
let left = parseAdditiveExpression();
|
|
777
|
-
while (
|
|
778
|
-
|
|
779
|
-
|
|
840
|
+
while (true) {
|
|
841
|
+
let operator;
|
|
842
|
+
if (isIdentifier("not", "in")) {
|
|
843
|
+
operator = new Token("not in", TOKEN_TYPES.Identifier);
|
|
844
|
+
current += 2;
|
|
845
|
+
} else if (isIdentifier("in")) {
|
|
846
|
+
operator = tokens[current++];
|
|
847
|
+
} else if (is(TOKEN_TYPES.ComparisonBinaryOperator)) {
|
|
848
|
+
operator = tokens[current++];
|
|
849
|
+
} else {
|
|
850
|
+
break;
|
|
851
|
+
}
|
|
780
852
|
const right = parseAdditiveExpression();
|
|
781
853
|
left = new BinaryExpression(operator, left, right);
|
|
782
854
|
}
|
|
@@ -816,14 +888,21 @@ function parse(tokens) {
|
|
|
816
888
|
function parseArgumentsList() {
|
|
817
889
|
const args = [];
|
|
818
890
|
while (!is(TOKEN_TYPES.CloseParen)) {
|
|
819
|
-
let argument
|
|
820
|
-
if (
|
|
891
|
+
let argument;
|
|
892
|
+
if (tokens[current].type === TOKEN_TYPES.MultiplicativeBinaryOperator && tokens[current].value === "*") {
|
|
821
893
|
++current;
|
|
822
|
-
|
|
823
|
-
|
|
894
|
+
const expr = parseExpression();
|
|
895
|
+
argument = new SpreadExpression(expr);
|
|
896
|
+
} else {
|
|
897
|
+
argument = parseExpression();
|
|
898
|
+
if (is(TOKEN_TYPES.Equals)) {
|
|
899
|
+
++current;
|
|
900
|
+
if (!(argument instanceof Identifier)) {
|
|
901
|
+
throw new SyntaxError(`Expected identifier for keyword argument`);
|
|
902
|
+
}
|
|
903
|
+
const value = parseExpression();
|
|
904
|
+
argument = new KeywordArgumentExpression(argument, value);
|
|
824
905
|
}
|
|
825
|
-
const value = parseExpression();
|
|
826
|
-
argument = new KeywordArgumentExpression(argument, value);
|
|
827
906
|
}
|
|
828
907
|
args.push(argument);
|
|
829
908
|
if (is(TOKEN_TYPES.Comma)) {
|
|
@@ -864,7 +943,7 @@ function parse(tokens) {
|
|
|
864
943
|
const operator = tokens[current];
|
|
865
944
|
++current;
|
|
866
945
|
let property;
|
|
867
|
-
const computed = operator.type
|
|
946
|
+
const computed = operator.type === TOKEN_TYPES.OpenSquareBracket;
|
|
868
947
|
if (computed) {
|
|
869
948
|
property = parseMemberExpressionArgumentsList();
|
|
870
949
|
expect(TOKEN_TYPES.CloseSquareBracket, "Expected closing square bracket");
|
|
@@ -881,8 +960,7 @@ function parse(tokens) {
|
|
|
881
960
|
function parseMultiplicativeExpression() {
|
|
882
961
|
let left = parseTestExpression();
|
|
883
962
|
while (is(TOKEN_TYPES.MultiplicativeBinaryOperator)) {
|
|
884
|
-
const operator = tokens[current];
|
|
885
|
-
++current;
|
|
963
|
+
const operator = tokens[current++];
|
|
886
964
|
const right = parseTestExpression();
|
|
887
965
|
left = new BinaryExpression(operator, left, right);
|
|
888
966
|
}
|
|
@@ -890,18 +968,13 @@ function parse(tokens) {
|
|
|
890
968
|
}
|
|
891
969
|
function parseTestExpression() {
|
|
892
970
|
let operand = parseFilterExpression();
|
|
893
|
-
while (is
|
|
971
|
+
while (isIdentifier("is")) {
|
|
894
972
|
++current;
|
|
895
|
-
const negate =
|
|
973
|
+
const negate = isIdentifier("not");
|
|
896
974
|
if (negate) {
|
|
897
975
|
++current;
|
|
898
976
|
}
|
|
899
|
-
|
|
900
|
-
if (filter instanceof BooleanLiteral) {
|
|
901
|
-
filter = new Identifier(filter.value.toString());
|
|
902
|
-
} else if (filter instanceof NullLiteral) {
|
|
903
|
-
filter = new Identifier("none");
|
|
904
|
-
}
|
|
977
|
+
const filter = parsePrimaryExpression();
|
|
905
978
|
if (!(filter instanceof Identifier)) {
|
|
906
979
|
throw new SyntaxError(`Expected identifier for the test`);
|
|
907
980
|
}
|
|
@@ -925,34 +998,27 @@ function parse(tokens) {
|
|
|
925
998
|
return operand;
|
|
926
999
|
}
|
|
927
1000
|
function parsePrimaryExpression() {
|
|
928
|
-
const token = tokens[current];
|
|
1001
|
+
const token = tokens[current++];
|
|
929
1002
|
switch (token.type) {
|
|
930
|
-
case TOKEN_TYPES.NumericLiteral:
|
|
931
|
-
|
|
932
|
-
return new
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
return new NullLiteral(null);
|
|
1003
|
+
case TOKEN_TYPES.NumericLiteral: {
|
|
1004
|
+
const num = token.value;
|
|
1005
|
+
return num.includes(".") ? new FloatLiteral(Number(num)) : new IntegerLiteral(Number(num));
|
|
1006
|
+
}
|
|
1007
|
+
case TOKEN_TYPES.StringLiteral: {
|
|
1008
|
+
let value = token.value;
|
|
1009
|
+
while (is(TOKEN_TYPES.StringLiteral)) {
|
|
1010
|
+
value += tokens[current++].value;
|
|
1011
|
+
}
|
|
1012
|
+
return new StringLiteral(value);
|
|
1013
|
+
}
|
|
942
1014
|
case TOKEN_TYPES.Identifier:
|
|
943
|
-
++current;
|
|
944
1015
|
return new Identifier(token.value);
|
|
945
1016
|
case TOKEN_TYPES.OpenParen: {
|
|
946
|
-
++current;
|
|
947
1017
|
const expression = parseExpressionSequence();
|
|
948
|
-
|
|
949
|
-
throw new SyntaxError(`Expected closing parenthesis, got ${tokens[current].type} instead`);
|
|
950
|
-
}
|
|
951
|
-
++current;
|
|
1018
|
+
expect(TOKEN_TYPES.CloseParen, "Expected closing parenthesis, got ${tokens[current].type} instead.");
|
|
952
1019
|
return expression;
|
|
953
1020
|
}
|
|
954
1021
|
case TOKEN_TYPES.OpenSquareBracket: {
|
|
955
|
-
++current;
|
|
956
1022
|
const values = [];
|
|
957
1023
|
while (!is(TOKEN_TYPES.CloseSquareBracket)) {
|
|
958
1024
|
values.push(parseExpression());
|
|
@@ -964,7 +1030,6 @@ function parse(tokens) {
|
|
|
964
1030
|
return new ArrayLiteral(values);
|
|
965
1031
|
}
|
|
966
1032
|
case TOKEN_TYPES.OpenCurlyBracket: {
|
|
967
|
-
++current;
|
|
968
1033
|
const values = /* @__PURE__ */ new Map();
|
|
969
1034
|
while (!is(TOKEN_TYPES.CloseCurlyBracket)) {
|
|
970
1035
|
const key = parseExpression();
|
|
@@ -1018,6 +1083,52 @@ function slice(array, start, stop, step = 1) {
|
|
|
1018
1083
|
function titleCase(value) {
|
|
1019
1084
|
return value.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
1020
1085
|
}
|
|
1086
|
+
function strftime_now(format2) {
|
|
1087
|
+
return strftime(/* @__PURE__ */ new Date(), format2);
|
|
1088
|
+
}
|
|
1089
|
+
function strftime(date, format2) {
|
|
1090
|
+
const monthFormatterLong = new Intl.DateTimeFormat(void 0, { month: "long" });
|
|
1091
|
+
const monthFormatterShort = new Intl.DateTimeFormat(void 0, { month: "short" });
|
|
1092
|
+
const pad2 = (n) => n < 10 ? "0" + n : n.toString();
|
|
1093
|
+
return format2.replace(/%[YmdbBHM%]/g, (token) => {
|
|
1094
|
+
switch (token) {
|
|
1095
|
+
case "%Y":
|
|
1096
|
+
return date.getFullYear().toString();
|
|
1097
|
+
case "%m":
|
|
1098
|
+
return pad2(date.getMonth() + 1);
|
|
1099
|
+
case "%d":
|
|
1100
|
+
return pad2(date.getDate());
|
|
1101
|
+
case "%b":
|
|
1102
|
+
return monthFormatterShort.format(date);
|
|
1103
|
+
case "%B":
|
|
1104
|
+
return monthFormatterLong.format(date);
|
|
1105
|
+
case "%H":
|
|
1106
|
+
return pad2(date.getHours());
|
|
1107
|
+
case "%M":
|
|
1108
|
+
return pad2(date.getMinutes());
|
|
1109
|
+
case "%%":
|
|
1110
|
+
return "%";
|
|
1111
|
+
default:
|
|
1112
|
+
return token;
|
|
1113
|
+
}
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
function escapeRegExp(s) {
|
|
1117
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1118
|
+
}
|
|
1119
|
+
function replace(str, oldvalue, newvalue, count) {
|
|
1120
|
+
if (count === 0)
|
|
1121
|
+
return str;
|
|
1122
|
+
let remaining = count == null || count < 0 ? Infinity : count;
|
|
1123
|
+
const pattern = oldvalue.length === 0 ? new RegExp("(?=)", "gu") : new RegExp(escapeRegExp(oldvalue), "gu");
|
|
1124
|
+
return str.replaceAll(pattern, (match) => {
|
|
1125
|
+
if (remaining > 0) {
|
|
1126
|
+
--remaining;
|
|
1127
|
+
return newvalue;
|
|
1128
|
+
}
|
|
1129
|
+
return match;
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1021
1132
|
|
|
1022
1133
|
// src/runtime.ts
|
|
1023
1134
|
var BreakControl = class extends Error {
|
|
@@ -1045,9 +1156,18 @@ var RuntimeValue = class {
|
|
|
1045
1156
|
__bool__() {
|
|
1046
1157
|
return new BooleanValue(!!this.value);
|
|
1047
1158
|
}
|
|
1159
|
+
toString() {
|
|
1160
|
+
return String(this.value);
|
|
1161
|
+
}
|
|
1162
|
+
};
|
|
1163
|
+
var IntegerValue = class extends RuntimeValue {
|
|
1164
|
+
type = "IntegerValue";
|
|
1048
1165
|
};
|
|
1049
|
-
var
|
|
1050
|
-
type = "
|
|
1166
|
+
var FloatValue = class extends RuntimeValue {
|
|
1167
|
+
type = "FloatValue";
|
|
1168
|
+
toString() {
|
|
1169
|
+
return this.value % 1 === 0 ? this.value.toFixed(1) : this.value.toString();
|
|
1170
|
+
}
|
|
1051
1171
|
};
|
|
1052
1172
|
var StringValue = class extends RuntimeValue {
|
|
1053
1173
|
type = "StringValue";
|
|
@@ -1076,7 +1196,13 @@ var StringValue = class extends RuntimeValue {
|
|
|
1076
1196
|
return new StringValue(titleCase(this.value));
|
|
1077
1197
|
})
|
|
1078
1198
|
],
|
|
1079
|
-
[
|
|
1199
|
+
[
|
|
1200
|
+
"capitalize",
|
|
1201
|
+
new FunctionValue(() => {
|
|
1202
|
+
return new StringValue(this.value.charAt(0).toUpperCase() + this.value.slice(1));
|
|
1203
|
+
})
|
|
1204
|
+
],
|
|
1205
|
+
["length", new IntegerValue(this.value.length)],
|
|
1080
1206
|
[
|
|
1081
1207
|
"rstrip",
|
|
1082
1208
|
new FunctionValue(() => {
|
|
@@ -1095,11 +1221,21 @@ var StringValue = class extends RuntimeValue {
|
|
|
1095
1221
|
if (args.length === 0) {
|
|
1096
1222
|
throw new Error("startswith() requires at least one argument");
|
|
1097
1223
|
}
|
|
1098
|
-
const
|
|
1099
|
-
if (
|
|
1100
|
-
|
|
1224
|
+
const pattern = args[0];
|
|
1225
|
+
if (pattern instanceof StringValue) {
|
|
1226
|
+
return new BooleanValue(this.value.startsWith(pattern.value));
|
|
1227
|
+
} else if (pattern instanceof ArrayValue) {
|
|
1228
|
+
for (const item of pattern.value) {
|
|
1229
|
+
if (!(item instanceof StringValue)) {
|
|
1230
|
+
throw new Error("startswith() tuple elements must be strings");
|
|
1231
|
+
}
|
|
1232
|
+
if (this.value.startsWith(item.value)) {
|
|
1233
|
+
return new BooleanValue(true);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
return new BooleanValue(false);
|
|
1101
1237
|
}
|
|
1102
|
-
|
|
1238
|
+
throw new Error("startswith() argument must be a string or tuple of strings");
|
|
1103
1239
|
})
|
|
1104
1240
|
],
|
|
1105
1241
|
[
|
|
@@ -1108,11 +1244,21 @@ var StringValue = class extends RuntimeValue {
|
|
|
1108
1244
|
if (args.length === 0) {
|
|
1109
1245
|
throw new Error("endswith() requires at least one argument");
|
|
1110
1246
|
}
|
|
1111
|
-
const
|
|
1112
|
-
if (
|
|
1113
|
-
|
|
1247
|
+
const pattern = args[0];
|
|
1248
|
+
if (pattern instanceof StringValue) {
|
|
1249
|
+
return new BooleanValue(this.value.endsWith(pattern.value));
|
|
1250
|
+
} else if (pattern instanceof ArrayValue) {
|
|
1251
|
+
for (const item of pattern.value) {
|
|
1252
|
+
if (!(item instanceof StringValue)) {
|
|
1253
|
+
throw new Error("endswith() tuple elements must be strings");
|
|
1254
|
+
}
|
|
1255
|
+
if (this.value.endsWith(item.value)) {
|
|
1256
|
+
return new BooleanValue(true);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
return new BooleanValue(false);
|
|
1114
1260
|
}
|
|
1115
|
-
|
|
1261
|
+
throw new Error("endswith() argument must be a string or tuple of strings");
|
|
1116
1262
|
})
|
|
1117
1263
|
],
|
|
1118
1264
|
[
|
|
@@ -1124,8 +1270,8 @@ var StringValue = class extends RuntimeValue {
|
|
|
1124
1270
|
if (!(sep instanceof StringValue || sep instanceof NullValue)) {
|
|
1125
1271
|
throw new Error("sep argument must be a string or null");
|
|
1126
1272
|
}
|
|
1127
|
-
const maxsplit = args[1] ?? new
|
|
1128
|
-
if (!(maxsplit instanceof
|
|
1273
|
+
const maxsplit = args[1] ?? new IntegerValue(-1);
|
|
1274
|
+
if (!(maxsplit instanceof IntegerValue)) {
|
|
1129
1275
|
throw new Error("maxsplit argument must be a number");
|
|
1130
1276
|
}
|
|
1131
1277
|
let result = [];
|
|
@@ -1149,6 +1295,33 @@ var StringValue = class extends RuntimeValue {
|
|
|
1149
1295
|
}
|
|
1150
1296
|
return new ArrayValue(result.map((part) => new StringValue(part)));
|
|
1151
1297
|
})
|
|
1298
|
+
],
|
|
1299
|
+
[
|
|
1300
|
+
"replace",
|
|
1301
|
+
new FunctionValue((args) => {
|
|
1302
|
+
if (args.length < 2) {
|
|
1303
|
+
throw new Error("replace() requires at least two arguments");
|
|
1304
|
+
}
|
|
1305
|
+
const oldValue = args[0];
|
|
1306
|
+
const newValue = args[1];
|
|
1307
|
+
if (!(oldValue instanceof StringValue && newValue instanceof StringValue)) {
|
|
1308
|
+
throw new Error("replace() arguments must be strings");
|
|
1309
|
+
}
|
|
1310
|
+
let count;
|
|
1311
|
+
if (args.length > 2) {
|
|
1312
|
+
if (args[2].type === "KeywordArgumentsValue") {
|
|
1313
|
+
count = args[2].value.get("count") ?? new NullValue();
|
|
1314
|
+
} else {
|
|
1315
|
+
count = args[2];
|
|
1316
|
+
}
|
|
1317
|
+
} else {
|
|
1318
|
+
count = new NullValue();
|
|
1319
|
+
}
|
|
1320
|
+
if (!(count instanceof IntegerValue || count instanceof NullValue)) {
|
|
1321
|
+
throw new Error("replace() count argument must be a number or null");
|
|
1322
|
+
}
|
|
1323
|
+
return new StringValue(replace(this.value, oldValue.value, newValue.value, count.value));
|
|
1324
|
+
})
|
|
1152
1325
|
]
|
|
1153
1326
|
]);
|
|
1154
1327
|
};
|
|
@@ -1178,22 +1351,28 @@ var ObjectValue = class extends RuntimeValue {
|
|
|
1178
1351
|
return this.value.get(key.value) ?? defaultValue ?? new NullValue();
|
|
1179
1352
|
})
|
|
1180
1353
|
],
|
|
1181
|
-
[
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
return new ArrayValue(
|
|
1185
|
-
Array.from(this.value.entries()).map(([key, value]) => new ArrayValue([new StringValue(key), value]))
|
|
1186
|
-
);
|
|
1187
|
-
})
|
|
1188
|
-
]
|
|
1354
|
+
["items", new FunctionValue(() => this.items())],
|
|
1355
|
+
["keys", new FunctionValue(() => this.keys())],
|
|
1356
|
+
["values", new FunctionValue(() => this.values())]
|
|
1189
1357
|
]);
|
|
1358
|
+
items() {
|
|
1359
|
+
return new ArrayValue(
|
|
1360
|
+
Array.from(this.value.entries()).map(([key, value]) => new ArrayValue([new StringValue(key), value]))
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1363
|
+
keys() {
|
|
1364
|
+
return new ArrayValue(Array.from(this.value.keys()).map((key) => new StringValue(key)));
|
|
1365
|
+
}
|
|
1366
|
+
values() {
|
|
1367
|
+
return new ArrayValue(Array.from(this.value.values()));
|
|
1368
|
+
}
|
|
1190
1369
|
};
|
|
1191
1370
|
var KeywordArgumentsValue = class extends ObjectValue {
|
|
1192
1371
|
type = "KeywordArgumentsValue";
|
|
1193
1372
|
};
|
|
1194
1373
|
var ArrayValue = class extends RuntimeValue {
|
|
1195
1374
|
type = "ArrayValue";
|
|
1196
|
-
builtins = /* @__PURE__ */ new Map([["length", new
|
|
1375
|
+
builtins = /* @__PURE__ */ new Map([["length", new IntegerValue(this.value.length)]]);
|
|
1197
1376
|
/**
|
|
1198
1377
|
* NOTE: necessary to override since all JavaScript arrays are considered truthy,
|
|
1199
1378
|
* while only non-empty Python arrays are consider truthy.
|
|
@@ -1248,8 +1427,8 @@ var Environment = class {
|
|
|
1248
1427
|
[
|
|
1249
1428
|
"odd",
|
|
1250
1429
|
(operand) => {
|
|
1251
|
-
if (operand
|
|
1252
|
-
throw new Error(`
|
|
1430
|
+
if (!(operand instanceof IntegerValue)) {
|
|
1431
|
+
throw new Error(`cannot odd on ${operand.type}`);
|
|
1253
1432
|
}
|
|
1254
1433
|
return operand.value % 2 !== 0;
|
|
1255
1434
|
}
|
|
@@ -1257,8 +1436,8 @@ var Environment = class {
|
|
|
1257
1436
|
[
|
|
1258
1437
|
"even",
|
|
1259
1438
|
(operand) => {
|
|
1260
|
-
if (operand
|
|
1261
|
-
throw new Error(`
|
|
1439
|
+
if (!(operand instanceof IntegerValue)) {
|
|
1440
|
+
throw new Error(`cannot even on ${operand.type}`);
|
|
1262
1441
|
}
|
|
1263
1442
|
return operand.value % 2 === 0;
|
|
1264
1443
|
}
|
|
@@ -1267,8 +1446,8 @@ var Environment = class {
|
|
|
1267
1446
|
["true", (operand) => operand.type === "BooleanValue" && operand.value],
|
|
1268
1447
|
["none", (operand) => operand.type === "NullValue"],
|
|
1269
1448
|
["string", (operand) => operand.type === "StringValue"],
|
|
1270
|
-
["number", (operand) => operand
|
|
1271
|
-
["integer", (operand) => operand
|
|
1449
|
+
["number", (operand) => operand instanceof IntegerValue || operand instanceof FloatValue],
|
|
1450
|
+
["integer", (operand) => operand instanceof IntegerValue],
|
|
1272
1451
|
["iterable", (operand) => operand.type === "ArrayValue" || operand.type === "StringValue"],
|
|
1273
1452
|
["mapping", (operand) => operand.type === "ObjectValue"],
|
|
1274
1453
|
[
|
|
@@ -1339,6 +1518,19 @@ var Environment = class {
|
|
|
1339
1518
|
}
|
|
1340
1519
|
}
|
|
1341
1520
|
};
|
|
1521
|
+
function setupGlobals(env) {
|
|
1522
|
+
env.set("false", false);
|
|
1523
|
+
env.set("true", true);
|
|
1524
|
+
env.set("none", null);
|
|
1525
|
+
env.set("raise_exception", (args) => {
|
|
1526
|
+
throw new Error(args);
|
|
1527
|
+
});
|
|
1528
|
+
env.set("range", range);
|
|
1529
|
+
env.set("strftime_now", strftime_now);
|
|
1530
|
+
env.set("True", true);
|
|
1531
|
+
env.set("False", false);
|
|
1532
|
+
env.set("None", null);
|
|
1533
|
+
}
|
|
1342
1534
|
var Interpreter = class {
|
|
1343
1535
|
global;
|
|
1344
1536
|
constructor(env) {
|
|
@@ -1369,29 +1561,39 @@ var Interpreter = class {
|
|
|
1369
1561
|
return new BooleanValue(left.value != right.value);
|
|
1370
1562
|
}
|
|
1371
1563
|
if (left instanceof UndefinedValue || right instanceof UndefinedValue) {
|
|
1372
|
-
|
|
1564
|
+
if (right instanceof UndefinedValue && ["in", "not in"].includes(node.operator.value)) {
|
|
1565
|
+
return new BooleanValue(node.operator.value === "not in");
|
|
1566
|
+
}
|
|
1567
|
+
throw new Error(`Cannot perform operation ${node.operator.value} on undefined values`);
|
|
1373
1568
|
} else if (left instanceof NullValue || right instanceof NullValue) {
|
|
1374
1569
|
throw new Error("Cannot perform operation on null values");
|
|
1375
|
-
} else if (
|
|
1570
|
+
} else if (node.operator.value === "~") {
|
|
1571
|
+
return new StringValue(left.value.toString() + right.value.toString());
|
|
1572
|
+
} else if ((left instanceof IntegerValue || left instanceof FloatValue) && (right instanceof IntegerValue || right instanceof FloatValue)) {
|
|
1573
|
+
const a = left.value, b = right.value;
|
|
1376
1574
|
switch (node.operator.value) {
|
|
1377
1575
|
case "+":
|
|
1378
|
-
return new NumericValue(left.value + right.value);
|
|
1379
1576
|
case "-":
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1577
|
+
case "*": {
|
|
1578
|
+
const res = node.operator.value === "+" ? a + b : node.operator.value === "-" ? a - b : a * b;
|
|
1579
|
+
const isFloat = left instanceof FloatValue || right instanceof FloatValue;
|
|
1580
|
+
return isFloat ? new FloatValue(res) : new IntegerValue(res);
|
|
1581
|
+
}
|
|
1383
1582
|
case "/":
|
|
1384
|
-
return new
|
|
1385
|
-
case "%":
|
|
1386
|
-
|
|
1583
|
+
return new FloatValue(a / b);
|
|
1584
|
+
case "%": {
|
|
1585
|
+
const rem = a % b;
|
|
1586
|
+
const isFloat = left instanceof FloatValue || right instanceof FloatValue;
|
|
1587
|
+
return isFloat ? new FloatValue(rem) : new IntegerValue(rem);
|
|
1588
|
+
}
|
|
1387
1589
|
case "<":
|
|
1388
|
-
return new BooleanValue(
|
|
1590
|
+
return new BooleanValue(a < b);
|
|
1389
1591
|
case ">":
|
|
1390
|
-
return new BooleanValue(
|
|
1592
|
+
return new BooleanValue(a > b);
|
|
1391
1593
|
case ">=":
|
|
1392
|
-
return new BooleanValue(
|
|
1594
|
+
return new BooleanValue(a >= b);
|
|
1393
1595
|
case "<=":
|
|
1394
|
-
return new BooleanValue(
|
|
1596
|
+
return new BooleanValue(a <= b);
|
|
1395
1597
|
}
|
|
1396
1598
|
} else if (left instanceof ArrayValue && right instanceof ArrayValue) {
|
|
1397
1599
|
switch (node.operator.value) {
|
|
@@ -1435,7 +1637,16 @@ var Interpreter = class {
|
|
|
1435
1637
|
const positionalArguments = [];
|
|
1436
1638
|
const keywordArguments = /* @__PURE__ */ new Map();
|
|
1437
1639
|
for (const argument of args) {
|
|
1438
|
-
if (argument.type === "
|
|
1640
|
+
if (argument.type === "SpreadExpression") {
|
|
1641
|
+
const spreadNode = argument;
|
|
1642
|
+
const val = this.evaluate(spreadNode.argument, environment);
|
|
1643
|
+
if (!(val instanceof ArrayValue)) {
|
|
1644
|
+
throw new Error(`Cannot unpack non-iterable type: ${val.type}`);
|
|
1645
|
+
}
|
|
1646
|
+
for (const item of val.value) {
|
|
1647
|
+
positionalArguments.push(item);
|
|
1648
|
+
}
|
|
1649
|
+
} else if (argument.type === "KeywordArgumentExpression") {
|
|
1439
1650
|
const kwarg = argument;
|
|
1440
1651
|
keywordArguments.set(kwarg.key.value, this.evaluate(kwarg.value, environment));
|
|
1441
1652
|
} else {
|
|
@@ -1447,13 +1658,9 @@ var Interpreter = class {
|
|
|
1447
1658
|
}
|
|
1448
1659
|
return [positionalArguments, keywordArguments];
|
|
1449
1660
|
}
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
evaluateFilterExpression(node, environment) {
|
|
1454
|
-
const operand = this.evaluate(node.operand, environment);
|
|
1455
|
-
if (node.filter.type === "Identifier") {
|
|
1456
|
-
const filter = node.filter;
|
|
1661
|
+
applyFilter(operand, filterNode, environment) {
|
|
1662
|
+
if (filterNode.type === "Identifier") {
|
|
1663
|
+
const filter = filterNode;
|
|
1457
1664
|
if (filter.value === "tojson") {
|
|
1458
1665
|
return new StringValue(toJSON(operand));
|
|
1459
1666
|
}
|
|
@@ -1466,7 +1673,7 @@ var Interpreter = class {
|
|
|
1466
1673
|
case "last":
|
|
1467
1674
|
return operand.value[operand.value.length - 1];
|
|
1468
1675
|
case "length":
|
|
1469
|
-
return new
|
|
1676
|
+
return new IntegerValue(operand.value.length);
|
|
1470
1677
|
case "reverse":
|
|
1471
1678
|
return new ArrayValue(operand.value.reverse());
|
|
1472
1679
|
case "sort":
|
|
@@ -1476,7 +1683,8 @@ var Interpreter = class {
|
|
|
1476
1683
|
throw new Error(`Cannot compare different types: ${a.type} and ${b.type}`);
|
|
1477
1684
|
}
|
|
1478
1685
|
switch (a.type) {
|
|
1479
|
-
case "
|
|
1686
|
+
case "IntegerValue":
|
|
1687
|
+
case "FloatValue":
|
|
1480
1688
|
return a.value - b.value;
|
|
1481
1689
|
case "StringValue":
|
|
1482
1690
|
return a.value.localeCompare(b.value);
|
|
@@ -1489,21 +1697,40 @@ var Interpreter = class {
|
|
|
1489
1697
|
return new StringValue(operand.value.map((x) => x.value).join(""));
|
|
1490
1698
|
case "string":
|
|
1491
1699
|
return new StringValue(toJSON(operand));
|
|
1700
|
+
case "unique": {
|
|
1701
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1702
|
+
const output = [];
|
|
1703
|
+
for (const item of operand.value) {
|
|
1704
|
+
if (!seen.has(item.value)) {
|
|
1705
|
+
seen.add(item.value);
|
|
1706
|
+
output.push(item);
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
return new ArrayValue(output);
|
|
1710
|
+
}
|
|
1492
1711
|
default:
|
|
1493
1712
|
throw new Error(`Unknown ArrayValue filter: ${filter.value}`);
|
|
1494
1713
|
}
|
|
1495
1714
|
} else if (operand instanceof StringValue) {
|
|
1496
1715
|
switch (filter.value) {
|
|
1497
1716
|
case "length":
|
|
1498
|
-
return new NumericValue(operand.value.length);
|
|
1499
1717
|
case "upper":
|
|
1500
|
-
return new StringValue(operand.value.toUpperCase());
|
|
1501
1718
|
case "lower":
|
|
1502
|
-
return new StringValue(operand.value.toLowerCase());
|
|
1503
1719
|
case "title":
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1720
|
+
case "capitalize": {
|
|
1721
|
+
const builtin = operand.builtins.get(filter.value);
|
|
1722
|
+
if (builtin instanceof FunctionValue) {
|
|
1723
|
+
return builtin.value(
|
|
1724
|
+
/* no arguments */
|
|
1725
|
+
[],
|
|
1726
|
+
environment
|
|
1727
|
+
);
|
|
1728
|
+
} else if (builtin instanceof IntegerValue) {
|
|
1729
|
+
return builtin;
|
|
1730
|
+
} else {
|
|
1731
|
+
throw new Error(`Unknown StringValue filter: ${filter.value}`);
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1507
1734
|
case "trim":
|
|
1508
1735
|
return new StringValue(operand.value.trim());
|
|
1509
1736
|
case "indent":
|
|
@@ -1518,13 +1745,25 @@ var Interpreter = class {
|
|
|
1518
1745
|
case "join":
|
|
1519
1746
|
case "string":
|
|
1520
1747
|
return operand;
|
|
1748
|
+
case "int": {
|
|
1749
|
+
const val = parseInt(operand.value, 10);
|
|
1750
|
+
return new IntegerValue(isNaN(val) ? 0 : val);
|
|
1751
|
+
}
|
|
1752
|
+
case "float": {
|
|
1753
|
+
const val = parseFloat(operand.value);
|
|
1754
|
+
return new FloatValue(isNaN(val) ? 0 : val);
|
|
1755
|
+
}
|
|
1521
1756
|
default:
|
|
1522
1757
|
throw new Error(`Unknown StringValue filter: ${filter.value}`);
|
|
1523
1758
|
}
|
|
1524
|
-
} else if (operand instanceof
|
|
1759
|
+
} else if (operand instanceof IntegerValue || operand instanceof FloatValue) {
|
|
1525
1760
|
switch (filter.value) {
|
|
1526
1761
|
case "abs":
|
|
1527
|
-
return new
|
|
1762
|
+
return operand instanceof IntegerValue ? new IntegerValue(Math.abs(operand.value)) : new FloatValue(Math.abs(operand.value));
|
|
1763
|
+
case "int":
|
|
1764
|
+
return new IntegerValue(Math.floor(operand.value));
|
|
1765
|
+
case "float":
|
|
1766
|
+
return new FloatValue(operand.value);
|
|
1528
1767
|
default:
|
|
1529
1768
|
throw new Error(`Unknown NumericValue filter: ${filter.value}`);
|
|
1530
1769
|
}
|
|
@@ -1535,14 +1774,27 @@ var Interpreter = class {
|
|
|
1535
1774
|
Array.from(operand.value.entries()).map(([key, value]) => new ArrayValue([new StringValue(key), value]))
|
|
1536
1775
|
);
|
|
1537
1776
|
case "length":
|
|
1538
|
-
return new
|
|
1777
|
+
return new IntegerValue(operand.value.size);
|
|
1539
1778
|
default:
|
|
1540
1779
|
throw new Error(`Unknown ObjectValue filter: ${filter.value}`);
|
|
1541
1780
|
}
|
|
1781
|
+
} else if (operand instanceof BooleanValue) {
|
|
1782
|
+
switch (filter.value) {
|
|
1783
|
+
case "bool":
|
|
1784
|
+
return new BooleanValue(operand.value);
|
|
1785
|
+
case "int":
|
|
1786
|
+
return new IntegerValue(operand.value ? 1 : 0);
|
|
1787
|
+
case "float":
|
|
1788
|
+
return new FloatValue(operand.value ? 1 : 0);
|
|
1789
|
+
case "string":
|
|
1790
|
+
return new StringValue(operand.value ? "true" : "false");
|
|
1791
|
+
default:
|
|
1792
|
+
throw new Error(`Unknown BooleanValue filter: ${filter.value}`);
|
|
1793
|
+
}
|
|
1542
1794
|
}
|
|
1543
1795
|
throw new Error(`Cannot apply filter "${filter.value}" to type: ${operand.type}`);
|
|
1544
|
-
} else if (
|
|
1545
|
-
const filter =
|
|
1796
|
+
} else if (filterNode.type === "CallExpression") {
|
|
1797
|
+
const filter = filterNode;
|
|
1546
1798
|
if (filter.callee.type !== "Identifier") {
|
|
1547
1799
|
throw new Error(`Unknown filter: ${filter.callee.type}`);
|
|
1548
1800
|
}
|
|
@@ -1550,7 +1802,7 @@ var Interpreter = class {
|
|
|
1550
1802
|
if (filterName === "tojson") {
|
|
1551
1803
|
const [, kwargs] = this.evaluateArguments(filter.args, environment);
|
|
1552
1804
|
const indent = kwargs.get("indent") ?? new NullValue();
|
|
1553
|
-
if (!(indent instanceof
|
|
1805
|
+
if (!(indent instanceof IntegerValue || indent instanceof NullValue)) {
|
|
1554
1806
|
throw new Error("If set, indent must be a number");
|
|
1555
1807
|
}
|
|
1556
1808
|
return new StringValue(toJSON(operand, indent.value));
|
|
@@ -1569,6 +1821,30 @@ var Interpreter = class {
|
|
|
1569
1821
|
throw new Error("separator must be a string");
|
|
1570
1822
|
}
|
|
1571
1823
|
return new StringValue(value.join(separator.value));
|
|
1824
|
+
} else if (filterName === "int" || filterName === "float") {
|
|
1825
|
+
const [args, kwargs] = this.evaluateArguments(filter.args, environment);
|
|
1826
|
+
const defaultValue = args.at(0) ?? kwargs.get("default") ?? (filterName === "int" ? new IntegerValue(0) : new FloatValue(0));
|
|
1827
|
+
if (operand instanceof StringValue) {
|
|
1828
|
+
const val = filterName === "int" ? parseInt(operand.value, 10) : parseFloat(operand.value);
|
|
1829
|
+
return isNaN(val) ? defaultValue : filterName === "int" ? new IntegerValue(val) : new FloatValue(val);
|
|
1830
|
+
} else if (operand instanceof IntegerValue || operand instanceof FloatValue) {
|
|
1831
|
+
return operand;
|
|
1832
|
+
} else if (operand instanceof BooleanValue) {
|
|
1833
|
+
return filterName === "int" ? new IntegerValue(operand.value ? 1 : 0) : new FloatValue(operand.value ? 1 : 0);
|
|
1834
|
+
} else {
|
|
1835
|
+
throw new Error(`Cannot apply filter "${filterName}" to type: ${operand.type}`);
|
|
1836
|
+
}
|
|
1837
|
+
} else if (filterName === "default") {
|
|
1838
|
+
const [args, kwargs] = this.evaluateArguments(filter.args, environment);
|
|
1839
|
+
const defaultValue = args[0] ?? new StringValue("");
|
|
1840
|
+
const booleanValue = args[1] ?? kwargs.get("boolean") ?? new BooleanValue(false);
|
|
1841
|
+
if (!(booleanValue instanceof BooleanValue)) {
|
|
1842
|
+
throw new Error("`default` filter flag must be a boolean");
|
|
1843
|
+
}
|
|
1844
|
+
if (operand instanceof UndefinedValue || booleanValue.value && !operand.__bool__().value) {
|
|
1845
|
+
return defaultValue;
|
|
1846
|
+
}
|
|
1847
|
+
return operand;
|
|
1572
1848
|
}
|
|
1573
1849
|
if (operand instanceof ArrayValue) {
|
|
1574
1850
|
switch (filterName) {
|
|
@@ -1624,8 +1900,8 @@ var Interpreter = class {
|
|
|
1624
1900
|
switch (filterName) {
|
|
1625
1901
|
case "indent": {
|
|
1626
1902
|
const [args, kwargs] = this.evaluateArguments(filter.args, environment);
|
|
1627
|
-
const width = args.at(0) ?? kwargs.get("width") ?? new
|
|
1628
|
-
if (!(width instanceof
|
|
1903
|
+
const width = args.at(0) ?? kwargs.get("width") ?? new IntegerValue(4);
|
|
1904
|
+
if (!(width instanceof IntegerValue)) {
|
|
1629
1905
|
throw new Error("width must be a number");
|
|
1630
1906
|
}
|
|
1631
1907
|
const first = args.at(1) ?? kwargs.get("first") ?? new BooleanValue(false);
|
|
@@ -1637,13 +1913,28 @@ var Interpreter = class {
|
|
|
1637
1913
|
);
|
|
1638
1914
|
return new StringValue(indented.join("\n"));
|
|
1639
1915
|
}
|
|
1916
|
+
case "replace": {
|
|
1917
|
+
const replaceFn = operand.builtins.get("replace");
|
|
1918
|
+
if (!(replaceFn instanceof FunctionValue)) {
|
|
1919
|
+
throw new Error("replace filter not available");
|
|
1920
|
+
}
|
|
1921
|
+
const [args, kwargs] = this.evaluateArguments(filter.args, environment);
|
|
1922
|
+
return replaceFn.value([...args, new KeywordArgumentsValue(kwargs)], environment);
|
|
1923
|
+
}
|
|
1640
1924
|
}
|
|
1641
1925
|
throw new Error(`Unknown StringValue filter: ${filterName}`);
|
|
1642
1926
|
} else {
|
|
1643
1927
|
throw new Error(`Cannot apply filter "${filterName}" to type: ${operand.type}`);
|
|
1644
1928
|
}
|
|
1645
1929
|
}
|
|
1646
|
-
throw new Error(`Unknown filter: ${
|
|
1930
|
+
throw new Error(`Unknown filter: ${filterNode.type}`);
|
|
1931
|
+
}
|
|
1932
|
+
/**
|
|
1933
|
+
* Evaluates expressions following the filter operation type.
|
|
1934
|
+
*/
|
|
1935
|
+
evaluateFilterExpression(node, environment) {
|
|
1936
|
+
const operand = this.evaluate(node.operand, environment);
|
|
1937
|
+
return this.applyFilter(operand, node.filter, environment);
|
|
1647
1938
|
}
|
|
1648
1939
|
/**
|
|
1649
1940
|
* Evaluates expressions following the test operation type.
|
|
@@ -1657,6 +1948,16 @@ var Interpreter = class {
|
|
|
1657
1948
|
const result = test(operand);
|
|
1658
1949
|
return new BooleanValue(node.negate ? !result : result);
|
|
1659
1950
|
}
|
|
1951
|
+
/**
|
|
1952
|
+
* Evaluates expressions following the select operation type.
|
|
1953
|
+
*/
|
|
1954
|
+
evaluateSelectExpression(node, environment) {
|
|
1955
|
+
const predicate = this.evaluate(node.test, environment);
|
|
1956
|
+
if (!predicate.__bool__().value) {
|
|
1957
|
+
return new UndefinedValue();
|
|
1958
|
+
}
|
|
1959
|
+
return this.evaluate(node.lhs, environment);
|
|
1960
|
+
}
|
|
1660
1961
|
/**
|
|
1661
1962
|
* Evaluates expressions following the unary operation type.
|
|
1662
1963
|
*/
|
|
@@ -1669,6 +1970,10 @@ var Interpreter = class {
|
|
|
1669
1970
|
throw new SyntaxError(`Unknown operator: ${node.operator.value}`);
|
|
1670
1971
|
}
|
|
1671
1972
|
}
|
|
1973
|
+
evaluateTernaryExpression(node, environment) {
|
|
1974
|
+
const cond = this.evaluate(node.condition, environment);
|
|
1975
|
+
return cond.__bool__().value ? this.evaluate(node.trueExpr, environment) : this.evaluate(node.falseExpr, environment);
|
|
1976
|
+
}
|
|
1672
1977
|
evalProgram(program, environment) {
|
|
1673
1978
|
return this.evaluateBlock(program.body, environment);
|
|
1674
1979
|
}
|
|
@@ -1677,7 +1982,7 @@ var Interpreter = class {
|
|
|
1677
1982
|
for (const statement of statements) {
|
|
1678
1983
|
const lastEvaluated = this.evaluate(statement, environment);
|
|
1679
1984
|
if (lastEvaluated.type !== "NullValue" && lastEvaluated.type !== "UndefinedValue") {
|
|
1680
|
-
result += lastEvaluated.
|
|
1985
|
+
result += lastEvaluated.toString();
|
|
1681
1986
|
}
|
|
1682
1987
|
}
|
|
1683
1988
|
return new StringValue(result);
|
|
@@ -1703,13 +2008,13 @@ var Interpreter = class {
|
|
|
1703
2008
|
const start = this.evaluate(expr.start, environment);
|
|
1704
2009
|
const stop = this.evaluate(expr.stop, environment);
|
|
1705
2010
|
const step = this.evaluate(expr.step, environment);
|
|
1706
|
-
if (!(start instanceof
|
|
2011
|
+
if (!(start instanceof IntegerValue || start instanceof UndefinedValue)) {
|
|
1707
2012
|
throw new Error("Slice start must be numeric or undefined");
|
|
1708
2013
|
}
|
|
1709
|
-
if (!(stop instanceof
|
|
2014
|
+
if (!(stop instanceof IntegerValue || stop instanceof UndefinedValue)) {
|
|
1710
2015
|
throw new Error("Slice stop must be numeric or undefined");
|
|
1711
2016
|
}
|
|
1712
|
-
if (!(step instanceof
|
|
2017
|
+
if (!(step instanceof IntegerValue || step instanceof UndefinedValue)) {
|
|
1713
2018
|
throw new Error("Slice step must be numeric or undefined");
|
|
1714
2019
|
}
|
|
1715
2020
|
if (object instanceof ArrayValue) {
|
|
@@ -1737,7 +2042,7 @@ var Interpreter = class {
|
|
|
1737
2042
|
}
|
|
1738
2043
|
value = object.value.get(property.value) ?? object.builtins.get(property.value);
|
|
1739
2044
|
} else if (object instanceof ArrayValue || object instanceof StringValue) {
|
|
1740
|
-
if (property instanceof
|
|
2045
|
+
if (property instanceof IntegerValue) {
|
|
1741
2046
|
value = object.value.at(property.value);
|
|
1742
2047
|
if (object instanceof StringValue) {
|
|
1743
2048
|
value = new StringValue(object.value.at(property.value));
|
|
@@ -1760,6 +2065,22 @@ var Interpreter = class {
|
|
|
1760
2065
|
if (node.assignee.type === "Identifier") {
|
|
1761
2066
|
const variableName = node.assignee.value;
|
|
1762
2067
|
environment.setVariable(variableName, rhs);
|
|
2068
|
+
} else if (node.assignee.type === "TupleLiteral") {
|
|
2069
|
+
const tuple = node.assignee;
|
|
2070
|
+
if (!(rhs instanceof ArrayValue)) {
|
|
2071
|
+
throw new Error(`Cannot unpack non-iterable type in set: ${rhs.type}`);
|
|
2072
|
+
}
|
|
2073
|
+
const arr = rhs.value;
|
|
2074
|
+
if (arr.length !== tuple.value.length) {
|
|
2075
|
+
throw new Error(`Too ${tuple.value.length > arr.length ? "few" : "many"} items to unpack in set`);
|
|
2076
|
+
}
|
|
2077
|
+
for (let i = 0; i < tuple.value.length; ++i) {
|
|
2078
|
+
const elem = tuple.value[i];
|
|
2079
|
+
if (elem.type !== "Identifier") {
|
|
2080
|
+
throw new Error(`Cannot unpack to non-identifier in set: ${elem.type}`);
|
|
2081
|
+
}
|
|
2082
|
+
environment.setVariable(elem.value, arr[i]);
|
|
2083
|
+
}
|
|
1763
2084
|
} else if (node.assignee.type === "MemberExpression") {
|
|
1764
2085
|
const member = node.assignee;
|
|
1765
2086
|
const object = this.evaluate(member.object, environment);
|
|
@@ -1784,13 +2105,16 @@ var Interpreter = class {
|
|
|
1784
2105
|
let test, iterable;
|
|
1785
2106
|
if (node.iterable.type === "SelectExpression") {
|
|
1786
2107
|
const select = node.iterable;
|
|
1787
|
-
iterable = this.evaluate(select.
|
|
2108
|
+
iterable = this.evaluate(select.lhs, scope);
|
|
1788
2109
|
test = select.test;
|
|
1789
2110
|
} else {
|
|
1790
2111
|
iterable = this.evaluate(node.iterable, scope);
|
|
1791
2112
|
}
|
|
1792
|
-
if (!(iterable instanceof ArrayValue)) {
|
|
1793
|
-
throw new Error(`Expected iterable type in for loop: got ${iterable.type}`);
|
|
2113
|
+
if (!(iterable instanceof ArrayValue || iterable instanceof ObjectValue)) {
|
|
2114
|
+
throw new Error(`Expected iterable or object type in for loop: got ${iterable.type}`);
|
|
2115
|
+
}
|
|
2116
|
+
if (iterable instanceof ObjectValue) {
|
|
2117
|
+
iterable = iterable.keys();
|
|
1794
2118
|
}
|
|
1795
2119
|
const items = [];
|
|
1796
2120
|
const scopeUpdateFunctions = [];
|
|
@@ -1834,13 +2158,13 @@ var Interpreter = class {
|
|
|
1834
2158
|
let noIteration = true;
|
|
1835
2159
|
for (let i = 0; i < items.length; ++i) {
|
|
1836
2160
|
const loop = /* @__PURE__ */ new Map([
|
|
1837
|
-
["index", new
|
|
1838
|
-
["index0", new
|
|
1839
|
-
["revindex", new
|
|
1840
|
-
["revindex0", new
|
|
2161
|
+
["index", new IntegerValue(i + 1)],
|
|
2162
|
+
["index0", new IntegerValue(i)],
|
|
2163
|
+
["revindex", new IntegerValue(items.length - i)],
|
|
2164
|
+
["revindex0", new IntegerValue(items.length - i - 1)],
|
|
1841
2165
|
["first", new BooleanValue(i === 0)],
|
|
1842
2166
|
["last", new BooleanValue(i === items.length - 1)],
|
|
1843
|
-
["length", new
|
|
2167
|
+
["length", new IntegerValue(items.length)],
|
|
1844
2168
|
["previtem", i > 0 ? items[i - 1] : new UndefinedValue()],
|
|
1845
2169
|
["nextitem", i < items.length - 1 ? items[i + 1] : new UndefinedValue()]
|
|
1846
2170
|
]);
|
|
@@ -1903,8 +2227,36 @@ var Interpreter = class {
|
|
|
1903
2227
|
);
|
|
1904
2228
|
return new NullValue();
|
|
1905
2229
|
}
|
|
2230
|
+
evaluateCallStatement(node, environment) {
|
|
2231
|
+
const callerFn = new FunctionValue((callerArgs, callerEnv) => {
|
|
2232
|
+
const callBlockEnv = new Environment(callerEnv);
|
|
2233
|
+
if (node.callerArgs) {
|
|
2234
|
+
for (let i = 0; i < node.callerArgs.length; ++i) {
|
|
2235
|
+
const param = node.callerArgs[i];
|
|
2236
|
+
if (param.type !== "Identifier") {
|
|
2237
|
+
throw new Error(`Caller parameter must be an identifier, got ${param.type}`);
|
|
2238
|
+
}
|
|
2239
|
+
callBlockEnv.setVariable(param.value, callerArgs[i] ?? new UndefinedValue());
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
return this.evaluateBlock(node.body, callBlockEnv);
|
|
2243
|
+
});
|
|
2244
|
+
const [macroArgs, macroKwargs] = this.evaluateArguments(node.call.args, environment);
|
|
2245
|
+
macroArgs.push(new KeywordArgumentsValue(macroKwargs));
|
|
2246
|
+
const fn = this.evaluate(node.call.callee, environment);
|
|
2247
|
+
if (fn.type !== "FunctionValue") {
|
|
2248
|
+
throw new Error(`Cannot call something that is not a function: got ${fn.type}`);
|
|
2249
|
+
}
|
|
2250
|
+
const newEnv = new Environment(environment);
|
|
2251
|
+
newEnv.setVariable("caller", callerFn);
|
|
2252
|
+
return fn.value(macroArgs, newEnv);
|
|
2253
|
+
}
|
|
2254
|
+
evaluateFilterStatement(node, environment) {
|
|
2255
|
+
const rendered = this.evaluateBlock(node.body, environment);
|
|
2256
|
+
return this.applyFilter(rendered, node.filter, environment);
|
|
2257
|
+
}
|
|
1906
2258
|
evaluate(statement, environment) {
|
|
1907
|
-
if (statement
|
|
2259
|
+
if (!statement)
|
|
1908
2260
|
return new UndefinedValue();
|
|
1909
2261
|
switch (statement.type) {
|
|
1910
2262
|
case "Program":
|
|
@@ -1917,18 +2269,18 @@ var Interpreter = class {
|
|
|
1917
2269
|
return this.evaluateFor(statement, environment);
|
|
1918
2270
|
case "Macro":
|
|
1919
2271
|
return this.evaluateMacro(statement, environment);
|
|
2272
|
+
case "CallStatement":
|
|
2273
|
+
return this.evaluateCallStatement(statement, environment);
|
|
1920
2274
|
case "Break":
|
|
1921
2275
|
throw new BreakControl();
|
|
1922
2276
|
case "Continue":
|
|
1923
2277
|
throw new ContinueControl();
|
|
1924
|
-
case "
|
|
1925
|
-
return new
|
|
2278
|
+
case "IntegerLiteral":
|
|
2279
|
+
return new IntegerValue(statement.value);
|
|
2280
|
+
case "FloatLiteral":
|
|
2281
|
+
return new FloatValue(statement.value);
|
|
1926
2282
|
case "StringLiteral":
|
|
1927
2283
|
return new StringValue(statement.value);
|
|
1928
|
-
case "BooleanLiteral":
|
|
1929
|
-
return new BooleanValue(statement.value);
|
|
1930
|
-
case "NullLiteral":
|
|
1931
|
-
return new NullValue(statement.value);
|
|
1932
2284
|
case "ArrayLiteral":
|
|
1933
2285
|
return new ArrayValue(statement.value.map((x) => this.evaluate(x, environment)));
|
|
1934
2286
|
case "TupleLiteral":
|
|
@@ -1956,8 +2308,16 @@ var Interpreter = class {
|
|
|
1956
2308
|
return this.evaluateBinaryExpression(statement, environment);
|
|
1957
2309
|
case "FilterExpression":
|
|
1958
2310
|
return this.evaluateFilterExpression(statement, environment);
|
|
2311
|
+
case "FilterStatement":
|
|
2312
|
+
return this.evaluateFilterStatement(statement, environment);
|
|
1959
2313
|
case "TestExpression":
|
|
1960
2314
|
return this.evaluateTestExpression(statement, environment);
|
|
2315
|
+
case "SelectExpression":
|
|
2316
|
+
return this.evaluateSelectExpression(statement, environment);
|
|
2317
|
+
case "Ternary":
|
|
2318
|
+
return this.evaluateTernaryExpression(statement, environment);
|
|
2319
|
+
case "Comment":
|
|
2320
|
+
return new NullValue();
|
|
1961
2321
|
default:
|
|
1962
2322
|
throw new SyntaxError(`Unknown node type: ${statement.type}`);
|
|
1963
2323
|
}
|
|
@@ -1966,7 +2326,7 @@ var Interpreter = class {
|
|
|
1966
2326
|
function convertToRuntimeValues(input) {
|
|
1967
2327
|
switch (typeof input) {
|
|
1968
2328
|
case "number":
|
|
1969
|
-
return new
|
|
2329
|
+
return Number.isInteger(input) ? new IntegerValue(input) : new FloatValue(input);
|
|
1970
2330
|
case "string":
|
|
1971
2331
|
return new StringValue(input);
|
|
1972
2332
|
case "boolean":
|
|
@@ -1998,7 +2358,8 @@ function toJSON(input, indent, depth) {
|
|
|
1998
2358
|
case "NullValue":
|
|
1999
2359
|
case "UndefinedValue":
|
|
2000
2360
|
return "null";
|
|
2001
|
-
case "
|
|
2361
|
+
case "IntegerValue":
|
|
2362
|
+
case "FloatValue":
|
|
2002
2363
|
case "StringValue":
|
|
2003
2364
|
case "BooleanValue":
|
|
2004
2365
|
return JSON.stringify(input.value);
|
|
@@ -2027,11 +2388,23 @@ function toJSON(input, indent, depth) {
|
|
|
2027
2388
|
var NEWLINE = "\n";
|
|
2028
2389
|
var OPEN_STATEMENT = "{%- ";
|
|
2029
2390
|
var CLOSE_STATEMENT = " -%}";
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2391
|
+
function getBinaryOperatorPrecedence(expr) {
|
|
2392
|
+
switch (expr.operator.type) {
|
|
2393
|
+
case "MultiplicativeBinaryOperator":
|
|
2394
|
+
return 4;
|
|
2395
|
+
case "AdditiveBinaryOperator":
|
|
2396
|
+
return 3;
|
|
2397
|
+
case "ComparisonBinaryOperator":
|
|
2398
|
+
return 2;
|
|
2399
|
+
case "Identifier":
|
|
2400
|
+
if (expr.operator.value === "and")
|
|
2401
|
+
return 1;
|
|
2402
|
+
if (expr.operator.value === "in" || expr.operator.value === "not in")
|
|
2403
|
+
return 2;
|
|
2404
|
+
return 0;
|
|
2405
|
+
}
|
|
2406
|
+
return 0;
|
|
2407
|
+
}
|
|
2035
2408
|
function format(program, indent = " ") {
|
|
2036
2409
|
const indentStr = typeof indent === "number" ? " ".repeat(indent) : indent;
|
|
2037
2410
|
const body = formatStatements(program.body, 0, indentStr);
|
|
@@ -2060,6 +2433,12 @@ function formatStatement(node, depth, indentStr) {
|
|
|
2060
2433
|
return pad + createStatement("break");
|
|
2061
2434
|
case "Continue":
|
|
2062
2435
|
return pad + createStatement("continue");
|
|
2436
|
+
case "CallStatement":
|
|
2437
|
+
return formatCallStatement(node, depth, indentStr);
|
|
2438
|
+
case "FilterStatement":
|
|
2439
|
+
return formatFilterStatement(node, depth, indentStr);
|
|
2440
|
+
case "Comment":
|
|
2441
|
+
return pad + "{# " + node.value + " #}";
|
|
2063
2442
|
default:
|
|
2064
2443
|
return pad + "{{- " + formatExpression(node) + " -}}";
|
|
2065
2444
|
}
|
|
@@ -2077,7 +2456,7 @@ function formatIf(node, depth, indentStr) {
|
|
|
2077
2456
|
}
|
|
2078
2457
|
}
|
|
2079
2458
|
let out = pad + createStatement("if", formatExpression(clauses[0].test)) + NEWLINE + formatStatements(clauses[0].body, depth + 1, indentStr);
|
|
2080
|
-
for (let i = 1; i < clauses.length; i
|
|
2459
|
+
for (let i = 1; i < clauses.length; ++i) {
|
|
2081
2460
|
out += NEWLINE + pad + createStatement("elif", formatExpression(clauses[i].test)) + NEWLINE + formatStatements(clauses[i].body, depth + 1, indentStr);
|
|
2082
2461
|
}
|
|
2083
2462
|
if (current && current.alternate.length > 0) {
|
|
@@ -2091,7 +2470,7 @@ function formatFor(node, depth, indentStr) {
|
|
|
2091
2470
|
let formattedIterable = "";
|
|
2092
2471
|
if (node.iterable.type === "SelectExpression") {
|
|
2093
2472
|
const n = node.iterable;
|
|
2094
|
-
formattedIterable = `${formatExpression(n.
|
|
2473
|
+
formattedIterable = `${formatExpression(n.lhs)} if ${formatExpression(n.test)}`;
|
|
2095
2474
|
} else {
|
|
2096
2475
|
formattedIterable = formatExpression(node.iterable);
|
|
2097
2476
|
}
|
|
@@ -2117,20 +2496,40 @@ function formatMacro(node, depth, indentStr) {
|
|
|
2117
2496
|
const args = node.args.map(formatExpression).join(", ");
|
|
2118
2497
|
return pad + createStatement("macro", `${node.name.value}(${args})`) + NEWLINE + formatStatements(node.body, depth + 1, indentStr) + NEWLINE + pad + createStatement("endmacro");
|
|
2119
2498
|
}
|
|
2499
|
+
function formatCallStatement(node, depth, indentStr) {
|
|
2500
|
+
const pad = indentStr.repeat(depth);
|
|
2501
|
+
const params = node.callerArgs && node.callerArgs.length > 0 ? `(${node.callerArgs.map(formatExpression).join(", ")})` : "";
|
|
2502
|
+
const callExpr = formatExpression(node.call);
|
|
2503
|
+
let out = pad + createStatement(`call${params}`, callExpr) + NEWLINE;
|
|
2504
|
+
out += formatStatements(node.body, depth + 1, indentStr) + NEWLINE;
|
|
2505
|
+
out += pad + createStatement("endcall");
|
|
2506
|
+
return out;
|
|
2507
|
+
}
|
|
2508
|
+
function formatFilterStatement(node, depth, indentStr) {
|
|
2509
|
+
const pad = indentStr.repeat(depth);
|
|
2510
|
+
const spec = node.filter.type === "Identifier" ? node.filter.value : formatExpression(node.filter);
|
|
2511
|
+
let out = pad + createStatement("filter", spec) + NEWLINE;
|
|
2512
|
+
out += formatStatements(node.body, depth + 1, indentStr) + NEWLINE;
|
|
2513
|
+
out += pad + createStatement("endfilter");
|
|
2514
|
+
return out;
|
|
2515
|
+
}
|
|
2120
2516
|
function formatExpression(node, parentPrec = -1) {
|
|
2121
2517
|
switch (node.type) {
|
|
2518
|
+
case "SpreadExpression": {
|
|
2519
|
+
const n = node;
|
|
2520
|
+
return `*${formatExpression(n.argument)}`;
|
|
2521
|
+
}
|
|
2122
2522
|
case "Identifier":
|
|
2123
2523
|
return node.value;
|
|
2124
|
-
case "
|
|
2125
|
-
return
|
|
2126
|
-
case "
|
|
2127
|
-
case "BooleanLiteral":
|
|
2524
|
+
case "IntegerLiteral":
|
|
2525
|
+
return `${node.value}`;
|
|
2526
|
+
case "FloatLiteral":
|
|
2128
2527
|
return `${node.value}`;
|
|
2129
2528
|
case "StringLiteral":
|
|
2130
2529
|
return JSON.stringify(node.value);
|
|
2131
2530
|
case "BinaryExpression": {
|
|
2132
2531
|
const n = node;
|
|
2133
|
-
const thisPrecedence =
|
|
2532
|
+
const thisPrecedence = getBinaryOperatorPrecedence(n);
|
|
2134
2533
|
const left = formatExpression(n.left, thisPrecedence);
|
|
2135
2534
|
const right = formatExpression(n.right, thisPrecedence + 1);
|
|
2136
2535
|
const expr = `${left} ${n.operator.value} ${right}`;
|
|
@@ -2141,20 +2540,28 @@ function formatExpression(node, parentPrec = -1) {
|
|
|
2141
2540
|
const val = n.operator.value + (n.operator.value === "not" ? " " : "") + formatExpression(n.argument, Infinity);
|
|
2142
2541
|
return val;
|
|
2143
2542
|
}
|
|
2144
|
-
case "LogicalNegationExpression":
|
|
2145
|
-
return `not ${formatExpression(node.argument, Infinity)}`;
|
|
2146
2543
|
case "CallExpression": {
|
|
2147
2544
|
const n = node;
|
|
2148
|
-
const args = n.args.map(
|
|
2149
|
-
return `${formatExpression(n.callee
|
|
2545
|
+
const args = n.args.map(formatExpression).join(", ");
|
|
2546
|
+
return `${formatExpression(n.callee)}(${args})`;
|
|
2150
2547
|
}
|
|
2151
2548
|
case "MemberExpression": {
|
|
2152
2549
|
const n = node;
|
|
2153
|
-
let obj = formatExpression(n.object
|
|
2154
|
-
if (
|
|
2550
|
+
let obj = formatExpression(n.object);
|
|
2551
|
+
if (![
|
|
2552
|
+
"Identifier",
|
|
2553
|
+
"MemberExpression",
|
|
2554
|
+
"CallExpression",
|
|
2555
|
+
"StringLiteral",
|
|
2556
|
+
"IntegerLiteral",
|
|
2557
|
+
"FloatLiteral",
|
|
2558
|
+
"ArrayLiteral",
|
|
2559
|
+
"TupleLiteral",
|
|
2560
|
+
"ObjectLiteral"
|
|
2561
|
+
].includes(n.object.type)) {
|
|
2155
2562
|
obj = `(${obj})`;
|
|
2156
2563
|
}
|
|
2157
|
-
let prop = formatExpression(n.property
|
|
2564
|
+
let prop = formatExpression(n.property);
|
|
2158
2565
|
if (!n.computed && n.property.type !== "Identifier") {
|
|
2159
2566
|
prop = `(${prop})`;
|
|
2160
2567
|
}
|
|
@@ -2164,47 +2571,47 @@ function formatExpression(node, parentPrec = -1) {
|
|
|
2164
2571
|
const n = node;
|
|
2165
2572
|
const operand = formatExpression(n.operand, Infinity);
|
|
2166
2573
|
if (n.filter.type === "CallExpression") {
|
|
2167
|
-
return `${operand} | ${formatExpression(n.filter
|
|
2574
|
+
return `${operand} | ${formatExpression(n.filter)}`;
|
|
2168
2575
|
}
|
|
2169
2576
|
return `${operand} | ${n.filter.value}`;
|
|
2170
2577
|
}
|
|
2171
2578
|
case "SelectExpression": {
|
|
2172
2579
|
const n = node;
|
|
2173
|
-
return `${formatExpression(n.
|
|
2580
|
+
return `${formatExpression(n.lhs)} if ${formatExpression(n.test)}`;
|
|
2174
2581
|
}
|
|
2175
2582
|
case "TestExpression": {
|
|
2176
2583
|
const n = node;
|
|
2177
|
-
return `${formatExpression(n.operand
|
|
2584
|
+
return `${formatExpression(n.operand)} is${n.negate ? " not" : ""} ${n.test.value}`;
|
|
2178
2585
|
}
|
|
2179
2586
|
case "ArrayLiteral":
|
|
2180
2587
|
case "TupleLiteral": {
|
|
2181
|
-
const elems = node.value.map(
|
|
2588
|
+
const elems = node.value.map(formatExpression);
|
|
2182
2589
|
const brackets = node.type === "ArrayLiteral" ? "[]" : "()";
|
|
2183
2590
|
return `${brackets[0]}${elems.join(", ")}${brackets[1]}`;
|
|
2184
2591
|
}
|
|
2185
2592
|
case "ObjectLiteral": {
|
|
2186
2593
|
const entries = Array.from(node.value.entries()).map(
|
|
2187
|
-
([k, v]) => `${formatExpression(k
|
|
2594
|
+
([k, v]) => `${formatExpression(k)}: ${formatExpression(v)}`
|
|
2188
2595
|
);
|
|
2189
|
-
return `{
|
|
2596
|
+
return `{${entries.join(", ")}}`;
|
|
2190
2597
|
}
|
|
2191
2598
|
case "SliceExpression": {
|
|
2192
2599
|
const n = node;
|
|
2193
|
-
const s = n.start ? formatExpression(n.start
|
|
2194
|
-
const t = n.stop ? formatExpression(n.stop
|
|
2195
|
-
const st = n.step ? `:${formatExpression(n.step
|
|
2600
|
+
const s = n.start ? formatExpression(n.start) : "";
|
|
2601
|
+
const t = n.stop ? formatExpression(n.stop) : "";
|
|
2602
|
+
const st = n.step ? `:${formatExpression(n.step)}` : "";
|
|
2196
2603
|
return `${s}:${t}${st}`;
|
|
2197
2604
|
}
|
|
2198
2605
|
case "KeywordArgumentExpression": {
|
|
2199
2606
|
const n = node;
|
|
2200
|
-
return `${n.key.value}=${formatExpression(n.value
|
|
2607
|
+
return `${n.key.value}=${formatExpression(n.value)}`;
|
|
2201
2608
|
}
|
|
2202
|
-
case "
|
|
2609
|
+
case "Ternary": {
|
|
2203
2610
|
const n = node;
|
|
2204
|
-
const
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
return
|
|
2611
|
+
const expr = `${formatExpression(n.trueExpr)} if ${formatExpression(n.condition, 0)} else ${formatExpression(
|
|
2612
|
+
n.falseExpr
|
|
2613
|
+
)}`;
|
|
2614
|
+
return parentPrec > -1 ? `(${expr})` : expr;
|
|
2208
2615
|
}
|
|
2209
2616
|
default:
|
|
2210
2617
|
throw new Error(`Unknown expression type: ${node.type}`);
|
|
@@ -2226,12 +2633,7 @@ var Template = class {
|
|
|
2226
2633
|
}
|
|
2227
2634
|
render(items) {
|
|
2228
2635
|
const env = new Environment();
|
|
2229
|
-
env
|
|
2230
|
-
env.set("true", true);
|
|
2231
|
-
env.set("raise_exception", (args) => {
|
|
2232
|
-
throw new Error(args);
|
|
2233
|
-
});
|
|
2234
|
-
env.set("range", range);
|
|
2636
|
+
setupGlobals(env);
|
|
2235
2637
|
if (items) {
|
|
2236
2638
|
for (const [key, value] of Object.entries(items)) {
|
|
2237
2639
|
env.set(key, value);
|
|
@@ -4358,7 +4760,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
4358
4760
|
|
|
4359
4761
|
|
|
4360
4762
|
|
|
4361
|
-
const VERSION = '3.6.
|
|
4763
|
+
const VERSION = '3.6.3';
|
|
4362
4764
|
|
|
4363
4765
|
// Check if various APIs are available (depends on environment)
|
|
4364
4766
|
const IS_BROWSER_ENV = typeof window !== "undefined" && typeof window.document !== "undefined";
|