Issues (119)

src/TokensList.php (2 issues)

Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpMyAdmin\SqlParser;
6
7
use ArrayAccess;
8
9
use function count;
10
use function in_array;
11
use function is_array;
12
13
/**
14
 * Defines an array of tokens and utility functions to iterate through it.
15
 *
16
 * A structure representing a list of tokens.
17
 *
18
 * @implements ArrayAccess<int, Token>
19
 */
20
class TokensList implements ArrayAccess
21
{
22
    /**
23
     * The count of tokens.
24
     */
25
    public int $count = 0;
26
27
    /**
28
     * The index of the next token to be returned.
29
     */
30
    public int $idx = 0;
31
32
    /** @param Token[] $tokens The array of tokens. */
33 1522
    public function __construct(public array $tokens = [])
34
    {
35 1522
        $this->count = count($tokens);
36
    }
37
38
    /**
39
     * Builds an array of tokens by merging their raw value.
40
     */
41 2
    public function build(): string
42
    {
43 2
        return static::buildFromArray($this->tokens);
44
    }
45
46
    /**
47
     * Builds an array of tokens by merging their raw value.
48
     *
49
     * @param Token[] $list the tokens to be built
50
     */
51 64
    public static function buildFromArray(array $list): string
52
    {
53 64
        $ret = '';
54 64
        foreach ($list as $token) {
55 24
            $ret .= $token->token;
56
        }
57
58 64
        return $ret;
59
    }
60
61
    /**
62
     * Adds a new token.
63
     *
64
     * @param Token $token token to be added in list
65
     */
66 2
    public function add(Token $token): void
67
    {
68 2
        $this->tokens[$this->count++] = $token;
69
    }
70
71
    /**
72
     * Gets the next token. Skips any irrelevant token (whitespaces and
73
     * comments).
74
     */
75 506
    public function getNext(): Token|null
76
    {
77 506
        for (; $this->idx < $this->count; ++$this->idx) {
78
            if (
79 506
                ($this->tokens[$this->idx]->type !== TokenType::Whitespace)
80 506
                && ($this->tokens[$this->idx]->type !== TokenType::Comment)
81
            ) {
82 506
                return $this->tokens[$this->idx++];
83
            }
84
        }
85
86 2
        return null;
87
    }
88
89
    /**
90
     * Gets the previous token. Skips any irrelevant token (whitespaces and
91
     * comments).
92
     */
93 512
    public function getPrevious(): Token|null
94
    {
95 512
        for (; $this->idx >= 0; --$this->idx) {
96
            if (
97 512
                ($this->tokens[$this->idx]->type !== TokenType::Whitespace)
98 512
                && ($this->tokens[$this->idx]->type !== TokenType::Comment)
99
            ) {
100 512
                return $this->tokens[$this->idx--];
101
            }
102
        }
103
104 14
        return null;
105
    }
106
107
    /**
108
     * Gets the previous token.
109
     *
110
     * @param TokenType|TokenType[] $type the type
111
     */
112 2
    public function getPreviousOfType(TokenType|array $type): Token|null
113
    {
114 2
        if (! is_array($type)) {
0 ignored issues
show
The condition is_array($type) is always true.
Loading history...
115 2
            $type = [$type];
116
        }
117
118 2
        for (; $this->idx >= 0; --$this->idx) {
119 2
            if (in_array($this->tokens[$this->idx]->type, $type, true)) {
120 2
                return $this->tokens[$this->idx--];
121
            }
122
        }
123
124 2
        return null;
125
    }
126
127
    /**
128
     * Gets the next token.
129
     *
130
     * @param TokenType|TokenType[] $type the type
131
     */
132 184
    public function getNextOfType(TokenType|array $type): Token|null
133
    {
134 184
        if (! is_array($type)) {
0 ignored issues
show
The condition is_array($type) is always true.
Loading history...
135 184
            $type = [$type];
136
        }
137
138 184
        for (; $this->idx < $this->count; ++$this->idx) {
139 184
            if (in_array($this->tokens[$this->idx]->type, $type, true)) {
140 166
                return $this->tokens[$this->idx++];
141
            }
142
        }
143
144 30
        return null;
145
    }
146
147
    /**
148
     * Gets the next token.
149
     *
150
     * @param TokenType $type  the type of the token
151
     * @param string    $value the value of the token
152
     */
153 1502
    public function getNextOfTypeAndValue(TokenType $type, string $value): Token|null
154
    {
155 1502
        for (; $this->idx < $this->count; ++$this->idx) {
156 1502
            if (($this->tokens[$this->idx]->type === $type) && ($this->tokens[$this->idx]->value === $value)) {
157 236
                return $this->tokens[$this->idx++];
158
            }
159
        }
160
161 1502
        return null;
162
    }
163
164
    /**
165
     * Gets the next token.
166
     *
167
     * @param TokenType $type the type of the token
168
     * @param int       $flag the flag of the token
169
     */
170 1502
    public function getNextOfTypeAndFlag(TokenType $type, int $flag): Token|null
171
    {
172 1502
        for (; $this->idx < $this->count; ++$this->idx) {
173 1502
            if (($this->tokens[$this->idx]->type === $type) && ($this->tokens[$this->idx]->flags === $flag)) {
174 220
                return $this->tokens[$this->idx++];
175
            }
176
        }
177
178 1502
        return null;
179
    }
180
181
    /**
182
     * Sets an value inside the container.
183
     *
184
     * @param int|null $offset the offset to be set
185
     * @param Token    $value  the token to be saved
186
     */
187 2
    public function offsetSet(mixed $offset, mixed $value): void
188
    {
189 2
        if ($offset === null) {
190 2
            $this->tokens[$this->count++] = $value;
191
        } else {
192 2
            $this->tokens[$offset] = $value;
193
        }
194
    }
195
196
    /**
197
     * Gets a value from the container.
198
     *
199
     * @param int $offset the offset to be returned
200
     */
201 2
    public function offsetGet(mixed $offset): Token|null
202
    {
203 2
        return $offset < $this->count ? $this->tokens[$offset] : null;
204
    }
205
206
    /**
207
     * Checks if an offset was previously set.
208
     *
209
     * @param int $offset the offset to be checked
210
     */
211 2
    public function offsetExists(mixed $offset): bool
212
    {
213 2
        return $offset < $this->count;
214
    }
215
216
    /**
217
     * Unsets the value of an offset.
218
     *
219
     * @param int $offset the offset to be unset
220
     */
221 2
    public function offsetUnset(mixed $offset): void
222
    {
223 2
        unset($this->tokens[$offset]);
224 2
        --$this->count;
225 2
        for ($i = $offset; $i < $this->count; ++$i) {
226 2
            $this->tokens[$i] = $this->tokens[$i + 1];
227
        }
228
229 2
        unset($this->tokens[$this->count]);
230
    }
231
}
232