summaryrefslogtreecommitdiff
path: root/vendor/doctrine/orm/src/Query/Lexer.php
blob: c446675d908f78f579be3a5cd89c59bebe7e051d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Query;

use Doctrine\Common\Lexer\AbstractLexer;

use function constant;
use function ctype_alpha;
use function defined;
use function is_numeric;
use function str_contains;
use function str_replace;
use function stripos;
use function strlen;
use function strtoupper;
use function substr;

/**
 * Scans a DQL query for tokens.
 *
 * @extends AbstractLexer<TokenType, string>
 */
class Lexer extends AbstractLexer
{
    /**
     * Creates a new query scanner object.
     *
     * @param string $input A query string.
     */
    public function __construct(string $input)
    {
        $this->setInput($input);
    }

    /**
     * {@inheritDoc}
     */
    protected function getCatchablePatterns(): array
    {
        return [
            '[a-z_][a-z0-9_]*\:[a-z_][a-z0-9_]*(?:\\\[a-z_][a-z0-9_]*)*', // aliased name
            '[a-z_\\\][a-z0-9_]*(?:\\\[a-z_][a-z0-9_]*)*', // identifier or qualified name
            '(?:[0-9]+(?:[\.][0-9]+)*)(?:e[+-]?[0-9]+)?', // numbers
            "'(?:[^']|'')*'", // quoted strings
            '\?[0-9]*|:[a-z_][a-z0-9_]*', // parameters
        ];
    }

    /**
     * {@inheritDoc}
     */
    protected function getNonCatchablePatterns(): array
    {
        return ['\s+', '--.*', '(.)'];
    }

    protected function getType(string &$value): TokenType
    {
        $type = TokenType::T_NONE;

        switch (true) {
            // Recognize numeric values
            case is_numeric($value):
                if (str_contains($value, '.') || stripos($value, 'e') !== false) {
                    return TokenType::T_FLOAT;
                }

                return TokenType::T_INTEGER;

            // Recognize quoted strings
            case $value[0] === "'":
                $value = str_replace("''", "'", substr($value, 1, strlen($value) - 2));

                return TokenType::T_STRING;

            // Recognize identifiers, aliased or qualified names
            case ctype_alpha($value[0]) || $value[0] === '_' || $value[0] === '\\':
                $name = 'Doctrine\ORM\Query\TokenType::T_' . strtoupper($value);

                if (defined($name)) {
                    $type = constant($name);

                    if ($type->value > 100) {
                        return $type;
                    }
                }

                if (str_contains($value, '\\')) {
                    return TokenType::T_FULLY_QUALIFIED_NAME;
                }

                return TokenType::T_IDENTIFIER;

            // Recognize input parameters
            case $value[0] === '?' || $value[0] === ':':
                return TokenType::T_INPUT_PARAMETER;

            // Recognize symbols
            case $value === '.':
                return TokenType::T_DOT;

            case $value === ',':
                return TokenType::T_COMMA;

            case $value === '(':
                return TokenType::T_OPEN_PARENTHESIS;

            case $value === ')':
                return TokenType::T_CLOSE_PARENTHESIS;

            case $value === '=':
                return TokenType::T_EQUALS;

            case $value === '>':
                return TokenType::T_GREATER_THAN;

            case $value === '<':
                return TokenType::T_LOWER_THAN;

            case $value === '+':
                return TokenType::T_PLUS;

            case $value === '-':
                return TokenType::T_MINUS;

            case $value === '*':
                return TokenType::T_MULTIPLY;

            case $value === '/':
                return TokenType::T_DIVIDE;

            case $value === '!':
                return TokenType::T_NEGATE;

            case $value === '{':
                return TokenType::T_OPEN_CURLY_BRACE;

            case $value === '}':
                return TokenType::T_CLOSE_CURLY_BRACE;

            // Default
            default:
                // Do nothing
        }

        return $type;
    }
}