annotate vendor/psy/psysh/src/Sudo/SudoVisitor.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@13 1 <?php
Chris@13 2
Chris@13 3 /*
Chris@13 4 * This file is part of Psy Shell.
Chris@13 5 *
Chris@13 6 * (c) 2012-2018 Justin Hileman
Chris@13 7 *
Chris@13 8 * For the full copyright and license information, please view the LICENSE
Chris@13 9 * file that was distributed with this source code.
Chris@13 10 */
Chris@13 11
Chris@13 12 namespace Psy\Sudo;
Chris@13 13
Chris@13 14 use PhpParser\Node;
Chris@13 15 use PhpParser\Node\Arg;
Chris@13 16 use PhpParser\Node\Expr\Assign;
Chris@13 17 use PhpParser\Node\Expr\ClassConstFetch;
Chris@13 18 use PhpParser\Node\Expr\MethodCall;
Chris@13 19 use PhpParser\Node\Expr\PropertyFetch;
Chris@13 20 use PhpParser\Node\Expr\StaticCall;
Chris@13 21 use PhpParser\Node\Expr\StaticPropertyFetch;
Chris@13 22 use PhpParser\Node\Identifier;
Chris@13 23 use PhpParser\Node\Name;
Chris@13 24 use PhpParser\Node\Name\FullyQualified as FullyQualifiedName;
Chris@13 25 use PhpParser\Node\Scalar\String_;
Chris@13 26 use PhpParser\NodeVisitorAbstract;
Chris@13 27
Chris@13 28 /**
Chris@13 29 * A PHP Parser node visitor which rewrites property and method access to use
Chris@13 30 * the Psy\Sudo visibility bypass methods.
Chris@13 31 *
Chris@13 32 * @todo handle assigning by reference
Chris@13 33 */
Chris@13 34 class SudoVisitor extends NodeVisitorAbstract
Chris@13 35 {
Chris@13 36 const SUDO_CLASS = 'Psy\Sudo';
Chris@13 37
Chris@13 38 const PROPERTY_FETCH = 'fetchProperty';
Chris@13 39 const PROPERTY_ASSIGN = 'assignProperty';
Chris@13 40 const METHOD_CALL = 'callMethod';
Chris@13 41 const STATIC_PROPERTY_FETCH = 'fetchStaticProperty';
Chris@13 42 const STATIC_PROPERTY_ASSIGN = 'assignStaticProperty';
Chris@13 43 const STATIC_CALL = 'callStatic';
Chris@13 44 const CLASS_CONST_FETCH = 'fetchClassConst';
Chris@13 45
Chris@13 46 /**
Chris@13 47 * {@inheritdoc}
Chris@13 48 */
Chris@13 49 public function enterNode(Node $node)
Chris@13 50 {
Chris@13 51 if ($node instanceof PropertyFetch) {
Chris@13 52 $name = $node->name instanceof Identifier ? $node->name->toString() : $node->name;
Chris@13 53 $args = [
Chris@13 54 $node->var,
Chris@17 55 \is_string($name) ? new String_($name) : $name,
Chris@13 56 ];
Chris@13 57
Chris@13 58 return $this->prepareCall(self::PROPERTY_FETCH, $args);
Chris@13 59 } elseif ($node instanceof Assign && $node->var instanceof PropertyFetch) {
Chris@13 60 $target = $node->var;
Chris@13 61 $name = $target->name instanceof Identifier ? $target->name->toString() : $target->name;
Chris@13 62 $args = [
Chris@13 63 $target->var,
Chris@17 64 \is_string($name) ? new String_($name) : $name,
Chris@13 65 $node->expr,
Chris@13 66 ];
Chris@13 67
Chris@13 68 return $this->prepareCall(self::PROPERTY_ASSIGN, $args);
Chris@13 69 } elseif ($node instanceof MethodCall) {
Chris@13 70 $name = $node->name instanceof Identifier ? $node->name->toString() : $node->name;
Chris@13 71 $args = $node->args;
Chris@17 72 \array_unshift($args, new Arg(\is_string($name) ? new String_($name) : $name));
Chris@17 73 \array_unshift($args, new Arg($node->var));
Chris@13 74
Chris@13 75 // not using prepareCall because the $node->args we started with are already Arg instances
Chris@13 76 return new StaticCall(new FullyQualifiedName(self::SUDO_CLASS), self::METHOD_CALL, $args);
Chris@13 77 } elseif ($node instanceof StaticPropertyFetch) {
Chris@13 78 $class = $node->class instanceof Name ? $node->class->toString() : $node->class;
Chris@13 79 $name = $node->name instanceof Identifier ? $node->name->toString() : $node->name;
Chris@13 80 $args = [
Chris@17 81 \is_string($class) ? new String_($class) : $class,
Chris@17 82 \is_string($name) ? new String_($name) : $name,
Chris@13 83 ];
Chris@13 84
Chris@13 85 return $this->prepareCall(self::STATIC_PROPERTY_FETCH, $args);
Chris@13 86 } elseif ($node instanceof Assign && $node->var instanceof StaticPropertyFetch) {
Chris@13 87 $target = $node->var;
Chris@13 88 $class = $target->class instanceof Name ? $target->class->toString() : $target->class;
Chris@13 89 $name = $target->name instanceof Identifier ? $target->name->toString() : $target->name;
Chris@13 90 $args = [
Chris@17 91 \is_string($class) ? new String_($class) : $class,
Chris@17 92 \is_string($name) ? new String_($name) : $name,
Chris@13 93 $node->expr,
Chris@13 94 ];
Chris@13 95
Chris@13 96 return $this->prepareCall(self::STATIC_PROPERTY_ASSIGN, $args);
Chris@13 97 } elseif ($node instanceof StaticCall) {
Chris@13 98 $args = $node->args;
Chris@13 99 $class = $node->class instanceof Name ? $node->class->toString() : $node->class;
Chris@13 100 $name = $node->name instanceof Identifier ? $node->name->toString() : $node->name;
Chris@17 101 \array_unshift($args, new Arg(\is_string($name) ? new String_($name) : $name));
Chris@17 102 \array_unshift($args, new Arg(\is_string($class) ? new String_($class) : $class));
Chris@13 103
Chris@13 104 // not using prepareCall because the $node->args we started with are already Arg instances
Chris@13 105 return new StaticCall(new FullyQualifiedName(self::SUDO_CLASS), self::STATIC_CALL, $args);
Chris@13 106 } elseif ($node instanceof ClassConstFetch) {
Chris@13 107 $class = $node->class instanceof Name ? $node->class->toString() : $node->class;
Chris@13 108 $name = $node->name instanceof Identifier ? $node->name->toString() : $node->name;
Chris@13 109 $args = [
Chris@17 110 \is_string($class) ? new String_($class) : $class,
Chris@17 111 \is_string($name) ? new String_($name) : $name,
Chris@13 112 ];
Chris@13 113
Chris@13 114 return $this->prepareCall(self::CLASS_CONST_FETCH, $args);
Chris@13 115 }
Chris@13 116 }
Chris@13 117
Chris@13 118 private function prepareCall($method, $args)
Chris@13 119 {
Chris@17 120 return new StaticCall(new FullyQualifiedName(self::SUDO_CLASS), $method, \array_map(function ($arg) {
Chris@13 121 return new Arg($arg);
Chris@13 122 }, $args));
Chris@13 123 }
Chris@13 124 }