getInstance() public static method

We can only reach the nodeStackState class through a ::getInstance() call.
public static getInstance ( ) : NodeStateStack
return NodeStateStack
Exemplo n.º 1
0
 /**
  * @param array $nodes
  * @return \PhpParser\Node[]
  */
 public function traverse(array $nodes)
 {
     NodeStateStack::getInstance()->pushVars();
     $ret = parent::traverse($nodes);
     NodeStateStack::getInstance()->popVars();
     return $ret;
 }
Exemplo n.º 2
0
 public function leaveNode(Node $node)
 {
     if ($node instanceof ClassLike) {
         NodeStateStack::getInstance()->pop('currentClass');
     }
     if (!$node instanceof Node\FunctionLike) {
         return;
     }
     $functionNode = NodeStateStack::getInstance()->end('currentFunction');
     $functionNode = $functionNode['node'];
     NodeStateStack::getInstance()->pop('currentFunction');
     // Remove return type if set
     if ($node->returnType) {
         $node->returnType = null;
     }
     // Remove scalar types and store for later
     $params = array();
     foreach ($node->params as $param) {
         if (in_array($param->type, array('string', 'int', 'float', 'bool'))) {
             $canBeNull = false;
             if ($param->default != null) {
                 if ($param->default instanceof Node\Expr\ConstFetch) {
                     if ($param->default->name->parts[0] == "null") {
                         $canBeNull = true;
                     }
                 }
             }
             $params[] = array('type' => $param->type, 'arg' => $param->name, 'func' => $node->name, 'nullable' => $canBeNull);
             $param->type = null;
         }
     }
     // Don't add checks when we don't enforce strict
     if (!NodeStateStack::getInstance()->get('isStrict')) {
         return null;
     }
     // No typehinting on abstract
     if ($functionNode instanceof Node\Stmt\ClassMethod && $functionNode->isAbstract()) {
         return null;
     }
     // No typehinting on interfaces
     if (NodeStateStack::getInstance()->end('currentClass') instanceof Interface_) {
         return null;
     }
     // Add code for checking scalar types
     foreach (array_reverse($params) as $param) {
         $code = sprintf('<?php if (! is_%s($%s) %s) { throw new \\InvalidArgumentException("Argument \\$%s passed to %s() must be of the type %s, ".(gettype($%s) == "object" ? get_class($%s) : gettype($%s))." given"); }', $param['type'], $param['arg'], $param['nullable'] ? 'and ! is_null($' . $param['arg'] . ')' : "", $param['arg'], $param['func'], $param['type'], $param['arg'], $param['arg'], $param['arg'], $param['arg']);
         $parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
         $stmts = $parser->parse($code);
         if (!$node->stmts) {
             $node->stmts = $stmts;
         } else {
             $node->stmts = array_merge($stmts, $node->stmts);
         }
     }
 }
 public function leaveNode(Node $node)
 {
     if ($node instanceof Node\Expr\Yield_) {
         $functionNode = NodeStateStack::getInstance()->pop('currentFunction');
         $functionNode['generator'] = true;
         NodeStateStack::getInstance()->push('currentFunction', $functionNode);
         return null;
     }
     if ($node instanceof Node\Stmt\Return_) {
         $functionNode = NodeStateStack::getInstance()->end('currentFunction');
         if ($functionNode['generator']) {
             throw new TranspileException("Cannot transpile return statements from generators");
         }
     }
     return null;
 }
Exemplo n.º 4
0
 public function leaveNode(Node $node)
 {
     if (!$node instanceof Node\Stmt\Declare_) {
         return null;
     }
     foreach ($node->declares as $idx => $declare) {
         if ($declare->key != 'strict_types') {
             continue;
         }
         // Set global strict value so others know what to do with scalar typehinting and return types.
         NodeStateStack::getInstance()->set('isStrict', $declare->value->value == 1);
         // Remove the strict_type declare
         return NodeTraverser::REMOVE_NODE;
     }
     return null;
 }
Exemplo n.º 5
0
 public function leaveNode(Node $node)
 {
     if (!$node instanceof Node\Stmt\Return_) {
         return null;
     }
     $functionNode = NodeStateStack::getInstance()->end('currentFunction');
     // No functionNode means we are doing a return in the global scope
     if (!$functionNode) {
         return null;
     }
     $functionNode = $functionNode['node'];
     // Check return type of current function
     if ($functionNode->returnType == null) {
         return null;
     }
     // Not strict, so no need to check return type;
     if (!NodeStateStack::getInstance()->get('isStrict')) {
         return null;
     }
     // Define uniq retvar for returning, most likely not needed but done to make sure we don't
     // hit any existing variables or multiple return vars
     $retVar = 'ret' . uniqid(true);
     // Generate code for "$retVar = <originalExpression>"
     $retNode = new Node\Expr\Assign(new Node\Expr\Variable($retVar), $node->expr);
     // Generate remainder code
     $returnType = (string) $functionNode->returnType;
     // Manually add starting namespace separator for FQCN
     if ($functionNode->returnType instanceof Node\Name\FullyQualified && $returnType[0] != '\\') {
         $returnType = '\\' . $returnType;
     }
     // @TODO: It might be easier to read when we generate ALL code directly from Nodes instead of generating it
     if (in_array($returnType, array('string', 'bool', 'int', 'float', 'array'))) {
         // Scalars are treated a bit different
         $code = sprintf('<?php ' . "\n" . '  if (! is_%s($' . $retVar . ')) { ' . "\n" . '    throw new \\InvalidArgumentException("Argument returned must be of the type %s, ".gettype($' . $retVar . ')." given"); ' . "\n" . '  } ' . "\n" . '  return $' . $retVar . '; ', $returnType, $returnType);
     } else {
         // Otherwise use is_a for check against classes
         $code = sprintf('<?php ' . "\n" . '  if (! $' . $retVar . ' instanceof %s) { ' . "\n" . '    throw new \\InvalidArgumentException("Argument returned must be of the type %s, ".(gettype($' . $retVar . ') == "object" ? get_class($' . $retVar . ') : gettype($' . $retVar . '))." given"); ' . "\n" . '  } ' . "\n" . '  return $' . $retVar . '; ', $returnType, $returnType);
     }
     $parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
     $stmts = $parser->parse($code);
     // Merge $retVar = <expr> with remainder code
     $stmts = array_merge(array($retNode), $stmts);
     return $stmts;
 }
Exemplo n.º 6
0
 /**
  * Add final anonymous classes to the statements
  *
  * @param array $nodes
  * @return array
  */
 public function afterTraverse(array $nodes)
 {
     // Nothing to do when there are no anonymous classes
     if (NodeStateStack::getInstance()->count('anonClasses') == 0) {
         return $nodes;
     }
     // We must transpile anonymous classes first, as we haven't done this yet
     $traverser = Transpile::getTraverser();
     $anonClassStmts = $traverser->traverse(NodeStateStack::getInstance()->get('anonClasses'));
     // Find hook point for anonymous classes, which must be after declare, namespaces and use-statements, and can
     // before anything else. This might cause issues when anonymous classes implement interfaces that are defined
     // later on.
     $idx = $this->getAnonymousClassHookIndex($nodes);
     // Array_merge the anonymous class statements on the correct position
     $preStmts = array_slice($nodes, 0, $idx);
     $postStmts = array_slice($nodes, $idx);
     $nodes = array_merge($preStmts, $anonClassStmts, $postStmts);
     return $nodes;
 }