Skip to content

Commit c0eee68

Browse files
committed
More iteration, some refactoring
1 parent 920262a commit c0eee68

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+627
-359
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of PHP-CFG, a Control flow graph implementation for PHP
7+
*
8+
* @copyright 2015 Anthony Ferrara. All rights reserved
9+
* @license MIT See LICENSE at the root of the project for more info
10+
*/
11+
12+
namespace PHPCfg\Op\Expr\BinaryOp;
13+
14+
use PHPCfg\Op\Expr\BinaryOp;
15+
16+
class Pipe extends BinaryOp {}

lib/PHPCfg/Op/Expr/Cast/Void_.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of PHP-CFG, a Control flow graph implementation for PHP
7+
*
8+
* @copyright 2015 Anthony Ferrara. All rights reserved
9+
* @license MIT See LICENSE at the root of the project for more info
10+
*/
11+
12+
namespace PHPCfg\Op\Expr\Cast;
13+
14+
use PHPCfg\Op\Expr\Cast;
15+
16+
class Void_ extends Cast {}

lib/PHPCfg/Op/Expr/YieldFrom.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of PHP-CFG, a Control flow graph implementation for PHP
7+
*
8+
* @copyright 2015 Anthony Ferrara. All rights reserved
9+
* @license MIT See LICENSE at the root of the project for more info
10+
*/
11+
12+
namespace PHPCfg\Op\Expr;
13+
14+
use PHPCfg\Op\Expr;
15+
use PhpCfg\Operand;
16+
17+
class YieldFrom extends Expr
18+
{
19+
public ?Operand $expr;
20+
21+
protected array $writeVariables = ['result'];
22+
23+
public function __construct(Operand $expr, array $attributes = [])
24+
{
25+
parent::__construct($attributes);
26+
$this->expr = $expr;
27+
}
28+
29+
public function getVariableNames(): array
30+
{
31+
return ['expr' => $this->expr, 'result' => $this->result];
32+
}
33+
}

lib/PHPCfg/Parser.php

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ class Parser
5151

5252
public $anonId = 0;
5353

54-
protected array $handlers = [];
55-
protected array $batchHandlers = [];
54+
protected array $stmtHandlers = [];
55+
protected array $exprHandlers = [];
56+
protected array $opHandlers = [];
5657

5758
public function __construct(AstParser $astParser, ?AstTraverser $astTraverser = null)
5859
{
@@ -69,10 +70,20 @@ public function __construct(AstParser $astParser, ?AstTraverser $astTraverser =
6970

7071
public function addHandler(string $name, ParserHandler $handler): void
7172
{
72-
if ($handler->isBatch()) {
73-
$this->batchHandlers[$name] = $handler;
74-
} else {
75-
$this->handlers[$name] = $handler;
73+
if ($handler instanceof ParserHandler\Batch) {
74+
foreach ($handler->getExprSupport() as $name) {
75+
$this->exprHandlers[$name] = $handler;
76+
}
77+
foreach ($handler->getStmtSupport() as $name) {
78+
$this->stmtHandlers[$name] = $handler;
79+
}
80+
return;
81+
}
82+
if ($handler instanceof ParserHandler\Expr) {
83+
$this->exprHandlers[$name] = $handler;
84+
}
85+
if ($handler instanceof ParserHandler\Stmt) {
86+
$this->stmtHandlers[$name] = $handler;
7687
}
7788
}
7889

@@ -92,6 +103,11 @@ protected function loadHandlers(): void
92103
$class = str_replace(__DIR__, '', $file->getPathname());
93104
$class = __NAMESPACE__ . str_replace("/", "\\", $class);
94105
$class = substr($class, 0, -4);
106+
107+
if (!class_exists($class)) {
108+
continue;
109+
}
110+
95111
$obj = new $class($this);
96112
$this->addHandler($obj->getName(), $obj);
97113
}
@@ -192,16 +208,10 @@ public function parseNode(Node $node): void
192208
}
193209

194210
$type = $node->getType();
195-
if (isset($this->handlers[$type])) {
196-
$this->handlers[$type]->handleStmt($node);
211+
if (isset($this->stmtHandlers[$type])) {
212+
$this->stmtHandlers[$type]->handleStmt($node);
197213
return;
198214
}
199-
foreach ($this->batchHandlers as $handler) {
200-
if ($handler->supports($node)) {
201-
$handler->handleStmt($node);
202-
return;
203-
}
204-
}
205215

206216
throw new RuntimeException('Unknown Node Encountered : ' . $type);
207217
}
@@ -293,13 +303,8 @@ public function parseExprNode($expr): ?Operand
293303
return new Literal($expr->value);
294304
}
295305

