vendor/symfony/expression-language/Lexer.php line 26

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\ExpressionLanguage;
  11. /**
  12.  * Lexes an expression.
  13.  *
  14.  * @author Fabien Potencier <fabien@symfony.com>
  15.  */
  16. class Lexer
  17. {
  18.     /**
  19.      * Tokenizes an expression.
  20.      *
  21.      * @throws SyntaxError
  22.      */
  23.     public function tokenize(string $expression): TokenStream
  24.     {
  25.         $expression str_replace(["\r""\n""\t""\v""\f"], ' '$expression);
  26.         $cursor 0;
  27.         $tokens = [];
  28.         $brackets = [];
  29.         $end \strlen($expression);
  30.         while ($cursor $end) {
  31.             if (' ' == $expression[$cursor]) {
  32.                 ++$cursor;
  33.                 continue;
  34.             }
  35.             if (preg_match('/
  36.                 (?(DEFINE)(?P<LNUM>[0-9]+(_[0-9]+)*))
  37.                 (?:\.(?&LNUM)|(?&LNUM)(?:\.(?!\.)(?&LNUM)?)?)(?:[eE][+-]?(?&LNUM))?/Ax',
  38.                 $expression$match0$cursor)
  39.             ) {
  40.                 // numbers
  41.                 $tokens[] = new Token(Token::NUMBER_TYPEstr_replace('_'''$match[0]), $cursor 1);
  42.                 $cursor += \strlen($match[0]);
  43.             } elseif (str_contains('([{'$expression[$cursor])) {
  44.                 // opening bracket
  45.                 $brackets[] = [$expression[$cursor], $cursor];
  46.                 $tokens[] = new Token(Token::PUNCTUATION_TYPE$expression[$cursor], $cursor 1);
  47.                 ++$cursor;
  48.             } elseif (str_contains(')]}'$expression[$cursor])) {
  49.                 // closing bracket
  50.                 if (empty($brackets)) {
  51.                     throw new SyntaxError(sprintf('Unexpected "%s".'$expression[$cursor]), $cursor$expression);
  52.                 }
  53.                 [$expect$cur] = array_pop($brackets);
  54.                 if ($expression[$cursor] != strtr($expect'([{'')]}')) {
  55.                     throw new SyntaxError(sprintf('Unclosed "%s".'$expect), $cur$expression);
  56.                 }
  57.                 $tokens[] = new Token(Token::PUNCTUATION_TYPE$expression[$cursor], $cursor 1);
  58.                 ++$cursor;
  59.             } elseif (preg_match('/"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As'$expression$match0$cursor)) {
  60.                 // strings
  61.                 $tokens[] = new Token(Token::STRING_TYPEstripcslashes(substr($match[0], 1, -1)), $cursor 1);
  62.                 $cursor += \strlen($match[0]);
  63.             } elseif (preg_match('/(?<=^|[\s(])starts with(?=[\s(])|(?<=^|[\s(])ends with(?=[\s(])|(?<=^|[\s(])contains(?=[\s(])|(?<=^|[\s(])matches(?=[\s(])|(?<=^|[\s(])not in(?=[\s(])|(?<=^|[\s(])not(?=[\s(])|(?<=^|[\s(])and(?=[\s(])|\=\=\=|\!\=\=|(?<=^|[\s(])or(?=[\s(])|\|\||&&|\=\=|\!\=|\>\=|\<\=|(?<=^|[\s(])in(?=[\s(])|\.\.|\*\*|\!|\||\^|&|\<|\>|\+|\-|~|\*|\/|%/A'$expression$match0$cursor)) {
  64.                 // operators
  65.                 $tokens[] = new Token(Token::OPERATOR_TYPE$match[0], $cursor 1);
  66.                 $cursor += \strlen($match[0]);
  67.             } elseif ('?' === $expression[$cursor] && '.' === ($expression[$cursor 1] ?? '')) {
  68.                 // null-safe
  69.                 $tokens[] = new Token(Token::PUNCTUATION_TYPE'?.', ++$cursor);
  70.                 ++$cursor;
  71.             } elseif (str_contains('.,?:'$expression[$cursor])) {
  72.                 // punctuation
  73.                 $tokens[] = new Token(Token::PUNCTUATION_TYPE$expression[$cursor], $cursor 1);
  74.                 ++$cursor;
  75.             } elseif (preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A'$expression$match0$cursor)) {
  76.                 // names
  77.                 $tokens[] = new Token(Token::NAME_TYPE$match[0], $cursor 1);
  78.                 $cursor += \strlen($match[0]);
  79.             } else {
  80.                 // unlexable
  81.                 throw new SyntaxError(sprintf('Unexpected character "%s".'$expression[$cursor]), $cursor$expression);
  82.             }
  83.         }
  84.         $tokens[] = new Token(Token::EOF_TYPEnull$cursor 1);
  85.         if (!empty($brackets)) {
  86.             [$expect$cur] = array_pop($brackets);
  87.             throw new SyntaxError(sprintf('Unclosed "%s".'$expect), $cur$expression);
  88.         }
  89.         return new TokenStream($tokens$expression);
  90.     }
  91. }