[ExpressionLanguage] Fixed collisions of character operators with object properties
This commit is contained in:
parent
648d488bb2
commit
4b83ae7547
@ -73,7 +73,7 @@ class Lexer
|
||||
// strings
|
||||
$tokens[] = new Token(Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)), $cursor + 1);
|
||||
$cursor += \strlen($match[0]);
|
||||
} elseif (preg_match('/not in(?=[\s(])|\!\=\=|not(?=[\s(])|and(?=[\s(])|\=\=\=|\>\=|or(?=[\s(])|\<\=|\*\*|\.\.|in(?=[\s(])|&&|\|\||matches|\=\=|\!\=|\*|~|%|\/|\>|\||\!|\^|&|\+|\<|\-/A', $expression, $match, 0, $cursor)) {
|
||||
} elseif (preg_match('/(?<=^|[\s(])not in(?=[\s(])|\!\=\=|(?<=^|[\s(])not(?=[\s(])|(?<=^|[\s(])and(?=[\s(])|\=\=\=|\>\=|(?<=^|[\s(])or(?=[\s(])|\<\=|\*\*|\.\.|(?<=^|[\s(])in(?=[\s(])|&&|\|\||(?<=^|[\s(])matches|\=\=|\!\=|\*|~|%|\/|\>|\||\!|\^|&|\+|\<|\-/A', $expression, $match, 0, $cursor)) {
|
||||
// operators
|
||||
$tokens[] = new Token(Token::OPERATOR_TYPE, $match[0], $cursor + 1);
|
||||
$cursor += \strlen($match[0]);
|
||||
|
@ -15,9 +15,13 @@ arsort($operators);
|
||||
|
||||
$regex = [];
|
||||
foreach ($operators as $operator => $length) {
|
||||
// an operator that ends with a character must be followed by
|
||||
// a whitespace or a parenthesis
|
||||
$regex[] = preg_quote($operator, '/').(ctype_alpha($operator[$length - 1]) ? '(?=[\s(])' : '');
|
||||
// Collisions of character operators:
|
||||
// - an operator that begins with a character must have a space or a parenthesis before or starting at the beginning of a string
|
||||
// - an operator that ends with a character must be followed by a whitespace or a parenthesis
|
||||
$regex[] =
|
||||
(ctype_alpha($operator[0]) ? '(?<=^|[\s(])' : '')
|
||||
.preg_quote($operator, '/')
|
||||
.(ctype_alpha($operator[$length - 1]) ? '(?=[\s(])' : '');
|
||||
}
|
||||
|
||||
echo '/'.implode('|', $regex).'/A';
|
||||
|
@ -233,6 +233,17 @@ class ExpressionLanguageTest extends TestCase
|
||||
$expressionLanguage->compile($expression, ['B' => 'b', 'a']);
|
||||
}
|
||||
|
||||
public function testOperatorCollisions()
|
||||
{
|
||||
$expressionLanguage = new ExpressionLanguage();
|
||||
$expression = 'foo.not in [bar]';
|
||||
$compiled = $expressionLanguage->compile($expression, ['foo', 'bar']);
|
||||
$this->assertSame('in_array($foo->not, [0 => $bar])', $compiled);
|
||||
|
||||
$result = $expressionLanguage->evaluate($expression, ['foo' => (object) ['not' => 'test'], 'bar' => 'test']);
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getRegisterCallbacks
|
||||
*/
|
||||
|
@ -112,6 +112,18 @@ class LexerTest extends TestCase
|
||||
[new Token('string', '#foo', 1)],
|
||||
'"#foo"',
|
||||
],
|
||||
[
|
||||
[
|
||||
new Token('name', 'foo', 1),
|
||||
new Token('punctuation', '.', 4),
|
||||
new Token('name', 'not', 5),
|
||||
new Token('operator', 'in', 9),
|
||||
new Token('punctuation', '[', 12),
|
||||
new Token('name', 'bar', 13),
|
||||
new Token('punctuation', ']', 16),
|
||||
],
|
||||
'foo.not in [bar]',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,9 @@ class ParserTest extends TestCase
|
||||
$arguments->addElement(new Node\ConstantNode(2));
|
||||
$arguments->addElement(new Node\ConstantNode(true));
|
||||
|
||||
$arrayNode = new Node\ArrayNode();
|
||||
$arrayNode->addElement(new Node\NameNode('bar'));
|
||||
|
||||
return [
|
||||
[
|
||||
new Node\NameNode('a'),
|
||||
@ -151,6 +154,36 @@ class ParserTest extends TestCase
|
||||
'bar',
|
||||
['foo' => 'bar'],
|
||||
],
|
||||
|
||||
// Operators collisions
|
||||
[
|
||||
new Node\BinaryNode(
|
||||
'in',
|
||||
new Node\GetAttrNode(
|
||||
new Node\NameNode('foo'),
|
||||
new Node\ConstantNode('not', true),
|
||||
new Node\ArgumentsNode(),
|
||||
Node\GetAttrNode::PROPERTY_CALL
|
||||
),
|
||||
$arrayNode
|
||||
),
|
||||
'foo.not in [bar]',
|
||||
['foo', 'bar'],
|
||||
],
|
||||
[
|
||||
new Node\BinaryNode(
|
||||
'or',
|
||||
new Node\UnaryNode('not', new Node\NameNode('foo')),
|
||||
new Node\GetAttrNode(
|
||||
new Node\NameNode('foo'),
|
||||
new Node\ConstantNode('not', true),
|
||||
new Node\ArgumentsNode(),
|
||||
Node\GetAttrNode::PROPERTY_CALL
|
||||
)
|
||||
),
|
||||
'not foo or foo.not',
|
||||
['foo'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user