/** * Skips whitespace in the specified text by advancing an index to * the next non-whitespace character. * * @param string $text Text to scan. * @param int &$textIndex Index to begin scanning from. * * @return boolean true if the end of the string was reached, false otherwise. */ public static function skipWhiteSpace($text, &$textIndex) { $textLen = strlen($text); while ($textIndex < $textLen && Char::isWhiteSpace($text[$textIndex])) { $textIndex++; } return $textLen == $textIndex; }
/** * Reads the next token, skipping whitespace as necessary. * * @return void */ public function nextToken() { while (Char::isWhiteSpace($this->_ch)) { $this->_nextChar(); } $t; $tokenPos = $this->_textPos; switch ($this->_ch) { case '(': $this->_nextChar(); $t = ExpressionTokenId::OPENPARAM; break; case ')': $this->_nextChar(); $t = ExpressionTokenId::CLOSEPARAM; break; case ',': $this->_nextChar(); $t = ExpressionTokenId::COMMA; break; case '-': $hasNext = $this->_textPos + 1 < $this->_textLen; if ($hasNext && Char::isDigit($this->_text[$this->_textPos + 1])) { $this->_nextChar(); $t = $this->_parseFromDigit(); if (self::isNumeric($t)) { break; } $this->_setTextPos($tokenPos); } else { if ($hasNext && $this->_text[$tokenPos + 1] == 'I') { $this->_nextChar(); $this->_parseIdentifier(); $currentIdentifier = substr($this->_text, $tokenPos + 1, $this->_textPos - $tokenPos - 1); if (self::_isInfinityLiteralDouble($currentIdentifier)) { $t = ExpressionTokenId::DOUBLE_LITERAL; break; } else { if (self::_isInfinityLiteralSingle($currentIdentifier)) { $t = ExpressionTokenId::SINGLE_LITERAL; break; } } // If it looked like '-INF' but wasn't we'll rewind and fall // through to a simple '-' token. $this->_setTextPos($tokenPos); } } $this->_nextChar(); $t = ExpressionTokenId::MINUS; break; case '=': $this->_nextChar(); $t = ExpressionTokenId::EQUAL; break; case '/': $this->_nextChar(); $t = ExpressionTokenId::SLASH; break; case '?': $this->_nextChar(); $t = ExpressionTokenId::QUESTION; break; case '.': $this->_nextChar(); $t = ExpressionTokenId::DOT; break; case '\'': $quote = $this->_ch; do { $this->_nextChar(); while ($this->_textPos < $this->_textLen && $this->_ch != $quote) { $this->_nextChar(); } if ($this->_textPos == $this->_textLen) { throw $this->_parseError(Messages::expressionLexerUnterminatedStringLiteral($this->_textPos, $this->_text)); } $this->_nextChar(); } while ($this->_ch == $quote); $t = ExpressionTokenId::STRING_LITERAL; break; case '*': $this->_nextChar(); $t = ExpressionTokenId::STAR; break; default: if (Char::isLetter($this->_ch) || $this->_ch == '_') { $this->_parseIdentifier(); $t = ExpressionTokenId::IDENTIFIER; break; } if (Char::isDigit($this->_ch)) { $t = $this->_parseFromDigit(); break; } if ($this->_textPos == $this->_textLen) { $t = ExpressionTokenId::END; break; } throw $this->_parseError(Messages::expressionLexerInvalidCharacter($this->_ch, $this->_textPos)); } $this->_token->Id = $t; $this->_token->Text = substr($this->_text, $tokenPos, $this->_textPos - $tokenPos); $this->_token->Position = $tokenPos; // Handle type-prefixed literals such as binary, datetime or guid. $this->_handleTypePrefixedLiterals(); // Handle keywords. if ($this->_token->Id == ExpressionTokenId::IDENTIFIER) { if (self::_isInfinityOrNaNDouble($this->_token->Text)) { $this->_token->Id = ExpressionTokenId::DOUBLE_LITERAL; } else { if (self::_isInfinityOrNanSingle($this->_token->Text)) { $this->_token->Id = ExpressionTokenId::SINGLE_LITERAL; } else { if ($this->_token->Text == ODataConstants::KEYWORD_TRUE || $this->_token->Text == ODataConstants::KEYWORD_FALSE) { $this->_token->Id = ExpressionTokenId::BOOLEAN_LITERAL; } else { if ($this->_token->Text == ODataConstants::KEYWORD_NULL) { $this->_token->Id = ExpressionTokenId::NULL_LITERAL; } } } } } }