Skip to content

Commit a9e3f05

Browse files
committed
-
1 parent 8521d03 commit a9e3f05

File tree

5 files changed

+45
-28
lines changed

5 files changed

+45
-28
lines changed

src/ExpressionParser.php

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -57,23 +57,27 @@ class ExpressionParser
5757

5858
private Operators $operators;
5959
private $readyNodes = [];
60-
private array $precedenceChanges = [];
60+
private \WeakMap $precedenceChanges;
6161
private bool $deprecationCheck = true;
6262

6363
public function __construct(
6464
private Parser $parser,
6565
private Environment $env,
6666
) {
6767
$this->operators = $env->getOperators();
68-
foreach ($this->operators as $name => $op) {
68+
$this->precedenceChanges = new \WeakMap();
69+
foreach ($this->operators as $op) {
6970
if (!$op->getPrecedenceChange()) {
7071
continue;
7172
}
7273
$min = min($op->getPrecedenceChange()->getNewPrecedence(), $op->getPrecedence());
7374
$max = max($op->getPrecedenceChange()->getNewPrecedence(), $op->getPrecedence());
74-
foreach ($this->operators as $n => $o) {
75+
foreach ($this->operators as $o) {
7576
if ($o->getPrecedence() > $min && $o->getPrecedence() < $max) {
76-
$this->precedenceChanges[$n][] = $name;
77+
if (!isset($this->precedenceChanges[$o])) {
78+
$this->precedenceChanges[$o] = [];
79+
}
80+
$this->precedenceChanges[$o][] = $op;
7781
}
7882
}
7983
}
@@ -111,7 +115,7 @@ public function parseExpression($precedence = 0)
111115
$expr = new $class($expr, $expr1, $token->getLine());
112116
}
113117

114-
$expr->setAttribute('operator', OperatorArity::Binary->value.'_'.$token->getValue());
118+
$expr->setAttribute('operator', $op);
115119

116120
$this->triggerPrecedenceDeprecations($expr);
117121

@@ -132,30 +136,29 @@ private function triggerPrecedenceDeprecations(AbstractExpression $expr): void
132136
return;
133137
}
134138

135-
if (str_starts_with($unaryOp = $expr->getAttribute('operator'), 'unary')) {
139+
if (OperatorArity::Unary === $expr->getAttribute('operator')->getArity()) {
136140
if ($expr->hasExplicitParentheses()) {
137141
return;
138142
}
139-
$target = explode('_', $unaryOp)[1];
143+
$operator = $expr->getAttribute('operator');
140144
/** @var AbstractExpression $node */
141145
$node = $expr->getNode('node');
142-
foreach ($this->precedenceChanges as $operatorName => $changes) {
143-
if (!\in_array($unaryOp, $changes)) {
146+
foreach ($this->precedenceChanges as $op => $changes) {
147+
if (!\in_array($operator, $changes, true)) {
144148
continue;
145149
}
146-
if ($node->hasAttribute('operator') && $operatorName === $node->getAttribute('operator')) {
147-
$change = $this->operators->getUnary($target)->getPrecedenceChange();
148-
trigger_deprecation($change->getPackage(), $change->getVersion(), \sprintf('Add explicit parentheses around the "%s" unary operator to avoid behavior change in the next major version as its precedence will change in "%s" at line %d.', $target, $this->parser->getStream()->getSourceContext()->getName(), $node->getTemplateLine()));
150+
if ($node->hasAttribute('operator') && $op === $node->getAttribute('operator')) {
151+
$change = $operator->getPrecedenceChange();
152+
trigger_deprecation($change->getPackage(), $change->getVersion(), \sprintf('Add explicit parentheses around the "%s" unary operator to avoid behavior change in the next major version as its precedence will change in "%s" at line %d.', $operator->getOperator(), $this->parser->getStream()->getSourceContext()->getName(), $node->getTemplateLine()));
149153
}
150154
}
151155
} else {
152-
foreach ($this->precedenceChanges[$expr->getAttribute('operator')] as $operatorName) {
156+
foreach ($this->precedenceChanges[$expr->getAttribute('operator')] as $operator) {
153157
foreach ($expr as $node) {
154158
/** @var AbstractExpression $node */
155-
if ($node->hasAttribute('operator') && $operatorName === $node->getAttribute('operator') && !$node->hasExplicitParentheses()) {
156-
$op = explode('_', $operatorName)[1];
157-
$change = $this->operators->getBinary($op)->getPrecedenceChange();
158-
trigger_deprecation($change->getPackage(), $change->getVersion(), \sprintf('Add explicit parentheses around the "%s" binary operator to avoid behavior change in the next major version as its precedence will change in "%s" at line %d.', $op, $this->parser->getStream()->getSourceContext()->getName(), $node->getTemplateLine()));
159+
if ($node->hasAttribute('operator') && $operator === $node->getAttribute('operator') && !$node->hasExplicitParentheses()) {
160+
$change = $operator->getPrecedenceChange();
161+
trigger_deprecation($change->getPackage(), $change->getVersion(), \sprintf('Add explicit parentheses around the "%s" binary operator to avoid behavior change in the next major version as its precedence will change in "%s" at line %d.', $operator->getOperator(), $this->parser->getStream()->getSourceContext()->getName(), $node->getTemplateLine()));
159162
}
160163
}
161164
}
@@ -230,7 +233,7 @@ private function getPrimary(): AbstractExpression
230233
$class = $operator->getNodeClass();
231234

232235
$expr = new $class($expr, $token->getLine());
233-
$expr->setAttribute('operator', OperatorArity::Unary->value.'_'.$token->getValue());
236+
$expr->setAttribute('operator', $operator);
234237

235238
if ($this->deprecationCheck) {
236239
$this->triggerPrecedenceDeprecations($expr);

src/Operator/AbstractOperator.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,9 @@ public function getAliases(): array
2424
{
2525
return [];
2626
}
27+
28+
public function getId(): string
29+
{
30+
return 'arity_'.$this->getArity()->value.'_operator_'.$this->getOperator();
31+
}
2732
}

src/Operator/OperatorArity.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111

1212
namespace Twig\Operator;
1313

14-
enum OperatorArity: string
14+
enum OperatorArity: int
1515
{
16-
case Unary = 'unary';
17-
case Binary = 'binary';
18-
case Ternary = 'ternary';
16+
case Unary = 1;
17+
case Binary = 2;
18+
case Ternary = 3;
1919
}

src/Operator/OperatorInterface.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,9 @@ public function getPrecedence(): int;
2626
public function getPrecedenceChange(): ?OperatorPrecedenceChange;
2727

2828
public function getAliases(): array;
29+
30+
/**
31+
* @return string A unique identifier for the operator.
32+
*/
33+
public function getId(): string;
2934
}

src/Operator/Operators.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
namespace Twig\Operator;
1313

1414
use Twig\Operator\Binary\AbstractBinaryOperator;
15+
use Twig\Operator\Ternary\AbstractTernaryOperator;
1516
use Twig\Operator\Unary\AbstractUnaryOperator;
1617

1718
class Operators implements \IteratorAggregate
1819
{
19-
/** @var array<AbstractOperator> */
2020
private array $operators = [];
21+
private array $aliases = [];
2122

2223
public function __construct(
2324
array $operators = [],
@@ -33,9 +34,9 @@ public function __construct(
3334
public function add(array $operators): self
3435
{
3536
foreach ($operators as $operator) {
36-
$this->operators[$operator->getArity()->value.'_'.$operator->getOperator()] = $operator;
37+
$this->operators[$operator->getArity()->value][$operator->getOperator()] = $operator;
3738
foreach ($operator->getAliases() as $alias) {
38-
$this->operators[$operator->getArity()->value.'_'.$alias] = $operator;
39+
$this->aliases[$operator->getArity()->value][$alias] = $operator;
3940
}
4041
}
4142

@@ -44,16 +45,19 @@ public function add(array $operators): self
4445

4546
public function getUnary(string $name): ?AbstractUnaryOperator
4647
{
47-
return $this->operators[OperatorArity::Unary->value.'_'.$name] ?? null;
48+
return $this->operators[OperatorArity::Unary->value][$name] ?? ($this->aliases[OperatorArity::Unary->value][$name] ?? null);
4849
}
4950

5051
public function getBinary(string $name): ?AbstractBinaryOperator
5152
{
52-
return $this->operators[OperatorArity::Binary->value.'_'.$name] ?? null;
53+
return $this->operators[OperatorArity::Binary->value][$name] ?? ($this->aliases[OperatorArity::Binary->value][$name] ?? null);
5354
}
5455

5556
public function getIterator(): \Traversable
5657
{
57-
return new \ArrayIterator($this->operators);
58+
foreach ($this->operators as $operators) {
59+
// we don't yield the keys
60+
yield from $operators;
61+
}
5862
}
5963
}

0 commit comments

Comments
 (0)