Пример #1
0
 /**
  * Parse the operand.
  *
  * @param Grammar $grammar The grammar of the parser.
  * @param TokenStream $stream The token stream to parse.
  * @return OperandNode The operand node.
  */
 public function parse(Grammar $grammar, TokenStream $stream)
 {
     /* @var \com\mohiva\pyramid\Token $token */
     $token = $stream->current();
     $node = new OperandNode($token->getValue());
     return $node;
 }
Пример #2
0
 /**
  * Test if the parse method returns the `OperandNode` with the correct number.
  */
 public function testParseReturnsNodeWithCorrectNumber()
 {
     $number = mt_rand(1, 100);
     $tokenStream = new TokenStream();
     $tokenStream->push(new Token(Lexer::T_NUMBER, $number, 1));
     $tokenStream->rewind();
     $operand = new NumberOperand();
     $node = $operand->parse(new Grammar(), $tokenStream);
     $this->assertSame($number, $node->evaluate());
 }
Пример #3
0
 /**
  * Create an array from the token stream which contains only the tokens and the operators/values.
  *
  * @param TokenStream $stream The stream containing the lexer tokens.
  * @return array The actual list with tokens and operators/values.
  */
 private function buildActualTokens(TokenStream $stream)
 {
     $actual = array();
     while ($stream->valid()) {
         /* @var \com\mohiva\pyramid\Token $current */
         $current = $stream->current();
         $stream->next();
         $actual[] = array($current->getCode() => $current->getValue());
     }
     return $actual;
 }
Пример #4
0
 /**
  * Test if the `parse` method throws an exception if the closing parentheses is missing
  * and the end of the stream is reached.
  *
  * @expectedException \com\mohiva\common\exceptions\SyntaxErrorException
  */
 public function testParseThrowsExceptionIfEndOfStreamIsReached()
 {
     $tokenStream = new TokenStream();
     $tokenStream->push(new Token(Lexer::T_OPEN_PARENTHESIS, '(', 1));
     $tokenStream->push(new Token(Lexer::T_NUMBER, 100, 1));
     $tokenStream->rewind();
     $grammar = new Grammar();
     $grammar->addOperand(new NumberOperand());
     $operand = new ParenthesesOperand();
     $operand->parse($grammar, $tokenStream);
 }
Пример #5
0
 /**
  * Parse the operand.
  *
  * This example shows how you should parse sub expressions. You must only create a
  * new parser with the passed grammar and token stream.
  *
  * @param Grammar $grammar The grammar of the parser.
  * @param TokenStream $stream The token stream to parse.
  * @return Node The node between the parentheses.
  * @throws SyntaxErrorException if an unexpected token was found.
  */
 public function parse(Grammar $grammar, TokenStream $stream)
 {
     $stream->next();
     $parser = new Parser($grammar);
     $node = $parser->parse($stream);
     $stream->expect(array(Lexer::T_CLOSE_PARENTHESIS), function (Token $current = null) {
         if ($current) {
             $message = "Expected `)`; got `{$current->getValue()}`";
         } else {
             $message = "Expected `)` but end of stream reached";
         }
         throw new SyntaxErrorException($message);
     });
     return $node;
 }
Пример #6
0
 /**
  * Parse the operand.
  *
  * @return Node The node object for the operand.
  * @throws SyntaxErrorException if no operand parser can be found for
  * the current token.
  */
 private function parseOperand()
 {
     /* @var Token $token */
     $token = $this->stream->current();
     try {
         /* @var Operand $operand */
         $operand = $this->operandTable->getOperand($token);
     } catch (InvalidIdentifierException $e) {
         $message = "Cannot find operand parser for token `{$token->getValue()}`";
         throw new SyntaxErrorException($message, 0, $e);
     }
     return $operand->parse($this->grammar, $this->stream);
 }
