-
-
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 #4482 Enforce AbstractBinary for all binary operators (fabpot)
This PR was merged into the 3.x branch. Discussion ---------- Enforce AbstractBinary for all binary operators Commits ------- 4f8ba93 Enforce AbstractBinary for all binary operators
- Loading branch information
Showing
20 changed files
with
351 additions
and
47 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
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,50 @@ | ||
<?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. | ||
*/ | ||
|
||
namespace Twig\Node\Expression\Binary; | ||
|
||
use Twig\Compiler; | ||
use Twig\Node\Expression\AbstractExpression; | ||
use Twig\Node\Expression\OperatorEscapeInterface; | ||
|
||
final class ElvisBinary extends AbstractBinary implements OperatorEscapeInterface | ||
{ | ||
public function __construct(AbstractExpression $left, AbstractExpression $right, int $lineno) | ||
{ | ||
parent::__construct($left, $right, $lineno); | ||
|
||
$this->setNode('test', clone $left); | ||
$left->setAttribute('always_defined', true); | ||
} | ||
|
||
public function compile(Compiler $compiler): void | ||
{ | ||
$compiler | ||
->raw('((') | ||
->subcompile($this->getNode('test')) | ||
->raw(') ? (') | ||
->subcompile($this->getNode('left')) | ||
->raw(') : (') | ||
->subcompile($this->getNode('right')) | ||
->raw('))') | ||
; | ||
} | ||
|
||
public function operator(Compiler $compiler): Compiler | ||
{ | ||
return $compiler->raw('?:'); | ||
} | ||
|
||
public function getOperandNamesToEscape(): array | ||
{ | ||
return ['left', 'right']; | ||
} | ||
} |
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,84 @@ | ||
<?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. | ||
*/ | ||
|
||
namespace Twig\Node\Expression\Binary; | ||
|
||
use Twig\Compiler; | ||
use Twig\Node\EmptyNode; | ||
use Twig\Node\Expression\AbstractExpression; | ||
use Twig\Node\Expression\BlockReferenceExpression; | ||
use Twig\Node\Expression\NameExpression; | ||
use Twig\Node\Expression\OperatorEscapeInterface; | ||
use Twig\Node\Expression\Test\DefinedTest; | ||
use Twig\Node\Expression\Test\NullTest; | ||
use Twig\Node\Expression\Unary\NotUnary; | ||
use Twig\TwigTest; | ||
|
||
final class NullCoalesceBinary extends AbstractBinary implements OperatorEscapeInterface | ||
{ | ||
public function __construct(AbstractExpression $left, AbstractExpression $right, int $lineno) | ||
{ | ||
parent::__construct($left, $right, $lineno); | ||
|
||
if (!$left instanceof NameExpression) { | ||
$left = clone $left; | ||
$test = new DefinedTest($left, new TwigTest('defined'), new EmptyNode(), $left->getTemplateLine()); | ||
// for "block()", we don't need the null test as the return value is always a string | ||
if (!$left instanceof BlockReferenceExpression) { | ||
$test = new AndBinary( | ||
$test, | ||
new NotUnary(new NullTest($left, new TwigTest('null'), new EmptyNode(), $left->getTemplateLine()), $left->getTemplateLine()), | ||
$left->getTemplateLine(), | ||
); | ||
} | ||
|
||
$this->setNode('test', $test); | ||
} else { | ||
$left->setAttribute('always_defined', true); | ||
} | ||
} | ||
|
||
public function compile(Compiler $compiler): void | ||
{ | ||
/* | ||
* This optimizes only one case. PHP 7 also supports more complex expressions | ||
* that can return null. So, for instance, if log is defined, log("foo") ?? "..." works, | ||
* but log($a["foo"]) ?? "..." does not if $a["foo"] is not defined. More advanced | ||
* 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->hasNode('test')) { | ||
$compiler | ||
->raw('((') | ||
->subcompile($this->getNode('test')) | ||
->raw(') ? (') | ||
->subcompile($this->getNode('left')) | ||
->raw(') : (') | ||
->subcompile($this->getNode('right')) | ||
->raw('))') | ||
; | ||
|
||
return; | ||
} | ||
|
||
parent::compile($compiler); | ||
} | ||
|
||
public function operator(Compiler $compiler): Compiler | ||
{ | ||
return $compiler->raw('??'); | ||
} | ||
|
||
public function getOperandNamesToEscape(): array | ||
{ | ||
return $this->hasNode('test') ? ['left', 'right'] : ['right']; | ||
} | ||
} |
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,25 @@ | ||
<?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. | ||
*/ | ||
|
||
namespace Twig\Node\Expression; | ||
|
||
/** | ||
* Interface implemented by n-ary operators for n > 1. | ||
* | ||
* @author Fabien Potencier <[email protected]> | ||
*/ | ||
interface OperatorEscapeInterface | ||
{ | ||
/** | ||
* @return string[] | ||
*/ | ||
public function getOperandNamesToEscape(): array; | ||
} |
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,42 @@ | ||
<?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. | ||
*/ | ||
|
||
namespace Twig\Node\Expression\Ternary; | ||
|
||
use Twig\Compiler; | ||
use Twig\Node\Expression\AbstractExpression; | ||
use Twig\Node\Expression\OperatorEscapeInterface; | ||
|
||
final class ConditionalTernary extends AbstractExpression implements OperatorEscapeInterface | ||
{ | ||
public function __construct(AbstractExpression $test, AbstractExpression $left, AbstractExpression $right, int $lineno) | ||
{ | ||
parent::__construct(['test' => $test, 'left' => $left, 'right' => $right], [], $lineno); | ||
} | ||
|
||
public function compile(Compiler $compiler): void | ||
{ | ||
$compiler | ||
->raw('((') | ||
->subcompile($this->getNode('test')) | ||
->raw(') ? (') | ||
->subcompile($this->getNode('left')) | ||
->raw(') : (') | ||
->subcompile($this->getNode('right')) | ||
->raw('))') | ||
; | ||
} | ||
|
||
public function getOperandNamesToEscape(): array | ||
{ | ||
return ['left', 'right']; | ||
} | ||
} |
Oops, something went wrong.