import * as __WEBPACK_EXTERNAL_MODULE_chrome_global_content_ml_ort_webgpu_dev_mjs_a
2210ba4__ from "chrome://global/content/ml/ort.webgpu-dev.mjs";
/******/ var __webpack_modules__ = ({
/***/ "#onnxruntime-webgpu":
/*!****************************************************************!*\
!*** external "chrome://global/content/ml/ort.webgpu-dev.mjs" ***!
\****************************************************************/
/***/ ((module) => {
module.exports = __WEBPACK_EXTERNAL_MODULE_chrome_global_content_ml_ort_webgpu_dev_mjs_a2210ba4__;
/***/ }),
/***/ "?7a2c":
/*!********************!*\
!*** fs (ignored) ***!
\********************/
/***/ (() => {
/* (ignored) */
/***/ }),
/***/ "?a42a":
/*!**********************!*\
!*** path (ignored) ***!
\**********************/
/***/ (() => {
/* (ignored) */
/***/ }),
/***/ "?2b25":
/*!***********************!*\
!*** sharp (ignored) ***!
\***********************/
/***/ (() => {
/* (ignored) */
/***/ }),
/***/ "?569f":
/*!********************!*\
!*** fs (ignored) ***!
\********************/
/***/ (() => {
/* (ignored) */
/***/ }),
/***/ "?3f59":
/*!**********************!*\
!*** path (ignored) ***!
\**********************/
/***/ (() => {
/* (ignored) */
/***/ }),
/***/ "?154a":
/*!*********************!*\
!*** url (ignored) ***!
\*********************/
/***/ (() => {
/* (ignored) */
/***/ }),
/***/ "./node_modules/@huggingface/jinja/dist/index.js":
/*!*******************************************************!*\
!*** ./node_modules/@huggingface/jinja/dist/index.js ***!
\*******************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Environment: () => (/* binding */ Environment),
/* harmony export */ Interpreter: () => (/* binding */ Interpreter),
/* harmony export */ Template: () => (/* binding */ Template),
/* harmony export */ parse: () => (/* binding */ parse),
/* harmony export */ tokenize: () => (/* binding */ tokenize)
/* harmony export */ });
// src/lexer.ts
var TOKEN_TYPES = Object.freeze({
Text: "Text" ,
// The text between Jinja statements or expressions
NumericLiteral: "NumericLiteral" ,
// e.g., 123
BooleanLiteral: "BooleanLiteral" ,
// true or false
NullLiteral: "NullLiteral" ,
// none
StringLiteral: "StringLiteral" ,
// 'string'
Identifier: "Identifier" ,
// Variables, functions, etc.
Equals: "Equals" ,
// =
OpenParen: "OpenParen" ,
// (
CloseParen: "CloseParen" ,
// )
OpenStatement: "OpenStatement" ,
// {%
CloseStatement: "CloseStatement" ,
// %}
OpenExpression: "OpenExpression" ,
// {{
CloseExpression: "CloseExpression" ,
// }}
OpenSquareBracket: "OpenSquareBracket" ,
// [
CloseSquareBracket: "CloseSquareBracket" ,
// ]
OpenCurlyBracket: "OpenCurlyBracket" ,
// {
CloseCurlyBracket: "CloseCurlyBracket" ,
// }
Comma: "Comma" ,
// ,
Dot: "Dot" ,
// .
Colon: "Colon" ,
// :
Pipe: "Pipe" ,
// |
CallOperator: "CallOperator" ,
// ()
AdditiveBinaryOperator: "AdditiveBinaryOperator" ,
// + -
MultiplicativeBinaryOperator: "MultiplicativeBinaryOperator" ,
// * / %
ComparisonBinaryOperator: "ComparisonBinaryOperator" ,
// < > <= >= == !=
UnaryOperator: "UnaryOperator" ,
// ! - +
// Keywords
Set: "Set" ,
If : "If" ,
For : "For" ,
In: "In" ,
Is: "Is" ,
NotIn: "NotIn" ,
Else : "Else" ,
EndIf: "EndIf" ,
ElseIf: "ElseIf" ,
EndFor: "EndFor" ,
And: "And" ,
Or: "Or" ,
Not: "UnaryOperator" ,
Macro: "Macro" ,
EndMacro: "EndMacro"
});
var KEYWORDS = Object.freeze({
set: TOKEN_TYPES.Set,
for : TOKEN_TYPES.For ,
in: TOKEN_TYPES.In,
is: TOKEN_TYPES.Is,
if : TOKEN_TYPES.If ,
else : TOKEN_TYPES.Else ,
endif: TOKEN_TYPES.EndIf,
elif: TOKEN_TYPES.ElseIf,
endfor: TOKEN_TYPES.EndFor,
and: TOKEN_TYPES.And,
or: TOKEN_TYPES.Or,
not: TOKEN_TYPES.Not,
"not in" : TOKEN_TYPES.NotIn,
macro: TOKEN_TYPES.Macro,
endmacro: TOKEN_TYPES.EndMacro,
// Literals
true : TOKEN_TYPES.BooleanLiteral,
false : TOKEN_TYPES.BooleanLiteral,
none: TOKEN_TYPES.NullLiteral,
// NOTE: According to the Jinja docs: The special constants true, false, and none are indeed lowercase.
// Because that caused confusion in the past, (True used to expand to an undefined variable that was considered false),
// all three can now also be written in title case (True, False, and None). However, for consistency, (all Jinja identifiers are lowercase)
// you should use the lowercase versions.
True : TOKEN_TYPES.BooleanLiteral,
False : TOKEN_TYPES.BooleanLiteral,
None: TOKEN_TYPES.NullLiteral
});
var Token = class {
/**
* Constructs a new Token.
* @param {string} value The raw value as seen inside the source code.
* @param {TokenType} type The type of token.
*/
constructor(value, type) {
this .value = value;
this .type = type;
}
};
function isWord(char ) {
return /\w/.test(char );
}
function isInteger(char ) {
return /[0-9]/.test(char );
}
var ORDERED_MAPPING_TABLE = [
// Control sequences
["{%" , TOKEN_TYPES.OpenStatement],
["%}" , TOKEN_TYPES.CloseStatement],
["{{" , TOKEN_TYPES.OpenExpression],
["}}" , TOKEN_TYPES.CloseExpression],
// Single character tokens
["(" , TOKEN_TYPES.OpenParen],
[")" , TOKEN_TYPES.CloseParen],
["{" , TOKEN_TYPES.OpenCurlyBracket],
["}" , TOKEN_TYPES.CloseCurlyBracket],
["[" , TOKEN_TYPES.OpenSquareBracket],
["]" , TOKEN_TYPES.CloseSquareBracket],
["," , TOKEN_TYPES.Comma],
["." , TOKEN_TYPES.Dot],
[":" , TOKEN_TYPES.Colon],
["|" , TOKEN_TYPES.Pipe],
// Comparison operators
["<=" , TOKEN_TYPES.ComparisonBinaryOperator],
[">=" , TOKEN_TYPES.ComparisonBinaryOperator],
["==" , TOKEN_TYPES.ComparisonBinaryOperator],
["!=" , TOKEN_TYPES.ComparisonBinaryOperator],
["<" , TOKEN_TYPES.ComparisonBinaryOperator],
[">" , TOKEN_TYPES.ComparisonBinaryOperator],
// Arithmetic operators
["+" , TOKEN_TYPES.AdditiveBinaryOperator],
["-" , TOKEN_TYPES.AdditiveBinaryOperator],
["*" , TOKEN_TYPES.MultiplicativeBinaryOperator],
["/" , TOKEN_TYPES.MultiplicativeBinaryOperator],
["%" , TOKEN_TYPES.MultiplicativeBinaryOperator],
// Assignment operator
["=" , TOKEN_TYPES.Equals]
];
var ESCAPE_CHARACTERS = /* @__PURE__ */ new Map([
["n" , "\n" ],
// New line
["t" , " " ],
// Horizontal tab
["r" , "\r" ],
// Carriage return
["b" , "\b" ],
// Backspace
["f" , "\f" ],
// Form feed
["v" , "\v" ],
// Vertical tab
["'" , "'" ],
// Single quote
['"' , '"' ],
// Double quote
["\\" , "\\" ]
// Backslash
]);
function preprocess(template, options = {}) {
if (template.endsWith("\n" )) {
template = template.slice(0, -1);
}
template = template.replace(/{#.*?#}/gs, "{##}" );
if (options.lstrip_blocks) {
template = template.replace(/^[ \t]*({[#%])/gm, "$1" );
}
if (options.trim_blocks) {
template = template.replace(/([#%]})\n/g, "$1" );
}
return template.replace(/{##}/g, "" ).replace(/-%}\s*/g, "%}" ).replace(/\s*{%-/g, "{%" ).replace(/-}}\s*/g, "}}" ).replace(/\s*{{-/g, "{{" );
}
function tokenize(source, options = {}) {
const tokens = [];
const src = preprocess(source, options);
let cursorPosition = 0;
const consumeWhile = (predicate) => {
let str = "" ;
while (predicate(src[cursorPosition])) {
if (src[cursorPosition] === "\\" ) {
++cursorPosition;
if (cursorPosition >= src.length)
throw new SyntaxError("Unexpected end of input" );
const escaped = src[cursorPosition++];
const unescaped = ESCAPE_CHARACTERS.get(escaped);
if (unescaped === void 0) {
throw new SyntaxError(`Unexpected escaped character: ${escaped}`);
}
str += unescaped;
continue ;
}
str += src[cursorPosition++];
if (cursorPosition >= src.length)
throw new SyntaxError("Unexpected end of input" );
}
return str;
};
main:
while (cursorPosition < src.length) {
const lastTokenType = tokens.at(-1)?.type;
if (lastTokenType === void 0 || lastTokenType === TOKEN_TYPES.CloseStatement || lastTokenType === TOKEN_TYPES.CloseExpression) {
let text = "" ;
while (cursorPosition < src.length && // Keep going until we hit the next Jinja statement or expression
!(src[cursorPosition] === "{" && (src[cursorPosition + 1] === "%" || src[cursorPosition + 1] === "{" ))) {
text += src[cursorPosition++];
}
if (text.length > 0) {
tokens.push(new Token(text, TOKEN_TYPES.Text));
continue ;
}
}
consumeWhile((char2) => /\s/.test(char2));
const char = src[cursorPosition];
if (char === "-" || char === "+" ) {
const lastTokenType2 = tokens.at(-1)?.type;
if (lastTokenType2 === TOKEN_TYPES.Text || lastTokenType2 === void 0) {
throw new SyntaxError(`Unexpected character: ${char }`);
}
switch (lastTokenType2) {
case TOKEN_TYPES.Identifier:
case TOKEN_TYPES.NumericLiteral:
case TOKEN_TYPES.BooleanLiteral:
case TOKEN_TYPES.NullLiteral:
case TOKEN_TYPES.StringLiteral:
case TOKEN_TYPES.CloseParen:
case TOKEN_TYPES.CloseSquareBracket:
break ;
default : {
++cursorPosition;
const num = consumeWhile(isInteger);
tokens.push(
new Token(`${char }${num}`, num.length > 0 ? TOKEN_TYPES.NumericLiteral : TOKEN_TYPES.UnaryOperator)
);
continue ;
}
}
}
for (const [char2, token] of ORDERED_MAPPING_TABLE) {
const slice2 = src.slice(cursorPosition, cursorPosition + char2.length);
if (slice2 === char2) {
tokens.push(new Token(char2, token));
cursorPosition += char2.length;
continue main;
}
}
if (char === "'" || char === '"' ) {
++cursorPosition;
const str = consumeWhile((c) => c !== char );
tokens.push(new Token(str, TOKEN_TYPES.StringLiteral));
++cursorPosition;
continue ;
}
if (isInteger(char )) {
const num = consumeWhile(isInteger);
tokens.push(new Token(num, TOKEN_TYPES.NumericLiteral));
continue ;
}
if (isWord(char )) {
const word = consumeWhile(isWord);
const type = Object.hasOwn(KEYWORDS, word) ? KEYWORDS[word] : TOKEN_TYPES.Identifier;
if (type === TOKEN_TYPES.In && tokens.at(-1)?.type === TOKEN_TYPES.Not) {
tokens.pop();
tokens.push(new Token("not in" , TOKEN_TYPES.NotIn));
} else {
tokens.push(new Token(word, type));
}
continue ;
}
throw new SyntaxError(`Unexpected character: ${char }`);
}
return tokens;
}
// src/ast.ts
var Statement = class {
type = "Statement" ;
};
var Program = class extends Statement {
constructor(body) {
super ();
this .body = body;
}
type = "Program" ;
};
var If = class extends Statement {
constructor(test, body, alternate) {
super ();
this .test = test;
this .body = body;
this .alternate = alternate;
}
type = "If" ;
};
var For = class extends Statement {
constructor(loopvar, iterable, body, defaultBlock) {
super ();
this .loopvar = loopvar;
this .iterable = iterable;
this .body = body;
this .defaultBlock = defaultBlock;
}
type = "For" ;
};
var SetStatement = class extends Statement {
constructor(assignee, value) {
super ();
this .assignee = assignee;
this .value = value;
}
type = "Set" ;
};
var Macro = class extends Statement {
constructor(name, args, body) {
super ();
this .name = name;
this .args = args;
this .body = body;
}
type = "Macro" ;
};
var Expression = class extends Statement {
type = "Expression" ;
};
var MemberExpression = class extends Expression {
constructor(object, property, computed) {
super ();
this .object = object;
this .property = property;
this .computed = computed;
}
type = "MemberExpression" ;
};
var CallExpression = class extends Expression {
constructor(callee, args) {
super ();
this .callee = callee;
this .args = args;
}
type = "CallExpression" ;
};
var Identifier = class extends Expression {
/**
* @param {string} value The name of the identifier
*/
constructor(value) {
super ();
this .value = value;
}
type = "Identifier" ;
};
var Literal = class extends Expression {
constructor(value) {
super ();
this .value = value;
}
type = "Literal" ;
};
var NumericLiteral = class extends Literal {
type = "NumericLiteral" ;
};
var StringLiteral = class extends Literal {
type = "StringLiteral" ;
};
var BooleanLiteral = class extends Literal {
type = "BooleanLiteral" ;
};
var NullLiteral = class extends Literal {
type = "NullLiteral" ;
};
var ArrayLiteral = class extends Literal {
type = "ArrayLiteral" ;
};
var TupleLiteral = class extends Literal {
type = "TupleLiteral" ;
};
var ObjectLiteral = class extends Literal {
type = "ObjectLiteral" ;
};
var BinaryExpression = class extends Expression {
constructor(operator, left, right) {
super ();
this .operator = operator;
this .left = left;
this .right = right;
}
type = "BinaryExpression" ;
};
var FilterExpression = class extends Expression {
constructor(operand, filter) {
super ();
this .operand = operand;
this .filter = filter;
}
type = "FilterExpression" ;
};
var SelectExpression = class extends Expression {
constructor(iterable, test) {
super ();
this .iterable = iterable;
this .test = test;
}
type = "SelectExpression" ;
};
var TestExpression = class extends Expression {
constructor(operand, negate, test) {
super ();
this .operand = operand;
this .negate = negate;
this .test = test;
}
type = "TestExpression" ;
};
var UnaryExpression = class extends Expression {
constructor(operator, argument) {
super ();
this .operator = operator;
this .argument = argument;
}
type = "UnaryExpression" ;
};
var SliceExpression = class extends Expression {
constructor(start = void 0, stop = void 0, step = void 0) {
super ();
this .start = start;
this .stop = stop;
this .step = step;
}
type = "SliceExpression" ;
};
var KeywordArgumentExpression = class extends Expression {
constructor(key, value) {
super ();
this .key = key;
this .value = value;
}
type = "KeywordArgumentExpression" ;
};
// src/parser.ts
function parse(tokens) {
const program = new Program([]);
let current = 0;
function expect(type, error) {
const prev = tokens[current++];
if (!prev || prev.type !== type) {
throw new Error(`Parser Error: ${error}. ${prev.type} !== ${type}.`);
}
return prev;
}
function parseAny() {
switch (tokens[current].type) {
case TOKEN_TYPES.Text:
return parseText();
case TOKEN_TYPES.OpenStatement:
return parseJinjaStatement();
case TOKEN_TYPES.OpenExpression:
return parseJinjaExpression();
default :
throw new SyntaxError(`Unexpected token type: ${tokens[current].type}`);
}
}
function not(...types) {
return current + types.length <= tokens.length && types.some((type, i) => type !== tokens[current + i].type);
}
function is(...types) {
return current + types.length <= tokens.length && types.every((type, i) => type === tokens[current + i].type);
}
function parseText() {
return new StringLiteral(expect(TOKEN_TYPES.Text, "Expected text token" ).value);
}
function parseJinjaStatement() {
expect(TOKEN_TYPES.OpenStatement, "Expected opening statement token" );
let result;
switch (tokens[current].type) {
case TOKEN_TYPES.Set:
++current;
result = parseSetStatement();
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token" );
break ;
case TOKEN_TYPES.If :
++current;
result = parseIfStatement();
expect(TOKEN_TYPES.OpenStatement, "Expected {% token" );
expect(TOKEN_TYPES.EndIf, "Expected endif token" );
expect(TOKEN_TYPES.CloseStatement, "Expected %} token" );
break ;
case TOKEN_TYPES.Macro:
++current;
result = parseMacroStatement();
expect(TOKEN_TYPES.OpenStatement, "Expected {% token" );
expect(TOKEN_TYPES.EndMacro, "Expected endmacro token" );
expect(TOKEN_TYPES.CloseStatement, "Expected %} token" );
break ;
case TOKEN_TYPES.For :
++current;
result = parseForStatement();
expect(TOKEN_TYPES.OpenStatement, "Expected {% token" );
expect(TOKEN_TYPES.EndFor, "Expected endfor token" );
expect(TOKEN_TYPES.CloseStatement, "Expected %} token" );
break ;
default :
throw new SyntaxError(`Unknown statement type: ${tokens[current].type}`);
}
return result;
}
function parseJinjaExpression() {
expect(TOKEN_TYPES.OpenExpression, "Expected opening expression token" );
const result = parseExpression();
expect(TOKEN_TYPES.CloseExpression, "Expected closing expression token" );
return result;
}
function parseSetStatement() {
const left = parseExpression();
if (is(TOKEN_TYPES.Equals)) {
++current;
const value = parseSetStatement();
return new SetStatement(left, value);
}
return left;
}
function parseIfStatement() {
const test = parseExpression();
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token" );
const body = [];
const alternate = [];
while (!(tokens[current]?.type === TOKEN_TYPES.OpenStatement && (tokens[current + 1]?.type === TOKEN_TYPES.ElseIf || tokens[current + 1]?.type === TOKEN_TYPES.Else || tokens[current + 1]?.type === TOKEN_TYPES.EndIf))) {
body.push(parseAny());
}
if (tokens[current]?.type === TOKEN_TYPES.OpenStatement && tokens[current + 1]?.type !== TOKEN_TYPES.EndIf) {
++current;
if (is(TOKEN_TYPES.ElseIf)) {
expect(TOKEN_TYPES.ElseIf, "Expected elseif token" );
alternate.push(parseIfStatement());
} else {
expect(TOKEN_TYPES.Else , "Expected else token" );
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token" );
while (!(tokens[current]?.type === TOKEN_TYPES.OpenStatement && tokens[current + 1]?.type === TOKEN_TYPES.EndIf)) {
alternate.push(parseAny());
}
}
}
return new If (test, body, alternate);
}
function parseMacroStatement() {
const name = parsePrimaryExpression();
if (name.type !== "Identifier" ) {
throw new SyntaxError(`Expected identifier following macro statement`);
}
const args = parseArgs();
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token" );
const body = [];
while (not(TOKEN_TYPES.OpenStatement, TOKEN_TYPES.EndMacro)) {
body.push(parseAny());
}
return new Macro(name, args, body);
}
function parseExpressionSequence(primary = false ) {
const fn = primary ? parsePrimaryExpression : parseExpression;
const expressions = [fn()];
const isTuple = is(TOKEN_TYPES.Comma);
while (isTuple) {
++current;
expressions.push(fn());
if (!is(TOKEN_TYPES.Comma)) {
break ;
}
}
return isTuple ? new TupleLiteral(expressions) : expressions[0];
}
function parseForStatement() {
const loopVariable = parseExpressionSequence(true );
if (!(loopVariable instanceof Identifier || loopVariable instanceof TupleLiteral)) {
throw new SyntaxError(`Expected identifier/tuple for the loop variable, got ${loopVariable.type} instead`);
}
expect(TOKEN_TYPES.In, "Expected `in` keyword following loop variable" );
const iterable = parseExpression();
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token" );
const body = [];
while (not(TOKEN_TYPES.OpenStatement, TOKEN_TYPES.EndFor) && not(TOKEN_TYPES.OpenStatement, TOKEN_TYPES.Else )) {
body.push(parseAny());
}
const alternative = [];
if (is(TOKEN_TYPES.OpenStatement, TOKEN_TYPES.Else )) {
++current;
++current;
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token" );
while (not(TOKEN_TYPES.OpenStatement, TOKEN_TYPES.EndFor)) {
alternative.push(parseAny());
}
}
return new For (loopVariable, iterable, body, alternative);
}
function parseExpression() {
return parseIfExpression();
}
function parseIfExpression() {
const a = parseLogicalOrExpression();
if (is(TOKEN_TYPES.If )) {
++current;
const predicate = parseLogicalOrExpression();
if (is(TOKEN_TYPES.Else )) {
++current;
const b = parseLogicalOrExpression();
return new If (predicate, [a], [b]);
} else {
return new SelectExpression(a, predicate);
}
}
return a;
}
function parseLogicalOrExpression() {
let left = parseLogicalAndExpression();
while (is(TOKEN_TYPES.Or)) {
const operator = tokens[current];
++current;
const right = parseLogicalAndExpression();
left = new BinaryExpression(operator, left, right);
}
return left;
}
function parseLogicalAndExpression() {
let left = parseLogicalNegationExpression();
while (is(TOKEN_TYPES.And)) {
const operator = tokens[current];
++current;
const right = parseLogicalNegationExpression();
left = new BinaryExpression(operator, left, right);
}
return left;
}
function parseLogicalNegationExpression() {
let right;
while (is(TOKEN_TYPES.Not)) {
const operator = tokens[current];
++current;
const arg = parseLogicalNegationExpression();
right = new UnaryExpression(operator, arg);
}
return right ?? parseComparisonExpression();
}
function parseComparisonExpression() {
let left = parseAdditiveExpression();
while (is(TOKEN_TYPES.ComparisonBinaryOperator) || is(TOKEN_TYPES.In) || is(TOKEN_TYPES.NotIn)) {
const operator = tokens[current];
++current;
const right = parseAdditiveExpression();
left = new BinaryExpression(operator, left, right);
}
return left;
}
function parseAdditiveExpression() {
let left = parseMultiplicativeExpression();
while (is(TOKEN_TYPES.AdditiveBinaryOperator)) {
const operator = tokens[current];
++current;
const right = parseMultiplicativeExpression();
left = new BinaryExpression(operator, left, right);
}
return left;
}
function parseCallMemberExpression() {
const member = parseMemberExpression();
if (is(TOKEN_TYPES.OpenParen)) {
return parseCallExpression(member);
}
return member;
}
function parseCallExpression(callee) {
let callExpression = new CallExpression(callee, parseArgs());
if (is(TOKEN_TYPES.OpenParen)) {
callExpression = parseCallExpression(callExpression);
}
return callExpression;
}
function parseArgs() {
expect(TOKEN_TYPES.OpenParen, "Expected opening parenthesis for arguments list" );
const args = parseArgumentsList();
expect(TOKEN_TYPES.CloseParen, "Expected closing parenthesis for arguments list" );
return args;
}
function parseArgumentsList() {
const args = [];
while (!is(TOKEN_TYPES.CloseParen)) {
let argument = parseExpression();
if (is(TOKEN_TYPES.Equals)) {
++current;
if (!(argument instanceof Identifier)) {
throw new SyntaxError(`Expected identifier for keyword argument`);
}
const value = parseExpression();
argument = new KeywordArgumentExpression(argument, value);
}
args.push(argument);
if (is(TOKEN_TYPES.Comma)) {
++current;
}
}
return args;
}
function parseMemberExpressionArgumentsList() {
const slices = [];
let isSlice = false ;
while (!is(TOKEN_TYPES.CloseSquareBracket)) {
if (is(TOKEN_TYPES.Colon)) {
slices.push(void 0);
++current;
isSlice = true ;
} else {
slices.push(parseExpression());
if (is(TOKEN_TYPES.Colon)) {
++current;
isSlice = true ;
}
}
}
if (slices.length === 0) {
throw new SyntaxError(`Expected at least one argument for member/slice expression`);
}
if (isSlice) {
if (slices.length > 3) {
throw new SyntaxError(`Expected 0-3 arguments for slice expression`);
}
return new SliceExpression(...slices);
}
return slices[0];
}
function parseMemberExpression() {
let object = parsePrimaryExpression();
while (is(TOKEN_TYPES.Dot) || is(TOKEN_TYPES.OpenSquareBracket)) {
const operator = tokens[current];
++current;
let property;
const computed = operator.type !== TOKEN_TYPES.Dot;
if (computed) {
property = parseMemberExpressionArgumentsList();
expect(TOKEN_TYPES.CloseSquareBracket, "Expected closing square bracket" );
} else {
property = parsePrimaryExpression();
if (property.type !== "Identifier" ) {
throw new SyntaxError(`Expected identifier following dot operator`);
}
}
object = new MemberExpression(object, property, computed);
}
return object;
}
function parseMultiplicativeExpression() {
let left = parseTestExpression();
while (is(TOKEN_TYPES.MultiplicativeBinaryOperator)) {
const operator = tokens[current];
++current;
const right = parseTestExpression();
left = new BinaryExpression(operator, left, right);
}
return left;
}
function parseTestExpression() {
let operand = parseFilterExpression();
while (is(TOKEN_TYPES.Is)) {
++current;
const negate = is(TOKEN_TYPES.Not);
if (negate) {
++current;
}
let filter = parsePrimaryExpression();
if (filter instanceof BooleanLiteral) {
filter = new Identifier(filter.value.toString());
} else if (filter instanceof NullLiteral) {
filter = new Identifier("none" );
}
if (!(filter instanceof Identifier)) {
throw new SyntaxError(`Expected identifier for the test`);
}
operand = new TestExpression(operand, negate, filter);
}
return operand;
}
function parseFilterExpression() {
let operand = parseCallMemberExpression();
while (is(TOKEN_TYPES.Pipe)) {
++current;
let filter = parsePrimaryExpression();
if (!(filter instanceof Identifier)) {
throw new SyntaxError(`Expected identifier for the filter`);
}
if (is(TOKEN_TYPES.OpenParen)) {
filter = parseCallExpression(filter);
}
operand = new FilterExpression(operand, filter);
}
return operand;
}
function parsePrimaryExpression() {
const token = tokens[current];
switch (token.type) {
case TOKEN_TYPES.NumericLiteral:
++current;
return new NumericLiteral(Number(token.value));
case TOKEN_TYPES.StringLiteral:
++current;
return new StringLiteral(token.value);
case TOKEN_TYPES.BooleanLiteral:
++current;
return new BooleanLiteral(token.value.toLowerCase() === "true" );
case TOKEN_TYPES.NullLiteral:
++current;
return new NullLiteral(null );
case TOKEN_TYPES.Identifier:
++current;
return new Identifier(token.value);
case TOKEN_TYPES.OpenParen: {
++current;
const expression = parseExpressionSequence();
if (tokens[current].type !== TOKEN_TYPES.CloseParen) {
throw new SyntaxError(`Expected closing parenthesis, got ${tokens[current].type} instead`);
}
++current;
return expression;
}
case TOKEN_TYPES.OpenSquareBracket: {
++current;
const values = [];
while (!is(TOKEN_TYPES.CloseSquareBracket)) {
values.push(parseExpression());
if (is(TOKEN_TYPES.Comma)) {
++current;
}
}
++current;
return new ArrayLiteral(values);
}
case TOKEN_TYPES.OpenCurlyBracket: {
++current;
const values = /* @__PURE__ */ new Map();
while (!is(TOKEN_TYPES.CloseCurlyBracket)) {
const key = parseExpression();
expect(TOKEN_TYPES.Colon, "Expected colon between key and value in object literal" );
const value = parseExpression();
values.set(key, value);
if (is(TOKEN_TYPES.Comma)) {
++current;
}
}
++current;
return new ObjectLiteral(values);
}
default :
throw new SyntaxError(`Unexpected token: ${token.type}`);
}
}
while (current < tokens.length) {
program.body.push(parseAny());
}
return program;
}
// src/utils.ts
function range(start, stop, step = 1) {
if (stop === void 0) {
stop = start;
start = 0;
}
const result = [];
for (let i = start; i < stop; i += step) {
result.push(i);
}
return result;
}
function slice(array, start, stop, step = 1) {
const direction = Math.sign(step);
if (direction >= 0) {
start = (start ??= 0) < 0 ? Math.max(array.length + start, 0) : Math.min(start, array.length);
stop = (stop ??= array.length) < 0 ? Math.max(array.length + stop, 0) : Math.min(stop, array.length);
} else {
start = (start ??= array.length - 1) < 0 ? Math.max(array.length + start, -1) : Math.min(start, array.length - 1);
stop = (stop ??= -1) < -1 ? Math.max(array.length + stop, -1) : Math.min(stop, array.length - 1);
}
const result = [];
for (let i = start; direction * i < direction * stop; i += step) {
result.push(array[i]);
}
return result;
}
function titleCase(value) {
return value.replace(/\b\w/g, (c) => c.toUpperCase());
}
// src/runtime.ts
var RuntimeValue = class {
type = "RuntimeValue" ;
value;
/**
* A collection of built-in functions for this type.
*/
builtins = /* @__PURE__ */ new Map();
/**
* Creates a new RuntimeValue.
*/
constructor(value = void 0) {
this .value = value;
}
/**
* Determines truthiness or falsiness of the runtime value.
* This function should be overridden by subclasses if it has custom truthiness criteria.
* @returns {BooleanValue} BooleanValue(true) if the value is truthy, BooleanValue(false) otherwise.
*/
__bool__() {
return new BooleanValue(!!this .value);
}
};
var NumericValue = class extends RuntimeValue {
type = "NumericValue" ;
};
var StringValue = class extends RuntimeValue {
type = "StringValue" ;
builtins = /* @__PURE__ */ new Map([
[
"upper" ,
new FunctionValue(() => {
return new StringValue(this .value.toUpperCase());
})
],
[
"lower" ,
new FunctionValue(() => {
return new StringValue(this .value.toLowerCase());
})
],
[
"strip" ,
new FunctionValue(() => {
return new StringValue(this .value.trim());
})
],
[
"title" ,
new FunctionValue(() => {
return new StringValue(titleCase(this .value));
})
],
["length" , new NumericValue(this .value.length)],
[
"rstrip" ,
new FunctionValue(() => {
return new StringValue(this .value.trimEnd());
})
],
[
"lstrip" ,
new FunctionValue(() => {
return new StringValue(this .value.trimStart());
})
]
]);
};
var BooleanValue = class extends RuntimeValue {
type = "BooleanValue" ;
};
var ObjectValue = class extends RuntimeValue {
type = "ObjectValue" ;
/**
* NOTE: necessary to override since all JavaScript arrays are considered truthy,
* while only non-empty Python arrays are consider truthy.
*
* e.g.,
* - JavaScript: {} && 5 -> 5
* - Python: {} and 5 -> {}
*/
__bool__() {
return new BooleanValue(this .value.size > 0);
}
builtins = /* @__PURE__ */ new Map([
[
"get" ,
new FunctionValue(([key, defaultValue]) => {
if (!(key instanceof StringValue)) {
throw new Error(`Object key must be a string: got ${key.type}`);
}
return this .value.get(key.value) ?? defaultValue ?? new NullValue();
})
],
[
"items" ,
new FunctionValue(() => {
return new ArrayValue(
Array.from(this .value.entries()).map(([key, value]) => new ArrayValue([new StringValue(key), value]))
);
})
]
]);
};
var KeywordArgumentsValue = class extends ObjectValue {
type = "KeywordArgumentsValue" ;
};
var ArrayValue = class extends RuntimeValue {
type = "ArrayValue" ;
builtins = /* @__PURE__ */ new Map([["length", new NumericValue(this.value.length)]]);
/**
* NOTE: necessary to override since all JavaScript arrays are considered truthy,
* while only non-empty Python arrays are consider truthy.
*
* e.g.,
* - JavaScript: [] && 5 -> 5
* - Python: [] and 5 -> []
*/
__bool__() {
return new BooleanValue(this .value.length > 0);
}
};
var TupleValue = class extends ArrayValue {
type = "TupleValue" ;
};
var FunctionValue = class extends RuntimeValue {
type = "FunctionValue" ;
};
var NullValue = class extends RuntimeValue {
type = "NullValue" ;
};
var UndefinedValue = class extends RuntimeValue {
type = "UndefinedValue" ;
};
var Environment = class {
constructor(parent) {
this .parent = parent;
}
/**
* The variables declared in this environment.
*/
variables = /* @__PURE__ */ new Map([
[
"namespace" ,
new FunctionValue((args) => {
if (args.length === 0) {
return new ObjectValue(/* @__PURE__ */ new Map());
}
if (args.length !== 1 || !(args[0] instanceof ObjectValue)) {
throw new Error("`namespace` expects either zero arguments or a single object argument" );
}
return args[0];
})
]
]);
/**
* The tests available in this environment.
*/
tests = /* @__PURE__ */ new Map([
["boolean" , (operand) => operand.type === "BooleanValue" ],
["callable" , (operand) => operand instanceof FunctionValue],
[
"odd" ,
(operand) => {
if (operand.type !== "NumericValue" ) {
throw new Error(`Cannot apply test "odd" to type: ${operand.type}`);
}
return operand.value % 2 !== 0;
}
],
[
"even" ,
(operand) => {
if (operand.type !== "NumericValue" ) {
throw new Error(`Cannot apply test "even" to type: ${operand.type}`);
}
return operand.value % 2 === 0;
}
],
["false" , (operand) => operand.type === "BooleanValue" && !operand.value],
["true" , (operand) => operand.type === "BooleanValue" && operand.value],
["none" , (operand) => operand.type === "NullValue" ],
["string" , (operand) => operand.type === "StringValue" ],
["number" , (operand) => operand.type === "NumericValue" ],
["integer" , (operand) => operand.type === "NumericValue" && Number.isInteger(operand.value)],
["iterable" , (operand) => operand.type === "ArrayValue" || operand.type === "StringValue" ],
["mapping" , (operand) => operand.type === "ObjectValue" ],
[
"lower" ,
(operand) => {
const str = operand.value;
return operand.type === "StringValue" && str === str.toLowerCase();
}
],
[
"upper" ,
(operand) => {
const str = operand.value;
return operand.type === "StringValue" && str === str.toUpperCase();
}
],
["none" , (operand) => operand.type === "NullValue" ],
["defined" , (operand) => operand.type !== "UndefinedValue" ],
["undefined" , (operand) => operand.type === "UndefinedValue" ],
["equalto" , (a, b) => a.value === b.value],
["eq" , (a, b) => a.value === b.value]
]);
/**
* Set the value of a variable in the current environment.
*/
set(name, value) {
return this .declareVariable(name, convertToRuntimeValues(value));
}
declareVariable(name, value) {
if (this .variables.has(name)) {
throw new SyntaxError(`Variable already declared: ${name}`);
}
this .variables.set(name, value);
return value;
}
// private assignVariable(name: string, value: AnyRuntimeValue): AnyRuntimeValue {
// const env = this.resolve(name);
// env.variables.set(name, value);
// return value;
// }
/**
* Set variable in the current scope.
* See https://jinja.palletsprojects.com/en/3.0.x/templates/#assignments for more information.
*/
setVariable(name, value) {
this .variables.set(name, value);
return value;
}
/**
* Resolve the environment in which the variable is declared.
* @param {string} name The name of the variable.
* @returns {Environment} The environment in which the variable is declared.
*/
resolve(name) {
if (this .variables.has(name)) {
return this ;
}
if (this .parent) {
return this .parent.resolve(name);
}
throw new Error(`Unknown variable: ${name}`);
}
lookupVariable(name) {
try {
return this .resolve(name).variables.get(name) ?? new UndefinedValue();
} catch {
return new UndefinedValue();
}
}
};
var Interpreter = class {
global;
constructor(env) {
this .global = env ?? new Environment();
}
/**
* Run the program.
*/
run(program) {
return this .evaluate(program, this .global);
}
/**
* Evaluates expressions following the binary operation type.
*/
evaluateBinaryExpression(node, environment) {
const left = this .evaluate(node.left, environment);
switch (node.operator.value) {
case "and" :
return left.__bool__().value ? this .evaluate(node.right, environment) : left;
case "or" :
return left.__bool__().value ? left : this .evaluate(node.right, environment);
}
const right = this .evaluate(node.right, environment);
switch (node.operator.value) {
case "==" :
return new BooleanValue(left.value == right.value);
case "!=" :
return new BooleanValue(left.value != right.value);
}
if (left instanceof UndefinedValue || right instanceof UndefinedValue) {
throw new Error("Cannot perform operation on undefined values" );
} else if (left instanceof NullValue || right instanceof NullValue) {
throw new Error("Cannot perform operation on null values" );
} else if (left instanceof NumericValue && right instanceof NumericValue) {
switch (node.operator.value) {
case "+" :
return new NumericValue(left.value + right.value);
case "-" :
return new NumericValue(left.value - right.value);
case "*" :
return new NumericValue(left.value * right.value);
case "/" :
return new NumericValue(left.value / right.value);
case "%" :
return new NumericValue(left.value % right.value);
case "<" :
return new BooleanValue(left.value < right.value);
case ">" :
return new BooleanValue(left.value > right.value);
case ">=" :
return new BooleanValue(left.value >= right.value);
case "<=" :
return new BooleanValue(left.value <= right.value);
}
} else if (left instanceof ArrayValue && right instanceof ArrayValue) {
switch (node.operator.value) {
case "+" :
return new ArrayValue(left.value.concat(right.value));
}
} else if (right instanceof ArrayValue) {
const member = right.value.find((x) => x.value === left.value) !== void 0;
switch (node.operator.value) {
case "in" :
return new BooleanValue(member);
case "not in" :
return new BooleanValue(!member);
}
}
if (left instanceof StringValue || right instanceof StringValue) {
switch (node.operator.value) {
case "+" :
return new StringValue(left.value.toString() + right.value.toString());
}
}
if (left instanceof StringValue && right instanceof StringValue) {
switch (node.operator.value) {
case "in" :
return new BooleanValue(right.value.includes(left.value));
case "not in" :
return new BooleanValue(!right.value.includes(left.value));
}
}
if (left instanceof StringValue && right instanceof ObjectValue) {
switch (node.operator.value) {
case "in" :
return new BooleanValue(right.value.has(left.value));
case "not in" :
return new BooleanValue(!right.value.has(left.value));
}
}
throw new SyntaxError(`Unknown operator "${node.operator.value}" between ${left.type} and ${right.type}`);
}
evaluateArguments(args, environment) {
const positionalArguments = [];
const keywordArguments = /* @__PURE__ */ new Map();
for (const argument of args) {
if (argument.type === "KeywordArgumentExpression" ) {
const kwarg = argument;
keywordArguments.set(kwarg.key.value, this .evaluate(kwarg.value, environment));
} else {
if (keywordArguments.size > 0) {
throw new Error("Positional arguments must come before keyword arguments" );
}
positionalArguments.push(this .evaluate(argument, environment));
}
}
return [positionalArguments, keywordArguments];
}
/**
* Evaluates expressions following the filter operation type.
*/
evaluateFilterExpression(node, environment) {
const operand = this .evaluate(node.operand, environment);
if (node.filter.type === "Identifier" ) {
const filter = node.filter;
if (filter.value === "tojson" ) {
return new StringValue(toJSON(operand));
}
if (operand instanceof ArrayValue) {
switch (filter.value) {
case "list" :
return operand;
case "first" :
return operand.value[0];
case "last" :
return operand.value[operand.value.length - 1];
case "length" :
return new NumericValue(operand.value.length);
case "reverse" :
return new ArrayValue(operand.value.reverse());
case "sort" :
return new ArrayValue(
operand.value.sort((a, b) => {
if (a.type !== b.type) {
throw new Error(`Cannot compare different types: ${a.type} and ${b.type}`);
}
switch (a.type) {
case "NumericValue" :
return a.value - b.value;
case "StringValue" :
return a.value.localeCompare(b.value);
default :
throw new Error(`Cannot compare type: ${a.type}`);
}
})
);
default :
throw new Error(`Unknown ArrayValue filter: ${filter.value}`);
}
} else if (operand instanceof StringValue) {
switch (filter.value) {
case "length" :
return new NumericValue(operand.value.length);
case "upper" :
return new StringValue(operand.value.toUpperCase());
case "lower" :
return new StringValue(operand.value.toLowerCase());
case "title" :
return new StringValue(titleCase(operand.value));
case "capitalize" :
return new StringValue(operand.value.charAt(0).toUpperCase() + operand.value.slice(1));
case "trim" :
return new StringValue(operand.value.trim());
case "indent" :
return new StringValue(
operand.value.split("\n" ).map(
(x, i) => (
// By default, don't indent the first line or empty lines
i === 0 || x.length === 0 ? x : " " + x
)
).join("\n" )
);
case "string" :
return operand;
default :
throw new Error(`Unknown StringValue filter: ${filter.value}`);
}
} else if (operand instanceof NumericValue) {
switch (filter.value) {
case "abs" :
return new NumericValue(Math.abs(operand.value));
default :
throw new Error(`Unknown NumericValue filter: ${filter.value}`);
}
} else if (operand instanceof ObjectValue) {
switch (filter.value) {
case "items" :
return new ArrayValue(
Array.from(operand.value.entries()).map(([key, value]) => new ArrayValue([new StringValue(key), value]))
);
case "length" :
return new NumericValue(operand.value.size);
default :
throw new Error(`Unknown ObjectValue filter: ${filter.value}`);
}
}
throw new Error(`Cannot apply filter "${filter.value}" to type: ${operand.type}`);
} else if (node.filter.type === "CallExpression" ) {
const filter = node.filter;
if (filter.callee.type !== "Identifier" ) {
throw new Error(`Unknown filter: ${filter.callee.type}`);
}
const filterName = filter.callee.value;
if (filterName === "tojson" ) {
const [, kwargs] = this .evaluateArguments(filter.args, environment);
const indent = kwargs.get("indent" ) ?? new NullValue();
if (!(indent instanceof NumericValue || indent instanceof NullValue)) {
throw new Error("If set, indent must be a number" );
}
return new StringValue(toJSON(operand, indent.value));
}
if (operand instanceof ArrayValue) {
switch (filterName) {
case "selectattr" :
case "rejectattr" : {
const select = filterName === "selectattr" ;
if (operand.value.some((x) => !(x instanceof ObjectValue))) {
throw new Error(`\`${filterName}\` can only be applied to array of objects`);
}
if (filter.args.some((x) => x.type !== "StringLiteral" )) {
throw new Error(`arguments of \`${filterName}\` must be strings`);
}
const [attr, testName, value] = filter.args.map((x) => this .evaluate(x, environment));
let testFunction;
if (testName) {
const test = environment.tests.get(testName.value);
if (!test) {
throw new Error(`Unknown test: ${testName.value}`);
}
testFunction = test;
} else {
testFunction = (...x) => x[0].__bool__().value;
}
const filtered = operand.value.filter((item) => {
const a = item.value.get(attr.value);
const result = a ? testFunction(a, value) : false ;
return select ? result : !result;
});
return new ArrayValue(filtered);
}
case "map" : {
const [, kwargs] = this .evaluateArguments(filter.args, environment);
if (kwargs.has("attribute" )) {
const attr = kwargs.get("attribute" );
if (!(attr instanceof StringValue)) {
throw new Error("attribute must be a string" );
}
const defaultValue = kwargs.get("default" );
const mapped = operand.value.map((item) => {
if (!(item instanceof ObjectValue)) {
throw new Error("items in map must be an object" );
}
return item.value.get(attr.value) ?? defaultValue ?? new UndefinedValue();
});
return new ArrayValue(mapped);
} else {
throw new Error("`map` expressions without `attribute` set are not currently supported." );
}
}
}
throw new Error(`Unknown ArrayValue filter: ${filterName}`);
} else if (operand instanceof StringValue) {
switch (filterName) {
case "indent" : {
const [args, kwargs] = this .evaluateArguments(filter.args, environment);
const width = args.at(0) ?? kwargs.get("width" ) ?? new NumericValue(4);
if (!(width instanceof NumericValue)) {
throw new Error("width must be a number" );
}
const first = args.at(1) ?? kwargs.get("first" ) ?? new BooleanValue(false );
const blank = args.at(2) ?? kwargs.get("blank" ) ?? new BooleanValue(false );
const lines = operand.value.split("\n" );
const indent = " " .repeat(width.value);
const indented = lines.map(
(x, i) => !first.value && i === 0 || !blank.value && x.length === 0 ? x : indent + x
);
return new StringValue(indented.join("\n" ));
}
}
throw new Error(`Unknown StringValue filter: ${filterName}`);
} else {
throw new Error(`Cannot apply filter "${filterName}" to type: ${operand.type}`);
}
}
throw new Error(`Unknown filter: ${node.filter.type}`);
}
/**
* Evaluates expressions following the test operation type.
*/
evaluateTestExpression(node, environment) {
const operand = this .evaluate(node.operand, environment);
const test = environment.tests.get(node.test.value);
if (!test) {
throw new Error(`Unknown test: ${node.test.value}`);
}
const result = test(operand);
return new BooleanValue(node.negate ? !result : result);
}
/**
* Evaluates expressions following the unary operation type.
*/
evaluateUnaryExpression(node, environment) {
const argument = this .evaluate(node.argument, environment);
switch (node.operator.value) {
case "not" :
return new BooleanValue(!argument.value);
default :
throw new SyntaxError(`Unknown operator: ${node.operator.value}`);
}
}
evalProgram(program, environment) {
return this .evaluateBlock(program.body, environment);
}
evaluateBlock(statements, environment) {
let result = "" ;
for (const statement of statements) {
const lastEvaluated = this .evaluate(statement, environment);
if (lastEvaluated.type !== "NullValue" && lastEvaluated.type !== "UndefinedValue" ) {
result += lastEvaluated.value;
}
}
return new StringValue(result);
}
evaluateIdentifier(node, environment) {
return environment.lookupVariable(node.value);
}
evaluateCallExpression(expr, environment) {
const [args, kwargs] = this .evaluateArguments(expr.args, environment);
if (kwargs.size > 0) {
args.push(new KeywordArgumentsValue(kwargs));
}
const fn = this .evaluate(expr.callee, environment);
if (fn.type !== "FunctionValue" ) {
throw new Error(`Cannot call something that is not a function : got ${fn.type}`);
}
return fn.value(args, environment);
}
evaluateSliceExpression(object, expr, environment) {
if (!(object instanceof ArrayValue || object instanceof StringValue)) {
throw new Error("Slice object must be an array or string" );
}
const start = this .evaluate(expr.start, environment);
const stop = this .evaluate(expr.stop, environment);
const step = this .evaluate(expr.step, environment);
if (!(start instanceof NumericValue || start instanceof UndefinedValue)) {
throw new Error("Slice start must be numeric or undefined" );
}
if (!(stop instanceof NumericValue || stop instanceof UndefinedValue)) {
throw new Error("Slice stop must be numeric or undefined" );
}
if (!(step instanceof NumericValue || step instanceof UndefinedValue)) {
throw new Error("Slice step must be numeric or undefined" );
}
if (object instanceof ArrayValue) {
return new ArrayValue(slice(object.value, start.value, stop.value, step.value));
} else {
return new StringValue(slice(Array.from(object.value), start.value, stop.value, step.value).join("" ));
}
}
evaluateMemberExpression(expr, environment) {
const object = this .evaluate(expr.object, environment);
let property;
if (expr.computed) {
if (expr.property.type === "SliceExpression" ) {
return this .evaluateSliceExpression(object, expr.property, environment);
} else {
property = this .evaluate(expr.property, environment);
}
} else {
property = new StringValue(expr.property.value);
}
let value;
if (object instanceof ObjectValue) {
if (!(property instanceof StringValue)) {
throw new Error(`Cannot access property with non-string: got ${property.type}`);
}
value = object.value.get(property.value) ?? object.builtins.get(property.value);
} else if (object instanceof ArrayValue || object instanceof StringValue) {
if (property instanceof NumericValue) {
value = object.value.at(property.value);
if (object instanceof StringValue) {
value = new StringValue(object.value.at(property.value));
}
} else if (property instanceof StringValue) {
value = object.builtins.get(property.value);
} else {
throw new Error(`Cannot access property with non-string/non-number: got ${property.type}`);
}
} else {
if (!(property instanceof StringValue)) {
throw new Error(`Cannot access property with non-string: got ${property.type}`);
}
value = object.builtins.get(property.value);
}
return value instanceof RuntimeValue ? value : new UndefinedValue();
}
evaluateSet(node, environment) {
const rhs = this .evaluate(node.value, environment);
if (node.assignee.type === "Identifier" ) {
const variableName = node.assignee.value;
environment.setVariable(variableName, rhs);
} else if (node.assignee.type === "MemberExpression" ) {
const member = node.assignee;
const object = this .evaluate(member.object, environment);
if (!(object instanceof ObjectValue)) {
throw new Error("Cannot assign to member of non-object" );
}
if (member.property.type !== "Identifier" ) {
throw new Error("Cannot assign to member with non-identifier property" );
}
object.value.set(member.property.value, rhs);
} else {
throw new Error(`Invalid LHS inside assignment expression: ${JSON.stringify(node.assignee)}`);
}
return new NullValue();
}
evaluateIf(node, environment) {
const test = this .evaluate(node.test, environment);
return this .evaluateBlock(test.__bool__().value ? node.body : node.alternate, environment);
}
evaluateFor(node, environment) {
const scope = new Environment(environment);
let test, iterable;
if (node.iterable.type === "SelectExpression" ) {
const select = node.iterable;
iterable = this .evaluate(select.iterable, scope);
test = select.test;
} else {
iterable = this .evaluate(node.iterable, scope);
}
if (!(iterable instanceof ArrayValue)) {
throw new Error(`Expected iterable type in for loop: got ${iterable.type}`);
}
const items = [];
const scopeUpdateFunctions = [];
for (let i = 0; i < iterable.value.length; ++i) {
const loopScope = new Environment(scope);
const current = iterable.value[i];
let scopeUpdateFunction;
if (node.loopvar.type === "Identifier" ) {
scopeUpdateFunction = (scope2) => scope2.setVariable(node.loopvar.value, current);
} else if (node.loopvar.type === "TupleLiteral" ) {
const loopvar = node.loopvar;
if (current.type !== "ArrayValue" ) {
throw new Error(`Cannot unpack non-iterable type: ${current.type}`);
}
const c = current;
if (loopvar.value.length !== c.value.length) {
throw new Error(`Too ${loopvar.value.length > c.value.length ? "few" : "many" } items to unpack`);
}
scopeUpdateFunction = (scope2) => {
for (let j = 0; j < loopvar.value.length; ++j) {
if (loopvar.value[j].type !== "Identifier" ) {
throw new Error(`Cannot unpack non-identifier type: ${loopvar.value[j].type}`);
}
scope2.setVariable(loopvar.value[j].value, c.value[j]);
}
};
} else {
throw new Error(`Invalid loop variable(s): ${node.loopvar.type}`);
}
if (test) {
scopeUpdateFunction(loopScope);
const testValue = this .evaluate(test, loopScope);
if (!testValue.__bool__().value) {
continue ;
}
}
items.push(current);
scopeUpdateFunctions.push(scopeUpdateFunction);
}
let result = "" ;
let noIteration = true ;
for (let i = 0; i < items.length; ++i) {
const loop = /* @__PURE__ */ new Map([
["index" , new NumericValue(i + 1)],
["index0" , new NumericValue(i)],
["revindex" , new NumericValue(items.length - i)],
["revindex0" , new NumericValue(items.length - i - 1)],
["first" , new BooleanValue(i === 0)],
["last" , new BooleanValue(i === items.length - 1)],
["length" , new NumericValue(items.length)],
["previtem" , i > 0 ? items[i - 1] : new UndefinedValue()],
["nextitem" , i < items.length - 1 ? items[i + 1] : new UndefinedValue()]
]);
scope.setVariable("loop" , new ObjectValue(loop));
scopeUpdateFunctions[i](scope);
const evaluated = this .evaluateBlock(node.body, scope);
result += evaluated.value;
noIteration = false ;
}
if (noIteration) {
const defaultEvaluated = this .evaluateBlock(node.defaultBlock, scope);
result += defaultEvaluated.value;
}
return new StringValue(result);
}
/**
* See https://jinja.palletsprojects.com/en/3.1.x/templates/#macros for more information.
*/
evaluateMacro(node, environment) {
environment.setVariable(
node.name.value,
new FunctionValue((args, scope) => {
const macroScope = new Environment(scope);
args = args.slice();
let kwargs;
if (args.at(-1)?.type === "KeywordArgumentsValue" ) {
kwargs = args.pop();
}
for (let i = 0; i < node.args.length; ++i) {
const nodeArg = node.args[i];
const passedArg = args[i];
if (nodeArg.type === "Identifier" ) {
const identifier = nodeArg;
if (!passedArg) {
throw new Error(`Missing positional argument: ${identifier.value}`);
}
macroScope.setVariable(identifier.value, passedArg);
} else if (nodeArg.type === "KeywordArgumentExpression" ) {
const kwarg = nodeArg;
const value = passedArg ?? // Try positional arguments first
kwargs?.value.get(kwarg.key.value) ?? // Look in user-passed kwargs
this .evaluate(kwarg.value, macroScope);
macroScope.setVariable(kwarg.key.value, value);
} else {
throw new Error(`Unknown argument type: ${nodeArg.type}`);
}
}
return this .evaluateBlock(node.body, macroScope);
})
);
return new NullValue();
}
evaluate(statement, environment) {
if (statement === void 0)
return new UndefinedValue();
switch (statement.type) {
case "Program" :
return this .evalProgram(statement, environment);
case "Set" :
return this .evaluateSet(statement, environment);
case "If" :
return this .evaluateIf(statement, environment);
case "For" :
return this .evaluateFor(statement, environment);
case "Macro" :
return this .evaluateMacro(statement, environment);
case "NumericLiteral" :
return new NumericValue(Number(statement.value));
case "StringLiteral" :
return new StringValue(statement.value);
case "BooleanLiteral" :
return new BooleanValue(statement.value);
case "NullLiteral" :
return new NullValue(statement.value);
case "ArrayLiteral" :
return new ArrayValue(statement.value.map((x) => this .evaluate(x, environment)));
case "TupleLiteral" :
return new TupleValue(statement.value.map((x) => this .evaluate(x, environment)));
case "ObjectLiteral" : {
const mapping = /* @__PURE__ */ new Map();
for (const [key, value] of statement.value) {
const evaluatedKey = this .evaluate(key, environment);
if (!(evaluatedKey instanceof StringValue)) {
throw new Error(`Object keys must be strings: got ${evaluatedKey.type}`);
}
mapping.set(evaluatedKey.value, this .evaluate(value, environment));
}
return new ObjectValue(mapping);
}
case "Identifier" :
return this .evaluateIdentifier(statement, environment);
case "CallExpression" :
return this .evaluateCallExpression(statement, environment);
case "MemberExpression" :
return this .evaluateMemberExpression(statement, environment);
case "UnaryExpression" :
return this .evaluateUnaryExpression(statement, environment);
case "BinaryExpression" :
return this .evaluateBinaryExpression(statement, environment);
case "FilterExpression" :
return this .evaluateFilterExpression(statement, environment);
case "TestExpression" :
return this .evaluateTestExpression(statement, environment);
default :
throw new SyntaxError(`Unknown node type: ${statement.type}`);
}
}
};
function convertToRuntimeValues(input) {
switch (typeof input) {
case "number" :
return new NumericValue(input);
case "string" :
return new StringValue(input);
case "boolean" :
return new BooleanValue(input);
case "undefined" :
return new UndefinedValue();
case "object" :
if (input === null ) {
return new NullValue();
} else if (Array.isArray(input)) {
return new ArrayValue(input.map(convertToRuntimeValues));
} else {
return new ObjectValue(
new Map(Object.entries(input).map(([key, value]) => [key, convertToRuntimeValues(value)]))
);
}
case "function" :
return new FunctionValue((args, _scope) => {
const result = input(...args.map((x) => x.value)) ?? null ;
return convertToRuntimeValues(result);
});
default :
throw new Error(`Cannot convert to runtime value: ${input}`);
}
}
function toJSON(input, indent, depth) {
const currentDepth = depth ?? 0;
switch (input.type) {
case "NullValue" :
case "UndefinedValue" :
return "null" ;
case "NumericValue" :
case "StringValue" :
case "BooleanValue" :
return JSON.stringify(input.value);
case "ArrayValue" :
case "ObjectValue" : {
const indentValue = indent ? " " .repeat(indent) : "" ;
const basePadding = "\n" + indentValue.repeat(currentDepth);
const childrenPadding = basePadding + indentValue;
if (input.type === "ArrayValue" ) {
const core = input.value.map((x) => toJSON(x, indent, currentDepth + 1));
return indent ? `[${childrenPadding}${core.join(`,${childrenPadding}`)}${basePadding}]` : `[${core.join(", " )}]`;
} else {
const core = Array.from(input.value.entries()).map(([key, value]) => {
const v = `"${key}" : ${toJSON(value, indent, currentDepth + 1)}`;
return indent ? `${childrenPadding}${v}` : v;
});
return indent ? `{${core.join("," )}${basePadding}}` : `{${core.join(", " )}}`;
}
}
default :
throw new Error(`Cannot convert to JSON: ${input.type}`);
}
}
// src/index.ts
var Template = class {
parsed;
/**
* @param {string} template The template string
*/
constructor(template) {
const tokens = tokenize(template, {
lstrip_blocks: true ,
trim_blocks: true
});
this .parsed = parse(tokens);
}
render(items) {
const env = new Environment();
env.set("false" , false );
env.set("true" , true );
env.set("raise_exception" , (args) => {
throw new Error(args);
});
env.set("range" , range);
for (const [key, value] of Object.entries(items)) {
env.set(key, value);
}
const interpreter = new Interpreter(env);
const result = interpreter.run(this .parsed);
return result.value;
}
};
/***/ }),
/***/ "./node_modules/onnxruntime-common/dist/esm/backend-impl.js":
/*!******************************************************************!*\
!*** ./node_modules/onnxruntime-common/dist/esm/backend-impl.js ***!
\******************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ registerBackend: () => (/* binding */ registerBackend),
/* harmony export */ resolveBackendAndExecutionProviders: () => (/* binding */ resolveBackendAndExecutionProviders)
/* harmony export */ });
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const backends = new Map();
const backendsSortedByPriority = [];
/**
* Register a backend.
*
* @param name - the name as a key to lookup as an execution provider.
* @param backend - the backend object.
* @param priority - an integer indicating the priority of the backend. Higher number means higher priority. if priority
* < 0, it will be considered as a 'beta' version and will not be used as a fallback backend by default.
*
* @ignore
*/
const registerBackend = (name, backend, priority) => {
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5 C=93 H=93 G=92
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland