/**
  * @param mixed[] $tokens
  *   Tokens from token_get_all().
  * @param int $i
  *   Before: Position of the opening '{'.
  *   After (success): Position after the closing '}'.
  *   After (failure): Same as before.
  *
  * @return \Donquixote\HastyPhpAst\Ast\ClassLikeBody\AstClassLikeBodyInterface|false
  */
 function parse(array $tokens, &$i)
 {
     $iStart = $i;
     if ('{' !== $tokens[$i]) {
         # return FALSE;
         // Wrong usage of this parser. The calling code is responsible!
         throw new \InvalidArgumentException('Class body must begin with "{".');
     }
     ++$i;
     $memberNodes = array();
     while (TRUE) {
         $memberNode = $this->memberParser->parse($tokens, $i);
         if (FALSE === $memberNode) {
             $id = ParserUtil::nextSubstantialIncl($tokens, $i);
             if ('}' === $id) {
                 // End of class body.
                 ++$i;
                 break;
             }
             $i = $iStart;
             return FALSE;
         }
         if (NULL !== $memberNode) {
             $memberNodes[] = $memberNode;
         }
     }
     return new AstClassLikeBody($memberNodes);
 }
 /**
  * @param array $tokens
  *   The tokens from token_get_all()
  * @param int $iParent
  *   Before: Position on T_FUNCTION.
  *   After, success: Position directly after the closing '}' or ';'.
  *   After, failure: Same as before.
  * @param true[] $modifiers
  *   E.g. array(T_ABSTRACT => true, T_PRIVATE => true)
  * @param string $docComment
  *
  * @return false|\Donquixote\HastyPhpAst\Ast\FunctionLike\AstFunctionLike
  */
 function parse(array $tokens, &$iParent, array $modifiers = array(), $docComment = NULL)
 {
     $i = $iParent;
     $id = ParserUtil::nextSubstantialExcl($tokens, $i);
     if ('&' === $id) {
         $modifiers['&'] = TRUE;
         $id = ParserUtil::nextSubstantialExcl($tokens, $i);
     }
     if (T_STRING !== $id) {
         return FALSE;
     }
     $name = $tokens[$i][1];
     $id = ParserUtil::nextSubstantialExcl($tokens, $i);
     if ('(' !== $id) {
         return FALSE;
     }
     // Skip the signature.
     ParserUtil::skipCurvy($tokens, $i);
     $id = ParserUtil::nextSubstantialIncl($tokens, $i);
     if (';' === $id) {
         $iParent = $i + 1;
         return new AstFunctionLike($docComment, $modifiers, $name);
     } elseif ('{' === $id) {
         ParserUtil::skipCurly($tokens, $i);
         $iParent = $i;
         return new AstFunctionLike($docComment, $modifiers, $name);
     } else {
         return FALSE;
     }
 }
Ejemplo n.º 3
0
 /**
  * @param mixed[] $tokens
  * @param int $i
  *
  * @return string[]|bool
  */
 static function parseIdentifierList(array $tokens, &$i)
 {
     $list = array();
     while (TRUE) {
         $id = ParserUtil::nextSubstantialIncl($tokens, $i);
         if (T_STRING !== $id) {
             return FALSE;
         }
         $list[] = $tokens[$i][1];
         $id = ParserUtil::nextSubstantialExcl($tokens, $i);
         if (',' !== $id) {
             break;
         }
         ++$i;
     }
     return $list;
 }
 /**
  * @param mixed[] $tokens
  * @param int $i
  *
  * @return mixed
  */
 private function doParse(array $tokens, &$i)
 {
     $id = ParserUtil::nextSubstantialIncl($tokens, $i);
     if (T_USE === $id) {
         return ParserUtil::parseUseStatementGroup($tokens, $i);
     } elseif (T_NAMESPACE === $id) {
         return ParserUtil::parseNamespaceDeclaration($tokens, $i);
     } elseif (T_FINAL === $id || T_ABSTRACT === $id) {
         if (T_DOC_COMMENT === $tokens[$i - 2][0]) {
             $docComment = $tokens[$i - 2][1];
         } else {
             $docComment = NULL;
         }
         $modifiers = array($id => TRUE);
         while (TRUE) {
             $id = ParserUtil::nextSubstantialExcl($tokens, $i);
             $modifiers[$id] = TRUE;
             if (T_CLASS === $id || T_INTERFACE === $id || T_TRAIT === $id) {
                 return $this->classLikeParser->parse($tokens, $i, $modifiers, $docComment);
             } elseif (T_FINAL === $id || T_ABSTRACT === $id) {
                 $modifiers[$id] = TRUE;
             } else {
                 // Something other than the above does not belong here.
                 return FALSE;
             }
         }
         throw new \RuntimeException('Unreachable code.');
     } elseif (T_CLASS === $id || T_INTERFACE === $id || T_TRAIT === $id) {
         if (T_DOC_COMMENT === $tokens[$i - 2][0]) {
             $docComment = $tokens[$i - 2][1];
         } else {
             $docComment = NULL;
         }
         return $this->classLikeParser->parse($tokens, $i, array($id => TRUE), $docComment);
     } elseif ('#' === $id) {
         return FALSE;
     } else {
         return self::ignoreStatement($tokens, $i);
     }
 }
