diff --git a/src/ExpressionParser.php b/src/ExpressionParser.php index 8bd7d74f0..ce925a029 100644 --- a/src/ExpressionParser.php +++ b/src/ExpressionParser.php @@ -23,7 +23,6 @@ use Twig\Node\Expression\ConditionalExpression; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\GetAttrExpression; use Twig\Node\Expression\MacroReferenceExpression; -use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\TestExpression; use Twig\Node\Expression\Unary\AbstractUnary; use Twig\Node\Expression\Unary\NegUnary; @@ -592,7 +591,7 @@ class ExpressionParser $name = null; if (($token = $stream->nextIf(Token::OPERATOR_TYPE, '=')) || ($token = $stream->nextIf(Token::PUNCTUATION_TYPE, ':'))) { - if (!$value instanceof NameExpression) { + if (!$value instanceof ContextVariable) { throw new SyntaxError(\sprintf('A parameter name must be a string, "%s" given.', $value::class), $token->getLine(), $stream->getSourceContext()); } $name = $value->getAttribute('name'); @@ -662,7 +661,7 @@ class ExpressionParser $arguments = new Nodes([0 => $this->getPrimary()]); } - if ('defined' === $test->getName() && $node instanceof NameExpression && null !== $alias = $this->parser->getImportedSymbol('function', $node->getAttribute('name'))) { + if ('defined' === $test->getName() && $node instanceof ContextVariable && null !== $alias = $this->parser->getImportedSymbol('function', $node->getAttribute('name'))) { $node = new MacroReferenceExpression(new TemplateVariable($alias['node']->getAttribute('name'), $node->getTemplateLine()), $alias['name'], new ArrayExpression([], $node->getTemplateLine()), $node->getTemplateLine()); } @@ -789,7 +788,7 @@ class ExpressionParser $name = null; if (($token = $stream->nextIf(Token::OPERATOR_TYPE, '=')) || ($token = $stream->nextIf(Token::PUNCTUATION_TYPE, ':'))) { - if (!$value instanceof NameExpression) { + if (!$value instanceof ContextVariable) { throw new SyntaxError(\sprintf('A parameter name must be a string, "%s" given.', \get_class($value)), $token->getLine(), $stream->getSourceContext()); } $name = $value->getAttribute('name'); @@ -839,7 +838,7 @@ class ExpressionParser } if ( - $node instanceof NameExpression + $node instanceof ContextVariable && ( null !== $this->parser->getImportedSymbol('template', (new TemplateVariable($node->getAttribute('name'), $node->getTemplateLine()))->getAttribute('name')) diff --git a/src/Extension/CoreExtension.php b/src/Extension/CoreExtension.php index 5798280d4..e8efa114a 100644 --- a/src/Extension/CoreExtension.php +++ b/src/Extension/CoreExtension.php @@ -56,7 +56,6 @@ use Twig\Node\Expression\Filter\RawFilter; use Twig\Node\Expression\FunctionNode\EnumCasesFunction; use Twig\Node\Expression\FunctionNode\EnumFunction; use Twig\Node\Expression\GetAttrExpression; -use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\NullCoalesceExpression; use Twig\Node\Expression\ParentExpression; use Twig\Node\Expression\Test\ConstantTest; @@ -69,8 +68,8 @@ use Twig\Node\Expression\Test\SameasTest; use Twig\Node\Expression\Unary\NegUnary; use Twig\Node\Expression\Unary\NotUnary; use Twig\Node\Expression\Unary\PosUnary; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; -use Twig\OperatorPrecedenceChange; use Twig\Parser; use Twig\Source; use Twig\Template; @@ -1937,7 +1936,7 @@ final class CoreExtension extends AbstractExtension $args = (new CallableArgumentsExtractor($fakeNode, $fakeFunction))->extractArguments($args); $recurseArgs = new ArrayExpression([new ConstantExpression(0, $line), $args[0]], $line); - $expr = new GetAttrExpression(new NameExpression('loop', $line), new ConstantExpression('__invoke', $line), $recurseArgs, Template::METHOD_CALL, $line); + $expr = new GetAttrExpression(new ContextVariable('loop', $line), new ConstantExpression('__invoke', $line), $recurseArgs, Template::METHOD_CALL, $line); $expr->setAttribute('is_generator', true); $expr = new RawFilter($expr); $expr->setAttribute('is_generator', true); diff --git a/src/Node/Expression/ArrayExpression.php b/src/Node/Expression/ArrayExpression.php index 783c25d0d..57be4dc6a 100644 --- a/src/Node/Expression/ArrayExpression.php +++ b/src/Node/Expression/ArrayExpression.php @@ -13,6 +13,8 @@ namespace Twig\Node\Expression; use Twig\Compiler; use Twig\Node\Expression\Unary\StringCastUnary; +use Twig\Node\Expression\Variable\ContextVariable; +use Twig\Node\Expression\Variable\LocalVariable; class ArrayExpression extends AbstractExpression { @@ -77,10 +79,10 @@ class ArrayExpression extends AbstractExpression $first = false; $key = null; - if ($pair['key'] instanceof NameExpression) { + if ($pair['key'] instanceof ContextVariable) { $pair['key'] = new StringCastUnary($pair['key'], $pair['key']->getTemplateLine()); } - if ($pair['key'] instanceof TempNameExpression) { + if ($pair['key'] instanceof LocalVariable) { $key = $pair['key']->getAttribute('name'); $pair['key'] = new ConstantExpression($key, $pair['key']->getTemplateLine()); } diff --git a/src/Node/Expression/AssignNameExpression.php b/src/Node/Expression/AssignNameExpression.php deleted file mode 100644 index c2cbb8e4a..000000000 --- a/src/Node/Expression/AssignNameExpression.php +++ /dev/null @@ -1,43 +0,0 @@ -raw('$context[') - ->string($this->getAttribute('name')) - ->raw(']') - ; - } -} diff --git a/src/Node/Expression/Filter/DefaultFilter.php b/src/Node/Expression/Filter/DefaultFilter.php index e81da7632..be06b902b 100644 --- a/src/Node/Expression/Filter/DefaultFilter.php +++ b/src/Node/Expression/Filter/DefaultFilter.php @@ -19,8 +19,8 @@ use Twig\Node\Expression\ConditionalExpression; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\FilterExpression; use Twig\Node\Expression\GetAttrExpression; -use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\Test\DefinedTest; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; use Twig\TwigFilter; use Twig\TwigTest; @@ -40,7 +40,7 @@ class DefaultFilter extends FilterExpression $name = $filter->getName(); $default = new FilterExpression($node, $filter, $arguments, $node->getTemplateLine()); - if ('default' === $name && ($node instanceof NameExpression || $node instanceof GetAttrExpression)) { + if ('default' === $name && ($node instanceof ContextVariable || $node instanceof GetAttrExpression)) { $test = new DefinedTest(clone $node, new TwigTest('defined'), new EmptyNode(), $node->getTemplateLine()); $false = \count($arguments) ? $arguments->getNode(0) : new ConstantExpression('', $node->getTemplateLine()); diff --git a/src/Node/Expression/GetAttrExpression.php b/src/Node/Expression/GetAttrExpression.php index 33edff383..77756dff4 100644 --- a/src/Node/Expression/GetAttrExpression.php +++ b/src/Node/Expression/GetAttrExpression.php @@ -14,11 +14,12 @@ namespace Twig\Node\Expression; use Twig\Compiler; use Twig\Extension\SandboxExtension; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Template; class GetAttrExpression extends AbstractExpression { - public function __construct(AbstractExpression $node, AbstractExpression $attribute, ArrayExpression|NameExpression|null $arguments, string $type, int $lineno) + public function __construct(AbstractExpression $node, AbstractExpression $attribute, ArrayExpression|ContextVariable|null $arguments, string $type, int $lineno) { $nodes = ['node' => $node, 'attribute' => $attribute]; if (null !== $arguments) { diff --git a/src/Node/Expression/NameExpression.php b/src/Node/Expression/NameExpression.php deleted file mode 100644 index 975ebcc06..000000000 --- a/src/Node/Expression/NameExpression.php +++ /dev/null @@ -1,85 +0,0 @@ - '$this->getTemplateName()', - '_context' => '$context', - '_charset' => '$this->env->getCharset()', - ]; - - public function __construct(string $name, int $lineno) - { - if (self::class === static::class) { - trigger_deprecation('twig/twig', '3.15', 'The "%s" class is deprecated, use "%s" instead.', self::class, ContextVariable::class); - } - - parent::__construct([], ['name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false], $lineno); - } - - public function compile(Compiler $compiler): void - { - $name = $this->getAttribute('name'); - - $compiler->addDebugInfo($this); - - if ($this->getAttribute('is_defined_test')) { - if (isset($this->specialVars[$name])) { - $compiler->repr(true); - } else { - $compiler - ->raw('array_key_exists(') - ->string($name) - ->raw(', $context)') - ; - } - } elseif (isset($this->specialVars[$name])) { - $compiler->raw($this->specialVars[$name]); - } elseif ($this->getAttribute('always_defined')) { - $compiler - ->raw('$context[') - ->string($name) - ->raw(']') - ; - } else { - if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) { - $compiler - ->raw('($context[') - ->string($name) - ->raw('] ?? null)') - ; - } else { - $compiler - ->raw('(array_key_exists(') - ->string($name) - ->raw(', $context) ?') - ; - $compiler - ->raw(' $context[') - ->string($name) - ->raw('] : throw new RuntimeError(\'Variable ') - ->string($name) - ->raw(' does not exist.\', ') - ->repr($this->lineno) - ->raw(', $this->source)') - ->raw(')') - ; - } - } - } -} diff --git a/src/Node/Expression/NullCoalesceExpression.php b/src/Node/Expression/NullCoalesceExpression.php index 1a954ae7e..adbcea63d 100644 --- a/src/Node/Expression/NullCoalesceExpression.php +++ b/src/Node/Expression/NullCoalesceExpression.php @@ -17,6 +17,7 @@ use Twig\Node\Expression\Binary\AndBinary; use Twig\Node\Expression\Test\DefinedTest; use Twig\Node\Expression\Test\NullTest; use Twig\Node\Expression\Unary\NotUnary; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\TwigTest; class NullCoalesceExpression extends ConditionalExpression @@ -45,7 +46,7 @@ class NullCoalesceExpression extends ConditionalExpression * cases might be implemented as an optimizer node visitor, but has not been done * as benefits are probably not worth the added complexity. */ - if ($this->getNode('expr2') instanceof NameExpression) { + if ($this->getNode('expr2') instanceof ContextVariable) { $this->getNode('expr2')->setAttribute('always_defined', true); $compiler ->raw('((') diff --git a/src/Node/Expression/TempNameExpression.php b/src/Node/Expression/TempNameExpression.php deleted file mode 100644 index bf304a98c..000000000 --- a/src/Node/Expression/TempNameExpression.php +++ /dev/null @@ -1,49 +0,0 @@ - $name], $lineno); - } - - public function compile(Compiler $compiler): void - { - if (null === $this->getAttribute('name')) { - $this->setAttribute('name', \sprintf('_l%d', $compiler->getVarName())); - } - - $compiler->raw('$'.$this->getAttribute('name')); - } -} diff --git a/src/Node/Expression/Test/DefinedTest.php b/src/Node/Expression/Test/DefinedTest.php index b2559e6d1..57b1532a7 100644 --- a/src/Node/Expression/Test/DefinedTest.php +++ b/src/Node/Expression/Test/DefinedTest.php @@ -21,8 +21,8 @@ use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\FunctionExpression; use Twig\Node\Expression\GetAttrExpression; use Twig\Node\Expression\MacroReferenceExpression; -use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\TestExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; use Twig\TwigTest; @@ -41,7 +41,7 @@ class DefinedTest extends TestExpression #[FirstClassTwigCallableReady] public function __construct(AbstractExpression $node, TwigTest $name, ?Node $arguments, int $lineno) { - if ($node instanceof NameExpression) { + if ($node instanceof ContextVariable) { $node->setAttribute('is_defined_test', true); } elseif ($node instanceof GetAttrExpression) { $node->setAttribute('is_defined_test', true); diff --git a/src/Node/Expression/Variable/AssignContextVariable.php b/src/Node/Expression/Variable/AssignContextVariable.php index 30d810675..36dca76a7 100644 --- a/src/Node/Expression/Variable/AssignContextVariable.php +++ b/src/Node/Expression/Variable/AssignContextVariable.php @@ -11,8 +11,28 @@ namespace Twig\Node\Expression\Variable; -use Twig\Node\Expression\AssignNameExpression; +use Twig\Compiler; +use Twig\Error\SyntaxError; +use Twig\Node\Expression\Variable\ContextVariable; -final class AssignContextVariable extends AssignNameExpression +final class AssignContextVariable extends ContextVariable { + public function __construct(string $name, int $lineno) + { + // All names supported by ExpressionParser::parsePrimaryExpression() should be excluded + if (\in_array(strtolower($name), ['true', 'false', 'none', 'null'])) { + throw new SyntaxError(\sprintf('You cannot assign a value to "%s".', $name), $lineno); + } + + parent::__construct($name, $lineno); + } + + public function compile(Compiler $compiler): void + { + $compiler + ->raw('$context[') + ->string($this->getAttribute('name')) + ->raw(']') + ; + } } diff --git a/src/Node/Expression/Variable/ContextVariable.php b/src/Node/Expression/Variable/ContextVariable.php index cabc16a43..733efcbe9 100644 --- a/src/Node/Expression/Variable/ContextVariable.php +++ b/src/Node/Expression/Variable/ContextVariable.php @@ -11,8 +11,70 @@ namespace Twig\Node\Expression\Variable; -use Twig\Node\Expression\NameExpression; +use Twig\Compiler; +use Twig\Node\Expression\AbstractExpression; -final class ContextVariable extends NameExpression +class ContextVariable extends AbstractExpression { + private array $specialVars = [ + '_self' => '$this->getTemplateName()', + '_context' => '$context', + '_charset' => '$this->env->getCharset()', + ]; + + public function __construct(string $name, int $lineno) + { + parent::__construct([], ['name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false], $lineno); + } + + public function compile(Compiler $compiler): void + { + $name = $this->getAttribute('name'); + + $compiler->addDebugInfo($this); + + if ($this->getAttribute('is_defined_test')) { + if (isset($this->specialVars[$name])) { + $compiler->repr(true); + } else { + $compiler + ->raw('array_key_exists(') + ->string($name) + ->raw(', $context)') + ; + } + } elseif (isset($this->specialVars[$name])) { + $compiler->raw($this->specialVars[$name]); + } elseif ($this->getAttribute('always_defined')) { + $compiler + ->raw('$context[') + ->string($name) + ->raw(']') + ; + } else { + if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) { + $compiler + ->raw('($context[') + ->string($name) + ->raw('] ?? null)') + ; + } else { + $compiler + ->raw('(array_key_exists(') + ->string($name) + ->raw(', $context) ?') + ; + $compiler + ->raw(' $context[') + ->string($name) + ->raw('] : throw new RuntimeError(\'Variable ') + ->string($name) + ->raw(' does not exist.\', ') + ->repr($this->lineno) + ->raw(', $this->source)') + ->raw(')') + ; + } + } + } } diff --git a/src/Node/Expression/Variable/LocalVariable.php b/src/Node/Expression/Variable/LocalVariable.php index a5ee17566..32e15f237 100644 --- a/src/Node/Expression/Variable/LocalVariable.php +++ b/src/Node/Expression/Variable/LocalVariable.php @@ -11,8 +11,36 @@ namespace Twig\Node\Expression\Variable; -use Twig\Node\Expression\TempNameExpression; +use Twig\Error\SyntaxError; +use Twig\Compiler; +use Twig\Node\Expression\AbstractExpression; -final class LocalVariable extends TempNameExpression +final class LocalVariable extends AbstractExpression { + public const RESERVED_NAMES = ['varargs', 'context', 'macros', 'blocks', 'this']; + + public function __construct(string|int|null $name, int $lineno) + { + // All names supported by ExpressionParser::parsePrimaryExpression() should be excluded + if ($name && \in_array(strtolower($name), ['true', 'false', 'none', 'null'])) { + throw new SyntaxError(\sprintf('You cannot assign a value to "%s".', $name), $lineno); + } + + if (null !== $name && (is_int($name) || ctype_digit($name))) { + $name = (int) $name; + } elseif (in_array($name, self::RESERVED_NAMES)) { + $name = '_'.$name.'_'; + } + + parent::__construct([], ['name' => $name], $lineno); + } + + public function compile(Compiler $compiler): void + { + if (null === $this->getAttribute('name')) { + $this->setAttribute('name', \sprintf('_l%d', $compiler->getVarName())); + } + + $compiler->raw('$'.$this->getAttribute('name')); + } } diff --git a/src/Node/Expression/Variable/TemplateVariable.php b/src/Node/Expression/Variable/TemplateVariable.php index e2a36eafa..33b08e85e 100644 --- a/src/Node/Expression/Variable/TemplateVariable.php +++ b/src/Node/Expression/Variable/TemplateVariable.php @@ -12,10 +12,29 @@ namespace Twig\Node\Expression\Variable; use Twig\Compiler; -use Twig\Node\Expression\TempNameExpression; +use Twig\Error\SyntaxError; +use Twig\Node\Expression\AbstractExpression; -class TemplateVariable extends TempNameExpression +class TemplateVariable extends AbstractExpression { + public const RESERVED_NAMES = ['varargs', 'context', 'macros', 'blocks', 'this']; + + public function __construct(string|int|null $name, int $lineno) + { + // All names supported by ExpressionParser::parsePrimaryExpression() should be excluded + if ($name && \in_array(strtolower($name), ['true', 'false', 'none', 'null'])) { + throw new SyntaxError(\sprintf('You cannot assign a value to "%s".', $name), $lineno); + } + + if (null !== $name && (is_int($name) || ctype_digit($name))) { + $name = (int) $name; + } elseif (in_array($name, self::RESERVED_NAMES)) { + $name = '_'.$name.'_'; + } + + parent::__construct([], ['name' => $name], $lineno); + } + public function compile(Compiler $compiler): void { if (null === $this->getAttribute('name')) { diff --git a/src/Node/ForNode.php b/src/Node/ForNode.php index 8aa5b5407..b3ca78707 100644 --- a/src/Node/ForNode.php +++ b/src/Node/ForNode.php @@ -15,7 +15,7 @@ namespace Twig\Node; use Twig\Attribute\YieldReady; use Twig\Compiler; use Twig\Node\Expression\AbstractExpression; -use Twig\Node\Expression\AssignNameExpression; +use Twig\Node\Expression\Variable\AssignContextVariable; /** * Represents a for node. @@ -25,7 +25,7 @@ use Twig\Node\Expression\AssignNameExpression; #[YieldReady] class ForNode extends Node { - public function __construct(AssignNameExpression $keyTarget, AssignNameExpression $valueTarget, AbstractExpression $seq, ?AbstractExpression $ifexpr, Node $body, ?Node $else, int $lineno) + public function __construct(AssignContextVariable $keyTarget, AssignContextVariable $valueTarget, AbstractExpression $seq, ?AbstractExpression $ifexpr, Node $body, ?Node $else, int $lineno) { if ($ifexpr) { $body = new IfNode(new Nodes([$ifexpr, $body]), null, $lineno); diff --git a/src/Node/ImportNode.php b/src/Node/ImportNode.php index a026ef27a..0443f657a 100644 --- a/src/Node/ImportNode.php +++ b/src/Node/ImportNode.php @@ -13,10 +13,9 @@ namespace Twig\Node; use Twig\Attribute\YieldReady; use Twig\Compiler; -use Twig\Error\SyntaxError; use Twig\Node\Expression\AbstractExpression; -use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\Variable\AssignTemplateVariable; +use Twig\Node\Expression\Variable\ContextVariable; /** * Represents an import node. @@ -26,18 +25,8 @@ use Twig\Node\Expression\Variable\AssignTemplateVariable; #[YieldReady] class ImportNode extends Node { - public function __construct(AbstractExpression $expr, AbstractExpression|AssignTemplateVariable $var, int $lineno) + public function __construct(AbstractExpression $expr, AssignTemplateVariable $var, int $lineno) { - if (!\is_bool(\func_num_args() > 3)) { - trigger_deprecation('twig/twig', '3.15', \sprintf('Passing more than 3 arguments to "%s()" is deprecated.', __METHOD__)); - } - - if (!$var instanceof AssignTemplateVariable) { - trigger_deprecation('twig/twig', '3.15', \sprintf('Passing a "%s" instance as the second argument of "%s" is deprecated, pass a "%s" instead.', $var::class, __CLASS__, AssignTemplateVariable::class)); - - $var = new AssignTemplateVariable($var->getAttribute('name'), $lineno); - } - parent::__construct(['expr' => $expr, 'var' => $var], [], $lineno); } @@ -45,7 +34,7 @@ class ImportNode extends Node { $compiler->subcompile($this->getNode('var')); - if ($this->getNode('expr') instanceof NameExpression && '_self' === $this->getNode('expr')->getAttribute('name')) { + if ($this->getNode('expr') instanceof ContextVariable && '_self' === $this->getNode('expr')->getAttribute('name')) { $compiler->raw('$this'); } else { $compiler diff --git a/src/NodeVisitor/OptimizerNodeVisitor.php b/src/NodeVisitor/OptimizerNodeVisitor.php index 2fb743ce1..74e72f863 100644 --- a/src/NodeVisitor/OptimizerNodeVisitor.php +++ b/src/NodeVisitor/OptimizerNodeVisitor.php @@ -17,8 +17,8 @@ use Twig\Node\Expression\BlockReferenceExpression; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\FunctionExpression; use Twig\Node\Expression\GetAttrExpression; -use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\ParentExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\ForNode; use Twig\Node\IncludeNode; use Twig\Node\Node; @@ -133,13 +133,13 @@ final class OptimizerNodeVisitor implements NodeVisitorInterface // when do we need to add the loop variable back? // the loop variable is referenced for the current loop - elseif ($node instanceof NameExpression && 'loop' === $node->getAttribute('name')) { + elseif ($node instanceof ContextVariable && 'loop' === $node->getAttribute('name')) { $node->setAttribute('always_defined', true); $this->addLoopToCurrent(); } // optimize access to loop targets - elseif ($node instanceof NameExpression && \in_array($node->getAttribute('name'), $this->loopsTargets)) { + elseif ($node instanceof ContextVariable && \in_array($node->getAttribute('name'), $this->loopsTargets)) { $node->setAttribute('always_defined', true); } @@ -169,7 +169,7 @@ final class OptimizerNodeVisitor implements NodeVisitorInterface || 'parent' === $node->getNode('attribute')->getAttribute('value') ) && (true === $this->loops[0]->getAttribute('with_loop') - || ($node->getNode('node') instanceof NameExpression + || ($node->getNode('node') instanceof ContextVariable && 'loop' === $node->getNode('node')->getAttribute('name') ) ) diff --git a/src/NodeVisitor/SafeAnalysisNodeVisitor.php b/src/NodeVisitor/SafeAnalysisNodeVisitor.php index 5793456b7..3e6a3f9b3 100644 --- a/src/NodeVisitor/SafeAnalysisNodeVisitor.php +++ b/src/NodeVisitor/SafeAnalysisNodeVisitor.php @@ -19,8 +19,8 @@ use Twig\Node\Expression\FilterExpression; use Twig\Node\Expression\FunctionExpression; use Twig\Node\Expression\GetAttrExpression; use Twig\Node\Expression\MacroReferenceExpression; -use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\ParentExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; /** @@ -115,7 +115,7 @@ final class SafeAnalysisNodeVisitor implements NodeVisitorInterface } elseif ($node instanceof MacroReferenceExpression) { // all macro calls are safe $this->setSafe($node, ['all']); - } elseif ($node instanceof GetAttrExpression && $node->getNode('node') instanceof NameExpression) { + } elseif ($node instanceof GetAttrExpression && $node->getNode('node') instanceof ContextVariable) { $name = $node->getNode('node')->getAttribute('name'); if (\in_array($name, $this->safeVars)) { $this->setSafe($node, ['all']); diff --git a/src/NodeVisitor/SandboxNodeVisitor.php b/src/NodeVisitor/SandboxNodeVisitor.php index fb5f9a105..45f7bbec7 100644 --- a/src/NodeVisitor/SandboxNodeVisitor.php +++ b/src/NodeVisitor/SandboxNodeVisitor.php @@ -20,7 +20,7 @@ use Twig\Node\Expression\Binary\RangeBinary; use Twig\Node\Expression\FilterExpression; use Twig\Node\Expression\FunctionExpression; use Twig\Node\Expression\GetAttrExpression; -use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\ModuleNode; use Twig\Node\Node; use Twig\Node\Nodes; @@ -120,7 +120,7 @@ final class SandboxNodeVisitor implements NodeVisitorInterface private function wrapNode(Node $node, string $name): void { $expr = $node->getNode($name); - if (($expr instanceof NameExpression || $expr instanceof GetAttrExpression) && !$expr->isGenerator()) { + if (($expr instanceof ContextVariable || $expr instanceof GetAttrExpression) && !$expr->isGenerator()) { $node->setNode($name, new CheckToStringNode($expr)); } } diff --git a/src/Parser.php b/src/Parser.php index d333e1de0..06980614b 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -78,13 +78,6 @@ class Parser return $this->env; } - public function getVarName(): string - { - trigger_deprecation('twig/twig', '3.15', 'The "%s()" method is deprecated.', __METHOD__); - - return \sprintf('__internal_parse_%d', $this->varNameSalt++); - } - public function parse(TokenStream $stream, $test = null, bool $dropNeedle = false): ModuleNode { $vars = get_object_vars($this); @@ -276,14 +269,8 @@ class Parser $this->embeddedTemplates[] = $template; } - public function addImportedSymbol(string $type, string $alias, ?string $name = null, AbstractExpression|TemplateVariable|null $internalRef = null): void + public function addImportedSymbol(string $type, string $alias, ?string $name = null, ?TemplateVariable $internalRef = null): void { - if ($internalRef && !$internalRef instanceof TemplateVariable) { - trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance as an internal reference is deprecated ("%s" given).', __METHOD__, TemplateVariable::class, $internalRef::class); - - $internalRef = new TemplateVariable($internalRef->getAttribute('name'), $internalRef->getTemplateLine()); - } - $this->importedSymbols[0][$type][$alias] = ['name' => $name, 'node' => $internalRef]; } diff --git a/src/TokenParser/EmbedTokenParser.php b/src/TokenParser/EmbedTokenParser.php index 7bf3233e2..f1acbf1ef 100644 --- a/src/TokenParser/EmbedTokenParser.php +++ b/src/TokenParser/EmbedTokenParser.php @@ -13,7 +13,7 @@ namespace Twig\TokenParser; use Twig\Node\EmbedNode; use Twig\Node\Expression\ConstantExpression; -use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; use Twig\Token; @@ -35,7 +35,7 @@ final class EmbedTokenParser extends IncludeTokenParser $parentToken = $fakeParentToken = new Token(Token::STRING_TYPE, '__parent__', $token->getLine()); if ($parent instanceof ConstantExpression) { $parentToken = new Token(Token::STRING_TYPE, $parent->getAttribute('value'), $token->getLine()); - } elseif ($parent instanceof NameExpression) { + } elseif ($parent instanceof ContextVariable) { $parentToken = new Token(Token::NAME_TYPE, $parent->getAttribute('name'), $token->getLine()); } diff --git a/tests/ExpressionParserTest.php b/tests/ExpressionParserTest.php index fa1267457..5b6b3a4ff 100644 --- a/tests/ExpressionParserTest.php +++ b/tests/ExpressionParserTest.php @@ -20,13 +20,8 @@ use Twig\Loader\ArrayLoader; use Twig\Node\Expression\ArrayExpression; use Twig\Node\Expression\Binary\ConcatBinary; use Twig\Node\Expression\ConstantExpression; -use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\Unary\SpreadUnary; -use Twig\Node\Expression\FilterExpression; -use Twig\Node\Expression\FunctionExpression; -use Twig\Node\Expression\TestExpression; use Twig\Node\Expression\Variable\ContextVariable; -use Twig\Node\Node; use Twig\Parser; use Twig\Source; use Twig\TwigFilter; @@ -183,7 +178,7 @@ class ExpressionParserTest extends TestCase new ConstantExpression(2, 1), new ConstantExpression(2, 1), - self::createContextVariable(new SpreadUnary(new NameExpression('foo', 1), 1)), + new SpreadUnary(new ContextVariable('foo', 1), 1), ], 1)], // mapping with spread operator @@ -196,7 +191,7 @@ class ExpressionParserTest extends TestCase new ConstantExpression('c', 1), new ConstantExpression(0, 1), - self::createContextVariable(new SpreadUnary(new NameExpression('otherLetters', 1), 1)), + new SpreadUnary(new ContextVariable('otherLetters', 1), 1), ], 1)], ]; } @@ -445,14 +440,4 @@ class ExpressionParserTest extends TestCase $parser->parse($env->tokenize(new Source('{{ 1 is empty element }}', 'index'))); $this->expectNotToPerformAssertions(); } - - private static function createContextVariable(string $name, array $attributes): ContextVariable - { - $expression = new ContextVariable($name, 1); - foreach ($attributes as $key => $value) { - $expression->setAttribute($key, $value); - } - - return $expression; - } } diff --git a/tests/Node/ForTest.php b/tests/Node/ForTest.php index a707150eb..32c22021d 100644 --- a/tests/Node/ForTest.php +++ b/tests/Node/ForTest.php @@ -13,9 +13,7 @@ namespace Twig\Tests\Node; use Twig\Environment; use Twig\Loader\ArrayLoader; -use Twig\Node\Expression\AssignNameExpression; use Twig\Node\Expression\ConstantExpression; -use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\Variable\AssignContextVariable; use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\ForNode; @@ -30,9 +28,9 @@ class ForTest extends NodeTestCase { $keyTarget = new AssignContextVariable('key', 1); $valueTarget = new AssignContextVariable('item', 1); - $seq = new NameExpression('items', 1); + $seq = new ContextVariable('items', 1); $ifexpr = new ConstantExpression(true, 1); - $body = new Nodes([new PrintNode(new NameExpression('foo', 1), 1)], 1); + $body = new Nodes([new PrintNode(new ContextVariable('foo', 1), 1)], 1); $else = null; $node = new ForNode($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1); $node->setAttribute('with_loop', false); @@ -135,10 +133,10 @@ EOF $keyTarget = new AssignContextVariable('k', 1); $valueTarget = new AssignContextVariable('v', 1); - $seq = new NameExpression('values', 1); + $seq = new ContextVariable('values', 1); $ifexpr = new ConstantExpression(true, 1); - $body = new Nodes([new PrintNode(new NameExpression('foo', 1), 1)], 1); - $else = new PrintNode(new NameExpression('foo', 1), 1); + $body = new Nodes([new PrintNode(new ContextVariable('foo', 1), 1)], 1); + $else = new PrintNode(new ContextVariable('foo', 1), 1); $node = new ForNode($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1); $node->setAttribute('with_loop', true); diff --git a/tests/NodeVisitor/OptimizerTest.php b/tests/NodeVisitor/OptimizerTest.php index 3237b4b75..21d1d7a64 100644 --- a/tests/NodeVisitor/OptimizerTest.php +++ b/tests/NodeVisitor/OptimizerTest.php @@ -16,8 +16,8 @@ use PHPUnit\Framework\TestCase; use Twig\Environment; use Twig\Loader\ArrayLoader; use Twig\Node\Expression\BlockReferenceExpression; -use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\ParentExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\ForNode; use Twig\Node\Node; use Twig\NodeVisitor\OptimizerNodeVisitor; @@ -71,7 +71,7 @@ class OptimizerTest extends TestCase public function checkForVarConfiguration(Node $node, $target) { foreach ($node as $n) { - if (NameExpression::class === $n::class && $target === $n->getAttribute('name')) { + if (ContextVariable::class === $n::class && $target === $n->getAttribute('name')) { $this->assertTrue($n->getAttribute('always_defined')); } else { $this->checkForVarConfiguration($n, $target);