diff --git a/composer.json b/composer.json index d78f5ac..74fdd78 100755 --- a/composer.json +++ b/composer.json @@ -27,4 +27,4 @@ "bin": [ "bin/php-cfg" ] -} +} \ No newline at end of file diff --git a/lib/PHPCfg/Op/Terminal/StaticVar.php b/lib/PHPCfg/Op/Terminal/StaticVar.php index 4026d05..3d7dcc0 100755 --- a/lib/PHPCfg/Op/Terminal/StaticVar.php +++ b/lib/PHPCfg/Op/Terminal/StaticVar.php @@ -21,7 +21,7 @@ class StaticVar extends Terminal public ?Block $defaultBlock; - public ?Operand $defaultVar; + public ?Operand $defaultVar = null; public function __construct(Operand $var, ?Block $defaultBlock = null, ?Operand $defaultVar = null, array $attributes = []) { diff --git a/lib/PHPCfg/Parser.php b/lib/PHPCfg/Parser.php index bcf7dac..836f507 100755 --- a/lib/PHPCfg/Parser.php +++ b/lib/PHPCfg/Parser.php @@ -91,9 +91,9 @@ protected function loadHandlers(): void { $it = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( - __DIR__ . '/ParserHandler/', - RecursiveIteratorIterator::LEAVES_ONLY - ) + __DIR__ . '/ParserHandler/' + ), + RecursiveIteratorIterator::LEAVES_ONLY ); $handlers = []; foreach ($it as $file) { @@ -310,7 +310,7 @@ public function parseExprNode($expr): ?Operand if (isset($this->exprHandlers[$expr->getType()])) { return $this->exprHandlers[$expr->getType()]->handleExpr($expr); } - var_dump(array_keys($this->exprHandlers)); + throw new RuntimeException('Unknown Expr Type ' . $expr->getType()); } @@ -456,6 +456,7 @@ public function readVariableRecursive(string $name, Block $block): Operand return $var; } + $var = new Temporary(new Variable(new Literal($name))); $phi = new Op\Phi($var, ['block' => $block]); $this->ctx->addToIncompletePhis($block, $name, $phi); diff --git a/lib/PHPCfg/ParserHandler/Batch/Scalar.php b/lib/PHPCfg/ParserHandler/Batch/Scalar.php index 7523ff5..8019387 100644 --- a/lib/PHPCfg/ParserHandler/Batch/Scalar.php +++ b/lib/PHPCfg/ParserHandler/Batch/Scalar.php @@ -78,7 +78,6 @@ public function handleExpr(Node\Expr $scalar): Operand // TODO return new Operand\Literal('__FUNCTION__'); default: - var_dump($scalar); throw new RuntimeException('Unknown how to deal with scalar type ' . $scalar->getType()); } } diff --git a/lib/PHPCfg/ParserHandler/Batch/Unary.php b/lib/PHPCfg/ParserHandler/Batch/Unary.php index 921c09e..58b41fe 100644 --- a/lib/PHPCfg/ParserHandler/Batch/Unary.php +++ b/lib/PHPCfg/ParserHandler/Batch/Unary.php @@ -9,6 +9,7 @@ namespace PHPCfg\ParserHandler\Batch; +use PHPCfg\Assertion; use PHPCfg\Op; use PHPCfg\Operand; use PHPCfg\ParserHandler; diff --git a/lib/PHPCfg/ParserHandler/Expr/ConstFetch.php b/lib/PHPCfg/ParserHandler/Expr/ConstFetch.php index 395f2a0..c6b96ff 100644 --- a/lib/PHPCfg/ParserHandler/Expr/ConstFetch.php +++ b/lib/PHPCfg/ParserHandler/Expr/ConstFetch.php @@ -19,16 +19,14 @@ class ConstFetch extends ParserHandler implements Expr { public function handleExpr(Node\Expr $expr): Operand { - if ($expr->name->isUnqualified()) { - $lcname = strtolower($expr->name->toString()); - switch ($lcname) { - case 'null': - return new Operand\Literal(null); - case 'true': - return new Operand\Literal(true); - case 'false': - return new Operand\Literal(false); - } + $lcname = strtolower($expr->name->toString()); + switch ($lcname) { + case 'null': + return new Operand\NullOperand(); + case 'true': + return new Operand\Literal(true); + case 'false': + return new Operand\Literal(false); } $nsName = null; diff --git a/lib/PHPCfg/Printer/Printer.php b/lib/PHPCfg/Printer/Printer.php index 53f838c..ddb3828 100755 --- a/lib/PHPCfg/Printer/Printer.php +++ b/lib/PHPCfg/Printer/Printer.php @@ -11,6 +11,7 @@ namespace PHPCfg\Printer; +use FilesystemIterator; use LogicException; use PHPCfg\Block; use PHPCfg\Func; @@ -59,10 +60,13 @@ protected function loadRenderers(): void $it = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( __DIR__ . '/Renderer/', - RecursiveIteratorIterator::LEAVES_ONLY - ) + FilesystemIterator::SKIP_DOTS + ), + RecursiveIteratorIterator::LEAVES_ONLY ); + $handlers = []; + $classes = []; foreach ($it as $file) { if (!$file->isFile() || $file->getExtension() !== 'php') { continue; @@ -75,14 +79,32 @@ protected function loadRenderers(): void continue; } + $classes[] = $class; + } + + usort($classes, function ($a, $b) { + $aParts = substr_count($a, '\\'); + $bParts = substr_count($b, '\\'); + + if ($aParts == $bParts) { + return 0; + } + return ($aParts < $bParts) ? 1 : -1; + }); + + foreach ($classes as $class) { $obj = new $class($this); $this->addRenderer($obj); } } - abstract public function printScript(Script $script): string; + abstract public function printScript(Script $script): mixed; + + abstract public function printFunc(Func $func): mixed; - abstract public function printFunc(Func $func): string; + abstract public function renderOperand(Operand $var): mixed; + + abstract public function renderOpLabel(array $desc): mixed; protected function reset(): void { @@ -98,20 +120,6 @@ protected function getBlockId(Block $block): int return $this->blocks[$block]; } - public function renderOperand(Operand $var): string - { - foreach ($this->renderers as $renderer) { - $result = $renderer->renderOperand($var); - if ($result !== null) { - $kind = $result['kind']; - $type = $result['type']; - unset($result['kind'], $result['type']); - return strtoupper($kind) . $type . '(' . trim(implode(" ", $result)) . ')'; - } - } - return 'UNKNOWN'; - } - public function renderOp(Op $op): array { foreach ($this->renderers as $renderer) { @@ -121,17 +129,14 @@ public function renderOp(Op $op): array $childblocks = $result['childblocks']; return [ 'op' => $op, + 'kind' => $kind, 'label' => $this->renderOpLabel($result), 'childBlocks' => $childblocks, ]; } } - return [ - 'op' => $op, - 'label' => 'UNKNOWN', - 'childBlocks' => $childBlocks, - ]; + throw new LogicException("Unknown op rendering: " . get_class($op)); } protected function indent($str, $levels = 1): string @@ -145,7 +150,7 @@ protected function indent($str, $levels = 1): string public function enqueueBlock(Block $block): void { - if (! $this->blocks->contains($block)) { + if (! $this->blocks->offsetExists($block)) { $this->blocks[$block] = count($this->blocks) + 1; $this->blockQueue->enqueue($block); } @@ -163,14 +168,7 @@ protected function render(Func $func) $block = $this->blockQueue->dequeue(); $ops = []; foreach ($block->phi as $phi) { - $result = $this->indent($this->renderOperand($phi->result) . ' = Phi('); - $result .= implode(', ', array_map([$this, 'renderOperand'], $phi->vars)); - $result .= ')'; - $renderedOps[$phi] = $ops[] = [ - 'op' => $phi, - 'label' => $result, - 'childBlocks' => [], - ]; + $renderedOps[$phi] = $ops[] = $this->renderOp($phi); } foreach ($block->children as $child) { $renderedOps[$child] = $ops[] = $this->renderOp($child); @@ -222,24 +220,4 @@ public function renderType(?Op\Type $type): string } throw new LogicException("Unknown type rendering: " . get_class($type)); } - - public function renderOpLabel(array $desc): string - { - $result = "{$desc['kind']}"; - unset($desc['kind'], $desc['childblocks']); - foreach ($desc as $name => $val) { - if (is_array($val)) { - foreach ($val as $v) { - if (is_array($v)) { - $result .= $this->indent("\n" . implode("\n", $v)); - } else { - $result .= $this->indent("\n{$v}"); - } - } - } else { - $result .= $this->indent("\n{$val}"); - } - } - return $result; - } } diff --git a/lib/PHPCfg/Printer/Renderer/GenericOp.php b/lib/PHPCfg/Printer/Renderer/GenericOp.php index df97452..9cabc4f 100644 --- a/lib/PHPCfg/Printer/Renderer/GenericOp.php +++ b/lib/PHPCfg/Printer/Renderer/GenericOp.php @@ -30,46 +30,52 @@ public function reset(): void {} public function renderOp(Op $op): ?array { $result = [ + 'attributes' => $this->renderAttributes($op->getAttributes()), + 'attrGroups' => [], + 'childblocks' => [], 'kind' => $op->getType(), 'types' => [], 'vars' => [], - 'attributes' => $this->renderAttributes($op->getAttributes()), - 'childblocks' => [], ]; + if ($op instanceof Op\AttributableOp) { + $result['attrGroups'] = $this->renderAttrGroups($op); + } + if ($op instanceof Op\CallableOp) { $func = $op->getFunc(); - $result['vars'][] = "name: {$func->name}"; + $result['vars']['name'] = $func->name; } if ($op instanceof Op\Stmt\Property || $op instanceof Op\Stmt\ClassMethod) { - $result['vars'][] = "flags: " . $this->renderFlags($op); + $result['vars']['flags'] = $this->renderFlags($op); } - foreach ($op->getTypeNames() as $typeName => $type) { if (is_array($type)) { + $result['types'][$typeName] = []; foreach ($type as $key => $subType) { if (! $subType) { continue; } - $result['types'][] = "{$typeName}[{$key}]: " . $this->printer->renderType($subType); + $result['types'][$typeName][$key] = $this->printer->renderType($subType); } } elseif ($type) { - $result['types'][] = "{$typeName}: " . $this->printer->renderType($type); + $result['types'][$typeName] = $this->printer->renderType($type); } } foreach ($op->getVariableNames() as $varName => $vars) { if (is_array($vars)) { + $result['vars'][$varName] = []; foreach ($vars as $key => $var) { if (! $var) { continue; } - $result['vars'][] = "{$varName}[{$key}]: " . $this->printer->renderOperand($var); + $result['vars'][$varName][$key] = $this->printer->renderOperand($var); } } elseif ($vars) { - $result['vars'][] = "{$varName}: " . $this->printer->renderOperand($vars); + $result['vars'][$varName] = $this->printer->renderOperand($vars); } } @@ -91,12 +97,6 @@ public function renderOp(Op $op): ?array } } - if ($op instanceof Op\AttributableOp) { - $result['attrGroups'] = $this->renderAttrGroups($op); - } - - - return $result; } @@ -105,8 +105,6 @@ public function renderOperand(Operand $operand): ?array return null; } - - protected function renderAttributes(array $attributes): array { if (!$this->printer->renderAttributes) { @@ -115,30 +113,29 @@ protected function renderAttributes(array $attributes): array $result = []; foreach ($attributes as $key => $value) { if (is_string($value) || is_numeric($value)) { - $result[] = "attribute['" . $key . "']: " . $value; + $result['attribute'][$key] = $value; } } return $result; } - protected function renderAttrGroups(Op\AttributableOp $op): array { $result = []; + $result['attrGroup'] = []; foreach ($op->getAttributeGroups() as $indexGroup => $attrGroup) { - $result[$indexGroup] = []; - $result[$indexGroup][] = "attrGroup[$indexGroup]: "; - foreach ($this->renderAttributes($attrGroup->getAttributes()) as $attr) { - $result[$indexGroup][] = " {$attr}"; + $result['attrGroup'][$indexGroup] = []; + foreach ($this->renderAttributes($attrGroup->getAttributes()) as $i => $attr) { + $result['attrGroup'][$indexGroup][$i] = $attr; } foreach ($attrGroup->attrs as $indexAttr => $attr) { - $result[$indexGroup][] = " attr[$indexAttr]: "; - foreach ($this->renderAttributes($attr->getAttributes()) as $rendered) { - $result[$indexGroup][] = " {$rendered}"; + $result['attrGroup'][$indexGroup][$indexAttr] = []; + foreach ($this->renderAttributes($attr->getAttributes()) as $j => $rendered) { + $result['attrGroup'][$indexGroup][$indexAttr][$j] = $rendered; } - $result[$indexGroup][] = " name: " . $this->printer->renderOperand($attr->name); + $result['attrGroup'][$indexGroup][$indexAttr]['name'] = $this->printer->renderOperand($attr->name); foreach ($attr->args as $indexArg => $arg) { - $result[$indexGroup][] = " args[$indexArg]: " . $this->printer->renderOperand($arg); + $result['attrGroup'][$indexGroup][$indexAttr]['args'][$indexArg] = $this->printer->renderOperand($arg); } } } @@ -146,7 +143,6 @@ protected function renderAttrGroups(Op\AttributableOp $op): array return $result; } - protected function renderFlags(Op\Stmt $stmt): string { $result = ''; @@ -178,5 +174,4 @@ protected function renderFlags(Op\Stmt $stmt): string return $result; } - } diff --git a/lib/PHPCfg/Printer/Renderer/Op/Assertion.php b/lib/PHPCfg/Printer/Renderer/Op/Assertion.php index 1fbfb58..7fcacc8 100644 --- a/lib/PHPCfg/Printer/Renderer/Op/Assertion.php +++ b/lib/PHPCfg/Printer/Renderer/Op/Assertion.php @@ -24,25 +24,30 @@ public function renderOp(Op $op): ?array } $result = parent::renderOp($op); - $result['assert'] = 'assert: ' . $this->renderAssertion($op->assertion); + $result['vars']['assert'] = $this->renderAssertion($op->assertion); return $result; } - protected function renderAssertion(CoreAssertion $assert): string + protected function renderAssertion(CoreAssertion $assert): mixed { - if (is_array($assert->value)) { $combinator = $assert->mode === CoreAssertion::MODE_UNION ? '|' : '&'; - - $ret = implode($combinator, array_map([$this, 'renderAssertion'], $assert->value)); + if (count($assert->value) == 1) { + $ret = $this->renderAssertion($assert->value[0]); + } else { + foreach ($assert->value as $value) { + $ret[$combinator][] = $this->renderAssertion($value); + } + } } else { $ret = $this->printer->renderOperand($assert->value); } + $kind = $assert->getKind(); if ($kind === 'type' || empty($kind)) { return $ret; } - return "$kind({$ret})"; + return [$kind => $ret]; } } diff --git a/lib/PHPCfg/Printer/Renderer/Op/Include_.php b/lib/PHPCfg/Printer/Renderer/Op/Include_.php index 2bc7e8f..21906eb 100644 --- a/lib/PHPCfg/Printer/Renderer/Op/Include_.php +++ b/lib/PHPCfg/Printer/Renderer/Op/Include_.php @@ -25,21 +25,21 @@ public function renderOp(Op $op): ?array switch ($op->type) { case 1: - $result['vars'][] = "type: include"; + $result['vars']['type'] = "include"; break; case 2: - $result['vars'][] = "type: include_once"; + $result['vars']['type'] = "include_once"; break; case 3: - $result['vars'][] = "type: require"; + $result['vars']['type'] = "require"; break; case 4: - $result['vars'][] = "type: require_once"; + $result['vars']['type'] = "require_once"; break; default: throw new LogicException("Unknown include type rendering: " . $type); } + return $result; } - } diff --git a/lib/PHPCfg/Printer/Renderer/Op/TraitUse.php b/lib/PHPCfg/Printer/Renderer/Op/TraitUse.php index 0980cd3..cfba646 100644 --- a/lib/PHPCfg/Printer/Renderer/Op/TraitUse.php +++ b/lib/PHPCfg/Printer/Renderer/Op/TraitUse.php @@ -24,21 +24,23 @@ public function renderOp(Op $op): ?array $result = parent::renderOp($op); foreach ($op->traits as $index => $trait_) { - $result['vars'][] = "use[$index]: " . $this->printer->renderOperand($trait_); + $result['vars']['use'][$index] = $this->printer->renderOperand($trait_); } + + $adapt = []; foreach ($op->adaptations as $index => $adaptation) { - $adapt = []; if ($adaptation instanceof Op\TraitUseAdaptation\Alias) { - $adapt[] = "adaptation[$index]: Alias"; + $adapt['adaptation'][$index] = []; + $adapt['adaptation'][$index]['alias'] = []; if ($adaptation->trait != null) { - $adapt[] = " trait: " . $this->printer->renderOperand($adaptation->trait); + $adapt['adaptation'][$index]['alias']['trait'] = $this->printer->renderOperand($adaptation->trait); } - $adapt[] = " method: " . $this->printer->renderOperand($adaptation->method); + $adapt['adaptation'][$index]['alias']['method'] = $this->printer->renderOperand($adaptation->method); if ($adaptation->newName != null) { - $adapt[] = " newName: " . $this->printer->renderOperand($adaptation->newName); + $adapt['adaptation'][$index]['alias']['newName'] = $this->printer->renderOperand($adaptation->newName); } if ($adaptation->newModifier != null) { - $mod = " newModifier: "; + $mod = ""; if ($adaptation->isPublic()) { $mod .= "public"; } @@ -48,21 +50,22 @@ public function renderOp(Op $op): ?array if ($adaptation->isProtected()) { $mod .= "protected"; } - $adapt[] = $mod; + $adapt['adaptation'][$index]['alias']['newModifier'] = $mod; } } elseif ($adaptation instanceof Op\TraitUseAdaptation\Precedence) { - $adapt[] = "adaptation[$index]: Insteadof"; + $adapt['adaptation'][$index]['Insteadof'] = []; if ($adaptation->trait != null) { - $adapt[] = " trait: " . $this->printer->renderOperand($adaptation->trait); + $adapt['adaptation'][$index]['Insteadof']['trait'] = $this->printer->renderOperand($adaptation->trait); } - $adapt[] = " method: " . $this->printer->renderOperand($adaptation->method); + $adapt['adaptation'][$index]['Insteadof']['method'] = $this->printer->renderOperand($adaptation->method); foreach ($adaptation->insteadof as $index2 => $insteadof) { - $adapt[] = " insteadof[$index2]: " . $this->printer->renderOperand($insteadof); + $adapt['adaptation'][$index]['Insteadof']['insteadof'][$index2] = $this->printer->renderOperand($insteadof); } } - $result['vars'] = array_merge($result['vars'], $adapt); } + + $result['vars'] = array_merge($result['vars'], $adapt); + return $result; } - } diff --git a/lib/PHPCfg/Printer/Renderer/Operand/Literal.php b/lib/PHPCfg/Printer/Renderer/Operand/Literal.php index 59e3862..2959851 100644 --- a/lib/PHPCfg/Printer/Renderer/Operand/Literal.php +++ b/lib/PHPCfg/Printer/Renderer/Operand/Literal.php @@ -41,14 +41,15 @@ public function renderOperand(Operand $operand): ?array "type" => "", ]; } + if (!$operand instanceof Operand\Literal) { return null; } return [ "kind" => "LITERAL", - "type" => $operand->type ? "<{$operand->type}>" : "", - "value" => var_export($operand->value, true), + "type" => $this->printer->renderType($operand->type), + "value" => $operand->value, ]; } diff --git a/lib/PHPCfg/Printer/Renderer/Operand/Temporary.php b/lib/PHPCfg/Printer/Renderer/Operand/Temporary.php index d0f43d5..227180b 100644 --- a/lib/PHPCfg/Printer/Renderer/Operand/Temporary.php +++ b/lib/PHPCfg/Printer/Renderer/Operand/Temporary.php @@ -44,11 +44,12 @@ public function renderOperand(Operand $operand): ?array if (!$operand instanceof Operand\Temporary) { return null; } + return [ "kind" => "TEMP", - "type" => $operand->type ? "<{$operand->type}>" : "", - "id" => "#" . $this->getVarId($operand), - "original" => $operand->original ? "<" . $this->printer->renderOperand($operand->original) . ">" : "", + "type" => $this->printer->renderType($operand->type), + "id" => $this->getVarId($operand), + "original" => $operand->original ? $this->printer->renderOperand($operand->original) : null, ]; } diff --git a/lib/PHPCfg/Printer/Renderer/Operand/Variable.php b/lib/PHPCfg/Printer/Renderer/Operand/Variable.php index 073e091..a48543c 100644 --- a/lib/PHPCfg/Printer/Renderer/Operand/Variable.php +++ b/lib/PHPCfg/Printer/Renderer/Operand/Variable.php @@ -40,24 +40,26 @@ public function renderOperand(Operand $operand): ?array } assert($operand->name instanceof Operand\Literal); - $prefix = "$"; + $reference = false; + $scope = ""; if ($operand instanceof Operand\BoundVariable) { if ($operand->byRef) { - $prefix = '&$'; + $reference = true; } + switch ($operand->scope) { case Operand\BoundVariable::SCOPE_GLOBAL: - $prefix = "global $prefix"; + $scope = "global"; break; case Operand\BoundVariable::SCOPE_LOCAL: - $prefix = "local $prefix"; + $scope = "local"; break; case Operand\BoundVariable::SCOPE_OBJECT: - $prefix = "this $prefix"; + $scope = "this"; break; case Operand\BoundVariable::SCOPE_FUNCTION: - $prefix = "static $prefix"; + $scope = "static"; break; default: throw new LogicException('Unknown bound variable scope'); @@ -66,9 +68,10 @@ public function renderOperand(Operand $operand): ?array return [ "kind" => "VARIABLE", - "type" => $operand->type ? "<{$operand->type}>" : "", - "name" => $prefix . $operand->name->value, + "type" => $this->printer->renderType($operand->type), + "name" => $operand->name->value, + "scope" => $scope, + "reference" => $reference, ]; } - } diff --git a/lib/PHPCfg/Printer/Text.php b/lib/PHPCfg/Printer/Text.php index 2e74773..35fc4c9 100755 --- a/lib/PHPCfg/Printer/Text.php +++ b/lib/PHPCfg/Printer/Text.php @@ -11,7 +11,9 @@ namespace PHPCfg\Printer; +use LogicException; use PHPCfg\Func; +use PHPCfg\Operand; use PHPCfg\Script; class Text extends Printer @@ -37,7 +39,7 @@ public function printFunc(Func $func): string $ops = $rendered['blocks'][$block]; $output .= "\nBlock#" . $rendered['blockIds'][$block]; foreach ($block->parents as $prev) { - if ($rendered['blockIds']->contains($prev)) { + if ($rendered['blockIds']->offsetExists($prev)) { $output .= $this->indent("\nParent: Block#" . $rendered['blockIds'][$prev]); } } @@ -46,7 +48,7 @@ public function printFunc(Func $func): string $output .= $this->indent("\ncatchTarget<" . $this->renderType($catch['type']) . ">(" . $this->renderOperand($catch['var']) . "): Block#" . $rendered['blockIds'][$catch['block']], 2); } - if ($rendered['blockIds']->contains($block->catchTarget->finally)) { + if ($rendered['blockIds']->offsetExists($block->catchTarget->finally)) { $output .= $this->indent("\nfinallyTarget: Block#" . $rendered['blockIds'][$block->catchTarget->finally], 2); } } @@ -72,13 +74,13 @@ public function printVars(Func $func): string $output .= "\nVar#{$id}"; $output .= $this->indent("\n" . 'WriteOps:'); foreach ($var->ops as $writeOp) { - if ($rendered['ops']->contains($writeOp)) { + if ($rendered['ops']->offsetExists($writeOp)) { $output .= $this->indent("\n" . $rendered['ops'][$writeOp]['label'], 2); } } $output .= $this->indent("\n" . 'ReadOps:'); foreach ($var->usages as $usage) { - if ($rendered['ops']->contains($usage)) { + if ($rendered['ops']->offsetExists($usage)) { $output .= $this->indent("\n" . $rendered['ops'][$usage]['label'], 2); } } @@ -87,4 +89,71 @@ public function printVars(Func $func): string return $output; } + + public function renderOperand(Operand $var): string + { + foreach ($this->renderers as $renderer) { + $result = $renderer->renderOperand($var); + if ($result !== null) { + $kind = $result['kind']; + $type = $result['type'] ? "<{$result['type']}>" : ""; + + if ($kind == "TEMP") { + $result['id'] = "#" . $result['id']; + if (isset($result['original']) && $result['original']) { + $result['original'] = "<" . $result['original'] . ">"; + } + } elseif ($kind == "VARIABLE") { + $result['name'] = $result['reference'] ? "&$" . $result['name'] : "$" . $result['name']; + + if ($result['scope']) { + $result['name'] = $result['scope'] . " " . $result['name']; + } + + unset($result['scope'], $result['reference']); + } elseif ($kind == "LITERAL") { + $result['value'] = var_export($result['value'], true); + } + + unset($result['kind'], $result['type']); + return strtoupper($kind) . $type . '(' . trim(implode(" ", $result)) . ')'; + } + } + + throw new LogicException("Unknown operand rendering: " . get_class($var)); + } + + public function renderOpLabelValue(array|string|int $value, string $prefix): string + { + $result = ''; + if (is_array($value)) { + foreach ($value as $k => $v) { + $newprefix = is_string($k) ? "{$prefix}['{$k}']" : "{$prefix}[{$k}]"; + $result .= $this->renderOpLabelValue($v, $newprefix); + } + } else { + $result .= $this->indent("{$prefix}: {$value}"); + } + + return $result; + } + + public function renderOpLabel(array $desc): string + { + $result = "{$desc['kind']}"; + unset($desc['kind'], $desc['childblocks']); + + foreach ($desc as $name => $val) { + if (is_array($val)) { + foreach ($val as $k => $v) { + $prefix = "\n{$k}"; + $result .= $this->renderOpLabelValue($v, $prefix); + } + } else { + $result .= $this->indent("\n{$name}: {$val}"); + } + } + + return $result; + } } diff --git a/lib/PHPCfg/Traverser.php b/lib/PHPCfg/Traverser.php index a90e93d..f3f42d1 100755 --- a/lib/PHPCfg/Traverser.php +++ b/lib/PHPCfg/Traverser.php @@ -57,12 +57,12 @@ private function traverseFunc(Func $func) private function traverseBlock(Block $block, ?Block $prior = null) { - if ($this->seen->contains($block)) { + if ($this->seen->offsetExists($block)) { $this->event('skipBlock', [$block, $prior]); // Always return null on a skip event return; } - $this->seen->attach($block); + $this->seen->offsetSet($block); $this->event('enterBlock', [$block, $prior]); $children = $block->children; for ($i = 0; $i < count($children); ++$i) { diff --git a/lib/PHPCfg/Visitor/DebugVisitor.php b/lib/PHPCfg/Visitor/DebugVisitor.php index 3131bf0..c29be60 100644 --- a/lib/PHPCfg/Visitor/DebugVisitor.php +++ b/lib/PHPCfg/Visitor/DebugVisitor.php @@ -71,7 +71,7 @@ public function leaveFunc(Func $func) protected function getBlockId(Block $block) { - if (! $this->blocks->contains($block)) { + if (! $this->blocks->offsetExists($block)) { $this->blocks[$block] = count($this->blocks) + 1; } diff --git a/lib/PHPCfg/Visitor/Simplifier.php b/lib/PHPCfg/Visitor/Simplifier.php index 406fb13..e4c34f0 100644 --- a/lib/PHPCfg/Visitor/Simplifier.php +++ b/lib/PHPCfg/Visitor/Simplifier.php @@ -43,10 +43,10 @@ public function leaveFunc(Func $func): void public function enterOp(Op $op, Block $block): void { - if ($this->recursionProtection->contains($op)) { + if ($this->recursionProtection->offsetExists($op)) { return; } - $this->recursionProtection->attach($op); + $this->recursionProtection->offsetSet($op); foreach ($op->getSubBlocks() as $name => $targets) { /** @var Block $block */ if (! is_array($targets)) { @@ -58,7 +58,7 @@ public function enterOp(Op $op, Block $block): void if (! $target || ! isset($target->children[0]) || ! $target->children[0] instanceof Op\Stmt\Jump) { continue; } - if ($this->removed->contains($target)) { + if ($this->removed->offsetExists($target)) { // short circuit $results[$key] = $target->children[0]->target; if (! in_array($block, $target->children[0]->target->parents, true)) { @@ -111,7 +111,7 @@ public function enterOp(Op $op, Block $block): void } $target->phi = []; } - $this->removed->attach($target); + $this->removed->offsetSet($target); $target->dead = true; // Remove the target from the list of parents @@ -132,18 +132,18 @@ public function enterOp(Op $op, Block $block): void $op->{$name} = $results; } } - $this->recursionProtection->detach($op); + $this->recursionProtection->offsetUnset($op); } private function removeTrivialPhi(Block $block): void { $toReplace = new SplObjectStorage(); $replaced = new SplObjectStorage(); - $toReplace->attach($block); + $toReplace->offsetSet($block); while ($toReplace->count() > 0) { foreach ($toReplace as $block) { - $toReplace->detach($block); - $replaced->attach($block); + $toReplace->offsetUnset($block); + $replaced->offsetSet($block); foreach ($block->phi as $key => $phi) { if ($this->tryRemoveTrivialPhi($phi, $block)) { unset($block->phi[$key]); @@ -158,8 +158,8 @@ private function removeTrivialPhi(Block $block): void $subBlocks = [$subBlocks]; } foreach ($subBlocks as $subBlock) { - if (! $replaced->contains($subBlock)) { - $toReplace->attach($subBlock); + if (! $replaced->offsetExists($subBlock)) { + $toReplace->offsetSet($subBlock); } } } @@ -169,7 +169,7 @@ private function removeTrivialPhi(Block $block): void while ($this->trivialPhiCandidates->count() > 0) { foreach ($this->trivialPhiCandidates as $phi) { $block = $this->trivialPhiCandidates[$phi]; - $this->trivialPhiCandidates->detach($phi); + $this->trivialPhiCandidates->offsetUnset($phi); if ($this->tryRemoveTrivialPhi($phi, $block)) { $key = array_search($phi, $block->phi, true); if ($key !== false) { @@ -201,11 +201,11 @@ private function replaceVariables(Operand $from, Operand $to, Block $block): voi { $toReplace = new SplObjectStorage(); $replaced = new SplObjectStorage(); - $toReplace->attach($block); + $toReplace->offsetSet($block); while ($toReplace->count() > 0) { foreach ($toReplace as $block) { - $toReplace->detach($block); - $replaced->attach($block); + $toReplace->offsetUnset($block); + $replaced->offsetSet($block); foreach ($block->phi as $phi) { if ($phi->hasOperand($from)) { // Since we're removing from the phi, it may become trivial @@ -225,7 +225,7 @@ private function replaceVariables(Operand $from, Operand $to, Block $block): voi } foreach ($subBlocks as $subBlock) { if (! $replaced->contains($subBlock)) { - $toReplace->attach($subBlock); + $toReplace->offsetSet($subBlock); } } } diff --git a/lib/PHPCfg/Visitor/VariableFinder.php b/lib/PHPCfg/Visitor/VariableFinder.php index d3f0688..20b0a8e 100644 --- a/lib/PHPCfg/Visitor/VariableFinder.php +++ b/lib/PHPCfg/Visitor/VariableFinder.php @@ -47,7 +47,7 @@ public function enterOp(Op $op, Block $block): void if (null === $v) { continue; } - $this->variables->attach($v); + $this->variables->offsetSet($v); } } } diff --git a/test/CodeTest.php b/test/CodeTest.php index aabf85d..0ced704 100755 --- a/test/CodeTest.php +++ b/test/CodeTest.php @@ -24,7 +24,7 @@ class CodeTest extends TestCase { #[DataProvider('provideTestParseAndDump')] - public function testParseAndDump($code, $expectedDump) + public function testParseAndDump($code, $expectedDump, $file) { $astTraverser = new PhpParser\NodeTraverser(); $astTraverser->addVisitor(new PhpParser\NodeVisitor\NameResolver()); @@ -41,9 +41,11 @@ public function testParseAndDump($code, $expectedDump) $result = $e->getMessage(); } + // file_put_contents($file, $code . "\n-----" . $result . "\n"); + $this->assertEquals( - $this->canonicalize($expectedDump), - $this->canonicalize($result), + CodeTest::canonicalize($expectedDump), + CodeTest::canonicalize($result), ); } @@ -61,11 +63,11 @@ public static function provideTestParseAndDump() } $contents = file_get_contents($file->getPathname()); - yield $file->getBasename() => explode('-----', $contents); + yield $file->getBasename() => array_merge(explode('-----', $contents), [$file->getPathname()]); } } - private function canonicalize($str) + public static function canonicalize($str) { // trim from both sides $str = trim($str); diff --git a/test/code/and.test b/test/code/and.test index 9f8877d..2b18ab2 100755 --- a/test/code/and.test +++ b/test/code/and.test @@ -1,6 +1,7 @@ ) expr: TEMP(#4) result: TEMP(#6) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/anonymous_class.test b/test/code/anonymous_class.test index 465fc6c..d938c95 100644 --- a/test/code/anonymous_class.test +++ b/test/code/anonymous_class.test @@ -6,6 +6,7 @@ $var = new class { }; $instance = new #[Attr('foo')] class {}; + ----- Block#1 Stmt_Class @@ -19,11 +20,9 @@ Block#1 expr: TEMP(#1) result: TEMP(#3) Stmt_Class + attrGroup[0][0]['name']: LITERAL('Attr') + attrGroup[0][0]['args'][0]: LITERAL('foo') name: {anonymousClass}#2 - attrGroup[0]: - attr[0]: - name: LITERAL('Attr') - args[0]: LITERAL('foo') stmts: Block#3 Expr_New class: LITERAL('{anonymousClass}#2') @@ -46,3 +45,4 @@ Block#1 Terminal_Echo expr: LITERAL('Hello World') Terminal_Return + diff --git a/test/code/arrayList.test b/test/code/arrayList.test index 33308d5..a7d3678 100755 --- a/test/code/arrayList.test +++ b/test/code/arrayList.test @@ -1,6 +1,7 @@ ) expr: TEMP(#9) result: TEMP(#11) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/arrow_fn.test b/test/code/arrow_fn.test index a9e2476..7ab0f28 100644 --- a/test/code/arrow_fn.test +++ b/test/code/arrow_fn.test @@ -4,6 +4,7 @@ $b = 1; $fn = fn($a) => $b++ * $a; $fn(3); var_dump($b); + ----- Block#1 Expr_Assign @@ -46,4 +47,5 @@ Block#1 right: TEMP(#1 ) result: TEMP(#6) Terminal_Return - expr: TEMP(#6) \ No newline at end of file + expr: TEMP(#6) + diff --git a/test/code/assign_coalesce.test b/test/code/assign_coalesce.test index 24d29d2..b00651e 100644 --- a/test/code/assign_coalesce.test +++ b/test/code/assign_coalesce.test @@ -1,6 +1,7 @@ ) expr: TEMP(#3) result: TEMP(#5) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/block.test b/test/code/block.test index e37c6f0..9d689bb 100644 --- a/test/code/block.test +++ b/test/code/block.test @@ -3,11 +3,12 @@ echo "a"; { $aaaa = 1; -} +} + +{ -{ - } + ----- Block#1 Terminal_Echo @@ -17,3 +18,4 @@ Block#1 expr: LITERAL(1) result: TEMP(#2) Terminal_Return + diff --git a/test/code/cast.test b/test/code/cast.test index b902665..0278f05 100644 --- a/test/code/cast.test +++ b/test/code/cast.test @@ -12,3 +12,4 @@ Block#1 expr: TEMP(#1) result: TEMP(#3) Terminal_Return + diff --git a/test/code/class.test b/test/code/class.test index c4a4607..80ac0df 100755 --- a/test/code/class.test +++ b/test/code/class.test @@ -26,6 +26,7 @@ class NameOfClass extends \X implements Iface { } } $obj = new NameOfClass(); + ----- Block#1 Stmt_Interface @@ -101,3 +102,4 @@ Block#1 Function 'NS\NameOfClass::method6': mixed Block#1 Terminal_Return + diff --git a/test/code/classMethod_empty.test b/test/code/classMethod_empty.test index 27af6a9..de8d59a 100755 --- a/test/code/classMethod_empty.test +++ b/test/code/classMethod_empty.test @@ -2,6 +2,7 @@ class NameOfClass { function doSomething() {} } + ----- Block#1 Stmt_Class @@ -16,4 +17,5 @@ Block#2 Function 'NameOfClass::doSomething': mixed Block#1 - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/class_attributes.test b/test/code/class_attributes.test index 3d7225d..6302640 100644 --- a/test/code/class_attributes.test +++ b/test/code/class_attributes.test @@ -28,38 +28,28 @@ class NameOfClass5 { #[FooAttribute(null)] class NameOfClass6 { } + ----- Block#1 Stmt_Class + attrGroup[0][0]['name']: LITERAL('NameOfAttribute') name: NameOfClass1 - attrGroup[0]: - attr[0]: - name: LITERAL('NameOfAttribute') stmts: Block#2 Stmt_Class + attrGroup[0][0]['name']: LITERAL('ExampleAttribute') + attrGroup[0][0]['args'][0]: LITERAL('foo') + attrGroup[0][0]['args'][1]: LITERAL('bar') name: NameOfClass2 - attrGroup[0]: - attr[0]: - name: LITERAL('ExampleAttribute') - args[0]: LITERAL('foo') - args[1]: LITERAL('bar') stmts: Block#3 Stmt_Class + attrGroup[0][0]['name']: LITERAL('Attr') + attrGroup[1][0]['name']: LITERAL('FooAttr') name: NameOfClass3 - attrGroup[0]: - attr[0]: - name: LITERAL('Attr') - attrGroup[1]: - attr[0]: - name: LITERAL('FooAttr') stmts: Block#4 Stmt_Class + attrGroup[0][0]['name']: LITERAL('Attr') + attrGroup[0][1]['name']: LITERAL('FooAttr') name: NameOfClass4 - attrGroup[0]: - attr[0]: - name: LITERAL('Attr') - attr[1]: - name: LITERAL('FooAttr') stmts: Block#5 Expr_ClassConstFetch class: LITERAL('Attribute') @@ -74,36 +64,25 @@ Block#1 right: TEMP(#2) result: TEMP(#3) Stmt_Class + attrGroup[0][0]['name']: LITERAL('Attribute') + attrGroup[0][0]['args'][0]: TEMP(#3) name: NameOfClass5 - attrGroup[0]: - attr[0]: - name: LITERAL('Attribute') - args[0]: TEMP(#3) stmts: Block#6 - Expr_ConstFetch - name: LITERAL('null') - result: TEMP(#4) Stmt_Class + attrGroup[0][0]['name']: LITERAL('ConstAttr') + attrGroup[1][0]['name']: LITERAL('FooAttribute') + attrGroup[1][0]['args'][0]: NULL() name: NameOfClass6 - attrGroup[0]: - attr[0]: - name: LITERAL('ConstAttr') - attrGroup[1]: - attr[0]: - name: LITERAL('FooAttribute') - args[0]: TEMP(#4) stmts: Block#7 Terminal_Return Block#2 Stmt_ClassMethod + attrGroup[0][0]['name']: LITERAL('ExampleAttributeMethod') + attrGroup[0][0]['args'][0]: LITERAL('foo') + attrGroup[0][0]['args'][1]: LITERAL('bar') name: method1 flags: private - attrGroup[0]: - attr[0]: - name: LITERAL('ExampleAttributeMethod') - args[0]: LITERAL('foo') - args[1]: LITERAL('bar') Block#3 @@ -118,11 +97,10 @@ Block#7 Function 'NameOfClass1::method1': mixed Block#1 Expr_Param + attrGroup[0][0]['name']: LITERAL('FooParamAttrib') + attrGroup[0][0]['args'][0]: LITERAL('Foo1') declaredType: mixed name: LITERAL('foo') result: TEMP(#1 ) - attrGroup[0]: - attr[0]: - name: LITERAL('FooParamAttrib') - args[0]: LITERAL('Foo1') - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/class_this.test b/test/code/class_this.test index 4b33043..b064752 100755 --- a/test/code/class_this.test +++ b/test/code/class_this.test @@ -5,6 +5,7 @@ class NameOfClass { echo $this->hello(); } } + ----- Block#1 Stmt_Class @@ -25,4 +26,5 @@ Block#1 result: TEMP(#1) Terminal_Echo expr: TEMP(#1) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/class_typed_property.test b/test/code/class_typed_property.test index 02e020c..2f17946 100755 --- a/test/code/class_typed_property.test +++ b/test/code/class_typed_property.test @@ -1,25 +1,27 @@ -) - expr: TEMP(#1) - result: TEMP(#3) - Terminal_Return - -Block#2 - Stmt_Property - declaredType: ?NS\NameOfClass - flags: public - name: LITERAL('self') \ No newline at end of file +) + expr: TEMP(#1) + result: TEMP(#3) + Terminal_Return + +Block#2 + Stmt_Property + declaredType: ?NS\NameOfClass + flags: public + name: LITERAL('self') + diff --git a/test/code/closure.test b/test/code/closure.test index 79ed5b4..08cf414 100755 --- a/test/code/closure.test +++ b/test/code/closure.test @@ -7,6 +7,7 @@ $fn = function($a) use($b, &$c) { }; $fn(3); var_dump($c); + ----- Block#1 Expr_Assign @@ -54,4 +55,5 @@ Block#1 var: TEMP(#6 ) expr: TEMP(#5) result: TEMP(#7) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/closure_empty.test b/test/code/closure_empty.test index fbb1b95..a5f7b3d 100755 --- a/test/code/closure_empty.test +++ b/test/code/closure_empty.test @@ -1,5 +1,6 @@ ) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/constDecl.test b/test/code/constDecl.test index 599ff10..8c53ec2 100755 --- a/test/code/constDecl.test +++ b/test/code/constDecl.test @@ -4,6 +4,7 @@ class C { const D = 3, E = 4 + 4; } var_dump(A, C::D); + ----- Block#1 Terminal_Const @@ -55,4 +56,5 @@ Block#6 Expr_BinaryOp_Plus left: LITERAL(4) right: LITERAL(4) - result: TEMP(#5) \ No newline at end of file + result: TEMP(#5) + diff --git a/test/code/constFetch.test b/test/code/constFetch.test index 6714550..d3690d4 100755 --- a/test/code/constFetch.test +++ b/test/code/constFetch.test @@ -6,6 +6,7 @@ namespace Foo; \var_dump(true); \var_dump(false); \var_dump(null); + ----- Block#1 Expr_ConstFetch @@ -26,6 +27,7 @@ Block#1 result: TEMP(#4) Expr_FuncCall name: LITERAL('var_dump') - args[0]: LITERAL(NULL) + args[0]: NULL() result: TEMP(#5) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/duplicate_label.test b/test/code/duplicate_label.test index c9e3f51..9db654d 100644 --- a/test/code/duplicate_label.test +++ b/test/code/duplicate_label.test @@ -1,5 +1,5 @@ ) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/exit.test b/test/code/exit.test index 3e25a90..c2ea4ee 100755 --- a/test/code/exit.test +++ b/test/code/exit.test @@ -2,6 +2,7 @@ $a = 1; exit; echo $a; + ----- Block#1 Expr_Assign @@ -9,3 +10,4 @@ Block#1 expr: LITERAL(1) result: TEMP(#2) Terminal_Exit + diff --git a/test/code/exit_message.test b/test/code/exit_message.test index 2198894..70e8f9b 100755 --- a/test/code/exit_message.test +++ b/test/code/exit_message.test @@ -2,6 +2,7 @@ $a = 1; exit('Quitting with message: ' . $a); echo $a; + ----- Block#1 Expr_Assign @@ -14,3 +15,4 @@ Block#1 result: TEMP(#3) Terminal_Exit expr: TEMP(#3) + diff --git a/test/code/exprFuncCall.test b/test/code/exprFuncCall.test index 4ccd4aa..9586be5 100755 --- a/test/code/exprFuncCall.test +++ b/test/code/exprFuncCall.test @@ -2,6 +2,7 @@ $a = "print_r"; $a("some string"); + ----- Block#1 Expr_Assign @@ -12,4 +13,5 @@ Block#1 name: TEMP(#1 ) args[0]: LITERAL('some string') result: TEMP(#3) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/foreach.test b/test/code/foreach.test index d5949f4..12a8763 100755 --- a/test/code/foreach.test +++ b/test/code/foreach.test @@ -3,6 +3,7 @@ $a = []; foreach ($a as $b) { echo $b; } + ----- Block#1 Expr_Array @@ -43,4 +44,5 @@ Block#3 Block#4 Parent: Block#2 - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/forever.test b/test/code/forever.test index 5164392..be4bbaa 100755 --- a/test/code/forever.test +++ b/test/code/forever.test @@ -3,6 +3,7 @@ for (;;) { echo 1; } echo 2; + ----- Block#1 Stmt_Jump @@ -28,3 +29,4 @@ Block#4 Terminal_Echo expr: LITERAL(2) Terminal_Return + diff --git a/test/code/function.test b/test/code/function.test index bd4c3ec..6725d68 100755 --- a/test/code/function.test +++ b/test/code/function.test @@ -2,6 +2,7 @@ function foo($a) { return $a; } + ----- Block#1 Stmt_Function @@ -15,4 +16,5 @@ Block#1 name: LITERAL('a') result: TEMP(#1 ) Terminal_Return - expr: TEMP(#1 ) \ No newline at end of file + expr: TEMP(#1 ) + diff --git a/test/code/function_attributes.test b/test/code/function_attributes.test index 27e3919..672be86 100644 --- a/test/code/function_attributes.test +++ b/test/code/function_attributes.test @@ -8,27 +8,19 @@ function foo2(){} function foo5(){} function foo_func(#[FooParamAttrib('Foo1')] $foo) {} + ----- Block#1 Stmt_Function + attrGroup[0][0]['name']: LITERAL('ExampleAttribute') + attrGroup[0][0]['args'][0]: LITERAL('foo') + attrGroup[0][0]['args'][1]: LITERAL('bar') name: foo2 - attrGroup[0]: - attr[0]: - name: LITERAL('ExampleAttribute') - args[0]: LITERAL('foo') - args[1]: LITERAL('bar') - Expr_ConstFetch - name: LITERAL('null') - result: TEMP(#1) Stmt_Function + attrGroup[0][0]['name']: LITERAL('ConstAttr') + attrGroup[1][0]['name']: LITERAL('FooAttribute') + attrGroup[1][0]['args'][0]: NULL() name: foo5 - attrGroup[0]: - attr[0]: - name: LITERAL('ConstAttr') - attrGroup[1]: - attr[0]: - name: LITERAL('FooAttribute') - args[0]: TEMP(#1) Stmt_Function name: foo_func Terminal_Return @@ -44,11 +36,10 @@ Block#1 Function 'foo_func': mixed Block#1 Expr_Param + attrGroup[0][0]['name']: LITERAL('FooParamAttrib') + attrGroup[0][0]['args'][0]: LITERAL('Foo1') declaredType: mixed name: LITERAL('foo') result: TEMP(#1 ) - attrGroup[0]: - attr[0]: - name: LITERAL('FooParamAttrib') - args[0]: LITERAL('Foo1') - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/function_empty.test b/test/code/function_empty.test index 579ed54..447474d 100755 --- a/test/code/function_empty.test +++ b/test/code/function_empty.test @@ -1,5 +1,6 @@ ) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/function_namespace.test b/test/code/function_namespace.test index 8098e77..ca0b479 100755 --- a/test/code/function_namespace.test +++ b/test/code/function_namespace.test @@ -3,6 +3,7 @@ namespace NS; function foo($a) { return $a; } + ----- Block#1 Stmt_Function @@ -16,4 +17,5 @@ Block#1 name: LITERAL('a') result: TEMP(#1 ) Terminal_Return - expr: TEMP(#1 ) \ No newline at end of file + expr: TEMP(#1 ) + diff --git a/test/code/function_return_type.test b/test/code/function_return_type.test index 7698b91..bc3d7dc 100755 --- a/test/code/function_return_type.test +++ b/test/code/function_return_type.test @@ -1,18 +1,20 @@ -) - Terminal_Return - expr: TEMP(#1 ) \ No newline at end of file +) + Terminal_Return + expr: TEMP(#1 ) + diff --git a/test/code/goto_forever.test b/test/code/goto_forever.test index adc63a9..28dfd06 100644 --- a/test/code/goto_forever.test +++ b/test/code/goto_forever.test @@ -1,6 +1,7 @@ $a, $key => $b) = $array; + ----- Block#1 Expr_Assign @@ -24,4 +25,5 @@ Block#1 var: TEMP(#8 ) expr: TEMP(#7) result: TEMP(#9) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/literal.test b/test/code/literal.test index 1f92ac6..49065b9 100644 --- a/test/code/literal.test +++ b/test/code/literal.test @@ -4,6 +4,7 @@ $a = "aaaa"; $b = "aaaa')eeee"; $c = "aaaa')"; $d = "aaaa'')"; + ----- Block#1 Expr_Assign @@ -22,4 +23,5 @@ Block#1 var: TEMP(#7 ) expr: LITERAL('aaaa\'\')') result: TEMP(#8) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/match.test b/test/code/match.test index 64d83d5..52f520d 100644 --- a/test/code/match.test +++ b/test/code/match.test @@ -4,6 +4,7 @@ echo match(10) { 5 => 'bar', 10 => 'baz' . 'buz', }; + ----- Block#1 Stmt_MatchTable @@ -31,7 +32,7 @@ Block#3 expr: LITERAL('bar') result: TEMP(#4) Stmt_Jump - target: Block#5 + target: Block#5 Block#4 Parent: Block#1 @@ -46,9 +47,12 @@ Block#5 Parent: Block#2 Parent: Block#3 Parent: Block#4 - TEMP(#6) = Phi(TEMP(#1), TEMP(#3), TEMP(#5)) + Phi + vars[0]: TEMP(#1) + vars[1]: TEMP(#3) + vars[2]: TEMP(#5) + result: TEMP(#6) Terminal_Echo expr: TEMP(#6) Terminal_Return - diff --git a/test/code/match2.test b/test/code/match2.test index 4cf8aa0..9cdf4af 100644 --- a/test/code/match2.test +++ b/test/code/match2.test @@ -4,6 +4,7 @@ echo match(10) { 5 => 'bar', 5 + 5 => 'baz' . 'buz', }; + ----- Block#1 Expr_BinaryOp_Identical @@ -39,15 +40,19 @@ Block#4 Parent: Block#2 Parent: Block#5 Parent: Block#7 - TEMP(#5) = Phi(TEMP(#2), TEMP(#6), TEMP(#7)) + Phi + vars[0]: TEMP(#2) + vars[1]: TEMP(#5) + vars[2]: TEMP(#6) + result: TEMP(#7) Terminal_Echo - expr: TEMP(#5) + expr: TEMP(#7) Terminal_Return Block#5 Parent: Block#3 Expr_Assign - var: TEMP(#6) + var: TEMP(#5) expr: LITERAL('bar') result: TEMP(#8) Stmt_Jump @@ -73,7 +78,7 @@ Block#7 Expr_BinaryOp_Concat left: LITERAL('baz') right: LITERAL('buz') - result: TEMP(#7) + result: TEMP(#6) Stmt_Jump target: Block#4 @@ -81,3 +86,4 @@ Block#8 Parent: Block#6 Terminal_MatchError cond: LITERAL(10) + diff --git a/test/code/namespaced_conditionals.test b/test/code/namespaced_conditionals.test index 21d49c0..81a31bf 100755 --- a/test/code/namespaced_conditionals.test +++ b/test/code/namespaced_conditionals.test @@ -11,6 +11,7 @@ namespace Bar { echo 'bar'; } } + ----- Block#1 Stmt_JumpIf @@ -43,4 +44,5 @@ Block#4 Block#5 Parent: Block#4 Parent: Block#3 - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/nested_phi.test b/test/code/nested_phi.test index d6e5edf..f54e255 100755 --- a/test/code/nested_phi.test +++ b/test/code/nested_phi.test @@ -31,7 +31,10 @@ Block#2 Parent: Block#1 Parent: Block#3 Parent: Block#5 - TEMP(#4 ) = Phi(TEMP(#1 ), TEMP(#5 )) + Phi + vars[0]: TEMP(#1 ) + vars[1]: TEMP(#4 ) + result: TEMP(#5 ) Iterator_Valid var: TEMP(#3) result: TEMP(#6) @@ -50,7 +53,7 @@ Block#3 expr: TEMP(#7) result: TEMP(#9) Expr_BinaryOp_Greater - left: TEMP(#4 ) + left: TEMP(#5 ) right: LITERAL(0) result: TEMP(#10) Stmt_JumpIf @@ -61,18 +64,19 @@ Block#3 Block#4 Parent: Block#2 Terminal_Echo - expr: TEMP(#4 ) + expr: TEMP(#5 ) Terminal_Return Block#5 Parent: Block#3 Expr_BinaryOp_Plus - left: TEMP(#4 ) + left: TEMP(#5 ) right: TEMP(#8 ) result: TEMP(#11) Expr_Assign - var: TEMP(#5 ) + var: TEMP(#4 ) expr: TEMP(#11) result: TEMP(#12) Stmt_Jump - target: Block#2 \ No newline at end of file + target: Block#2 + diff --git a/test/code/nop.test b/test/code/nop.test index 522e670..e9b66e0 100755 --- a/test/code/nop.test +++ b/test/code/nop.test @@ -3,6 +3,7 @@ $a = 1; /* foo */ ; echo $a; + ----- Block#1 Expr_Assign @@ -11,4 +12,5 @@ Block#1 result: TEMP(#2) Terminal_Echo expr: TEMP(#1 ) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/nsFuncCall.test b/test/code/nsFuncCall.test index 5006170..cc6a7a8 100755 --- a/test/code/nsFuncCall.test +++ b/test/code/nsFuncCall.test @@ -2,10 +2,12 @@ namespace Foo; call(); + ----- Block#1 Expr_NsFuncCall nsName: LITERAL('Foo\\call') name: LITERAL('call') result: TEMP(#1) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/or.test b/test/code/or.test index 8d4ec80..15f9865 100755 --- a/test/code/or.test +++ b/test/code/or.test @@ -1,6 +1,7 @@ ) - expr: TEMP(#2) + expr: TEMP(#3) result: TEMP(#5) Terminal_Return @@ -28,6 +32,7 @@ Block#3 result: TEMP(#6) Expr_Cast_Bool expr: TEMP(#6) - result: TEMP(#3) + result: TEMP(#2) Stmt_Jump - target: Block#2 \ No newline at end of file + target: Block#2 + diff --git a/test/code/property.test b/test/code/property.test index 54b2559..fba3446 100755 --- a/test/code/property.test +++ b/test/code/property.test @@ -7,7 +7,7 @@ class A { private readonly static $prop5; static $prop6; protected $prop7; - + #[ConstAttr] #[FooAttribute(null)] private string $foo5; @@ -15,6 +15,7 @@ class A { #[NameOfAttribute] private const FOO = 'foo'; } + ----- Block#1 Stmt_Class @@ -55,20 +56,13 @@ Block#2 declaredType: mixed flags: protected name: LITERAL('prop7') - Expr_ConstFetch - name: LITERAL('null') - result: TEMP(#2) Stmt_Property + attrGroup[0][0]['name']: LITERAL('ConstAttr') + attrGroup[1][0]['name']: LITERAL('FooAttribute') + attrGroup[1][0]['args'][0]: NULL() declaredType: string flags: private name: LITERAL('foo5') - attrGroup[0]: - attr[0]: - name: LITERAL('ConstAttr') - attrGroup[1]: - attr[0]: - name: LITERAL('FooAttribute') - args[0]: TEMP(#2) Terminal_Const name: LITERAL('FOO') value: LITERAL('foo') @@ -83,3 +77,4 @@ Block#4 result: TEMP(#1) Block#5 + diff --git a/test/code/shellExec.test b/test/code/shellExec.test index 80cb58e..96fbdf2 100755 --- a/test/code/shellExec.test +++ b/test/code/shellExec.test @@ -1,6 +1,7 @@ ) - defaultVar: TEMP(#2) + defaultVar: LITERAL(false) defaultBlock: Block#2 Terminal_Echo expr: TEMP(#1 ) @@ -13,6 +14,4 @@ Block#1 Block#2 Parent: Block#1 - Expr_ConstFetch - name: LITERAL('FALSE') - result: TEMP(#2) + diff --git a/test/code/switch.test b/test/code/switch.test index d90c58a..bd88995 100755 --- a/test/code/switch.test +++ b/test/code/switch.test @@ -11,6 +11,7 @@ switch ($i) { default: echo "i < 0 || i > 3"; } + ----- Block#1 Stmt_Switch @@ -50,4 +51,5 @@ Block#5 Parent: Block#2 Parent: Block#3 Parent: Block#4 - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/switch2.test b/test/code/switch2.test index 5aa06e5..45f6ef9 100755 --- a/test/code/switch2.test +++ b/test/code/switch2.test @@ -11,6 +11,7 @@ switch ($i) { echo "C"; } echo "D"; + ----- Block#1 Expr_BinaryOp_Equal @@ -84,4 +85,5 @@ Block#8 Terminal_Echo expr: LITERAL('C') Stmt_Jump - target: Block#6 \ No newline at end of file + target: Block#6 + diff --git a/test/code/ternary.test b/test/code/ternary.test index debaa27..aa8b177 100755 --- a/test/code/ternary.test +++ b/test/code/ternary.test @@ -1,6 +1,7 @@ ) expr: TEMP(#8) result: TEMP(#10) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/ternary2.test b/test/code/ternary2.test index 5ca3bb7..55e2849 100755 --- a/test/code/ternary2.test +++ b/test/code/ternary2.test @@ -1,6 +1,7 @@ ) - expr: TEMP(#4) + expr: TEMP(#5) result: TEMP(#7) Terminal_Return @@ -55,10 +59,14 @@ Block#6 Block#7 Parent: Block#5 Parent: Block#6 - TEMP(#13) = Phi(TEMP(#8), TEMP(#10)) + Phi + vars[0]: TEMP(#8) + vars[1]: TEMP(#10) + result: TEMP(#13) Expr_Assign - var: TEMP(#5) + var: TEMP(#4) expr: TEMP(#13) result: TEMP(#14) Stmt_Jump - target: Block#4 \ No newline at end of file + target: Block#4 + diff --git a/test/code/throw.test b/test/code/throw.test index fa695cd..e449694 100644 --- a/test/code/throw.test +++ b/test/code/throw.test @@ -2,6 +2,7 @@ $x || throw new Exception("foo"); throw new \InvalidArgumentException("foo"); + ----- Block#1 Stmt_JumpIf @@ -11,7 +12,10 @@ Block#1 Block#2 Parent: Block#1 - TEMP(#2) = Phi(LITERAL(true), TEMP(#3)) + Phi + vars[0]: LITERAL(true) + vars[1]: TEMP(#2) + result: TEMP(#3) Expr_New class: LITERAL('InvalidArgumentException') args[0]: LITERAL('foo') @@ -27,3 +31,4 @@ Block#3 result: TEMP(#5) Terminal_Throw expr: TEMP(#5) + diff --git a/test/code/traitUse.test b/test/code/traitUse.test index d9e3317..b9c1a1e 100644 --- a/test/code/traitUse.test +++ b/test/code/traitUse.test @@ -31,6 +31,7 @@ class Aliased_Talker { B::bigTalk as private talk; } } + ----- Block#1 Stmt_Trait @@ -67,32 +68,27 @@ Block#4 Stmt_TraitUse use[0]: LITERAL('\\A') use[1]: LITERAL('\\B') - adaptation[0]: Insteadof - trait: LITERAL('\\B') - method: LITERAL('smallTalk') - insteadof[0]: LITERAL('\\A') - adaptation[1]: Insteadof - trait: LITERAL('\\A') - method: LITERAL('bigTalk') - insteadof[0]: LITERAL('\\B') + adaptation[0]['Insteadof']['trait']: LITERAL('\\B') + adaptation[0]['Insteadof']['method']: LITERAL('smallTalk') + adaptation[0]['Insteadof']['insteadof'][0]: LITERAL('\\A') + adaptation[1]['Insteadof']['trait']: LITERAL('\\A') + adaptation[1]['Insteadof']['method']: LITERAL('bigTalk') + adaptation[1]['Insteadof']['insteadof'][0]: LITERAL('\\B') Block#5 Stmt_TraitUse use[0]: LITERAL('\\A') use[1]: LITERAL('\\B') - adaptation[0]: Insteadof - trait: LITERAL('\\B') - method: LITERAL('smallTalk') - insteadof[0]: LITERAL('\\A') - adaptation[1]: Insteadof - trait: LITERAL('\\A') - method: LITERAL('bigTalk') - insteadof[0]: LITERAL('\\B') - adaptation[2]: Alias - trait: LITERAL('\\B') - method: LITERAL('bigTalk') - newName: LITERAL('talk') - newModifier: private + adaptation[0]['Insteadof']['trait']: LITERAL('\\B') + adaptation[0]['Insteadof']['method']: LITERAL('smallTalk') + adaptation[0]['Insteadof']['insteadof'][0]: LITERAL('\\A') + adaptation[1]['Insteadof']['trait']: LITERAL('\\A') + adaptation[1]['Insteadof']['method']: LITERAL('bigTalk') + adaptation[1]['Insteadof']['insteadof'][0]: LITERAL('\\B') + adaptation[2]['alias']['trait']: LITERAL('\\B') + adaptation[2]['alias']['method']: LITERAL('bigTalk') + adaptation[2]['alias']['newName']: LITERAL('talk') + adaptation[2]['alias']['newModifier']: private Function 'A::smallTalk': mixed Block#1 @@ -116,4 +112,5 @@ Function 'B::bigTalk': mixed Block#1 Terminal_Echo expr: LITERAL('B') - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/traitUse2.test b/test/code/traitUse2.test index 05de201..c2db9ac 100644 --- a/test/code/traitUse2.test +++ b/test/code/traitUse2.test @@ -12,6 +12,7 @@ class MyClass1 { class MyClass2 { use HelloWorld { sayHello as private myPrivateHello; } } + ----- Block#1 Stmt_Trait @@ -33,20 +34,19 @@ Block#2 Block#3 Stmt_TraitUse use[0]: LITERAL('\\HelloWorld') - adaptation[0]: Alias - method: LITERAL('sayHello') - newModifier: protected + adaptation[0]['alias']['method']: LITERAL('sayHello') + adaptation[0]['alias']['newModifier']: protected Block#4 Stmt_TraitUse use[0]: LITERAL('\\HelloWorld') - adaptation[0]: Alias - method: LITERAL('sayHello') - newName: LITERAL('myPrivateHello') - newModifier: private + adaptation[0]['alias']['method']: LITERAL('sayHello') + adaptation[0]['alias']['newName']: LITERAL('myPrivateHello') + adaptation[0]['alias']['newModifier']: private Function 'HelloWorld::sayHello': mixed Block#1 Terminal_Echo expr: LITERAL('Hello World!') - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/try.test b/test/code/try.test index 0c6fd0d..299b830 100644 --- a/test/code/try.test +++ b/test/code/try.test @@ -7,6 +7,7 @@ try { } catch (MyException2) { echo "MyException2"; } + ----- Block#1 Stmt_Try @@ -53,4 +54,5 @@ Block#5 Parent: Block#1 Parent: Block#3 Parent: Block#4 - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/try_bodyblocks.test b/test/code/try_bodyblocks.test index dd1449b..9fe8cea 100644 --- a/test/code/try_bodyblocks.test +++ b/test/code/try_bodyblocks.test @@ -13,6 +13,7 @@ try { } finally { return 'finally'; } + ----- Block#1 Stmt_Try @@ -42,9 +43,13 @@ Block#3 Parent: Block#7 Parent: Block#8 finallyTarget: Block#4 - TEMP(#3 ) = Phi(TEMP(#1 ), TEMP(#4 ), TEMP(#5 )) + Phi + vars[0]: TEMP(#1 ) + vars[1]: TEMP(#3 ) + vars[2]: TEMP(#4 ) + result: TEMP(#5 ) Terminal_Return - expr: TEMP(#3 ) + expr: TEMP(#5 ) Block#4 Parent: Block#2 @@ -106,4 +111,5 @@ Block#9 catchTarget(TEMP(#1 )): Block#3 finallyTarget: Block#4 Stmt_Jump - target: Block#4 \ No newline at end of file + target: Block#4 + diff --git a/test/code/try_bodyblocks2.test b/test/code/try_bodyblocks2.test index 21e7ab5..b271353 100644 --- a/test/code/try_bodyblocks2.test +++ b/test/code/try_bodyblocks2.test @@ -15,6 +15,7 @@ try { } echo "next"; + ----- Block#1 Stmt_Try @@ -44,9 +45,13 @@ Block#3 Parent: Block#8 Parent: Block#9 finallyTarget: Block#4 - TEMP(#3 ) = Phi(TEMP(#1 ), TEMP(#4 ), TEMP(#5 )) + Phi + vars[0]: TEMP(#1 ) + vars[1]: TEMP(#3 ) + vars[2]: TEMP(#4 ) + result: TEMP(#5 ) Terminal_Return - expr: TEMP(#3 ) + expr: TEMP(#5 ) Block#4 Parent: Block#2 @@ -116,4 +121,5 @@ Block#10 catchTarget(TEMP(#1 )): Block#3 finallyTarget: Block#4 Stmt_Jump - target: Block#4 \ No newline at end of file + target: Block#4 + diff --git a/test/code/try_finally.test b/test/code/try_finally.test index 59ce932..267ccd6 100644 --- a/test/code/try_finally.test +++ b/test/code/try_finally.test @@ -7,6 +7,7 @@ try { } finally { return 'finally'; } + ----- Block#1 Stmt_Try @@ -37,4 +38,5 @@ Block#4 Parent: Block#2 Parent: Block#3 Terminal_Return - expr: LITERAL('finally') \ No newline at end of file + expr: LITERAL('finally') + diff --git a/test/code/try_nested.test b/test/code/try_nested.test index dcf61a6..bd752f7 100644 --- a/test/code/try_nested.test +++ b/test/code/try_nested.test @@ -3,7 +3,7 @@ try { try { echo "nested try"; - } + } catch(Exception1 $e1) { echo $e1; } @@ -15,6 +15,7 @@ try { } finally { return false; } + ----- Block#1 Stmt_Try @@ -39,9 +40,12 @@ Block#3 Parent: Block#2 Parent: Block#7 finallyTarget: Block#4 - TEMP(#3 ) = Phi(TEMP(#1 ), TEMP(#4 )) + Phi + vars[0]: TEMP(#1 ) + vars[1]: TEMP(#3 ) + result: TEMP(#4 ) Terminal_Echo - expr: TEMP(#3 ) + expr: TEMP(#4 ) Stmt_Jump target: Block#4 @@ -49,11 +53,8 @@ Block#4 Parent: Block#2 Parent: Block#3 Parent: Block#7 - Expr_ConstFetch - name: LITERAL('false') - result: TEMP(#5) Terminal_Return - expr: TEMP(#5) + expr: LITERAL(false) Block#5 Parent: Block#2 @@ -77,8 +78,6 @@ Block#7 Parent: Block#6 catchTarget(TEMP(#1 )): Block#3 finallyTarget: Block#4 - Expr_ConstFetch - name: LITERAL('true') - result: TEMP(#6) Terminal_Return - expr: TEMP(#6) \ No newline at end of file + expr: LITERAL(true) + diff --git a/test/code/type_assert.test b/test/code/type_assert.test index 4517799..26efa78 100755 --- a/test/code/type_assert.test +++ b/test/code/type_assert.test @@ -4,6 +4,7 @@ if (is_int($a) || is_float($a)) { echo $a; } var_dump($a); + ----- Block#1 Expr_FuncCall @@ -29,7 +30,7 @@ Block#3 Expr_Assertion expr: TEMP(#1 ) result: TEMP(#4 ) - assert: not(LITERAL('int')) + assert['not']: LITERAL('int') Expr_FuncCall name: LITERAL('is_float') args[0]: TEMP(#4 ) @@ -43,8 +44,14 @@ Block#3 Block#4 Parent: Block#3 Parent: Block#2 - TEMP(#7) = Phi(LITERAL(true), TEMP(#6)) - TEMP(#8 ) = Phi(TEMP(#4 ), TEMP(#3 )) + Phi + vars[0]: LITERAL(true) + vars[1]: TEMP(#6) + result: TEMP(#7) + Phi + vars[0]: TEMP(#4 ) + vars[1]: TEMP(#3 ) + result: TEMP(#8 ) Stmt_JumpIf cond: TEMP(#7) if: Block#5 @@ -55,7 +62,8 @@ Block#5 Expr_Assertion expr: TEMP(#8 ) result: TEMP(#9 ) - assert: LITERAL('int')|LITERAL('float') + assert['|'][0]: LITERAL('int') + assert['|'][1]: LITERAL('float') Terminal_Echo expr: TEMP(#9 ) Stmt_Jump @@ -66,16 +74,21 @@ Block#6 Expr_Assertion expr: TEMP(#8 ) result: TEMP(#10 ) - assert: not(LITERAL('int')|LITERAL('float')) + assert['not']['|'][0]: LITERAL('int') + assert['not']['|'][1]: LITERAL('float') Stmt_Jump target: Block#7 Block#7 Parent: Block#5 Parent: Block#6 - TEMP(#11 ) = Phi(TEMP(#9 ), TEMP(#10 )) + Phi + vars[0]: TEMP(#9 ) + vars[1]: TEMP(#10 ) + result: TEMP(#11 ) Expr_FuncCall name: LITERAL('var_dump') args[0]: TEMP(#11 ) result: TEMP(#12) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/unary.test b/test/code/unary.test index 4a2d323..11684f7 100644 --- a/test/code/unary.test +++ b/test/code/unary.test @@ -27,4 +27,5 @@ Block#1 var: TEMP(#8 ) expr: TEMP(#7) result: TEMP(#9) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/unionType.test b/test/code/unionType.test index 4a53472..b104f9b 100644 --- a/test/code/unionType.test +++ b/test/code/unionType.test @@ -2,6 +2,7 @@ function foo(array|string|null $string) { } + ----- Block#1 Stmt_Function diff --git a/test/code/variablevariable.test b/test/code/variablevariable.test index a43200b..020130e 100755 --- a/test/code/variablevariable.test +++ b/test/code/variablevariable.test @@ -2,13 +2,14 @@ ${$foo} = "bar"; ${$foo1."plus".$foo2} = "bar"; -$$foo = "bar"; +$$foo = "bar"; $$$$$$$a = "b"; echo $foo->{$baz[1]}; echo $foo->{$start . $end}; echo $foo->{$arr[1]}; echo $foo->{$arr}[1]; + ----- Block#1 Expr_VarVar @@ -102,4 +103,5 @@ Block#1 result: TEMP(#31) Terminal_Echo expr: TEMP(#31) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/while.test b/test/code/while.test index f7c0b0a..f3780fb 100644 --- a/test/code/while.test +++ b/test/code/while.test @@ -13,11 +13,8 @@ Block#1 Block#2 Parent: Block#1 Parent: Block#3 - Expr_ConstFetch - name: LITERAL('true') - result: TEMP(#1) Stmt_JumpIf - cond: TEMP(#1) + cond: LITERAL(true) if: Block#3 else: Block#4 @@ -32,4 +29,5 @@ Block#4 Parent: Block#2 Terminal_Echo expr: LITERAL(2) - Terminal_Return \ No newline at end of file + Terminal_Return + diff --git a/test/code/yeild_from.test b/test/code/yeild_from.test index a52b7d8..200a0bd 100644 --- a/test/code/yeild_from.test +++ b/test/code/yeild_from.test @@ -10,6 +10,7 @@ function gen_zero_four() { yield from gen_one_to_three(); yield 4; } + ----- Block#1 Stmt_Function @@ -30,9 +31,12 @@ Block#1 Block#2 Parent: Block#1 Parent: Block#5 - TEMP(#3 ) = Phi(TEMP(#1 ), TEMP(#4 )) + Phi + vars[0]: TEMP(#1 ) + vars[1]: TEMP(#3 ) + result: TEMP(#4 ) Expr_BinaryOp_SmallerOrEqual - left: TEMP(#3 ) + left: TEMP(#4 ) right: LITERAL(3) result: TEMP(#5) Stmt_JumpIf @@ -43,7 +47,7 @@ Block#2 Block#3 Parent: Block#2 Expr_Yield - key: TEMP(#3 ) + key: TEMP(#4 ) result: TEMP(#6) Stmt_Jump target: Block#5 @@ -55,11 +59,11 @@ Block#4 Block#5 Parent: Block#3 Expr_BinaryOp_Plus - left: TEMP(#3 ) + left: TEMP(#4 ) right: LITERAL(1) result: TEMP(#7) Expr_Assign - var: TEMP(#4 ) + var: TEMP(#3 ) expr: TEMP(#7) result: TEMP(#8) Stmt_Jump @@ -80,3 +84,4 @@ Block#1 key: LITERAL(4) result: TEMP(#4) Terminal_Return + diff --git a/test/code/yield.test b/test/code/yield.test index f9eebf2..2c5a5ea 100644 --- a/test/code/yield.test +++ b/test/code/yield.test @@ -9,6 +9,7 @@ $generator = gen_one_to_three(); foreach ($generator as $value) { echo "$value\n"; } + ----- Block#1 Stmt_Function @@ -71,9 +72,12 @@ Block#1 Block#2 Parent: Block#1 Parent: Block#5 - TEMP(#3 ) = Phi(TEMP(#1 ), TEMP(#4 )) + Phi + vars[0]: TEMP(#1 ) + vars[1]: TEMP(#3 ) + result: TEMP(#4 ) Expr_BinaryOp_SmallerOrEqual - left: TEMP(#3 ) + left: TEMP(#4 ) right: LITERAL(3) result: TEMP(#5) Stmt_JumpIf @@ -84,7 +88,7 @@ Block#2 Block#3 Parent: Block#2 Expr_Yield - key: TEMP(#3 ) + key: TEMP(#4 ) result: TEMP(#6) Stmt_Jump target: Block#5 @@ -96,12 +100,13 @@ Block#4 Block#5 Parent: Block#3 Expr_BinaryOp_Plus - left: TEMP(#3 ) + left: TEMP(#4 ) right: LITERAL(1) result: TEMP(#7) Expr_Assign - var: TEMP(#4 ) + var: TEMP(#3 ) expr: TEMP(#7) result: TEMP(#8) Stmt_Jump - target: Block#2 \ No newline at end of file + target: Block#2 + diff --git a/test/integration/ParserAttributesTest.php b/test/integration/ParserAttributesTest.php index 0eb27f2..9a5419d 100755 --- a/test/integration/ParserAttributesTest.php +++ b/test/integration/ParserAttributesTest.php @@ -57,7 +57,7 @@ function foo(\$a) { $result = $e->getMessage(); } - $this->assertEquals($this->canonicalize($expected), $this->canonicalize($result)); + $this->assertEquals(CodeTest::canonicalize($expected), CodeTest::canonicalize($result)); } public function testAttributes() @@ -77,7 +77,6 @@ function foowithattribute(\$a) { $expected = <<<'EOF' Block#1 Stmt_Function - name: foo attribute['filename']: foo.php attribute['startLine']: 2 attribute['startTokenPos']: 1 @@ -85,8 +84,8 @@ function foowithattribute(\$a) { attribute['endLine']: 4 attribute['endTokenPos']: 15 attribute['endFilePos']: 40 + name: foo Stmt_Function - name: foowithattribute attribute['filename']: foo.php attribute['startLine']: 6 attribute['startTokenPos']: 17 @@ -94,31 +93,27 @@ function foowithattribute(\$a) { attribute['endLine']: 9 attribute['endTokenPos']: 35 attribute['endFilePos']: 98 - attrGroup[0]: - attribute['filename']: foo.php - attribute['startLine']: 6 - attribute['startTokenPos']: 17 - attribute['startFilePos']: 43 - attribute['endLine']: 6 - attribute['endTokenPos']: 19 - attribute['endFilePos']: 49 - attr[0]: - attribute['filename']: foo.php - attribute['startLine']: 6 - attribute['startTokenPos']: 18 - attribute['startFilePos']: 45 - attribute['endLine']: 6 - attribute['endTokenPos']: 18 - attribute['endFilePos']: 48 - name: LITERAL('Attr') + attrGroup[0]['attribute']['filename']: foo.php + attrGroup[0]['attribute']['startLine']: 6 + attrGroup[0]['attribute']['startTokenPos']: 17 + attrGroup[0]['attribute']['startFilePos']: 43 + attrGroup[0]['attribute']['endLine']: 6 + attrGroup[0]['attribute']['endTokenPos']: 19 + attrGroup[0]['attribute']['endFilePos']: 49 + attrGroup[0][0]['attribute']['filename']: foo.php + attrGroup[0][0]['attribute']['startLine']: 6 + attrGroup[0][0]['attribute']['startTokenPos']: 18 + attrGroup[0][0]['attribute']['startFilePos']: 45 + attrGroup[0][0]['attribute']['endLine']: 6 + attrGroup[0][0]['attribute']['endTokenPos']: 18 + attrGroup[0][0]['attribute']['endFilePos']: 48 + attrGroup[0][0]['name']: LITERAL('Attr') + name: foowithattribute Terminal_Return Function 'foo': mixed Block#1 Expr_Param - declaredType: mixed - name: LITERAL('a') - result: TEMP(#1 ) attribute['filename']: foo.php attribute['startLine']: 2 attribute['startTokenPos']: 5 @@ -126,8 +121,10 @@ function foowithattribute(\$a) { attribute['endLine']: 2 attribute['endTokenPos']: 5 attribute['endFilePos']: 20 + declaredType: mixed + name: LITERAL('a') + result: TEMP(#1 ) Terminal_Return - expr: TEMP(#1 ) attribute['filename']: foo.php attribute['startLine']: 3 attribute['startTokenPos']: 10 @@ -135,13 +132,11 @@ function foowithattribute(\$a) { attribute['endLine']: 3 attribute['endTokenPos']: 13 attribute['endFilePos']: 38 + expr: TEMP(#1 ) Function 'foowithattribute': mixed Block#1 Expr_Param - declaredType: mixed - name: LITERAL('a') - result: TEMP(#1 ) attribute['filename']: foo.php attribute['startLine']: 7 attribute['startTokenPos']: 25 @@ -149,8 +144,10 @@ function foowithattribute(\$a) { attribute['endLine']: 7 attribute['endTokenPos']: 25 attribute['endFilePos']: 78 + declaredType: mixed + name: LITERAL('a') + result: TEMP(#1 ) Terminal_Return - expr: TEMP(#1 ) attribute['filename']: foo.php attribute['startLine']: 8 attribute['startTokenPos']: 30 @@ -158,6 +155,7 @@ function foowithattribute(\$a) { attribute['endLine']: 8 attribute['endTokenPos']: 33 attribute['endFilePos']: 96 + expr: TEMP(#1 ) EOF; $parser = new Parser((new ParserFactory())->createForNewestSupportedVersion(), null); @@ -173,18 +171,6 @@ function foowithattribute(\$a) { $result = $e->getMessage(); } - $this->assertEquals($this->canonicalize($expected), $this->canonicalize($result)); - } - - private function canonicalize($str) - { - // trim from both sides - $str = trim($str); - - // normalize EOL to \n - $str = str_replace(["\r\n", "\r"], "\n", $str); - - // trim right side of all lines - return implode("\n", array_map('rtrim', explode("\n", $str))); + $this->assertEquals(CodeTest::canonicalize($expected), CodeTest::canonicalize($result)); } }