Example #1
0
 public function testNamespaceResolverPersistsNamespace()
 {
     $nr = new NameInformation('Foo\\Bar');
     $this->assertEquals('Foo\\Bar', $nr->getNamespace());
     $nr = new NameInformation();
     $nr->setNamespace('Bar\\Baz');
     $this->assertEquals('Bar\\Baz', $nr->getNamespace());
 }
Example #2
0
 /**
  * Scan tokens
  *
  * @return void
  * @throws Exception\RuntimeException
  */
 protected function scan()
 {
     if ($this->isScanned) {
         return;
     }
     if (!$this->tokens) {
         throw new Exception\RuntimeException('No tokens were provided');
     }
     /**
      * Variables & Setup
      */
     $tokens =& $this->tokens;
     // localize
     $infos =& $this->infos;
     // localize
     $tokenIndex = null;
     $token = null;
     $tokenType = null;
     $tokenContent = null;
     $tokenLine = null;
     $namespace = null;
     $infoIndex = 0;
     $braceCount = 0;
     /*
      * MACRO creation
      */
     $MACRO_TOKEN_ADVANCE = function () use(&$tokens, &$tokenIndex, &$token, &$tokenType, &$tokenContent, &$tokenLine) {
         static $lastTokenArray = null;
         $tokenIndex = $tokenIndex === null ? 0 : $tokenIndex + 1;
         if (!isset($tokens[$tokenIndex])) {
             $token = false;
             $tokenContent = false;
             $tokenType = false;
             $tokenLine = false;
             return false;
         }
         $token = $tokens[$tokenIndex];
         if (is_string($token)) {
             $tokenType = null;
             $tokenContent = $token;
             $tokenLine = $tokenLine + substr_count($lastTokenArray[1], "\n");
             // adjust token line by last known newline count
         } else {
             $lastTokenArray = $token;
             list($tokenType, $tokenContent, $tokenLine) = $token;
         }
         return $tokenIndex;
     };
     $MACRO_INFO_ADVANCE = function () use(&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
         $infos[$infoIndex]['tokenEnd'] = $tokenIndex;
         $infos[$infoIndex]['lineEnd'] = $tokenLine;
         $infoIndex++;
         return $infoIndex;
     };
     /**
      * START FINITE STATE MACHINE FOR SCANNING TOKENS
      */
     // Initialize token
     $MACRO_TOKEN_ADVANCE();
     SCANNER_TOP:
     switch ($tokenType) {
         case T_DOC_COMMENT:
             $this->docComment = $tokenContent;
             goto SCANNER_CONTINUE;
             //goto no break needed
         //goto no break needed
         case T_FINAL:
         case T_ABSTRACT:
         case T_CLASS:
         case T_INTERFACE:
             // CLASS INFORMATION
             $classContext = null;
             $classInterfaceIndex = 0;
             SCANNER_CLASS_INFO_TOP:
             if (is_string($tokens[$tokenIndex + 1]) && $tokens[$tokenIndex + 1] === '{') {
                 goto SCANNER_CLASS_INFO_END;
             }
             $this->lineStart = $tokenLine;
             switch ($tokenType) {
                 case T_FINAL:
                     $this->isFinal = true;
                     goto SCANNER_CLASS_INFO_CONTINUE;
                     //goto no break needed
                 //goto no break needed
                 case T_ABSTRACT:
                     $this->isAbstract = true;
                     goto SCANNER_CLASS_INFO_CONTINUE;
                     //goto no break needed
                 //goto no break needed
                 case T_INTERFACE:
                     $this->isInterface = true;
                     //fall-through
                 //fall-through
                 case T_CLASS:
                     $this->shortName = $tokens[$tokenIndex + 2][1];
                     if ($this->nameInformation && $this->nameInformation->hasNamespace()) {
                         $this->name = $this->nameInformation->getNamespace() . '\\' . $this->shortName;
                     } else {
                         $this->name = $this->shortName;
                     }
                     goto SCANNER_CLASS_INFO_CONTINUE;
                     //goto no break needed
                 //goto no break needed
                 case T_NS_SEPARATOR:
                 case T_STRING:
                     switch ($classContext) {
                         case T_EXTENDS:
                             $this->shortParentClass .= $tokenContent;
                             break;
                         case T_IMPLEMENTS:
                             $this->shortInterfaces[$classInterfaceIndex] .= $tokenContent;
                             break;
                     }
                     goto SCANNER_CLASS_INFO_CONTINUE;
                     //goto no break needed
                 //goto no break needed
                 case T_EXTENDS:
                 case T_IMPLEMENTS:
                     $classContext = $tokenType;
                     if ($this->isInterface && $classContext === T_EXTENDS || $classContext === T_IMPLEMENTS) {
                         $this->shortInterfaces[$classInterfaceIndex] = '';
                     } elseif (!$this->isInterface && $classContext === T_EXTENDS) {
                         $this->shortParentClass = '';
                     }
                     goto SCANNER_CLASS_INFO_CONTINUE;
                     //goto no break needed
                 //goto no break needed
                 case null:
                     if ($classContext == T_IMPLEMENTS && $tokenContent == ',') {
                         $classInterfaceIndex++;
                         $this->shortInterfaces[$classInterfaceIndex] = '';
                     }
             }
             SCANNER_CLASS_INFO_CONTINUE:
             if ($MACRO_TOKEN_ADVANCE() === false) {
                 goto SCANNER_END;
             }
             goto SCANNER_CLASS_INFO_TOP;
             SCANNER_CLASS_INFO_END:
             goto SCANNER_CONTINUE;
     }
     if ($tokenType === null && $tokenContent === '{' && $braceCount === 0) {
         $braceCount++;
         if ($MACRO_TOKEN_ADVANCE() === false) {
             goto SCANNER_END;
         }
         SCANNER_CLASS_BODY_TOP:
         if ($braceCount === 0) {
             goto SCANNER_CLASS_BODY_END;
         }
         switch ($tokenType) {
             case T_CONST:
                 $infos[$infoIndex] = array('type' => 'constant', 'tokenStart' => $tokenIndex, 'tokenEnd' => null, 'lineStart' => $tokenLine, 'lineEnd' => null, 'name' => null, 'value' => null);
                 SCANNER_CLASS_BODY_CONST_TOP:
                 if ($tokenContent === ';') {
                     goto SCANNER_CLASS_BODY_CONST_END;
                 }
                 if ($tokenType === T_STRING && null === $infos[$infoIndex]['name']) {
                     $infos[$infoIndex]['name'] = $tokenContent;
                 }
                 SCANNER_CLASS_BODY_CONST_CONTINUE:
                 if ($MACRO_TOKEN_ADVANCE() === false) {
                     goto SCANNER_END;
                 }
                 goto SCANNER_CLASS_BODY_CONST_TOP;
                 SCANNER_CLASS_BODY_CONST_END:
                 $MACRO_INFO_ADVANCE();
                 goto SCANNER_CLASS_BODY_CONTINUE;
                 //goto no break needed
             //goto no break needed
             case T_DOC_COMMENT:
             case T_PUBLIC:
             case T_PROTECTED:
             case T_PRIVATE:
             case T_ABSTRACT:
             case T_FINAL:
             case T_VAR:
             case T_FUNCTION:
                 $infos[$infoIndex] = array('type' => null, 'tokenStart' => $tokenIndex, 'tokenEnd' => null, 'lineStart' => $tokenLine, 'lineEnd' => null, 'name' => null);
                 $memberContext = null;
                 $methodBodyStarted = false;
                 SCANNER_CLASS_BODY_MEMBER_TOP:
                 if ($memberContext === 'method') {
                     switch ($tokenContent) {
                         case '{':
                             $methodBodyStarted = true;
                             $braceCount++;
                             goto SCANNER_CLASS_BODY_MEMBER_CONTINUE;
                             //goto no break needed
                         //goto no break needed
                         case '}':
                             $braceCount--;
                             goto SCANNER_CLASS_BODY_MEMBER_CONTINUE;
                     }
                 }
                 if ($memberContext !== null) {
                     if ($memberContext === 'property' && $tokenContent === ';' || $memberContext === 'method' && $methodBodyStarted && $braceCount === 1 || $memberContext === 'method' && $this->isInterface && $tokenContent === ';') {
                         goto SCANNER_CLASS_BODY_MEMBER_END;
                     }
                 }
                 switch ($tokenType) {
                     case T_CONST:
                         $memberContext = 'constant';
                         $infos[$infoIndex]['type'] = 'constant';
                         goto SCANNER_CLASS_BODY_CONST_CONTINUE;
                         //goto no break needed
                     //goto no break needed
                     case T_VARIABLE:
                         if ($memberContext === null) {
                             $memberContext = 'property';
                             $infos[$infoIndex]['type'] = 'property';
                             $infos[$infoIndex]['name'] = ltrim($tokenContent, '$');
                         }
                         goto SCANNER_CLASS_BODY_MEMBER_CONTINUE;
                         //goto no break needed
                     //goto no break needed
                     case T_FUNCTION:
                         $memberContext = 'method';
                         $infos[$infoIndex]['type'] = 'method';
                         goto SCANNER_CLASS_BODY_MEMBER_CONTINUE;
                         //goto no break needed
                     //goto no break needed
                     case T_STRING:
                         if ($memberContext === 'method' && null === $infos[$infoIndex]['name']) {
                             $infos[$infoIndex]['name'] = $tokenContent;
                         }
                         goto SCANNER_CLASS_BODY_MEMBER_CONTINUE;
                         //goto no break needed
                 }
                 SCANNER_CLASS_BODY_MEMBER_CONTINUE:
                 if ($MACRO_TOKEN_ADVANCE() === false) {
                     goto SCANNER_END;
                 }
                 goto SCANNER_CLASS_BODY_MEMBER_TOP;
                 SCANNER_CLASS_BODY_MEMBER_END:
                 $memberContext = null;
                 $MACRO_INFO_ADVANCE();
                 goto SCANNER_CLASS_BODY_CONTINUE;
                 //goto no break needed
             //goto no break needed
             case null:
                 // no type, is a string
                 switch ($tokenContent) {
                     case '{':
                         $braceCount++;
                         goto SCANNER_CLASS_BODY_CONTINUE;
                         //fall-through
                     //fall-through
                     case '}':
                         $braceCount--;
                         goto SCANNER_CLASS_BODY_CONTINUE;
                 }
         }
         SCANNER_CLASS_BODY_CONTINUE:
         if ($braceCount === 0 || $MACRO_TOKEN_ADVANCE() === false) {
             goto SCANNER_CONTINUE;
         }
         goto SCANNER_CLASS_BODY_TOP;
         SCANNER_CLASS_BODY_END:
         goto SCANNER_CONTINUE;
     }
     SCANNER_CONTINUE:
     if ($tokenContent === '}') {
         $this->lineEnd = $tokenLine;
     }
     if ($MACRO_TOKEN_ADVANCE() === false) {
         goto SCANNER_END;
     }
     goto SCANNER_TOP;
     SCANNER_END:
     // process short names
     if ($this->nameInformation) {
         if ($this->shortParentClass) {
             $this->parentClass = $this->nameInformation->resolveName($this->shortParentClass);
         }
         if ($this->shortInterfaces) {
             foreach ($this->shortInterfaces as $siIndex => $si) {
                 $this->interfaces[$siIndex] = $this->nameInformation->resolveName($si);
             }
         }
     } else {
         $this->parentClass = $this->shortParentClass;
         $this->interfaces = $this->shortInterfaces;
     }
     $this->isScanned = true;
     return;
 }
 /**
  * Scan tokens
  *
  * @return void
  * @throws Exception\RuntimeException
  */
 protected function scan()
 {
     if ($this->isScanned) {
         return;
     }
     if (!$this->tokens) {
         throw new Exception\RuntimeException('No tokens were provided');
     }
     /**
      * Variables & Setup
      */
     $tokens =& $this->tokens;
     // localize
     $infos =& $this->infos;
     // localize
     $tokenIndex = null;
     $token = null;
     $tokenType = null;
     $tokenContent = null;
     $tokenLine = null;
     $namespace = null;
     $infoIndex = 0;
     $braceCount = 0;
     /*
      * MACRO creation
      */
     $MACRO_TOKEN_ADVANCE = function () use(&$tokens, &$tokenIndex, &$token, &$tokenType, &$tokenContent, &$tokenLine) {
         static $lastTokenArray = null;
         $tokenIndex = $tokenIndex === null ? 0 : $tokenIndex + 1;
         if (!isset($tokens[$tokenIndex])) {
             $token = false;
             $tokenContent = false;
             $tokenType = false;
             $tokenLine = false;
             return false;
         }
         $token = $tokens[$tokenIndex];
         if (is_string($token)) {
             $tokenType = null;
             $tokenContent = $token;
             $tokenLine = $tokenLine + substr_count($lastTokenArray[1], "\n");
             // adjust token line by last known newline count
         } else {
             $lastTokenArray = $token;
             list($tokenType, $tokenContent, $tokenLine) = $token;
         }
         return $tokenIndex;
     };
     $MACRO_INFO_ADVANCE = function () use(&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
         $infos[$infoIndex]['tokenEnd'] = $tokenIndex;
         $infos[$infoIndex]['lineEnd'] = $tokenLine;
         $infoIndex++;
         return $infoIndex;
     };
     /**
      * START FINITE STATE MACHINE FOR SCANNING TOKENS
      */
     // Initialize token
     $MACRO_TOKEN_ADVANCE();
     SCANNER_TOP:
     switch ($tokenType) {
         case T_DOC_COMMENT:
             $this->docComment = $tokenContent;
             goto SCANNER_CONTINUE;
             //goto no break needed
         //goto no break needed
         case T_FINAL:
         case T_ABSTRACT:
         case T_CLASS:
         case T_INTERFACE:
         case T_TRAIT:
             // CLASS INFORMATION
             $classContext = null;
             $classInterfaceIndex = 0;
             SCANNER_CLASS_INFO_TOP:
             if (is_string($tokens[$tokenIndex + 1]) && $tokens[$tokenIndex + 1] === '{') {
                 goto SCANNER_CLASS_INFO_END;
             }
             $this->lineStart = $tokenLine;
             switch ($tokenType) {
                 case T_FINAL:
                     $this->isFinal = true;
                     goto SCANNER_CLASS_INFO_CONTINUE;
                     // goto no break needed
                 // goto no break needed
                 case T_ABSTRACT:
                     $this->isAbstract = true;
                     goto SCANNER_CLASS_INFO_CONTINUE;
                     // goto no break needed
                 // goto no break needed
                 case T_TRAIT:
                     $this->isTrait = true;
                     $this->shortName = $tokens[$tokenIndex + 2][1];
                     if ($this->nameInformation && $this->nameInformation->hasNamespace()) {
                         $this->name = $this->nameInformation->getNamespace() . '\\' . $this->shortName;
                     } else {
                         $this->name = $this->shortName;
                     }
                     goto SCANNER_CLASS_INFO_CONTINUE;
                 case T_INTERFACE:
                     $this->isInterface = true;
                     //fall-through
                 //fall-through
                 case T_CLASS:
                     $this->shortName = $tokens[$tokenIndex + 2][1];
                     if ($this->nameInformation && $this->nameInformation->hasNamespace()) {
                         $this->name = $this->nameInformation->getNamespace() . '\\' . $this->shortName;
                     } else {
                         $this->name = $this->shortName;
                     }
                     goto SCANNER_CLASS_INFO_CONTINUE;
                     //goto no break needed
                 //goto no break needed
                 case T_NS_SEPARATOR:
                 case T_STRING:
                     switch ($classContext) {
                         case T_EXTENDS:
                             $this->shortParentClass .= $tokenContent;
                             break;
                         case T_IMPLEMENTS:
                             $this->shortInterfaces[$classInterfaceIndex] .= $tokenContent;
                             break;
                     }
                     goto SCANNER_CLASS_INFO_CONTINUE;
                     //goto no break needed
                 //goto no break needed
                 case T_EXTENDS:
                 case T_IMPLEMENTS:
                     $classContext = $tokenType;
                     if ($this->isInterface && $classContext === T_EXTENDS || $classContext === T_IMPLEMENTS) {
                         $this->shortInterfaces[$classInterfaceIndex] = '';
                     } elseif (!$this->isInterface && $classContext === T_EXTENDS) {
                         $this->shortParentClass = '';
                     }
                     goto SCANNER_CLASS_INFO_CONTINUE;
                     //goto no break needed
                 //goto no break needed
                 case null:
                     if ($classContext == T_IMPLEMENTS && $tokenContent == ',') {
                         $classInterfaceIndex++;
                         $this->shortInterfaces[$classInterfaceIndex] = '';
                     }
             }
             SCANNER_CLASS_INFO_CONTINUE:
             if ($MACRO_TOKEN_ADVANCE() === false) {
                 goto SCANNER_END;
             }
             goto SCANNER_CLASS_INFO_TOP;
             SCANNER_CLASS_INFO_END:
             goto SCANNER_CONTINUE;
     }
     if ($tokenType === null && $tokenContent === '{' && $braceCount === 0) {
         $braceCount++;
         if ($MACRO_TOKEN_ADVANCE() === false) {
             goto SCANNER_END;
         }
         SCANNER_CLASS_BODY_TOP:
         if ($braceCount === 0) {
             goto SCANNER_CLASS_BODY_END;
         }
         switch ($tokenType) {
             case T_CONST:
                 $infos[$infoIndex] = ['type' => 'constant', 'tokenStart' => $tokenIndex, 'tokenEnd' => null, 'lineStart' => $tokenLine, 'lineEnd' => null, 'name' => null, 'value' => null];
                 SCANNER_CLASS_BODY_CONST_TOP:
                 if ($tokenContent === ';') {
                     goto SCANNER_CLASS_BODY_CONST_END;
                 }
                 if ($tokenType === T_STRING && null === $infos[$infoIndex]['name']) {
                     $infos[$infoIndex]['name'] = $tokenContent;
                 }
                 SCANNER_CLASS_BODY_CONST_CONTINUE:
                 if ($MACRO_TOKEN_ADVANCE() === false) {
                     goto SCANNER_END;
                 }
                 goto SCANNER_CLASS_BODY_CONST_TOP;
                 SCANNER_CLASS_BODY_CONST_END:
                 $MACRO_INFO_ADVANCE();
                 goto SCANNER_CLASS_BODY_CONTINUE;
                 // goto no break needed
             // goto no break needed
             case T_USE:
                 // ensure php backwards compatibility
                 if (!defined('T_INSTEADOF')) {
                     define('T_INSTEADOF', 24000);
                 }
                 $infos[$infoIndex] = ['type' => 'use', 'tokenStart' => $tokenIndex, 'tokenEnd' => null, 'lineStart' => $tokens[$tokenIndex][2], 'lineEnd' => null, 'name' => $namespace, 'use_statements' => [0 => null], 'aliases' => [0 => null]];
                 $isOriginalName = [T_STRING, T_DOUBLE_COLON];
                 $isAlias = [T_STRING];
                 $isVisibility = [T_PRIVATE, T_PROTECTED, T_PUBLIC, T_STATIC];
                 $isAliasType = [T_AS, T_INSTEADOF];
                 $isValidAlias = array_merge($isOriginalName, $isAlias, $isVisibility, $isAliasType);
                 $useStatementIndex = 0;
                 $aliasStatementIndex = 0;
                 $useAliasContext = false;
                 $useAsContext = false;
                 // start processing with next token
                 if ($MACRO_TOKEN_ADVANCE() === false) {
                     goto SCANNER_END;
                 }
                 SCANNER_USE_TOP:
                 if ($tokenType === null) {
                     if ($tokenContent === "{") {
                         $useStatementIndex = 0;
                         $useAliasContext = true;
                         $infos[$infoIndex]['aliases'][$useStatementIndex] = ['original' => null, 'alias' => null, 'visibility' => null, 'type' => 'as'];
                     } elseif ($tokenContent === "}") {
                         $useAliasContext = false;
                         goto SCANNER_USE_END;
                     } elseif ($tokenContent === ';') {
                         if ($useAliasContext === true) {
                             $useStatementIndex++;
                             $useAsContext = false;
                         }
                         // only end if we aren't inside braces
                         if (false === $useAliasContext) {
                             goto SCANNER_USE_END;
                         }
                     } elseif ($tokenContent === ',') {
                         $useStatementIndex++;
                         $infos[$infoIndex]['use_statements'][$useStatementIndex] = '';
                     }
                 }
                 // ANALYZE
                 if ($tokenType !== null) {
                     // use context
                     if (false === $useAliasContext) {
                         if ($tokenType == T_NS_SEPARATOR || $tokenType == T_STRING) {
                             $infos[$infoIndex]['use_statements'][$useStatementIndex] .= $tokenContent;
                         }
                     } else {
                         if (in_array($tokenType, $isValidAlias) && empty($infos[$infoIndex]['aliases'][$useStatementIndex])) {
                             $infos[$infoIndex]['aliases'][$useStatementIndex] = ['original' => null, 'visibility' => null, 'alias' => null, 'type' => null];
                         }
                         if ($tokenType == T_AS || $tokenType == T_INSTEADOF) {
                             $useAsContext = true;
                             $infos[$infoIndex]['aliases'][$useStatementIndex]['type'] = $tokenType == T_INSTEADOF ? 'insteadof' : 'as';
                             goto SCANNER_USE_CONTINUE;
                         }
                         // in alias context
                         if ($useAsContext === true && in_array($tokenType, $isAlias)) {
                             $infos[$infoIndex]['aliases'][$useStatementIndex]['alias'] = $tokenContent;
                         } elseif (in_array($tokenType, $isOriginalName)) {
                             $infos[$infoIndex]['aliases'][$useStatementIndex]['original'] .= $tokenContent;
                         } elseif (in_array($tokenType, $isVisibility)) {
                             //add whitespace (will trim later)
                             $infos[$infoIndex]['aliases'][$useStatementIndex]['visibility'] = $tokenType;
                         }
                     }
                 }
                 SCANNER_USE_CONTINUE:
                 if ($MACRO_TOKEN_ADVANCE() === false) {
                     goto SCANNER_END;
                 }
                 goto SCANNER_USE_TOP;
                 SCANNER_USE_END:
                 $MACRO_INFO_ADVANCE();
                 goto SCANNER_CLASS_BODY_CONTINUE;
             case T_DOC_COMMENT:
             case T_PUBLIC:
             case T_PROTECTED:
             case T_PRIVATE:
             case T_ABSTRACT:
             case T_FINAL:
             case T_VAR:
             case T_FUNCTION:
                 $infos[$infoIndex] = ['type' => null, 'tokenStart' => $tokenIndex, 'tokenEnd' => null, 'lineStart' => $tokenLine, 'lineEnd' => null, 'name' => null];
                 $memberContext = null;
                 $methodBodyStarted = false;
                 SCANNER_CLASS_BODY_MEMBER_TOP:
                 if ($memberContext === 'method') {
                     switch ($tokenContent) {
                         case '{':
                             $methodBodyStarted = true;
                             $braceCount++;
                             goto SCANNER_CLASS_BODY_MEMBER_CONTINUE;
                             // goto no break needed
                         // goto no break needed
                         case '}':
                             $braceCount--;
                             goto SCANNER_CLASS_BODY_MEMBER_CONTINUE;
                         case ';':
                             $infos[$infoIndex]['tokenEnd'] = $tokenIndex;
                             goto SCANNER_CLASS_BODY_MEMBER_CONTINUE;
                     }
                 }
                 if ($memberContext !== null) {
                     if ($memberContext === 'property' && $tokenContent === ';' || $memberContext === 'method' && $methodBodyStarted && $braceCount === 1 || $memberContext === 'method' && $this->isInterface && $tokenContent === ';') {
                         goto SCANNER_CLASS_BODY_MEMBER_END;
                     }
                 }
                 switch ($tokenType) {
                     case T_CONST:
                         $memberContext = 'constant';
                         $infos[$infoIndex]['type'] = 'constant';
                         goto SCANNER_CLASS_BODY_CONST_CONTINUE;
                         //goto no break needed
                     //goto no break needed
                     case T_VARIABLE:
                         if ($memberContext === null) {
                             $memberContext = 'property';
                             $infos[$infoIndex]['type'] = 'property';
                             $infos[$infoIndex]['name'] = ltrim($tokenContent, '$');
                         }
                         goto SCANNER_CLASS_BODY_MEMBER_CONTINUE;
                         // goto no break needed
                     // goto no break needed
                     case T_FUNCTION:
                         $memberContext = 'method';
                         $infos[$infoIndex]['type'] = 'method';
                         goto SCANNER_CLASS_BODY_MEMBER_CONTINUE;
                         // goto no break needed
                     // goto no break needed
                     case T_STRING:
                         if ($memberContext === 'method' && null === $infos[$infoIndex]['name']) {
                             $infos[$infoIndex]['name'] = $tokenContent;
                         }
                         goto SCANNER_CLASS_BODY_MEMBER_CONTINUE;
                         // goto no break needed
                 }
                 SCANNER_CLASS_BODY_MEMBER_CONTINUE:
                 if ($MACRO_TOKEN_ADVANCE() === false) {
                     goto SCANNER_END;
                 }
                 goto SCANNER_CLASS_BODY_MEMBER_TOP;
                 SCANNER_CLASS_BODY_MEMBER_END:
                 $memberContext = null;
                 $MACRO_INFO_ADVANCE();
                 goto SCANNER_CLASS_BODY_CONTINUE;
                 // goto no break needed
             // goto no break needed
             case null:
                 // no type, is a string
                 switch ($tokenContent) {
                     case '{':
                         $braceCount++;
                         goto SCANNER_CLASS_BODY_CONTINUE;
                         // goto no break needed
                     // goto no break needed
                     case '}':
                         $braceCount--;
                         goto SCANNER_CLASS_BODY_CONTINUE;
                 }
         }
         SCANNER_CLASS_BODY_CONTINUE:
         if ($braceCount === 0 || $MACRO_TOKEN_ADVANCE() === false) {
             goto SCANNER_CONTINUE;
         }
         goto SCANNER_CLASS_BODY_TOP;
         SCANNER_CLASS_BODY_END:
         goto SCANNER_CONTINUE;
     }
     SCANNER_CONTINUE:
     if ($tokenContent === '}') {
         $this->lineEnd = $tokenLine;
     }
     if ($MACRO_TOKEN_ADVANCE() === false) {
         goto SCANNER_END;
     }
     goto SCANNER_TOP;
     SCANNER_END:
     // process short names
     if ($this->nameInformation) {
         if ($this->shortParentClass) {
             $this->parentClass = $this->nameInformation->resolveName($this->shortParentClass);
         }
         if ($this->shortInterfaces) {
             foreach ($this->shortInterfaces as $siIndex => $si) {
                 $this->interfaces[$siIndex] = $this->nameInformation->resolveName($si);
             }
         }
     } else {
         $this->parentClass = $this->shortParentClass;
         $this->interfaces = $this->shortInterfaces;
     }
     $this->isScanned = true;
     return;
 }