/**
  * @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;
     }
 }
 /**
  * @param array $tokens
  *   The tokens from token_get_all()
  * @param int $i
  *   Before: Position of the first token of the element to parse.
  *   After, success: Position of the first token _after_ the parsed element.
  *   After, failure: Same as before.
  *
  * @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, &$i)
 {
     $iStart = $i;
     if (FALSE === ParserUtil::skipCurly($tokens, $i)) {
         return FALSE;
     }
     return new AstClassLikeBody_LazyProxy($this->decorated, $tokens, $iStart);
 }
 /**
  * @param string $php
  * @param int $i_start
  * @param int $i_expected
  * @param bool $result_expected
  *
  * @dataProvider providerSkipCurly
  */
 public function testSkipCurly($php, $i_start, $i_expected, $result_expected)
 {
     $tokens = token_get_all($php);
     $tokens[] = '#';
     static::assertSame('{', $tokens[$i_start]);
     $i = $i_start;
     $result = ParserUtil::skipCurly($tokens, $i);
     static::assertSame($i_expected, $i);
     if ($result_expected !== false) {
         static::assertSame('}', $tokens[$i_expected - 1]);
     }
     static::assertSame($result_expected, $result);
 }
 /**
  * @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
  *
  * @return bool|null
  */
 static function ignoreStatement($tokens, &$i)
 {
     for (;; ++$i) {
         if (';' === ($token = $tokens[$i])) {
             ++$i;
             return NULL;
         } elseif ('(' === $token) {
             if (FALSE === ParserUtil::skipCurvy($tokens, $i)) {
                 return FALSE;
             }
         } elseif ('{' === $token) {
             if (FALSE === ParserUtil::skipCurly($tokens, $i)) {
                 return FALSE;
             }
             return NULL;
         } elseif (')' === $token) {
             return FALSE;
         } elseif ('}' === $token) {
             return FALSE;
         } elseif ('#' === $token) {
             return FALSE;
         }
     }
     return FALSE;
 }
 /**
  * @param mixed[] $tokens
  * @param int $i
  *   Before: Position on the T_NAMESPACE.
  *   After (success): Position after the ';'.
  *
  * @return bool|\Donquixote\HastyPhpAst\Ast\Namespace_\AstNamespaceDeclaration
  */
 static function parseNamespaceDeclaration(array $tokens, &$i)
 {
     $id = ParserUtil::nextSubstantialExcl($tokens, $i);
     if (T_STRING !== $id) {
         return FALSE;
     }
     $fqcn = Ptk_Qcn::parse($tokens, $i);
     if (FALSE === $fqcn) {
         return FALSE;
     }
     return new AstNamespaceDeclaration($fqcn);
 }
 /**
  * @param mixed[] $tokens
  * @param int $i
  *
  * @return bool|null
  */
 static function ignoreMiraculousMember(array $tokens, &$i)
 {
     # $iStart = $i;
     for (;; ++$i) {
         if (';' === ($token = $tokens[$i])) {
             ++$i;
             return NULL;
             # return new AstIgnored($tokens, $iStart, $i);
         } elseif ('(' === $token) {
             if (FALSE === ParserUtil::skipCurvy($tokens, $i)) {
                 return FALSE;
             }
             --$i;
         } elseif ('{' === $token) {
             if (FALSE === ParserUtil::skipCurly($tokens, $i)) {
                 return FALSE;
             }
             return NULL;
             # return new AstIgnored($tokens, $iStart, $i);
         } elseif (')' === $token) {
             ++$i;
             return FALSE;
         } elseif ('}' === $token) {
             ++$i;
             return FALSE;
         } elseif ('#' === $token) {
             return FALSE;
         }
     }
     return FALSE;
 }