alanvww/p5js-object-detection-webgpu
1
1/******/ (() => { // webpackBootstrap2/******/ var __webpack_modules__ = ({3 4/***/ "?2ce3":5/*!**********************************!*\6 !*** onnxruntime-node (ignored) ***!7 \**********************************/8/***/ (() => {9 10/* (ignored) */11 12/***/ }),13 14/***/ "?9c66":15/*!****************************************!*\16 !*** onnxruntime-web/webgpu (ignored) ***!17 \****************************************/18/***/ (() => {19 20/* (ignored) */21 22/***/ }),23 24/***/ "?7a2c":25/*!********************!*\26 !*** fs (ignored) ***!27 \********************/28/***/ (() => {29 30/* (ignored) */31 32/***/ }),33 34/***/ "?a42a":35/*!**********************!*\36 !*** path (ignored) ***!37 \**********************/38/***/ (() => {39 40/* (ignored) */41 42/***/ }),43 44/***/ "?2b25":45/*!***********************!*\46 !*** sharp (ignored) ***!47 \***********************/48/***/ (() => {49 50/* (ignored) */51 52/***/ }),53 54/***/ "?569f":55/*!********************!*\56 !*** fs (ignored) ***!57 \********************/58/***/ (() => {59 60/* (ignored) */61 62/***/ }),63 64/***/ "?3f59":65/*!**********************!*\66 !*** path (ignored) ***!67 \**********************/68/***/ (() => {69 70/* (ignored) */71 72/***/ }),73 74/***/ "?154a":75/*!*********************!*\76 !*** url (ignored) ***!77 \*********************/78/***/ (() => {79 80/* (ignored) */81 82/***/ }),83 84/***/ "./node_modules/@huggingface/jinja/dist/index.js":85/*!*******************************************************!*\86 !*** ./node_modules/@huggingface/jinja/dist/index.js ***!87 \*******************************************************/88/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {89 90"use strict";91__webpack_require__.r(__webpack_exports__);92/* harmony export */ __webpack_require__.d(__webpack_exports__, {93/* harmony export */ "Environment": () => (/* binding */ Environment),94/* harmony export */ "Interpreter": () => (/* binding */ Interpreter),95/* harmony export */ "Template": () => (/* binding */ Template),96/* harmony export */ "parse": () => (/* binding */ parse),97/* harmony export */ "tokenize": () => (/* binding */ tokenize)98/* harmony export */ });99// src/lexer.ts100var TOKEN_TYPES = Object.freeze({101 Text: "Text",102 // The text between Jinja statements or expressions103 NumericLiteral: "NumericLiteral",104 // e.g., 123105 BooleanLiteral: "BooleanLiteral",106 // true or false107 StringLiteral: "StringLiteral",108 // 'string'109 Identifier: "Identifier",110 // Variables, functions, etc.111 Equals: "Equals",112 // =113 OpenParen: "OpenParen",114 // (115 CloseParen: "CloseParen",116 // )117 OpenStatement: "OpenStatement",118 // {%119 CloseStatement: "CloseStatement",120 // %}121 OpenExpression: "OpenExpression",122 // {{123 CloseExpression: "CloseExpression",124 // }}125 OpenSquareBracket: "OpenSquareBracket",126 // [127 CloseSquareBracket: "CloseSquareBracket",128 // ]129 OpenCurlyBracket: "OpenCurlyBracket",130 // {131 CloseCurlyBracket: "CloseCurlyBracket",132 // }133 Comma: "Comma",134 // ,135 Dot: "Dot",136 // .137 Colon: "Colon",138 // :139 Pipe: "Pipe",140 // |141 CallOperator: "CallOperator",142 // ()143 AdditiveBinaryOperator: "AdditiveBinaryOperator",144 // + -145 MultiplicativeBinaryOperator: "MultiplicativeBinaryOperator",146 // * / %147 ComparisonBinaryOperator: "ComparisonBinaryOperator",148 // < > <= >= == !=149 UnaryOperator: "UnaryOperator",150 // ! - +151 // Keywords152 Set: "Set",153 If: "If",154 For: "For",155 In: "In",156 Is: "Is",157 NotIn: "NotIn",158 Else: "Else",159 EndIf: "EndIf",160 ElseIf: "ElseIf",161 EndFor: "EndFor",162 And: "And",163 Or: "Or",164 Not: "UnaryOperator"165});166var KEYWORDS = Object.freeze({167 set: TOKEN_TYPES.Set,168 for: TOKEN_TYPES.For,169 in: TOKEN_TYPES.In,170 is: TOKEN_TYPES.Is,171 if: TOKEN_TYPES.If,172 else: TOKEN_TYPES.Else,173 endif: TOKEN_TYPES.EndIf,174 elif: TOKEN_TYPES.ElseIf,175 endfor: TOKEN_TYPES.EndFor,176 and: TOKEN_TYPES.And,177 or: TOKEN_TYPES.Or,178 not: TOKEN_TYPES.Not,179 "not in": TOKEN_TYPES.NotIn,180 // Literals181 true: TOKEN_TYPES.BooleanLiteral,182 false: TOKEN_TYPES.BooleanLiteral183});184var Token = class {185 /**186 * Constructs a new Token.187 * @param {string} value The raw value as seen inside the source code.188 * @param {TokenType} type The type of token.189 */190 constructor(value, type) {191 this.value = value;192 this.type = type;193 }194};195function isWord(char) {196 return /\w/.test(char);197}198function isInteger(char) {199 return /[0-9]/.test(char);200}201var ORDERED_MAPPING_TABLE = [202 // Control sequences203 ["{%", TOKEN_TYPES.OpenStatement],204 ["%}", TOKEN_TYPES.CloseStatement],205 ["{{", TOKEN_TYPES.OpenExpression],206 ["}}", TOKEN_TYPES.CloseExpression],207 // Single character tokens208 ["(", TOKEN_TYPES.OpenParen],209 [")", TOKEN_TYPES.CloseParen],210 ["{", TOKEN_TYPES.OpenCurlyBracket],211 ["}", TOKEN_TYPES.CloseCurlyBracket],212 ["[", TOKEN_TYPES.OpenSquareBracket],213 ["]", TOKEN_TYPES.CloseSquareBracket],214 [",", TOKEN_TYPES.Comma],215 [".", TOKEN_TYPES.Dot],216 [":", TOKEN_TYPES.Colon],217 ["|", TOKEN_TYPES.Pipe],218 // Comparison operators219 ["<=", TOKEN_TYPES.ComparisonBinaryOperator],220 [">=", TOKEN_TYPES.ComparisonBinaryOperator],221 ["==", TOKEN_TYPES.ComparisonBinaryOperator],222 ["!=", TOKEN_TYPES.ComparisonBinaryOperator],223 ["<", TOKEN_TYPES.ComparisonBinaryOperator],224 [">", TOKEN_TYPES.ComparisonBinaryOperator],225 // Arithmetic operators226 ["+", TOKEN_TYPES.AdditiveBinaryOperator],227 ["-", TOKEN_TYPES.AdditiveBinaryOperator],228 ["*", TOKEN_TYPES.MultiplicativeBinaryOperator],229 ["/", TOKEN_TYPES.MultiplicativeBinaryOperator],230 ["%", TOKEN_TYPES.MultiplicativeBinaryOperator],231 // Assignment operator232 ["=", TOKEN_TYPES.Equals]233];234var ESCAPE_CHARACTERS = /* @__PURE__ */ new Map([235 ["n", "\n"],236 // New line237 ["t", " "],238 // Horizontal tab239 ["r", "\r"],240 // Carriage return241 ["b", "\b"],242 // Backspace243 ["f", "\f"],244 // Form feed245 ["v", "\v"],246 // Vertical tab247 ["'", "'"],248 // Single quote249 ['"', '"'],250 // Double quote251 ["\\", "\\"]252 // Backslash253]);254function preprocess(template, options = {}) {255 if (template.endsWith("\n")) {256 template = template.slice(0, -1);257 }258 template = template.replace(/{#.*?#}/gs, "{##}");259 if (options.lstrip_blocks) {260 template = template.replace(/^[ \t]*({[#%])/gm, "$1");261 }262 if (options.trim_blocks) {263 template = template.replace(/([#%]})\n/g, "$1");264 }265 return template.replace(/{##}/g, "").replace(/-%}\s*/g, "%}").replace(/\s*{%-/g, "{%").replace(/-}}\s*/g, "}}").replace(/\s*{{-/g, "{{");266}267function tokenize(source, options = {}) {268 const tokens = [];269 const src = preprocess(source, options);270 let cursorPosition = 0;271 const consumeWhile = (predicate) => {272 let str = "";273 while (predicate(src[cursorPosition])) {274 if (src[cursorPosition] === "\\") {275 ++cursorPosition;276 if (cursorPosition >= src.length)277 throw new SyntaxError("Unexpected end of input");278 const escaped = src[cursorPosition++];279 const unescaped = ESCAPE_CHARACTERS.get(escaped);280 if (unescaped === void 0) {281 throw new SyntaxError(`Unexpected escaped character: ${escaped}`);282 }283 str += unescaped;284 continue;285 }286 str += src[cursorPosition++];287 if (cursorPosition >= src.length)288 throw new SyntaxError("Unexpected end of input");289 }290 return str;291 };292 main:293 while (cursorPosition < src.length) {294 const lastTokenType = tokens.at(-1)?.type;295 if (lastTokenType === void 0 || lastTokenType === TOKEN_TYPES.CloseStatement || lastTokenType === TOKEN_TYPES.CloseExpression) {296 let text = "";297 while (cursorPosition < src.length && // Keep going until we hit the next Jinja statement or expression298 !(src[cursorPosition] === "{" && (src[cursorPosition + 1] === "%" || src[cursorPosition + 1] === "{"))) {299 text += src[cursorPosition++];300 }301 if (text.length > 0) {302 tokens.push(new Token(text, TOKEN_TYPES.Text));303 continue;304 }305 }306 consumeWhile((char2) => /\s/.test(char2));307 const char = src[cursorPosition];308 if (char === "-" || char === "+") {309 const lastTokenType2 = tokens.at(-1)?.type;310 if (lastTokenType2 === TOKEN_TYPES.Text || lastTokenType2 === void 0) {311 throw new SyntaxError(`Unexpected character: ${char}`);312 }313 switch (lastTokenType2) {314 case TOKEN_TYPES.Identifier:315 case TOKEN_TYPES.NumericLiteral:316 case TOKEN_TYPES.BooleanLiteral:317 case TOKEN_TYPES.StringLiteral:318 case TOKEN_TYPES.CloseParen:319 case TOKEN_TYPES.CloseSquareBracket:320 break;321 default: {322 ++cursorPosition;323 const num = consumeWhile(isInteger);324 tokens.push(325 new Token(`${char}${num}`, num.length > 0 ? TOKEN_TYPES.NumericLiteral : TOKEN_TYPES.UnaryOperator)326 );327 continue;328 }329 }330 }331 for (const [char2, token] of ORDERED_MAPPING_TABLE) {332 const slice2 = src.slice(cursorPosition, cursorPosition + char2.length);333 if (slice2 === char2) {334 tokens.push(new Token(char2, token));335 cursorPosition += char2.length;336 continue main;337 }338 }339 if (char === "'" || char === '"') {340 ++cursorPosition;341 const str = consumeWhile((c) => c !== char);342 tokens.push(new Token(str, TOKEN_TYPES.StringLiteral));343 ++cursorPosition;344 continue;345 }346 if (isInteger(char)) {347 const num = consumeWhile(isInteger);348 tokens.push(new Token(num, TOKEN_TYPES.NumericLiteral));349 continue;350 }351 if (isWord(char)) {352 const word = consumeWhile(isWord);353 const type = Object.hasOwn(KEYWORDS, word) ? KEYWORDS[word] : TOKEN_TYPES.Identifier;354 if (type === TOKEN_TYPES.In && tokens.at(-1)?.type === TOKEN_TYPES.Not) {355 tokens.pop();356 tokens.push(new Token("not in", TOKEN_TYPES.NotIn));357 } else {358 tokens.push(new Token(word, type));359 }360 continue;361 }362 throw new SyntaxError(`Unexpected character: ${char}`);363 }364 return tokens;365}366 367// src/ast.ts368var Statement = class {369 type = "Statement";370};371var Program = class extends Statement {372 constructor(body) {373 super();374 this.body = body;375 }376 type = "Program";377};378var If = class extends Statement {379 constructor(test, body, alternate) {380 super();381 this.test = test;382 this.body = body;383 this.alternate = alternate;384 }385 type = "If";386};387var For = class extends Statement {388 constructor(loopvar, iterable, body) {389 super();390 this.loopvar = loopvar;391 this.iterable = iterable;392 this.body = body;393 }394 type = "For";395};396var SetStatement = class extends Statement {397 constructor(assignee, value) {398 super();399 this.assignee = assignee;400 this.value = value;401 }402 type = "Set";403};404var Expression = class extends Statement {405 type = "Expression";406};407var MemberExpression = class extends Expression {408 constructor(object, property, computed) {409 super();410 this.object = object;411 this.property = property;412 this.computed = computed;413 }414 type = "MemberExpression";415};416var CallExpression = class extends Expression {417 constructor(callee, args) {418 super();419 this.callee = callee;420 this.args = args;421 }422 type = "CallExpression";423};424var Identifier = class extends Expression {425 /**426 * @param {string} value The name of the identifier427 */428 constructor(value) {429 super();430 this.value = value;431 }432 type = "Identifier";433};434var Literal = class extends Expression {435 constructor(value) {436 super();437 this.value = value;438 }439 type = "Literal";440};441var NumericLiteral = class extends Literal {442 type = "NumericLiteral";443};444var StringLiteral = class extends Literal {445 type = "StringLiteral";446};447var BooleanLiteral = class extends Literal {448 type = "BooleanLiteral";449};450var ArrayLiteral = class extends Literal {451 type = "ArrayLiteral";452};453var TupleLiteral = class extends Literal {454 type = "TupleLiteral";455};456var ObjectLiteral = class extends Literal {457 type = "ObjectLiteral";458};459var BinaryExpression = class extends Expression {460 constructor(operator, left, right) {461 super();462 this.operator = operator;463 this.left = left;464 this.right = right;465 }466 type = "BinaryExpression";467};468var FilterExpression = class extends Expression {469 constructor(operand, filter) {470 super();471 this.operand = operand;472 this.filter = filter;473 }474 type = "FilterExpression";475};476var TestExpression = class extends Expression {477 constructor(operand, negate, test) {478 super();479 this.operand = operand;480 this.negate = negate;481 this.test = test;482 }483 type = "TestExpression";484};485var UnaryExpression = class extends Expression {486 constructor(operator, argument) {487 super();488 this.operator = operator;489 this.argument = argument;490 }491 type = "UnaryExpression";492};493var SliceExpression = class extends Expression {494 constructor(start = void 0, stop = void 0, step = void 0) {495 super();496 this.start = start;497 this.stop = stop;498 this.step = step;499 }500 type = "SliceExpression";501};502var KeywordArgumentExpression = class extends Expression {503 constructor(key, value) {504 super();505 this.key = key;506 this.value = value;507 }508 type = "KeywordArgumentExpression";509};510 511// src/parser.ts512function parse(tokens) {513 const program = new Program([]);514 let current = 0;515 function expect(type, error) {516 const prev = tokens[current++];517 if (!prev || prev.type !== type) {518 throw new Error(`Parser Error: ${error}. ${prev.type} !== ${type}.`);519 }520 return prev;521 }522 function parseAny() {523 switch (tokens[current].type) {524 case TOKEN_TYPES.Text:525 return parseText();526 case TOKEN_TYPES.OpenStatement:527 return parseJinjaStatement();528 case TOKEN_TYPES.OpenExpression:529 return parseJinjaExpression();530 default:531 throw new SyntaxError(`Unexpected token type: ${tokens[current].type}`);532 }533 }534 function not(...types) {535 return current + types.length <= tokens.length && types.some((type, i) => type !== tokens[current + i].type);536 }537 function is(...types) {538 return current + types.length <= tokens.length && types.every((type, i) => type === tokens[current + i].type);539 }540 function parseText() {541 return new StringLiteral(expect(TOKEN_TYPES.Text, "Expected text token").value);542 }543 function parseJinjaStatement() {544 expect(TOKEN_TYPES.OpenStatement, "Expected opening statement token");545 let result;546 switch (tokens[current].type) {547 case TOKEN_TYPES.Set:548 ++current;549 result = parseSetStatement();550 expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");551 break;552 case TOKEN_TYPES.If:553 ++current;554 result = parseIfStatement();555 expect(TOKEN_TYPES.OpenStatement, "Expected {% token");556 expect(TOKEN_TYPES.EndIf, "Expected endif token");557 expect(TOKEN_TYPES.CloseStatement, "Expected %} token");558 break;559 case TOKEN_TYPES.For:560 ++current;561 result = parseForStatement();562 expect(TOKEN_TYPES.OpenStatement, "Expected {% token");563 expect(TOKEN_TYPES.EndFor, "Expected endfor token");564 expect(TOKEN_TYPES.CloseStatement, "Expected %} token");565 break;566 default:567 throw new SyntaxError(`Unknown statement type: ${tokens[current].type}`);568 }569 return result;570 }571 function parseJinjaExpression() {572 expect(TOKEN_TYPES.OpenExpression, "Expected opening expression token");573 const result = parseExpression();574 expect(TOKEN_TYPES.CloseExpression, "Expected closing expression token");575 return result;576 }577 function parseSetStatement() {578 const left = parseExpression();579 if (is(TOKEN_TYPES.Equals)) {580 ++current;581 const value = parseSetStatement();582 return new SetStatement(left, value);583 }584 return left;585 }586 function parseIfStatement() {587 const test = parseExpression();588 expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");589 const body = [];590 const alternate = [];591 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))) {592 body.push(parseAny());593 }594 if (tokens[current]?.type === TOKEN_TYPES.OpenStatement && tokens[current + 1]?.type !== TOKEN_TYPES.EndIf) {595 ++current;596 if (is(TOKEN_TYPES.ElseIf)) {597 expect(TOKEN_TYPES.ElseIf, "Expected elseif token");598 alternate.push(parseIfStatement());599 } else {600 expect(TOKEN_TYPES.Else, "Expected else token");601 expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");602 while (!(tokens[current]?.type === TOKEN_TYPES.OpenStatement && tokens[current + 1]?.type === TOKEN_TYPES.EndIf)) {603 alternate.push(parseAny());604 }605 }606 }607 return new If(test, body, alternate);608 }609 function parseExpressionSequence(primary = false) {610 const fn = primary ? parsePrimaryExpression : parseExpression;611 const expressions = [fn()];612 const isTuple = is(TOKEN_TYPES.Comma);613 while (isTuple) {614 ++current;615 expressions.push(fn());616 if (!is(TOKEN_TYPES.Comma)) {617 break;618 }619 }620 return isTuple ? new TupleLiteral(expressions) : expressions[0];621 }622 function parseForStatement() {623 const loopVariable = parseExpressionSequence(true);624 if (!(loopVariable instanceof Identifier || loopVariable instanceof TupleLiteral)) {625 throw new SyntaxError(`Expected identifier/tuple for the loop variable, got ${loopVariable.type} instead`);626 }627 expect(TOKEN_TYPES.In, "Expected `in` keyword following loop variable");628 const iterable = parseExpression();629 expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");630 const body = [];631 while (not(TOKEN_TYPES.OpenStatement, TOKEN_TYPES.EndFor)) {632 body.push(parseAny());633 }634 return new For(loopVariable, iterable, body);635 }636 function parseExpression() {637 return parseTernaryExpression();638 }639 function parseTernaryExpression() {640 const a = parseLogicalOrExpression();641 if (is(TOKEN_TYPES.If)) {642 ++current;643 const predicate = parseLogicalOrExpression();644 expect(TOKEN_TYPES.Else, "Expected else token");645 const b = parseLogicalOrExpression();646 return new If(predicate, [a], [b]);647 }648 return a;649 }650 function parseLogicalOrExpression() {651 let left = parseLogicalAndExpression();652 while (is(TOKEN_TYPES.Or)) {653 const operator = tokens[current];654 ++current;655 const right = parseLogicalAndExpression();656 left = new BinaryExpression(operator, left, right);657 }658 return left;659 }660 function parseLogicalAndExpression() {661 let left = parseLogicalNegationExpression();662 while (is(TOKEN_TYPES.And)) {663 const operator = tokens[current];664 ++current;665 const right = parseLogicalNegationExpression();666 left = new BinaryExpression(operator, left, right);667 }668 return left;669 }670 function parseLogicalNegationExpression() {671 let right;672 while (is(TOKEN_TYPES.Not)) {673 const operator = tokens[current];674 ++current;675 const arg = parseLogicalNegationExpression();676 right = new UnaryExpression(operator, arg);677 }678 return right ?? parseComparisonExpression();679 }680 function parseComparisonExpression() {681 let left = parseAdditiveExpression();682 while (is(TOKEN_TYPES.ComparisonBinaryOperator) || is(TOKEN_TYPES.In) || is(TOKEN_TYPES.NotIn)) {683 const operator = tokens[current];684 ++current;685 const right = parseAdditiveExpression();686 left = new BinaryExpression(operator, left, right);687 }688 return left;689 }690 function parseAdditiveExpression() {691 let left = parseMultiplicativeExpression();692 while (is(TOKEN_TYPES.AdditiveBinaryOperator)) {693 const operator = tokens[current];694 ++current;695 const right = parseMultiplicativeExpression();696 left = new BinaryExpression(operator, left, right);697 }698 return left;699 }700 function parseCallMemberExpression() {701 const member = parseMemberExpression();702 if (is(TOKEN_TYPES.OpenParen)) {703 return parseCallExpression(member);704 }705 return member;706 }707 function parseCallExpression(callee) {708 let callExpression = new CallExpression(callee, parseArgs());709 if (is(TOKEN_TYPES.OpenParen)) {710 callExpression = parseCallExpression(callExpression);711 }712 return callExpression;713 }714 function parseArgs() {715 expect(TOKEN_TYPES.OpenParen, "Expected opening parenthesis for arguments list");716 const args = parseArgumentsList();717 expect(TOKEN_TYPES.CloseParen, "Expected closing parenthesis for arguments list");718 return args;719 }720 function parseArgumentsList() {721 const args = [];722 while (!is(TOKEN_TYPES.CloseParen)) {723 let argument = parseExpression();724 if (is(TOKEN_TYPES.Equals)) {725 ++current;726 if (!(argument instanceof Identifier)) {727 throw new SyntaxError(`Expected identifier for keyword argument`);728 }729 const value = parseExpression();730 argument = new KeywordArgumentExpression(argument, value);731 }732 args.push(argument);733 if (is(TOKEN_TYPES.Comma)) {734 ++current;735 }736 }737 return args;738 }739 function parseMemberExpressionArgumentsList() {740 const slices = [];741 let isSlice = false;742 while (!is(TOKEN_TYPES.CloseSquareBracket)) {743 if (is(TOKEN_TYPES.Colon)) {744 slices.push(void 0);745 ++current;746 isSlice = true;747 } else {748 slices.push(parseExpression());749 if (is(TOKEN_TYPES.Colon)) {750 ++current;751 isSlice = true;752 }753 }754 }755 if (slices.length === 0) {756 throw new SyntaxError(`Expected at least one argument for member/slice expression`);757 }758 if (isSlice) {759 if (slices.length > 3) {760 throw new SyntaxError(`Expected 0-3 arguments for slice expression`);761 }762 return new SliceExpression(...slices);763 }764 return slices[0];765 }766 function parseMemberExpression() {767 let object = parsePrimaryExpression();768 while (is(TOKEN_TYPES.Dot) || is(TOKEN_TYPES.OpenSquareBracket)) {769 const operator = tokens[current];770 ++current;771 let property;772 const computed = operator.type !== TOKEN_TYPES.Dot;773 if (computed) {774 property = parseMemberExpressionArgumentsList();775 expect(TOKEN_TYPES.CloseSquareBracket, "Expected closing square bracket");776 } else {777 property = parsePrimaryExpression();778 if (property.type !== "Identifier") {779 throw new SyntaxError(`Expected identifier following dot operator`);780 }781 }782 object = new MemberExpression(object, property, computed);783 }784 return object;785 }786 function parseMultiplicativeExpression() {787 let left = parseTestExpression();788 while (is(TOKEN_TYPES.MultiplicativeBinaryOperator)) {789 const operator = tokens[current];790 ++current;791 const right = parseTestExpression();792 left = new BinaryExpression(operator, left, right);793 }794 return left;795 }796 function parseTestExpression() {797 let operand = parseFilterExpression();798 while (is(TOKEN_TYPES.Is)) {799 ++current;800 const negate = is(TOKEN_TYPES.Not);801 if (negate) {802 ++current;803 }804 let filter = parsePrimaryExpression();805 if (filter instanceof BooleanLiteral) {806 filter = new Identifier(filter.value.toString());807 }808 if (!(filter instanceof Identifier)) {809 throw new SyntaxError(`Expected identifier for the test`);810 }811 operand = new TestExpression(operand, negate, filter);812 }813 return operand;814 }815 function parseFilterExpression() {816 let operand = parseCallMemberExpression();817 while (is(TOKEN_TYPES.Pipe)) {818 ++current;819 let filter = parsePrimaryExpression();820 if (!(filter instanceof Identifier)) {821 throw new SyntaxError(`Expected identifier for the filter`);822 }823 if (is(TOKEN_TYPES.OpenParen)) {824 filter = parseCallExpression(filter);825 }826 operand = new FilterExpression(operand, filter);827 }828 return operand;829 }830 function parsePrimaryExpression() {831 const token = tokens[current];832 switch (token.type) {833 case TOKEN_TYPES.NumericLiteral:834 ++current;835 return new NumericLiteral(Number(token.value));836 case TOKEN_TYPES.StringLiteral:837 ++current;838 return new StringLiteral(token.value);839 case TOKEN_TYPES.BooleanLiteral:840 ++current;841 return new BooleanLiteral(token.value === "true");842 case TOKEN_TYPES.Identifier:843 ++current;844 return new Identifier(token.value);845 case TOKEN_TYPES.OpenParen: {846 ++current;847 const expression = parseExpressionSequence();848 if (tokens[current].type !== TOKEN_TYPES.CloseParen) {849 throw new SyntaxError(`Expected closing parenthesis, got ${tokens[current].type} instead`);850 }851 ++current;852 return expression;853 }854 case TOKEN_TYPES.OpenSquareBracket: {855 ++current;856 const values = [];857 while (!is(TOKEN_TYPES.CloseSquareBracket)) {858 values.push(parseExpression());859 if (is(TOKEN_TYPES.Comma)) {860 ++current;861 }862 }863 ++current;864 return new ArrayLiteral(values);865 }866 case TOKEN_TYPES.OpenCurlyBracket: {867 ++current;868 const values = /* @__PURE__ */ new Map();869 while (!is(TOKEN_TYPES.CloseCurlyBracket)) {870 const key = parseExpression();871 expect(TOKEN_TYPES.Colon, "Expected colon between key and value in object literal");872 const value = parseExpression();873 values.set(key, value);874 if (is(TOKEN_TYPES.Comma)) {875 ++current;876 }877 }878 ++current;879 return new ObjectLiteral(values);880 }881 default:882 throw new SyntaxError(`Unexpected token: ${token.type}`);883 }884 }885 while (current < tokens.length) {886 program.body.push(parseAny());887 }888 return program;889}890 891// src/utils.ts892function range(start, stop, step = 1) {893 if (stop === void 0) {894 stop = start;895 start = 0;896 }897 const result = [];898 for (let i = start; i < stop; i += step) {899 result.push(i);900 }901 return result;902}903function slice(array, start, stop, step = 1) {904 const direction = Math.sign(step);905 if (direction >= 0) {906 start = (start ??= 0) < 0 ? Math.max(array.length + start, 0) : Math.min(start, array.length);907 stop = (stop ??= array.length) < 0 ? Math.max(array.length + stop, 0) : Math.min(stop, array.length);908 } else {909 start = (start ??= array.length - 1) < 0 ? Math.max(array.length + start, -1) : Math.min(start, array.length - 1);910 stop = (stop ??= -1) < -1 ? Math.max(array.length + stop, -1) : Math.min(stop, array.length - 1);911 }912 const result = [];913 for (let i = start; direction * i < direction * stop; i += step) {914 result.push(array[i]);915 }916 return result;917}918function titleCase(value) {919 return value.replace(/\b\w/g, (c) => c.toUpperCase());920}921 922// src/runtime.ts923var RuntimeValue = class {924 type = "RuntimeValue";925 value;926 /**927 * A collection of built-in functions for this type.928 */929 builtins = /* @__PURE__ */ new Map();930 /**931 * Creates a new RuntimeValue.932 */933 constructor(value = void 0) {934 this.value = value;935 }936 /**937 * Determines truthiness or falsiness of the runtime value.938 * This function should be overridden by subclasses if it has custom truthiness criteria.939 * @returns {BooleanValue} BooleanValue(true) if the value is truthy, BooleanValue(false) otherwise.940 */941 __bool__() {942 return new BooleanValue(!!this.value);943 }944};945var NumericValue = class extends RuntimeValue {946 type = "NumericValue";947};948var StringValue = class extends RuntimeValue {949 type = "StringValue";950 builtins = /* @__PURE__ */ new Map([951 [952 "upper",953 new FunctionValue(() => {954 return new StringValue(this.value.toUpperCase());955 })956 ],957 [958 "lower",959 new FunctionValue(() => {960 return new StringValue(this.value.toLowerCase());961 })962 ],963 [964 "strip",965 new FunctionValue(() => {966 return new StringValue(this.value.trim());967 })968 ],969 [970 "title",971 new FunctionValue(() => {972 return new StringValue(titleCase(this.value));973 })974 ],975 ["length", new NumericValue(this.value.length)]976 ]);977};978var BooleanValue = class extends RuntimeValue {979 type = "BooleanValue";980};981var ObjectValue = class extends RuntimeValue {982 type = "ObjectValue";983 /**984 * NOTE: necessary to override since all JavaScript arrays are considered truthy,985 * while only non-empty Python arrays are consider truthy.986 *987 * e.g.,988 * - JavaScript: {} && 5 -> 5989 * - Python: {} and 5 -> {}990 */991 __bool__() {992 return new BooleanValue(this.value.size > 0);993 }994 builtins = /* @__PURE__ */ new Map([995 [996 "get",997 new FunctionValue(([key, defaultValue]) => {998 if (!(key instanceof StringValue)) {999 throw new Error(`Object key must be a string: got ${key.type}`);1000 }1001 return this.value.get(key.value) ?? defaultValue ?? new NullValue();1002 })1003 ],1004 [1005 "items",1006 new FunctionValue(() => {1007 return new ArrayValue(1008 Array.from(this.value.entries()).map(([key, value]) => new ArrayValue([new StringValue(key), value]))1009 );1010 })1011 ]1012 ]);1013};1014var ArrayValue = class extends RuntimeValue {1015 type = "ArrayValue";1016 builtins = /* @__PURE__ */ new Map([["length", new NumericValue(this.value.length)]]);1017 /**1018 * NOTE: necessary to override since all JavaScript arrays are considered truthy,1019 * while only non-empty Python arrays are consider truthy.1020 *1021 * e.g.,1022 * - JavaScript: [] && 5 -> 51023 * - Python: [] and 5 -> []1024 */1025 __bool__() {1026 return new BooleanValue(this.value.length > 0);1027 }1028};1029var TupleValue = class extends ArrayValue {1030 type = "TupleValue";1031};1032var FunctionValue = class extends RuntimeValue {1033 type = "FunctionValue";1034};1035var NullValue = class extends RuntimeValue {1036 type = "NullValue";1037};1038var UndefinedValue = class extends RuntimeValue {1039 type = "UndefinedValue";1040};1041var Environment = class {1042 constructor(parent) {1043 this.parent = parent;1044 }1045 /**1046 * The variables declared in this environment.1047 */1048 variables = /* @__PURE__ */ new Map([1049 [1050 "namespace",1051 new FunctionValue((args) => {1052 if (args.length === 0) {1053 return new ObjectValue(/* @__PURE__ */ new Map());1054 }1055 if (args.length !== 1 || !(args[0] instanceof ObjectValue)) {1056 throw new Error("`namespace` expects either zero arguments or a single object argument");1057 }1058 return args[0];1059 })1060 ]1061 ]);1062 /**1063 * The tests available in this environment.1064 */1065 tests = /* @__PURE__ */ new Map([1066 ["boolean", (operand) => operand.type === "BooleanValue"],1067 ["callable", (operand) => operand instanceof FunctionValue],1068 [1069 "odd",1070 (operand) => {1071 if (operand.type !== "NumericValue") {1072 throw new Error(`Cannot apply test "odd" to type: ${operand.type}`);1073 }1074 return operand.value % 2 !== 0;1075 }1076 ],1077 [1078 "even",1079 (operand) => {1080 if (operand.type !== "NumericValue") {1081 throw new Error(`Cannot apply test "even" to type: ${operand.type}`);1082 }1083 return operand.value % 2 === 0;1084 }1085 ],1086 ["false", (operand) => operand.type === "BooleanValue" && !operand.value],1087 ["true", (operand) => operand.type === "BooleanValue" && operand.value],1088 ["number", (operand) => operand.type === "NumericValue"],1089 ["integer", (operand) => operand.type === "NumericValue" && Number.isInteger(operand.value)],1090 ["iterable", (operand) => operand instanceof ArrayValue || operand instanceof StringValue],1091 [1092 "lower",1093 (operand) => {1094 const str = operand.value;1095 return operand.type === "StringValue" && str === str.toLowerCase();1096 }1097 ],1098 [1099 "upper",1100 (operand) => {1101 const str = operand.value;1102 return operand.type === "StringValue" && str === str.toUpperCase();1103 }1104 ],1105 ["none", (operand) => operand.type === "NullValue"],1106 ["defined", (operand) => operand.type !== "UndefinedValue"],1107 ["undefined", (operand) => operand.type === "UndefinedValue"],1108 ["equalto", (a, b) => a.value === b.value]1109 ]);1110 /**1111 * Set the value of a variable in the current environment.1112 */1113 set(name, value) {1114 return this.declareVariable(name, convertToRuntimeValues(value));1115 }1116 declareVariable(name, value) {1117 if (this.variables.has(name)) {1118 throw new SyntaxError(`Variable already declared: ${name}`);1119 }1120 this.variables.set(name, value);1121 return value;1122 }1123 // private assignVariable(name: string, value: AnyRuntimeValue): AnyRuntimeValue {1124 // const env = this.resolve(name);1125 // env.variables.set(name, value);1126 // return value;1127 // }1128 /**1129 * Set variable in the current scope.1130 * See https://jinja.palletsprojects.com/en/3.0.x/templates/#assignments for more information.1131 */1132 setVariable(name, value) {1133 this.variables.set(name, value);1134 return value;1135 }1136 /**1137 * Resolve the environment in which the variable is declared.1138 * @param {string} name The name of the variable.1139 * @returns {Environment} The environment in which the variable is declared.1140 */1141 resolve(name) {1142 if (this.variables.has(name)) {1143 return this;1144 }1145 if (this.parent) {1146 return this.parent.resolve(name);1147 }1148 throw new Error(`Unknown variable: ${name}`);1149 }1150 lookupVariable(name) {1151 try {1152 return this.resolve(name).variables.get(name) ?? new UndefinedValue();1153 } catch {1154 return new UndefinedValue();1155 }1156 }1157};1158var Interpreter = class {1159 global;1160 constructor(env) {1161 this.global = env ?? new Environment();1162 }1163 /**1164 * Run the program.1165 */1166 run(program) {1167 return this.evaluate(program, this.global);1168 }1169 /**1170 * Evaluates expressions following the binary operation type.1171 */1172 evaluateBinaryExpression(node, environment) {1173 const left = this.evaluate(node.left, environment);1174 switch (node.operator.value) {1175 case "and":1176 return left.__bool__().value ? this.evaluate(node.right, environment) : left;1177 case "or":1178 return left.__bool__().value ? left : this.evaluate(node.right, environment);1179 }1180 const right = this.evaluate(node.right, environment);1181 switch (node.operator.value) {1182 case "==":1183 return new BooleanValue(left.value == right.value);1184 case "!=":1185 return new BooleanValue(left.value != right.value);1186 }1187 if (left instanceof UndefinedValue || right instanceof UndefinedValue) {1188 throw new Error("Cannot perform operation on undefined values");1189 } else if (left instanceof NullValue || right instanceof NullValue) {1190 throw new Error("Cannot perform operation on null values");1191 } else if (left instanceof NumericValue && right instanceof NumericValue) {1192 switch (node.operator.value) {1193 case "+":1194 return new NumericValue(left.value + right.value);1195 case "-":1196 return new NumericValue(left.value - right.value);1197 case "*":1198 return new NumericValue(left.value * right.value);1199 case "/":1200 return new NumericValue(left.value / right.value);