Chris@0: functionDepth = 0; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function enterNode(Node $node) Chris@0: { Chris@0: // keep track of nested function-like nodes, because they can have Chris@0: // returns statements... and we don't want to call markEnd for those. Chris@0: if ($node instanceof FunctionLike) { Chris@0: $this->functionDepth++; Chris@0: Chris@0: return; Chris@0: } Chris@0: Chris@0: // replace any top-level `return` statements with a `markEnd` call Chris@0: if ($this->functionDepth === 0 && $node instanceof Return_) { Chris@0: return new Return_($this->getEndCall($node->expr), $node->getAttributes()); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function leaveNode(Node $node) Chris@0: { Chris@0: if ($node instanceof FunctionLike) { Chris@0: $this->functionDepth--; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function afterTraverse(array $nodes) Chris@0: { Chris@0: // prepend a `markStart` call Chris@0: array_unshift($nodes, $this->maybeExpression($this->getStartCall())); Chris@0: Chris@0: // append a `markEnd` call (wrapping the final node, if it's an expression) Chris@0: $last = $nodes[count($nodes) - 1]; Chris@0: if ($last instanceof Expr) { Chris@0: array_pop($nodes); Chris@0: $nodes[] = $this->getEndCall($last); Chris@0: } elseif ($last instanceof Expression) { Chris@0: array_pop($nodes); Chris@0: $nodes[] = new Expression($this->getEndCall($last->expr), $last->getAttributes()); Chris@0: } elseif ($last instanceof Return_) { Chris@0: // nothing to do here, we're already ending with a return call Chris@0: } else { Chris@0: $nodes[] = $this->maybeExpression($this->getEndCall()); Chris@0: } Chris@0: Chris@0: return $nodes; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get PhpParser AST nodes for a `markStart` call. Chris@0: * Chris@0: * @return PhpParser\Node\Expr\StaticCall Chris@0: */ Chris@0: private function getStartCall() Chris@0: { Chris@0: return new StaticCall(new FullyQualifiedName('Psy\Command\TimeitCommand'), 'markStart'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get PhpParser AST nodes for a `markEnd` call. Chris@0: * Chris@0: * Optionally pass in a return value. Chris@0: * Chris@0: * @param Expr|null $arg Chris@0: * Chris@0: * @return PhpParser\Node\Expr\StaticCall Chris@0: */ Chris@0: private function getEndCall(Expr $arg = null) Chris@0: { Chris@0: if ($arg === null) { Chris@0: $arg = NoReturnValue::create(); Chris@0: } Chris@0: Chris@0: return new StaticCall(new FullyQualifiedName('Psy\Command\TimeitCommand'), 'markEnd', [new Arg($arg)]); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Compatibility shim for PHP Parser 3.x. Chris@0: * Chris@0: * Wrap $expr in a PhpParser\Node\Stmt\Expression if the class exists. Chris@0: * Chris@0: * @param PhpParser\Node $expr Chris@0: * @param array $attrs Chris@0: * Chris@0: * @return PhpParser\Node\Expr|PhpParser\Node\Stmt\Expression Chris@0: */ Chris@0: private function maybeExpression($expr, $attrs = []) Chris@0: { Chris@0: return class_exists('PhpParser\Node\Stmt\Expression') ? new Expression($expr, $attrs) : $expr; Chris@0: } Chris@0: }