diff --git a/CHANGELOG b/CHANGELOG index 4bd3a1c8d..6eac17dc9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ # 3.15.0 (2024-XX-XX) + * Deprecate `TempNameExpression` in favor of `LocalVariable` + * Deprecate `NameExpression` in favor of `ContextVariable` + * Deprecate `AssignNameExpression` in favor of `AssignContextVariable` * Remove `MacroAutoImportNodeVisitor` * Deprecate `MethodCallExpression` in favor of `MacroReferenceExpression` * Fix support for the "is defined" test on `_self.xxx` (auto-imported) macros diff --git a/doc/deprecated.rst b/doc/deprecated.rst index 7d6653413..fed5cb380 100644 --- a/doc/deprecated.rst +++ b/doc/deprecated.rst @@ -173,6 +173,16 @@ Nodes * The ``MethodCallExpression`` class is deprecated as of Twig 3.15, use ``MacroReferenceExpression`` instead. +* The ``Twig\Node\Expression\TempNameExpression`` class is deprecated as of + Twig 3.15; use ``Twig\Node\Expression\Variable\LocalVariable`` instead. + +* The ``Twig\Node\Expression\NameExpression`` class is deprecated as of Twig + 3.15; use ``Twig\Node\Expression\Variable\ContextVariable`` instead. + +* The ``Twig\Node\Expression\AssignNameExpression`` class is deprecated as of + Twig 3.15; use ``Twig\Node\Expression\Variable\AssignContextVariable`` + instead. + Node Visitors ------------- diff --git a/src/Compiler.php b/src/Compiler.php index 1a43aa7f6..ba7b6cbaa 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -243,7 +243,7 @@ class Compiler public function getVarName(): string { - return \sprintf('__internal_compile_%d', $this->varNameSalt++); + return \sprintf('_v%d', $this->varNameSalt++); } private function checkForEcho(string $string): void diff --git a/src/ExpressionParser.php b/src/ExpressionParser.php index 6892f7c78..8af4ea046 100644 --- a/src/ExpressionParser.php +++ b/src/ExpressionParser.php @@ -18,7 +18,6 @@ use Twig\Node\EmptyNode; use Twig\Node\Expression\AbstractExpression; use Twig\Node\Expression\ArrayExpression; use Twig\Node\Expression\ArrowFunctionExpression; -use Twig\Node\Expression\AssignNameExpression; use Twig\Node\Expression\Binary\AbstractBinary; use Twig\Node\Expression\Binary\ConcatBinary; use Twig\Node\Expression\ConditionalExpression; @@ -26,13 +25,15 @@ use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\GetAttrExpression; use Twig\Node\Expression\MacroReferenceExpression; use Twig\Node\Expression\NameExpression; -use Twig\Node\Expression\TempNameExpression; use Twig\Node\Expression\TestExpression; use Twig\Node\Expression\Unary\AbstractUnary; use Twig\Node\Expression\Unary\NegUnary; use Twig\Node\Expression\Unary\NotUnary; use Twig\Node\Expression\Unary\PosUnary; use Twig\Node\Expression\Unary\SpreadUnary; +use Twig\Node\Expression\Variable\AssignContextVariable; +use Twig\Node\Expression\Variable\ContextVariable; +use Twig\Node\Expression\Variable\LocalVariable; use Twig\Node\Expression\Variable\TemplateVariable; use Twig\Node\Node; use Twig\Node\Nodes; @@ -184,7 +185,7 @@ class ExpressionParser if ($stream->look(1)->test(Token::ARROW_TYPE)) { $line = $stream->getCurrent()->getLine(); $token = $stream->expect(Token::NAME_TYPE); - $names = [new AssignNameExpression($token->getValue(), $token->getLine())]; + $names = [new AssignContextVariable($token->getValue(), $token->getLine())]; $stream->expect(Token::ARROW_TYPE); return new ArrowFunctionExpression($this->parseExpression(), new Nodes($names), $line); @@ -219,7 +220,7 @@ class ExpressionParser $names = []; while (true) { $token = $stream->expect(Token::NAME_TYPE); - $names[] = new AssignNameExpression($token->getValue(), $token->getLine()); + $names[] = new AssignContextVariable($token->getValue(), $token->getLine()); if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) { break; @@ -327,7 +328,7 @@ class ExpressionParser if ('(' === $this->parser->getCurrentToken()->getValue()) { $node = $this->getFunctionNode($token->getValue(), $token->getLine()); } else { - $node = new NameExpression($token->getValue(), $token->getLine()); + $node = new ContextVariable($token->getValue(), $token->getLine()); } } break; @@ -354,7 +355,7 @@ class ExpressionParser if (preg_match(Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) { // in this context, string operators are variable names $this->parser->getStream()->next(); - $node = new NameExpression($token->getValue(), $token->getLine()); + $node = new ContextVariable($token->getValue(), $token->getLine()); break; } @@ -485,7 +486,7 @@ class ExpressionParser // {a} is a shortcut for {a:a} if ($stream->test(Token::PUNCTUATION_TYPE, [',', '}'])) { - $value = new NameExpression($key->getAttribute('value'), $key->getTemplateLine()); + $value = new ContextVariable($key->getAttribute('value'), $key->getTemplateLine()); $node->addElement($value, $key); continue; } @@ -532,7 +533,7 @@ class ExpressionParser public function getFunctionNode($name, $line) { if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) { - return new MacroReferenceExpression(new TemplateVariable($alias['node'], $line), $alias['name'], $this->createArguments($line), $line); + return new MacroReferenceExpression(new TemplateVariable($alias['node']->getAttribute('name'), $line), $alias['name'], $this->createArguments($line), $line); } $args = $this->parseOnlyArguments(); @@ -646,7 +647,7 @@ class ExpressionParser if ($definition) { $token = $stream->expect(Token::NAME_TYPE, null, 'An argument must be a name'); - $value = new NameExpression($token->getValue(), $this->parser->getCurrentToken()->getLine()); + $value = new ContextVariable($token->getValue(), $this->parser->getCurrentToken()->getLine()); } else { if ($stream->nextIf(Token::SPREAD_TYPE)) { $hasSpread = true; @@ -708,7 +709,7 @@ class ExpressionParser } else { $stream->expect(Token::NAME_TYPE, null, 'Only variables can be assigned to'); } - $targets[] = new AssignNameExpression($token->getValue(), $token->getLine()); + $targets[] = new AssignContextVariable($token->getValue(), $token->getLine()); if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) { break; @@ -749,7 +750,7 @@ class ExpressionParser } if ('defined' === $test->getName() && $node instanceof NameExpression && null !== $alias = $this->parser->getImportedSymbol('function', $node->getAttribute('name'))) { - $node = new MacroReferenceExpression(new TemplateVariable($alias['node'], $node->getTemplateLine()), $alias['name'], new ArrayExpression([], $node->getTemplateLine()), $node->getTemplateLine()); + $node = new MacroReferenceExpression(new TemplateVariable($alias['node']->getAttribute('name'), $node->getTemplateLine()), $alias['name'], new ArrayExpression([], $node->getTemplateLine()), $node->getTemplateLine()); } $ready = $test instanceof TwigTest; @@ -870,7 +871,7 @@ class ExpressionParser { $arguments = new ArrayExpression([], $line); foreach ($this->parseOnlyArguments() as $k => $n) { - $arguments->addElement($n, new TempNameExpression($k, $line)); + $arguments->addElement($n, new LocalVariable($k, $line)); } return $arguments; @@ -956,7 +957,7 @@ class ExpressionParser $node instanceof NameExpression && ( - null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name')) + null !== $this->parser->getImportedSymbol('template', (new TemplateVariable($node->getAttribute('name'), $node->getTemplateLine()))->getAttribute('name')) || '_self' === $node->getAttribute('name') && $attribute instanceof ConstantExpression ) diff --git a/src/Node/Expression/AssignNameExpression.php b/src/Node/Expression/AssignNameExpression.php index a0df3b7a3..c2cbb8e4a 100644 --- a/src/Node/Expression/AssignNameExpression.php +++ b/src/Node/Expression/AssignNameExpression.php @@ -14,11 +14,16 @@ namespace Twig\Node\Expression; use Twig\Compiler; use Twig\Error\SyntaxError; +use Twig\Node\Expression\Variable\AssignContextVariable; class AssignNameExpression extends NameExpression { 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, AssignContextVariable::class); + } + // 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); diff --git a/src/Node/Expression/NameExpression.php b/src/Node/Expression/NameExpression.php index 12a9bb71c..322fbc2e0 100644 --- a/src/Node/Expression/NameExpression.php +++ b/src/Node/Expression/NameExpression.php @@ -13,6 +13,7 @@ namespace Twig\Node\Expression; use Twig\Compiler; +use Twig\Node\Expression\Variable\ContextVariable; class NameExpression extends AbstractExpression { @@ -24,6 +25,10 @@ class NameExpression extends AbstractExpression 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); } diff --git a/src/Node/Expression/TempNameExpression.php b/src/Node/Expression/TempNameExpression.php index 8bdb456ef..bf304a98c 100644 --- a/src/Node/Expression/TempNameExpression.php +++ b/src/Node/Expression/TempNameExpression.php @@ -18,14 +18,18 @@ class TempNameExpression extends AbstractExpression { public const RESERVED_NAMES = ['varargs', 'context', 'macros', 'blocks', 'this']; - public function __construct(string|int $name, int $lineno) + public function __construct(string|int|null $name, int $lineno) { // All names supported by ExpressionParser::parsePrimaryExpression() should be excluded - if (\in_array(strtolower($name), ['true', 'false', 'none', 'null'])) { + if ($name && \in_array(strtolower($name), ['true', 'false', 'none', 'null'])) { throw new SyntaxError(\sprintf('You cannot assign a value to "%s".', $name), $lineno); } - if (is_int($name) || ctype_digit($name)) { + if (self::class === static::class) { + trigger_deprecation('twig/twig', '3.15', 'The "%s" class is deprecated.', self::class); + } + + if (null !== $name && (is_int($name) || ctype_digit($name))) { $name = (int) $name; } elseif (in_array($name, self::RESERVED_NAMES)) { $name = '_'.$name.'_'; @@ -36,6 +40,10 @@ class TempNameExpression extends AbstractExpression 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/AssignContextVariable.php b/src/Node/Expression/Variable/AssignContextVariable.php new file mode 100644 index 000000000..30d810675 --- /dev/null +++ b/src/Node/Expression/Variable/AssignContextVariable.php @@ -0,0 +1,18 @@ +getAttribute('name')) { + $this->setAttribute('name', \sprintf('_l%d', $compiler->getVarName())); + } + + if ('_self' === $this->getAttribute('name')) { + $compiler->raw('$this'); + } else { + $compiler + ->raw('$this->macros[') + ->string($this->getAttribute('name')) + ->raw(']') + ; + } + } +} diff --git a/src/Node/Expression/Variable/LocalVariable.php b/src/Node/Expression/Variable/LocalVariable.php new file mode 100644 index 000000000..a5ee17566 --- /dev/null +++ b/src/Node/Expression/Variable/LocalVariable.php @@ -0,0 +1,18 @@ +getAttribute('name')) { + $this->setAttribute('name', \sprintf('_l%d', $compiler->getVarName())); + } + if ('_self' === $this->getAttribute('name')) { $compiler->raw('$this'); } else { diff --git a/src/Node/ImportNode.php b/src/Node/ImportNode.php index 7f057ed97..b083d064d 100644 --- a/src/Node/ImportNode.php +++ b/src/Node/ImportNode.php @@ -14,8 +14,9 @@ namespace Twig\Node; use Twig\Attribute\YieldReady; use Twig\Compiler; use Twig\Node\Expression\AbstractExpression; -use Twig\Node\Expression\AssignNameExpression; use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\GlobalTemplateVariable; +use Twig\Node\Expression\Variable\TemplateVariable; /** * Represents an import node. @@ -28,7 +29,7 @@ class ImportNode extends Node /** * @param bool $global */ - public function __construct(AbstractExpression $expr, AbstractExpression|string $var, int $lineno, $global = true) + public function __construct(AbstractExpression $expr, AbstractExpression|TemplateVariable $var, int $lineno, $global = true) { if (null === $global || \is_string($global)) { trigger_deprecation('twig/twig', '3.12', 'Passing a tag to %s() is deprecated.', __METHOD__); @@ -37,31 +38,28 @@ class ImportNode extends Node throw new \TypeError(\sprintf('Argument 4 passed to "%s()" must be a boolean, "%s" given.', __METHOD__, get_debug_type($global))); } - if (!\is_string($var)) { - trigger_deprecation('twig/twig', '3.15', \sprintf('Passing a "%s" instance as the second argument of "%s" is deprecated, pass a "string" instead.', $var::class, __CLASS__)); - } else { - $var = new AssignNameExpression($var, $lineno); + if (!$var instanceof TemplateVariable) { + 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__, TemplateVariable::class)); + + $var = new TemplateVariable($var->getAttribute('name'), $lineno); } - $this->deprecateNode('var', new NameDeprecation('var', '3.15')); - - parent::__construct(['expr' => $expr, 'var' => $var], ['global' => $global, 'var' => $var->getAttribute('name')], $lineno); + parent::__construct(['expr' => $expr, 'var' => $var], ['global' => $global], $lineno); } public function compile(Compiler $compiler): void { $compiler ->addDebugInfo($this) - ->write('$macros[') - ->repr($this->getAttribute('var')) - ->raw('] = ') + ->write('') + ->subcompile($this->getNode('var')) + ->raw(' = ') ; if ($this->getAttribute('global')) { $compiler - ->raw('$this->macros[') - ->repr($this->getAttribute('var')) - ->raw('] = ') + ->subcompile(new GlobalTemplateVariable($this->getNode('var')->getAttribute('name'), $this->getTemplateLine())) + ->raw(' = ') ; } diff --git a/src/Node/MacroNode.php b/src/Node/MacroNode.php index 7c2603a62..5ada1b220 100644 --- a/src/Node/MacroNode.php +++ b/src/Node/MacroNode.php @@ -15,7 +15,7 @@ use Twig\Attribute\YieldReady; use Twig\Compiler; use Twig\Error\SyntaxError; use Twig\Node\Expression\ArrayExpression; -use Twig\Node\Expression\TempNameExpression; +use Twig\Node\Expression\Variable\LocalVariable; /** * Represents a macro node. @@ -42,7 +42,7 @@ class MacroNode extends Node $args = new ArrayExpression([], $arguments->getTemplateLine()); foreach ($arguments as $name => $default) { - $args->addElement($default, new TempNameExpression($name, $default->getTemplateLine())); + $args->addElement($default, new LocalVariable($name, $default->getTemplateLine())); } $arguments = $args; } diff --git a/src/NodeVisitor/EscaperNodeVisitor.php b/src/NodeVisitor/EscaperNodeVisitor.php index 6f5aa10bf..c942f825b 100644 --- a/src/NodeVisitor/EscaperNodeVisitor.php +++ b/src/NodeVisitor/EscaperNodeVisitor.php @@ -61,7 +61,7 @@ final class EscaperNodeVisitor implements NodeVisitorInterface } elseif ($node instanceof BlockNode) { $this->statusStack[] = $this->blocks[$node->getAttribute('name')] ?? $this->needEscaping(); } elseif ($node instanceof ImportNode) { - $this->safeVars[] = $node->getAttribute('var'); + $this->safeVars[] = $node->getNode('var')->getAttribute('name'); } return $node; diff --git a/src/Parser.php b/src/Parser.php index 249c23de1..b55c0148a 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -18,6 +18,7 @@ use Twig\Node\BlockReferenceNode; use Twig\Node\BodyNode; use Twig\Node\EmptyNode; use Twig\Node\Expression\AbstractExpression; +use Twig\Node\Expression\Variable\TemplateVariable; use Twig\Node\MacroNode; use Twig\Node\ModuleNode; use Twig\Node\Node; @@ -60,6 +61,8 @@ class Parser public function getVarName(): string { + trigger_deprecation('twig/twig', '3.15', 'The "%s()" method is deprecated.', __METHOD__); + return \sprintf('__internal_parse_%d', $this->varNameSalt++); } @@ -292,12 +295,12 @@ class Parser $this->embeddedTemplates[] = $template; } - public function addImportedSymbol(string $type, string $alias, ?string $name = null, AbstractExpression|string|null $internalRef = null): void + public function addImportedSymbol(string $type, string $alias, ?string $name = null, AbstractExpression|TemplateVariable|null $internalRef = null): void { - if ($internalRef instanceof AbstractExpression) { - trigger_deprecation('twig/twig', '3.15', 'Passing a non-string internal reference name to "%s" is deprecated ("%s" given).', __METHOD__, $internalRef::class); + 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 = $internalRef->getAttribute('name'); + $internalRef = new TemplateVariable($internalRef->getAttribute('name'), $internalRef->getTemplateLine()); } $this->importedSymbols[0][$type][$alias] = ['name' => $name, 'node' => $internalRef]; diff --git a/src/TokenParser/ApplyTokenParser.php b/src/TokenParser/ApplyTokenParser.php index 58c2a3ee4..0c9507482 100644 --- a/src/TokenParser/ApplyTokenParser.php +++ b/src/TokenParser/ApplyTokenParser.php @@ -11,7 +11,7 @@ namespace Twig\TokenParser; -use Twig\Node\Expression\TempNameExpression; +use Twig\Node\Expression\Variable\LocalVariable; use Twig\Node\Node; use Twig\Node\Nodes; use Twig\Node\PrintNode; @@ -32,11 +32,7 @@ final class ApplyTokenParser extends AbstractTokenParser public function parse(Token $token): Node { $lineno = $token->getLine(); - $name = $this->parser->getVarName(); - - $ref = new TempNameExpression($name, $lineno); - $ref->setAttribute('always_defined', true); - + $ref = new LocalVariable(null, $lineno); $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref); $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); diff --git a/src/TokenParser/ForTokenParser.php b/src/TokenParser/ForTokenParser.php index cf655f842..c0a0e3c29 100644 --- a/src/TokenParser/ForTokenParser.php +++ b/src/TokenParser/ForTokenParser.php @@ -12,7 +12,7 @@ namespace Twig\TokenParser; -use Twig\Node\Expression\AssignNameExpression; +use Twig\Node\Expression\Variable\AssignContextVariable; use Twig\Node\ForNode; use Twig\Node\Node; use Twig\Token; @@ -50,13 +50,13 @@ final class ForTokenParser extends AbstractTokenParser if (\count($targets) > 1) { $keyTarget = $targets->getNode('0'); - $keyTarget = new AssignNameExpression($keyTarget->getAttribute('name'), $keyTarget->getTemplateLine()); + $keyTarget = new AssignContextVariable($keyTarget->getAttribute('name'), $keyTarget->getTemplateLine()); $valueTarget = $targets->getNode('1'); } else { - $keyTarget = new AssignNameExpression('_key', $lineno); + $keyTarget = new AssignContextVariable('_key', $lineno); $valueTarget = $targets->getNode('0'); } - $valueTarget = new AssignNameExpression($valueTarget->getAttribute('name'), $valueTarget->getTemplateLine()); + $valueTarget = new AssignContextVariable($valueTarget->getAttribute('name'), $valueTarget->getTemplateLine()); return new ForNode($keyTarget, $valueTarget, $seq, null, $body, $else, $lineno); } diff --git a/src/TokenParser/FromTokenParser.php b/src/TokenParser/FromTokenParser.php index fbd8f560f..b5f985f55 100644 --- a/src/TokenParser/FromTokenParser.php +++ b/src/TokenParser/FromTokenParser.php @@ -11,7 +11,8 @@ namespace Twig\TokenParser; -use Twig\Node\Expression\AssignNameExpression; +use Twig\Node\Expression\Variable\AssignContextVariable; +use Twig\Node\Expression\Variable\TemplateVariable; use Twig\Node\ImportNode; use Twig\Node\Node; use Twig\Token; @@ -36,9 +37,9 @@ final class FromTokenParser extends AbstractTokenParser $name = $stream->expect(Token::NAME_TYPE)->getValue(); if ($stream->nextIf('as')) { - $alias = new AssignNameExpression($stream->expect(Token::NAME_TYPE)->getValue(), $token->getLine()); + $alias = new AssignContextVariable($stream->expect(Token::NAME_TYPE)->getValue(), $token->getLine()); } else { - $alias = new AssignNameExpression($name, $token->getLine()); + $alias = new AssignContextVariable($name, $token->getLine()); } $targets[$name] = $alias; @@ -50,7 +51,7 @@ final class FromTokenParser extends AbstractTokenParser $stream->expect(Token::BLOCK_END_TYPE); - $internalRef = $this->parser->getVarName(); + $internalRef = new TemplateVariable(null, $token->getLine()); $node = new ImportNode($macro, $internalRef, $token->getLine(), $this->parser->isMainScope()); foreach ($targets as $name => $alias) { diff --git a/src/TokenParser/ImportTokenParser.php b/src/TokenParser/ImportTokenParser.php index f4f1acd3d..0f1dd1c97 100644 --- a/src/TokenParser/ImportTokenParser.php +++ b/src/TokenParser/ImportTokenParser.php @@ -11,6 +11,7 @@ namespace Twig\TokenParser; +use Twig\Node\Expression\Variable\TemplateVariable; use Twig\Node\ImportNode; use Twig\Node\Node; use Twig\Token; @@ -28,9 +29,9 @@ final class ImportTokenParser extends AbstractTokenParser { $macro = $this->parser->getExpressionParser()->parseExpression(); $this->parser->getStream()->expect(Token::NAME_TYPE, 'as'); - $var = $this->parser->getStream()->expect(Token::NAME_TYPE)->getValue(); + $var = new TemplateVariable($this->parser->getStream()->expect(Token::NAME_TYPE)->getValue(), $token->getLine()); $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); - $this->parser->addImportedSymbol('template', $var); + $this->parser->addImportedSymbol('template', $var->getAttribute('name')); return new ImportNode($macro, $var, $token->getLine(), $this->parser->isMainScope()); } diff --git a/src/TokenParser/MacroTokenParser.php b/src/TokenParser/MacroTokenParser.php index 7b34eeef6..7d47821b2 100644 --- a/src/TokenParser/MacroTokenParser.php +++ b/src/TokenParser/MacroTokenParser.php @@ -16,9 +16,9 @@ use Twig\Node\BodyNode; use Twig\Node\EmptyNode; use Twig\Node\Expression\ArrayExpression; use Twig\Node\Expression\ConstantExpression; -use Twig\Node\Expression\TempNameExpression; use Twig\Node\Expression\Unary\NegUnary; use Twig\Node\Expression\Unary\PosUnary; +use Twig\Node\Expression\Variable\LocalVariable; use Twig\Node\MacroNode; use Twig\Node\Node; use Twig\Token; @@ -85,7 +85,7 @@ final class MacroTokenParser extends AbstractTokenParser } $token = $stream->expect(Token::NAME_TYPE, null, 'An argument must be a name'); - $name = new TempNameExpression($token->getValue(), $this->parser->getCurrentToken()->getLine()); + $name = new LocalVariable($token->getValue(), $this->parser->getCurrentToken()->getLine()); if ($token = $stream->nextIf(Token::OPERATOR_TYPE, '=')) { $default = $this->parser->getExpressionParser()->parseExpression(); } else { diff --git a/tests/ExpressionParserTest.php b/tests/ExpressionParserTest.php index def632c19..162f8836c 100644 --- a/tests/ExpressionParserTest.php +++ b/tests/ExpressionParserTest.php @@ -23,8 +23,8 @@ use Twig\Node\Expression\Binary\ConcatBinary; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\FilterExpression; use Twig\Node\Expression\FunctionExpression; -use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\TestExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; use Twig\Parser; use Twig\Source; @@ -175,9 +175,9 @@ class ExpressionParserTest extends TestCase ], ['{{ {a, b} }}', new ArrayExpression([ new ConstantExpression('a', 1), - new NameExpression('a', 1), + new ContextVariable('a', 1), new ConstantExpression('b', 1), - new NameExpression('b', 1), + new ContextVariable('b', 1), ], 1)], // sequence with spread operator @@ -190,7 +190,7 @@ class ExpressionParserTest extends TestCase new ConstantExpression(2, 1), new ConstantExpression(2, 1), - self::createNameExpression('foo', ['spread' => true]), + self::createContextVariable('foo', ['spread' => true]), ], 1)], // mapping with spread operator @@ -203,7 +203,7 @@ class ExpressionParserTest extends TestCase new ConstantExpression('c', 1), new ConstantExpression(0, 1), - self::createNameExpression('otherLetters', ['spread' => true]), + self::createContextVariable('otherLetters', ['spread' => true]), ], 1)], ]; } @@ -237,7 +237,7 @@ class ExpressionParserTest extends TestCase [ '{{ "foo #{bar}" }}', new ConcatBinary( new ConstantExpression('foo ', 1), - new NameExpression('bar', 1), + new ContextVariable('bar', 1), 1 ), ], @@ -245,7 +245,7 @@ class ExpressionParserTest extends TestCase '{{ "foo #{bar} baz" }}', new ConcatBinary( new ConcatBinary( new ConstantExpression('foo ', 1), - new NameExpression('bar', 1), + new ContextVariable('bar', 1), 1 ), new ConstantExpression(' baz', 1), @@ -260,7 +260,7 @@ class ExpressionParserTest extends TestCase new ConcatBinary( new ConcatBinary( new ConstantExpression('foo ', 1), - new NameExpression('bar', 1), + new ContextVariable('bar', 1), 1 ), new ConstantExpression(' baz', 1), @@ -564,9 +564,9 @@ class ExpressionParserTest extends TestCase $this->expectNotToPerformAssertions(); } - private static function createNameExpression(string $name, array $attributes): NameExpression + private static function createContextVariable(string $name, array $attributes): ContextVariable { - $expression = new NameExpression($name, 1); + $expression = new ContextVariable($name, 1); foreach ($attributes as $key => $value) { $expression->setAttribute($key, $value); } diff --git a/tests/Node/Expression/GetAttrTest.php b/tests/Node/Expression/GetAttrTest.php index 0446c73eb..537b010ac 100644 --- a/tests/Node/Expression/GetAttrTest.php +++ b/tests/Node/Expression/GetAttrTest.php @@ -14,7 +14,7 @@ namespace Twig\Tests\Node\Expression; use Twig\Node\Expression\ArrayExpression; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\GetAttrExpression; -use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Template; use Twig\Test\NodeTestCase; @@ -22,10 +22,10 @@ class GetAttrTest extends NodeTestCase { public function testConstructor() { - $expr = new NameExpression('foo', 1); + $expr = new ContextVariable('foo', 1); $attr = new ConstantExpression('bar', 1); $args = new ArrayExpression([], 1); - $args->addElement(new NameExpression('foo', 1)); + $args->addElement(new ContextVariable('foo', 1)); $args->addElement(new ConstantExpression('bar', 1)); $node = new GetAttrExpression($expr, $attr, $args, Template::ARRAY_CALL, 1); @@ -39,18 +39,18 @@ class GetAttrTest extends NodeTestCase { $tests = []; - $expr = new NameExpression('foo', 1); + $expr = new ContextVariable('foo', 1); $attr = new ConstantExpression('bar', 1); $args = new ArrayExpression([], 1); $node = new GetAttrExpression($expr, $attr, $args, Template::ANY_CALL, 1); $tests[] = [$node, \sprintf('%s%s, "bar", [], "any", false, false, false, 1)', self::createAttributeGetter(), self::createVariableGetter('foo', 1))]; $node = new GetAttrExpression($expr, $attr, $args, Template::ARRAY_CALL, 1); - $tests[] = [$node, '(($__internal_%s = // line 1'."\n". - '($context["foo"] ?? null)) && is_array($__internal_%s) || $__internal_%s instanceof ArrayAccess ? ($__internal_%s["bar"] ?? null) : null)', null, true, ]; + $tests[] = [$node, '(($_v%s = // line 1'."\n". + '($context["foo"] ?? null)) && is_array($_v%s) || $_v%s instanceof ArrayAccess ? ($_v%s["bar"] ?? null) : null)', null, true, ]; $args = new ArrayExpression([], 1); - $args->addElement(new NameExpression('foo', 1)); + $args->addElement(new ContextVariable('foo', 1)); $args->addElement(new ConstantExpression('bar', 1)); $node = new GetAttrExpression($expr, $attr, $args, Template::METHOD_CALL, 1); $tests[] = [$node, \sprintf('%s%s, "bar", [%s, "bar"], "method", false, false, false, 1)', self::createAttributeGetter(), self::createVariableGetter('foo', 1), self::createVariableGetter('foo'))]; diff --git a/tests/Node/Expression/NullCoalesceTest.php b/tests/Node/Expression/NullCoalesceTest.php index e529db736..88f8a95f1 100644 --- a/tests/Node/Expression/NullCoalesceTest.php +++ b/tests/Node/Expression/NullCoalesceTest.php @@ -12,15 +12,15 @@ namespace Twig\Tests\Node\Expression; */ use Twig\Node\Expression\ConstantExpression; -use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\NullCoalesceExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Test\NodeTestCase; class NullCoalesceTest extends NodeTestCase { public static function provideTests(): iterable { - $left = new NameExpression('foo', 1); + $left = new ContextVariable('foo', 1); $right = new ConstantExpression(2, 1); $node = new NullCoalesceExpression($left, $right, 1); diff --git a/tests/Node/Expression/AssignNameTest.php b/tests/Node/Expression/Variable/AssignContextVariableTest.php similarity index 70% rename from tests/Node/Expression/AssignNameTest.php rename to tests/Node/Expression/Variable/AssignContextVariableTest.php index 3ed8511d8..4ff469eaa 100644 --- a/tests/Node/Expression/AssignNameTest.php +++ b/tests/Node/Expression/Variable/AssignContextVariableTest.php @@ -11,21 +11,21 @@ namespace Twig\Tests\Node\Expression; * file that was distributed with this source code. */ -use Twig\Node\Expression\AssignNameExpression; +use Twig\Node\Expression\Variable\AssignContextVariable; use Twig\Test\NodeTestCase; -class AssignNameTest extends NodeTestCase +class AssignContextVariableTest extends NodeTestCase { public function testConstructor() { - $node = new AssignNameExpression('foo', 1); + $node = new AssignContextVariable('foo', 1); $this->assertEquals('foo', $node->getAttribute('name')); } public static function provideTests(): iterable { - $node = new AssignNameExpression('foo', 1); + $node = new AssignContextVariable('foo', 1); return [ [$node, '$context["foo"]'], diff --git a/tests/Node/Expression/NameTest.php b/tests/Node/Expression/Variable/ContextVariableTest.php similarity index 79% rename from tests/Node/Expression/NameTest.php rename to tests/Node/Expression/Variable/ContextVariableTest.php index b38d446de..be9f6917b 100644 --- a/tests/Node/Expression/NameTest.php +++ b/tests/Node/Expression/Variable/ContextVariableTest.php @@ -13,23 +13,23 @@ namespace Twig\Tests\Node\Expression; use Twig\Environment; use Twig\Loader\ArrayLoader; -use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Test\NodeTestCase; -class NameTest extends NodeTestCase +class ContextVariableTest extends NodeTestCase { public function testConstructor() { - $node = new NameExpression('foo', 1); + $node = new ContextVariable('foo', 1); $this->assertEquals('foo', $node->getAttribute('name')); } public static function provideTests(): iterable { - $node = new NameExpression('foo', 1); - $self = new NameExpression('_self', 1); - $context = new NameExpression('_context', 1); + $node = new ContextVariable('foo', 1); + $self = new ContextVariable('_self', 1); + $context = new ContextVariable('_context', 1); $env = new Environment(new ArrayLoader(), ['strict_variables' => true]); $env1 = new Environment(new ArrayLoader(), ['strict_variables' => false]); diff --git a/tests/Node/ForTest.php b/tests/Node/ForTest.php index 4f96e94c4..814b6086a 100644 --- a/tests/Node/ForTest.php +++ b/tests/Node/ForTest.php @@ -11,8 +11,8 @@ namespace Twig\Tests\Node; * file that was distributed with this source code. */ -use Twig\Node\Expression\AssignNameExpression; -use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\AssignContextVariable; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\ForNode; use Twig\Node\Nodes; use Twig\Node\PrintNode; @@ -22,10 +22,10 @@ class ForTest extends NodeTestCase { public function testConstructor() { - $keyTarget = new AssignNameExpression('key', 1); - $valueTarget = new AssignNameExpression('item', 1); - $seq = new NameExpression('items', 1); - $body = new Nodes([new PrintNode(new NameExpression('foo', 1), 1)], 1); + $keyTarget = new AssignContextVariable('key', 1); + $valueTarget = new AssignContextVariable('item', 1); + $seq = new ContextVariable('items', 1); + $body = new Nodes([new PrintNode(new ContextVariable('foo', 1), 1)], 1); $else = null; $node = new ForNode($keyTarget, $valueTarget, $seq, null, $body, $else, 1); $node->setAttribute('with_loop', false); @@ -36,7 +36,7 @@ class ForTest extends NodeTestCase $this->assertEquals($body, $node->getNode('body')->getNode('0')); $this->assertFalse($node->hasNode('else')); - $else = new PrintNode(new NameExpression('foo', 1), 1); + $else = new PrintNode(new ContextVariable('foo', 1), 1); $node = new ForNode($keyTarget, $valueTarget, $seq, null, $body, $else, 1); $node->setAttribute('with_loop', false); $this->assertEquals($else, $node->getNode('else')); @@ -46,10 +46,10 @@ class ForTest extends NodeTestCase { $tests = []; - $keyTarget = new AssignNameExpression('key', 1); - $valueTarget = new AssignNameExpression('item', 1); - $seq = new NameExpression('items', 1); - $body = new Nodes([new PrintNode(new NameExpression('foo', 1), 1)], 1); + $keyTarget = new AssignContextVariable('key', 1); + $valueTarget = new AssignContextVariable('item', 1); + $seq = new ContextVariable('items', 1); + $body = new Nodes([new PrintNode(new ContextVariable('foo', 1), 1)], 1); $else = null; $node = new ForNode($keyTarget, $valueTarget, $seq, null, $body, $else, 1); $node->setAttribute('with_loop', false); @@ -71,10 +71,10 @@ unset(\$context['_seq'], \$context['key'], \$context['item'], \$context['_parent EOF ]; - $keyTarget = new AssignNameExpression('k', 1); - $valueTarget = new AssignNameExpression('v', 1); - $seq = new NameExpression('values', 1); - $body = new Nodes([new PrintNode(new NameExpression('foo', 1), 1)], 1); + $keyTarget = new AssignContextVariable('k', 1); + $valueTarget = new AssignContextVariable('v', 1); + $seq = new ContextVariable('values', 1); + $body = new Nodes([new PrintNode(new ContextVariable('foo', 1), 1)], 1); $else = null; $node = new ForNode($keyTarget, $valueTarget, $seq, null, $body, $else, 1); $node->setAttribute('with_loop', true); @@ -113,10 +113,10 @@ unset(\$context['_seq'], \$context['k'], \$context['v'], \$context['_parent'], \ EOF ]; - $keyTarget = new AssignNameExpression('k', 1); - $valueTarget = new AssignNameExpression('v', 1); - $seq = new NameExpression('values', 1); - $body = new Nodes([new PrintNode(new NameExpression('foo', 1), 1)], 1); + $keyTarget = new AssignContextVariable('k', 1); + $valueTarget = new AssignContextVariable('v', 1); + $seq = new ContextVariable('values', 1); + $body = new Nodes([new PrintNode(new ContextVariable('foo', 1), 1)], 1); $else = null; $node = new ForNode($keyTarget, $valueTarget, $seq, null, $body, $else, 1); $node->setAttribute('with_loop', true); @@ -155,11 +155,11 @@ unset(\$context['_seq'], \$context['k'], \$context['v'], \$context['_parent'], \ EOF ]; - $keyTarget = new AssignNameExpression('k', 1); - $valueTarget = new AssignNameExpression('v', 1); - $seq = new NameExpression('values', 1); - $body = new Nodes([new PrintNode(new NameExpression('foo', 1), 1)], 1); - $else = new PrintNode(new NameExpression('foo', 1), 1); + $keyTarget = new AssignContextVariable('k', 1); + $valueTarget = new AssignContextVariable('v', 1); + $seq = new ContextVariable('values', 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, null, $body, $else, 1); $node->setAttribute('with_loop', true); diff --git a/tests/Node/IfTest.php b/tests/Node/IfTest.php index c3939f1e0..47b99509f 100644 --- a/tests/Node/IfTest.php +++ b/tests/Node/IfTest.php @@ -12,7 +12,7 @@ namespace Twig\Tests\Node; */ use Twig\Node\Expression\ConstantExpression; -use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\IfNode; use Twig\Node\Nodes; use Twig\Node\PrintNode; @@ -24,7 +24,7 @@ class IfTest extends NodeTestCase { $t = new Nodes([ new ConstantExpression(true, 1), - new PrintNode(new NameExpression('foo', 1), 1), + new PrintNode(new ContextVariable('foo', 1), 1), ], 1); $else = null; $node = new IfNode($t, $else, 1); @@ -32,7 +32,7 @@ class IfTest extends NodeTestCase $this->assertEquals($t, $node->getNode('tests')); $this->assertFalse($node->hasNode('else')); - $else = new PrintNode(new NameExpression('bar', 1), 1); + $else = new PrintNode(new ContextVariable('bar', 1), 1); $node = new IfNode($t, $else, 1); $this->assertEquals($else, $node->getNode('else')); } @@ -43,7 +43,7 @@ class IfTest extends NodeTestCase $t = new Nodes([ new ConstantExpression(true, 1), - new PrintNode(new NameExpression('foo', 1), 1), + new PrintNode(new ContextVariable('foo', 1), 1), ], 1); $else = null; $node = new IfNode($t, $else, 1); @@ -61,9 +61,9 @@ EOF $t = new Nodes([ new ConstantExpression(true, 1), - new PrintNode(new NameExpression('foo', 1), 1), + new PrintNode(new ContextVariable('foo', 1), 1), new ConstantExpression(false, 1), - new PrintNode(new NameExpression('bar', 1), 1), + new PrintNode(new ContextVariable('bar', 1), 1), ], 1); $else = null; $node = new IfNode($t, $else, 1); @@ -80,9 +80,9 @@ EOF $t = new Nodes([ new ConstantExpression(true, 1), - new PrintNode(new NameExpression('foo', 1), 1), + new PrintNode(new ContextVariable('foo', 1), 1), ], 1); - $else = new PrintNode(new NameExpression('bar', 1), 1); + $else = new PrintNode(new ContextVariable('bar', 1), 1); $node = new IfNode($t, $else, 1); $tests[] = [$node, <<assertEquals($macro, $node->getNode('expr')); - $this->assertEquals($var, $node->getAttribute('var')); + $this->assertEquals('macro', $node->getNode('var')->getAttribute('name')); } public static function provideTests(): iterable @@ -31,7 +32,7 @@ class ImportTest extends NodeTestCase $tests = []; $macro = new ConstantExpression('foo.twig', 1); - $node = new ImportNode($macro, 'macro', 1); + $node = new ImportNode($macro, new TemplateVariable('macro', 1), 1); $tests[] = [$node, <<loadTemplate("foo.twig", null, 1); + \$_v%s = \$this->loadTemplate("foo.twig", null, 1); } catch (LoaderError \$e) { // ignore missing template - \$__internal_%s = null; + \$_v%s = null; } -if (\$__internal_%s) { - yield from \$__internal_%s->unwrap()->yield(CoreExtension::toArray(["foo" => true])); +if (\$_v%s) { + yield from \$_v%s->unwrap()->yield(CoreExtension::toArray(["foo" => true])); } EOF , null, true]; diff --git a/tests/Node/MacroTest.php b/tests/Node/MacroTest.php index 8db7d9277..39ff9cd1f 100644 --- a/tests/Node/MacroTest.php +++ b/tests/Node/MacroTest.php @@ -16,8 +16,8 @@ use Twig\Loader\ArrayLoader; use Twig\Node\BodyNode; use Twig\Node\Expression\ArrayExpression; use Twig\Node\Expression\ConstantExpression; -use Twig\Node\Expression\NameExpression; -use Twig\Node\Expression\TempNameExpression; +use Twig\Node\Expression\Variable\ContextVariable; +use Twig\Node\Expression\Variable\LocalVariable; use Twig\Node\MacroNode; use Twig\Node\TextNode; use Twig\Test\NodeTestCase; @@ -27,7 +27,7 @@ class MacroTest extends NodeTestCase public function testConstructor() { $body = new BodyNode([new TextNode('foo', 1)]); - $arguments = new ArrayExpression([new NameExpression('foo', 1), new ConstantExpression(null, 1)], 1); + $arguments = new ArrayExpression([new ContextVariable('foo', 1), new ConstantExpression(null, 1)], 1); $node = new MacroNode('foo', $body, $arguments, 1); $this->assertEquals($body, $node->getNode('body')); @@ -38,9 +38,9 @@ class MacroTest extends NodeTestCase public static function provideTests(): iterable { $arguments = new ArrayExpression([ - new TempNameExpression('foo', 1), + new LocalVariable('foo', 1), new ConstantExpression(null, 1), - new TempNameExpression('bar', 1), + new LocalVariable('bar', 1), new ConstantExpression('Foo', 1), ], 1); diff --git a/tests/Node/ModuleTest.php b/tests/Node/ModuleTest.php index 8edbfab46..ea208f26c 100644 --- a/tests/Node/ModuleTest.php +++ b/tests/Node/ModuleTest.php @@ -15,9 +15,10 @@ use Twig\Environment; use Twig\Loader\ArrayLoader; use Twig\Node\BodyNode; use Twig\Node\EmptyNode; -use Twig\Node\Expression\AssignNameExpression; use Twig\Node\Expression\ConditionalExpression; use Twig\Node\Expression\ConstantExpression; +use Twig\Node\Expression\Variable\AssignContextVariable; +use Twig\Node\Expression\Variable\TemplateVariable; use Twig\Node\ImportNode; use Twig\Node\ModuleNode; use Twig\Node\Nodes; @@ -129,7 +130,7 @@ class __TwigTemplate_%x extends Template EOF , $twig, true]; - $import = new ImportNode(new ConstantExpression('foo.twig', 1), 'macro', 2); + $import = new ImportNode(new ConstantExpression('foo.twig', 1), new TemplateVariable('macro', 2), 2); $body = new BodyNode([$import]); $extends = new ConstantExpression('layout.twig', 1); @@ -219,7 +220,7 @@ class __TwigTemplate_%x extends Template EOF , $twig, true]; - $set = new SetNode(false, new Nodes([new AssignNameExpression('foo', 4)]), new Nodes([new ConstantExpression('foo', 4)]), 4); + $set = new SetNode(false, new Nodes([new AssignContextVariable('foo', 4)]), new Nodes([new ConstantExpression('foo', 4)]), 4); $body = new BodyNode([$set]); $extends = new ConditionalExpression( new ConstantExpression(true, 2), diff --git a/tests/Node/PrintTest.php b/tests/Node/PrintTest.php index f91c41eb8..a28f21a3d 100644 --- a/tests/Node/PrintTest.php +++ b/tests/Node/PrintTest.php @@ -13,7 +13,7 @@ namespace Twig\Tests\Node; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\GetAttrExpression; -use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\PrintNode; use Twig\Template; use Twig\Test\NodeTestCase; @@ -33,7 +33,7 @@ class PrintTest extends NodeTestCase $tests = []; $tests[] = [new PrintNode(new ConstantExpression('foo', 1), 1), "// line 1\nyield \"foo\";"]; - $expr = new NameExpression('foo', 1); + $expr = new ContextVariable('foo', 1); $attr = new ConstantExpression('bar', 1); $node = new GetAttrExpression($expr, $attr, null, Template::METHOD_CALL, 1); $node->setAttribute('is_generator', true); diff --git a/tests/Node/SetTest.php b/tests/Node/SetTest.php index 6283884af..d55376145 100644 --- a/tests/Node/SetTest.php +++ b/tests/Node/SetTest.php @@ -13,9 +13,9 @@ 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\Nodes; use Twig\Node\PrintNode; use Twig\Node\SetNode; @@ -26,7 +26,7 @@ class SetTest extends NodeTestCase { public function testConstructor() { - $names = new Nodes([new AssignNameExpression('foo', 1)], 1); + $names = new Nodes([new AssignContextVariable('foo', 1)], 1); $values = new Nodes([new ConstantExpression('foo', 1)], 1); $node = new SetNode(false, $names, $values, 1); @@ -39,7 +39,7 @@ class SetTest extends NodeTestCase { $tests = []; - $names = new Nodes([new AssignNameExpression('foo', 1)], 1); + $names = new Nodes([new AssignContextVariable('foo', 1)], 1); $values = new Nodes([new ConstantExpression('foo', 1)], 1); $node = new SetNode(false, $names, $values, 1); $tests[] = [$node, << false]), ]; - $names = new Nodes([new AssignNameExpression('foo', 1)], 1); + $names = new Nodes([new AssignContextVariable('foo', 1)], 1); $values = new TextNode('foo', 1); $node = new SetNode(true, $names, $values, 1); $tests[] = [$node, <<setAttribute('is_generator', true); $node = new ModuleNode(new BodyNode([new PrintNode($expr, 1)]), null, new EmptyNode(), new EmptyNode(), new EmptyNode(), new EmptyNode(), new Source('foo', 'foo')); $traverser = new NodeTraverser($env, [new SandboxNodeVisitor($env)]);