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