-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature #4543 Move operator definitions to objects (fabpot)
This PR was squashed before being merged into the 3.x branch. Discussion ---------- Move operator definitions to objects Commits ------- 79d828b Fix version 251c0b5 Fix CS 561c662 Remove obsolete code 4b57f48 Use generics in ExpressionParsers 8ff1909 Fix precedence rules 0cb5c0e Add deprecation notices in CHANGELOG and docs f67078b Move Operators to ExpressionParsers, deprecate ExpressionParser 9334a70 Add a script to update operator precedence documentation 42c82e1 Extract operators logic from ExpressionParser to their own classes df877a1 Introduce operator classes to describe operators provided by extensions instead of arrays
- Loading branch information
Showing
72 changed files
with
2,541 additions
and
1,064 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
/.github/ export-ignore | ||
/bin/ export-ignore | ||
/doc/ export-ignore | ||
/extra/ export-ignore | ||
/tests/ export-ignore | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of Twig. | ||
* | ||
* (c) Fabien Potencier | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
use Twig\Environment; | ||
use Twig\ExpressionParser\ExpressionParserDescriptionInterface; | ||
use Twig\ExpressionParser\ExpressionParserType; | ||
use Twig\ExpressionParser\InfixAssociativity; | ||
use Twig\ExpressionParser\InfixExpressionParserInterface; | ||
use Twig\Loader\ArrayLoader; | ||
|
||
require_once \dirname(__DIR__).'/vendor/autoload.php'; | ||
|
||
$output = fopen(\dirname(__DIR__).'/doc/operators_precedence.rst', 'w'); | ||
|
||
$twig = new Environment(new ArrayLoader([])); | ||
$expressionParsers = []; | ||
foreach ($twig->getExpressionParsers() as $expressionParser) { | ||
$expressionParsers[] = $expressionParser; | ||
} | ||
|
||
fwrite($output, "\n=========== ================ ======= ============= ===========\n"); | ||
fwrite($output, "Precedence Operator Type Associativity Description\n"); | ||
fwrite($output, '=========== ================ ======= ============= ==========='); | ||
|
||
usort($expressionParsers, fn ($a, $b) => $b->getPrecedence() <=> $a->getPrecedence()); | ||
|
||
$previous = null; | ||
foreach ($expressionParsers as $expressionParser) { | ||
$precedence = $expressionParser->getPrecedence(); | ||
$previousPrecedence = $previous ? $previous->getPrecedence() : \PHP_INT_MAX; | ||
$associativity = $expressionParser instanceof InfixExpressionParserInterface ? (InfixAssociativity::Left === $expressionParser->getAssociativity() ? 'Left' : 'Right') : 'n/a'; | ||
$previousAssociativity = $previous ? ($previous instanceof InfixExpressionParserInterface ? (InfixAssociativity::Left === $previous->getAssociativity() ? 'Left' : 'Right') : 'n/a') : 'n/a'; | ||
if ($previousPrecedence !== $precedence) { | ||
$previous = null; | ||
} | ||
fwrite($output, rtrim(\sprintf("\n%-11s %-16s %-7s %-13s %s\n", | ||
(!$previous || $previousPrecedence !== $precedence ? $precedence : '').($expressionParser->getPrecedenceChange() ? ' => '.$expressionParser->getPrecedenceChange()->getNewPrecedence() : ''), | ||
'``'.$expressionParser->getName().'``', | ||
!$previous || ExpressionParserType::getType($previous) !== ExpressionParserType::getType($expressionParser) ? ExpressionParserType::getType($expressionParser)->value : '', | ||
!$previous || $previousAssociativity !== $associativity ? $associativity : '', | ||
$expressionParser instanceof ExpressionParserDescriptionInterface ? $expressionParser->getDescription() : '', | ||
))); | ||
$previous = $expressionParser; | ||
} | ||
fwrite($output, "\n=========== ================ ======= ============= ===========\n"); | ||
fwrite($output, "\nWhen a precedence will change in 4.0, the new precedence is indicated by the arrow ``=>``.\n"); | ||
|
||
fwrite($output, "\nHere is the same table for Twig 4.0 with adjusted precedences:\n"); | ||
|
||
fwrite($output, "\n=========== ================ ======= ============= ===========\n"); | ||
fwrite($output, "Precedence Operator Type Associativity Description\n"); | ||
fwrite($output, '=========== ================ ======= ============= ==========='); | ||
|
||
usort($expressionParsers, function ($a, $b) { | ||
$aPrecedence = $a->getPrecedenceChange() ? $a->getPrecedenceChange()->getNewPrecedence() : $a->getPrecedence(); | ||
$bPrecedence = $b->getPrecedenceChange() ? $b->getPrecedenceChange()->getNewPrecedence() : $b->getPrecedence(); | ||
|
||
return $bPrecedence - $aPrecedence; | ||
}); | ||
|
||
$previous = null; | ||
foreach ($expressionParsers as $expressionParser) { | ||
$precedence = $expressionParser->getPrecedenceChange() ? $expressionParser->getPrecedenceChange()->getNewPrecedence() : $expressionParser->getPrecedence(); | ||
$previousPrecedence = $previous ? ($previous->getPrecedenceChange() ? $previous->getPrecedenceChange()->getNewPrecedence() : $previous->getPrecedence()) : \PHP_INT_MAX; | ||
$associativity = $expressionParser instanceof InfixExpressionParserInterface ? (InfixAssociativity::Left === $expressionParser->getAssociativity() ? 'Left' : 'Right') : 'n/a'; | ||
$previousAssociativity = $previous ? ($previous instanceof InfixExpressionParserInterface ? (InfixAssociativity::Left === $previous->getAssociativity() ? 'Left' : 'Right') : 'n/a') : 'n/a'; | ||
if ($previousPrecedence !== $precedence) { | ||
$previous = null; | ||
} | ||
fwrite($output, rtrim(\sprintf("\n%-11s %-16s %-7s %-13s %s\n", | ||
!$previous || $previousPrecedence !== $precedence ? $precedence : '', | ||
'``'.$expressionParser->getName().'``', | ||
!$previous || ExpressionParserType::getType($previous) !== ExpressionParserType::getType($expressionParser) ? ExpressionParserType::getType($expressionParser)->value : '', | ||
!$previous || $previousAssociativity !== $associativity ? $associativity : '', | ||
$expressionParser instanceof ExpressionParserDescriptionInterface ? $expressionParser->getDescription() : '', | ||
))); | ||
$previous = $expressionParser; | ||
} | ||
fwrite($output, "\n=========== ================ ======= ============= ===========\n"); | ||
|
||
fclose($output); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
|
||
=========== ================ ======= ============= =========== | ||
Precedence Operator Type Associativity Description | ||
=========== ================ ======= ============= =========== | ||
512 => 300 ``|`` infix Left Twig filter call | ||
``(`` Twig function call | ||
``.`` Get an attribute on a variable | ||
``[`` Array access | ||
500 ``-`` prefix n/a | ||
``+`` | ||
300 => 5 ``??`` infix Right Null coalescing operator (a ?? b) | ||
250 ``=>`` infix Left Arrow function (x => expr) | ||
200 ``**`` infix Right Exponentiation operator | ||
100 ``is`` infix Left Twig tests | ||
``is not`` Twig tests | ||
60 ``*`` infix Left | ||
``/`` | ||
``//`` Floor division | ||
``%`` | ||
50 => 70 ``not`` prefix n/a | ||
40 => 27 ``~`` infix Left | ||
30 ``+`` infix Left | ||
``-`` | ||
25 ``..`` infix Left | ||
20 ``==`` infix Left | ||
``!=`` | ||
``<=>`` | ||
``<`` | ||
``>`` | ||
``>=`` | ||
``<=`` | ||
``not in`` | ||
``in`` | ||
``matches`` | ||
``starts with`` | ||
``ends with`` | ||
``has some`` | ||
``has every`` | ||
18 ``b-and`` infix Left | ||
17 ``b-xor`` infix Left | ||
16 ``b-or`` infix Left | ||
15 ``and`` infix Left | ||
12 ``xor`` infix Left | ||
10 ``or`` infix Left | ||
5 ``?:`` infix Right Elvis operator (a ?: b) | ||
``?:`` Elvis operator (a ?: b) | ||
0 ``(`` prefix n/a Explicit group expression (a) | ||
``literal`` A literal value (boolean, string, number, sequence, mapping, ...) | ||
``?`` infix Left Conditional operator (a ? b : c) | ||
=========== ================ ======= ============= =========== | ||
|
||
When a precedence will change in 4.0, the new precedence is indicated by the arrow ``=>``. | ||
|
||
Here is the same table for Twig 4.0 with adjusted precedences: | ||
|
||
=========== ============== ======= ============= =========== | ||
Precedence Operator Type Associativity Description | ||
=========== ============== ======= ============= =========== | ||
512 `(` infix Left Twig function call | ||
`.` Get an attribute on a variable | ||
`[` Array access | ||
500 `-` prefix n/a | ||
`+` | ||
300 `|` infix Left Twig filter call | ||
250 `=>` infix Left Arrow function (x => expr) | ||
200 `**` infix Right Exponentiation operator | ||
100 `is` infix Left Twig tests | ||
`is not` Twig tests | ||
70 `not` prefix n/a | ||
60 `*` infix Left | ||
`/` | ||
`//` Floor division | ||
`%` | ||
30 `+` infix Left | ||
`-` | ||
27 `~` infix Left | ||
25 `..` infix Left | ||
20 `==` infix Left | ||
`!=` | ||
`<=>` | ||
`<` | ||
`>` | ||
`>=` | ||
`<=` | ||
`not in` | ||
`in` | ||
`matches` | ||
`starts with` | ||
`ends with` | ||
`has some` | ||
`has every` | ||
18 `b-and` infix Left | ||
17 `b-xor` infix Left | ||
16 `b-or` infix Left | ||
15 `and` infix Left | ||
12 `xor` infix Left | ||
10 `or` infix Left | ||
5 `??` infix Right Null coalescing operator (a ?? b) | ||
`?:` Elvis operator (a ?: b) | ||
`?:` Elvis operator (a ?: b) | ||
0 `(` prefix n/a Explicit group expression (a) | ||
`literal` A literal value (boolean, string, number, sequence, mapping, ...) | ||
`?` infix Left Conditional operator (a ? b : c) | ||
=========== ============== ======= ============= =========== |
Oops, something went wrong.