in packages/jinja/src/parser.ts [102:197]
function parseJinjaStatement(): Statement {
// Consume {% token
expect(TOKEN_TYPES.OpenStatement, "Expected opening statement token");
// next token must be Identifier whose .value tells us which statement
if (tokens[current].type !== TOKEN_TYPES.Identifier) {
throw new SyntaxError(`Unknown statement, got ${tokens[current].type}`);
}
const name = tokens[current].value;
let result: Statement;
switch (name) {
case "set":
++current;
result = parseSetStatement();
break;
case "if":
++current;
result = parseIfStatement();
// expect {% endif %}
expect(TOKEN_TYPES.OpenStatement, "Expected {% token");
expectIdentifier("endif");
expect(TOKEN_TYPES.CloseStatement, "Expected %} token");
break;
case "macro":
++current;
result = parseMacroStatement();
// expect {% endmacro %}
expect(TOKEN_TYPES.OpenStatement, "Expected {% token");
expectIdentifier("endmacro");
expect(TOKEN_TYPES.CloseStatement, "Expected %} token");
break;
case "for":
++current;
result = parseForStatement();
// expect {% endfor %}
expect(TOKEN_TYPES.OpenStatement, "Expected {% token");
expectIdentifier("endfor");
expect(TOKEN_TYPES.CloseStatement, "Expected %} token");
break;
case "call": {
++current; // consume 'call'
let callerArgs: Statement[] | null = null;
if (is(TOKEN_TYPES.OpenParen)) {
// Optional caller arguments, e.g. {% call(user) dump_users(...) %}
callerArgs = parseArgs();
}
const callee = parsePrimaryExpression();
if (callee.type !== "Identifier") {
throw new SyntaxError(`Expected identifier following call statement`);
}
const callArgs = parseArgs();
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
const body: Statement[] = [];
while (!isStatement("endcall")) {
body.push(parseAny());
}
expect(TOKEN_TYPES.OpenStatement, "Expected '{%'");
expectIdentifier("endcall");
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
const callExpr = new CallExpression(callee, callArgs);
result = new CallStatement(callExpr, callerArgs, body);
break;
}
case "break":
++current;
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
result = new Break();
break;
case "continue":
++current;
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
result = new Continue();
break;
case "filter": {
++current; // consume 'filter'
let filterNode = parsePrimaryExpression();
if (filterNode instanceof Identifier && is(TOKEN_TYPES.OpenParen)) {
filterNode = parseCallExpression(filterNode);
}
expect(TOKEN_TYPES.CloseStatement, "Expected closing statement token");
const filterBody: Statement[] = [];
while (!isStatement("endfilter")) {
filterBody.push(parseAny());
}
expect(TOKEN_TYPES.OpenStatement, "Expected '{%'");
expectIdentifier("endfilter");
expect(TOKEN_TYPES.CloseStatement, "Expected '%}'");
result = new FilterStatement(filterNode as Identifier | CallExpression, filterBody);
break;
}
default:
throw new SyntaxError(`Unknown statement type: ${name}`);
}
return result;
}