public function testQuery() { $this->assertTokens("AVG(user.id) as Avg, count(id), (id + 10) / 2\n" . "from UserGroup\n" . "where (id in (1, \$1) or id >= \$2) and (name like \"%'ы'%\") " . "order by id desc", array(OqlToken::make('avg', 'AVG', OqlToken::AGGREGATE_FUNCTION, 1, 0), OqlToken::make('(', '(', OqlToken::PARENTHESES, 1, 3), OqlToken::make('user.id', 'user.id', OqlToken::IDENTIFIER, 1, 4), OqlToken::make(')', ')', OqlToken::PARENTHESES, 1, 11), OqlToken::make('as', 'as', OqlToken::KEYWORD, 1, 13), OqlToken::make('avg', 'Avg', OqlToken::AGGREGATE_FUNCTION, 1, 16), OqlToken::make(',', ',', OqlToken::PUNCTUATION, 1, 19), OqlToken::make('count', 'count', OqlToken::AGGREGATE_FUNCTION, 1, 21), OqlToken::make('(', '(', OqlToken::PARENTHESES, 1, 26), OqlToken::make('id', 'id', OqlToken::IDENTIFIER, 1, 27), OqlToken::make(')', ')', OqlToken::PARENTHESES, 1, 29), OqlToken::make(',', ',', OqlToken::PUNCTUATION, 1, 30), OqlToken::make('(', '(', OqlToken::PARENTHESES, 1, 32), OqlToken::make('id', 'id', OqlToken::IDENTIFIER, 1, 33), OqlToken::make('+', '+', OqlToken::ARITHMETIC_OPERATOR, 1, 36), OqlToken::make(10.0, '10', OqlToken::NUMBER, 1, 38), OqlToken::make(')', ')', OqlToken::PARENTHESES, 1, 40), OqlToken::make('/', '/', OqlToken::ARITHMETIC_OPERATOR, 1, 42), OqlToken::make(2.0, '2', OqlToken::NUMBER, 1, 44), OqlToken::make('from', 'from', OqlToken::KEYWORD, 2, 0), OqlToken::make('UserGroup', 'UserGroup', OqlToken::IDENTIFIER, 2, 5), OqlToken::make('where', 'where', OqlToken::KEYWORD, 3, 0), OqlToken::make('(', '(', OqlToken::PARENTHESES, 3, 6), OqlToken::make('id', 'id', OqlToken::IDENTIFIER, 3, 7), OqlToken::make('in', 'in', OqlToken::KEYWORD, 3, 10), OqlToken::make('(', '(', OqlToken::PARENTHESES, 3, 13), OqlToken::make(1.0, '1', OqlToken::NUMBER, 3, 14), OqlToken::make(',', ',', OqlToken::PUNCTUATION, 3, 15), OqlToken::make(1, '$1', OqlToken::SUBSTITUTION, 3, 17), OqlToken::make(')', ')', OqlToken::PARENTHESES, 3, 19), OqlToken::make('or', 'or', OqlToken::KEYWORD, 3, 21), OqlToken::make('id', 'id', OqlToken::IDENTIFIER, 3, 24), OqlToken::make('>=', '>=', OqlToken::COMPARISON_OPERATOR, 3, 27), OqlToken::make(2, '$2', OqlToken::SUBSTITUTION, 3, 30), OqlToken::make(')', ')', OqlToken::PARENTHESES, 3, 32), OqlToken::make('and', 'and', OqlToken::KEYWORD, 3, 34), OqlToken::make('(', '(', OqlToken::PARENTHESES, 3, 38), OqlToken::make('name', 'name', OqlToken::IDENTIFIER, 3, 39), OqlToken::make('like', 'like', OqlToken::KEYWORD, 3, 44), OqlToken::make('%\'ы\'%', '"%\'ы\'%"', OqlToken::STRING, 3, 49), OqlToken::make(')', ')', OqlToken::PARENTHESES, 3, 56), OqlToken::make('order by', 'order by', OqlToken::KEYWORD, 3, 58), OqlToken::make('id', 'id', OqlToken::IDENTIFIER, 3, 67), OqlToken::make('desc', 'desc', OqlToken::KEYWORD, 3, 70))); }
/** * @return OqlTokenizer **/ private function tokenize($string) { Assert::isString($string); $maxMultibyteDelta = strlen($string) - mb_strlen($string); $isMultibyte = $maxMultibyteDelta > 0; $pattern = '/(' . implode(')|(', self::$masks) . ')/is'; if ($isMultibyte) { $pattern .= 'u'; } preg_match_all($pattern, $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE); $line = 1; $lineStart = 0; $multibyteDelta = 0; foreach ($matches as $match) { $type = count($match) - 1; $offset = $match[0][1] - $multibyteDelta; if ($type == OqlToken::NEW_LINE) { $line++; $lineStart = $offset + 1; continue; } $value = $match[0][0]; $position = $offset - $lineStart; $this->tokens[] = OqlToken::make($this->importTokenValue($value, $type), $value, $type, $line, $position); if ($type == OqlToken::KEYWORD && ($pos = strpos($value, "\n")) !== false) { $line++; $lineStart = $offset + $pos + 1; } if ($isMultibyte && $type == OqlToken::STRING) { $multibyteDelta += strlen($value) - mb_strlen($value); if ($multibyteDelta >= $maxMultibyteDelta) { $isMultibyte = false; } } } $this->tokensCount = count($this->tokens); return $this; }