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