protected function compileBody(Block $block, $indent) { if ($this->state->seen->contains($block)) { return ''; } $result = ''; $this->state->seen->attach($block); foreach ($block->phi as $phi) { foreach ($phi->vars as $var) { if ($var instanceof Operand\Literal) { $result .= $indent . $this->getVarName($phi->result) . " = " . $this->getVarName($var) . ";\n"; } } } // This comes after constant phi assignment, since we can possibly re-enter $result .= $this->getLabel($block) . ":\n"; foreach ($block->children as $op) { if ($op instanceof Op\Expr) { $result .= $this->compileExpr($op, $indent); continue; } switch ($op->getType()) { case 'Stmt_Jump': if ($this->state->seen->contains($op->target)) { // Only issue the goto if it's not the next statement $result .= $indent . "goto " . $this->getLabel($op->target) . ";\n"; } $result .= $this->compileBody($op->target, $indent); break; case 'Stmt_JumpIf': $result .= $indent . "if (" . $this->getVarName($op->cond) . ") {\n"; $result .= $this->compileBody($op->if, $indent . ' '); $result .= $indent . "} else {\n"; $result .= $this->compileBody($op->else, $indent . ' '); $result .= $indent . "}\n"; break; case 'Terminal_Return': $result .= $indent . 'return'; if ($op->expr) { $result .= ' ' . $this->getVarName($op->expr); } $result .= "\n"; return $result; default: throw new \RuntimeException("Unknown op compilation attempt: " . $op->getType()); } } return $result; }