/**
  * Parses the token substream and prepares namespace reflections from the file.
  *
  * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
  * @param \TokenReflection\IReflection       $parent      Parent reflection object
  *
  * @return \TokenReflection\ReflectionFile
  */
 protected function parseStream(Stream $tokenStream, IReflection $parent = null)
 {
     $this->name = $tokenStream->getFileName();
     if (1 >= $tokenStream->count()) {
         // No PHP content
         $this->docComment = new ReflectionAnnotation($this, null);
         return $this;
     }
     $docCommentPosition = null;
     if (!$tokenStream->is(T_OPEN_TAG)) {
         $this->namespaces[] = new ReflectionFileNamespace($tokenStream, $this->broker, $this);
     } else {
         $tokenStream->skipWhitespaces();
         while (null !== ($type = $tokenStream->getType())) {
             switch ($type) {
                 case T_DOC_COMMENT:
                     if (null === $docCommentPosition) {
                         $docCommentPosition = $tokenStream->key();
                     }
                 case T_WHITESPACE:
                 case T_COMMENT:
                     break;
                 case T_DECLARE:
                     // Intentionally twice call of skipWhitespaces()
                     $tokenStream->skipWhitespaces()->findMatchingBracket()->skipWhitespaces()->skipWhitespaces();
                     break;
                 case T_NAMESPACE:
                     $docCommentPosition = $docCommentPosition ?: -1;
                     break 2;
                 default:
                     $docCommentPosition = $docCommentPosition ?: -1;
                     $this->namespaces[] = new ReflectionFileNamespace($tokenStream, $this->broker, $this);
                     break 2;
             }
             $tokenStream->skipWhitespaces();
         }
         while (null !== ($type = $tokenStream->getType())) {
             if (T_NAMESPACE === $type) {
                 $this->namespaces[] = new ReflectionFileNamespace($tokenStream, $this->broker, $this);
             } else {
                 $tokenStream->skipWhitespaces();
             }
         }
     }
     if (null !== $docCommentPosition && !empty($this->namespaces) && $docCommentPosition === $this->namespaces[0]->getStartPosition()) {
         $docCommentPosition = null;
     }
     $this->docComment = new ReflectionAnnotation($this, null !== $docCommentPosition ? $tokenStream->getTokenValue($docCommentPosition) : null);
     return $this;
 }
 /**
  * Constructor.
  *
  * Creates a token substream from a file.
  *
  * @param string $fileName File name
  * @throws \TokenReflection\Exception\StreamException If the file does not exist or is not readable.
  */
 public function __construct($fileName)
 {
     parent::__construct();
     $this->fileName = Broker::getRealPath($fileName);
     if (false === $this->fileName) {
         throw new Exception\StreamException($this, 'File does not exist.', Exception\StreamException::DOES_NOT_EXIST);
     }
     $contents = @file_get_contents($this->fileName);
     if (false === $contents) {
         throw new Exception\StreamException($this, 'File is not readable.', Exception\StreamException::NOT_READABLE);
     }
     $this->processSource($contents);
 }
 /**
  * Parses base method modifiers (abstract, final, public, ...).
  *
  * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
  *
  * @return \TokenReflection\ReflectionMethod
  */
 private function parseBaseModifiers(Stream $tokenStream)
 {
     while (true) {
         switch ($tokenStream->getType()) {
             case T_ABSTRACT:
                 $this->modifiers |= InternalReflectionMethod::IS_ABSTRACT;
                 break;
             case T_FINAL:
                 $this->modifiers |= InternalReflectionMethod::IS_FINAL;
                 break;
             case T_PUBLIC:
                 $this->modifiers |= InternalReflectionMethod::IS_PUBLIC;
                 break;
             case T_PRIVATE:
                 $this->modifiers |= InternalReflectionMethod::IS_PRIVATE;
                 break;
             case T_PROTECTED:
                 $this->modifiers |= InternalReflectionMethod::IS_PROTECTED;
                 break;
             case T_STATIC:
                 $this->modifiers |= InternalReflectionMethod::IS_STATIC;
                 break;
             case T_FUNCTION:
             case null:
                 break 2;
             default:
                 break;
         }
         $tokenStream->skipWhitespaces();
     }
     if (!($this->modifiers & (InternalReflectionMethod::IS_PRIVATE | InternalReflectionMethod::IS_PROTECTED))) {
         $this->modifiers |= InternalReflectionMethod::IS_PUBLIC;
     }
     return $this;
 }
