mirror of
https://gitlab.com/nightlycommit/twing.git
synced 2025-01-18 08:46:50 +02:00
Merge branch 'issue-602' into 'main'
Resolve issue #602 - Unexpected token "operator" of value "and" ("end of statement block" expected) Closes #602 See merge request nightlycommit/twing!597
This commit is contained in:
commit
e1a9315c7d
@ -337,11 +337,11 @@ export const createParser = (
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (type === "block_reference" || type === "print" || type === "text") {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// here, nested means "being at the root level of a child template"
|
||||
// we need to discard the wrapping node for the "body" node
|
||||
nested = nested || (type !== "wrapper");
|
||||
@ -653,7 +653,24 @@ export const createParser = (
|
||||
return Object.keys(traits).length > 0
|
||||
};
|
||||
|
||||
const isBinary = (token: Token): TwingOperator | null => {
|
||||
const isBinary = (token: Token): {
|
||||
associativity: TwingOperator["associativity"];
|
||||
expressionFactory: TwingOperator["expressionFactory"];
|
||||
name: TwingOperator["name"];
|
||||
precedence: TwingOperator["precedence"];
|
||||
} | {
|
||||
expressionFactory: null;
|
||||
name: "is" | "is not";
|
||||
precedence: TwingOperator["precedence"];
|
||||
} | null => {
|
||||
if (token.value === "is" || token.value === "is not") {
|
||||
return {
|
||||
expressionFactory: null,
|
||||
name: token.value,
|
||||
precedence: 100
|
||||
};
|
||||
}
|
||||
|
||||
return (token.test("OPERATOR") && binaryOperatorsRegister.get(token.value)) || null;
|
||||
};
|
||||
|
||||
@ -1020,30 +1037,29 @@ export const createParser = (
|
||||
|
||||
let expression = getPrimary(stream);
|
||||
let token = stream.current;
|
||||
let operator: TwingOperator | null = null;
|
||||
let operator: ReturnType<typeof isBinary> = null;
|
||||
|
||||
if ((token.value === "is not") || (token.value === "is")) {
|
||||
while (((operator = isBinary(token)) !== null && operator.precedence >= precedence)) {
|
||||
stream.next();
|
||||
|
||||
if (token.value === "is not") {
|
||||
expression = parseNotTestExpression(stream, expression);
|
||||
if (operator.expressionFactory === null) {
|
||||
expression = parseTestExpression(stream, expression);
|
||||
|
||||
if (operator.name === "is not") {
|
||||
const {line, column} = stream.current;
|
||||
|
||||
expression = createNotNode(expression, line, column);
|
||||
}
|
||||
}
|
||||
else {
|
||||
expression = parseTestExpression(stream, expression);
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (((operator = isBinary(token)) !== null) && operator.precedence >= precedence) {
|
||||
stream.next();
|
||||
|
||||
const {expressionFactory} = operator;
|
||||
|
||||
const operand = parseExpression(stream, operator.associativity === "LEFT" ? operator.precedence + 1 : operator.precedence, true);
|
||||
|
||||
expression = expressionFactory([expression, operand], token.line, token.column);
|
||||
|
||||
token = stream.current;
|
||||
}
|
||||
|
||||
token = stream.current;
|
||||
}
|
||||
|
||||
if (precedence === 0) {
|
||||
@ -1233,12 +1249,6 @@ export const createParser = (
|
||||
return createWrapperNode(targets, line, column);
|
||||
};
|
||||
|
||||
const parseNotTestExpression = (stream: TwingTokenStream, node: TwingBaseExpressionNode): TwingBaseExpressionNode => {
|
||||
const {line, column} = stream.current;
|
||||
|
||||
return createNotNode(parseTestExpression(stream, node), line, column);
|
||||
};
|
||||
|
||||
const parsePostfixExpression = (stream: TwingTokenStream, node: TwingBaseExpressionNode, prefixToken: Token): TwingBaseExpressionNode => {
|
||||
while (true) {
|
||||
let token = stream.current;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import "./basic";
|
||||
import "./expression";
|
||||
import "./expression_as_boolean";
|
||||
import "./on-hash";
|
||||
import "./on-hash";
|
||||
import "./with-test-as-binary-expression-operand";
|
||||
|
@ -0,0 +1,16 @@
|
||||
import {runTest} from "../../TestBase";
|
||||
|
||||
runTest({
|
||||
description: '"if" tag with a test as binary expression operand',
|
||||
templates: {
|
||||
"index.twig": `
|
||||
{% if a is defined and b %}true{% else %}false{% endif %}
|
||||
`
|
||||
},
|
||||
expectation: `
|
||||
true`,
|
||||
context: Promise.resolve({
|
||||
a: true,
|
||||
b: true
|
||||
})
|
||||
});
|
Loading…
Reference in New Issue
Block a user