Skip to content

Commit

Permalink
Fix GraphViz printer, add printScript() method
Browse files Browse the repository at this point in the history
  • Loading branch information
nikic committed Mar 28, 2016
1 parent e6638a4 commit 1b0e384
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 39 deletions.
41 changes: 30 additions & 11 deletions demo.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
<?php

require "vendor/autoload.php";
use PhpParser\ParserFactory;

require __DIR__ . "/vendor/autoload.php";

$graphviz = false;
list($fileName, $code) = getCode($argc, $argv);

$parser = new PHPCfg\Parser((new ParserFactory)->create(ParserFactory::PREFER_PHP7));

$declarations = new PHPCfg\Visitor\DeclarationFinder;
Expand All @@ -15,17 +20,31 @@
$traverser->addVisitor(new PHPCfg\Visitor\Simplifier);
$traverser->addVisitor($variables);

$code = <<<'EOF'
<?php
function foo(array $a) {
$a[] = 1;
}
EOF;


$script = $parser->parse($code, __FILE__);
$traverser->traverse($script);

$dumper = new PHPCfg\Printer\Text();
echo $dumper->printScript($script);
if ($graphviz) {
$dumper = new PHPCfg\Printer\GraphViz();
echo $dumper->printScript($script);
} else {
$dumper = new PHPCfg\Printer\Text();
echo $dumper->printScript($script);
}

function getCode($argc, $argv) {
if ($argc >= 2) {
if (strpos($argv[1], '<?php') === 0) {
return ['command line code', $argv[1]];
} else {
return [$argv[1], file_get_contents($argv[1])];
}
} else {
return [__FILE__, <<<'EOF'
<?php
function foo(array $a) {
$a[] = 1;
}
EOF
];
}
}
1 change: 1 addition & 0 deletions lib/PHPCfg/Printer.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public function __construct() {
$this->reset();
}

abstract public function printScript(Script $script);
abstract public function printFunc(Func $func);
abstract public function printVars(Func $func);

Expand Down
90 changes: 62 additions & 28 deletions lib/PHPCfg/Printer/GraphViz.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,36 @@ public function __construct(array $options = []) {
$this->options = $options + $this->options;
}

public function printFunc(Func $func) {
$graph = Graph::create("cfg");
foreach ($this->options['graph'] as $name => $value) {
$setter = 'set' . $name;
$graph->$setter($value);
public function printScript(Script $script) {
$i = 0;
$graph = $this->createGraph();
$this->printFuncWithHeader($script->main, $graph, 'func_' . ++$i . '_');
foreach ($script->functions as $func) {
$this->printFuncWithHeader($func, $graph, 'func_' - ++$i . '_');
}
$rendered = $this->render($func->cfg);
return $graph;
}

public function printFunc(Func $func) {
$graph = $this->createGraph();
$this->printFuncInfo($func, $graph, '');
return $graph;
}

protected function printFuncWithHeader(Func $func, Graph $graph, $prefix) {
$scope = $func->class ? $func->class->value . '::' : '';
$header = $this->createNode(
$prefix . 'header', "Function $scope$func->name():"
);
$graph->setNode($header);

$start = $this->printFuncInto($func, $graph, $prefix);
$edge = $this->createEdge($header, $start);
$graph->link($edge);
}

protected function printFuncInto(Func $func, Graph $graph, $prefix) {
$rendered = $this->render($func);
$nodes = new \SplObjectStorage;
foreach ($rendered['blocks'] as $block) {
$blockId = $rendered['blockIds'][$block];
Expand All @@ -46,27 +69,21 @@ public function printFunc(Func $func) {
foreach ($ops as $op) {
$output .= $this->indent("\n" . $op['label']);
}
$nodes[$block] = new Node("block_" . $blockId, $output);
foreach ($this->options['node'] as $name => $value) {
$setter = 'set' . $name;
$nodes[$block]->$setter($value);
}
$nodes[$block] = $this->createNode($prefix . "block_" . $blockId, $output);
$graph->setNode($nodes[$block]);
}

foreach ($rendered['blocks'] as $block) {
foreach ($rendered['blocks'][$block] as $op) {
foreach ($op['childBlocks'] as $child) {
$edge = new Edge($nodes[$block], $nodes[$child['block']]);
foreach ($this->options['edge'] as $name => $value) {
$setter = 'set' . $name;
$edge->$setter($value);
}
$edge = $this->createEdge($nodes[$block], $nodes[$child['block']]);
$edge->setlabel($child['name']);
$graph->link($edge);
}
}
}
return $graph;

return $nodes[$func->cfg];
}

public function printVars(Func $func) {
Expand All @@ -83,11 +100,7 @@ public function printVars(Func $func) {
}
$id = $rendered['varIds'][$var];
$output = $this->renderOperand($var);
$nodes[$var] = new Node("var_" . $id, $output);
foreach ($this->options['node'] as $name => $value) {
$setter = 'set' . $name;
$nodes[$var]->$setter($value);
}
$nodes[$var] = $this->createNode("var_" . $id, $output);
$graph->setNode($nodes[$var]);
}
foreach ($rendered['varIds'] as $var) {
Expand All @@ -102,16 +115,12 @@ public function printVars(Func $func) {
if (!$v || $write->isWriteVariable($varName) || !$nodes->contains($v)) {
continue;
}
$edge = new Edge($nodes[$v], $nodes[$var]);
$edge = $this->createEdge($nodes[$v], $nodes[$var]);
if ($b) {
$edge->setlabel('Block<' . $rendered['blockIds'][$b] . '>' . $write->getType() . ":" . $varName);
} else {
$edge->setlabel($write->getType() . ":" . $varName);
}
foreach ($this->options['edge'] as $name => $value) {
$setter = 'set' . $name;
$edge->$setter($value);
}
$graph->link($edge);
}
}
Expand All @@ -120,6 +129,31 @@ public function printVars(Func $func) {
return $graph;
}

private function createGraph() {
$graph = Graph::create("cfg");
foreach ($this->options['graph'] as $name => $value) {
$setter = 'set' . $name;
$graph->$setter($value);
}
return $graph;
}

private function createNode($id, $content) {
$node = new Node($id, $content);
foreach ($this->options['node'] as $name => $value) {
$node->{'set' . $name}($value);
}
return $node;
}

private function createEdge(Node $from, Node $to) {
$edge = new Edge($from, $to);
foreach ($this->options['edge'] as $name => $value) {
$edge->{'set' . $name}($value);
}
return $edge;
}

/**
* @param string $str
*
Expand All @@ -132,4 +166,4 @@ protected function indent($str, $levels = 1) {
return str_replace(["\n", "\\l"], "\\l ", $str);
}

}
}

0 comments on commit 1b0e384

Please sign in to comment.