Example #4
0
 /**
  * Parses child reflection objects from the token stream.
  *
  * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
  * @param \TokenReflection\IReflection $parent Parent reflection object
  * @return \TokenReflection\ReflectionClass
  * @throws \TokenReflection\Exception\ParseException If a parse error was detected.
  */
 protected function parseChildren(Stream $tokenStream, IReflection $parent)
 {
     while (true) {
         switch ($type = $tokenStream->getType()) {
             case null:
                 break 2;
             case T_COMMENT:
             case T_DOC_COMMENT:
                 $docblock = $tokenStream->getTokenValue();
                 if (preg_match('~^' . preg_quote(self::DOCBLOCK_TEMPLATE_START, '~') . '~', $docblock)) {
                     array_unshift($this->docblockTemplates, new ReflectionAnnotation($this, $docblock));
                 } elseif (self::DOCBLOCK_TEMPLATE_END === $docblock) {
                     array_shift($this->docblockTemplates);
                 }
                 $tokenStream->next();
                 break;
             case '}':
                 break 2;
             case T_PUBLIC:
             case T_PRIVATE:
             case T_PROTECTED:
             case T_STATIC:
             case T_VAR:
             case T_VARIABLE:
                 static $searching = array(T_VARIABLE => true, T_FUNCTION => true);
                 if (T_VAR !== $tokenStream->getType()) {
                     $position = $tokenStream->key();
                     while (null !== ($type = $tokenStream->getType($position)) && !isset($searching[$type])) {
                         $position++;
                     }
                 }
                 if (T_VARIABLE === $type || T_VAR === $type) {
                     $property = new ReflectionProperty($tokenStream, $this->getBroker(), $this);
                     $this->properties[$property->getName()] = $property;
                     $tokenStream->next();
                     break;
                 }
                 // Break missing on purpose
             // Break missing on purpose
             case T_FINAL:
             case T_ABSTRACT:
             case T_FUNCTION:
                 $method = new ReflectionMethod($tokenStream, $this->getBroker(), $this);
                 $this->methods[$method->getName()] = $method;
                 $tokenStream->next();
                 break;
             case T_CONST:
                 $tokenStream->skipWhitespaces(true);
                 while ($tokenStream->is(T_STRING)) {
                     $constant = new ReflectionConstant($tokenStream, $this->getBroker(), $this);
                     $this->constants[$constant->getName()] = $constant;
                     if ($tokenStream->is(',')) {
                         $tokenStream->skipWhitespaces(true);
                     } else {
                         $tokenStream->next();
                     }
                 }
                 break;
             case T_USE:
                 $tokenStream->skipWhitespaces(true);
                 while (true) {
                     $traitName = '';
                     $type = $tokenStream->getType();
                     while (T_STRING === $type || T_NS_SEPARATOR === $type) {
                         $traitName .= $tokenStream->getTokenValue();
                         $type = $tokenStream->skipWhitespaces(true)->getType();
                     }
                     if ('' === trim($traitName, '\\')) {
                         throw new Exception\ParseException($this, $tokenStream, 'An empty trait name found.', Exception\ParseException::LOGICAL_ERROR);
                     }
                     $this->traits[] = Resolver::resolveClassFQN($traitName, $this->aliases, $this->namespaceName);
                     if (';' === $type) {
                         // End of "use"
                         $tokenStream->skipWhitespaces();
                         break;
                     } elseif (',' === $type) {
                         // Next trait name follows
                         $tokenStream->skipWhitespaces();
                         continue;
                     } elseif ('{' !== $type) {
                         // Unexpected token
                         throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found: "%s".', Exception\ParseException::UNEXPECTED_TOKEN);
                     }
                     // Aliases definition
                     $type = $tokenStream->skipWhitespaces(true)->getType();
                     while (true) {
                         if ('}' === $type) {
                             $tokenStream->skipWhitespaces();
                             break 2;
                         }
                         $leftSide = '';
                         $rightSide = array('', null);
                         $alias = true;
                         while (T_STRING === $type || T_NS_SEPARATOR === $type || T_DOUBLE_COLON === $type) {
                             $leftSide .= $tokenStream->getTokenValue();
                             $type = $tokenStream->skipWhitespaces(true)->getType();
                         }
                         if (T_INSTEADOF === $type) {
                             $alias = false;
                         } elseif (T_AS !== $type) {
                             throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN);
                         }
                         $type = $tokenStream->skipWhitespaces(true)->getType();
                         if (T_PUBLIC === $type || T_PROTECTED === $type || T_PRIVATE === $type) {
                             if (!$alias) {
                                 throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN);
                             }
                             switch ($type) {
                                 case T_PUBLIC:
                                     $type = InternalReflectionMethod::IS_PUBLIC;
                                     break;
                                 case T_PROTECTED:
                                     $type = InternalReflectionMethod::IS_PROTECTED;
                                     break;
                                 case T_PRIVATE:
                                     $type = InternalReflectionMethod::IS_PRIVATE;
                                     break;
                                 default:
                                     break;
                             }
                             $rightSide[1] = $type;
                             $type = $tokenStream->skipWhitespaces(true)->getType();
                         }
                         while (T_STRING === $type || T_NS_SEPARATOR === $type && !$alias) {
                             $rightSide[0] .= $tokenStream->getTokenValue();
                             $type = $tokenStream->skipWhitespaces(true)->getType();
                         }
                         if (empty($leftSide)) {
                             throw new Exception\ParseException($this, $tokenStream, 'An empty method name was found.', Exception\ParseException::LOGICAL_ERROR);
                         }
                         if ($alias) {
                             // Alias
                             if ($pos = strpos($leftSide, '::')) {
                                 $methodName = substr($leftSide, $pos + 2);
                                 $className = Resolver::resolveClassFQN(substr($leftSide, 0, $pos), $this->aliases, $this->namespaceName);
                                 $leftSide = $className . '::' . $methodName;
                                 $this->traitAliases[$rightSide[0]] = $leftSide;
                             } else {
                                 $this->traitAliases[$rightSide[0]] = '(null)::' . $leftSide;
                             }
                             $this->traitImports[$leftSide][] = $rightSide;
                         } else {
                             // Insteadof
                             if ($pos = strpos($leftSide, '::')) {
                                 $methodName = substr($leftSide, $pos + 2);
                             } else {
                                 throw new Exception\ParseException($this, $tokenStream, 'A T_DOUBLE_COLON has to be present when using T_INSTEADOF.', Exception\ParseException::UNEXPECTED_TOKEN);
                             }
                             $this->traitImports[Resolver::resolveClassFQN($rightSide[0], $this->aliases, $this->namespaceName) . '::' . $methodName][] = null;
                         }
                         if (',' === $type) {
                             $tokenStream->skipWhitespaces(true);
                             continue;
                         } elseif (';' !== $type) {
                             throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN);
                         }
                         $type = $tokenStream->skipWhitespaces()->getType();
                     }
                 }
                 break;
             default:
                 $tokenStream->next();
                 break;
         }
     }
     return $this;
 }
 /**
  * Parses the parameter default value.
  *
  * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
  * @return \TokenReflection\ReflectionParameter
  * @throws \TokenReflection\Exception\ParseException If the default value could not be determined.
  */
 private function parseDefaultValue(Stream $tokenStream)
 {
     if ($tokenStream->is('=')) {
         $tokenStream->skipWhitespaces(true);
         $level = 0;
         while (null !== ($type = $tokenStream->getType())) {
             switch ($type) {
                 case ')':
                     if (0 === $level) {
                         break 2;
                     }
                 case '}':
                 case ']':
                     $level--;
                     break;
                 case '(':
                 case '{':
                 case '[':
                     $level++;
                     break;
                 case ',':
                     if (0 === $level) {
                         break 2;
                     }
                     break;
                 default:
                     break;
             }
             $this->defaultValueDefinition[] = $tokenStream->current();
             $tokenStream->next();
         }
         if (')' !== $type && ',' !== $type) {
             throw new Exception\ParseException($this, $tokenStream, 'The property default value is not terminated properly. Expected "," or ")".', Exception\ParseException::UNEXPECTED_TOKEN);
         }
     }
     return $this;
 }
 /**
  * Parses function/method parameters.
  *
  * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
  *
  * @return \TokenReflection\ReflectionFunctionBase
  * @throws \TokenReflection\Exception\ParseException If parameters could not be parsed.
  */
 protected final function parseParameters(Stream $tokenStream)
 {
     if (!$tokenStream->is('(')) {
         throw new Exception\ParseException($this, $tokenStream, 'Could find the start token.', Exception\ParseException::UNEXPECTED_TOKEN);
     }
     static $accepted = array(T_NS_SEPARATOR => true, T_STRING => true, T_ARRAY => true, T_CALLABLE => true, T_VARIABLE => true, '&' => true);
     $tokenStream->skipWhitespaces(true);
     while (null !== ($type = $tokenStream->getType()) && ')' !== $type) {
         if (isset($accepted[$type])) {
             $parameter = new ReflectionParameter($tokenStream, $this->getBroker(), $this);
             $this->parameters[] = $parameter;
         }
         if ($tokenStream->is(')')) {
             break;
         }
         $tokenStream->skipWhitespaces(true);
     }
     $tokenStream->skipWhitespaces();
     return $this;
 }
 /**
  * Parses child reflection objects from the token stream.
  *
  * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
  * @param \TokenReflection\IReflection $parent Parent reflection object
  * @return \TokenReflection\ReflectionFileNamespace
  * @throws \TokenReflection\Exception\ParseException If child elements could not be parsed.
  */
 protected function parseChildren(Stream $tokenStream, IReflection $parent)
 {
     static $skipped = array(T_WHITESPACE => true, T_COMMENT => true, T_DOC_COMMENT => true);
     $depth = 0;
     $firstChild = null;
     while (true) {
         switch ($tokenStream->getType()) {
             case T_USE:
                 while (true) {
                     $namespaceName = '';
                     $alias = null;
                     $tokenStream->skipWhitespaces(true);
                     while (true) {
                         switch ($tokenStream->getType()) {
                             case T_STRING:
                             case T_NS_SEPARATOR:
                                 $namespaceName .= $tokenStream->getTokenValue();
                                 break;
                             case T_FUNCTION:
                                 // "use function" in 5.6+
                                 break;
                             default:
                                 break 2;
                         }
                         $tokenStream->skipWhitespaces(true);
                     }
                     $namespaceName = ltrim($namespaceName, '\\');
                     if (empty($namespaceName)) {
                         throw new Exception\ParseException($this, $tokenStream, 'Imported namespace name could not be determined.', Exception\ParseException::LOGICAL_ERROR);
                     } elseif ('\\' === substr($namespaceName, -1)) {
                         throw new Exception\ParseException($this, $tokenStream, sprintf('Invalid namespace name "%s".', $namespaceName), Exception\ParseException::LOGICAL_ERROR);
                     }
                     if ($tokenStream->is(T_AS)) {
                         // Alias defined
                         $tokenStream->skipWhitespaces(true);
                         if (!$tokenStream->is(T_STRING)) {
                             throw new Exception\ParseException($this, $tokenStream, sprintf('The imported namespace "%s" seems aliased but the alias name could not be determined.', $namespaceName), Exception\ParseException::LOGICAL_ERROR);
                         }
                         $alias = $tokenStream->getTokenValue();
                         $tokenStream->skipWhitespaces(true);
                     } else {
                         // No explicit alias
                         if (false !== ($pos = strrpos($namespaceName, '\\'))) {
                             $alias = substr($namespaceName, $pos + 1);
                         } else {
                             $alias = $namespaceName;
                         }
                     }
                     if (isset($this->aliases[$alias])) {
                         throw new Exception\ParseException($this, $tokenStream, sprintf('Namespace alias "%s" already defined.', $alias), Exception\ParseException::LOGICAL_ERROR);
                     }
                     $this->aliases[$alias] = $namespaceName;
                     $type = $tokenStream->getType();
                     if (';' === $type) {
                         $tokenStream->skipWhitespaces();
                         break 2;
                     } elseif (',' === $type) {
                         // Next namespace in the current "use" definition
                         continue;
                     }
                     throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN);
                 }
             case T_COMMENT:
             case T_DOC_COMMENT:
                 $docblock = $tokenStream->getTokenValue();
                 if (preg_match('~^' . preg_quote(self::DOCBLOCK_TEMPLATE_START, '~') . '~', $docblock)) {
                     array_unshift($this->docblockTemplates, new ReflectionAnnotation($this, $docblock));
                 } elseif (self::DOCBLOCK_TEMPLATE_END === $docblock) {
                     array_shift($this->docblockTemplates);
                 }
                 $tokenStream->next();
                 break;
             case '{':
                 $tokenStream->next();
                 $depth++;
                 break;
             case '}':
                 if (0 === $depth--) {
                     break 2;
                 }
                 $tokenStream->next();
                 break;
             case null:
             case T_NAMESPACE:
                 break 2;
             case T_ABSTRACT:
             case T_FINAL:
             case T_CLASS:
             case T_TRAIT:
             case T_INTERFACE:
                 $class = new ReflectionClass($tokenStream, $this->getBroker(), $this);
                 $firstChild = $firstChild ?: $class;
                 $className = $class->getName();
                 if (isset($this->classes[$className])) {
                     if (!$this->classes[$className] instanceof Invalid\ReflectionClass) {
                         $this->classes[$className] = new Invalid\ReflectionClass($className, $this->classes[$className]->getFileName(), $this->getBroker());
                     }
                     if (!$this->classes[$className]->hasReasons()) {
                         $this->classes[$className]->addReason(new Exception\ParseException($this, $tokenStream, sprintf('Class %s is defined multiple times in the file.', $className), Exception\ParseException::ALREADY_EXISTS));
                     }
                 } else {
                     $this->classes[$className] = $class;
                 }
                 $tokenStream->next();
                 break;
             case T_CONST:
                 $tokenStream->skipWhitespaces(true);
                 do {
                     $constant = new ReflectionConstant($tokenStream, $this->getBroker(), $this);
                     $firstChild = $firstChild ?: $constant;
                     $constantName = $constant->getName();
                     if (isset($this->constants[$constantName])) {
                         if (!$this->constants[$constantName] instanceof Invalid\ReflectionConstant) {
                             $this->constants[$constantName] = new Invalid\ReflectionConstant($constantName, $this->constants[$constantName]->getFileName(), $this->getBroker());
                         }
                         if (!$this->constants[$constantName]->hasReasons()) {
                             $this->constants[$constantName]->addReason(new Exception\ParseException($this, $tokenStream, sprintf('Constant %s is defined multiple times in the file.', $constantName), Exception\ParseException::ALREADY_EXISTS));
                         }
                     } else {
                         $this->constants[$constantName] = $constant;
                     }
                     if ($tokenStream->is(',')) {
                         $tokenStream->skipWhitespaces(true);
                     } else {
                         $tokenStream->next();
                     }
                 } while ($tokenStream->is(T_STRING));
                 break;
             case T_STRING:
                 switch ($tokenStream->getTokenValue()) {
                     case 'define':
                         // definition case
                     // definition case
                     default:
                         break;
                 }
                 $tokenStream->next();
                 break;
             case T_FUNCTION:
                 $position = $tokenStream->key() + 1;
                 while (isset($skipped[$type = $tokenStream->getType($position)])) {
                     $position++;
                 }
                 if ('(' === $type) {
                     // Skipping anonymous functions
                     $tokenStream->seek($position)->findMatchingBracket()->skipWhiteSpaces(true);
                     if ($tokenStream->is(T_USE)) {
                         $tokenStream->skipWhitespaces(true)->findMatchingBracket()->skipWhitespaces(true);
                     }
                     $tokenStream->findMatchingBracket()->next();
                     continue;
                 }
                 $function = new ReflectionFunction($tokenStream, $this->getBroker(), $this);
                 $firstChild = $firstChild ?: $function;
                 $functionName = $function->getName();
                 if (isset($this->functions[$functionName])) {
                     if (!$this->functions[$functionName] instanceof Invalid\ReflectionFunction) {
                         $this->functions[$functionName] = new Invalid\ReflectionFunction($functionName, $this->functions[$functionName]->getFileName(), $this->getBroker());
                     }
                     if (!$this->functions[$functionName]->hasReasons()) {
                         $this->functions[$functionName]->addReason(new Exception\ParseException($this, $tokenStream, sprintf('Function %s is defined multiple times in the file.', $functionName), Exception\ParseException::ALREADY_EXISTS));
                     }
                 } else {
                     $this->functions[$functionName] = $function;
                 }
                 $tokenStream->next();
                 break;
             default:
                 $tokenStream->next();
                 break;
         }
     }
     if ($firstChild) {
         $this->startPosition = min($this->startPosition, $firstChild->getStartPosition());
     }
     return $this;
 }
 /**
  * Saves the end line number.
  *
  * @param \TokenReflection\Stream\StreamBase $tokenStream Token susbtream
  * @return \TokenReflection\ReflectionElement
  */
 private final function parseEndLine(Stream $tokenStream)
 {
     $token = $tokenStream->current();
     $this->endLine = $token[2];
     $this->endPosition = $tokenStream->key();
     return $this;
 }
 /**
  * Returns the processed file name.
  *
  * @return string
  */
 public function getFileName()
 {
     return $this->stream->getFileName();
 }
 /**
  * Parses static variables.
  *
  * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
  * @return \TokenReflection\ReflectionFunctionBase
  * @throws \TokenReflection\Exception\ParseException If static variables could not be parsed.
  */
 protected final function parseStaticVariables(Stream $tokenStream)
 {
     $type = $tokenStream->getType();
     if ('{' === $type) {
         if ($this->getBroker()->isOptionSet(Broker::OPTION_PARSE_FUNCTION_BODY)) {
             $tokenStream->skipWhitespaces(true);
             while ('}' !== ($type = $tokenStream->getType())) {
                 switch ($type) {
                     case T_STATIC:
                         $type = $tokenStream->skipWhitespaces(true)->getType();
                         if (T_VARIABLE !== $type) {
                             // Late static binding
                             break;
                         }
                         while (T_VARIABLE === $type) {
                             $variableName = $tokenStream->getTokenValue();
                             $variableDefinition = array();
                             $type = $tokenStream->skipWhitespaces(true)->getType();
                             if ('=' === $type) {
                                 $type = $tokenStream->skipWhitespaces(true)->getType();
                                 $level = 0;
                                 while ($tokenStream->valid()) {
                                     switch ($type) {
                                         case '(':
                                         case '[':
                                         case '{':
                                         case T_CURLY_OPEN:
                                         case T_DOLLAR_OPEN_CURLY_BRACES:
                                             $level++;
                                             break;
                                         case ')':
                                         case ']':
                                         case '}':
                                             $level--;
                                             break;
                                         case ';':
                                         case ',':
                                             if (0 === $level) {
                                                 break 2;
                                             }
                                         default:
                                             break;
                                     }
                                     $variableDefinition[] = $tokenStream->current();
                                     $type = $tokenStream->skipWhitespaces(true)->getType();
                                 }
                                 if (!$tokenStream->valid()) {
                                     throw new Exception\ParseException($this, $tokenStream, 'Invalid end of token stream.', Exception\ParseException::READ_BEYOND_EOS);
                                 }
                             }
                             $this->staticVariablesDefinition[substr($variableName, 1)] = $variableDefinition;
                             if (',' === $type) {
                                 $type = $tokenStream->skipWhitespaces(true)->getType();
                             } else {
                                 break;
                             }
                         }
                         break;
                     case T_FUNCTION:
                         // Anonymous function -> skip to its end
                         if (!$tokenStream->find('{')) {
                             throw new Exception\ParseException($this, $tokenStream, 'Could not find beginning of the anonymous function.', Exception\ParseException::UNEXPECTED_TOKEN);
                         }
                         // Break missing intentionally
                     // Break missing intentionally
                     case '{':
                     case '[':
                     case '(':
                     case T_CURLY_OPEN:
                     case T_DOLLAR_OPEN_CURLY_BRACES:
                         $tokenStream->findMatchingBracket()->skipWhitespaces(true);
                         break;
                     default:
                         $tokenStream->skipWhitespaces();
                         break;
                 }
             }
         } else {
             $tokenStream->findMatchingBracket();
         }
     } elseif (';' !== $type) {
         throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN);
     }
     return $this;
 }
 /**
  * Parses the constant value.
  *
  * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
  * @param \TokenReflection\IReflection $parent Parent reflection object
  * @return \TokenReflection\ReflectionConstant
  * @throws \TokenReflection\Exception\ParseException If the constant value could not be determined.
  */
 private function parseValue(Stream $tokenStream, IReflection $parent)
 {
     if (!$tokenStream->is('=')) {
         throw new Exception\ParseException($this, $tokenStream, 'Could not find the definition start.', Exception\ParseException::UNEXPECTED_TOKEN);
     }
     $tokenStream->skipWhitespaces(true);
     static $acceptedTokens = array('-' => true, '+' => true, T_STRING => true, T_NS_SEPARATOR => true, T_CONSTANT_ENCAPSED_STRING => true, T_DNUMBER => true, T_LNUMBER => true, T_DOUBLE_COLON => true, T_CLASS_C => true, T_DIR => true, T_FILE => true, T_FUNC_C => true, T_LINE => true, T_METHOD_C => true, T_NS_C => true, T_TRAIT_C => true);
     while (null !== ($type = $tokenStream->getType())) {
         if (T_START_HEREDOC === $type) {
             $this->valueDefinition[] = $tokenStream->current();
             while (null !== $type && T_END_HEREDOC !== $type) {
                 $tokenStream->next();
                 $this->valueDefinition[] = $tokenStream->current();
                 $type = $tokenStream->getType();
             }
             $tokenStream->next();
         } elseif (isset($acceptedTokens[$type])) {
             $this->valueDefinition[] = $tokenStream->current();
             $tokenStream->next();
         } elseif ($tokenStream->isWhitespace(true)) {
             $tokenStream->skipWhitespaces(true);
         } else {
             break;
         }
     }
     if (empty($this->valueDefinition)) {
         throw new Exception\ParseException($this, $tokenStream, 'Value definition is empty.', Exception\ParseException::LOGICAL_ERROR);
     }
     $value = $tokenStream->getTokenValue();
     if (null === $type || ',' !== $value && ';' !== $value) {
         throw new Exception\ParseException($this, $tokenStream, 'Invalid value definition.', Exception\ParseException::LOGICAL_ERROR);
     }
     return $this;
 }
 /**
  * Parses the type hint.
  *
  * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
  *
  * @return \TokenReflection\ReflectionParameter
  * @throws \TokenReflection\Exception\ParseException If the type hint class name could not be determined.
  */
 private function parseTypeHint(Stream $tokenStream)
 {
     $type = $tokenStream->getType();
     if (T_ARRAY === $type) {
         $this->typeHint = self::ARRAY_TYPE_HINT;
         $this->originalTypeHint = self::ARRAY_TYPE_HINT;
         $tokenStream->skipWhitespaces(true);
     } elseif (T_CALLABLE === $type) {
         $this->typeHint = self::CALLABLE_TYPE_HINT;
         $this->originalTypeHint = self::CALLABLE_TYPE_HINT;
         $tokenStream->skipWhitespaces(true);
     } elseif (T_STRING === $type || T_NS_SEPARATOR === $type) {
         $className = '';
         do {
             $className .= $tokenStream->getTokenValue();
             $tokenStream->skipWhitespaces(true);
             $type = $tokenStream->getType();
         } while (T_STRING === $type || T_NS_SEPARATOR === $type);
         if ('' === ltrim($className, '\\')) {
             throw new Exception\ParseException($this, $tokenStream, sprintf('Invalid class name definition: "%s".', $className), Exception\ParseException::LOGICAL_ERROR);
         }
         $this->originalTypeHint = $className;
     }
     return $this;
 }
 /**
  * Parses the property name.
  *
  * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
  *
  * @return \TokenReflection\ReflectionProperty
  * @throws \TokenReflection\Exception\ParseException If the property name could not be determined.
  */
 protected function parseName(Stream $tokenStream)
 {
     if (!$tokenStream->is(T_VARIABLE)) {
         throw new Exception\ParseException($this, $tokenStream, 'The property name could not be determined.', Exception\ParseException::LOGICAL_ERROR);
     }
     $this->name = substr($tokenStream->getTokenValue(), 1);
     $tokenStream->skipWhitespaces(true);
     return $this;
 }
 /**
  * Parses the constant name.
  *
  * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
  *
  * @return \TokenReflection\ReflectionConstant
  * @throws \TokenReflection\Exception\ParseReflection If the constant name could not be determined.
  */
 protected function parseName(Stream $tokenStream)
 {
     if (!$tokenStream->is(T_STRING)) {
         throw new Exception\ParseException($this, $tokenStream, 'The constant name could not be determined.', Exception\ParseException::LOGICAL_ERROR);
     }
     if (null === $this->namespaceName || $this->namespaceName === ReflectionNamespace::NO_NAMESPACE_NAME) {
         $this->name = $tokenStream->getTokenValue();
     } else {
         $this->name = $this->namespaceName . '\\' . $tokenStream->getTokenValue();
     }
     $tokenStream->skipWhitespaces(true);
     return $this;
 }