Upgrade 1-11.38

This commit is contained in:
xesmyd
2026-03-30 14:10:30 +02:00
parent f2a7e6d1fc
commit ac648ef29d
24665 changed files with 69682 additions and 2205004 deletions
@@ -1,3 +0,0 @@
vendor/
composer.lock
phpunit.xml
+8
View File
@@ -1,6 +1,14 @@
CHANGELOG
=========
4.0.0
-----
* the first argument of the `ExpressionLanguage` constructor must be an instance
of `CacheItemPoolInterface`
* removed the `ArrayParserCache` and `ParserCacheAdapter` classes
* removed the `ParserCacheInterface`
2.6.0
-----
+3 -1
View File
@@ -11,12 +11,14 @@
namespace Symfony\Component\ExpressionLanguage;
use Symfony\Contracts\Service\ResetInterface;
/**
* Compiles a node to PHP code.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Compiler
class Compiler implements ResetInterface
{
private $source;
private $functions;
+2 -5
View File
@@ -20,12 +20,9 @@ class Expression
{
protected $expression;
/**
* @param string $expression An expression
*/
public function __construct($expression)
public function __construct(string $expression)
{
$this->expression = (string) $expression;
$this->expression = $expression;
}
/**
+5 -7
View File
@@ -39,7 +39,7 @@ class ExpressionFunction
* @param callable $compiler A callable able to compile the function
* @param callable $evaluator A callable able to evaluate the function
*/
public function __construct($name, callable $compiler, callable $evaluator)
public function __construct(string $name, callable $compiler, callable $evaluator)
{
$this->name = $name;
$this->compiler = $compiler;
@@ -85,14 +85,12 @@ class ExpressionFunction
throw new \InvalidArgumentException(sprintf('An expression function name must be defined when PHP function "%s" is namespaced.', $phpFunctionName));
}
$compiler = function () use ($phpFunctionName) {
return sprintf('\%s(%s)', $phpFunctionName, implode(', ', \func_get_args()));
$compiler = function (...$args) use ($phpFunctionName) {
return sprintf('\%s(%s)', $phpFunctionName, implode(', ', $args));
};
$evaluator = function () use ($phpFunctionName) {
$args = \func_get_args();
return \call_user_func_array($phpFunctionName, array_splice($args, 1));
$evaluator = function ($p, ...$args) use ($phpFunctionName) {
return $phpFunctionName(...$args);
};
return new self($expressionFunctionName ?: end($parts), $compiler, $evaluator);
+5 -17
View File
@@ -13,8 +13,6 @@ namespace Symfony\Component\ExpressionLanguage;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheAdapter;
use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface;
/**
* Allows to compile and evaluate expressions written in your own DSL.
@@ -31,21 +29,11 @@ class ExpressionLanguage
protected $functions = [];
/**
* @param CacheItemPoolInterface $cache
* @param ExpressionFunctionProviderInterface[] $providers
*/
public function __construct($cache = null, array $providers = [])
public function __construct(CacheItemPoolInterface $cache = null, array $providers = [])
{
if (null !== $cache) {
if ($cache instanceof ParserCacheInterface) {
@trigger_error(sprintf('Passing an instance of %s as constructor argument for %s is deprecated as of 3.2 and will be removed in 4.0. Pass an instance of %s instead.', ParserCacheInterface::class, self::class, CacheItemPoolInterface::class), \E_USER_DEPRECATED);
$cache = new ParserCacheAdapter($cache);
} elseif (!$cache instanceof CacheItemPoolInterface) {
throw new \InvalidArgumentException(sprintf('Cache argument has to implement "%s".', CacheItemPoolInterface::class));
}
}
$this->cache = $cache ?: new ArrayAdapter();
$this->cache = $cache ?? new ArrayAdapter();
$this->registerFunctions();
foreach ($providers as $provider) {
$this->registerProvider($provider);
@@ -149,7 +137,7 @@ class ExpressionLanguage
$this->addFunction(ExpressionFunction::fromPhp('constant'));
}
private function getLexer()
private function getLexer(): Lexer
{
if (null === $this->lexer) {
$this->lexer = new Lexer();
@@ -158,7 +146,7 @@ class ExpressionLanguage
return $this->lexer;
}
private function getParser()
private function getParser(): Parser
{
if (null === $this->parser) {
$this->parser = new Parser($this->functions);
@@ -167,7 +155,7 @@ class ExpressionLanguage
return $this->parser;
}
private function getCompiler()
private function getCompiler(): Compiler
{
if (null === $this->compiler) {
$this->compiler = new Compiler($this->functions);
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2004-2020 Fabien Potencier
Copyright (c) 2004-2022 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+3 -3
View File
@@ -42,7 +42,7 @@ class Lexer
continue;
}
if (preg_match('/[0-9]+(?:\.[0-9]+)?/A', $expression, $match, 0, $cursor)) {
if (preg_match('/[0-9]+(?:\.[0-9]+)?([Ee][\+\-][0-9]+)?/A', $expression, $match, 0, $cursor)) {
// numbers
$number = (float) $match[0]; // floats
if (preg_match('/^[0-9]+$/', $match[0]) && $number <= \PHP_INT_MAX) {
@@ -62,7 +62,7 @@ class Lexer
throw new SyntaxError(sprintf('Unexpected "%s".', $expression[$cursor]), $cursor, $expression);
}
list($expect, $cur) = array_pop($brackets);
[$expect, $cur] = array_pop($brackets);
if ($expression[$cursor] != strtr($expect, '([{', ')]}')) {
throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $cur, $expression);
}
@@ -94,7 +94,7 @@ class Lexer
$tokens[] = new Token(Token::EOF_TYPE, null, $cursor + 1);
if (!empty($brackets)) {
list($expect, $cur) = array_pop($brackets);
[$expect, $cur] = array_pop($brackets);
throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $cur, $expression);
}
+28 -11
View File
@@ -12,6 +12,7 @@
namespace Symfony\Component\ExpressionLanguage\Node;
use Symfony\Component\ExpressionLanguage\Compiler;
use Symfony\Component\ExpressionLanguage\SyntaxError;
/**
* @author Fabien Potencier <fabien@symfony.com>
@@ -20,20 +21,20 @@ use Symfony\Component\ExpressionLanguage\Compiler;
*/
class BinaryNode extends Node
{
private static $operators = [
private const OPERATORS = [
'~' => '.',
'and' => '&&',
'or' => '||',
];
private static $functions = [
private const FUNCTIONS = [
'**' => 'pow',
'..' => 'range',
'in' => 'in_array',
'not in' => '!in_array',
];
public function __construct($operator, Node $left, Node $right)
public function __construct(string $operator, Node $left, Node $right)
{
parent::__construct(
['left' => $left, 'right' => $right],
@@ -46,8 +47,12 @@ class BinaryNode extends Node
$operator = $this->attributes['operator'];
if ('matches' == $operator) {
if ($this->nodes['right'] instanceof ConstantNode) {
$this->evaluateMatches($this->nodes['right']->evaluate([], []), '');
}
$compiler
->raw('preg_match(')
->raw('(static function ($regexp, $str) { set_error_handler(function ($t, $m) use ($regexp, $str) { throw new \Symfony\Component\ExpressionLanguage\SyntaxError(sprintf(\'Regexp "%s" passed to "matches" is not valid\', $regexp).substr($m, 12)); }); try { return preg_match($regexp, (string) $str); } finally { restore_error_handler(); } })(')
->compile($this->nodes['right'])
->raw(', ')
->compile($this->nodes['left'])
@@ -57,9 +62,9 @@ class BinaryNode extends Node
return;
}
if (isset(self::$functions[$operator])) {
if (isset(self::FUNCTIONS[$operator])) {
$compiler
->raw(sprintf('%s(', self::$functions[$operator]))
->raw(sprintf('%s(', self::FUNCTIONS[$operator]))
->compile($this->nodes['left'])
->raw(', ')
->compile($this->nodes['right'])
@@ -69,8 +74,8 @@ class BinaryNode extends Node
return;
}
if (isset(self::$operators[$operator])) {
$operator = self::$operators[$operator];
if (isset(self::OPERATORS[$operator])) {
$operator = self::OPERATORS[$operator];
}
$compiler
@@ -89,13 +94,13 @@ class BinaryNode extends Node
$operator = $this->attributes['operator'];
$left = $this->nodes['left']->evaluate($functions, $values);
if (isset(self::$functions[$operator])) {
if (isset(self::FUNCTIONS[$operator])) {
$right = $this->nodes['right']->evaluate($functions, $values);
if ('not in' === $operator) {
return !\in_array($left, $right);
}
$f = self::$functions[$operator];
$f = self::FUNCTIONS[$operator];
return $f($left, $right);
}
@@ -159,7 +164,7 @@ class BinaryNode extends Node
return $left % $right;
case 'matches':
return preg_match($right, $left);
return $this->evaluateMatches($right, $left);
}
}
@@ -167,4 +172,16 @@ class BinaryNode extends Node
{
return ['(', $this->nodes['left'], ' '.$this->attributes['operator'].' ', $this->nodes['right'], ')'];
}
private function evaluateMatches(string $regexp, ?string $str): int
{
set_error_handler(function ($t, $m) use ($regexp) {
throw new SyntaxError(sprintf('Regexp "%s" passed to "matches" is not valid', $regexp).substr($m, 12));
});
try {
return preg_match($regexp, (string) $str);
} finally {
restore_error_handler();
}
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ class ConstantNode extends Node
{
private $isIdentifier;
public function __construct($value, $isIdentifier = false)
public function __construct($value, bool $isIdentifier = false)
{
$this->isIdentifier = $isIdentifier;
parent::__construct(
+3 -3
View File
@@ -20,7 +20,7 @@ use Symfony\Component\ExpressionLanguage\Compiler;
*/
class FunctionNode extends Node
{
public function __construct($name, Node $arguments)
public function __construct(string $name, Node $arguments)
{
parent::__construct(
['arguments' => $arguments],
@@ -37,7 +37,7 @@ class FunctionNode extends Node
$function = $compiler->getFunction($this->attributes['name']);
$compiler->raw(\call_user_func_array($function['compiler'], $arguments));
$compiler->raw($function['compiler'](...$arguments));
}
public function evaluate($functions, $values)
@@ -47,7 +47,7 @@ class FunctionNode extends Node
$arguments[] = $node->evaluate($functions, $values);
}
return \call_user_func_array($functions[$this->attributes['name']]['evaluator'], $arguments);
return $functions[$this->attributes['name']]['evaluator'](...$arguments);
}
public function toArray()
+5 -11
View File
@@ -20,11 +20,11 @@ use Symfony\Component\ExpressionLanguage\Compiler;
*/
class GetAttrNode extends Node
{
const PROPERTY_CALL = 1;
const METHOD_CALL = 2;
const ARRAY_CALL = 3;
public const PROPERTY_CALL = 1;
public const METHOD_CALL = 2;
public const ARRAY_CALL = 3;
public function __construct(Node $node, Node $attribute, ArrayNode $arguments, $type)
public function __construct(Node $node, Node $attribute, ArrayNode $arguments, int $type)
{
parent::__construct(
['node' => $node, 'attribute' => $attribute, 'arguments' => $arguments],
@@ -86,13 +86,7 @@ class GetAttrNode extends Node
throw new \RuntimeException(sprintf('Unable to call method "%s" of object "%s".', $this->nodes['attribute']->attributes['value'], \get_class($obj)));
}
$arguments = $this->nodes['arguments']->evaluate($functions, $values);
if (\PHP_VERSION_ID >= 80000) {
$arguments = array_values($arguments);
}
return \call_user_func_array($toCall, $arguments);
return $toCall(...array_values($this->nodes['arguments']->evaluate($functions, $values)));
case self::ARRAY_CALL:
$array = $this->nodes['node']->evaluate($functions, $values);
+1 -1
View File
@@ -20,7 +20,7 @@ use Symfony\Component\ExpressionLanguage\Compiler;
*/
class NameNode extends Node
{
public function __construct($name)
public function __construct(string $name)
{
parent::__construct(
[],
+4 -1
View File
@@ -33,6 +33,9 @@ class Node
$this->attributes = $attributes;
}
/**
* @return string
*/
public function __toString()
{
$attributes = [];
@@ -84,7 +87,7 @@ class Node
$dump = '';
foreach ($this->toArray() as $v) {
$dump .= is_scalar($v) ? $v : $v->dump();
$dump .= \is_scalar($v) ? $v : $v->dump();
}
return $dump;
+4 -4
View File
@@ -20,14 +20,14 @@ use Symfony\Component\ExpressionLanguage\Compiler;
*/
class UnaryNode extends Node
{
private static $operators = [
private const OPERATORS = [
'!' => '!',
'not' => '!',
'+' => '+',
'-' => '-',
];
public function __construct($operator, Node $node)
public function __construct(string $operator, Node $node)
{
parent::__construct(
['node' => $node],
@@ -39,7 +39,7 @@ class UnaryNode extends Node
{
$compiler
->raw('(')
->raw(self::$operators[$this->attributes['operator']])
->raw(self::OPERATORS[$this->attributes['operator']])
->compile($this->nodes['node'])
->raw(')')
;
@@ -59,7 +59,7 @@ class UnaryNode extends Node
return $value;
}
public function toArray()
public function toArray(): array
{
return ['(', $this->attributes['operator'].' ', $this->nodes['node'], ')'];
}
+1 -5
View File
@@ -22,11 +22,7 @@ class ParsedExpression extends Expression
{
private $nodes;
/**
* @param string $expression An expression
* @param Node $nodes A Node representing the expression
*/
public function __construct($expression, Node $nodes)
public function __construct(string $expression, Node $nodes)
{
parent::__construct($expression);
+3 -4
View File
@@ -23,8 +23,8 @@ namespace Symfony\Component\ExpressionLanguage;
*/
class Parser
{
const OPERATOR_LEFT = 1;
const OPERATOR_RIGHT = 2;
public const OPERATOR_LEFT = 1;
public const OPERATOR_RIGHT = 2;
private $stream;
private $unaryOperators;
@@ -85,8 +85,7 @@ class Parser
* variable 'container' can be used in the expression
* but the compiled code will use 'this'.
*
* @param TokenStream $stream A token stream instance
* @param array $names An array of valid names
* @param array $names An array of valid names
*
* @return Node\Node A node tree
*
@@ -1,42 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\ParserCache;
@trigger_error('The '.__NAMESPACE__.'\ArrayParserCache class is deprecated since Symfony 3.2 and will be removed in 4.0. Use the Symfony\Component\Cache\Adapter\ArrayAdapter class instead.', \E_USER_DEPRECATED);
use Symfony\Component\ExpressionLanguage\ParsedExpression;
/**
* @author Adrien Brault <adrien.brault@gmail.com>
*
* @deprecated ArrayParserCache class is deprecated since version 3.2 and will be removed in 4.0. Use the Symfony\Component\Cache\Adapter\ArrayAdapter class instead.
*/
class ArrayParserCache implements ParserCacheInterface
{
private $cache = [];
/**
* {@inheritdoc}
*/
public function fetch($key)
{
return isset($this->cache[$key]) ? $this->cache[$key] : null;
}
/**
* {@inheritdoc}
*/
public function save($key, ParsedExpression $expression)
{
$this->cache[$key] = $expression;
}
}
@@ -1,120 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\ParserCache;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem;
/**
* @author Alexandre GESLIN <alexandre@gesl.in>
*
* @internal and will be removed in Symfony 4.0.
*/
class ParserCacheAdapter implements CacheItemPoolInterface
{
private $pool;
private $createCacheItem;
public function __construct(ParserCacheInterface $pool)
{
$this->pool = $pool;
$this->createCacheItem = \Closure::bind(
static function ($key, $value, $isHit) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;
$item->isHit = $isHit;
return $item;
},
null,
CacheItem::class
);
}
/**
* {@inheritdoc}
*/
public function getItem($key)
{
$value = $this->pool->fetch($key);
$f = $this->createCacheItem;
return $f($key, $value, null !== $value);
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
$this->pool->save($item->getKey(), $item->get());
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = [])
{
throw new \BadMethodCallException('Not implemented.');
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
throw new \BadMethodCallException('Not implemented.');
}
/**
* {@inheritdoc}
*/
public function clear()
{
throw new \BadMethodCallException('Not implemented.');
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
throw new \BadMethodCallException('Not implemented.');
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
throw new \BadMethodCallException('Not implemented.');
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
throw new \BadMethodCallException('Not implemented.');
}
/**
* {@inheritdoc}
*/
public function commit()
{
throw new \BadMethodCallException('Not implemented.');
}
}
@@ -1,41 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\ParserCache;
@trigger_error('The '.__NAMESPACE__.'\ParserCacheInterface interface is deprecated since Symfony 3.2 and will be removed in 4.0. Use Psr\Cache\CacheItemPoolInterface instead.', \E_USER_DEPRECATED);
use Symfony\Component\ExpressionLanguage\ParsedExpression;
/**
* @author Adrien Brault <adrien.brault@gmail.com>
*
* @deprecated since version 3.2, to be removed in 4.0. Use Psr\Cache\CacheItemPoolInterface instead.
*/
interface ParserCacheInterface
{
/**
* Saves an expression in the cache.
*
* @param string $key The cache key
* @param ParsedExpression $expression A ParsedExpression instance to store in the cache
*/
public function save($key, ParsedExpression $expression);
/**
* Fetches an expression from the cache.
*
* @param string $key The cache key
*
* @return ParsedExpression|null
*/
public function fetch($key);
}
+5 -5
View File
@@ -8,8 +8,8 @@ evaluate expressions. An expression is a one-liner that returns a value
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/expression_language/introduction.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)
* [Documentation](https://symfony.com/doc/current/components/expression_language/introduction.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)
@@ -9,6 +9,10 @@
* file that was distributed with this source code.
*/
if ('cli' !== \PHP_SAPI) {
throw new Exception('This script must be run from the command line.');
}
$operators = ['not', '!', 'or', '||', '&&', 'and', '|', '^', '&', '==', '===', '!=', '!==', '<', '>', '>=', '<=', 'not in', 'in', '..', '+', '-', '~', '*', '/', '%', 'matches', '**'];
$operators = array_combine($operators, array_map('strlen', $operators));
arsort($operators);
@@ -24,9 +24,9 @@ class SerializedParsedExpression extends ParsedExpression
* @param string $expression An expression
* @param string $nodes The serialized nodes for the expression
*/
public function __construct($expression, $nodes)
public function __construct(string $expression, string $nodes)
{
$this->expression = (string) $expression;
$this->expression = $expression;
$this->nodes = $nodes;
}
+1 -1
View File
@@ -13,7 +13,7 @@ namespace Symfony\Component\ExpressionLanguage;
class SyntaxError extends \LogicException
{
public function __construct($message, $cursor = 0, $expression = '', $subject = null, array $proposals = null)
public function __construct(string $message, int $cursor = 0, string $expression = '', string $subject = null, array $proposals = null)
{
$message = sprintf('%s around position %d', rtrim($message, '.'), $cursor);
if ($expression) {
@@ -1,41 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
/**
* Tests ExpressionFunction.
*
* @author Dany Maillard <danymaillard93b@gmail.com>
*/
class ExpressionFunctionTest extends TestCase
{
public function testFunctionDoesNotExist()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('PHP function "fn_does_not_exist" does not exist.');
ExpressionFunction::fromPhp('fn_does_not_exist');
}
public function testFunctionNamespaced()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('An expression function name must be defined when PHP function "Symfony\Component\ExpressionLanguage\Tests\fn_namespaced" is namespaced.');
ExpressionFunction::fromPhp('Symfony\Component\ExpressionLanguage\Tests\fn_namespaced');
}
}
function fn_namespaced()
{
}
@@ -1,308 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\ExpressionLanguage\ParsedExpression;
use Symfony\Component\ExpressionLanguage\Tests\Fixtures\TestProvider;
class ExpressionLanguageTest extends TestCase
{
public function testCachedParse()
{
$cacheMock = $this->getMockBuilder('Psr\Cache\CacheItemPoolInterface')->getMock();
$cacheItemMock = $this->getMockBuilder('Psr\Cache\CacheItemInterface')->getMock();
$savedParsedExpression = null;
$expressionLanguage = new ExpressionLanguage($cacheMock);
$cacheMock
->expects($this->exactly(2))
->method('getItem')
->with('1%20%2B%201%2F%2F')
->willReturn($cacheItemMock)
;
$cacheItemMock
->expects($this->exactly(2))
->method('get')
->willReturnCallback(function () use (&$savedParsedExpression) {
return $savedParsedExpression;
})
;
$cacheItemMock
->expects($this->exactly(1))
->method('set')
->with($this->isInstanceOf(ParsedExpression::class))
->willReturnCallback(function ($parsedExpression) use (&$savedParsedExpression) {
$savedParsedExpression = $parsedExpression;
})
;
$cacheMock
->expects($this->exactly(1))
->method('save')
->with($cacheItemMock)
;
$parsedExpression = $expressionLanguage->parse('1 + 1', []);
$this->assertSame($savedParsedExpression, $parsedExpression);
$parsedExpression = $expressionLanguage->parse('1 + 1', []);
$this->assertSame($savedParsedExpression, $parsedExpression);
}
/**
* @group legacy
*/
public function testCachedParseWithDeprecatedParserCacheInterface()
{
$cacheMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock();
$savedParsedExpression = null;
$expressionLanguage = new ExpressionLanguage($cacheMock);
$cacheMock
->expects($this->exactly(1))
->method('fetch')
->with('1%20%2B%201%2F%2F')
->willReturn($savedParsedExpression)
;
$cacheMock
->expects($this->exactly(1))
->method('save')
->with('1%20%2B%201%2F%2F', $this->isInstanceOf(ParsedExpression::class))
->willReturnCallback(function ($key, $expression) use (&$savedParsedExpression) {
$savedParsedExpression = $expression;
})
;
$parsedExpression = $expressionLanguage->parse('1 + 1', []);
$this->assertSame($savedParsedExpression, $parsedExpression);
}
public function testWrongCacheImplementation()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('Cache argument has to implement "Psr\Cache\CacheItemPoolInterface".');
$cacheMock = $this->getMockBuilder('Psr\Cache\CacheItemSpoolInterface')->getMock();
new ExpressionLanguage($cacheMock);
}
public function testConstantFunction()
{
$expressionLanguage = new ExpressionLanguage();
$this->assertEquals(\PHP_VERSION, $expressionLanguage->evaluate('constant("PHP_VERSION")'));
$expressionLanguage = new ExpressionLanguage();
$this->assertEquals('\constant("PHP_VERSION")', $expressionLanguage->compile('constant("PHP_VERSION")'));
}
public function testProviders()
{
$expressionLanguage = new ExpressionLanguage(null, [new TestProvider()]);
$this->assertEquals('foo', $expressionLanguage->evaluate('identity("foo")'));
$this->assertEquals('"foo"', $expressionLanguage->compile('identity("foo")'));
$this->assertEquals('FOO', $expressionLanguage->evaluate('strtoupper("foo")'));
$this->assertEquals('\strtoupper("foo")', $expressionLanguage->compile('strtoupper("foo")'));
$this->assertEquals('foo', $expressionLanguage->evaluate('strtolower("FOO")'));
$this->assertEquals('\strtolower("FOO")', $expressionLanguage->compile('strtolower("FOO")'));
$this->assertTrue($expressionLanguage->evaluate('fn_namespaced()'));
$this->assertEquals('\Symfony\Component\ExpressionLanguage\Tests\Fixtures\fn_namespaced()', $expressionLanguage->compile('fn_namespaced()'));
}
/**
* @dataProvider shortCircuitProviderEvaluate
*/
public function testShortCircuitOperatorsEvaluate($expression, array $values, $expected)
{
$expressionLanguage = new ExpressionLanguage();
$this->assertEquals($expected, $expressionLanguage->evaluate($expression, $values));
}
/**
* @dataProvider shortCircuitProviderCompile
*/
public function testShortCircuitOperatorsCompile($expression, array $names, $expected)
{
$result = null;
$expressionLanguage = new ExpressionLanguage();
eval(sprintf('$result = %s;', $expressionLanguage->compile($expression, $names)));
$this->assertSame($expected, $result);
}
public function testParseThrowsInsteadOfNotice()
{
$this->expectException('Symfony\Component\ExpressionLanguage\SyntaxError');
$this->expectExceptionMessage('Unexpected end of expression around position 6 for expression `node.`.');
$expressionLanguage = new ExpressionLanguage();
$expressionLanguage->parse('node.', ['node']);
}
public function shortCircuitProviderEvaluate()
{
$object = $this->getMockBuilder('stdClass')->setMethods(['foo'])->getMock();
$object->expects($this->never())->method('foo');
return [
['false and object.foo()', ['object' => $object], false],
['false && object.foo()', ['object' => $object], false],
['true || object.foo()', ['object' => $object], true],
['true or object.foo()', ['object' => $object], true],
];
}
public function shortCircuitProviderCompile()
{
return [
['false and foo', ['foo' => 'foo'], false],
['false && foo', ['foo' => 'foo'], false],
['true || foo', ['foo' => 'foo'], true],
['true or foo', ['foo' => 'foo'], true],
];
}
public function testCachingForOverriddenVariableNames()
{
$expressionLanguage = new ExpressionLanguage();
$expression = 'a + b';
$expressionLanguage->evaluate($expression, ['a' => 1, 'b' => 1]);
$result = $expressionLanguage->compile($expression, ['a', 'B' => 'b']);
$this->assertSame('($a + $B)', $result);
}
public function testStrictEquality()
{
$expressionLanguage = new ExpressionLanguage();
$expression = '123 === a';
$result = $expressionLanguage->compile($expression, ['a']);
$this->assertSame('(123 === $a)', $result);
}
public function testCachingWithDifferentNamesOrder()
{
$cacheMock = $this->getMockBuilder('Psr\Cache\CacheItemPoolInterface')->getMock();
$cacheItemMock = $this->getMockBuilder('Psr\Cache\CacheItemInterface')->getMock();
$expressionLanguage = new ExpressionLanguage($cacheMock);
$savedParsedExpression = null;
$cacheMock
->expects($this->exactly(2))
->method('getItem')
->with('a%20%2B%20b%2F%2Fa%7CB%3Ab')
->willReturn($cacheItemMock)
;
$cacheItemMock
->expects($this->exactly(2))
->method('get')
->willReturnCallback(function () use (&$savedParsedExpression) {
return $savedParsedExpression;
})
;
$cacheItemMock
->expects($this->exactly(1))
->method('set')
->with($this->isInstanceOf(ParsedExpression::class))
->willReturnCallback(function ($parsedExpression) use (&$savedParsedExpression) {
$savedParsedExpression = $parsedExpression;
})
;
$cacheMock
->expects($this->exactly(1))
->method('save')
->with($cacheItemMock)
;
$expression = 'a + b';
$expressionLanguage->compile($expression, ['a', 'B' => 'b']);
$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
*/
public function testRegisterAfterParse($registerCallback)
{
$this->expectException('LogicException');
$el = new ExpressionLanguage();
$el->parse('1 + 1', []);
$registerCallback($el);
}
/**
* @dataProvider getRegisterCallbacks
*/
public function testRegisterAfterEval($registerCallback)
{
$this->expectException('LogicException');
$el = new ExpressionLanguage();
$el->evaluate('1 + 1');
$registerCallback($el);
}
public function testCallBadCallable()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessageMatches('/Unable to call method "\w+" of object "\w+"./');
$el = new ExpressionLanguage();
$el->evaluate('foo.myfunction()', ['foo' => new \stdClass()]);
}
/**
* @dataProvider getRegisterCallbacks
*/
public function testRegisterAfterCompile($registerCallback)
{
$this->expectException('LogicException');
$el = new ExpressionLanguage();
$el->compile('1 + 1');
$registerCallback($el);
}
public function getRegisterCallbacks()
{
return [
[
function (ExpressionLanguage $el) {
$el->register('fn', function () {}, function () {});
},
],
[
function (ExpressionLanguage $el) {
$el->addFunction(new ExpressionFunction('fn', function () {}, function () {}));
},
],
[
function (ExpressionLanguage $el) {
$el->registerProvider(new TestProvider());
},
],
];
}
}
@@ -1,28 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ExpressionLanguage\Expression;
class ExpressionTest extends TestCase
{
public function testSerialization()
{
$expression = new Expression('kernel.boot()');
$serializedExpression = serialize($expression);
$unserializedExpression = unserialize($serializedExpression);
$this->assertEquals($expression, $unserializedExpression);
}
}
@@ -1,41 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests\Fixtures;
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
use Symfony\Component\ExpressionLanguage\ExpressionPhpFunction;
class TestProvider implements ExpressionFunctionProviderInterface
{
public function getFunctions()
{
return [
new ExpressionFunction('identity', function ($input) {
return $input;
}, function (array $values, $input) {
return $input;
}),
ExpressionFunction::fromPhp('strtoupper'),
ExpressionFunction::fromPhp('\strtolower'),
ExpressionFunction::fromPhp('Symfony\Component\ExpressionLanguage\Tests\Fixtures\fn_namespaced', 'fn_namespaced'),
];
}
}
function fn_namespaced()
{
return true;
}
-129
View File
@@ -1,129 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ExpressionLanguage\Lexer;
use Symfony\Component\ExpressionLanguage\Token;
use Symfony\Component\ExpressionLanguage\TokenStream;
class LexerTest extends TestCase
{
/**
* @var Lexer
*/
private $lexer;
protected function setUp()
{
$this->lexer = new Lexer();
}
/**
* @dataProvider getTokenizeData
*/
public function testTokenize($tokens, $expression)
{
$tokens[] = new Token('end of expression', null, \strlen($expression) + 1);
$this->assertEquals(new TokenStream($tokens, $expression), $this->lexer->tokenize($expression));
}
public function testTokenizeThrowsErrorWithMessage()
{
$this->expectException('Symfony\Component\ExpressionLanguage\SyntaxError');
$this->expectExceptionMessage('Unexpected character "\'" around position 33 for expression `service(faulty.expression.example\').dummyMethod()`.');
$expression = "service(faulty.expression.example').dummyMethod()";
$this->lexer->tokenize($expression);
}
public function testTokenizeThrowsErrorOnUnclosedBrace()
{
$this->expectException('Symfony\Component\ExpressionLanguage\SyntaxError');
$this->expectExceptionMessage('Unclosed "(" around position 7 for expression `service(unclosed.expression.dummyMethod()`.');
$expression = 'service(unclosed.expression.dummyMethod()';
$this->lexer->tokenize($expression);
}
public function getTokenizeData()
{
return [
[
[new Token('name', 'a', 3)],
' a ',
],
[
[new Token('name', 'a', 1)],
'a',
],
[
[new Token('string', 'foo', 1)],
'"foo"',
],
[
[new Token('number', '3', 1)],
'3',
],
[
[new Token('operator', '+', 1)],
'+',
],
[
[new Token('punctuation', '.', 1)],
'.',
],
[
[
new Token('punctuation', '(', 1),
new Token('number', '3', 2),
new Token('operator', '+', 4),
new Token('number', '5', 6),
new Token('punctuation', ')', 7),
new Token('operator', '~', 9),
new Token('name', 'foo', 11),
new Token('punctuation', '(', 14),
new Token('string', 'bar', 15),
new Token('punctuation', ')', 20),
new Token('punctuation', '.', 21),
new Token('name', 'baz', 22),
new Token('punctuation', '[', 25),
new Token('number', '4', 26),
new Token('punctuation', ']', 27),
],
'(3 + 5) ~ foo("bar").baz[4]',
],
[
[new Token('operator', '..', 1)],
'..',
],
[
[new Token('string', '#foo', 1)],
"'#foo'",
],
[
[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]',
],
];
}
}
@@ -1,50 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests\Node;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ExpressionLanguage\Compiler;
abstract class AbstractNodeTest extends TestCase
{
/**
* @dataProvider getEvaluateData
*/
public function testEvaluate($expected, $node, $variables = [], $functions = [])
{
$this->assertSame($expected, $node->evaluate($functions, $variables));
}
abstract public function getEvaluateData();
/**
* @dataProvider getCompileData
*/
public function testCompile($expected, $node, $functions = [])
{
$compiler = new Compiler($functions);
$node->compile($compiler);
$this->assertSame($expected, $compiler->getSource());
}
abstract public function getCompileData();
/**
* @dataProvider getDumpData
*/
public function testDump($expected, $node)
{
$this->assertSame($expected, $node->dump());
}
abstract public function getDumpData();
}
@@ -1,36 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests\Node;
use Symfony\Component\ExpressionLanguage\Node\ArgumentsNode;
class ArgumentsNodeTest extends ArrayNodeTest
{
public function getCompileData()
{
return [
['"a", "b"', $this->getArrayNode()],
];
}
public function getDumpData()
{
return [
['"a", "b"', $this->getArrayNode()],
];
}
protected function createArrayNode()
{
return new ArgumentsNode();
}
}
@@ -1,73 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests\Node;
use Symfony\Component\ExpressionLanguage\Node\ArrayNode;
use Symfony\Component\ExpressionLanguage\Node\ConstantNode;
class ArrayNodeTest extends AbstractNodeTest
{
public function testSerialization()
{
$node = $this->createArrayNode();
$node->addElement(new ConstantNode('foo'));
$serializedNode = serialize($node);
$unserializedNode = unserialize($serializedNode);
$this->assertEquals($node, $unserializedNode);
$this->assertNotEquals($this->createArrayNode(), $unserializedNode);
}
public function getEvaluateData()
{
return [
[['b' => 'a', 'b'], $this->getArrayNode()],
];
}
public function getCompileData()
{
return [
['["b" => "a", 0 => "b"]', $this->getArrayNode()],
];
}
public function getDumpData()
{
yield ['{"b": "a", 0: "b"}', $this->getArrayNode()];
$array = $this->createArrayNode();
$array->addElement(new ConstantNode('c'), new ConstantNode('a"b'));
$array->addElement(new ConstantNode('d'), new ConstantNode('a\b'));
yield ['{"a\\"b": "c", "a\\\\b": "d"}', $array];
$array = $this->createArrayNode();
$array->addElement(new ConstantNode('c'));
$array->addElement(new ConstantNode('d'));
yield ['["c", "d"]', $array];
}
protected function getArrayNode()
{
$array = $this->createArrayNode();
$array->addElement(new ConstantNode('a'), new ConstantNode('b'));
$array->addElement(new ConstantNode('b'));
return $array;
}
protected function createArrayNode()
{
return new ArrayNode();
}
}
@@ -1,166 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests\Node;
use Symfony\Component\ExpressionLanguage\Node\ArrayNode;
use Symfony\Component\ExpressionLanguage\Node\BinaryNode;
use Symfony\Component\ExpressionLanguage\Node\ConstantNode;
class BinaryNodeTest extends AbstractNodeTest
{
public function getEvaluateData()
{
$array = new ArrayNode();
$array->addElement(new ConstantNode('a'));
$array->addElement(new ConstantNode('b'));
return [
[true, new BinaryNode('or', new ConstantNode(true), new ConstantNode(false))],
[true, new BinaryNode('||', new ConstantNode(true), new ConstantNode(false))],
[false, new BinaryNode('and', new ConstantNode(true), new ConstantNode(false))],
[false, new BinaryNode('&&', new ConstantNode(true), new ConstantNode(false))],
[0, new BinaryNode('&', new ConstantNode(2), new ConstantNode(4))],
[6, new BinaryNode('|', new ConstantNode(2), new ConstantNode(4))],
[6, new BinaryNode('^', new ConstantNode(2), new ConstantNode(4))],
[true, new BinaryNode('<', new ConstantNode(1), new ConstantNode(2))],
[true, new BinaryNode('<=', new ConstantNode(1), new ConstantNode(2))],
[true, new BinaryNode('<=', new ConstantNode(1), new ConstantNode(1))],
[false, new BinaryNode('>', new ConstantNode(1), new ConstantNode(2))],
[false, new BinaryNode('>=', new ConstantNode(1), new ConstantNode(2))],
[true, new BinaryNode('>=', new ConstantNode(1), new ConstantNode(1))],
[true, new BinaryNode('===', new ConstantNode(true), new ConstantNode(true))],
[false, new BinaryNode('!==', new ConstantNode(true), new ConstantNode(true))],
[false, new BinaryNode('==', new ConstantNode(2), new ConstantNode(1))],
[true, new BinaryNode('!=', new ConstantNode(2), new ConstantNode(1))],
[-1, new BinaryNode('-', new ConstantNode(1), new ConstantNode(2))],
[3, new BinaryNode('+', new ConstantNode(1), new ConstantNode(2))],
[4, new BinaryNode('*', new ConstantNode(2), new ConstantNode(2))],
[1, new BinaryNode('/', new ConstantNode(2), new ConstantNode(2))],
[1, new BinaryNode('%', new ConstantNode(5), new ConstantNode(2))],
[25, new BinaryNode('**', new ConstantNode(5), new ConstantNode(2))],
['ab', new BinaryNode('~', new ConstantNode('a'), new ConstantNode('b'))],
[true, new BinaryNode('in', new ConstantNode('a'), $array)],
[false, new BinaryNode('in', new ConstantNode('c'), $array)],
[true, new BinaryNode('not in', new ConstantNode('c'), $array)],
[false, new BinaryNode('not in', new ConstantNode('a'), $array)],
[[1, 2, 3], new BinaryNode('..', new ConstantNode(1), new ConstantNode(3))],
[1, new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('/^[a-z]+$/'))],
];
}
public function getCompileData()
{
$array = new ArrayNode();
$array->addElement(new ConstantNode('a'));
$array->addElement(new ConstantNode('b'));
return [
['(true || false)', new BinaryNode('or', new ConstantNode(true), new ConstantNode(false))],
['(true || false)', new BinaryNode('||', new ConstantNode(true), new ConstantNode(false))],
['(true && false)', new BinaryNode('and', new ConstantNode(true), new ConstantNode(false))],
['(true && false)', new BinaryNode('&&', new ConstantNode(true), new ConstantNode(false))],
['(2 & 4)', new BinaryNode('&', new ConstantNode(2), new ConstantNode(4))],
['(2 | 4)', new BinaryNode('|', new ConstantNode(2), new ConstantNode(4))],
['(2 ^ 4)', new BinaryNode('^', new ConstantNode(2), new ConstantNode(4))],
['(1 < 2)', new BinaryNode('<', new ConstantNode(1), new ConstantNode(2))],
['(1 <= 2)', new BinaryNode('<=', new ConstantNode(1), new ConstantNode(2))],
['(1 <= 1)', new BinaryNode('<=', new ConstantNode(1), new ConstantNode(1))],
['(1 > 2)', new BinaryNode('>', new ConstantNode(1), new ConstantNode(2))],
['(1 >= 2)', new BinaryNode('>=', new ConstantNode(1), new ConstantNode(2))],
['(1 >= 1)', new BinaryNode('>=', new ConstantNode(1), new ConstantNode(1))],
['(true === true)', new BinaryNode('===', new ConstantNode(true), new ConstantNode(true))],
['(true !== true)', new BinaryNode('!==', new ConstantNode(true), new ConstantNode(true))],
['(2 == 1)', new BinaryNode('==', new ConstantNode(2), new ConstantNode(1))],
['(2 != 1)', new BinaryNode('!=', new ConstantNode(2), new ConstantNode(1))],
['(1 - 2)', new BinaryNode('-', new ConstantNode(1), new ConstantNode(2))],
['(1 + 2)', new BinaryNode('+', new ConstantNode(1), new ConstantNode(2))],
['(2 * 2)', new BinaryNode('*', new ConstantNode(2), new ConstantNode(2))],
['(2 / 2)', new BinaryNode('/', new ConstantNode(2), new ConstantNode(2))],
['(5 % 2)', new BinaryNode('%', new ConstantNode(5), new ConstantNode(2))],
['pow(5, 2)', new BinaryNode('**', new ConstantNode(5), new ConstantNode(2))],
['("a" . "b")', new BinaryNode('~', new ConstantNode('a'), new ConstantNode('b'))],
['in_array("a", [0 => "a", 1 => "b"])', new BinaryNode('in', new ConstantNode('a'), $array)],
['in_array("c", [0 => "a", 1 => "b"])', new BinaryNode('in', new ConstantNode('c'), $array)],
['!in_array("c", [0 => "a", 1 => "b"])', new BinaryNode('not in', new ConstantNode('c'), $array)],
['!in_array("a", [0 => "a", 1 => "b"])', new BinaryNode('not in', new ConstantNode('a'), $array)],
['range(1, 3)', new BinaryNode('..', new ConstantNode(1), new ConstantNode(3))],
['preg_match("/^[a-z]+/i\$/", "abc")', new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('/^[a-z]+/i$/'))],
];
}
public function getDumpData()
{
$array = new ArrayNode();
$array->addElement(new ConstantNode('a'));
$array->addElement(new ConstantNode('b'));
return [
['(true or false)', new BinaryNode('or', new ConstantNode(true), new ConstantNode(false))],
['(true || false)', new BinaryNode('||', new ConstantNode(true), new ConstantNode(false))],
['(true and false)', new BinaryNode('and', new ConstantNode(true), new ConstantNode(false))],
['(true && false)', new BinaryNode('&&', new ConstantNode(true), new ConstantNode(false))],
['(2 & 4)', new BinaryNode('&', new ConstantNode(2), new ConstantNode(4))],
['(2 | 4)', new BinaryNode('|', new ConstantNode(2), new ConstantNode(4))],
['(2 ^ 4)', new BinaryNode('^', new ConstantNode(2), new ConstantNode(4))],
['(1 < 2)', new BinaryNode('<', new ConstantNode(1), new ConstantNode(2))],
['(1 <= 2)', new BinaryNode('<=', new ConstantNode(1), new ConstantNode(2))],
['(1 <= 1)', new BinaryNode('<=', new ConstantNode(1), new ConstantNode(1))],
['(1 > 2)', new BinaryNode('>', new ConstantNode(1), new ConstantNode(2))],
['(1 >= 2)', new BinaryNode('>=', new ConstantNode(1), new ConstantNode(2))],
['(1 >= 1)', new BinaryNode('>=', new ConstantNode(1), new ConstantNode(1))],
['(true === true)', new BinaryNode('===', new ConstantNode(true), new ConstantNode(true))],
['(true !== true)', new BinaryNode('!==', new ConstantNode(true), new ConstantNode(true))],
['(2 == 1)', new BinaryNode('==', new ConstantNode(2), new ConstantNode(1))],
['(2 != 1)', new BinaryNode('!=', new ConstantNode(2), new ConstantNode(1))],
['(1 - 2)', new BinaryNode('-', new ConstantNode(1), new ConstantNode(2))],
['(1 + 2)', new BinaryNode('+', new ConstantNode(1), new ConstantNode(2))],
['(2 * 2)', new BinaryNode('*', new ConstantNode(2), new ConstantNode(2))],
['(2 / 2)', new BinaryNode('/', new ConstantNode(2), new ConstantNode(2))],
['(5 % 2)', new BinaryNode('%', new ConstantNode(5), new ConstantNode(2))],
['(5 ** 2)', new BinaryNode('**', new ConstantNode(5), new ConstantNode(2))],
['("a" ~ "b")', new BinaryNode('~', new ConstantNode('a'), new ConstantNode('b'))],
['("a" in ["a", "b"])', new BinaryNode('in', new ConstantNode('a'), $array)],
['("c" in ["a", "b"])', new BinaryNode('in', new ConstantNode('c'), $array)],
['("c" not in ["a", "b"])', new BinaryNode('not in', new ConstantNode('c'), $array)],
['("a" not in ["a", "b"])', new BinaryNode('not in', new ConstantNode('a'), $array)],
['(1 .. 3)', new BinaryNode('..', new ConstantNode(1), new ConstantNode(3))],
['("abc" matches "/^[a-z]+/i$/")', new BinaryNode('matches', new ConstantNode('abc'), new ConstantNode('/^[a-z]+/i$/'))],
];
}
}
@@ -1,42 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests\Node;
use Symfony\Component\ExpressionLanguage\Node\ConditionalNode;
use Symfony\Component\ExpressionLanguage\Node\ConstantNode;
class ConditionalNodeTest extends AbstractNodeTest
{
public function getEvaluateData()
{
return [
[1, new ConditionalNode(new ConstantNode(true), new ConstantNode(1), new ConstantNode(2))],
[2, new ConditionalNode(new ConstantNode(false), new ConstantNode(1), new ConstantNode(2))],
];
}
public function getCompileData()
{
return [
['((true) ? (1) : (2))', new ConditionalNode(new ConstantNode(true), new ConstantNode(1), new ConstantNode(2))],
['((false) ? (1) : (2))', new ConditionalNode(new ConstantNode(false), new ConstantNode(1), new ConstantNode(2))],
];
}
public function getDumpData()
{
return [
['(true ? 1 : 2)', new ConditionalNode(new ConstantNode(true), new ConstantNode(1), new ConstantNode(2))],
['(false ? 1 : 2)', new ConditionalNode(new ConstantNode(false), new ConstantNode(1), new ConstantNode(2))],
];
}
}
@@ -1,60 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests\Node;
use Symfony\Component\ExpressionLanguage\Node\ConstantNode;
class ConstantNodeTest extends AbstractNodeTest
{
public function getEvaluateData()
{
return [
[false, new ConstantNode(false)],
[true, new ConstantNode(true)],
[null, new ConstantNode(null)],
[3, new ConstantNode(3)],
[3.3, new ConstantNode(3.3)],
['foo', new ConstantNode('foo')],
[[1, 'b' => 'a'], new ConstantNode([1, 'b' => 'a'])],
];
}
public function getCompileData()
{
return [
['false', new ConstantNode(false)],
['true', new ConstantNode(true)],
['null', new ConstantNode(null)],
['3', new ConstantNode(3)],
['3.3', new ConstantNode(3.3)],
['"foo"', new ConstantNode('foo')],
['[0 => 1, "b" => "a"]', new ConstantNode([1, 'b' => 'a'])],
];
}
public function getDumpData()
{
return [
['false', new ConstantNode(false)],
['true', new ConstantNode(true)],
['null', new ConstantNode(null)],
['3', new ConstantNode(3)],
['3.3', new ConstantNode(3.3)],
['"foo"', new ConstantNode('foo')],
['foo', new ConstantNode('foo', true)],
['{0: 1, "b": "a", 1: true}', new ConstantNode([1, 'b' => 'a', true])],
['{"a\\"b": "c", "a\\\\b": "d"}', new ConstantNode(['a"b' => 'c', 'a\\b' => 'd'])],
['["c", "d"]', new ConstantNode(['c', 'd'])],
['{"a": ["b"]}', new ConstantNode(['a' => ['b']])],
];
}
}
@@ -1,52 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests\Node;
use Symfony\Component\ExpressionLanguage\Node\ConstantNode;
use Symfony\Component\ExpressionLanguage\Node\FunctionNode;
use Symfony\Component\ExpressionLanguage\Node\Node;
class FunctionNodeTest extends AbstractNodeTest
{
public function getEvaluateData()
{
return [
['bar', new FunctionNode('foo', new Node([new ConstantNode('bar')])), [], ['foo' => $this->getCallables()]],
];
}
public function getCompileData()
{
return [
['foo("bar")', new FunctionNode('foo', new Node([new ConstantNode('bar')])), ['foo' => $this->getCallables()]],
];
}
public function getDumpData()
{
return [
['foo("bar")', new FunctionNode('foo', new Node([new ConstantNode('bar')])), ['foo' => $this->getCallables()]],
];
}
protected function getCallables()
{
return [
'compiler' => function ($arg) {
return sprintf('foo(%s)', $arg);
},
'evaluator' => function ($variables, $arg) {
return $arg;
},
];
}
}
@@ -1,78 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests\Node;
use Symfony\Component\ExpressionLanguage\Node\ArrayNode;
use Symfony\Component\ExpressionLanguage\Node\ConstantNode;
use Symfony\Component\ExpressionLanguage\Node\GetAttrNode;
use Symfony\Component\ExpressionLanguage\Node\NameNode;
class GetAttrNodeTest extends AbstractNodeTest
{
public function getEvaluateData()
{
return [
['b', new GetAttrNode(new NameNode('foo'), new ConstantNode(0), $this->getArrayNode(), GetAttrNode::ARRAY_CALL), ['foo' => ['b' => 'a', 'b']]],
['a', new GetAttrNode(new NameNode('foo'), new ConstantNode('b'), $this->getArrayNode(), GetAttrNode::ARRAY_CALL), ['foo' => ['b' => 'a', 'b']]],
['bar', new GetAttrNode(new NameNode('foo'), new ConstantNode('foo'), $this->getArrayNode(), GetAttrNode::PROPERTY_CALL), ['foo' => new Obj()]],
['baz', new GetAttrNode(new NameNode('foo'), new ConstantNode('foo'), $this->getArrayNode(), GetAttrNode::METHOD_CALL), ['foo' => new Obj()]],
['a', new GetAttrNode(new NameNode('foo'), new NameNode('index'), $this->getArrayNode(), GetAttrNode::ARRAY_CALL), ['foo' => ['b' => 'a', 'b'], 'index' => 'b']],
];
}
public function getCompileData()
{
return [
['$foo[0]', new GetAttrNode(new NameNode('foo'), new ConstantNode(0), $this->getArrayNode(), GetAttrNode::ARRAY_CALL)],
['$foo["b"]', new GetAttrNode(new NameNode('foo'), new ConstantNode('b'), $this->getArrayNode(), GetAttrNode::ARRAY_CALL)],
['$foo->foo', new GetAttrNode(new NameNode('foo'), new ConstantNode('foo'), $this->getArrayNode(), GetAttrNode::PROPERTY_CALL), ['foo' => new Obj()]],
['$foo->foo(["b" => "a", 0 => "b"])', new GetAttrNode(new NameNode('foo'), new ConstantNode('foo'), $this->getArrayNode(), GetAttrNode::METHOD_CALL), ['foo' => new Obj()]],
['$foo[$index]', new GetAttrNode(new NameNode('foo'), new NameNode('index'), $this->getArrayNode(), GetAttrNode::ARRAY_CALL)],
];
}
public function getDumpData()
{
return [
['foo[0]', new GetAttrNode(new NameNode('foo'), new ConstantNode(0), $this->getArrayNode(), GetAttrNode::ARRAY_CALL)],
['foo["b"]', new GetAttrNode(new NameNode('foo'), new ConstantNode('b'), $this->getArrayNode(), GetAttrNode::ARRAY_CALL)],
['foo.foo', new GetAttrNode(new NameNode('foo'), new NameNode('foo'), $this->getArrayNode(), GetAttrNode::PROPERTY_CALL), ['foo' => new Obj()]],
['foo.foo({"b": "a", 0: "b"})', new GetAttrNode(new NameNode('foo'), new NameNode('foo'), $this->getArrayNode(), GetAttrNode::METHOD_CALL), ['foo' => new Obj()]],
['foo[index]', new GetAttrNode(new NameNode('foo'), new NameNode('index'), $this->getArrayNode(), GetAttrNode::ARRAY_CALL)],
];
}
protected function getArrayNode()
{
$array = new ArrayNode();
$array->addElement(new ConstantNode('a'), new ConstantNode('b'));
$array->addElement(new ConstantNode('b'));
return $array;
}
}
class Obj
{
public $foo = 'bar';
public function foo()
{
return 'baz';
}
}
@@ -1,38 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests\Node;
use Symfony\Component\ExpressionLanguage\Node\NameNode;
class NameNodeTest extends AbstractNodeTest
{
public function getEvaluateData()
{
return [
['bar', new NameNode('foo'), ['foo' => 'bar']],
];
}
public function getCompileData()
{
return [
['$foo', new NameNode('foo')],
];
}
public function getDumpData()
{
return [
['foo', new NameNode('foo')],
];
}
}
@@ -1,41 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests\Node;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ExpressionLanguage\Node\ConstantNode;
use Symfony\Component\ExpressionLanguage\Node\Node;
class NodeTest extends TestCase
{
public function testToString()
{
$node = new Node([new ConstantNode('foo')]);
$this->assertEquals(<<<'EOF'
Node(
ConstantNode(value: 'foo')
)
EOF
, (string) $node);
}
public function testSerialization()
{
$node = new Node(['foo' => 'bar'], ['bar' => 'foo']);
$serializedNode = serialize($node);
$unserializedNode = unserialize($serializedNode);
$this->assertEquals($node, $unserializedNode);
}
}
@@ -1,48 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests\Node;
use Symfony\Component\ExpressionLanguage\Node\ConstantNode;
use Symfony\Component\ExpressionLanguage\Node\UnaryNode;
class UnaryNodeTest extends AbstractNodeTest
{
public function getEvaluateData()
{
return [
[-1, new UnaryNode('-', new ConstantNode(1))],
[3, new UnaryNode('+', new ConstantNode(3))],
[false, new UnaryNode('!', new ConstantNode(true))],
[false, new UnaryNode('not', new ConstantNode(true))],
];
}
public function getCompileData()
{
return [
['(-1)', new UnaryNode('-', new ConstantNode(1))],
['(+3)', new UnaryNode('+', new ConstantNode(3))],
['(!true)', new UnaryNode('!', new ConstantNode(true))],
['(!true)', new UnaryNode('not', new ConstantNode(true))],
];
}
public function getDumpData()
{
return [
['(- 1)', new UnaryNode('-', new ConstantNode(1))],
['(+ 3)', new UnaryNode('+', new ConstantNode(3))],
['(! true)', new UnaryNode('!', new ConstantNode(true))],
['(not true)', new UnaryNode('not', new ConstantNode(true))],
];
}
}
@@ -1,29 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ExpressionLanguage\Node\ConstantNode;
use Symfony\Component\ExpressionLanguage\ParsedExpression;
class ParsedExpressionTest extends TestCase
{
public function testSerialization()
{
$expression = new ParsedExpression('25', new ConstantNode('25'));
$serializedExpression = serialize($expression);
$unserializedExpression = unserialize($serializedExpression);
$this->assertEquals($expression, $unserializedExpression);
}
}
@@ -1,140 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ExpressionLanguage\Node\Node;
use Symfony\Component\ExpressionLanguage\ParsedExpression;
use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheAdapter;
/**
* @group legacy
*/
class ParserCacheAdapterTest extends TestCase
{
public function testGetItem()
{
$poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock();
$key = 'key';
$value = 'value';
$parserCacheAdapter = new ParserCacheAdapter($poolMock);
$poolMock
->expects($this->once())
->method('fetch')
->with($key)
->willReturn($value)
;
$cacheItem = $parserCacheAdapter->getItem($key);
$this->assertEquals($value, $cacheItem->get());
$this->assertTrue($cacheItem->isHit());
}
public function testSave()
{
$poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock();
$cacheItemMock = $this->getMockBuilder('Psr\Cache\CacheItemInterface')->getMock();
$key = 'key';
$value = new ParsedExpression('1 + 1', new Node([], []));
$parserCacheAdapter = new ParserCacheAdapter($poolMock);
$poolMock
->expects($this->once())
->method('save')
->with($key, $value)
;
$cacheItemMock
->expects($this->once())
->method('getKey')
->willReturn($key)
;
$cacheItemMock
->expects($this->once())
->method('get')
->willReturn($value)
;
$parserCacheAdapter->save($cacheItemMock);
}
public function testGetItems()
{
$poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock();
$parserCacheAdapter = new ParserCacheAdapter($poolMock);
$this->expectException(\BadMethodCallException::class);
$parserCacheAdapter->getItems();
}
public function testHasItem()
{
$poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock();
$key = 'key';
$parserCacheAdapter = new ParserCacheAdapter($poolMock);
$this->expectException(\BadMethodCallException::class);
$parserCacheAdapter->hasItem($key);
}
public function testClear()
{
$poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock();
$parserCacheAdapter = new ParserCacheAdapter($poolMock);
$this->expectException(\BadMethodCallException::class);
$parserCacheAdapter->clear();
}
public function testDeleteItem()
{
$poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock();
$key = 'key';
$parserCacheAdapter = new ParserCacheAdapter($poolMock);
$this->expectException(\BadMethodCallException::class);
$parserCacheAdapter->deleteItem($key);
}
public function testDeleteItems()
{
$poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock();
$keys = ['key'];
$parserCacheAdapter = new ParserCacheAdapter($poolMock);
$this->expectException(\BadMethodCallException::class);
$parserCacheAdapter->deleteItems($keys);
}
public function testSaveDeferred()
{
$poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock();
$parserCacheAdapter = new ParserCacheAdapter($poolMock);
$cacheItemMock = $this->getMockBuilder('Psr\Cache\CacheItemInterface')->getMock();
$this->expectException(\BadMethodCallException::class);
$parserCacheAdapter->saveDeferred($cacheItemMock);
}
public function testCommit()
{
$poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock();
$parserCacheAdapter = new ParserCacheAdapter($poolMock);
$this->expectException(\BadMethodCallException::class);
$parserCacheAdapter->commit();
}
}
-237
View File
@@ -1,237 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ExpressionLanguage\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ExpressionLanguage\Lexer;
use Symfony\Component\ExpressionLanguage\Node;
use Symfony\Component\ExpressionLanguage\Parser;
class ParserTest extends TestCase
{
public function testParseWithInvalidName()
{
$this->expectException('Symfony\Component\ExpressionLanguage\SyntaxError');
$this->expectExceptionMessage('Variable "foo" is not valid around position 1 for expression `foo`.');
$lexer = new Lexer();
$parser = new Parser([]);
$parser->parse($lexer->tokenize('foo'));
}
public function testParseWithZeroInNames()
{
$this->expectException('Symfony\Component\ExpressionLanguage\SyntaxError');
$this->expectExceptionMessage('Variable "foo" is not valid around position 1 for expression `foo`.');
$lexer = new Lexer();
$parser = new Parser([]);
$parser->parse($lexer->tokenize('foo'), [0]);
}
/**
* @dataProvider getParseData
*/
public function testParse($node, $expression, $names = [])
{
$lexer = new Lexer();
$parser = new Parser([]);
$this->assertEquals($node, $parser->parse($lexer->tokenize($expression), $names));
}
public function getParseData()
{
$arguments = new Node\ArgumentsNode();
$arguments->addElement(new Node\ConstantNode('arg1'));
$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'),
'a',
['a'],
],
[
new Node\ConstantNode('a'),
'"a"',
],
[
new Node\ConstantNode(3),
'3',
],
[
new Node\ConstantNode(false),
'false',
],
[
new Node\ConstantNode(true),
'true',
],
[
new Node\ConstantNode(null),
'null',
],
[
new Node\UnaryNode('-', new Node\ConstantNode(3)),
'-3',
],
[
new Node\BinaryNode('-', new Node\ConstantNode(3), new Node\ConstantNode(3)),
'3 - 3',
],
[
new Node\BinaryNode('*',
new Node\BinaryNode('-', new Node\ConstantNode(3), new Node\ConstantNode(3)),
new Node\ConstantNode(2)
),
'(3 - 3) * 2',
],
[
new Node\GetAttrNode(new Node\NameNode('foo'), new Node\ConstantNode('bar', true), new Node\ArgumentsNode(), Node\GetAttrNode::PROPERTY_CALL),
'foo.bar',
['foo'],
],
[
new Node\GetAttrNode(new Node\NameNode('foo'), new Node\ConstantNode('bar', true), new Node\ArgumentsNode(), Node\GetAttrNode::METHOD_CALL),
'foo.bar()',
['foo'],
],
[
new Node\GetAttrNode(new Node\NameNode('foo'), new Node\ConstantNode('not', true), new Node\ArgumentsNode(), Node\GetAttrNode::METHOD_CALL),
'foo.not()',
['foo'],
],
[
new Node\GetAttrNode(
new Node\NameNode('foo'),
new Node\ConstantNode('bar', true),
$arguments,
Node\GetAttrNode::METHOD_CALL
),
'foo.bar("arg1", 2, true)',
['foo'],
],
[
new Node\GetAttrNode(new Node\NameNode('foo'), new Node\ConstantNode(3), new Node\ArgumentsNode(), Node\GetAttrNode::ARRAY_CALL),
'foo[3]',
['foo'],
],
[
new Node\ConditionalNode(new Node\ConstantNode(true), new Node\ConstantNode(true), new Node\ConstantNode(false)),
'true ? true : false',
],
[
new Node\BinaryNode('matches', new Node\ConstantNode('foo'), new Node\ConstantNode('/foo/')),
'"foo" matches "/foo/"',
],
// chained calls
[
$this->createGetAttrNode(
$this->createGetAttrNode(
$this->createGetAttrNode(
$this->createGetAttrNode(new Node\NameNode('foo'), 'bar', Node\GetAttrNode::METHOD_CALL),
'foo', Node\GetAttrNode::METHOD_CALL),
'baz', Node\GetAttrNode::PROPERTY_CALL),
'3', Node\GetAttrNode::ARRAY_CALL),
'foo.bar().foo().baz[3]',
['foo'],
],
[
new Node\NameNode('foo'),
'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'],
],
];
}
private function createGetAttrNode($node, $item, $type)
{
return new Node\GetAttrNode($node, new Node\ConstantNode($item, Node\GetAttrNode::ARRAY_CALL !== $type), new Node\ArgumentsNode(), $type);
}
/**
* @dataProvider getInvalidPostfixData
*/
public function testParseWithInvalidPostfixData($expr, $names = [])
{
$this->expectException('Symfony\Component\ExpressionLanguage\SyntaxError');
$lexer = new Lexer();
$parser = new Parser([]);
$parser->parse($lexer->tokenize($expr), $names);
}
public function getInvalidPostfixData()
{
return [
[
'foo."#"',
['foo'],
],
[
'foo."bar"',
['foo'],
],
[
'foo.**',
['foo'],
],
[
'foo.123',
['foo'],
],
];
}
public function testNameProposal()
{
$this->expectException('Symfony\Component\ExpressionLanguage\SyntaxError');
$this->expectExceptionMessage('Did you mean "baz"?');
$lexer = new Lexer();
$parser = new Parser([]);
$parser->parse($lexer->tokenize('foo > bar'), ['foo', 'baz']);
}
}
+7 -7
View File
@@ -22,19 +22,19 @@ class Token
public $type;
public $cursor;
const EOF_TYPE = 'end of expression';
const NAME_TYPE = 'name';
const NUMBER_TYPE = 'number';
const STRING_TYPE = 'string';
const OPERATOR_TYPE = 'operator';
const PUNCTUATION_TYPE = 'punctuation';
public const EOF_TYPE = 'end of expression';
public const NAME_TYPE = 'name';
public const NUMBER_TYPE = 'number';
public const STRING_TYPE = 'string';
public const OPERATOR_TYPE = 'operator';
public const PUNCTUATION_TYPE = 'punctuation';
/**
* @param string $type The type of the token (self::*_TYPE)
* @param string|int|float|null $value The token value
* @param int $cursor The cursor position in the source
*/
public function __construct($type, $value, $cursor)
public function __construct(string $type, $value, ?int $cursor)
{
$this->type = $type;
$this->value = $value;
+2 -8
View File
@@ -24,11 +24,7 @@ class TokenStream
private $position = 0;
private $expression;
/**
* @param array $tokens An array of tokens
* @param string $expression
*/
public function __construct(array $tokens, $expression = '')
public function __construct(array $tokens, string $expression = '')
{
$this->tokens = $tokens;
$this->current = $tokens[0];
@@ -87,10 +83,8 @@ class TokenStream
/**
* @internal
*
* @return string
*/
public function getExpression()
public function getExpression(): string
{
return $this->expression;
}
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "symfony/expression-language",
"type": "library",
"description": "Symfony ExpressionLanguage Component",
"description": "Provides an engine that can compile and evaluate expressions",
"keywords": [],
"homepage": "https://symfony.com",
"license": "MIT",
@@ -16,9 +16,9 @@
}
],
"require": {
"php": "^5.5.9|>=7.0.8",
"symfony/cache": "~3.1|~4.0",
"symfony/polyfill-php70": "~1.6"
"php": ">=7.1.3",
"symfony/cache": "^3.4|^4.0|^5.0",
"symfony/service-contracts": "^1.1|^2"
},
"autoload": {
"psr-4": { "Symfony\\Component\\ExpressionLanguage\\": "" },
-30
View File
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
>
<php>
<ini name="error_reporting" value="-1" />
</php>
<testsuites>
<testsuite name="Symfony ExpressionLanguage Component Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>