Пример #7
0
 /**
  * Throw a syntax error exception.
  *
  * @param array $tokens A list with expected tokens.
  * @param AnnotationToken $lookahead The lookahead token.
  * @throws SyntaxErrorException if a syntax error occurs.
  */
 private function syntaxError(array $tokens, AnnotationToken $lookahead = null)
 {
     $refObject = new ReflectionClass(__NAMESPACE__ . '\\AnnotationLexer');
     $tokens = array_map(array($refObject, 'getConstantByValue'), $tokens);
     $tokens = implode('`,`', $tokens);
     if (!$lookahead) {
         $message = "Syntax error in DocBlock for: {$this->context->getLocation()}, ";
         $message .= "expected tokens: `{$tokens}` but end of string reached";
     } else {
         $snippet = preg_replace('/[\\r\\n\\t]*/', '', substr($this->stream->getSource(), $lookahead->getOffset(), 50));
         $message = "Syntax error in DocBlock for: {$this->context->getLocation()}, ";
         $message .= "expected tokens: `{$tokens}` but found `{$lookahead->getValue()}` ";
         $message .= "at offset `{$lookahead->getOffset()}` near: `{$snippet}`";
     }
     throw new SyntaxErrorException($message);
 }
Пример #8
0
 /**
  * Transform the input string into a token stream.
  *
  * @param string $input The string input to tokenize.
  * @return TokenStream The resulting token stream.
  */
 private function tokenize($input)
 {
     $stream = new TokenStream();
     $stream->setSource($input);
     $pattern = '/' . implode('|', $this->lexemes) . '/';
     $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
     $matches = preg_split($pattern, $input, -1, $flags);
     foreach ($matches as $match) {
         $value = strtolower($match[0]);
         if ($value[0] == "'" || $value[0] == '"' || $value == 'true' || $value == 'false' || $value == 'null' || is_numeric($value)) {
             $code = self::T_VALUE;
         } else {
             if (isset($this->constMap[$value])) {
                 $code = $this->constMap[$value];
             } else {
                 if (preg_match('/[a-z0-9_]+/', $value)) {
                     $code = self::T_NAME;
                 } else {
                     if (ctype_space($value)) {
                         continue;
                     } else {
                         $code = self::T_NONE;
                     }
                 }
             }
         }
         $stream->push(new AnnotationToken($code, $match[0], $match[1]));
     }
     return $stream;
 }
Пример #9
0
 /**
  * Data provider which returns a TokenStream instance.
  *
  * @return array An array containing a TokenStream instance.
  */
 public function tokenStreamProvider()
 {
     // user.name.split(" ").join("-")
     $stream = new TokenStream();
     $stream->push(new TestToken(self::T_NAME));
     $stream->push(new TestToken(self::T_POINT));
     $stream->push(new TestToken(self::T_NAME));
     $stream->push(new TestToken(self::T_POINT));
     $stream->push(new TestToken(self::T_NAME));
     $stream->push(new TestToken(self::T_OPEN_PARENTHESIS));
     $stream->push(new TestToken(self::T_VALUE));
     $stream->push(new TestToken(self::T_CLOSE_PARENTHESIS));
     $stream->push(new TestToken(self::T_POINT));
     $stream->push(new TestToken(self::T_NAME));
     $stream->push(new TestToken(self::T_OPEN_PARENTHESIS));
     $stream->push(new TestToken(self::T_VALUE));
     $stream->push(new TestToken(self::T_CLOSE_PARENTHESIS));
     $stream->rewind();
     return array(array($stream));
 }
Пример #10
0
 /**
  * Transform the input string into a token stream.
  *
  * @param string $input The string input to tokenize.
  * @return TokenStream The resulting token stream.
  */
 private function tokenize($input)
 {
     $stream = new TokenStream();
     $stream->setSource($input);
     $pattern = '/' . implode('|', $this->lexemes) . '/';
     $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
     $matches = preg_split($pattern, $input, -1, $flags);
     foreach ($matches as $match) {
         $value = strtolower($match[0]);
         if (is_numeric($value)) {
             $code = self::T_NUMBER;
         } else {
             if (isset($this->constTokenMap[$value])) {
                 $code = $this->constTokenMap[$value];
             } else {
                 if (ctype_space($value)) {
                     continue;
                 } else {
                     $code = self::T_NONE;
                 }
             }
         }
         $stream->push(new Token($code, $match[0], $match[1]));
     }
     return $stream;
 }