296-
if (isset($this->handlers[$expr->getType()])) {
297-
return $this->handlers[$expr->getType()]->handleExpr($expr);
298-
}
299-
foreach ($this->batchHandlers as $handler) {
300-
if ($handler->supports($expr)) {
301-
return $handler->handleExpr($expr);
302-
}
306+
if (isset($this->exprHandlers[$expr->getType()])) {
307+
return $this->exprHandlers[$expr->getType()]->handleExpr($expr);
303308
}
304309
throw new RuntimeException('Unknown Expr Type ' . $expr->getType());
305310
}

lib/PHPCfg/ParserHandler.php

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

1212
namespace PHPCfg;
1313

14-
use LogicException;
1514
use PhpParser\Node;
1615

1716
abstract class ParserHandler
@@ -23,20 +22,6 @@ public function __construct(Parser $parser)
2322
$this->parser = $parser;
2423
}
2524

26-
public function handleExpr(Node\Expr $expr): Operand
27-
{
28-
throw new LogicException("Expr " . $expr->getType() . " not Implemented Yet");
29-
}
30-
public function handleStmt(Node\Stmt $stmt): void
31-
{
32-
throw new LogicException("Stmt " . $stmt->getType() . " not Implemented Yet");
33-
}
34-
35-
public function isBatch(): bool
36-
{
37-
return false;
38-
}
39-
4025
public function getName(): string
4126
{
4227
$name = str_replace([__CLASS__ . '\\', '_'], '', get_class($this));

lib/PHPCfg/ParserHandler/Batch.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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;
11+
12+
interface Batch
13+
{
14+
public function getExprSupport(): array;
15+
public function getStmtSupport(): array;
16+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
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 PHPCfg\ParserHandler\Batch;
16+
use PHPCfg\ParserHandler\Expr;
17+
use PHPCfg\ParserHandler\Stmt;
18+
use PhpParser\Node;
19+
20+
class AssignAndForeach extends ParserHandler implements Expr, Stmt, Batch
21+
{
22+
public function getExprSupport(): array
23+
{
24+
return ['Expr_Assign'];
25+
}
26+
27+
public function getStmtSupport(): array
28+
{
29+
return ['Stmt_Foreach'];
30+
}
31+
32+
public function handleStmt(Node\Stmt $node): void
33+
{
34+
// Foreach Implementation
35+
$attrs = $this->mapAttributes($node);
36+
$iterable = $this->parser->readVariable($this->parser->parseExprNode($node->expr));
37+
$this->addOp(new Op\Iterator\Reset($iterable, $attrs));
38+
39+
$loopInit = $this->createBlockWithCatchTarget();
40+
$loopBody = $this->createBlockWithCatchTarget();
41+
$loopEnd = $this->createBlockWithCatchTarget();
42+
43+
$this->addOp(new Op\Stmt\Jump($loopInit, $attrs));
44+
45+
$this->block($loopInit);
46+
$result = $this->addExpr(new Op\Iterator\Valid($iterable, $attrs));
47+
$this->addOp(new Op\Stmt\JumpIf($result, $loopBody, $loopEnd, $attrs));
48+
49+
$this->block($loopBody);
50+
51+
if ($node->keyVar) {
52+
$this->addOp($keyOp = new Op\Iterator\Key($iterable, $attrs));
53+
$this->addOp(new Op\Expr\Assign($this->parser->writeVariable($this->parser->parseExprNode($node->keyVar)), $keyOp->result, $attrs));
54+
}
55+
56+
$this->addOp($valueOp = new Op\Iterator\Value($iterable, $node->byRef, $attrs));
57+
58+
if ($node->valueVar instanceof Node\Expr\List_ || $node->valueVar instanceof Node\Expr\Array_) {
59+
$this->parseListAssignment($node->valueVar, $valueOp->result);
60+
} elseif ($node->byRef) {
61+
$this->addOp(new Op\Expr\AssignRef($this->parser->writeVariable($this->parser->parseExprNode($node->valueVar)), $valueOp->result, $attrs));
62+
} else {
63+
$this->addOp(new Op\Expr\Assign($this->parser->writeVariable($this->parser->parseExprNode($node->valueVar)), $valueOp->result, $attrs));
64+
}
65+
66+
$this->block($this->parser->parseNodes($node->stmts, $this->block()));
67+
$this->addOp(new Op\Stmt\Jump($loopInit, $attrs));
68+
69+
$this->block($loopEnd);
70+
}
71+
72+
public function handleExpr(Node\Expr $expr): Operand
73+
{
74+
$e = $this->parser->readVariable($this->parser->parseExprNode($expr->expr));
75+
if ($expr->var instanceof Node\Expr\List_ || $expr->var instanceof Node\Expr\Array_) {
76+
$this->parseListAssignment($expr->var, $e);
77+
78+
return $e;
79+
}
80+
$v = $this->parser->writeVariable($this->parser->parseExprNode($expr->var));
81+
82+
return $this->addExpr(new Op\Expr\Assign($v, $e, $this->mapAttributes($expr)));
83+
}
84+
85+
protected function parseListAssignment(Node\Expr\List_|Node\Expr\Array_ $expr, Operand $rhs): void
86+
{
87+
foreach ($expr->items as $i => $item) {
88+
if (null === $item) {
89+
continue;
90+
}
91+
92+
if ($item->key === null) {
93+
$key = new Operand\Literal($i);
94+
} else {
95+
$key = $this->parser->readVariable($this->parser->parseExprNode($item->key));
96+
}
97+
98+
$var = $item->value;
99+
$result = $this->addExpr(new Op\Expr\ArrayDimFetch($rhs, $key, $this->mapAttributes($expr)));
100+
if ($var instanceof Node\Expr\List_ || $var instanceof Node\Expr\Array_) {
101+
$this->parseListAssignment($var, $result);
102+
103+
continue;
104+
}
105+
106+
$this->addOp(new Op\Expr\Assign(
107+
$this->parser->writeVariable($this->parser->parseExprNode($var)),
108+
$result,
109+
$this->mapAttributes($expr),
110+
));
111+
}
112+
}
113+
}

lib/PHPCfg/ParserHandler/Batch/AssignOp.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
use PHPCfg\Op;
1313
use PHPCfg\Operand;
1414
use PHPCfg\ParserHandler;
15+
use PHPCfg\ParserHandler\Batch;
16+
use PHPCfg\ParserHandler\Expr;
1517
use PhpParser\Node;
16-
use PhpParser\Node\Expr;
1718
use RuntimeException;
1819

19-
class AssignOp extends ParserHandler
20+
class AssignOp extends ParserHandler implements Expr, Batch
2021
{
2122
private const MAP = [
2223
'Expr_AssignOp_BitwiseAnd' => Op\Expr\BinaryOp\BitwiseAnd::class,
@@ -34,17 +35,17 @@ class AssignOp extends ParserHandler
3435
'Expr_AssignOp_ShiftRight' => Op\Expr\BinaryOp\ShiftRight::class,
3536
];
3637

37-
public function isBatch(): bool
38+
public function getExprSupport(): array
3839
{
39-
return true;
40+
return array_keys(self::MAP);
4041
}
4142

42-
public function supports(Node $expr): bool
43+
public function getStmtSupport(): array
4344
{
44-
return isset(self::MAP[$expr->getType()]);
45+
return [];
4546
}
4647

47-
public function handleExpr(Expr $expr): Operand
48+
public function handleExpr(Node\Expr $expr): Operand
4849
{
4950
$type = $expr->getType();
5051
if (!isset(self::MAP[$type])) {

lib/PHPCfg/ParserHandler/Batch/BinaryOp.php

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
use PHPCfg\Op;
1414
use PHPCfg\Operand;
1515
use PHPCfg\ParserHandler;
16+
use PHPCfg\ParserHandler\Batch;
17+
use PHPCfg\ParserHandler\Expr;
1618
use PhpParser\Node;
17-
use PhpParser\Node\Expr;
1819
use PhpParser\Node\Expr\BinaryOp as AstBinaryOp;
1920

20-
class BinaryOp extends ParserHandler
21+
class BinaryOp extends ParserHandler implements Expr, Batch
2122
{
2223
private const MAP = [
2324
'Expr_BinaryOp_LogicalAnd' => '',
@@ -40,6 +41,7 @@ class BinaryOp extends ParserHandler
4041
'Expr_BinaryOp_Mul' => Op\Expr\BinaryOp\Mul::class,
4142
'Expr_BinaryOp_NotEqual' => Op\Expr\BinaryOp\NotEqual::class,
4243
'Expr_BinaryOp_NotIdentical' => Op\Expr\BinaryOp\NotIdentical::class,
44+
'Expr_BinaryOp_Pipe' => Op\Expr\BinaryOp\Pipe::class,
4345
'Expr_BinaryOp_Plus' => Op\Expr\BinaryOp\Plus::class,
4446
'Expr_BinaryOp_Pow' => Op\Expr\BinaryOp\Pow::class,
4547
'Expr_BinaryOp_ShiftLeft' => Op\Expr\BinaryOp\ShiftLeft::class,
@@ -49,17 +51,17 @@ class BinaryOp extends ParserHandler
4951
'Expr_BinaryOp_Spaceship' => Op\Expr\BinaryOp\Spaceship::class,
5052
];
5153

52-
public function isBatch(): bool
54+
public function getExprSupport(): array
5355
{
54-
return true;
56+
return array_keys(self::MAP);
5557
}
5658

57-
public function supports(Node $expr): bool
59+
public function getStmtSupport(): array
5860
{
59-
return isset(self::MAP[$expr->getType()]);
61+
return [];
6062
}
6163

62-
public function handleExpr(Expr $expr): Operand
64+
public function handleExpr(Node\Expr $expr): Operand
6365
{
6466
$type = $expr->getType();
6567
if (!isset(self::MAP[$type])) {

0 commit comments

Comments
 (0)