Ejemplo n.º 5
0
 /**
  * @param array $tokens
  * @param int $i
  *
  * @return \Donquixote\HastyPhpAst\Ast\File\AstFileInterface|false
  */
 function parse(array $tokens, &$i)
 {
     if (T_OPEN_TAG !== $tokens[$i][0]) {
         return FALSE;
     }
     ++$i;
     $nodes = array();
     while (TRUE) {
         $node = $this->parser->parse($tokens, $i);
         if (FALSE === $node) {
             $id = ParserUtil::nextSubstantialIncl($tokens, $i);
             if ('#' === $id) {
                 // End of file/stream.
                 break;
             }
             return FALSE;
         }
         if (NULL !== $node) {
             $nodes[] = $node;
         }
     }
     return new AstFile($nodes);
 }
 /**
  * @param array $tokens
  *   The tokens from token_get_all()
  * @param int $iParent
  *   Before: Position of the T_CLASS or T_INTERFACE or T_TRAIT.
  *   After, success: Position after the closing '}' or ';'.
  *   After, failure: Same as before.
  * @param true[] $modifiers
  *   E.g. array(T_ABSTRACT => true, T_INTERFACE => true, T_PRIVATE => true)
  * @param string $docComment
  *   Doc comment collected in calling code.
  *
  * @return mixed|false|null
  *   FALSE, if this parser does not match.
  *   NULL, if the parsed element can be skipped in the result.
  *   A parse subtree, otherwise.
  *
  * @throws ParseError
  *   If a syntax error is found in the code.
  *
  * @see token_get_all()
  */
 function parse(array $tokens, &$iParent, array $modifiers = array(), $docComment = NULL)
 {
     $i = $iParent;
     $id = ParserUtil::nextSubstantialExcl($tokens, $i);
     if (T_STRING !== $id) {
         return FALSE;
     }
     $shortName = $tokens[$i][1];
     $id = ParserUtil::nextSubstantialExcl($tokens, $i);
     $extendsAliases = array();
     if (T_EXTENDS === $id) {
         ++$i;
         $extendsAliases = ParserUtil::parseIdentifierList($tokens, $i);
         if (FALSE === $extendsAliases) {
             return FALSE;
         }
         $id = ParserUtil::nextSubstantialIncl($tokens, $i);
     }
     $implementsAliases = array();
     if (T_IMPLEMENTS === $id) {
         ++$i;
         $implementsAliases = ParserUtil::parseIdentifierList($tokens, $i);
         if (FALSE === $implementsAliases) {
             return FALSE;
         }
         $id = ParserUtil::nextSubstantialIncl($tokens, $i);
     }
     if ('{' !== $id) {
         return FALSE;
     }
     $body = $this->classBodyParser->parse($tokens, $i);
     if (FALSE === $body) {
         return FALSE;
     }
     $iParent = $i;
     return new AstClassLike($docComment, $modifiers, $shortName, $extendsAliases, $implementsAliases, $body);
 }
 /**
  * @param mixed[] $tokens
  * @param int $i
  *   Before: Position of T_TRAIT
  *   After (success): Position after the closing ';' or '}'.
  *   After (failure): Random position.
  *
  * @return \Donquixote\HastyPhpAst\Ast\UseTrait\AstUseTrait|false
  */
 static function parseUseTrait(array $tokens, &$i)
 {
     ++$i;
     $names = ParserUtil::parseIdentifierList($tokens, $i);
     if (FALSE === $names) {
         return FALSE;
     }
     $id = ParserUtil::nextSubstantialIncl($tokens, $i);
     if (';' === $id) {
         ++$i;
         return new AstUseTrait($names);
     } elseif ('{' === $id) {
         ParserUtil::skipCurly($tokens, $i);
         return new AstUseTrait($names);
     } else {
         return FALSE;
     }
 }