Skip to content

Commit b406142

Browse files
committed
Refactor rest of Expressions
1 parent 81cda11 commit b406142

36 files changed

+1079
-601
lines changed

lib/PHPCfg/Operand/Temporary.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
class Temporary extends Operand
1717
{
18-
public $original;
18+
public ?Operand $original;
1919

2020
/**
2121
* Constructs a temporary variable

lib/PHPCfg/Parser.php

Lines changed: 15 additions & 575 deletions
Large diffs are not rendered by default.

lib/PHPCfg/ParserHandler.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace PHPCfg;
1313

14+
use LogicException;
1415
use PhpParser\Node;
1516

1617
abstract class ParserHandler
@@ -24,11 +25,11 @@ public function __construct(Parser $parser)
2425

2526
public function handleExpr(Node\Expr $expr): Operand
2627
{
27-
throw new \LogicException("Expr " . $expr->getType() . " not Implemented Yet");
28+
throw new LogicException("Expr " . $expr->getType() . " not Implemented Yet");
2829
}
2930
public function handleStmt(Node\Stmt $stmt): void
3031
{
31-
throw new \LogicException("Stmt " . $stmt->getType() . " not Implemented Yet");
32+
throw new LogicException("Stmt " . $stmt->getType() . " not Implemented Yet");
3233
}
3334

3435
public function getName(): string
@@ -73,6 +74,15 @@ protected function mapAttributes(Node $expr): array
7374
protected function addOp(Op $op): void
7475
{
7576
$this->parser->block->children[] = $op;
77+
switch ($op->getType()) {
78+
case 'Stmt_JumpIf':
79+
$op->if->addParent($this->parser->block);
80+
$op->else->addParent($this->parser->block);
81+
break;
82+
case 'Stmt_Jump':
83+
$op->target->addParent($this->parser->block);
84+
break;
85+
}
7686
}
7787

7888
protected function addExpr(Op\Expr $expr): Operand
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
/**
4+
* This file is part of PHP-CFG, a Control flow graph implementation for PHP
5+
*
6+
* @copyright 2015 Anthony Ferrara. All rights reserved
7+
* @license MIT See LICENSE at the root of the project for more info
8+
*/
9+
10+
namespace PHPCfg\ParserHandler\Batch;
11+
12+
use PHPCfg\Op;
13+
use PHPCfg\Operand;
14+
use PHPCfg\ParserHandler;
15+
use PhpParser\Node;
16+
use PhpParser\Node\Expr;
17+
use RuntimeException;
18+
19+
class AssignOp extends ParserHandler
20+
{
21+
private const MAP = [
22+
'Expr_AssignOp_BitwiseAnd' => Op\Expr\BinaryOp\BitwiseAnd::class,
23+
'Expr_AssignOp_BitwiseOr' => Op\Expr\BinaryOp\BitwiseOr::class,
24+
'Expr_AssignOp_BitwiseXor' => Op\Expr\BinaryOp\BitwiseXor::class,
25+
'Expr_AssignOp_Coalesce' => Op\Expr\BinaryOp\Coalesce::class,
26+
'Expr_AssignOp_Concat' => Op\Expr\BinaryOp\Concat::class,
27+
'Expr_AssignOp_Div' => Op\Expr\BinaryOp\Div::class,
28+
'Expr_AssignOp_Minus' => Op\Expr\BinaryOp\Minus::class,
29+
'Expr_AssignOp_Mod' => Op\Expr\BinaryOp\Mod::class,
30+
'Expr_AssignOp_Mul' => Op\Expr\BinaryOp\Mul::class,
31+
'Expr_AssignOp_Plus' => Op\Expr\BinaryOp\Plus::class,
32+
'Expr_AssignOp_Pow' => Op\Expr\BinaryOp\Pow::class,
33+
'Expr_AssignOp_ShiftLeft' => Op\Expr\BinaryOp\ShiftLeft::class,
34+
'Expr_AssignOp_ShiftRight' => Op\Expr\BinaryOp\ShiftRight::class,
35+
];
36+
37+
public function supports(Node $expr): bool
38+
{
39+
return isset(self::MAP[$expr->getType()]);
40+
}
41+
42+
public function handleExpr(Expr $expr): Operand
43+
{
44+
$type = $expr->getType();
45+
if (!isset(self::MAP[$type])) {
46+
throw new RuntimeException("Unknown unary expression type $type");
47+
}
48+
$class = self::MAP[$type];
49+
$var = $this->parser->parseExprNode($expr->var);
50+
$read = $this->parser->readVariable($var);
51+
$write = $this->parser->writeVariable($var);
52+
$e = $this->parser->readVariable($this->parser->parseExprNode($expr->expr));
53+
54+
$attrs = $this->mapAttributes($expr);
55+
$this->addOp($op = new $class($read, $e, $attrs));
56+
return $this->addExpr(new Op\Expr\Assign($write, $op->result, $attrs));
57+
}
58+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
3+
/**
4+
* This file is part of PHP-CFG, a Control flow graph implementation for PHP
5+
*
6+
* @copyright 2015 Anthony Ferrara. All rights reserved
7+
* @license MIT See LICENSE at the root of the project for more info
8+
*/
9+
10+
namespace PHPCfg\ParserHandler\Batch;
11+
12+
use PHPCfg\Assertion;
13+
use PHPCfg\Op;
14+
use PHPCfg\Operand;
15+
use PHPCfg\ParserHandler;
16+
use PhpParser\Node;
17+
use PhpParser\Node\Expr;
18+
use PhpParser\Node\Expr\BinaryOp as AstBinaryOp;
19+
20+
class BinaryOp extends ParserHandler
21+
{
22+
private const MAP = [
23+
'Expr_BinaryOp_LogicalAnd' => '',
24+
'Expr_BinaryOp_LogicalOr' => '',
25+
'Expr_BinaryOp_BooleanAnd' => '',
26+
'Expr_BinaryOp_BooleanOr' => '',
27+
'Expr_BinaryOp_BitwiseAnd' => Op\Expr\BinaryOp\BitwiseAnd::class,
28+
'Expr_BinaryOp_BitwiseOr' => Op\Expr\BinaryOp\BitwiseOr::class,
29+
'Expr_BinaryOp_BitwiseXor' => Op\Expr\BinaryOp\BitwiseXor::class,
30+
'Expr_BinaryOp_Coalesce' => Op\Expr\BinaryOp\Coalesce::class,
31+
'Expr_BinaryOp_Concat' => Op\Expr\BinaryOp\Concat::class,
32+
'Expr_BinaryOp_Div' => Op\Expr\BinaryOp\Div::class,
33+
'Expr_BinaryOp_Equal' => Op\Expr\BinaryOp\Equal::class,
34+
'Expr_BinaryOp_Greater' => Op\Expr\BinaryOp\Greater::class,
35+
'Expr_BinaryOp_GreaterOrEqual' => Op\Expr\BinaryOp\GreaterOrEqual::class,
36+
'Expr_BinaryOp_Identical' => Op\Expr\BinaryOp\Identical::class,
37+
'Expr_BinaryOp_LogicalXor' => Op\Expr\BinaryOp\LogicalXor::class,
38+
'Expr_BinaryOp_Minus' => Op\Expr\BinaryOp\Minus::class,
39+
'Expr_BinaryOp_Mod' => Op\Expr\BinaryOp\Mod::class,
40+
'Expr_BinaryOp_Mul' => Op\Expr\BinaryOp\Mul::class,
41+
'Expr_BinaryOp_NotEqual' => Op\Expr\BinaryOp\NotEqual::class,
42+
'Expr_BinaryOp_NotIdentical' => Op\Expr\BinaryOp\NotIdentical::class,
43+
'Expr_BinaryOp_Plus' => Op\Expr\BinaryOp\Plus::class,
44+
'Expr_BinaryOp_Pow' => Op\Expr\BinaryOp\Pow::class,
45+
'Expr_BinaryOp_ShiftLeft' => Op\Expr\BinaryOp\ShiftLeft::class,
46+
'Expr_BinaryOp_ShiftRight' => Op\Expr\BinaryOp\ShiftRight::class,
47+
'Expr_BinaryOp_Smaller' => Op\Expr\BinaryOp\Smaller::class,
48+
'Expr_BinaryOp_SmallerOrEqual' => Op\Expr\BinaryOp\SmallerOrEqual::class,
49+
'Expr_BinaryOp_Spaceship' => Op\Expr\BinaryOp\Spaceship::class,
50+
];
51+
52+
public function supports(Node $expr): bool
53+
{
54+
return isset(self::MAP[$expr->getType()]);
55+
}
56+
57+
public function handleExpr(Expr $expr): Operand
58+
{
59+
$type = $expr->getType();
60+
if (!isset(self::MAP[$type])) {
61+
throw new \RuntimeException("Unknown unary expression type $type");
62+
}
63+
64+
if ($expr instanceof AstBinaryOp\LogicalAnd || $expr instanceof AstBinaryOp\BooleanAnd) {
65+
return $this->parseShortCircuiting($expr, false);
66+
}
67+
if ($expr instanceof AstBinaryOp\LogicalOr || $expr instanceof AstBinaryOp\BooleanOr) {
68+
return $this->parseShortCircuiting($expr, true);
69+
}
70+
71+
$class = self::MAP[$type];
72+
73+
$left = $this->parser->readVariable($this->parser->parseExprNode($expr->left));
74+
$right = $this->parser->readVariable($this->parser->parseExprNode($expr->right));
75+
if (empty($class)) {
76+
throw new RuntimeException('BinaryOp Not Found: ' . $expr->getType());
77+
}
78+
return $this->addExpr(new $class($left, $right, $this->mapAttributes($expr)));
79+
}
80+
81+
private function parseShortCircuiting(AstBinaryOp $expr, $isOr): Operand
82+
{
83+
$result = new Operand\Temporary();
84+
$longBlock = $this->createBlockWithCatchTarget();
85+
$endBlock = $this->createBlockWithCatchTarget();
86+
87+
$left = $this->parser->readVariable($this->parser->parseExprNode($expr->left));
88+
$if = $isOr ? $endBlock : $longBlock;
89+
$else = $isOr ? $longBlock : $endBlock;
90+
91+
$this->addOp(new Op\Stmt\JumpIf($left, $if, $else));
92+
$longBlock->addParent($this->block());
93+
$endBlock->addParent($this->block());
94+
95+
$this->block($longBlock);
96+
$right = $this->parser->readVariable($this->parser->parseExprNode($expr->right));
97+
$boolCast = new Op\Expr\Cast\Bool_($right);
98+
$this->addOp($boolCast);
99+
$this->addOp(new Op\Stmt\Jump($endBlock));
100+
$endBlock->addParent($this->block());
101+
102+
$this->block($endBlock);
103+
$phi = new Op\Phi($result, ['block' => $this->block()]);
104+
$phi->addOperand(new Operand\Literal($isOr));
105+
$phi->addOperand($boolCast->result);
106+
$this->block()->phi[] = $phi;
107+
108+
$mode = $isOr ? Assertion::MODE_UNION : Assertion::MODE_INTERSECTION;
109+
foreach ($left->assertions as $assert) {
110+
$result->addAssertion($assert['var'], $assert['assertion'], $mode);
111+
}
112+
foreach ($right->assertions as $assert) {
113+
$result->addAssertion($assert['var'], $assert['assertion'], $mode);
114+
}
115+
116+
return $result;
117+
}
118+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
/**
4+
* This file is part of PHP-CFG, a Control flow graph implementation for PHP
5+
*
6+
* @copyright 2015 Anthony Ferrara. All rights reserved
7+
* @license MIT See LICENSE at the root of the project for more info
8+
*/
9+
10+
namespace PHPCfg\ParserHandler\Batch;
11+
12+
use PHPCfg\Op;
13+
use PHPCfg\Operand;
14+
use PHPCfg\ParserHandler;
15+
use PhpParser\Node;
16+
use PhpParser\Node\Expr;
17+
use RuntimeException;
18+
19+
class IncDec extends ParserHandler
20+
{
21+
private const MAP = [
22+
'Expr_PostDec' => Op\Expr\BinaryOp\Minus::class,
23+
'Expr_PostInc' => Op\Expr\BinaryOp\Plus::class,
24+
'Expr_PreDec' => Op\Expr\BinaryOp\Minus::class,
25+
'Expr_PreInc' => Op\Expr\BinaryOp\Plus::class,
26+
];
27+
28+
public function supports(Node $expr): bool
29+
{
30+
return isset(self::MAP[$expr->getType()]);
31+
}
32+
33+
public function handleExpr(Expr $expr): Operand
34+
{
35+
$type = $expr->getType();
36+
if (!isset(self::MAP[$type])) {
37+
throw new RuntimeException("Unknown unary expression type $type");
38+
}
39+
40+
$class = self::MAP[$type];
41+
42+
$var = $this->parser->parseExprNode($expr->var);
43+
$read = $this->parser->readVariable($var);
44+
$write = $this->parser->writeVariable($var);
45+
46+
$this->addOp($op = new $class($read, new Operand\Literal(1), $this->mapAttributes($expr)));
47+
$this->addOp(new Op\Expr\Assign($write, $op->result, $this->mapAttributes($expr)));
48+
49+
if (strpos($type, 'Pre') !== false) {
50+
return $op->result;
51+
} else {
52+
return $read;
53+
}
54+
}
55+
56+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
/**
4+
* This file is part of PHP-CFG, a Control flow graph implementation for PHP
5+
*
6+
* @copyright 2015 Anthony Ferrara. All rights reserved
7+
* @license MIT See LICENSE at the root of the project for more info
8+
*/
9+
10+
namespace PHPCfg\ParserHandler\Batch;
11+
12+
use PHPCfg\Op;
13+
use PHPCfg\Operand;
14+
use PHPCfg\ParserHandler;
15+
use PhpParser\Node;
16+
use PhpParser\Node\Expr;
17+
use RuntimeException;
18+
19+
class Unary extends ParserHandler
20+
{
21+
private const MAP = [
22+
'Expr_BitwiseNot' => Op\Expr\BitwiseNot::class,
23+
'Expr_BooleanNot' => Op\Expr\BooleanNot::class,
24+
'Expr_Cast_Array' => Op\Expr\Cast\Array_::class,
25+
'Expr_Cast_Bool' => Op\Expr\Cast\Bool_::class,
26+
'Expr_Cast_Double' => Op\Expr\Cast\Double::class,
27+
'Expr_Cast_Int' => Op\Expr\Cast\Int_::class,
28+
'Expr_Cast_Object' => Op\Expr\Cast\Object_::class,
29+
'Expr_Cast_String' => Op\Expr\Cast\String_::class,
30+
'Expr_Cast_Unset' => Op\Expr\Cast\Unset_::class,
31+
'Expr_Empty' => Op\Expr\Empty_::class,
32+
'Expr_Eval' => Op\Expr\Eval_::class,
33+
'Expr_Print' => Op\Expr\Print_::class,
34+
'Expr_UnaryMinus' => Op\Expr\UnaryMinus::class,
35+
'Expr_UnaryPlus' => Op\Expr\UnaryPlus::class,
36+
];
37+
38+
public function supports(Node $expr): bool
39+
{
40+
return isset(self::MAP[$expr->getType()]);
41+
}
42+
43+
public function handleExpr(Expr $expr): Operand
44+
{
45+
$type = $expr->getType();
46+
if (!isset(self::MAP[$type])) {
47+
throw new RuntimeException("Unknown unary expression type $type");
48+
}
49+
$class = self::MAP[$type];
50+
$result = $this->addExpr(new $class(
51+
$cond = $this->parser->readVariable($this->parser->parseExprNode($expr->expr)),
52+
$this->mapAttributes($expr)
53+
));
54+
55+
if ($expr instanceof Expr\BooleanNot) {
56+
// process type assertions
57+
foreach ($cond->assertions as $assertion) {
58+
$result->addAssertion($assertion['var'], new Assertion\NegatedAssertion([$assertion['assertion']]));
59+
}
60+
}
61+
62+
return $result;
63+
}
64+
}

lib/PHPCfg/ParserHandler/Expr/ArrayDimFetch.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
use PHPCfg\Op;
1313
use PHPCfg\Operand;
14-
use PHPCfg\Parser;
1514
use PHPCfg\ParserHandler;
1615
use PhpParser\Node\Expr;
1716

@@ -29,4 +28,4 @@ public function handleExpr(Expr $expr): Operand
2928
return $this->addExpr(new Op\Expr\ArrayDimFetch($v, $d, $this->mapAttributes($expr)));
3029
}
3130

32-
}
31+
}

lib/PHPCfg/ParserHandler/Expr/Array_.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
use PHPCfg\Op;
1313
use PHPCfg\Operand;
14-
use PHPCfg\Parser;
1514
use PHPCfg\ParserHandler;
1615
use PhpParser\Node\Expr;
1716

@@ -37,4 +36,4 @@ public function handleExpr(Expr $expr): Operand
3736
return $this->addExpr($array = new Op\Expr\Array_($keys, $values, $byRef, $this->mapAttributes($expr)));
3837
}
3938

40-
}
39+
}

0 commit comments

Comments
 (0)